Merge tag 'asoc-v3.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Thu, 18 Apr 2013 14:24:31 +0000 (16:24 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 18 Apr 2013 14:24:31 +0000 (16:24 +0200)
ASoC: More updates for v3.10

The main additional change here is Lars-Peter's DMA work plus the
platform conversions which have been tested - getting this in mainline
will make life easier for development after the merge window.  These
factor a large chunk of code out of the drivers for the platforms using
dmaengine, greatly simplifying development.

200 files changed:
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/devicetree/bindings/sound/ak5386.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
Documentation/devicetree/bindings/sound/ti,tas5086.txt [new file with mode: 0644]
Documentation/sound/alsa/HD-Audio.txt
arch/arm/mach-s3c24xx/dma-s3c2410.c
arch/arm/mach-s3c24xx/dma-s3c2412.c
arch/arm/mach-s3c24xx/dma-s3c2440.c
arch/arm/mach-s3c24xx/dma-s3c2443.c
arch/arm/plat-samsung/devs.c
drivers/extcon/extcon-arizona.c
drivers/mfd/wm5102-tables.c
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/wm8994/pdata.h
include/linux/usb/audio-v2.h
include/sound/control.h
include/sound/core.h
include/sound/pcm.h
include/sound/soc-dai.h
include/sound/soc.h
include/sound/tas5086.h [new file with mode: 0644]
include/sound/tegra_wm8903.h [deleted file]
include/uapi/sound/asound.h
sound/core/control.c
sound/core/device.c
sound/core/hwdep.c
sound/core/info.c
sound/core/init.c
sound/core/isadma.c
sound/core/jack.c
sound/core/memalloc.c
sound/core/memory.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_misc.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/sound.c
sound/core/vmaster.c
sound/drivers/mpu401/mpu401_uart.c
sound/oss/sb_common.c
sound/oss/uart401.c
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_pcm.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/rme9652/hdspm.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/i2sc.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bf6xx-i2s.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1373.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak5386.c [new file with mode: 0644]
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs42l73.c
sound/soc/codecs/max98090.c
sound/soc/codecs/si476x.c
sound/soc/codecs/tas5086.c [new file with mode: 0644]
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5102.h
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm5110.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-vcif.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/mxs/mxs-saif.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/s6000/s6000-i2s.c
sound/soc/samsung/Kconfig
sound/soc/samsung/ac97.c
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/pcm.c
sound/soc/samsung/regs-ac97.h [moved from arch/arm/plat-samsung/include/plat/regs-ac97.h with 100% similarity]
sound/soc/samsung/regs-iis.h [moved from arch/arm/plat-samsung/include/plat/regs-iis.h with 100% similarity]
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c-i2s-v2.c
sound/soc/samsung/s3c-i2s-v2.h
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/spdif.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/migor.c
sound/soc/sh/siu_dai.c
sound/soc/sh/ssi.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/spear/spear_pcm.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_ahub.h
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/tegra_wm9712.c
sound/soc/tegra/trimslice.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/sound_core.c
sound/spi/at73c213.c
sound/usb/caiaq/audio.c
sound/usb/caiaq/audio.h
sound/usb/caiaq/control.c
sound/usb/caiaq/control.h
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/caiaq/input.c
sound/usb/caiaq/input.h
sound/usb/caiaq/midi.c
sound/usb/caiaq/midi.h
sound/usb/card.c
sound/usb/card.h
sound/usb/clock.c
sound/usb/clock.h
sound/usb/endpoint.c
sound/usb/endpoint.h
sound/usb/format.c
sound/usb/format.h
sound/usb/midi.c
sound/usb/pcm.c
sound/usb/proc.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/quirks.h
sound/usb/stream.c
sound/usb/usbaudio.h

index bd6fee2..06741e9 100644 (file)
@@ -6164,14 +6164,12 @@ struct _snd_pcm_runtime {
 
       <para>
         The macro takes an conditional expression to evaluate.
-       When <constant>CONFIG_SND_DEBUG</constant>, is set, the
-       expression is actually evaluated. If it's non-zero, it shows
-       the warning message such as
+       When <constant>CONFIG_SND_DEBUG</constant>, is set, if the
+       expression is non-zero, it shows the warning message such as
        <computeroutput>BUG? (xxx)</computeroutput>
-       normally followed by stack trace.  It returns the evaluated
-       value.
-       When no <constant>CONFIG_SND_DEBUG</constant> is set, this
-       macro always returns zero.
+       normally followed by stack trace.
+
+       In both cases it returns the evaluated value.
       </para>
 
     </section>
diff --git a/Documentation/devicetree/bindings/sound/ak5386.txt b/Documentation/devicetree/bindings/sound/ak5386.txt
new file mode 100644 (file)
index 0000000..dc3914f
--- /dev/null
@@ -0,0 +1,19 @@
+AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+
+This device has no control interface.
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak5386"
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset/power down pin.
+                If specified, it will be deasserted at probe time.
+
+Example:
+
+spdif: ak5386@0 {
+       compatible = "asahi-kasei,ak5386";
+       reset-gpio = <&gpio0 23>;
+};
index 1ac7b16..0e5c12c 100644 (file)
@@ -1,12 +1,22 @@
 NVIDIA Tegra30 AHUB (Audio Hub)
 
 Required properties:
-- compatible : "nvidia,tegra30-ahub"
+- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc.
 - reg : Should contain the register physical address and length for each of
-  the AHUB's APBIF registers and the AHUB's own registers.
+  the AHUB's register blocks.
+  - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks.
+  - Tegra114 requires an additional entry, for the APBIF2 register block.
 - interrupts : Should contain AHUB interrupt
-- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
-  request selector for the first APBIF channel.
+- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each
+  entry contains the Tegra DMA controller's phandle and request selector.
+  If a single entry is present, the request selectors for the channels are
+  assumed to be contiguous, and increment from this value.
+  If multiple values are given, one value must be given per channel.
+- clocks : Must contain an entry for each required entry in clock-names.
+- clock-names : Must include the following entries:
+  - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0,
+    dam1, dam2, spdif_in.
+  - Tegra114: Additionally requires amx, adx.
 - ranges : The bus address mapping for the configlink register bus.
   Can be empty since the mapping is 1:1.
 - #address-cells : For the configlink bus. Should be <1>;
@@ -25,7 +35,13 @@ ahub@70080000 {
        reg = <0x70080000 0x200 0x70080200 0x100>;
        interrupts = < 0 103 0x04 >;
        nvidia,dma-request-selector = <&apbdma 1>;
-
+       clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
+               <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
+               <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
+               <&tegra_car 110>, <&tegra_car 162>;
+       clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
+               "i2s3", "i2s4", "dam0", "dam1", "dam2",
+               "spdif_in";
        ranges;
        #address-cells = <1>;
        #size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
new file mode 100644 (file)
index 0000000..8ea4f5b
--- /dev/null
@@ -0,0 +1,32 @@
+Texas Instruments TAS5086 6-channel PWM Processor
+
+Required properties:
+
+ - compatible:         Should contain "ti,tas5086".
+ - reg:                        The i2c address. Should contain <0x1b>.
+
+Optional properties:
+
+ - reset-gpio:                 A GPIO spec to define which pin is connected to the
+                       chip's !RESET pin. If specified, the driver will
+                       assert a hardware reset at probe time.
+
+ - ti,charge-period:   This property should contain the time in microseconds
+                       that closely matches the external single-ended
+                       split-capacitor charge period. The hardware chip
+                       waits for this period of time before starting the
+                       PWM signals. This helps reduce pops and clicks.
+
+                       When not specified, the hardware default of 1300ms
+                       is retained.
+
+Examples:
+
+       i2c_bus {
+               tas5086@1b {
+                       compatible = "ti,tas5086";
+                       reg = <0x1b>;
+                       reset-gpio = <&gpio 23 0>;
+                       ti,charge-period = <156000>;
+               };
+       };
index d4faa63..c3c912d 100644 (file)
@@ -461,11 +461,13 @@ The generic parser supports the following hints:
   the corresponding mixer control, if available
 - add_stereo_mix_input (bool): add the stereo mix (analog-loopback
   mix) to the input mux if available
-- add_out_jack_modes (bool): add "xxx Jack Mode" enum controls to each
-  output jack for allowing to change the headphone amp capability
-- add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each
-  input jack for allowing to change the mic bias vref
+- add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
+  I/O jack for allowing to change the headphone amp and mic bias VREF
+  capabilities
 - power_down_unused (bool): power down the unused widgets
+- add_hp_mic (bool): add the headphone to capture source if possible
+- hp_mic_detect (bool): enable/disable the hp/mic shared input for a
+  single built-in mic case; default true
 - mixer_nid (int): specifies the widget NID of the analog-loopback
   mixer
 
index 25d085a..a4a13c9 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
index d2408ba..6eaa7a4 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
index 0b86e74..477d450 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
index 0553625..80a8d56 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { \
index 51afedd..d81d9fb 100644 (file)
@@ -146,14 +146,20 @@ struct platform_device s3c_device_camif = {
 
 /* ASOC DMA */
 
+#ifdef CONFIG_PLAT_S5P 
+static struct resource samsung_asoc_idma_resource = DEFINE_RES_IRQ(IRQ_I2S0);
+
 struct platform_device samsung_asoc_idma = {
        .name           = "samsung-idma",
        .id             = -1,
+       .num_resources  = 1,
+       .resource       = &samsung_asoc_idma_resource,
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        }
 };
+#endif
 
 /* FB */
 
index dc357a4..b289279 100644 (file)
@@ -100,6 +100,55 @@ static const char *arizona_cable[] = {
        NULL,
 };
 
+static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
+                                   unsigned int magic)
+{
+       struct arizona *arizona = info->arizona;
+       int ret;
+
+       mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+       arizona->hpdet_magic = magic;
+
+       /* Keep the HP output stages disabled while doing the magic */
+       if (magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, 0);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                               "Failed to disable headphone outputs: %d\n",
+                                ret);
+       }
+
+       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                                ret);
+
+       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                        ret);
+
+       /* Restore the desired state while not doing the magic */
+       if (!magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, arizona->hp_ena);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                                "Failed to restore headphone outputs: %d\n",
+                                ret);
+       }
+
+       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+}
+
 static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
 {
        struct arizona *arizona = info->arizona;
@@ -484,7 +533,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
        struct arizona *arizona = info->arizona;
        int id_gpio = arizona->pdata.hpdet_id_gpio;
        int report = ARIZONA_CABLE_HEADPHONE;
-       unsigned int val;
        int ret, reading;
 
        mutex_lock(&info->lock);
@@ -539,28 +587,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
                dev_err(arizona->dev, "Failed to report HP/line: %d\n",
                        ret);
 
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0);
 
 done:
        if (id_gpio)
@@ -606,13 +633,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
        if (info->mic)
                arizona_stop_mic(info);
 
-       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
-
-       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -653,7 +674,6 @@ err:
 static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 {
        struct arizona *arizona = info->arizona;
-       unsigned int val;
        int ret;
 
        dev_dbg(arizona->dev, "Starting identification via HPDET\n");
@@ -665,30 +685,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 
        arizona_extcon_pulse_micbias(info);
 
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
index a433f58..7d01069 100644 (file)
@@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
        { 0x00000177, 0x0181 },   /* R375   - FLL1 Loop Filter Test 1 */ 
        { 0x00000178, 0x0000 },   /* R376   - FLL1 NCO Test 0 */
+       { 0x00000179, 0x0000 },   /* R377   - FLL1 Control 7 */
        { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
        { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
        { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
        { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
        { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
        { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+       { 0x00000187, 0x0001 },   /* R391   - FLL1 Synchroniser 7 */
        { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
        { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
        { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
@@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
        { 0x00000197, 0x0000 },   /* R407   - FLL2 Loop Filter Test 1 */ 
        { 0x00000198, 0x0000 },   /* R408   - FLL2 NCO Test 0 */
+       { 0x00000199, 0x0000 },   /* R409   - FLL2 Control 7 */
        { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
        { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
        { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
        { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
        { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
        { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+       { 0x000001A7, 0x0001 },   /* R423   - FLL2 Synchroniser 7 */
        { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
        { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
        { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
@@ -1051,12 +1055,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL1_CONTROL_6:
        case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL1_NCO_TEST_0:
+       case ARIZONA_FLL1_CONTROL_7:
        case ARIZONA_FLL1_SYNCHRONISER_1:
        case ARIZONA_FLL1_SYNCHRONISER_2:
        case ARIZONA_FLL1_SYNCHRONISER_3:
        case ARIZONA_FLL1_SYNCHRONISER_4:
        case ARIZONA_FLL1_SYNCHRONISER_5:
        case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SYNCHRONISER_7:
        case ARIZONA_FLL1_SPREAD_SPECTRUM:
        case ARIZONA_FLL1_GPIO_CLOCK:
        case ARIZONA_FLL2_CONTROL_1:
@@ -1067,12 +1073,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL2_CONTROL_6:
        case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL2_NCO_TEST_0:
+       case ARIZONA_FLL2_CONTROL_7:
        case ARIZONA_FLL2_SYNCHRONISER_1:
        case ARIZONA_FLL2_SYNCHRONISER_2:
        case ARIZONA_FLL2_SYNCHRONISER_3:
        case ARIZONA_FLL2_SYNCHRONISER_4:
        case ARIZONA_FLL2_SYNCHRONISER_5:
        case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SYNCHRONISER_7:
        case ARIZONA_FLL2_SPREAD_SPECTRUM:
        case ARIZONA_FLL2_GPIO_CLOCK:
        case ARIZONA_MIC_CHARGE_PUMP_1:
@@ -1161,6 +1169,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_NOISE_GATE_CONTROL:
        case ARIZONA_PDM_SPK1_CTRL_1:
        case ARIZONA_PDM_SPK1_CTRL_2:
+       case ARIZONA_SPK_CTRL_2:
+       case ARIZONA_SPK_CTRL_3:
        case ARIZONA_DAC_COMP_1:
        case ARIZONA_DAC_COMP_2:
        case ARIZONA_DAC_COMP_3:
index a710255..cc28136 100644 (file)
@@ -100,6 +100,9 @@ struct arizona {
        struct regmap_irq_chip_data *aod_irq_chip;
        struct regmap_irq_chip_data *irq_chip;
 
+       bool hpdet_magic;
+       unsigned int hp_ena;
+
        struct mutex clk_lock;
        int clk32k_ref;
 
index 3403551..a47fd35 100644 (file)
 #define ARIZONA_FLL1_CONTROL_6                   0x176
 #define ARIZONA_FLL1_LOOP_FILTER_TEST_1          0x177
 #define ARIZONA_FLL1_NCO_TEST_0                  0x178
+#define ARIZONA_FLL1_CONTROL_7                   0x179
 #define ARIZONA_FLL1_SYNCHRONISER_1              0x181
 #define ARIZONA_FLL1_SYNCHRONISER_2              0x182
 #define ARIZONA_FLL1_SYNCHRONISER_3              0x183
 #define ARIZONA_FLL1_SYNCHRONISER_4              0x184
 #define ARIZONA_FLL1_SYNCHRONISER_5              0x185
 #define ARIZONA_FLL1_SYNCHRONISER_6              0x186
+#define ARIZONA_FLL1_SYNCHRONISER_7              0x187
 #define ARIZONA_FLL1_SPREAD_SPECTRUM             0x189
 #define ARIZONA_FLL1_GPIO_CLOCK                  0x18A
 #define ARIZONA_FLL2_CONTROL_1                   0x191
 #define ARIZONA_FLL2_CONTROL_6                   0x196
 #define ARIZONA_FLL2_LOOP_FILTER_TEST_1          0x197
 #define ARIZONA_FLL2_NCO_TEST_0                  0x198
+#define ARIZONA_FLL2_CONTROL_7                   0x199
 #define ARIZONA_FLL2_SYNCHRONISER_1              0x1A1
 #define ARIZONA_FLL2_SYNCHRONISER_2              0x1A2
 #define ARIZONA_FLL2_SYNCHRONISER_3              0x1A3
 #define ARIZONA_FLL2_SYNCHRONISER_4              0x1A4
 #define ARIZONA_FLL2_SYNCHRONISER_5              0x1A5
 #define ARIZONA_FLL2_SYNCHRONISER_6              0x1A6
+#define ARIZONA_FLL2_SYNCHRONISER_7              0x1A7
 #define ARIZONA_FLL2_SPREAD_SPECTRUM             0x1A9
 #define ARIZONA_FLL2_GPIO_CLOCK                  0x1AA
 #define ARIZONA_MIC_CHARGE_PUMP_1                0x200
 #define ARIZONA_PDM_SPK1_CTRL_2                  0x491
 #define ARIZONA_PDM_SPK2_CTRL_1                  0x492
 #define ARIZONA_PDM_SPK2_CTRL_2                  0x493
+#define ARIZONA_SPK_CTRL_2                       0x4B5
+#define ARIZONA_SPK_CTRL_3                       0x4B6
 #define ARIZONA_DAC_COMP_1                       0x4DC
 #define ARIZONA_DAC_COMP_2                       0x4DD
 #define ARIZONA_DAC_COMP_3                       0x4DE
 #define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH             12  /* FLL1_FRC_INTEG_VAL - [11:0] */
 
 /*
+ * R377 (0x179) - FLL1 Control 7
+ */
+#define ARIZONA_FLL1_GAIN_MASK                   0x003c  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_SHIFT                       2  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_WIDTH                       4  /* FLL1_GAIN */
+
+/*
  * R385 (0x181) - FLL1 Synchroniser 1
  */
 #define ARIZONA_FLL1_SYNC_ENA                    0x0001  /* FLL1_SYNC_ENA */
 #define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH               4  /* FLL1_CLK_SYNC_SRC - [3:0] */
 
 /*
+ * R391 (0x187) - FLL1 Synchroniser 7
+ */
+#define ARIZONA_FLL1_SYNC_GAIN_MASK              0x003c  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_SHIFT                  2  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_WIDTH                  4  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_BW                     0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_MASK                0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_SHIFT                    0  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_WIDTH                    1  /* FLL1_SYNC_BW */
+
+/*
  * R393 (0x189) - FLL1 Spread Spectrum
  */
 #define ARIZONA_FLL1_SS_AMPL_MASK                0x0030  /* FLL1_SS_AMPL - [5:4] */
 #define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH             12  /* FLL2_FRC_INTEG_VAL - [11:0] */
 
 /*
+ * R409 (0x199) - FLL2 Control 7
+ */
+#define ARIZONA_FLL2_GAIN_MASK                   0x003c  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_SHIFT                       2  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_WIDTH                       4  /* FLL2_GAIN */
+
+/*
  * R417 (0x1A1) - FLL2 Synchroniser 1
  */
 #define ARIZONA_FLL2_SYNC_ENA                    0x0001  /* FLL2_SYNC_ENA */
 #define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH               4  /* FLL2_CLK_SYNC_SRC - [3:0] */
 
 /*
+ * R423 (0x1A7) - FLL2 Synchroniser 7
+ */
+#define ARIZONA_FLL2_SYNC_GAIN_MASK              0x003c  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_SHIFT                  2  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_WIDTH                  4  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_SHIFT                    0  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_WIDTH                    1  /* FLL2_SYNC_BW */
+
+/*
  * R425 (0x1A9) - FLL2 Spread Spectrum
  */
 #define ARIZONA_FLL2_SS_AMPL_MASK                0x0030  /* FLL2_SS_AMPL - [5:4] */
index 8e21a09..68e7765 100644 (file)
@@ -17,6 +17,7 @@
 
 #define WM8994_NUM_LDO   2
 #define WM8994_NUM_GPIO 11
+#define WM8994_NUM_AIF   3
 
 struct wm8994_ldo_pdata {
        /** GPIOs to enable regulator, 0 or less if not available */
@@ -215,6 +216,13 @@ struct wm8994_pdata {
         * system.
         */
        bool spkmode_pu;
+
+       /**
+        * Maximum number of channels clocks will be generated for,
+        * useful for systems where and I2S bus with multiple data
+        * lines is mastered.
+        */
+       int max_channels_clocked[WM8994_NUM_AIF];
 };
 
 #endif
index ed13053..c5f2158 100644 (file)
@@ -170,6 +170,8 @@ struct uac2_as_header_descriptor {
        __u8 iChannelNames;
 } __attribute__((packed));
 
+#define UAC2_FORMAT_TYPE_I_RAW_DATA    (1 << 31)
+
 /* 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
 
 struct uac2_iso_endpoint_descriptor {
index 8332e86..34bc93d 100644 (file)
@@ -189,7 +189,6 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
  *
  * Add a virtual slave control to the given master element created via
  * snd_ctl_create_virtual_master() beforehand.
- * Returns zero if successful or a negative error code.
  *
  * All slaves must be the same type (returning the same information
  * via info callback).  The function doesn't check it, so it's your
@@ -199,6 +198,8 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
  * at most two channels,
  * logarithmic volume control (dB level) thus no linear volume,
  * master can only attenuate the volume without gain
+ *
+ * Return: Zero if successful or a negative error code.
  */
 static inline int
 snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
@@ -219,6 +220,8 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
  * When the control peeks the hardware values directly and the value
  * can be changed by other means than the put callback of the element,
  * this function should be used to keep the value always up-to-date.
+ *
+ * Return: Zero if successful or a negative error code.
  */
 static inline int
 snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
index 7cede2d..5bfe513 100644 (file)
@@ -229,7 +229,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card,
  * This function uses the card's device pointer to link to the
  * correct &struct device.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 static inline int snd_register_device(int type, struct snd_card *card, int dev,
                                      const struct file_operations *f_ops,
@@ -379,18 +379,10 @@ void __snd_printk(unsigned int level, const char *file, int line,
  * snd_BUG_ON - debugging check macro
  * @cond: condition to evaluate
  *
- * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition,
- * and call WARN() and returns the value if it's non-zero.
- * 
- * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given
- * condition is ignored.
- *
- * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n.
- * Thus, don't put any statement that influences on the code behavior,
- * such as pre/post increment, to the argument of this macro.
- * If you want to evaluate and give a warning, use standard WARN_ON().
+ * Has the same behavior as WARN_ON when CONFIG_SND_DEBUG is set,
+ * otherwise just evaluates the conditional and returns the value.
  */
-#define snd_BUG_ON(cond)       WARN((cond), "BUG? (%s)\n", __stringify(cond))
+#define snd_BUG_ON(cond)       WARN_ON((cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
@@ -400,11 +392,11 @@ __printf(2, 3)
 static inline void _snd_printd(int level, const char *format, ...) {}
 
 #define snd_BUG()                      do { } while (0)
-static inline int __snd_bug_on(int cond)
-{
-       return 0;
-}
-#define snd_BUG_ON(cond)       __snd_bug_on(0 && (cond))  /* always false */
+
+#define snd_BUG_ON(condition) ({ \
+       int __ret_warn_on = !!(condition); \
+       unlikely(__ret_warn_on); \
+})
 
 #endif /* CONFIG_SND_DEBUG */
 
index 45c1981..1b0c648 100644 (file)
@@ -181,6 +181,8 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_G723_24_1B    _SNDRV_PCM_FMTBIT(G723_24_1B)
 #define SNDRV_PCM_FMTBIT_G723_40       _SNDRV_PCM_FMTBIT(G723_40)
 #define SNDRV_PCM_FMTBIT_G723_40_1B    _SNDRV_PCM_FMTBIT(G723_40_1B)
+#define SNDRV_PCM_FMTBIT_DSD_U8                _SNDRV_PCM_FMTBIT(DSD_U8)
+#define SNDRV_PCM_FMTBIT_DSD_U16_LE    _SNDRV_PCM_FMTBIT(DSD_U16_LE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16           SNDRV_PCM_FMTBIT_S16_LE
@@ -659,7 +661,7 @@ static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime
  *
  * Checks whether enough free space is available on the playback buffer.
  *
- * Returns non-zero if available, or zero if not.
+ * Return: Non-zero if available, or zero if not.
  */
 static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream)
 {
@@ -673,7 +675,7 @@ static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream)
  *
  * Checks whether enough capture data is available on the capture buffer.
  *
- * Returns non-zero if available, or zero if not.
+ * Return: Non-zero if available, or zero if not.
  */
 static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream)
 {
@@ -685,10 +687,10 @@ static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream)
  * snd_pcm_playback_data - check whether any data exists on the playback buffer
  * @substream: the pcm substream instance
  *
- * Checks whether any data exists on the playback buffer. If stop_threshold
- * is bigger or equal to boundary, then this function returns always non-zero.
+ * Checks whether any data exists on the playback buffer.
  *
- * Returns non-zero if exists, or zero if not.
+ * Return: Non-zero if any data exists, or zero if not. If stop_threshold
+ * is bigger or equal to boundary, then this function returns always non-zero.
  */
 static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream)
 {
@@ -705,7 +707,7 @@ static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream)
  *
  * Checks whether the playback buffer is empty.
  *
- * Returns non-zero if empty, or zero if not.
+ * Return: Non-zero if empty, or zero if not.
  */
 static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream)
 {
@@ -719,7 +721,7 @@ static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream)
  *
  * Checks whether the capture buffer is empty.
  *
- * Returns non-zero if empty, or zero if not.
+ * Return: Non-zero if empty, or zero if not.
  */
 static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream)
 {
@@ -852,7 +854,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format);
  * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is CPU-endian, 0 if
+ * Return: 1 if the given PCM format is CPU-endian, 0 if
  * opposite, or a negative error code if endian not specified.
  */
 int snd_pcm_format_cpu_endian(snd_pcm_format_t format);
@@ -963,7 +965,7 @@ struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
  * contiguous in kernel virtual space, but not in physical memory.  Use this
  * if the buffer is accessed by kernel code but not by device DMA.
  *
- * Returns 1 if the buffer was changed, 0 if not changed, or a negative error
+ * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
  * code.
  */
 static int snd_pcm_lib_alloc_vmalloc_buffer
@@ -975,6 +977,9 @@ static int snd_pcm_lib_alloc_vmalloc_buffer
  *
  * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
  * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
+ *
+ * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
+ * code.
  */
 static int snd_pcm_lib_alloc_vmalloc_32_buffer
                        (struct snd_pcm_substream *substream, size_t size);
@@ -1070,6 +1075,8 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
 /**
  * snd_pcm_stream_str - Get a string naming the direction of a stream
  * @substream: the pcm substream instance
+ *
+ * Return: A string naming the direction of the stream.
  */
 static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
 {
index 3d84808..ae9a227 100644 (file)
@@ -95,14 +95,6 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
-/* Digital Audio Interface registration */
-int snd_soc_register_dai(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv);
-void snd_soc_unregister_dai(struct device *dev);
-int snd_soc_register_dais(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv, size_t count);
-void snd_soc_unregister_dais(struct device *dev, size_t count);
-
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir);
index 4429254..85c1522 100644 (file)
@@ -324,6 +324,8 @@ struct snd_soc_dai_link;
 struct snd_soc_platform_driver;
 struct snd_soc_codec;
 struct snd_soc_codec_driver;
+struct snd_soc_component;
+struct snd_soc_component_driver;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -381,6 +383,10 @@ int snd_soc_register_codec(struct device *dev,
                const struct snd_soc_codec_driver *codec_drv,
                struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_codec(struct device *dev);
+int snd_soc_register_component(struct device *dev,
+                        const struct snd_soc_component_driver *cmpnt_drv,
+                        struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_component(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
                                    unsigned int reg);
 int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
@@ -845,6 +851,20 @@ struct snd_soc_platform {
 #endif
 };
 
+struct snd_soc_component_driver {
+       const char *name;
+};
+
+struct snd_soc_component {
+       const char *name;
+       int id;
+       int num_dai;
+       struct device *dev;
+       struct list_head list;
+
+       const struct snd_soc_component_driver *driver;
+};
+
 struct snd_soc_dai_link {
        /* config - must be set by machine driver */
        const char *name;                       /* Codec name */
diff --git a/include/sound/tas5086.h b/include/sound/tas5086.h
new file mode 100644 (file)
index 0000000..aac481b
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _SND_SOC_CODEC_TAS5086_H_
+#define _SND_SOC_CODEC_TAS5086_H_
+
+#define TAS5086_CLK_IDX_MCLK   0
+#define TAS5086_CLK_IDX_SCLK   1
+
+#endif /* _SND_SOC_CODEC_TAS5086_H_ */
diff --git a/include/sound/tegra_wm8903.h b/include/sound/tegra_wm8903.h
deleted file mode 100644 (file)
index 57b202e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2011 NVIDIA, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __SOUND_TEGRA_WM38903_H
-#define __SOUND_TEGRA_WM38903_H
-
-struct tegra_wm8903_platform_data {
-       int gpio_spkr_en;
-       int gpio_hp_det;
-       int gpio_hp_mute;
-       int gpio_int_mic_en;
-       int gpio_ext_mic_en;
-};
-
-#endif
index 1774a5c..e3983d5 100644 (file)
@@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_G723_24_1B     ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
 #define        SNDRV_PCM_FORMAT_G723_40        ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
 #define        SNDRV_PCM_FORMAT_G723_40_1B     ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_G723_40_1B
+#define        SNDRV_PCM_FORMAT_DSD_U8         ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
+#define        SNDRV_PCM_FORMAT_DSD_U16_LE     ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
+#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_DSD_U16_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define        SNDRV_PCM_FORMAT_S16            SNDRV_PCM_FORMAT_S16_LE
index 8c7c2c9..d8aa206 100644 (file)
@@ -190,7 +190,7 @@ EXPORT_SYMBOL(snd_ctl_notify);
  * Allocates a new struct snd_kcontrol instance and copies the given template 
  * to the new instance. It does not copy volatile data (access).
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
                                        unsigned int access)
@@ -224,7 +224,7 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
  * template.  When the access field of ncontrol is 0, it's assumed as
  * READWRITE access. When the count field is 0, it's assumes as one.
  *
- * Returns the pointer of the newly generated instance, or NULL on failure.
+ * Return: The pointer of the newly generated instance, or %NULL on failure.
  */
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
                                  void *private_data)
@@ -322,9 +322,10 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
  * snd_ctl_new1() to the given card. Assigns also an unique
  * numid used for fast search.
  *
- * Returns zero if successful, or a negative error code on failure.
- *
  * It frees automatically the control which cannot be added.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ *
  */
 int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
@@ -380,9 +381,9 @@ EXPORT_SYMBOL(snd_ctl_add);
  * and the add_on_replace flag is set, the control is added.  If the
  * control exists, it is destroyed first.
  *
- * Returns zero if successful, or a negative error code on failure.
- *
  * It frees automatically the control which cannot be added or replaced.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
                    bool add_on_replace)
@@ -442,8 +443,8 @@ EXPORT_SYMBOL(snd_ctl_replace);
  * Removes the control from the card and then releases the instance.
  * You don't need to call snd_ctl_free_one(). You must be in
  * the write lock - down_write(&card->controls_rwsem).
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
@@ -470,8 +471,8 @@ EXPORT_SYMBOL(snd_ctl_remove);
  *
  * Finds the control instance with the given id, removes it from the
  * card list and releases it.
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
 {
@@ -498,8 +499,8 @@ EXPORT_SYMBOL(snd_ctl_remove_id);
  *
  * Finds the control instance with the given id, removes it from the
  * card list and releases it.
- * 
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
  */
 static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
                                   struct snd_ctl_elem_id *id)
@@ -541,7 +542,7 @@ error:
  * Finds the control instance with the given id, and activate or
  * inactivate the control together with notification, if changed.
  *
- * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
+ * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
  */
 int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
                        int active)
@@ -587,7 +588,7 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
  * Finds the control with the old id from the card, and replaces the
  * id with the new one.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
                      struct snd_ctl_elem_id *dst_id)
@@ -616,10 +617,11 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
  *
  * Finds the control instance with the given number-id from the card.
  *
- * Returns the pointer of the instance if found, or NULL if not.
- *
  * The caller must down card->controls_rwsem before calling this function
  * (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
  */
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
 {
@@ -643,10 +645,11 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
  *
  * Finds the control instance with the given id from the card.
  *
- * Returns the pointer of the instance if found, or NULL if not.
- *
  * The caller must down card->controls_rwsem before calling this function
  * (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
  */
 struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
                                     struct snd_ctl_elem_id *id)
@@ -1710,6 +1713,8 @@ EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
  * Sets all required fields in @info to their appropriate values.
  * If the control's accessibility is not the default (readable and writable),
  * the caller has to fill @info->access.
+ *
+ * Return: Zero.
  */
 int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
                      unsigned int items, const char *const names[])
index f03cb54..df88def 100644 (file)
@@ -39,7 +39,7 @@
  * The data pointer plays a role as the identifier, too, so the
  * pointer address must be unique and unchanged.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_device_new(struct snd_card *card, snd_device_type_t type,
                   void *device_data, struct snd_device_ops *ops)
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(snd_device_new);
  * callbacks, dev_disconnect and dev_free, corresponding to the state.
  * Then release the device.
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_free(struct snd_card *card, void *device_data)
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(snd_device_free);
  *
  * Usually called from snd_card_disconnect().
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_disconnect(struct snd_card *card, void *device_data)
@@ -151,7 +151,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
  * but it can be called later if any new devices are created after
  * invocation of snd_card_register().
  *
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
  * device not found.
  */
 int snd_device_register(struct snd_card *card, void *device_data)
index 3f7f662..d105073 100644 (file)
@@ -356,7 +356,7 @@ static const struct file_operations snd_hwdep_f_ops =
  * The callbacks (hwdep->ops) must be set on the returned instance
  * after this call manually by the caller.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_hwdep_new(struct snd_card *card, char *id, int device,
                  struct snd_hwdep **rhwdep)
index 5bb97e7..c9042b4 100644 (file)
@@ -89,7 +89,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer,
        char *nbuf;
 
        nsize = PAGE_ALIGN(nsize);
-       nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL);
+       nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL | __GFP_ZERO);
        if (! nbuf)
                return -ENOMEM;
 
@@ -105,7 +105,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer,
  *
  * Outputs the string on the procfs buffer just like printf().
  *
- * Returns the size of output string.
+ * Return: The size of output string, or a negative error code.
  */
 int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
 {
@@ -353,7 +353,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
                                goto __nomem;
                        data->rbuffer = buffer;
                        buffer->len = PAGE_SIZE;
-                       buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+                       buffer->buffer = kzalloc(buffer->len, GFP_KERNEL);
                        if (buffer->buffer == NULL)
                                goto __nomem;
                }
@@ -694,32 +694,27 @@ int snd_info_card_free(struct snd_card *card)
  *
  * Reads one line from the buffer and stores the string.
  *
- * Returns zero if successful, or 1 if error or EOF.
+ * Return: Zero if successful, or 1 if error or EOF.
  */
 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
 {
        int c = -1;
 
+       if (snd_BUG_ON(!buffer || !buffer->buffer))
+               return 1;
        if (len <= 0 || buffer->stop || buffer->error)
                return 1;
-       while (--len > 0) {
+       while (!buffer->stop) {
                c = buffer->buffer[buffer->curr++];
-               if (c == '\n') {
-                       if (buffer->curr >= buffer->size)
-                               buffer->stop = 1;
-                       break;
-               }
-               *line++ = c;
-               if (buffer->curr >= buffer->size) {
+               if (buffer->curr >= buffer->size)
                        buffer->stop = 1;
+               if (c == '\n')
                        break;
+               if (len) {
+                       len--;
+                       *line++ = c;
                }
        }
-       while (c != '\n' && !buffer->stop) {
-               c = buffer->buffer[buffer->curr++];
-               if (buffer->curr >= buffer->size)
-                       buffer->stop = 1;
-       }
        *line = '\0';
        return 0;
 }
@@ -735,7 +730,7 @@ EXPORT_SYMBOL(snd_info_get_line);
  * Parses the original string and copy a token to the given
  * string buffer.
  *
- * Returns the updated pointer of the original string so that
+ * Return: The updated pointer of the original string so that
  * it can be used for the next call.
  */
 const char *snd_info_get_str(char *dest, const char *src, int len)
@@ -774,7 +769,7 @@ EXPORT_SYMBOL(snd_info_get_str);
  * Usually called from other functions such as
  * snd_info_create_card_entry().
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 static struct snd_info_entry *snd_info_create_entry(const char *name)
 {
@@ -803,7 +798,7 @@ static struct snd_info_entry *snd_info_create_entry(const char *name)
  *
  * Creates a new info entry and assigns it to the given module.
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 struct snd_info_entry *snd_info_create_module_entry(struct module * module,
                                               const char *name,
@@ -827,7 +822,7 @@ EXPORT_SYMBOL(snd_info_create_module_entry);
  *
  * Creates a new info entry and assigns it to the given card.
  *
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
  */
 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
                                             const char *name,
@@ -893,7 +888,7 @@ static int snd_info_dev_register_entry(struct snd_device *device)
  * For releasing this entry, use snd_device_free() instead of
  * snd_info_free_entry(). 
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_card_proc_new(struct snd_card *card, const char *name,
                      struct snd_info_entry **entryp)
@@ -949,7 +944,7 @@ EXPORT_SYMBOL(snd_info_free_entry);
  *
  * Registers the proc info entry.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_info_register(struct snd_info_entry * entry)
 {
index 7b012d1..6ef0640 100644 (file)
@@ -144,7 +144,7 @@ static inline int init_info_for_card(struct snd_card *card)
  *  space for the driver to use freely.  The allocated struct is stored
  *  in the given card_ret pointer.
  *
- *  Returns zero if successful or a negative error code.
+ *  Return: Zero if successful or a negative error code.
  */
 int snd_card_create(int idx, const char *xid,
                    struct module *module, int extra_size,
@@ -337,7 +337,7 @@ static const struct file_operations snd_shutdown_f_ops =
  *
  *  Disconnects all APIs from the file-operations (user space).
  *
- *  Returns zero, otherwise a negative error code.
+ *  Return: Zero, otherwise a negative error code.
  *
  *  Note: The current implementation replaces all active file->f_op with special
  *        dummy file operations (they do nothing except release).
@@ -415,7 +415,7 @@ EXPORT_SYMBOL(snd_card_disconnect);
  *  devices automatically.  That is, you don't have to release the devices
  *  by yourself.
  *
- *  Returns zero. Frees all associated devices and frees the control
+ *  Return: Zero. Frees all associated devices and frees the control
  *  interface associated to given soundcard.
  */
 static int snd_card_do_free(struct snd_card *card)
@@ -677,7 +677,7 @@ static struct device_attribute card_number_attrs =
  *  external accesses.  Thus, you should call this function at the end
  *  of the initialization of the card.
  *
- *  Returns zero otherwise a negative error code if the registration failed.
+ *  Return: Zero otherwise a negative error code if the registration failed.
  */
 int snd_card_register(struct snd_card *card)
 {
@@ -849,7 +849,7 @@ int __exit snd_card_info_done(void)
  *  This function adds the component id string to the supported list.
  *  The component can be referred from the alsa-lib.
  *
- *  Returns zero otherwise a negative error code.
+ *  Return: Zero otherwise a negative error code.
  */
   
 int snd_component_add(struct snd_card *card, const char *component)
@@ -883,7 +883,7 @@ EXPORT_SYMBOL(snd_component_add);
  *  This linked-list is used to keep tracking the connection state,
  *  and to avoid the release of busy resources by hotplug.
  *
- *  Returns zero or a negative error code.
+ *  Return: zero or a negative error code.
  */
 int snd_card_file_add(struct snd_card *card, struct file *file)
 {
@@ -920,7 +920,7 @@ EXPORT_SYMBOL(snd_card_file_add);
  *  called beforehand, it processes the pending release of
  *  resources.
  *
- *  Returns zero or a negative error code.
+ *  Return: Zero or a negative error code.
  */
 int snd_card_file_remove(struct snd_card *card, struct file *file)
 {
@@ -959,6 +959,8 @@ EXPORT_SYMBOL(snd_card_file_remove);
  *
  *  Waits until the power-state is changed.
  *
+ *  Return: Zero if successful, or a negative error code.
+ *
  *  Note: the power lock must be active before call.
  */
 int snd_power_wait(struct snd_card *card, unsigned int power_state)
index c0f1208..e2b3861 100644 (file)
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(snd_dma_disable);
  * @dma: the dma number
  * @size: the dma transfer size
  *
- * Returns the current pointer in DMA tranfer buffer in bytes
+ * Return: The current pointer in DMA transfer buffer in bytes.
  */
 unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
 {
index a06b165..b35fe73 100644 (file)
@@ -98,8 +98,8 @@ static int snd_jack_dev_register(struct snd_device *device)
  *
  * Creates a new jack object.
  *
- * Returns zero if successful, or a negative error code on failure.
- * On success jjack will be initialised.
+ * Return: Zero if successful, or a negative error code on failure.
+ * On success @jjack will be initialised.
  */
 int snd_jack_new(struct snd_card *card, const char *id, int type,
                 struct snd_jack **jjack)
@@ -189,6 +189,8 @@ EXPORT_SYMBOL(snd_jack_set_parent);
  * using this abstraction.
  *
  * This function may only be called prior to registration of the jack.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
                     int keytype)
index 6915692..bdf826f 100644 (file)
@@ -81,7 +81,7 @@ static inline void dec_snd_pages(int order)
  *
  * Allocates the physically contiguous pages with the given size.
  *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ * Return: The pointer of the buffer, or %NULL if no enough memory.
  */
 void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
 {
@@ -175,9 +175,9 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
  *
  * Calls the memory-allocator function for the corresponding
  * buffer type.
- * 
- * Returns zero if the buffer with the given size is allocated successfully,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
  */
 int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                        struct snd_dma_buffer *dmab)
@@ -229,9 +229,9 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
  * buffer type.  When no space is left, this function reduces the size and
  * tries to allocate again.  The size actually allocated is stored in
  * res_size argument.
- * 
- * Returns zero if the buffer with the given size is allocated successfully,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
  */
 int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
                                 struct snd_dma_buffer *dmab)
@@ -292,7 +292,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
  * Looks for the reserved-buffer list and re-uses if the same buffer
  * is found in the list.  When the buffer is found, it's removed from the free list.
  *
- * Returns the size of buffer if the buffer is found, or zero if not found.
+ * Return: The size of buffer if the buffer is found, or zero if not found.
  */
 size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
@@ -326,8 +326,8 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
  * @id: the buffer id
  *
  * Reserves the given buffer as a reserved buffer.
- * 
- * Returns zero if successful, or a negative code at error.
+ *
+ * Return: Zero if successful, or a negative code on error.
  */
 int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
index 66a278d..36c0f1a 100644 (file)
@@ -33,7 +33,7 @@
  *
  * Copies the data from mmio-space to user-space.
  *
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
  */
 int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
 {
@@ -66,7 +66,7 @@ EXPORT_SYMBOL(copy_to_user_fromio);
  *
  * Copies the data from user-space to mmio-space.
  *
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
  */
 int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
 {
index 61798f8..17f45e8 100644 (file)
@@ -209,6 +209,8 @@ static char *snd_pcm_format_names[] = {
        FORMAT(G723_24_1B),
        FORMAT(G723_40),
        FORMAT(G723_40_1B),
+       FORMAT(DSD_U8),
+       FORMAT(DSD_U16_LE),
 };
 
 const char *snd_pcm_format_name(snd_pcm_format_t format)
@@ -637,7 +639,7 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea
  * calling this, i.e. zero must be given to the argument of
  * snd_pcm_new().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
 {
@@ -759,7 +761,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
  * The pcm operators have to be set afterwards to the new instance
  * via snd_pcm_set_ops().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new(struct snd_card *card, const char *id, int device,
                int playback_count, int capture_count, struct snd_pcm **rpcm)
@@ -787,7 +789,7 @@ EXPORT_SYMBOL(snd_pcm_new);
  * The pcm operators have to be set afterwards to the new instance
  * via snd_pcm_set_ops().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
        int playback_count, int capture_count,
index c4840ff..41b3dfe 100644 (file)
@@ -666,7 +666,8 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
  * The interval is changed to the range satisfying both intervals.
  * The interval status (min, max, integer, etc.) are evaluated.
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
@@ -865,7 +866,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
  * @nump: pointer to store the resultant numerator
  * @denp: pointer to store the resultant denominator
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_ratnum(struct snd_interval *i,
                        unsigned int rats_count, struct snd_ratnum *rats,
@@ -983,7 +985,8 @@ EXPORT_SYMBOL(snd_interval_ratnum);
  * @nump: pointer to store the resultant numerator
  * @denp: pointer to store the resultant denominator
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 static int snd_interval_ratden(struct snd_interval *i,
                               unsigned int rats_count, struct snd_ratden *rats,
@@ -1082,7 +1085,8 @@ static int snd_interval_ratden(struct snd_interval *i,
  * When mask is non-zero, only the elements corresponding to bit 1 are
  * evaluated.
  *
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_interval_list(struct snd_interval *i, unsigned int count,
                      const unsigned int *list, unsigned int mask)
@@ -1142,7 +1146,7 @@ static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned
  * @private: the private data pointer passed to function
  * @dep: the dependent variables
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
                        int var,
@@ -1200,6 +1204,8 @@ EXPORT_SYMBOL(snd_pcm_hw_rule_add);
  * @mask: the bitmap mask
  *
  * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
                               u_int32_t mask)
@@ -1220,6 +1226,8 @@ int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param
  * @mask: the 64bit bitmap mask
  *
  * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
                                 u_int64_t mask)
@@ -1240,6 +1248,9 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
  * @var: hw_params variable to apply the integer constraint
  *
  * Apply the constraint of integer to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
 {
@@ -1257,6 +1268,9 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
  * @max: the maximal value
  * 
  * Apply the min/max range constraint to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
  */
 int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
                                 unsigned int min, unsigned int max)
@@ -1288,6 +1302,8 @@ static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
  * @l: list
  * 
  * Apply the list of constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
                               unsigned int cond,
@@ -1322,6 +1338,8 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the ratnums constraint
  * @r: struct snd_ratnums constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
@@ -1355,6 +1373,8 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the ratdens constraint
  * @r: struct snd_ratdens constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
@@ -1386,6 +1406,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @width: sample bits width
  * @msbits: msbits width
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
                                 unsigned int cond,
@@ -1414,6 +1436,8 @@ static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
  * @cond: condition bits
  * @var: hw_params variable to apply the step constraint
  * @step: step size
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
                               unsigned int cond,
@@ -1444,6 +1468,8 @@ static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm
  * @runtime: PCM runtime instance
  * @cond: condition bits
  * @var: hw_params variable to apply the power-of-2 constraint
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
                               unsigned int cond,
@@ -1470,6 +1496,8 @@ static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
  * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
  * @runtime: PCM runtime instance
  * @base_rate: the rate at which the hardware does not resample
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
                               unsigned int base_rate)
@@ -1519,8 +1547,8 @@ EXPORT_SYMBOL(_snd_pcm_hw_params_any);
  * @var: parameter to retrieve
  * @dir: pointer to the direction (-1,0,1) or %NULL
  *
- * Return the value for field @var if it's fixed in configuration space
- * defined by @params. Return -%EINVAL otherwise.
+ * Return: The value for field @var if it's fixed in configuration space
+ * defined by @params. -%EINVAL otherwise.
  */
 int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
                           snd_pcm_hw_param_t var, int *dir)
@@ -1591,7 +1619,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
  *
  * Inside configuration space defined by @params remove from @var all
  * values > minimum. Reduce configuration space accordingly.
- * Return the minimum.
+ *
+ * Return: The minimum, or a negative error code on failure.
  */
 int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
                           struct snd_pcm_hw_params *params, 
@@ -1637,7 +1666,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
  *
  * Inside configuration space defined by @params remove from @var all
  * values < maximum. Reduce configuration space accordingly.
- * Return the maximum.
+ *
+ * Return: The maximum, or a negative error code on failure.
  */
 int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
                          struct snd_pcm_hw_params *params,
@@ -1665,6 +1695,8 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last);
  * The configuration chosen is that obtained fixing in this order:
  * first access, first format, first subformat, min channels,
  * min rate, min period time, max buffer size, min tick time
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
                             struct snd_pcm_hw_params *params)
@@ -1771,7 +1803,7 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
  * Processes the generic ioctl commands for PCM.
  * Can be passed as the ioctl callback for PCM ops.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
                      unsigned int cmd, void *arg)
@@ -2510,7 +2542,7 @@ static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
  * @info_ret: store struct snd_pcm_chmap instance if non-NULL
  *
  * Create channel-mapping control elements assigned to the given PCM stream(s).
- * Returns zero if succeed, or a negative error value.
+ * Return: Zero if successful, or a negative error value.
  */
 int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
                           const struct snd_pcm_chmap_elem *chmap,
index 69e01c4..0af622c 100644 (file)
@@ -95,7 +95,7 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream
  *
  * Releases the pre-allocated buffer of the given substream.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
 {
@@ -115,7 +115,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
  *
  * Releases all the pre-allocated buffers on the given pcm.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
 {
@@ -265,7 +265,7 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
  * destruction time.  The dma_buf_id must be unique for all systems
  * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
                                  int type, struct device *data,
@@ -289,7 +289,7 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
  * Do pre-allocation to all substreams of the given pcm for the
  * specified DMA type.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
                                          int type, void *data,
@@ -313,8 +313,9 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
  * @substream: the pcm substream instance
  * @offset: the buffer offset
  *
- * Returns the page struct at the given buffer offset.
  * Used as the page callback of PCM ops.
+ *
+ * Return: The page struct at the given buffer offset. %NULL on failure.
  */
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
 {
@@ -337,7 +338,7 @@ EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
  * Allocates the DMA buffer on the BUS type given earlier to
  * snd_pcm_lib_preallocate_xxx_pages().
  *
- * Returns 1 if the buffer is changed, 0 if not changed, or a negative
+ * Return: 1 if the buffer is changed, 0 if not changed, or a negative
  * code on failure.
  */
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
@@ -390,7 +391,7 @@ EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
  *
  * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages().
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
 {
@@ -437,6 +438,8 @@ EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
  * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
  * @substream: the substream with a buffer allocated by
  *     snd_pcm_lib_alloc_vmalloc_buffer()
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
 {
@@ -458,6 +461,8 @@ EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
  * @offset: offset in the buffer
  *
  * This function is to be used as the page callback in the PCM ops.
+ *
+ * Return: The page struct, or %NULL on failure.
  */
 struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
                                          unsigned long offset)
index d4fc1bf..43f24cc 100644 (file)
@@ -140,6 +140,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
                .width = 5, .phys = 5, .le = -1, .signd = -1,
                .silence = {},
        },
+       [SNDRV_PCM_FORMAT_DSD_U8] = {
+               .width = 8, .phys = 8, .le = 1, .signd = 0,
+               .silence = {},
+       },
+       [SNDRV_PCM_FORMAT_DSD_U16_LE] = {
+               .width = 16, .phys = 16, .le = 1, .signd = 0,
+               .silence = {},
+       },
        /* FIXME: the following three formats are not defined properly yet */
        [SNDRV_PCM_FORMAT_MPEG] = {
                .le = -1, .signd = -1,
@@ -213,7 +221,7 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
  * snd_pcm_format_signed - Check the PCM format is signed linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is signed linear, 0 if unsigned
+ * Return: 1 if the given PCM format is signed linear, 0 if unsigned
  * linear, and a negative error code for non-linear formats.
  */
 int snd_pcm_format_signed(snd_pcm_format_t format)
@@ -232,7 +240,7 @@ EXPORT_SYMBOL(snd_pcm_format_signed);
  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is unsigned linear, 0 if signed
+ * Return: 1 if the given PCM format is unsigned linear, 0 if signed
  * linear, and a negative error code for non-linear formats.
  */
 int snd_pcm_format_unsigned(snd_pcm_format_t format)
@@ -251,7 +259,7 @@ EXPORT_SYMBOL(snd_pcm_format_unsigned);
  * snd_pcm_format_linear - Check the PCM format is linear
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is linear, 0 if not.
+ * Return: 1 if the given PCM format is linear, 0 if not.
  */
 int snd_pcm_format_linear(snd_pcm_format_t format)
 {
@@ -264,7 +272,7 @@ EXPORT_SYMBOL(snd_pcm_format_linear);
  * snd_pcm_format_little_endian - Check the PCM format is little-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is little-endian, 0 if
+ * Return: 1 if the given PCM format is little-endian, 0 if
  * big-endian, or a negative error code if endian not specified.
  */
 int snd_pcm_format_little_endian(snd_pcm_format_t format)
@@ -283,7 +291,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian);
  * snd_pcm_format_big_endian - Check the PCM format is big-endian
  * @format: the format to check
  *
- * Returns 1 if the given PCM format is big-endian, 0 if
+ * Return: 1 if the given PCM format is big-endian, 0 if
  * little-endian, or a negative error code if endian not specified.
  */
 int snd_pcm_format_big_endian(snd_pcm_format_t format)
@@ -302,7 +310,7 @@ EXPORT_SYMBOL(snd_pcm_format_big_endian);
  * snd_pcm_format_width - return the bit-width of the format
  * @format: the format to check
  *
- * Returns the bit-width of the format, or a negative error code
+ * Return: The bit-width of the format, or a negative error code
  * if unknown format.
  */
 int snd_pcm_format_width(snd_pcm_format_t format)
@@ -321,7 +329,7 @@ EXPORT_SYMBOL(snd_pcm_format_width);
  * snd_pcm_format_physical_width - return the physical bit-width of the format
  * @format: the format to check
  *
- * Returns the physical bit-width of the format, or a negative error code
+ * Return: The physical bit-width of the format, or a negative error code
  * if unknown format.
  */
 int snd_pcm_format_physical_width(snd_pcm_format_t format)
@@ -341,7 +349,7 @@ EXPORT_SYMBOL(snd_pcm_format_physical_width);
  * @format: the format to check
  * @samples: sampling rate
  *
- * Returns the byte size of the given samples for the format, or a
+ * Return: The byte size of the given samples for the format, or a
  * negative error code if unknown format.
  */
 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
@@ -358,7 +366,7 @@ EXPORT_SYMBOL(snd_pcm_format_size);
  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
  * @format: the format to check
  *
- * Returns the format pattern to fill or NULL if error.
+ * Return: The format pattern to fill or %NULL if error.
  */
 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
 {
@@ -379,7 +387,7 @@ EXPORT_SYMBOL(snd_pcm_format_silence_64);
  *
  * Sets the silence data on the buffer for the given samples.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
 {
@@ -449,7 +457,7 @@ EXPORT_SYMBOL(snd_pcm_format_set_silence);
  * Determines the rate_min and rate_max fields from the rates bits of
  * the given runtime->hw.
  *
- * Returns zero if successful.
+ * Return: Zero if successful.
  */
 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
 {
@@ -475,7 +483,7 @@ EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
  * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
  * @rate: the sample rate to convert
  *
- * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
+ * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
  * SNDRV_PCM_RATE_KNOT for an unknown rate.
  */
 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
@@ -493,8 +501,8 @@ EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
  * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
  * @rate_bit: the rate bit to convert
  *
- * Returns the sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
- * or 0 for an unknown rate bit
+ * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
+ * or 0 for an unknown rate bit.
  */
 unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
 {
index 71ae86c..5bce915 100644 (file)
@@ -898,6 +898,8 @@ static struct action_ops snd_pcm_action_start = {
 /**
  * snd_pcm_start - start all linked streams
  * @substream: the PCM substream instance
+ *
+ * Return: Zero if successful, or a negative error code.
  */
 int snd_pcm_start(struct snd_pcm_substream *substream)
 {
@@ -951,6 +953,8 @@ static struct action_ops snd_pcm_action_stop = {
  * @state: PCM state after stopping the stream
  *
  * The state of each stream is then changed to the given state unconditionally.
+ *
+ * Return: Zero if succesful, or a negative error code.
  */
 int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
 {
@@ -965,6 +969,8 @@ EXPORT_SYMBOL(snd_pcm_stop);
  *
  * After stopping, the state is changed to SETUP.
  * Unlike snd_pcm_stop(), this affects only the given stream.
+ *
+ * Return: Zero if succesful, or a negative error code.
  */
 int snd_pcm_drain_done(struct snd_pcm_substream *substream)
 {
@@ -1098,6 +1104,9 @@ static struct action_ops snd_pcm_action_suspend = {
  * @substream: the PCM substream
  *
  * After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @substream is %NULL), or a negative error
+ * code.
  */
 int snd_pcm_suspend(struct snd_pcm_substream *substream)
 {
@@ -1120,6 +1129,8 @@ EXPORT_SYMBOL(snd_pcm_suspend);
  * @pcm: the PCM instance
  *
  * After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
  */
 int snd_pcm_suspend_all(struct snd_pcm *pcm)
 {
@@ -1343,6 +1354,8 @@ static struct action_ops snd_pcm_action_prepare = {
  * snd_pcm_prepare - prepare the PCM substream to be triggerable
  * @substream: the PCM substream instance
  * @file: file to refer f_flags
+ *
+ * Return: Zero if successful, or a negative error code.
  */
 static int snd_pcm_prepare(struct snd_pcm_substream *substream,
                           struct file *file)
index 1bb95ae..7b596b5 100644 (file)
@@ -863,7 +863,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
  *
  * Reads the data from the internal buffer.
  *
- * Returns the size of read data, or a negative error code on failure.
+ * Return: The size of read data, or a negative error code on failure.
  */
 int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                        const unsigned char *buffer, int count)
@@ -1024,8 +1024,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
 /**
  * snd_rawmidi_transmit_empty - check whether the output buffer is empty
  * @substream: the rawmidi substream
- * 
- * Returns 1 if the internal output buffer is empty, 0 if not.
+ *
+ * Return: 1 if the internal output buffer is empty, 0 if not.
  */
 int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
 {
@@ -1055,7 +1055,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
  * and call snd_rawmidi_transmit_ack() after the transmission is
  * finished.
  *
- * Returns the size of copied data, or a negative error code on failure.
+ * Return: The size of copied data, or a negative error code on failure.
  */
 int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count)
@@ -1107,7 +1107,7 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
  * the given size and updates the condition.
  * Call after the transmission is finished.
  *
- * Returns the advanced size if successful, or a negative error code on failure.
+ * Return: The advanced size if successful, or a negative error code on failure.
  */
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
 {
@@ -1140,7 +1140,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
  * 
  * Copies data from the buffer to the device and advances the pointer.
  *
- * Returns the copied size if successful, or a negative error code on failure.
+ * Return: The copied size if successful, or a negative error code on failure.
  */
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count)
@@ -1438,7 +1438,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
  * Creates a new rawmidi instance.
  * Use snd_rawmidi_set_ops() to set the operators to the new instance.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                    int output_count, int input_count,
index 70ccdab..f002bd9 100644 (file)
@@ -102,6 +102,9 @@ static void snd_request_other(int minor)
  * This function increments the reference counter of the card instance
  * if an associated instance with the given minor number and type is found.
  * The caller must call snd_card_unref() appropriately later.
+ *
+ * Return: The user data pointer if the specified device is found. %NULL
+ * otherwise.
  */
 void *snd_lookup_minor_data(unsigned int minor, int type)
 {
@@ -261,7 +264,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
  * Registers an ALSA device file for the given card.
  * The operators have to be set in reg parameter.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
                                const struct file_operations *f_ops,
@@ -339,7 +342,7 @@ static int find_snd_minor(int type, struct snd_card *card, int dev)
  * Unregisters the device file already registered via
  * snd_register_device().
  *
- * Returns zero if sucecessful, or a negative error code on failure
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_unregister_device(int type, struct snd_card *card, int dev)
 {
index 0097f36..02f90b4 100644 (file)
@@ -365,8 +365,7 @@ static void master_free(struct snd_kcontrol *kcontrol)
  * @name: name string of the control element to create
  * @tlv: optional TLV int array for dB information
  *
- * Creates a virtual matster control with the given name string.
- * Returns the created control element, or NULL for errors (ENOMEM).
+ * Creates a virtual master control with the given name string.
  *
  * After creating a vmaster element, you can add the slave controls
  * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
@@ -375,6 +374,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
  * for dB scale of the master control.  It should be a single element
  * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
  * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
+ *
+ * Return: The created control element, or %NULL for errors (ENOMEM).
  */
 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
                                                 const unsigned int *tlv)
@@ -426,6 +427,8 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master);
  *
  * Adds the given hook to the vmaster control element so that it's called
  * at each time when the value is changed.
+ *
+ * Return: Zero.
  */
 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
                             void (*hook)(void *private_data, int),
index 4608c2c..e3a90d0 100644 (file)
@@ -129,6 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
  * @dev_id: mpu401 instance
  *
  * Processes the interrupt for MPU401-UART i/o.
+ *
+ * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
 {
@@ -148,6 +150,8 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
  * @dev_id: mpu401 instance
  *
  * Processes the interrupt for MPU401-UART output.
+ *
+ * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
 {
@@ -519,7 +523,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
  * not the mpu401 instance itself.  To access to the mpu401 instance,
  * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast).
  *
- * Returns zero if successful, or a negative error code.
+ * Return: Zero if successful, or a negative error code.
  */
 int snd_mpu401_uart_new(struct snd_card *card, int device,
                        unsigned short hardware,
index 7d42c54..851a1da 100644 (file)
@@ -626,13 +626,12 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_
         */
 
 
-       detected_devc = kmalloc(sizeof(sb_devc), GFP_KERNEL);
+       detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL);
        if (detected_devc == NULL)
        {
                printk(KERN_ERR "sb: Can't allocate memory for device information\n");
                return 0;
        }
-       memcpy(detected_devc, devc, sizeof(sb_devc));
        MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
        return 1;
 }
index 8e514a6..5433c6f 100644 (file)
@@ -352,23 +352,26 @@ int probe_uart401(struct address_info *hw_config, struct module *owner)
                goto cleanup_irq;
        }
        conf_printf(name, hw_config);
-       midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
+       midi_devs[devc->my_dev] = kmemdup(&uart401_operations,
+                                         sizeof(struct midi_operations),
+                                         GFP_KERNEL);
        if (!midi_devs[devc->my_dev]) {
                printk(KERN_ERR "uart401: Failed to allocate memory\n");
                goto cleanup_unload_mididev;
        }
-       memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations));
 
        if (owner)
                midi_devs[devc->my_dev]->owner = owner;
        
        midi_devs[devc->my_dev]->devc = devc;
-       midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
+       midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth,
+                                                    sizeof(struct synth_operations),
+                                                    GFP_KERNEL);
+
        if (!midi_devs[devc->my_dev]->converter) {
                printk(KERN_WARNING "uart401: Failed to allocate memory\n");
                goto cleanup_midi_devs;
        }
-       memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations));
        strcpy(midi_devs[devc->my_dev]->info.name, name);
        midi_devs[devc->my_dev]->converter->id = "UART401";
        midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev;
index 8b0f996..d37c683 100644 (file)
@@ -299,7 +299,7 @@ EXPORT_SYMBOL(snd_ac97_write);
  * Reads a value from the given register.  This will invoke the read
  * callback directly after the register check.
  *
- * Returns the read value.
+ * Return: The read value.
  */
 unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
@@ -352,7 +352,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache);
  * Compares the value with the register cache and updates the value
  * only when the value is changed.
  *
- * Returns 1 if the value is changed, 0 if no change, or a negative
+ * Return: 1 if the value is changed, 0 if no change, or a negative
  * code on failure.
  */
 int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value)
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(snd_ac97_update);
  * Updates the masked-bits on the given register only when the value
  * is changed.
  *
- * Returns 1 if the bits are changed, 0 if no change, or a negative
+ * Return: 1 if the bits are changed, 0 if no change, or a negative
  * code on failure.
  */
 int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value)
@@ -1836,7 +1836,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m
  * snd_ac97_get_short_name - retrieve codec name
  * @ac97: the codec instance
  *
- * Returns the short identifying name of the codec.
+ * Return: The short identifying name of the codec.
  */
 const char *snd_ac97_get_short_name(struct snd_ac97 *ac97)
 {
@@ -1910,7 +1910,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem)
  * The AC97 bus instance is registered as a low-level device, so you don't
  * have to release it manually.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
                 void *private_data, struct snd_ac97_bus **rbus)
@@ -2006,7 +2006,7 @@ static void do_update_power(struct work_struct *work)
  * The ac97 instance is registered as a low-level device, so you don't
  * have to release it manually.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97)
 {
@@ -2373,6 +2373,8 @@ static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
  * @powerup: non-zero when power up the part
  *
  * Update the AC97 powerdown register bits of the given part.
+ *
+ * Return: Zero.
  */
 int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
 {
@@ -2885,7 +2887,7 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr)
  * headphone (true line-out) control as "Master".
  * The quirk-list must be terminated with a zero-filled entry.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 
 int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override)
index f1488fc..eab0fc9 100644 (file)
@@ -253,7 +253,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate)
  * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF
  * status bits.
  *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
 {
@@ -440,6 +440,8 @@ static unsigned int get_rates(struct ac97_pcm *pcm, unsigned int cidx, unsigned
  * It assigns available AC97 slots for given PCMs. If none or only
  * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members
  * are reduced and might be zero.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_assign(struct snd_ac97_bus *bus,
                        unsigned short pcms_count,
@@ -562,6 +564,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_assign);
  * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm
  *
  * It locks the specified slots and sets the given rate to AC97 registers.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
                      enum ac97_pcm_cfg cfg, unsigned short slots)
@@ -644,6 +648,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_open);
  * @pcm: the ac97 pcm instance
  *
  * It frees the locked AC97 slots.
+ *
+ * Return: Zero.
  */
 int snd_ac97_pcm_close(struct ac97_pcm *pcm)
 {
@@ -718,6 +724,8 @@ static int double_rate_hw_constraint_channels(struct snd_pcm_hw_params *params,
  *
  * Installs the hardware constraint rules to prevent using double rates and
  * more than two channels at the same time.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime)
 {
index a3ea76a..7c11d46 100644 (file)
@@ -119,6 +119,32 @@ static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
        }
 }
 
+static bool can_be_headset_mic(struct hda_codec *codec,
+                              struct auto_pin_cfg_item *item,
+                              int seq_number)
+{
+       int attr;
+       unsigned int def_conf;
+       if (item->type != AUTO_PIN_MIC)
+               return false;
+
+       if (item->is_headset_mic || item->is_headphone_mic)
+               return false; /* Already assigned */
+
+       def_conf = snd_hda_codec_get_pincfg(codec, item->pin);
+       attr = snd_hda_get_input_pin_attr(def_conf);
+       if (attr <= INPUT_PIN_ATTR_DOCK)
+               return false;
+
+       if (seq_number >= 0) {
+               int seq = get_defcfg_sequence(def_conf);
+               if (seq != seq_number)
+                       return false;
+       }
+
+       return true;
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -260,6 +286,38 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                }
        }
 
+       /* Find a pin that could be a headset or headphone mic */
+       if (cond_flags & HDA_PINCFG_HEADSET_MIC || cond_flags & HDA_PINCFG_HEADPHONE_MIC) {
+               bool hsmic = !!(cond_flags & HDA_PINCFG_HEADSET_MIC);
+               bool hpmic = !!(cond_flags & HDA_PINCFG_HEADPHONE_MIC);
+               for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++)
+                       if (hsmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xc)) {
+                               cfg->inputs[i].is_headset_mic = 1;
+                               hsmic = false;
+                       } else if (hpmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xd)) {
+                               cfg->inputs[i].is_headphone_mic = 1;
+                               hpmic = false;
+                       }
+
+               /* If we didn't find our sequence number mark, fall back to any sequence number */
+               for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) {
+                       if (!can_be_headset_mic(codec, &cfg->inputs[i], -1))
+                               continue;
+                       if (hsmic) {
+                               cfg->inputs[i].is_headset_mic = 1;
+                               hsmic = false;
+                       } else if (hpmic) {
+                               cfg->inputs[i].is_headphone_mic = 1;
+                               hpmic = false;
+                       }
+               }
+
+               if (hsmic)
+                       snd_printdd("Told to look for a headset mic, but didn't find any.\n");
+               if (hpmic)
+                       snd_printdd("Told to look for a headphone mic, but didn't find any.\n");
+       }
+
        /* FIX-UP:
         * If no line-out is defined but multiple HPs are found,
         * some of them might be the real line-outs.
@@ -388,6 +446,7 @@ EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
  */
 
 static const char *hda_get_input_pin_label(struct hda_codec *codec,
+                                          const struct auto_pin_cfg_item *item,
                                           hda_nid_t pin, bool check_location)
 {
        unsigned int def_conf;
@@ -400,6 +459,10 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
 
        switch (get_defcfg_device(def_conf)) {
        case AC_JACK_MIC_IN:
+               if (item && item->is_headset_mic)
+                       return "Headset Mic";
+               if (item && item->is_headphone_mic)
+                       return "Headphone Mic";
                if (!check_location)
                        return "Mic";
                attr = snd_hda_get_input_pin_attr(def_conf);
@@ -480,7 +543,8 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
                has_multiple_pins = 1;
        if (has_multiple_pins && type == AUTO_PIN_MIC)
                has_multiple_pins &= check_mic_location_need(codec, cfg, input);
-       return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+       return hda_get_input_pin_label(codec, &cfg->inputs[input],
+                                      cfg->inputs[input].pin,
                                       has_multiple_pins);
 }
 EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
@@ -649,7 +713,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
                        }
                }
                if (!name)
-                       name = hda_get_input_pin_label(codec, nid, true);
+                       name = hda_get_input_pin_label(codec, NULL, nid, true);
                break;
        }
        if (!name)
index f748071..e941f60 100644 (file)
@@ -36,6 +36,8 @@ enum {
 struct auto_pin_cfg_item {
        hda_nid_t pin;
        int type;
+       unsigned int is_headset_mic:1;
+       unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
 };
 
 struct auto_pin_cfg;
@@ -78,8 +80,10 @@ struct auto_pin_cfg {
 };
 
 /* bit-flags for snd_hda_parse_pin_def_config() behavior */
-#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
-#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
+#define HDA_PINCFG_NO_HP_FIXUP   (1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP   (1 << 1) /* don't take other outs as LO */
+#define HDA_PINCFG_HEADSET_MIC   (1 << 2) /* Try to find headset mic; mark seq number as 0xc to trigger */
+#define HDA_PINCFG_HEADPHONE_MIC (1 << 3) /* Try to find headphone mic; mark seq number as 0xd to trigger */
 
 int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                             struct auto_pin_cfg *cfg,
@@ -90,4 +94,25 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 #define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
        snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
 
+static inline int auto_cfg_hp_outs(const struct auto_pin_cfg *cfg)
+{
+       return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
+              cfg->line_outs : cfg->hp_outs;
+}
+static inline const hda_nid_t *auto_cfg_hp_pins(const struct auto_pin_cfg *cfg)
+{
+       return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
+              cfg->line_out_pins : cfg->hp_pins;
+}
+static inline int auto_cfg_speaker_outs(const struct auto_pin_cfg *cfg)
+{
+       return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
+              cfg->line_outs : cfg->speaker_outs;
+}
+static inline const hda_nid_t *auto_cfg_speaker_pins(const struct auto_pin_cfg *cfg)
+{
+       return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
+              cfg->line_out_pins : cfg->speaker_pins;
+}
+
 #endif /* __SOUND_HDA_AUTO_PARSER_H */
index 0849aac..63c9909 100644 (file)
@@ -39,13 +39,23 @@ static void snd_hda_generate_beep(struct work_struct *work)
        struct hda_beep *beep =
                container_of(work, struct hda_beep, beep_work);
        struct hda_codec *codec = beep->codec;
+       int tone;
 
        if (!beep->enabled)
                return;
 
+       tone = beep->tone;
+       if (tone && !beep->playing) {
+               snd_hda_power_up(codec);
+               beep->playing = 1;
+       }
        /* generate tone */
        snd_hda_codec_write(codec, beep->nid, 0,
-                       AC_VERB_SET_BEEP_CONTROL, beep->tone);
+                           AC_VERB_SET_BEEP_CONTROL, tone);
+       if (!tone && beep->playing) {
+               beep->playing = 0;
+               snd_hda_power_down(codec);
+       }
 }
 
 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
@@ -115,14 +125,23 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
        return 0;
 }
 
+static void turn_off_beep(struct hda_beep *beep)
+{
+       cancel_work_sync(&beep->beep_work);
+       if (beep->playing) {
+               /* turn off beep */
+               snd_hda_codec_write(beep->codec, beep->nid, 0,
+                                   AC_VERB_SET_BEEP_CONTROL, 0);
+               beep->playing = 0;
+               snd_hda_power_down(beep->codec);
+       }
+}
+
 static void snd_hda_do_detach(struct hda_beep *beep)
 {
        input_unregister_device(beep->dev);
        beep->dev = NULL;
-       cancel_work_sync(&beep->beep_work);
-       /* turn off beep for sure */
-       snd_hda_codec_write(beep->codec, beep->nid, 0,
-                                 AC_VERB_SET_BEEP_CONTROL, 0);
+       turn_off_beep(beep);
 }
 
 static int snd_hda_do_attach(struct hda_beep *beep)
@@ -170,12 +189,8 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
        enable = !!enable;
        if (beep->enabled != enable) {
                beep->enabled = enable;
-               if (!enable) {
-                       cancel_work_sync(&beep->beep_work);
-                       /* turn off beep */
-                       snd_hda_codec_write(beep->codec, beep->nid, 0,
-                                                 AC_VERB_SET_BEEP_CONTROL, 0);
-               }
+               if (!enable)
+                       turn_off_beep(beep);
                return 1;
        }
        return 0;
@@ -198,7 +213,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        snprintf(beep->phys, sizeof(beep->phys),
                "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
        /* enable linear scale */
-       snd_hda_codec_write(codec, nid, 0,
+       snd_hda_codec_write_cache(codec, nid, 0,
                AC_VERB_SET_DIGI_CONVERT_2, 0x01);
 
        beep->nid = nid;
index 4dc6933..cb88464 100644 (file)
@@ -36,6 +36,7 @@ struct hda_beep {
        hda_nid_t nid;
        unsigned int enabled:1;
        unsigned int linear_tone:1;     /* linear tone for IDT/STAC codec */
+       unsigned int playing:1;
        struct work_struct beep_work; /* scheduled task for beep event */
        struct mutex mutex;
 };
index 4aba764..6f9b647 100644 (file)
@@ -1065,8 +1065,14 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
 {
        struct hda_pincfg *pin;
 
+       /* the check below may be invalid when pins are added by a fixup
+        * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled
+        * for now
+        */
+       /*
        if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
                return -EINVAL;
+       */
 
        pin = look_up_pincfg(codec, list, nid);
        if (!pin) {
@@ -1300,8 +1306,6 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
 
 static unsigned int hda_set_power_state(struct hda_codec *codec,
                                unsigned int power_state);
-static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
-                                        unsigned int power_state);
 
 /**
  * snd_hda_codec_new - create a HDA codec
@@ -1422,7 +1426,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
 #endif
        codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
                                        AC_PWRST_EPSS);
-       codec->power_filter = default_power_filter;
 
        /* power-up all before initialization */
        hda_set_power_state(codec, AC_PWRST_D0);
@@ -2787,6 +2790,11 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
 {
        if (!hook->hook || !hook->codec)
                return;
+       /* don't call vmaster hook in the destructor since it might have
+        * been already destroyed
+        */
+       if (hook->codec->bus->shutdown)
+               return;
        switch (hook->mute_mode) {
        case HDA_VMUTE_FOLLOW_MASTER:
                snd_ctl_sync_vmaster_hook(hook->sw_kctl);
@@ -3770,8 +3778,9 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
 }
 
 /* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */
-static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
-                                        unsigned int power_state)
+unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
+                                            hda_nid_t nid,
+                                            unsigned int power_state)
 {
        if (power_state == AC_PWRST_D3 &&
            get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
@@ -3783,6 +3792,7 @@ static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
        }
        return power_state;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_eapd_power_filter);
 
 /*
  * set power state of the codec, and return the power state
@@ -3827,8 +3837,8 @@ static void sync_power_up_states(struct hda_codec *codec)
        hda_nid_t nid = codec->start_nid;
        int i;
 
-       /* don't care if no or standard filter is used */
-       if (!codec->power_filter || codec->power_filter == default_power_filter)
+       /* don't care if no filter is used */
+       if (!codec->power_filter)
                return;
 
        for (i = 0; i < codec->num_nodes; i++, nid++) {
@@ -5546,14 +5556,12 @@ void *snd_array_new(struct snd_array *array)
        if (array->used >= array->alloced) {
                int num = array->alloced + array->alloc_align;
                int size = (num + 1) * array->elem_size;
-               int oldsize = array->alloced * array->elem_size;
                void *nlist;
                if (snd_BUG_ON(num >= 4096))
                        return NULL;
-               nlist = krealloc(array->list, size, GFP_KERNEL);
+               nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
                if (!nlist)
                        return NULL;
-               memset(nlist + oldsize, 0, size - oldsize);
                array->list = nlist;
                array->alloced = num;
        }
index 23ca172..c93f902 100644 (file)
@@ -757,6 +757,9 @@ struct hda_pcm_ops {
                       struct snd_pcm_substream *substream);
        int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
                       struct snd_pcm_substream *substream);
+       unsigned int (*get_delay)(struct hda_pcm_stream *info,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream);
 };
 
 /* PCM information for each substream */
index 2dbe767..ac079f9 100644 (file)
@@ -34,6 +34,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
+#include "hda_beep.h"
 #include "hda_generic.h"
 
 
@@ -150,15 +151,25 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
        if (val >= 0)
                spec->add_stereo_mix_input = !!val;
+       /* the following two are just for compatibility */
        val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
        if (val >= 0)
-               spec->add_out_jack_modes = !!val;
+               spec->add_jack_modes = !!val;
        val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
        if (val >= 0)
-               spec->add_in_jack_modes = !!val;
+               spec->add_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_jack_modes");
+       if (val >= 0)
+               spec->add_jack_modes = !!val;
        val = snd_hda_get_bool_hint(codec, "power_down_unused");
        if (val >= 0)
                spec->power_down_unused = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_hp_mic");
+       if (val >= 0)
+               spec->hp_mic = !!val;
+       val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
+       if (val >= 0)
+               spec->suppress_hp_mic_detect = !val;
 
        if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
                spec->mixer_nid = val;
@@ -996,7 +1007,7 @@ enum {
        /* Primary DAC shared with main surrounds */
        BAD_SHARED_SURROUND = 0x100,
        /* No independent HP possible */
-       BAD_NO_INDEP_HP = 0x40,
+       BAD_NO_INDEP_HP = 0x10,
        /* Primary DAC shared with main CLFE */
        BAD_SHARED_CLFE = 0x10,
        /* Primary DAC shared with extra surrounds */
@@ -1051,16 +1062,7 @@ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
        return badness;
 }
 
-struct badness_table {
-       int no_primary_dac;     /* no primary DAC */
-       int no_dac;             /* no secondary DACs */
-       int shared_primary;     /* primary DAC is shared with main output */
-       int shared_surr;        /* secondary DAC shared with main or primary */
-       int shared_clfe;        /* third DAC shared with main or primary */
-       int shared_surr_main;   /* secondary DAC sahred with main/DAC0 */
-};
-
-static struct badness_table main_out_badness = {
+const struct badness_table hda_main_out_badness = {
        .no_primary_dac = BAD_NO_PRIMARY_DAC,
        .no_dac = BAD_NO_DAC,
        .shared_primary = BAD_NO_PRIMARY_DAC,
@@ -1068,8 +1070,9 @@ static struct badness_table main_out_badness = {
        .shared_clfe = BAD_SHARED_CLFE,
        .shared_surr_main = BAD_SHARED_SURROUND,
 };
+EXPORT_SYMBOL_HDA(hda_main_out_badness);
 
-static struct badness_table extra_out_badness = {
+const struct badness_table hda_extra_out_badness = {
        .no_primary_dac = BAD_NO_DAC,
        .no_dac = BAD_NO_DAC,
        .shared_primary = BAD_NO_EXTRA_DAC,
@@ -1077,6 +1080,7 @@ static struct badness_table extra_out_badness = {
        .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
        .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
 };
+EXPORT_SYMBOL_HDA(hda_extra_out_badness);
 
 /* get the DAC of the primary output corresponding to the given array index */
 static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
@@ -1367,22 +1371,25 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct nid_path *path;
-       hda_nid_t dac, pin;
+       hda_nid_t path_dac, dac, pin;
 
        path = snd_hda_get_path_from_idx(codec, path_idx);
        if (!path || !path->depth ||
            is_nid_contained(path, spec->mixer_nid))
                return 0;
-       dac = path->path[0];
+       path_dac = path->path[0];
+       dac = spec->private_dac_nids[0];
        pin = path->path[path->depth - 1];
        path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
        if (!path) {
-               if (dac != spec->multiout.dac_nids[0])
-                       dac = spec->multiout.dac_nids[0];
+               if (dac != path_dac)
+                       dac = path_dac;
                else if (spec->multiout.hp_out_nid[0])
                        dac = spec->multiout.hp_out_nid[0];
                else if (spec->multiout.extra_out_nid[0])
                        dac = spec->multiout.extra_out_nid[0];
+               else
+                       dac = 0;
                if (dac)
                        path = snd_hda_add_new_path(codec, dac, pin,
                                                    spec->mixer_nid);
@@ -1507,7 +1514,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 
        badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
                                   spec->private_dac_nids, spec->out_paths,
-                                  &main_out_badness);
+                                  spec->main_out_badness);
 
        if (fill_mio_first &&
            cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
@@ -1522,7 +1529,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
                                      spec->multiout.hp_out_nid,
                                      spec->hp_paths,
-                                     &extra_out_badness);
+                                     spec->extra_out_badness);
                if (err < 0)
                        return err;
                badness += err;
@@ -1532,7 +1539,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                                      cfg->speaker_pins,
                                      spec->multiout.extra_out_nid,
                                      spec->speaker_paths,
-                                     &extra_out_badness);
+                                     spec->extra_out_badness);
                if (err < 0)
                        return err;
                badness += err;
@@ -1926,6 +1933,17 @@ static int create_speaker_out_ctls(struct hda_codec *codec)
  * independent HP controls
  */
 
+/* update HP auto-mute state too */
+static void update_hp_automute_hook(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->hp_automute_hook)
+               spec->hp_automute_hook(codec, NULL);
+       else
+               snd_hda_gen_hp_automute(codec, NULL);
+}
+
 static int indep_hp_info(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_info *uinfo)
 {
@@ -1986,12 +2004,7 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol,
                else
                        *dacp = spec->alt_dac_nid;
 
-               /* update HP auto-mute state too */
-               if (spec->hp_automute_hook)
-                       spec->hp_automute_hook(codec, NULL);
-               else
-                       snd_hda_gen_hp_automute(codec, NULL);
-
+               update_hp_automute_hook(codec);
                ret = 1;
        }
  unlock:
@@ -2072,6 +2085,14 @@ get_multiio_path(struct hda_codec *codec, int idx)
 
 static void update_automute_all(struct hda_codec *codec);
 
+/* Default value to be passed as aamix argument for snd_hda_activate_path();
+ * used for output paths
+ */
+static bool aamix_default(struct hda_gen_spec *spec)
+{
+       return !spec->have_aamix_ctl || spec->aamix_mode;
+}
+
 static int set_multi_io(struct hda_codec *codec, int idx, bool output)
 {
        struct hda_gen_spec *spec = codec->spec;
@@ -2087,11 +2108,11 @@ static int set_multi_io(struct hda_codec *codec, int idx, bool output)
 
        if (output) {
                set_pin_target(codec, nid, PIN_OUT, true);
-               snd_hda_activate_path(codec, path, true, true);
+               snd_hda_activate_path(codec, path, true, aamix_default(spec));
                set_pin_eapd(codec, nid, true);
        } else {
                set_pin_eapd(codec, nid, false);
-               snd_hda_activate_path(codec, path, false, true);
+               snd_hda_activate_path(codec, path, false, aamix_default(spec));
                set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
                path_power_down_sync(codec, path);
        }
@@ -2182,8 +2203,8 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
                snd_hda_activate_path(codec, mix_path, true, true);
                path_power_down_sync(codec, nomix_path);
        } else {
-               snd_hda_activate_path(codec, mix_path, false, true);
-               snd_hda_activate_path(codec, nomix_path, true, true);
+               snd_hda_activate_path(codec, mix_path, false, false);
+               snd_hda_activate_path(codec, nomix_path, true, false);
                path_power_down_sync(codec, mix_path);
        }
 }
@@ -2240,63 +2261,95 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec)
 static void call_update_outputs(struct hda_codec *codec);
 
 /* for shared I/O, change the pin-control accordingly */
-static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
+static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
 {
        struct hda_gen_spec *spec = codec->spec;
+       bool as_mic;
        unsigned int val;
-       hda_nid_t pin = spec->autocfg.inputs[1].pin;
-       /* NOTE: this assumes that there are only two inputs, the
-        * first is the real internal mic and the second is HP/mic jack.
-        */
+       hda_nid_t pin;
 
-       val = snd_hda_get_default_vref(codec, pin);
+       pin = spec->hp_mic_pin;
+       as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
+
+       if (!force) {
+               val = snd_hda_codec_get_pin_target(codec, pin);
+               if (as_mic) {
+                       if (val & PIN_IN)
+                               return;
+               } else {
+                       if (val & PIN_OUT)
+                               return;
+               }
+       }
 
-       /* This pin does not have vref caps - let's enable vref on pin 0x18
-          instead, as suggested by Realtek */
+       val = snd_hda_get_default_vref(codec, pin);
+       /* if the HP pin doesn't support VREF and the codec driver gives an
+        * alternative pin, set up the VREF on that pin instead
+        */
        if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
                const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
                unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
                if (vref_val != AC_PINCTL_VREF_HIZ)
                        snd_hda_set_pin_ctl_cache(codec, vref_pin,
-                                       PIN_IN | (set_as_mic ? vref_val : 0));
+                                                 PIN_IN | (as_mic ? vref_val : 0));
        }
 
-       val = set_as_mic ? val | PIN_IN : PIN_HP;
-       set_pin_target(codec, pin, val, true);
-
-       spec->automute_speaker = !set_as_mic;
-       call_update_outputs(codec);
+       if (!spec->hp_mic_jack_modes) {
+               if (as_mic)
+                       val |= PIN_IN;
+               else
+                       val = PIN_HP;
+               set_pin_target(codec, pin, val, true);
+               update_hp_automute_hook(codec);
+       }
 }
 
 /* create a shared input with the headphone out */
-static int create_shared_input(struct hda_codec *codec)
+static int create_hp_mic(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int defcfg;
        hda_nid_t nid;
 
-       /* only one internal input pin? */
-       if (cfg->num_inputs != 1)
-               return 0;
-       defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
-       if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+       if (!spec->hp_mic) {
+               if (spec->suppress_hp_mic_detect)
+                       return 0;
+               /* automatic detection: only if no input or a single internal
+                * input pin is found, try to detect the shared hp/mic
+                */
+               if (cfg->num_inputs > 1)
+                       return 0;
+               else if (cfg->num_inputs == 1) {
+                       defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
+                       if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+                               return 0;
+               }
+       }
+
+       spec->hp_mic = 0; /* clear once */
+       if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
                return 0;
 
-       if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
-       else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
-               nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
-       else
-               return 0; /* both not available */
+       nid = 0;
+       if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
+               nid = cfg->line_out_pins[0];
+       else if (cfg->hp_outs > 0)
+               nid = cfg->hp_pins[0];
+       if (!nid)
+               return 0;
 
        if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
                return 0; /* no input */
 
-       cfg->inputs[1].pin = nid;
-       cfg->inputs[1].type = AUTO_PIN_MIC;
-       cfg->num_inputs = 2;
-       spec->shared_mic_hp = 1;
+       cfg->inputs[cfg->num_inputs].pin = nid;
+       cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
+       cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
+       cfg->num_inputs++;
+       spec->hp_mic = 1;
+       spec->hp_mic_pin = nid;
+       /* we can't handle auto-mic together with HP-mic */
+       spec->suppress_auto_mic = 1;
        snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
        return 0;
 }
@@ -2304,13 +2357,17 @@ static int create_shared_input(struct hda_codec *codec)
 /*
  * output jack mode
  */
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
+
+static const char * const out_jack_texts[] = {
+       "Line Out", "Headphone Out",
+};
+
 static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_info *uinfo)
 {
-       static const char * const texts[] = {
-               "Line Out", "Headphone Out",
-       };
-       return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts);
+       return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
 }
 
 static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
@@ -2372,6 +2429,17 @@ static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
                ;
 }
 
+static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->add_jack_modes) {
+               unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
+               if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
+                       return 2;
+       }
+       return 1;
+}
+
 static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
                                 hda_nid_t *pins)
 {
@@ -2380,8 +2448,13 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
 
        for (i = 0; i < num_pins; i++) {
                hda_nid_t pin = pins[i];
-               unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
-               if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) {
+               if (pin == spec->hp_mic_pin) {
+                       int ret = create_hp_mic_jack_mode(codec, pin);
+                       if (ret < 0)
+                               return ret;
+                       continue;
+               }
+               if (get_out_jack_num_items(codec, pin) > 1) {
                        struct snd_kcontrol_new *knew;
                        char name[44];
                        get_jack_mode_name(codec, pin, name, sizeof(name));
@@ -2502,12 +2575,24 @@ static const struct snd_kcontrol_new in_jack_mode_enum = {
        .put = in_jack_mode_put,
 };
 
+static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int nitems = 0;
+       if (spec->add_jack_modes)
+               nitems = hweight32(get_vref_caps(codec, pin));
+       return nitems ? nitems : 1;
+}
+
 static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 {
        struct hda_gen_spec *spec = codec->spec;
-       unsigned int defcfg;
        struct snd_kcontrol_new *knew;
        char name[44];
+       unsigned int defcfg;
+
+       if (pin == spec->hp_mic_pin)
+               return 0; /* already done in create_out_jack_mode() */
 
        /* no jack mode for fixed pins */
        defcfg = snd_hda_codec_get_pincfg(codec, pin);
@@ -2515,7 +2600,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
                return 0;
 
        /* no multiple vref caps? */
-       if (hweight32(get_vref_caps(codec, pin)) <= 1)
+       if (get_in_jack_num_items(codec, pin) <= 1)
                return 0;
 
        get_jack_mode_name(codec, pin, name, sizeof(name));
@@ -2526,6 +2611,132 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
        return 0;
 }
 
+/*
+ * HP/mic shared jack mode
+ */
+static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       const char *text = NULL;
+       int idx;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = out_jacks + in_jacks;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       idx = uinfo->value.enumerated.item;
+       if (idx < out_jacks) {
+               if (out_jacks > 1)
+                       text = out_jack_texts[idx];
+               else
+                       text = "Headphone Out";
+       } else {
+               idx -= out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       text = vref_texts[get_vref_idx(vref_caps, idx)];
+               } else
+                       text = "Mic In";
+       }
+
+       strcpy(uinfo->value.enumerated.name, text);
+       return 0;
+}
+
+static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
+{
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
+       int idx = 0;
+
+       if (val & PIN_OUT) {
+               if (out_jacks > 1 && val == PIN_HP)
+                       idx = 1;
+       } else if (val & PIN_IN) {
+               idx = out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       val &= AC_PINCTL_VREFEN;
+                       idx += cvt_from_vref_idx(vref_caps, val);
+               }
+       }
+       return idx;
+}
+
+static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       ucontrol->value.enumerated.item[0] =
+               get_cur_hp_mic_jack_mode(codec, nid);
+       return 0;
+}
+
+static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       unsigned int val, oldval, idx;
+
+       oldval = get_cur_hp_mic_jack_mode(codec, nid);
+       idx = ucontrol->value.enumerated.item[0];
+       if (oldval == idx)
+               return 0;
+
+       if (idx < out_jacks) {
+               if (out_jacks > 1)
+                       val = idx ? PIN_HP : PIN_OUT;
+               else
+                       val = PIN_HP;
+       } else {
+               idx -= out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       val = snd_hda_codec_get_pin_target(codec, nid);
+                       val &= ~(AC_PINCTL_VREFEN | PIN_HP);
+                       val |= get_vref_idx(vref_caps, idx) | PIN_IN;
+               } else
+                       val = snd_hda_get_default_vref(codec, nid);
+       }
+       snd_hda_set_pin_ctl_cache(codec, nid, val);
+       update_hp_automute_hook(codec);
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = hp_mic_jack_mode_info,
+       .get = hp_mic_jack_mode_get,
+       .put = hp_mic_jack_mode_put,
+};
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
+
+       if (get_out_jack_num_items(codec, pin) <= 1 &&
+           get_in_jack_num_items(codec, pin) <= 1)
+               return 0; /* no need */
+       knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
+                                   &hp_mic_jack_mode_enum);
+       if (!knew)
+               return -ENOMEM;
+       knew->private_value = pin;
+       spec->hp_mic_jack_modes = 1;
+       return 0;
+}
 
 /*
  * Parse input paths
@@ -2648,7 +2859,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
        unsigned int ok_bits;
        int i, n, nums;
 
- again:
        nums = 0;
        ok_bits = 0;
        for (n = 0; n < spec->num_adc_nids; n++) {
@@ -2663,12 +2873,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
        }
 
        if (!ok_bits) {
-               if (spec->shared_mic_hp) {
-                       spec->shared_mic_hp = 0;
-                       imux->num_items = 1;
-                       goto again;
-               }
-
                /* check whether ADC-switch is possible */
                for (i = 0; i < imux->num_items; i++) {
                        for (n = 0; n < spec->num_adc_nids; n++) {
@@ -2701,7 +2905,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
                spec->num_adc_nids = nums;
        }
 
-       if (imux->num_items == 1 || spec->shared_mic_hp) {
+       if (imux->num_items == 1 ||
+           (imux->num_items == 2 && spec->hp_mic)) {
                snd_printdd("hda-codec: reducing to a single ADC\n");
                spec->num_adc_nids = 1; /* reduce to a single ADC */
        }
@@ -2738,6 +2943,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
                        snd_hda_get_path_idx(codec, path);
 
                if (!imux_added) {
+                       if (spec->hp_mic_pin == pin)
+                               spec->hp_mic_mux_idx = imux->num_items;
                        spec->imux_pins[imux->num_items] = pin;
                        snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
                        imux_added = true;
@@ -2812,7 +3019,8 @@ static int create_input_ctls(struct hda_codec *codec)
                val = PIN_IN;
                if (cfg->inputs[i].type == AUTO_PIN_MIC)
                        val |= snd_hda_get_default_vref(codec, pin);
-               set_pin_target(codec, pin, val, false);
+               if (pin != spec->hp_mic_pin)
+                       set_pin_target(codec, pin, val, false);
 
                if (mixer) {
                        if (is_reachable_path(codec, pin, mixer)) {
@@ -2830,7 +3038,7 @@ static int create_input_ctls(struct hda_codec *codec)
                if (err < 0)
                        return err;
 
-               if (spec->add_in_jack_modes) {
+               if (spec->add_jack_modes) {
                        err = create_in_jack_mode(codec, pin);
                        if (err < 0)
                                return err;
@@ -3462,8 +3670,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
 
        spec->cur_mux[adc_idx] = idx;
 
-       if (spec->shared_mic_hp)
-               update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
+       if (spec->hp_mic)
+               update_hp_mic(codec, adc_idx, false);
 
        if (spec->dyn_adc_switch)
                dyn_adc_pcm_resetup(codec, idx);
@@ -3511,18 +3719,21 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
 
        for (i = 0; i < num_pins; i++) {
                hda_nid_t nid = pins[i];
-               unsigned int val;
+               unsigned int val, oldval;
                if (!nid)
                        break;
+               oldval = snd_hda_codec_get_pin_target(codec, nid);
+               if (oldval & PIN_IN)
+                       continue; /* no mute for inputs */
                /* don't reset VREF value in case it's controlling
                 * the amp (see alc861_fixup_asus_amp_vref_0f())
                 */
                if (spec->keep_vref_in_automute)
-                       val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP;
+                       val = oldval & ~PIN_HP;
                else
                        val = 0;
                if (!mute)
-                       val |= snd_hda_codec_get_pin_target(codec, nid);
+                       val |= oldval;
                /* here we call update_pin_ctl() so that the pinctl is changed
                 * without changing the pinctl target value;
                 * the original target value will be still referred at the
@@ -3543,8 +3754,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
         * in general, HP pins/amps control should be enabled in all cases,
         * but currently set only for master_mute, just to be safe
         */
-       if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
-               do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
                    spec->autocfg.hp_pins, spec->master_mute);
 
        if (!spec->automute_speaker)
@@ -3649,10 +3859,7 @@ static void update_automute_all(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
 
-       if (spec->hp_automute_hook)
-               spec->hp_automute_hook(codec, NULL);
-       else
-               snd_hda_gen_hp_automute(codec, NULL);
+       update_hp_automute_hook(codec);
        if (spec->line_automute_hook)
                spec->line_automute_hook(codec, NULL);
        else
@@ -3978,6 +4185,11 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
                cfg = &spec->autocfg;
        }
 
+       if (!spec->main_out_badness)
+               spec->main_out_badness = &hda_main_out_badness;
+       if (!spec->extra_out_badness)
+               spec->extra_out_badness = &hda_extra_out_badness;
+
        fill_all_dac_nids(codec);
 
        if (!cfg->line_outs) {
@@ -4024,7 +4236,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        err = create_loopback_mixing_ctl(codec);
        if (err < 0)
                return err;
-       err = create_shared_input(codec);
+       err = create_hp_mic(codec);
        if (err < 0)
                return err;
        err = create_input_ctls(codec);
@@ -4050,11 +4262,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        if (err < 0)
                return err;
 
-       if (!spec->shared_mic_hp) {
-               err = check_auto_mic_availability(codec);
-               if (err < 0)
-                       return err;
-       }
+       err = check_auto_mic_availability(codec);
+       if (err < 0)
+               return err;
 
        err = create_capture_mixers(codec);
        if (err < 0)
@@ -4064,7 +4274,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        if (err < 0)
                return err;
 
-       if (spec->add_out_jack_modes) {
+       if (spec->add_jack_modes) {
                if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                        err = create_out_jack_modes(codec, cfg->line_outs,
                                                    cfg->line_out_pins);
@@ -4085,6 +4295,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        if (spec->power_down_unused)
                codec->power_filter = snd_hda_gen_path_power_filter;
 
+       if (!spec->no_analog && spec->beep_nid) {
+               err = snd_hda_attach_beep_device(codec, spec->beep_nid);
+               if (err < 0)
+                       return err;
+       }
+
        return 1;
 }
 EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
@@ -4161,17 +4377,6 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
 
        free_kctls(spec); /* no longer needed */
 
-       if (spec->shared_mic_hp) {
-               int err;
-               int nid = spec->autocfg.inputs[1].pin;
-               err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
-               if (err < 0)
-                       return err;
-               err = snd_hda_jack_detect_enable(codec, nid, 0);
-               if (err < 0)
-                       return err;
-       }
-
        err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -4729,7 +4934,8 @@ static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
                return;
        pin = path->path[path->depth - 1];
        restore_pin_ctl(codec, pin);
-       snd_hda_activate_path(codec, path, path->active, true);
+       snd_hda_activate_path(codec, path, path->active,
+                             aamix_default(codec->spec));
        set_pin_eapd(codec, pin, path->active);
 }
 
@@ -4779,7 +4985,8 @@ static void init_multi_io(struct hda_codec *codec)
                if (!spec->multi_io[i].ctl_in)
                        spec->multi_io[i].ctl_in =
                                snd_hda_codec_get_pin_target(codec, pin);
-               snd_hda_activate_path(codec, path, path->active, true);
+               snd_hda_activate_path(codec, path, path->active,
+                                     aamix_default(spec));
        }
 }
 
@@ -4826,11 +5033,10 @@ static void init_input_src(struct hda_codec *codec)
                                snd_hda_activate_path(codec, path, active, false);
                        }
                }
+               if (spec->hp_mic)
+                       update_hp_mic(codec, c, true);
        }
 
-       if (spec->shared_mic_hp)
-               update_shared_mic_hp(codec, spec->cur_mux[0]);
-
        if (spec->cap_sync_hook)
                spec->cap_sync_hook(codec, NULL);
 }
@@ -4911,6 +5117,7 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_init);
  */
 void snd_hda_gen_free(struct hda_codec *codec)
 {
+       snd_hda_detach_beep_device(codec);
        snd_hda_gen_spec_free(codec->spec);
        kfree(codec->spec);
        codec->spec = NULL;
index 009b57b..54e6651 100644 (file)
@@ -76,6 +76,19 @@ enum {
        HDA_GEN_PCM_ACT_CLOSE,
 };
 
+/* DAC assignment badness table */
+struct badness_table {
+       int no_primary_dac;     /* no primary DAC */
+       int no_dac;             /* no secondary DACs */
+       int shared_primary;     /* primary DAC is shared with main output */
+       int shared_surr;        /* secondary DAC shared with main or primary */
+       int shared_clfe;        /* third DAC shared with main or primary */
+       int shared_surr_main;   /* secondary DAC sahred with main/DAC0 */
+};
+
+extern const struct badness_table hda_main_out_badness;
+extern const struct badness_table hda_extra_out_badness;
+
 struct hda_gen_spec {
        char stream_name_analog[32];    /* analog PCM stream */
        const struct hda_pcm_stream *stream_analog_playback;
@@ -145,7 +158,10 @@ struct hda_gen_spec {
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
        hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
        unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
+       /* shared hp/mic */
        hda_nid_t shared_mic_vref_pin;
+       hda_nid_t hp_mic_pin;
+       int hp_mic_mux_idx;
 
        /* DAC/ADC lists */
        int num_all_dacs;
@@ -200,7 +216,8 @@ struct hda_gen_spec {
 
        /* other parse behavior flags */
        unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
-       unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
+       unsigned int hp_mic:1; /* Allow HP as a mic-in */
+       unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
        unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
        unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
        unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
@@ -209,8 +226,7 @@ struct hda_gen_spec {
        unsigned int indep_hp:1; /* independent HP supported */
        unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
        unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
-       unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */
-       unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */
+       unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
        unsigned int power_down_unused:1; /* power down unused widgets */
 
        /* other internal flags */
@@ -218,10 +234,18 @@ struct hda_gen_spec {
        unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
        unsigned int indep_hp_enabled:1; /* independent HP enabled */
        unsigned int have_aamix_ctl:1;
+       unsigned int hp_mic_jack_modes:1;
+
+       /* badness tables for output path evaluations */
+       const struct badness_table *main_out_badness;
+       const struct badness_table *extra_out_badness;
 
        /* loopback mixing mode */
        bool aamix_mode;
 
+       /* digital beep */
+       hda_nid_t beep_nid;
+
        /* for virtual master */
        hda_nid_t vmaster_nid;
        unsigned int vmaster_tlv[4];
index bcd40ee..7b213d5 100644 (file)
@@ -1889,6 +1889,26 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream,
                tc->cycle_last = last;
 }
 
+static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
+                               u64 nsec)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       u64 codec_frames, codec_nsecs;
+
+       if (!hinfo->ops.get_delay)
+               return nsec;
+
+       codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
+       codec_nsecs = div_u64(codec_frames * 1000000000LL,
+                             substream->runtime->rate);
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               return nsec + codec_nsecs;
+
+       return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
+}
+
 static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
                                struct timespec *ts)
 {
@@ -1897,6 +1917,7 @@ static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
 
        nsec = timecounter_read(&azx_dev->azx_tc);
        nsec = div_u64(nsec, 3); /* can be optimized */
+       nsec = azx_adjust_codec_delay(substream, nsec);
 
        *ts = ns_to_timespec(nsec);
 
@@ -2349,8 +2370,11 @@ static unsigned int azx_get_position(struct azx *chip,
                                     struct azx_dev *azx_dev,
                                     bool with_check)
 {
+       struct snd_pcm_substream *substream = azx_dev->substream;
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        unsigned int pos;
-       int stream = azx_dev->substream->stream;
+       int stream = substream->stream;
+       struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
        int delay = 0;
 
        switch (chip->position_fix[stream]) {
@@ -2381,7 +2405,7 @@ static unsigned int azx_get_position(struct azx *chip,
                pos = 0;
 
        /* calculate runtime delay from LPIB */
-       if (azx_dev->substream->runtime &&
+       if (substream->runtime &&
            chip->position_fix[stream] == POS_FIX_POSBUF &&
            (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
                unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
@@ -2399,9 +2423,16 @@ static unsigned int azx_get_position(struct azx *chip,
                        delay = 0;
                        chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
                }
-               azx_dev->substream->runtime->delay =
-                       bytes_to_frames(azx_dev->substream->runtime, delay);
+               delay = bytes_to_frames(substream->runtime, delay);
        }
+
+       if (substream->runtime) {
+               if (hinfo->ops.get_delay)
+                       delay += hinfo->ops.get_delay(hinfo, apcm->codec,
+                                                     substream);
+               substream->runtime->delay = delay;
+       }
+
        trace_azx_get_position(chip, azx_dev, pos, delay);
        return pos;
 }
index 1d035ef..9e0a952 100644 (file)
@@ -394,7 +394,8 @@ static int get_unique_index(struct hda_codec *codec, const char *name, int idx)
 }
 
 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
-                        const struct auto_pin_cfg *cfg)
+                        const struct auto_pin_cfg *cfg,
+                        const char *base_name)
 {
        unsigned int def_conf, conn;
        char name[44];
@@ -410,7 +411,11 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
        phantom_jack = (conn != AC_JACK_PORT_COMPLEX) ||
                       !is_jack_detectable(codec, nid);
 
-       snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
+       if (base_name) {
+               strlcpy(name, base_name, sizeof(name));
+               idx = 0;
+       } else
+               snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
        if (phantom_jack)
                /* Example final name: "Internal Mic Phantom Jack" */
                strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
@@ -433,39 +438,51 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
        const hda_nid_t *p;
        int i, err;
 
+       for (i = 0; i < cfg->num_inputs; i++) {
+               /* If we have headphone mics; make sure they get the right name
+                  before grabbed by output pins */
+               if (cfg->inputs[i].is_headphone_mic) {
+                       if (auto_cfg_hp_outs(cfg) == 1)
+                               err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0],
+                                                   cfg, "Headphone Mic");
+                       else
+                               err = add_jack_kctl(codec, cfg->inputs[i].pin,
+                                                   cfg, "Headphone Mic");
+               } else
+                       err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
+                                           NULL);
+               if (err < 0)
+                       return err;
+       }
+
        for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
-               err = add_jack_kctl(codec, *p, cfg);
+               err = add_jack_kctl(codec, *p, cfg, NULL);
                if (err < 0)
                        return err;
        }
        for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
                if (*p == *cfg->line_out_pins) /* might be duplicated */
                        break;
-               err = add_jack_kctl(codec, *p, cfg);
+               err = add_jack_kctl(codec, *p, cfg, NULL);
                if (err < 0)
                        return err;
        }
        for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
                if (*p == *cfg->line_out_pins) /* might be duplicated */
                        break;
-               err = add_jack_kctl(codec, *p, cfg);
-               if (err < 0)
-                       return err;
-       }
-       for (i = 0; i < cfg->num_inputs; i++) {
-               err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg);
+               err = add_jack_kctl(codec, *p, cfg, NULL);
                if (err < 0)
                        return err;
        }
        for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
-               err = add_jack_kctl(codec, *p, cfg);
+               err = add_jack_kctl(codec, *p, cfg, NULL);
                if (err < 0)
                        return err;
        }
-       err = add_jack_kctl(codec, cfg->dig_in_pin, cfg);
+       err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL);
        if (err < 0)
                return err;
-       err = add_jack_kctl(codec, cfg->mono_out_pin, cfg);
+       err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL);
        if (err < 0)
                return err;
        return 0;
index 83b7486..e0bf753 100644 (file)
@@ -670,6 +670,10 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
        return (state != target_state);
 }
 
+unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
+                                            hda_nid_t nid,
+                                            unsigned int power_state);
+
 /*
  * AMP control callbacks
  */
index df8014b..977b0d8 100644 (file)
@@ -43,7 +43,6 @@ struct ad198x_spec {
        hda_nid_t eapd_nid;
 
        unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
-       hda_nid_t beep_dev_nid;
 
 #ifdef ENABLE_AD_STATIC_QUIRKS
        const struct snd_kcontrol_new *mixers[6];
@@ -609,7 +608,7 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = {
        .build_controls = ad198x_auto_build_controls,
        .build_pcms = snd_hda_gen_build_pcms,
        .init = snd_hda_gen_init,
-       .free = ad198x_free,
+       .free = snd_hda_gen_free,
        .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .check_power_status = snd_hda_gen_check_power_status,
@@ -638,12 +637,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       if (spec->beep_dev_nid) {
-               err = snd_hda_attach_beep_device(codec, spec->beep_dev_nid);
-               if (err < 0)
-                       return err;
-       }
-
        codec->patch_ops = ad198x_auto_patch_ops;
 
        return 0;
@@ -1240,7 +1233,7 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
        codec->inv_eapd = 1;
 
        spec->gen.mixer_nid = 0x07;
-       spec->beep_dev_nid = 0x19;
+       spec->gen.beep_nid = 0x19;
        set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
 
        /* AD1986A has a hardware problem that it can't share a stream
@@ -1256,7 +1249,7 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
 
        err = ad198x_parse_auto_config(codec);
        if (err < 0) {
-               ad198x_free(codec);
+               snd_hda_gen_free(codec);
                return err;
        }
 
@@ -1673,7 +1666,7 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
                return err;
        spec = codec->spec;
 
-       spec->beep_dev_nid = 0x10;
+       spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
        err = ad198x_parse_auto_config(codec);
        if (err < 0)
@@ -1684,7 +1677,7 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
        return 0;
 
  error:
-       ad198x_free(codec);
+       snd_hda_gen_free(codec);
        return err;
 }
 
@@ -2187,7 +2180,7 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
        spec = codec->spec;
 
        spec->gen.mixer_nid = 0x0e;
-       spec->beep_dev_nid = 0x10;
+       spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
 
        snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
@@ -2205,7 +2198,7 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
        return 0;
 
  error:
-       ad198x_free(codec);
+       snd_hda_gen_free(codec);
        return err;
 }
 
@@ -3236,7 +3229,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 
        spec->gen.mixer_nid = 0x20;
        spec->gen.mixer_merge_nid = 0x21;
-       spec->beep_dev_nid = 0x10;
+       spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
        err = ad198x_parse_auto_config(codec);
        if (err < 0)
@@ -3247,7 +3240,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
        return 0;
 
  error:
-       ad198x_free(codec);
+       snd_hda_gen_free(codec);
        return err;
 }
 
@@ -3653,7 +3646,7 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
        spec = codec->spec;
 
        spec->gen.mixer_nid = 0x20;
-       spec->beep_dev_nid = 0x10;
+       spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 
        snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
@@ -3671,7 +3664,7 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
        return 0;
 
  error:
-       ad198x_free(codec);
+       snd_hda_gen_free(codec);
        return err;
 }
 
@@ -5155,7 +5148,7 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
 
        spec->gen.mixer_nid = 0x20;
        spec->gen.mixer_merge_nid = 0x21;
-       spec->beep_dev_nid = 0x10;
+       spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
        err = ad198x_parse_auto_config(codec);
        if (err < 0)
@@ -5166,7 +5159,7 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
        return 0;
 
  error:
-       ad198x_free(codec);
+       snd_hda_gen_free(codec);
        return err;
 }
 
index 0792b57..90ff7a3 100644 (file)
@@ -131,6 +131,13 @@ enum {
 /* Effects values size*/
 #define EFFECT_VALS_MAX_COUNT 12
 
+/* Latency introduced by DSP blocks in milliseconds. */
+#define DSP_CAPTURE_INIT_LATENCY        0
+#define DSP_CRYSTAL_VOICE_LATENCY       124
+#define DSP_PLAYBACK_INIT_LATENCY       13
+#define DSP_PLAY_ENHANCEMENT_LATENCY    30
+#define DSP_SPEAKER_OUT_LATENCY         7
+
 struct ct_effect {
        char name[44];
        hda_nid_t nid;
@@ -741,6 +748,9 @@ struct ca0132_spec {
        long voicefx_val;
        long cur_mic_boost;
 
+       struct hda_codec *codec;
+       struct delayed_work unsol_hp_work;
+
 #ifdef ENABLE_TUNING_CONTROLS
        long cur_ctl_vals[TUNING_CTLS_COUNT];
 #endif
@@ -2740,6 +2750,31 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
        return 0;
 }
 
+static unsigned int ca0132_playback_pcm_delay(struct hda_pcm_stream *info,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int latency = DSP_PLAYBACK_INIT_LATENCY;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       /* Add latency if playback enhancement and either effect is enabled. */
+       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) {
+               if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) ||
+                   (spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID]))
+                       latency += DSP_PLAY_ENHANCEMENT_LATENCY;
+       }
+
+       /* Applying Speaker EQ adds latency as well. */
+       if (spec->cur_out_type == SPEAKER_OUT)
+               latency += DSP_SPEAKER_OUT_LATENCY;
+
+       return (latency * runtime->rate) / 1000;
+}
+
 /*
  * Digital out
  */
@@ -2808,6 +2843,23 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
        return 0;
 }
 
+static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int latency = DSP_CAPTURE_INIT_LATENCY;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
+               latency += DSP_CRYSTAL_VOICE_LATENCY;
+
+       return (latency * runtime->rate) / 1000;
+}
+
 /*
  * Controls stuffs.
  */
@@ -3227,6 +3279,14 @@ exit:
        return err < 0 ? err : 0;
 }
 
+static void ca0132_unsol_hp_delayed(struct work_struct *work)
+{
+       struct ca0132_spec *spec = container_of(
+               to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
+       ca0132_select_out(spec->codec);
+       snd_hda_jack_report_sync(spec->codec);
+}
+
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
 static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
 static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
@@ -3991,7 +4051,8 @@ static struct hda_pcm_stream ca0132_pcm_analog_playback = {
        .channels_max = 6,
        .ops = {
                .prepare = ca0132_playback_pcm_prepare,
-               .cleanup = ca0132_playback_pcm_cleanup
+               .cleanup = ca0132_playback_pcm_cleanup,
+               .get_delay = ca0132_playback_pcm_delay,
        },
 };
 
@@ -4001,7 +4062,8 @@ static struct hda_pcm_stream ca0132_pcm_analog_capture = {
        .channels_max = 2,
        .ops = {
                .prepare = ca0132_capture_pcm_prepare,
-               .cleanup = ca0132_capture_pcm_cleanup
+               .cleanup = ca0132_capture_pcm_cleanup,
+               .get_delay = ca0132_capture_pcm_delay,
        },
 };
 
@@ -4399,8 +4461,7 @@ static void ca0132_process_dsp_response(struct hda_codec *codec)
 
 static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       snd_printdd(KERN_INFO "ca0132_unsol_event: 0x%x\n", res);
-
+       struct ca0132_spec *spec = codec->spec;
 
        if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) {
                ca0132_process_dsp_response(codec);
@@ -4412,8 +4473,13 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
 
                switch (res) {
                case UNSOL_TAG_HP:
-                       ca0132_select_out(codec);
-                       snd_hda_jack_report_sync(codec);
+                       /* Delay enabling the HP amp, to let the mic-detection
+                        * state machine run.
+                        */
+                       cancel_delayed_work_sync(&spec->unsol_hp_work);
+                       queue_delayed_work(codec->bus->workq,
+                                          &spec->unsol_hp_work,
+                                          msecs_to_jiffies(500));
                        break;
                case UNSOL_TAG_AMIC1:
                        ca0132_select_mic(codec);
@@ -4588,6 +4654,7 @@ static void ca0132_free(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
        snd_hda_power_up(codec);
        snd_hda_sequence_write(codec, spec->base_exit_verbs);
        ca0132_exit_chip(codec);
@@ -4653,6 +4720,7 @@ static int patch_ca0132(struct hda_codec *codec)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       spec->codec = codec;
 
        spec->num_mixers = 1;
        spec->mixers[0] = ca0132_mixer;
@@ -4663,6 +4731,8 @@ static int patch_ca0132(struct hda_codec *codec)
        spec->init_verbs[1] = ca0132_init_verbs1;
        spec->num_init_verbs = 2;
 
+       INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
+
        ca0132_init_chip(codec);
 
        ca0132_config(codec);
index 0d9c58f..bd8d46c 100644 (file)
@@ -68,6 +68,7 @@ enum {
 enum {
        CS421X_CDB4210,
        CS421X_SENSE_B,
+       CS421X_STUMPY,
 };
 
 /* Vendor-specific processing widget */
@@ -538,6 +539,7 @@ static int patch_cs420x(struct hda_codec *codec)
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
        { .id = CS421X_CDB4210, .name = "cdb4210" },
+       { .id = CS421X_STUMPY, .name = "stumpy" },
        {}
 };
 
@@ -559,6 +561,17 @@ static const struct hda_pintbl cdb4210_pincfgs[] = {
        {} /* terminator */
 };
 
+/* Stumpy ChromeBox */
+static const struct hda_pintbl stumpy_pincfgs[] = {
+       { 0x05, 0x022120f0 },
+       { 0x06, 0x901700f0 },
+       { 0x07, 0x02a120f0 },
+       { 0x08, 0x77a70037 },
+       { 0x09, 0x77a6003e },
+       { 0x0a, 0x434510f0 },
+       {} /* terminator */
+};
+
 /* Setup GPIO/SENSE for each board (if used) */
 static void cs421x_fixup_sense_b(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action)
@@ -578,7 +591,11 @@ static const struct hda_fixup cs421x_fixups[] = {
        [CS421X_SENSE_B] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cs421x_fixup_sense_b,
-       }
+       },
+       [CS421X_STUMPY] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stumpy_pincfgs,
+       },
 };
 
 static const struct hda_verb cs421x_coef_init_verbs[] = {
index 2a89d1e..5499643 100644 (file)
@@ -139,8 +139,12 @@ struct conexant_spec {
 
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
-       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
+static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
+                               int idx, int dir)
+{
+       spec->gen.beep_nid = nid;
+       spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+}
 /* additional beep mixers; the actual parameters are overwritten at build */
 static const struct snd_kcontrol_new cxt_beep_mixer[] = {
        HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
@@ -3191,17 +3195,11 @@ static int cx_auto_build_controls(struct hda_codec *codec)
        return 0;
 }
 
-static void cx_auto_free(struct hda_codec *codec)
-{
-       snd_hda_detach_beep_device(codec);
-       snd_hda_gen_free(codec);
-}
-
 static const struct hda_codec_ops cx_auto_patch_ops = {
        .build_controls = cx_auto_build_controls,
        .build_pcms = snd_hda_gen_build_pcms,
        .init = snd_hda_gen_init,
-       .free = cx_auto_free,
+       .free = snd_hda_gen_free,
        .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .check_power_status = snd_hda_gen_check_power_status,
@@ -3356,7 +3354,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
        switch (codec->vendor_id) {
        case 0x14f15045:
                codec->single_adc_amp = 1;
-               codec->power_filter = NULL; /* Needs speaker amp to D3 to avoid click */
                break;
        case 0x14f15047:
                codec->pin_amp_workaround = 1;
@@ -3396,8 +3393,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
                goto error;
 
        codec->patch_ops = cx_auto_patch_ops;
-       if (spec->beep_amp)
-               snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
 
        /* Some laptops with Conexant chips show stalls in S3 resume,
         * which falls into the single-cmd mode.
index de8ac5c..32930e6 100644 (file)
@@ -44,16 +44,6 @@ static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
 MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
-/*
- * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support N independent pipes, each of them can be connected to one or
- * more ports (DVI, HDMI or DisplayPort).
- *
- * The HDA correspondence of pipes/ports are converter/pin nodes.
- */
-#define MAX_HDMI_CVTS  8
-#define MAX_HDMI_PINS  8
-
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
        int assigned;
@@ -80,16 +70,17 @@ struct hdmi_spec_per_pin {
        bool non_pcm;
        bool chmap_set;         /* channel-map override by ALSA API? */
        unsigned char chmap[8]; /* ALSA API channel-map */
+       char pcm_name[8];       /* filled in build_pcm callbacks */
 };
 
 struct hdmi_spec {
        int num_cvts;
-       struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
-       hda_nid_t cvt_nids[MAX_HDMI_CVTS];
+       struct snd_array cvts; /* struct hdmi_spec_per_cvt */
+       hda_nid_t cvt_nids[4]; /* only for haswell fix */
 
        int num_pins;
-       struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
-       struct hda_pcm pcm_rec[MAX_HDMI_PINS];
+       struct snd_array pins; /* struct hdmi_spec_per_pin */
+       struct snd_array pcm_rec; /* struct hda_pcm */
        unsigned int channels_max; /* max over all cvts */
 
        struct hdmi_eld temp_eld;
@@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
  * HDMI routines
  */
 
+#define get_pin(spec, idx) \
+       ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
+#define get_cvt(spec, idx) \
+       ((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
+#define get_pcm_rec(spec, idx) \
+       ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
+
 static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
 {
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
-               if (spec->pins[pin_idx].pin_nid == pin_nid)
+               if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
                        return pin_idx;
 
        snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
@@ -322,7 +320,7 @@ static int hinfo_to_pin_index(struct hdmi_spec *spec,
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
-               if (&spec->pcm_rec[pin_idx].stream[0] == hinfo)
+               if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
                        return pin_idx;
 
        snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
@@ -334,7 +332,7 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
        int cvt_idx;
 
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
-               if (spec->cvts[cvt_idx].cvt_nid == cvt_nid)
+               if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
                        return cvt_idx;
 
        snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
@@ -352,7 +350,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 
        pin_idx = kcontrol->private_value;
-       eld = &spec->pins[pin_idx].sink_eld;
+       eld = &get_pin(spec, pin_idx)->sink_eld;
 
        mutex_lock(&eld->lock);
        uinfo->count = eld->eld_valid ? eld->eld_size : 0;
@@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
        int pin_idx;
 
        pin_idx = kcontrol->private_value;
-       eld = &spec->pins[pin_idx].sink_eld;
+       eld = &get_pin(spec, pin_idx)->sink_eld;
 
        mutex_lock(&eld->lock);
        if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
@@ -410,11 +408,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
        kctl->private_value = pin_idx;
        kctl->id.device = device;
 
-       err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl);
+       err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl);
        if (err < 0)
                return err;
 
-       spec->pins[pin_idx].eld_ctl = kctl;
+       get_pin(spec, pin_idx)->eld_ctl = kctl;
        return 0;
 }
 
@@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
                                       struct snd_pcm_substream *substream)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
        int channels = substream->runtime->channels;
        struct hdmi_eld *eld;
        int ca;
        union audio_infoframe ai;
 
-       eld = &spec->pins[pin_idx].sink_eld;
+       eld = &per_pin->sink_eld;
        if (!eld->monitor_present)
                return;
 
@@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
        if (pin_idx < 0)
                return;
 
-       hdmi_present_sense(&spec->pins[pin_idx], 1);
+       hdmi_present_sense(get_pin(spec, pin_idx), 1);
        snd_hda_jack_report_sync(codec);
 }
 
@@ -1020,6 +1018,41 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
                hdmi_non_intrinsic_event(codec, res);
 }
 
+static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+{
+       int pwr, lamp, ramp;
+
+       pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+       pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+       if (pwr != AC_PWRST_D0) {
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+                                   AC_PWRST_D0);
+               msleep(40);
+               pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+               pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+               snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
+       }
+
+       lamp = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_AMP_GAIN_MUTE,
+                                 AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
+       ramp = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_AMP_GAIN_MUTE,
+                                 AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
+       if (lamp != ramp) {
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT | lamp);
+
+               lamp = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_AMP_GAIN_MUTE,
+                                 AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
+               ramp = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_AMP_GAIN_MUTE,
+                                 AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
+               snd_printd("Haswell HDMI audio: Mute after set on pin 0x%x: [0x%x 0x%x]\n", nid, lamp, ramp);
+       }
+}
+
 /*
  * Callbacks
  */
@@ -1034,6 +1067,9 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        int pinctl;
        int new_pinctl = 0;
 
+       if (codec->vendor_id == 0x80862807)
+               haswell_verify_pin_D0(codec, pin_nid);
+
        if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
                pinctl = snd_hda_codec_read(codec, pin_nid, 0,
                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1083,12 +1119,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        pin_idx = hinfo_to_pin_index(spec, hinfo);
        if (snd_BUG_ON(pin_idx < 0))
                return -EINVAL;
-       per_pin = &spec->pins[pin_idx];
+       per_pin = get_pin(spec, pin_idx);
        eld = &per_pin->sink_eld;
 
        /* Dynamically assign converter to stream */
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-               per_cvt = &spec->cvts[cvt_idx];
+               per_cvt = get_cvt(spec, cvt_idx);
 
                /* Must not already be assigned */
                if (per_cvt->assigned)
@@ -1151,7 +1187,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
 
        if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
@@ -1275,14 +1311,13 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
        if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
                return 0;
 
-       if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
-               return -E2BIG;
-
        if (codec->vendor_id == 0x80862807)
                intel_haswell_fixup_connect_list(codec, pin_nid);
 
        pin_idx = spec->num_pins;
-       per_pin = &spec->pins[pin_idx];
+       per_pin = snd_array_new(&spec->pins);
+       if (!per_pin)
+               return -ENOMEM;
 
        per_pin->pin_nid = pin_nid;
        per_pin->non_pcm = false;
@@ -1299,19 +1334,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
        struct hdmi_spec *spec = codec->spec;
-       int cvt_idx;
        struct hdmi_spec_per_cvt *per_cvt;
        unsigned int chans;
        int err;
 
-       if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
-               return -E2BIG;
-
        chans = get_wcaps(codec, cvt_nid);
        chans = get_wcaps_channels(chans);
 
-       cvt_idx = spec->num_cvts;
-       per_cvt = &spec->cvts[cvt_idx];
+       per_cvt = snd_array_new(&spec->cvts);
+       if (!per_cvt)
+               return -ENOMEM;
 
        per_cvt->cvt_nid = cvt_nid;
        per_cvt->channels_min = 2;
@@ -1328,7 +1360,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
        if (err < 0)
                return err;
 
-       spec->cvt_nids[spec->num_cvts++] = cvt_nid;
+       if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
+               spec->cvt_nids[spec->num_cvts] = cvt_nid;
+       spec->num_cvts++;
 
        return 0;
 }
@@ -1384,13 +1418,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *get_hdmi_pcm_name(int idx)
-{
-       static char names[MAX_HDMI_PINS][8];
-       sprintf(&names[idx][0], "HDMI %d", idx);
-       return &names[idx][0];
-}
-
 static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
        struct hda_spdif_out *spdif;
@@ -1417,7 +1444,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        hda_nid_t cvt_nid = hinfo->nid;
        struct hdmi_spec *spec = codec->spec;
        int pin_idx = hinfo_to_pin_index(spec, hinfo);
-       hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+       hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
        bool non_pcm;
 
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
@@ -1450,7 +1477,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
                if (snd_BUG_ON(cvt_idx < 0))
                        return -EINVAL;
-               per_cvt = &spec->cvts[cvt_idx];
+               per_cvt = get_cvt(spec, cvt_idx);
 
                snd_BUG_ON(!per_cvt->assigned);
                per_cvt->assigned = 0;
@@ -1459,7 +1486,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                pin_idx = hinfo_to_pin_index(spec, hinfo);
                if (snd_BUG_ON(pin_idx < 0))
                        return -EINVAL;
-               per_pin = &spec->pins[pin_idx];
+               per_pin = get_pin(spec, pin_idx);
 
                snd_hda_spdif_ctls_unassign(codec, pin_idx);
                per_pin->chmap_set = false;
@@ -1553,7 +1580,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = info->private_data;
        struct hdmi_spec *spec = codec->spec;
        int pin_idx = kcontrol->private_value;
-       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
@@ -1568,7 +1595,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = info->private_data;
        struct hdmi_spec *spec = codec->spec;
        int pin_idx = kcontrol->private_value;
-       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        unsigned int ctl_idx;
        struct snd_pcm_substream *substream;
        unsigned char chmap[8];
@@ -1613,9 +1640,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hda_pcm *info;
                struct hda_pcm_stream *pstr;
-
-               info = &spec->pcm_rec[pin_idx];
-               info->name = get_hdmi_pcm_name(pin_idx);
+               struct hdmi_spec_per_pin *per_pin;
+
+               per_pin = get_pin(spec, pin_idx);
+               sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
+               info = snd_array_new(&spec->pcm_rec);
+               if (!info)
+                       return -ENOMEM;
+               info->name = per_pin->pcm_name;
                info->pcm_type = HDA_PCM_TYPE_HDMI;
                info->own_chmap = true;
 
@@ -1626,7 +1658,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
        }
 
        codec->num_pcms = spec->num_pins;
-       codec->pcm_info = spec->pcm_rec;
+       codec->pcm_info = spec->pcm_rec.list;
 
        return 0;
 }
@@ -1635,8 +1667,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
 {
        char hdmi_str[32] = "HDMI/DP";
        struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
-       int pcmdev = spec->pcm_rec[pin_idx].device;
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+       int pcmdev = get_pcm_rec(spec, pin_idx)->device;
 
        if (pcmdev > 0)
                sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
@@ -1654,7 +1686,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 
                err = generic_hdmi_build_jack(codec, pin_idx);
                if (err < 0)
@@ -1669,9 +1701,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
                snd_hda_spdif_ctls_unassign(codec, pin_idx);
 
                /* add control for ELD Bytes */
-               err = hdmi_create_eld_ctl(codec,
-                                       pin_idx,
-                                       spec->pcm_rec[pin_idx].device);
+               err = hdmi_create_eld_ctl(codec, pin_idx,
+                                         get_pcm_rec(spec, pin_idx)->device);
 
                if (err < 0)
                        return err;
@@ -1709,7 +1740,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
                struct hdmi_eld *eld = &per_pin->sink_eld;
 
                per_pin->codec = codec;
@@ -1726,7 +1757,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
                hda_nid_t pin_nid = per_pin->pin_nid;
 
                hdmi_init_pin(codec, pin_nid);
@@ -1735,13 +1766,27 @@ static int generic_hdmi_init(struct hda_codec *codec)
        return 0;
 }
 
+static void hdmi_array_init(struct hdmi_spec *spec, int nums)
+{
+       snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
+       snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
+       snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
+}
+
+static void hdmi_array_free(struct hdmi_spec *spec)
+{
+       snd_array_free(&spec->pins);
+       snd_array_free(&spec->cvts);
+       snd_array_free(&spec->pcm_rec);
+}
+
 static void generic_hdmi_free(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
                struct hdmi_eld *eld = &per_pin->sink_eld;
 
                cancel_delayed_work(&per_pin->work);
@@ -1749,6 +1794,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
        }
 
        flush_workqueue(codec->bus->workq);
+       hdmi_array_free(spec);
        kfree(spec);
 }
 
@@ -1775,6 +1821,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 
        /* override pins connection list */
        snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
+       nconns = max(spec->num_cvts, 4);
        snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
 }
 
@@ -1855,6 +1902,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       hdmi_array_init(spec, 4);
 
        snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -1882,24 +1930,30 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 static int simple_playback_build_pcms(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
+       struct hda_pcm *info;
        unsigned int chans;
        struct hda_pcm_stream *pstr;
+       struct hdmi_spec_per_cvt *per_cvt;
 
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       chans = get_wcaps(codec, spec->cvts[0].cvt_nid);
+       per_cvt = get_cvt(spec, 0);
+       chans = get_wcaps(codec, per_cvt->cvt_nid);
        chans = get_wcaps_channels(chans);
 
-       info->name = get_hdmi_pcm_name(0);
+       info = snd_array_new(&spec->pcm_rec);
+       if (!info)
+               return -ENOMEM;
+       info->name = get_pin(spec, 0)->pcm_name;
+       sprintf(info->name, "HDMI 0");
        info->pcm_type = HDA_PCM_TYPE_HDMI;
        pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
        *pstr = spec->pcm_playback;
-       pstr->nid = spec->cvts[0].cvt_nid;
+       pstr->nid = per_cvt->cvt_nid;
        if (pstr->channels_max <= 2 && chans && chans <= 16)
                pstr->channels_max = chans;
 
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+
        return 0;
 }
 
@@ -1919,11 +1973,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec,
 static int simple_playback_build_controls(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt;
        int err;
 
-       err = snd_hda_create_spdif_out_ctls(codec,
-                                           spec->cvts[0].cvt_nid,
-                                           spec->cvts[0].cvt_nid);
+       per_cvt = get_cvt(spec, 0);
+       err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid,
+                                           per_cvt->cvt_nid);
        if (err < 0)
                return err;
        return simple_hdmi_build_jack(codec, 0);
@@ -1932,7 +1987,8 @@ static int simple_playback_build_controls(struct hda_codec *codec)
 static int simple_playback_init(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
-       hda_nid_t pin = spec->pins[0].pin_nid;
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
+       hda_nid_t pin = per_pin->pin_nid;
 
        snd_hda_codec_write(codec, pin, 0,
                            AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
@@ -1948,6 +2004,7 @@ static void simple_playback_free(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
 
+       hdmi_array_free(spec);
        kfree(spec);
 }
 
@@ -2111,20 +2168,29 @@ static int patch_simple_hdmi(struct hda_codec *codec,
                             hda_nid_t cvt_nid, hda_nid_t pin_nid)
 {
        struct hdmi_spec *spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       struct hdmi_spec_per_pin *per_pin;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
 
        codec->spec = spec;
+       hdmi_array_init(spec, 1);
 
        spec->multiout.num_dacs = 0;  /* no analog */
        spec->multiout.max_channels = 2;
        spec->multiout.dig_out_nid = cvt_nid;
        spec->num_cvts = 1;
        spec->num_pins = 1;
-       spec->cvts[0].cvt_nid = cvt_nid;
-       spec->pins[0].pin_nid = pin_nid;
+       per_pin = snd_array_new(&spec->pins);
+       per_cvt = snd_array_new(&spec->cvts);
+       if (!per_pin || !per_cvt) {
+               simple_playback_free(codec);
+               return -ENOMEM;
+       }
+       per_cvt->cvt_nid = cvt_nid;
+       per_pin->pin_nid = pin_nid;
        spec->pcm_playback = simple_pcm_playback;
 
        codec->patch_ops = simple_hdmi_patch_ops;
@@ -2201,9 +2267,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
        int i;
        struct hdmi_spec *spec = codec->spec;
        struct hda_spdif_out *spdif;
+       struct hdmi_spec_per_cvt *per_cvt;
 
        mutex_lock(&codec->spdif_mutex);
-       spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
+       per_cvt = get_cvt(spec, 0);
+       spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
 
        chs = substream->runtime->channels;
 
@@ -2325,13 +2393,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
        int err = simple_playback_build_pcms(codec);
-       spec->pcm_rec[0].own_chmap = true;
+       if (!err) {
+               struct hda_pcm *info = get_pcm_rec(spec, 0);
+               info->own_chmap = true;
+       }
        return err;
 }
 
 static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info;
        struct snd_pcm_chmap *chmap;
        int err;
 
@@ -2340,7 +2412,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
                return err;
 
        /* add channel maps */
-       err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm,
+       info = get_pcm_rec(spec, 0);
+       err = snd_pcm_add_chmap_ctls(info->pcm,
                                     SNDRV_PCM_STREAM_PLAYBACK,
                                     snd_pcm_alt_chmaps, 8, 0, &chmap);
        if (err < 0)
@@ -2395,6 +2468,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct snd_pcm_substream *substream)
 {
        struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0);
        int chans = substream->runtime->channels;
        int i, err;
 
@@ -2402,11 +2476,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                          substream);
        if (err < 0)
                return err;
-       snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+       snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
                            AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
        /* FIXME: XXX */
        for (i = 0; i < chans; i++) {
-               snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+               snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
                                    AC_VERB_SET_HDMI_CHAN_SLOT,
                                    (i << 4) | i);
        }
index f15c36b..28b3f5a 100644 (file)
@@ -34,7 +34,6 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
-#include "hda_beep.h"
 #include "hda_jack.h"
 #include "hda_generic.h"
 
@@ -53,6 +52,20 @@ enum {
        ALC_INIT_GPIO3,
 };
 
+enum {
+       ALC_HEADSET_MODE_UNKNOWN,
+       ALC_HEADSET_MODE_UNPLUGGED,
+       ALC_HEADSET_MODE_HEADSET,
+       ALC_HEADSET_MODE_MIC,
+       ALC_HEADSET_MODE_HEADPHONE,
+};
+
+enum {
+       ALC_HEADSET_TYPE_UNKNOWN,
+       ALC_HEADSET_TYPE_CTIA,
+       ALC_HEADSET_TYPE_OMTP,
+};
+
 struct alc_customize_define {
        unsigned int  sku_cfg;
        unsigned char port_connectivity;
@@ -86,6 +99,13 @@ struct alc_spec {
        int mute_led_polarity;
        hda_nid_t mute_led_nid;
 
+       unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
+
+       hda_nid_t headset_mic_pin;
+       hda_nid_t headphone_mic_pin;
+       int current_headset_mode;
+       int current_headset_type;
+
        /* hooks */
        void (*init_hook)(struct hda_codec *codec);
 #ifdef CONFIG_PM
@@ -805,17 +825,7 @@ static inline void alc_shutup(struct hda_codec *codec)
        snd_hda_shutup_pins(codec);
 }
 
-static void alc_free(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
-       snd_hda_gen_spec_free(&spec->gen);
-       snd_hda_detach_beep_device(codec);
-       kfree(spec);
-}
+#define alc_free       snd_hda_gen_free
 
 #ifdef CONFIG_PM
 static void alc_power_eapd(struct hda_codec *codec)
@@ -1401,6 +1411,7 @@ static int patch_alc880(struct hda_codec *codec)
 
        spec = codec->spec;
        spec->gen.need_dac_fix = 1;
+       spec->gen.beep_nid = 0x01;
 
        snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
                       alc880_fixups);
@@ -1411,12 +1422,8 @@ static int patch_alc880(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
        codec->patch_ops.unsol_event = alc880_unsol_event;
@@ -1455,6 +1462,7 @@ enum {
        ALC260_FIXUP_HP_B1900,
        ALC260_FIXUP_KN1,
        ALC260_FIXUP_FSC_S7020,
+       ALC260_FIXUP_FSC_S7020_JWSE,
 };
 
 static void alc260_gpio1_automute(struct hda_codec *codec)
@@ -1516,14 +1524,17 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.add_out_jack_modes = 1;
-               break;
-       case HDA_FIXUP_ACT_PROBE:
+       if (action == HDA_FIXUP_ACT_PROBE)
                spec->init_amp = ALC_INIT_NONE;
-               break;
+}
+
+static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.add_jack_modes = 1;
+               spec->gen.hp_mic = 1;
        }
 }
 
@@ -1586,6 +1597,12 @@ static const struct hda_fixup alc260_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc260_fixup_fsc_s7020,
        },
+       [ALC260_FIXUP_FSC_S7020_JWSE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_fsc_s7020_jwse,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_FSC_S7020,
+       },
 };
 
 static const struct snd_pci_quirk alc260_fixup_tbl[] = {
@@ -1602,6 +1619,14 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = {
        {}
 };
 
+static const struct hda_model_fixup alc260_fixup_models[] = {
+       {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
+       {.id = ALC260_FIXUP_COEF, .name = "coef"},
+       {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
+       {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
+       {}
+};
+
 /*
  */
 static int patch_alc260(struct hda_codec *codec)
@@ -1619,8 +1644,10 @@ static int patch_alc260(struct hda_codec *codec)
         * it's almost harmless.
         */
        spec->gen.prefer_hp_amp = 1;
+       spec->gen.beep_nid = 0x01;
 
-       snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+       snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
+                          alc260_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
        /* automatic parse from the BIOS config */
@@ -1628,12 +1655,8 @@ static int patch_alc260(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog)
                set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
        spec->shutup = alc_eapd_shutup;
@@ -2132,17 +2155,16 @@ static int patch_alc882(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
        /* automatic parse from the BIOS config */
        err = alc882_parse_auto_config(codec);
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog && spec->gen.beep_nid)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
 
@@ -2295,17 +2317,16 @@ static int patch_alc262(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
        /* automatic parse from the BIOS config */
        err = alc262_parse_auto_config(codec);
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog && spec->gen.beep_nid)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
        spec->shutup = alc_eapd_shutup;
@@ -2386,16 +2407,7 @@ static const struct snd_pci_quirk alc268_fixup_tbl[] = {
 static int alc268_parse_auto_config(struct hda_codec *codec)
 {
        static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       struct alc_spec *spec = codec->spec;
-       int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
-       if (err > 0) {
-               if (!spec->gen.no_analog &&
-                   spec->gen.autocfg.speaker_pins[0] != 0x1d) {
-                       add_mixer(spec, alc268_beep_mixer);
-                       snd_hda_add_verbs(codec, alc268_beep_init_verbs);
-               }
-       }
-       return err;
+       return alc_parse_auto_config(codec, NULL, alc268_ssids);
 }
 
 /*
@@ -2403,7 +2415,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 static int patch_alc268(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int i, has_beep, err;
+       int err;
 
        /* ALC268 has no aa-loopback mixer */
        err = alc_alloc_spec(codec, 0);
@@ -2411,6 +2423,7 @@ static int patch_alc268(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       spec->gen.beep_nid = 0x01;
 
        snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -2420,18 +2433,10 @@ static int patch_alc268(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       has_beep = 0;
-       for (i = 0; i < spec->num_mixers; i++) {
-               if (spec->mixers[i] == alc268_beep_mixer) {
-                       has_beep = 1;
-                       break;
-               }
-       }
-
-       if (has_beep) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (err > 0 && !spec->gen.no_analog &&
+           spec->gen.autocfg.speaker_pins[0] != 0x1d) {
+               add_mixer(spec, alc268_beep_mixer);
+               snd_hda_add_verbs(codec, alc268_beep_init_verbs);
                if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
                        /* override the amp caps for beep generator */
                        snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
@@ -2631,7 +2636,8 @@ static void alc271_fixup_dmic(struct hda_codec *codec,
        };
        unsigned int cfg;
 
-       if (strcmp(codec->chip_name, "ALC271X"))
+       if (strcmp(codec->chip_name, "ALC271X") &&
+           strcmp(codec->chip_name, "ALC269VB"))
                return;
        cfg = snd_hda_codec_get_pincfg(codec, 0x12);
        if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
@@ -2693,6 +2699,34 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec,
        spec->gen.automute_hook = alc269_quanta_automute;
 }
 
+static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_tbl *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+       msleep(200);
+       snd_hda_gen_hp_automute(codec, jack);
+
+       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+       msleep(100);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+       msleep(500);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
+       }
+}
+
+
 /* update mute-LED according to the speaker mute state via mic VREF pin */
 static void alc269_fixup_mic_mute_hook(void *private_data, int enabled)
 {
@@ -2757,6 +2791,356 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
        }
 }
 
+/* turn on/off mute LED per vmaster hook */
+static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct alc_spec *spec = codec->spec;
+       unsigned int oldval = spec->gpio_led;
+
+       if (enabled)
+               spec->gpio_led &= ~0x08;
+       else
+               spec->gpio_led |= 0x08;
+       if (spec->gpio_led != oldval)
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+}
+
+/* turn on/off mic-mute LED per capture hook */
+static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int oldval = spec->gpio_led;
+
+       if (!ucontrol)
+               return;
+
+       if (ucontrol->value.integer.value[0] ||
+           ucontrol->value.integer.value[1])
+               spec->gpio_led &= ~0x10;
+       else
+               spec->gpio_led |= 0x10;
+       if (spec->gpio_led != oldval)
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+}
+
+static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
+               {}
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+               spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook;
+               spec->gpio_led = 0;
+               snd_hda_add_verbs(codec, gpio_init);
+       }
+}
+
+static void alc_headset_mode_unplugged(struct hda_codec *codec)
+{
+       int val;
+
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               val = alc_read_coef_idx(codec, 0x35);
+               alc_write_coef_idx(codec, 0x35, val & 0xbfff);
+               alc_write_coef_idx(codec, 0x06, 0x2104);
+               alc_write_coef_idx(codec, 0x1a, 0x0001);
+               alc_write_coef_idx(codec, 0x26, 0x0004);
+               alc_write_coef_idx(codec, 0x32, 0x42a3);
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x76, 0x000e);
+               alc_write_coef_idx(codec, 0x6c, 0x2400);
+               alc_write_coef_idx(codec, 0x18, 0x7308);
+               alc_write_coef_idx(codec, 0x6b, 0xc429);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x15, 0x0d40);
+               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               break;
+       }
+       snd_printdd("Headset jack set to unplugged mode.\n");
+}
+
+
+static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+                                   hda_nid_t mic_pin)
+{
+       int val;
+
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               val = alc_read_coef_idx(codec, 0x35);
+               alc_write_coef_idx(codec, 0x35, val | 1<<14);
+               alc_write_coef_idx(codec, 0x06, 0x2100);
+               alc_write_coef_idx(codec, 0x1a, 0x0021);
+               alc_write_coef_idx(codec, 0x26, 0x008c);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0292:
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_write_coef_idx(codec, 0x19, 0xa208);
+               alc_write_coef_idx(codec, 0x2e, 0xacf0);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x11, 0x0001);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               alc_write_coef_idx(codec, 0xb5, 0x1040);
+               val = alc_read_coef_idx(codec, 0xc3);
+               alc_write_coef_idx(codec, 0xc3, val | 1<<12);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       }
+       snd_printdd("Headset jack set to mic-in mode.\n");
+}
+
+static void alc_headset_mode_default(struct hda_codec *codec)
+{
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x06, 0x2100);
+               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x76, 0x000e);
+               alc_write_coef_idx(codec, 0x6c, 0x2400);
+               alc_write_coef_idx(codec, 0x6b, 0xc429);
+               alc_write_coef_idx(codec, 0x18, 0x7308);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x11, 0x0041);
+               alc_write_coef_idx(codec, 0x15, 0x0d40);
+               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               break;
+       }
+       snd_printdd("Headset jack set to headphone (default) mode.\n");
+}
+
+/* Iphone type */
+static void alc_headset_mode_ctia(struct hda_codec *codec)
+{
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xd429);
+               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x6b, 0xd429);
+               alc_write_coef_idx(codec, 0x76, 0x0008);
+               alc_write_coef_idx(codec, 0x18, 0x7388);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x15, 0x0d60);
+               alc_write_coef_idx(codec, 0xc3, 0x0000);
+               break;
+       }
+       snd_printdd("Headset jack set to iPhone-style headset mode.\n");
+}
+
+/* Nokia type */
+static void alc_headset_mode_omtp(struct hda_codec *codec)
+{
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xe429);
+               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x6b, 0xe429);
+               alc_write_coef_idx(codec, 0x76, 0x0008);
+               alc_write_coef_idx(codec, 0x18, 0x7388);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x15, 0x0d50);
+               alc_write_coef_idx(codec, 0xc3, 0x0000);
+               break;
+       }
+       snd_printdd("Headset jack set to Nokia-style headset mode.\n");
+}
+
+static void alc_determine_headset_type(struct hda_codec *codec)
+{
+       int val;
+       bool is_ctia = false;
+       struct alc_spec *spec = codec->spec;
+
+       switch (codec->vendor_id) {
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xd029);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x6b, 0xd429);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x6c);
+               is_ctia = (val & 0x001c) == 0x001c;
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x11, 0x0001);
+               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               alc_write_coef_idx(codec, 0x15, 0x0d60);
+               alc_write_coef_idx(codec, 0xc3, 0x0c00);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0xbe);
+               is_ctia = (val & 0x1c02) == 0x1c02;
+               break;
+       }
+
+       snd_printdd("Headset jack detected iPhone-style headset: %s\n",
+                   is_ctia ? "yes" : "no");
+       spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
+}
+
+static void alc_update_headset_mode(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+
+       int new_headset_mode;
+
+       if (!snd_hda_jack_detect(codec, hp_pin))
+               new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
+       else if (mux_pin == spec->headset_mic_pin)
+               new_headset_mode = ALC_HEADSET_MODE_HEADSET;
+       else if (mux_pin == spec->headphone_mic_pin)
+               new_headset_mode = ALC_HEADSET_MODE_MIC;
+       else
+               new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
+
+       if (new_headset_mode == spec->current_headset_mode)
+               return;
+
+       switch (new_headset_mode) {
+       case ALC_HEADSET_MODE_UNPLUGGED:
+               alc_headset_mode_unplugged(codec);
+               spec->gen.hp_jack_present = false;
+               break;
+       case ALC_HEADSET_MODE_HEADSET:
+               if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
+                       alc_determine_headset_type(codec);
+               if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
+                       alc_headset_mode_ctia(codec);
+               else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
+                       alc_headset_mode_omtp(codec);
+               spec->gen.hp_jack_present = true;
+               break;
+       case ALC_HEADSET_MODE_MIC:
+               alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
+               spec->gen.hp_jack_present = false;
+               break;
+       case ALC_HEADSET_MODE_HEADPHONE:
+               alc_headset_mode_default(codec);
+               spec->gen.hp_jack_present = true;
+               break;
+       }
+       if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
+               snd_hda_set_pin_ctl_cache(codec, hp_pin,
+                                         AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+               if (spec->headphone_mic_pin)
+                       snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
+                                                 PIN_VREFHIZ);
+       }
+       spec->current_headset_mode = new_headset_mode;
+
+       snd_hda_gen_update_outputs(codec);
+}
+
+static void alc_update_headset_mode_hook(struct hda_codec *codec,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       alc_update_headset_mode(codec);
+}
+
+static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->current_headset_type = ALC_HEADSET_MODE_UNKNOWN;
+       snd_hda_gen_hp_automute(codec, jack);
+}
+
+static void alc_probe_headset_mode(struct hda_codec *codec)
+{
+       int i;
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+       /* Find mic pins */
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
+                       spec->headset_mic_pin = cfg->inputs[i].pin;
+               if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
+                       spec->headphone_mic_pin = cfg->inputs[i].pin;
+       }
+
+       spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
+       spec->gen.automute_hook = alc_update_headset_mode;
+       spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
+}
+
+static void alc_fixup_headset_mode(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               alc_probe_headset_mode(codec);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               spec->current_headset_mode = 0;
+               alc_update_headset_mode(codec);
+               break;
+       }
+}
+
+static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+       }
+       else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               int val;
+               alc_write_coef_idx(codec, 0xc4, 0x8000);
+               val = alc_read_coef_idx(codec, 0xc2);
+               alc_write_coef_idx(codec, 0xc2, val & 0xfe);
+               snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+       }
+       alc_fixup_headset_mode(codec, fix, action);
+}
+
 static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
                                    const struct hda_fixup *fix,
                                    int action)
@@ -2792,11 +3176,20 @@ enum {
        ALC269_FIXUP_HP_MUTE_LED,
        ALC269_FIXUP_HP_MUTE_LED_MIC1,
        ALC269_FIXUP_HP_MUTE_LED_MIC2,
+       ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
+       ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+       ALC269_FIXUP_HEADSET_MODE,
+       ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
+       ALC269_FIXUP_ASUS_X101_FUNC,
+       ALC269_FIXUP_ASUS_X101_VERB,
+       ALC269_FIXUP_ASUS_X101,
        ALC271_FIXUP_AMIC_MIC2,
        ALC271_FIXUP_HP_GATE_MIC_JACK,
+       ALC269_FIXUP_ACER_AC700,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -2931,6 +3324,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_hp_mute_led_mic2,
        },
+       [ALC269_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_gpio_led,
+       },
        [ALC269_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic_0x12,
@@ -2949,6 +3346,59 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
        },
+       [ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x21014020 }, /* dock line out */
+                       { 0x19, 0x21a19030 }, /* dock mic */
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC269_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode,
+       },
+       [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_no_hp_mic,
+       },
+       [ALC269_FIXUP_ASUS_X101_FUNC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_x101_headset_mic,
+       },
+       [ALC269_FIXUP_ASUS_X101_VERB] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+                       {0x20, AC_VERB_SET_PROC_COEF,  0x0310},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_ASUS_X101_FUNC
+       },
+       [ALC269_FIXUP_ASUS_X101] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x04a1182c }, /* Headset mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_ASUS_X101_VERB
+       },
        [ALC271_FIXUP_AMIC_MIC2] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -2965,12 +3415,46 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC271_FIXUP_AMIC_MIC2,
        },
+       [ALC269_FIXUP_ACER_AC700] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x03a11c20 }, /* mic */
+                       { 0x1e, 0x0346101e }, /* SPDIF1 */
+                       { 0x21, 0x0321101f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC271_FIXUP_DMIC,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05ec, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05ed, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05ee, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f3, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
@@ -2983,11 +3467,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
        SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
@@ -3063,6 +3549,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
        {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
        {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
+       {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
        {}
 };
 
@@ -3131,6 +3618,9 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
        switch (codec->vendor_id) {
        case 0x10ec0269:
                spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -3179,12 +3669,8 @@ static int patch_alc269(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog && spec->gen.beep_nid)
                set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
@@ -3292,6 +3778,7 @@ static int patch_alc861(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       spec->gen.beep_nid = 0x23;
 
        snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -3301,12 +3788,8 @@ static int patch_alc861(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog) {
-               err = snd_hda_attach_beep_device(codec, 0x23);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog)
                set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
@@ -3387,6 +3870,7 @@ static int patch_alc861vd(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       spec->gen.beep_nid = 0x23;
 
        snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -3396,12 +3880,8 @@ static int patch_alc861vd(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog) {
-               err = snd_hda_attach_beep_device(codec, 0x23);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-       }
 
        codec->patch_ops = alc_patch_ops;
 
@@ -3480,6 +3960,8 @@ enum {
        ALC662_FIXUP_NO_JACK_DETECT,
        ALC662_FIXUP_ZOTAC_Z68,
        ALC662_FIXUP_INV_DMIC,
+       ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC668_FIXUP_HEADSET_MODE,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -3640,6 +4122,20 @@ static const struct hda_fixup alc662_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic_0x12,
        },
+       [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_HEADSET_MODE
+       },
+       [ALC668_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc668,
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -3648,6 +4144,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
@@ -3784,10 +4282,14 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
        if ((alc_get_coef0(codec) & (1 << 14)) &&
            codec->bus->pci->subsystem_vendor == 0x1025 &&
            spec->cdefine.platform_type == 1) {
-               if (alc_codec_rename(codec, "ALC272X") < 0)
+               err = alc_codec_rename(codec, "ALC272X");
+               if (err < 0)
                        goto error;
        }
 
@@ -3796,10 +4298,7 @@ static int patch_alc662(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->gen.no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0)
-                       goto error;
+       if (!spec->gen.no_analog && spec->gen.beep_nid) {
                switch (codec->vendor_id) {
                case 0x10ec0662:
                        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
index dafe04a..1d9d642 100644 (file)
@@ -211,7 +211,6 @@ struct sigmatel_spec {
 
        /* beep widgets */
        hda_nid_t anabeep_nid;
-       hda_nid_t digbeep_nid;
 
        /* SPDIF-out mux */
        const char * const *spdif_labels;
@@ -3529,8 +3528,12 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        int err;
+       int flags = 0;
 
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       if (spec->headset_jack)
+               flags |= HDA_PINCFG_HEADSET_MIC;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, flags);
        if (err < 0)
                return err;
 
@@ -3560,16 +3563,13 @@ static int stac_parse_auto_config(struct hda_codec *codec)
 
        /* setup digital beep controls and input device */
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
-       if (spec->digbeep_nid > 0) {
-               hda_nid_t nid = spec->digbeep_nid;
+       if (spec->gen.beep_nid) {
+               hda_nid_t nid = spec->gen.beep_nid;
                unsigned int caps;
 
                err = stac_auto_create_beep_ctls(codec, nid);
                if (err < 0)
                        return err;
-               err = snd_hda_attach_beep_device(codec, nid);
-               if (err < 0)
-                       return err;
                if (codec->beep) {
                        /* IDT/STAC codecs have linear beep tone parameter */
                        codec->beep->linear_tone = spec->linear_tone_beep;
@@ -3657,17 +3657,7 @@ static void stac_shutup(struct hda_codec *codec)
                                ~spec->eapd_mask);
 }
 
-static void stac_free(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
-       snd_hda_gen_spec_free(&spec->gen);
-       kfree(spec);
-       snd_hda_detach_beep_device(codec);
-}
+#define stac_free      snd_hda_gen_free
 
 #ifdef CONFIG_PROC_FS
 static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
@@ -3797,6 +3787,7 @@ static int patch_stac9200(struct hda_codec *codec)
        spec->gen.own_eapd_ctl = 1;
 
        codec->patch_ops = stac_patch_ops;
+       codec->power_filter = snd_hda_codec_eapd_power_filter;
 
        snd_hda_add_verbs(codec, stac9200_eapd_init);
 
@@ -3884,7 +3875,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
        spec->aloopback_mask = 0x01;
        spec->aloopback_shift = 8;
 
-       spec->digbeep_nid = 0x1c;
+       spec->gen.beep_nid = 0x1c; /* digital beep */
 
        /* GPIO0 High = Enable EAPD */
        spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
@@ -3968,7 +3959,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->gen.power_down_unused = 1;
        spec->gen.mixer_nid = 0x1b;
 
-       spec->digbeep_nid = 0x21;
+       spec->gen.beep_nid = 0x21; /* digital beep */
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->default_polarity = -1; /* no default cfg */
@@ -4016,7 +4007,7 @@ static int patch_stac92hd95(struct hda_codec *codec)
        spec->gen.own_eapd_ctl = 1;
        spec->gen.power_down_unused = 1;
 
-       spec->digbeep_nid = 0x19;
+       spec->gen.beep_nid = 0x19; /* digital beep */
        spec->pwr_nids = stac92hd95_pwr_nids;
        spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids);
        spec->default_polarity = -1; /* no default cfg */
@@ -4091,7 +4082,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
        spec->aloopback_shift = 0;
 
        spec->powerdown_adcs = 1;
-       spec->digbeep_nid = 0x26;
+       spec->gen.beep_nid = 0x26; /* digital beep */
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
        spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
@@ -4173,7 +4164,7 @@ static int patch_stac927x(struct hda_codec *codec)
        spec->have_spdif_mux = 1;
        spec->spdif_labels = stac927x_spdif_labels;
 
-       spec->digbeep_nid = 0x23;
+       spec->gen.beep_nid = 0x23; /* digital beep */
 
        /* GPIO0 High = Enable EAPD */
        spec->eapd_mask = spec->gpio_mask = 0x01;
@@ -4232,7 +4223,7 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->gen.own_eapd_ctl = 1;
        spec->have_spdif_mux = 1;
 
-       spec->digbeep_nid = 0x23;
+       spec->gen.beep_nid = 0x23; /* digital beep */
 
        snd_hda_add_verbs(codec, stac9205_core_init);
        spec->aloopback_ctl = &stac9205_loopback;
index c35338a..e0dadcf 100644 (file)
@@ -626,11 +626,31 @@ static void via_set_jack_unsol_events(struct hda_codec *codec)
        }
 }
 
+static const struct badness_table via_main_out_badness = {
+       .no_primary_dac = 0x10000,
+       .no_dac = 0x4000,
+       .shared_primary = 0x10000,
+       .shared_surr = 0x20,
+       .shared_clfe = 0x20,
+       .shared_surr_main = 0x20,
+};
+static const struct badness_table via_extra_out_badness = {
+       .no_primary_dac = 0x4000,
+       .no_dac = 0x4000,
+       .shared_primary = 0x12,
+       .shared_surr = 0x20,
+       .shared_clfe = 0x20,
+       .shared_surr_main = 0x10,
+};
+
 static int via_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
 
+       spec->gen.main_out_badness = &via_main_out_badness;
+       spec->gen.extra_out_badness = &via_extra_out_badness;
+
        err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
        if (err < 0)
                return err;
index 223c3d9..9ea05e9 100644 (file)
@@ -969,6 +969,7 @@ static int snd_hdspm_create_pcm(struct snd_card *card,
                                struct hdspm *hdspm);
 
 static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
+static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
 static int hdspm_autosync_ref(struct hdspm *hdspm);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
@@ -1075,6 +1076,20 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
        return ret;
 }
 
+/* round arbitary sample rates to commonly known rates */
+static int hdspm_round_frequency(int rate)
+{
+       if (rate < 38050)
+               return 32000;
+       if (rate < 46008)
+               return 44100;
+       else
+               return 48000;
+}
+
+static int hdspm_tco_sync_check(struct hdspm *hdspm);
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
+
 /* check for external sample rate */
 static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
@@ -1216,22 +1231,45 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                                break;
                        }
 
-                       /* QS and DS rates normally can not be detected
-                        * automatically by the card. Only exception is MADI
-                        * in 96k frame mode.
-                        *
-                        * So if we read SS values (32 .. 48k), check for
-                        * user-provided DS/QS bits in the control register
-                        * and multiply the base frequency accordingly.
-                        */
-                       if (rate <= 48000) {
-                               if (hdspm->control_register & HDSPM_QuadSpeed)
-                                       rate *= 4;
-                               else if (hdspm->control_register &
-                                               HDSPM_DoubleSpeed)
-                                       rate *= 2;
+               } /* endif HDSPM_madiLock */
+
+               /* check sample rate from TCO or SYNC_IN */
+               {
+                       bool is_valid_input = 0;
+                       bool has_sync = 0;
+
+                       syncref = hdspm_autosync_ref(hdspm);
+                       if (HDSPM_AUTOSYNC_FROM_TCO == syncref) {
+                               is_valid_input = 1;
+                               has_sync = (HDSPM_SYNC_CHECK_SYNC ==
+                                       hdspm_tco_sync_check(hdspm));
+                       } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) {
+                               is_valid_input = 1;
+                               has_sync = (HDSPM_SYNC_CHECK_SYNC ==
+                                       hdspm_sync_in_sync_check(hdspm));
+                       }
+
+                       if (is_valid_input && has_sync) {
+                               rate = hdspm_round_frequency(
+                                       hdspm_get_pll_freq(hdspm));
                        }
                }
+
+               /* QS and DS rates normally can not be detected
+                * automatically by the card. Only exception is MADI
+                * in 96k frame mode.
+                *
+                * So if we read SS values (32 .. 48k), check for
+                * user-provided DS/QS bits in the control register
+                * and multiply the base frequency accordingly.
+                */
+               if (rate <= 48000) {
+                       if (hdspm->control_register & HDSPM_QuadSpeed)
+                               rate *= 4;
+                       else if (hdspm->control_register &
+                                       HDSPM_DoubleSpeed)
+                               rate *= 2;
+               }
                break;
        }
 
@@ -1979,16 +2017,25 @@ static void hdspm_midi_tasklet(unsigned long arg)
 /* get the system sample rate which is set */
 
 
+static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
+{
+       unsigned int period, rate;
+
+       period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
+       rate = hdspm_calc_dds_value(hdspm, period);
+
+       return rate;
+}
+
 /**
  * Calculate the real sample rate from the
  * current DDS value.
  **/
 static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
 {
-       unsigned int period, rate;
+       unsigned int rate;
 
-       period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
-       rate = hdspm_calc_dds_value(hdspm, period);
+       rate = hdspm_get_pll_freq(hdspm);
 
        if (rate > 207000) {
                /* Unreasonable high sample rate as seen on PCI MADI cards. */
@@ -2128,6 +2175,16 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
        return (status >> (idx*4)) & 0xF;
 }
 
+#define ENUMERATED_CTL_INFO(info, texts) \
+{ \
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
+       uinfo->count = 1; \
+       uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \
+               uinfo->value.enumerated.item =  uinfo->value.enumerated.items - 1; \
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \
+}
+
 
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
@@ -2143,14 +2200,7 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
 static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol,
                                               struct snd_ctl_elem_info *uinfo)
 {
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 10;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       texts_freq[uinfo->value.enumerated.item]);
+       ENUMERATED_CTL_INFO(uinfo, texts_freq);
        return 0;
 }
 
@@ -2316,15 +2366,7 @@ static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
                                            struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "Master", "AutoSync" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                   uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              texts[uinfo->value.enumerated.item]);
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -2888,6 +2930,112 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+
+
+#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READ |\
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+       .info = snd_hdspm_info_tco_video_input_format, \
+       .get = snd_hdspm_get_tco_video_input_format, \
+}
+
+static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {"No video", "NTSC", "PAL"};
+       ENUMERATED_CTL_INFO(uinfo, texts);
+       return 0;
+}
+
+static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       u32 status;
+       int ret = 0;
+
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+       switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC |
+                       HDSPM_TCO1_Video_Input_Format_PAL)) {
+       case HDSPM_TCO1_Video_Input_Format_NTSC:
+               /* ntsc */
+               ret = 1;
+               break;
+       case HDSPM_TCO1_Video_Input_Format_PAL:
+               /* pal */
+               ret = 2;
+               break;
+       default:
+               /* no video */
+               ret = 0;
+               break;
+       }
+       ucontrol->value.enumerated.item[0] = ret;
+       return 0;
+}
+
+
+
+#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READ |\
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+       .info = snd_hdspm_info_tco_ltc_frames, \
+       .get = snd_hdspm_get_tco_ltc_frames, \
+}
+
+static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
+                               "30 fps"};
+       ENUMERATED_CTL_INFO(uinfo, texts);
+       return 0;
+}
+
+static int hdspm_tco_ltc_frames(struct hdspm *hdspm)
+{
+       u32 status;
+       int ret = 0;
+
+       status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+       if (status & HDSPM_TCO1_LTC_Input_valid) {
+               switch (status & (HDSPM_TCO1_LTC_Format_LSB |
+                                       HDSPM_TCO1_LTC_Format_MSB)) {
+               case 0:
+                       /* 24 fps */
+                       ret = 1;
+                       break;
+               case HDSPM_TCO1_LTC_Format_LSB:
+                       /* 25 fps */
+                       ret = 2;
+                       break;
+               case HDSPM_TCO1_LTC_Format_MSB:
+                       /* 25 fps */
+                       ret = 3;
+                       break;
+               default:
+                       /* 30 fps */
+                       ret = 4;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm);
+       return 0;
+}
+
 #define HDSPM_TOGGLE_SETTING(xname, xindex) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
        .name = xname, \
@@ -2974,17 +3122,7 @@ static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "optical", "coaxial" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                   uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3046,17 +3184,7 @@ static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "Single", "Double" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                   uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3129,17 +3257,7 @@ static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "Single", "Double", "Quad" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 3;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                   uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3215,17 +3333,7 @@ static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "Single", "Double", "Quad" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 3;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                   uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3445,19 +3553,30 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
        .get = snd_hdspm_get_sync_check \
 }
 
+#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .private_value = xindex, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+       .info = snd_hdspm_tco_info_lock_check, \
+       .get = snd_hdspm_get_sync_check \
+}
+
+
 
 static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
+       ENUMERATED_CTL_INFO(uinfo, texts);
+       return 0;
+}
+
+static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = { "No Lock", "Lock" };
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3590,6 +3709,14 @@ static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx)
        return 0;
 }
 
+static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask)
+{
+       u32 status;
+       status = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+
+       return (status & mask) ? 1 : 0;
+}
+
 
 static int hdspm_tco_sync_check(struct hdspm *hdspm)
 {
@@ -3697,6 +3824,22 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
 
        }
 
+       if (hdspm->tco) {
+               switch (kcontrol->private_value) {
+               case 11:
+                       /* Check TCO for lock state of its current input */
+                       val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock);
+                       break;
+               case 12:
+                       /* Check TCO for valid time code on LTC input. */
+                       val = hdspm_tco_input_check(hdspm,
+                               HDSPM_TCO1_LTC_Input_valid);
+                       break;
+               default:
+                       break;
+               }
+       }
+
        if (-1 == val)
                val = 3;
 
@@ -3813,17 +3956,7 @@ static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "44.1 kHz", "48 kHz" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3869,17 +4002,7 @@ static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 5;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3924,17 +4047,7 @@ static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
                                             struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 3;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -3981,17 +4094,7 @@ static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
 {
        static char *texts[] = { "24 fps", "25 fps", "29.97fps",
                "29.97 dfps", "30 fps", "30 dfps" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 6;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -4037,17 +4140,7 @@ static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = { "LTC", "Video", "WCK" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 3;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       texts[uinfo->value.enumerated.item]);
-
+       ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
 
@@ -4145,6 +4238,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
        HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3),
        HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut),
        HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch),
+       HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX),
        HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms),
        HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp),
        HDSPM_INPUT_SELECT("Input Select", 0),
@@ -4272,7 +4366,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
        HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0),
        HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0),
        HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0),
-       HDSPM_TCO_WORD_TERM("TCO Word Term", 0)
+       HDSPM_TCO_WORD_TERM("TCO Word Term", 0),
+       HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11),
+       HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12),
+       HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0),
+       HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0)
 };
 
 
index e13580d..f3fdfa0 100644 (file)
@@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                break;
 
        case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+               /*
+                * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
+                *
+                * The SSC transmit clock is obtained from the BCLK signal on
+                * on the TK line, and the SSC receive clock is
+                * generated from the transmit clock.
+                *
+                * Data is transferred on first BCLK after LRC pulse rising
+                * edge.If stereo, the right channel data is contiguous with
+                * the left channel data.
+                */
+               rcmr =    SSC_BF(RCMR_PERIOD, 0)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, SSC_CKS_PIN);
+
+               rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(RFMR_FSLEN, 0)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, 0)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+
+               tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(TFMR_FSLEN, 0)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
        default:
                printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
                        ssc_p->daifmt);
@@ -707,13 +750,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
                .ops = &atmel_ssc_dai_ops,
 };
 
+static const struct snd_soc_component_driver atmel_ssc_component = {
+       .name           = "atmel-ssc",
+};
+
 static int asoc_ssc_init(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct ssc_device *ssc = platform_get_drvdata(pdev);
        int ret;
 
-       ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
+       ret = snd_soc_register_component(dev, &atmel_ssc_component,
+                                        &atmel_ssc_dai, 1);
        if (ret) {
                dev_err(dev, "Could not register DAI: %d\n", ret);
                goto err;
@@ -732,7 +780,7 @@ static int asoc_ssc_init(struct device *dev)
        return 0;
 
 err_unregister_dai:
-       snd_soc_unregister_dai(dev);
+       snd_soc_unregister_component(dev);
 err:
        return ret;
 }
@@ -747,7 +795,7 @@ static void asoc_ssc_exit(struct device *dev)
        else
                atmel_pcm_pdc_platform_unregister(dev);
 
-       snd_soc_unregister_dai(dev);
+       snd_soc_unregister_component(dev);
 }
 
 /**
index ea7d9d1..44b8dce 100644 (file)
@@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
        .ops                    = &alchemy_ac97c_ops,
 };
 
+static const struct snd_soc_component_driver au1xac97c_component = {
+       .name           = "au1xac97c",
+};
+
 static int au1xac97c_drvprobe(struct platform_device *pdev)
 {
        int ret;
@@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
+       ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
+                                        &au1xac97c_dai_driver, 1);
        if (ret)
                return ret;
 
@@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        WR(ctx, AC97_ENABLE, EN_D);     /* clock off, disable */
 
index 072448a..b3f37f6 100644 (file)
@@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
        .ops = &au1xi2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xi2s_component = {
+       .name           = "au1xi2s",
+};
+
 static int au1xi2s_drvprobe(struct platform_device *pdev)
 {
        struct resource *iores, *dmares;
@@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
+       return snd_soc_register_component(&pdev->dev, &au1xi2s_component,
+                                         &au1xi2s_dai_driver, 1);
 }
 
 static int au1xi2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        WR(ctx, I2S_ENABLE, EN_D);      /* clock off, disable */
 
index 6ba07e3..8f1862a 100644 (file)
@@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
        .ops = &au1xpsc_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_ac97_component = {
+       .name           = "au1xpsc-ac97",
+};
+
 static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
        int ret;
@@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
-       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+       ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
+                                        &wd->dai_drv, 1);
        if (ret)
                return ret;
 
@@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        /* disable PSC completely */
        au_writel(0, AC97_CFG(wd));
index 360b4e5..fe923a7 100644 (file)
@@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
        .ops = &au1xpsc_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_i2s_component = {
+       .name           = "au1xpsc-i2s",
+};
+
 static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
        struct resource *iores, *dmares;
@@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
-       return snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+       return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component,
+                                         &wd->dai_drv, 1);
 }
 
 static int au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        au_writel(0, I2S_CFG(wd));
        au_sync();
index 8e41bcb..4902173 100644 (file)
@@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
+static const struct snd_soc_component_driver bfin_ac97_component = {
+       .name           = "bfin-ac97",
+};
+
 static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
+                                        &bfin_ac97_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
index 168d88b..dd0c2a4 100644 (file)
@@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .ops = &bf5xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_i2s_component = {
+       .name           = "bf5xx-i2s",
+};
+
 static int bf5xx_i2s_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
                return -ENODEV;
 
        /* register with the ASoC layers */
-       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
+                                        &bf5xx_i2s_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                sport_done(sport_handle);
@@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
 
        pr_debug("%s enter\n", __func__);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 
        return 0;
index c1e516e..69e9a3e 100644 (file)
@@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
        .ops = &bf5xx_tdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_tdm_component = {
+       .name           = "bf5xx-tdm",
+};
+
 static int bfin_tdm_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
+                                        &bf5xx_tdm_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 
        return 0;
index 8f33797..c02405c 100644 (file)
@@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = {
        .ops = &bfin_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bfin_i2s_component = {
+       .name           = "bfin-i2s",
+};
+
 static int bfin_i2s_probe(struct platform_device *pdev)
 {
        struct sport_device *sport;
@@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev)
                return -ENODEV;
 
        /* register with the ASoC layers */
-       ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
+       ret = snd_soc_register_component(dev, &bfin_i2s_component,
+                                        &bfin_i2s_dai, 1);
        if (ret) {
                dev_err(dev, "Failed to register DAI: %d\n", ret);
                sport_delete(sport);
@@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev)
 {
        struct sport_device *sport = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_delete(sport);
 
        return 0;
index 8d30886..7798fbd 100644 (file)
@@ -354,6 +354,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
        .ops                    = &ep93xx_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_ac97_component = {
+       .name           = "ep93xx-ac97",
+};
+
 static int ep93xx_ac97_probe(struct platform_device *pdev)
 {
        struct ep93xx_ac97_info *info;
@@ -391,7 +395,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
        ep93xx_ac97_info = info;
        platform_set_drvdata(pdev, info);
 
-       ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
+                                        &ep93xx_ac97_dai, 1);
        if (ret)
                goto fail;
 
@@ -408,7 +413,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
 {
        struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        /* disable the AC97 controller */
        ep93xx_ac97_write_reg(info, AC97GCR, 0);
index 83075b3..5c1102e 100644 (file)
@@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .ops            = &ep93xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_i2s_component = {
+       .name           = "ep93xx-i2s",
+};
+
 static int ep93xx_i2s_probe(struct platform_device *pdev)
 {
        struct ep93xx_i2s_info *info;
@@ -405,7 +409,8 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, info);
        info->dma_data = ep93xx_i2s_dma_data;
 
-       err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
+       err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
+                                        &ep93xx_i2s_dai, 1);
        if (err)
                goto fail_put_lrclk;
 
@@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
 {
        struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
        clk_put(info->lrclk);
        clk_put(info->sclk);
index 350b864..2f45f00 100644 (file)
@@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4641 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
+       select SND_SOC_AK5386
        select SND_SOC_ALC5623 if I2C
        select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
@@ -63,6 +64,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA529 if I2C
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+       select SND_SOC_TAS5086 if I2C
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
        select SND_SOC_TLV320AIC32X4 if I2C
@@ -203,6 +205,9 @@ config SND_SOC_AK4642
 config SND_SOC_AK4671
        tristate
 
+config SND_SOC_AK5386
+       tristate
+
 config SND_SOC_ALC5623
        tristate
 config SND_SOC_ALC5632
@@ -320,6 +325,9 @@ config SND_SOC_STA529
 config SND_SOC_STAC9766
        tristate
 
+config SND_SOC_TAS5086
+       tristate
+
 config SND_SOC_TLV320AIC23
        tristate
 
index 6a3b3c3..b9e41c9 100644 (file)
@@ -14,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
+snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
@@ -55,6 +56,7 @@ snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
+snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -137,6 +139,7 @@ obj-$(CONFIG_SND_SOC_AK4535)        += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4641)   += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
+obj-$(CONFIG_SND_SOC_AK5386)   += snd-soc-ak5386.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)  += snd-soc-arizona.o
@@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_SSM2602)       += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
index 068b3ae..1aa10dd 100644 (file)
@@ -133,6 +133,8 @@ struct adau1373 {
 #define ADAU1373_DAI_FORMAT_DSP                0x3
 
 #define ADAU1373_BCLKDIV_SOURCE                BIT(5)
+#define ADAU1373_BCLKDIV_SR_MASK       (0x07 << 2)
+#define ADAU1373_BCLKDIV_BCLK_MASK     0x03
 #define ADAU1373_BCLKDIV_32            0x03
 #define ADAU1373_BCLKDIV_64            0x02
 #define ADAU1373_BCLKDIV_128           0x01
@@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
        adau1373_dai->enable_src = (div != 0);
 
        snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
-               ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
+               ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
+               (div << 2) | ADAU1373_BCLKDIV_64);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
index 6f6c335..c7cfdf9 100644 (file)
@@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int val = 0;
        int ret;
 
@@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
        if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
                return -EINVAL;
 
-       ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                                 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
-                                 val);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                                AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
+                                val);
        if (ret < 0)
                return ret;
 
@@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       int val = 0;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+       int ret, val = 0;
 
        /* set the IEC958 bits: consumer mode, no copyright bit */
        val |= IEC958_AES0_CON_NOT_COPYRIGHT;
-       snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val);
+       regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
 
        val = 0;
 
@@ -132,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val);
+       ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
+       if (ret < 0)
+               return ret;
+
+       /* enable transmitter */
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+                                AK4104_TX_TXE, AK4104_TX_TXE);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int ak4104_hw_free(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+
+       /* disable transmitter */
+       return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+                                 AK4104_TX_TXE, 0);
 }
 
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
        .hw_params = ak4104_hw_params,
+       .hw_free = ak4104_hw_free,
        .set_fmt = ak4104_set_dai_fmt,
 };
 
@@ -160,20 +184,17 @@ static int ak4104_probe(struct snd_soc_codec *codec)
        int ret;
 
        codec->control_data = ak4104->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0)
-               return ret;
 
        /* set power-up and non-reset bits */
-       ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
-                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                                AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
+                                AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
        if (ret < 0)
                return ret;
 
        /* enable transmitter */
-       ret = snd_soc_update_bits(codec, AK4104_REG_TX,
-                                 AK4104_TX_TXE, AK4104_TX_TXE);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+                                AK4104_TX_TXE, AK4104_TX_TXE);
        if (ret < 0)
                return ret;
 
@@ -182,8 +203,10 @@ static int ak4104_probe(struct snd_soc_codec *codec)
 
 static int ak4104_remove(struct snd_soc_codec *codec)
 {
-       snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                           AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                          AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 
        return 0;
 }
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
new file mode 100644 (file)
index 0000000..1f30398
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * ALSA SoC driver for
+ *    Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+ *
+ * (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+struct ak5386_priv {
+       int reset_gpio;
+};
+
+static struct snd_soc_codec_driver soc_codec_ak5386;
+
+static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       format &= SND_SOC_DAIFMT_FORMAT_MASK;
+       if (format != SND_SOC_DAIFMT_LEFT_J &&
+           format != SND_SOC_DAIFMT_I2S) {
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ak5386_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       /*
+        * From the datasheet:
+        *
+        * All external clocks (MCLK, SCLK and LRCK) must be present unless
+        * PDN pin = “L”. If these clocks are not provided, the AK5386 may
+        * draw excess current due to its use of internal dynamically
+        * refreshed logic. If the external clocks are not present, place
+        * the AK5386 in power-down mode (PDN pin = “L”).
+        */
+
+       if (gpio_is_valid(priv->reset_gpio))
+               gpio_set_value(priv->reset_gpio, 1);
+
+       return 0;
+}
+
+static int ak5386_hw_free(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(priv->reset_gpio))
+               gpio_set_value(priv->reset_gpio, 0);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ak5386_dai_ops = {
+       .set_fmt        = ak5386_set_dai_fmt,
+       .hw_params      = ak5386_hw_params,
+       .hw_free        = ak5386_hw_free,
+};
+
+static struct snd_soc_dai_driver ak5386_dai = {
+       .name           = "ak5386-hifi",
+       .capture        = {
+               .stream_name    = "Capture",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_8000_192000,
+               .formats        = SNDRV_PCM_FMTBIT_S8     |
+                                 SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S24_3LE,
+       },
+       .ops    = &ak5386_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ak5386_dt_ids[] = {
+       { .compatible = "asahi-kasei,ak5386", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
+#endif
+
+static int ak5386_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ak5386_priv *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->reset_gpio = -EINVAL;
+       dev_set_drvdata(dev, priv);
+
+       if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
+               priv->reset_gpio = of_get_named_gpio(dev->of_node,
+                                                     "reset-gpio", 0);
+
+       if (gpio_is_valid(priv->reset_gpio))
+               if (devm_gpio_request_one(dev, priv->reset_gpio,
+                                         GPIOF_OUT_INIT_LOW,
+                                         "AK5386 Reset"))
+                       priv->reset_gpio = -EINVAL;
+
+       return snd_soc_register_codec(dev, &soc_codec_ak5386,
+                                     &ak5386_dai, 1);
+}
+
+static int ak5386_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ak5386_driver = {
+       .probe          = ak5386_probe,
+       .remove         = ak5386_remove,
+       .driver         = {
+               .name   = "ak5386",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(ak5386_dt_ids),
+       },
+};
+
+module_platform_driver(ak5386_driver);
+
+MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_LICENSE("GPL");
index ac948a6..389f232 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/gcd.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #define arizona_aif_dbg(_dai, fmt, ...) \
        dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
 
+static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       bool manual_ena = false;
+       int val;
+
+       switch (arizona->type) {
+       case WM5102:
+               switch (arizona->rev) {
+               case 0:
+                       break;
+               default:
+                       manual_ena = true;
+                       break;
+               }
+       default:
+               break;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (!priv->spk_ena && manual_ena) {
+                       snd_soc_write(codec, 0x4f5, 0x25a);
+                       priv->spk_ena_pending = true;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
+               if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+                       dev_crit(arizona->dev,
+                                "Speaker not enabled due to temperature\n");
+                       return -EBUSY;
+               }
+
+               snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+                                   1 << w->shift, 1 << w->shift);
+
+               if (priv->spk_ena_pending) {
+                       msleep(75);
+                       snd_soc_write(codec, 0x4f5, 0xda);
+                       priv->spk_ena_pending = false;
+                       priv->spk_ena++;
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               if (manual_ena) {
+                       priv->spk_ena--;
+                       if (!priv->spk_ena)
+                               snd_soc_write(codec, 0x4f5, 0x25a);
+               }
+
+               snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+                                   1 << w->shift, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (manual_ena) {
+                       if (!priv->spk_ena)
+                               snd_soc_write(codec, 0x4f5, 0x0da);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static irqreturn_t arizona_thermal_warn(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+                         &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+                       ret);
+       } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
+               dev_crit(arizona->dev, "Thermal warning\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+                         &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+                       ret);
+       } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+               dev_crit(arizona->dev, "Thermal shutdown\n");
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT4L_ENA |
+                                        ARIZONA_OUT4R_ENA, 0);
+               if (ret != 0)
+                       dev_crit(arizona->dev,
+                                "Failed to disable speaker outputs: %d\n",
+                                ret);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct snd_soc_dapm_widget arizona_spkl =
+       SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
+                          ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+static const struct snd_soc_dapm_widget arizona_spkr =
+       SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
+                          ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+int arizona_init_spk(struct snd_soc_codec *codec)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
+       if (ret != 0)
+               return ret;
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
+       if (ret != 0)
+               return ret;
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
+                                 "Thermal warning", arizona_thermal_warn,
+                                 arizona);
+       if (ret != 0)
+               dev_err(arizona->dev,
+                       "Failed to get thermal warning IRQ: %d\n",
+                       ret);
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
+                                 "Thermal shutdown", arizona_thermal_shutdown,
+                                 arizona);
+       if (ret != 0)
+               dev_err(arizona->dev,
+                       "Failed to get thermal shutdown IRQ: %d\n",
+                       ret);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "None",
        "Tone Generator 1",
@@ -274,6 +432,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
 const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
 EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
 
+const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+       "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
+};
+EXPORT_SYMBOL_GPL(arizona_rate_text);
+
+const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+       0, 1, 2, 8,
+};
+EXPORT_SYMBOL_GPL(arizona_rate_val);
+
+
+const struct soc_enum arizona_isrc_fsl[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
+                             ARIZONA_ISRC1_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
+                             ARIZONA_ISRC2_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
+                             ARIZONA_ISRC3_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
+
 static const char *arizona_vol_ramp_text[] = {
        "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
        "15ms/6dB", "30ms/6dB",
@@ -332,9 +517,27 @@ const struct soc_enum arizona_ng_hold =
                        4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+       int i;
+
+       if (ena)
+               val = ARIZONA_IN_VU;
+       else
+               val = 0;
+
+       for (i = 0; i < priv->num_inputs; i++)
+               snd_soc_update_bits(codec,
+                                   ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
+                                   ARIZONA_IN_VU, val);
+}
+
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                  int event)
 {
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
        unsigned int reg;
 
        if (w->shift % 2)
@@ -343,13 +546,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
 
        switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               priv->in_pending++;
+               break;
        case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+
+               /* If this is the last input pending then allow VU */
+               priv->in_pending--;
+               if (priv->in_pending == 0) {
+                       msleep(1);
+                       arizona_in_set_vu(w->codec, 1);
+               }
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
-                                   ARIZONA_IN1L_MUTE);
+               snd_soc_update_bits(w->codec, reg,
+                                   ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
+                                   ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
                break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable volume updates if no inputs are enabled */
+               reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+               if (reg == 0)
+                       arizona_in_set_vu(w->codec, 0);
        }
 
        return 0;
@@ -360,10 +579,61 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       msleep(17);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol,
+                  int event)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       unsigned int mask = 1 << w->shift;
+       unsigned int val;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               val = mask;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Store the desired state for the HP outputs */
+       priv->arizona->hp_ena &= ~mask;
+       priv->arizona->hp_ena |= val;
+
+       /* Force off if HPDET magic is active */
+       if (priv->arizona->hpdet_magic)
+               val = 0;
+
+       snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+
+       return arizona_out_ev(w, kcontrol, event);
+}
+EXPORT_SYMBOL_GPL(arizona_hp_ev);
+
 static unsigned int arizona_sysclk_48k_rates[] = {
        6144000,
        12288000,
@@ -469,27 +739,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                break;
        case 11289600:
        case 12288000:
-               val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 22579200:
        case 24576000:
-               val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 45158400:
        case 49152000:
-               val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 67737600:
        case 73728000:
-               val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 90316800:
        case 98304000:
-               val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 135475200:
        case 147456000:
-               val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 0:
                dev_dbg(arizona->dev, "%s cleared\n", name);
@@ -783,7 +1053,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        struct arizona *arizona = priv->arizona;
        int base = dai->driver->base;
        const int *rates;
-       int i, ret;
+       int i, ret, val;
        int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
        int bclk, lrclk, wl, frame, bclk_target;
 
@@ -799,6 +1069,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
                bclk_target *= chan_limit;
        }
 
+       /* Force stereo for I2S mode */
+       val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
+       if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
+               arizona_aif_dbg(dai, "Forcing stereo mode\n");
+               bclk_target *= 2;
+       }
+
        for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
                if (rates[i] >= bclk_target &&
                    rates[i] % params_rate(params) == 0) {
@@ -955,6 +1232,16 @@ static struct {
        { 1000000, 13500000, 0,  1 },
 };
 
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 gain;
+} fll_gains[] = {
+       {       0,   256000, 0 },
+       {  256000,  1000000, 2 },
+       { 1000000, 13500000, 4 },
+};
+
 struct arizona_fll_cfg {
        int n;
        int theta;
@@ -962,6 +1249,7 @@ struct arizona_fll_cfg {
        int refdiv;
        int outdiv;
        int fratio;
+       int gain;
 };
 
 static int arizona_calc_fll(struct arizona_fll *fll,
@@ -1021,6 +1309,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
                return -EINVAL;
        }
 
+       for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+               if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+                       cfg->gain = fll_gains[i].gain;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_gains)) {
+               arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+                               Fref);
+               return -EINVAL;
+       }
+
        cfg->n = target / (ratio * Fref);
 
        if (target % (ratio * Fref)) {
@@ -1048,13 +1348,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
                        cfg->n, cfg->theta, cfg->lambda);
        arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
                        cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
+       arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
 
        return 0;
 
 }
 
 static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
-                             struct arizona_fll_cfg *cfg, int source)
+                             struct arizona_fll_cfg *cfg, int source,
+                             bool sync)
 {
        regmap_update_bits(arizona->regmap, base + 3,
                           ARIZONA_FLL1_THETA_MASK, cfg->theta);
@@ -1069,87 +1371,84 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
                           cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
                           source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
 
+       if (sync)
+               regmap_update_bits(arizona->regmap, base + 0x7,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+       else
+               regmap_update_bits(arizona->regmap, base + 0x9,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+
        regmap_update_bits(arizona->regmap, base + 2,
                           ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
                           ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
-int arizona_set_fll(struct arizona_fll *fll, int source,
-                   unsigned int Fref, unsigned int Fout)
+static bool arizona_is_enabled_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
-       struct arizona_fll_cfg cfg, sync;
-       unsigned int reg, val;
-       int syncsrc;
-       bool ena;
+       unsigned int reg;
        int ret;
 
-       if (fll->fref == Fref && fll->fout == Fout)
-               return 0;
-
        ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
        if (ret != 0) {
                arizona_fll_err(fll, "Failed to read current state: %d\n",
                                ret);
                return ret;
        }
-       ena = reg & ARIZONA_FLL1_ENA;
 
-       if (Fout) {
-               /* Do we have a 32kHz reference? */
-               regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
-               switch (val & ARIZONA_CLK_32K_SRC_MASK) {
-               case ARIZONA_CLK_SRC_MCLK1:
-               case ARIZONA_CLK_SRC_MCLK2:
-                       syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
-                       break;
-               default:
-                       syncsrc = -1;
-               }
+       return reg & ARIZONA_FLL1_ENA;
+}
 
-               if (source == syncsrc)
-                       syncsrc = -1;
+static void arizona_enable_fll(struct arizona_fll *fll,
+                             struct arizona_fll_cfg *ref,
+                             struct arizona_fll_cfg *sync)
+{
+       struct arizona *arizona = fll->arizona;
+       int ret;
 
-               if (syncsrc >= 0) {
-                       ret = arizona_calc_fll(fll, &sync, Fref, Fout);
-                       if (ret != 0)
-                               return ret;
+       /*
+        * If we have both REFCLK and SYNCCLK then enable both,
+        * otherwise apply the SYNCCLK settings to REFCLK.
+        */
+       if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
+               regmap_update_bits(arizona->regmap, fll->base + 5,
+                                  ARIZONA_FLL1_OUTDIV_MASK,
+                                  ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+               arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
+                                 false);
+               if (fll->sync_src >= 0)
+                       arizona_apply_fll(arizona, fll->base + 0x10, sync,
+                                         fll->sync_src, true);
+       } else if (fll->sync_src >= 0) {
+               regmap_update_bits(arizona->regmap, fll->base + 5,
+                                  ARIZONA_FLL1_OUTDIV_MASK,
+                                  sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+               arizona_apply_fll(arizona, fll->base, sync,
+                                 fll->sync_src, false);
 
-                       ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
-                       if (ret != 0)
-                               return ret;
-               } else {
-                       ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
-                       if (ret != 0)
-                               return ret;
-               }
-       } else {
-               regmap_update_bits(arizona->regmap, fll->base + 1,
-                                  ARIZONA_FLL1_ENA, 0);
                regmap_update_bits(arizona->regmap, fll->base + 0x11,
                                   ARIZONA_FLL1_SYNC_ENA, 0);
-
-               if (ena)
-                       pm_runtime_put_autosuspend(arizona->dev);
-
-               fll->fref = Fref;
-               fll->fout = Fout;
-
-               return 0;
-       }
-
-       regmap_update_bits(arizona->regmap, fll->base + 5,
-                          ARIZONA_FLL1_OUTDIV_MASK,
-                          cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
-
-       if (syncsrc >= 0) {
-               arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
-               arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
        } else {
-               arizona_apply_fll(arizona, fll->base, &cfg, source);
+               arizona_fll_err(fll, "No clocks provided\n");
+               return;
        }
 
-       if (!ena)
+       /*
+        * Increase the bandwidth if we're not using a low frequency
+        * sync source.
+        */
+       if (fll->sync_src >= 0 && fll->sync_freq > 100000)
+               regmap_update_bits(arizona->regmap, fll->base + 0x17,
+                                  ARIZONA_FLL1_SYNC_BW, 0);
+       else
+               regmap_update_bits(arizona->regmap, fll->base + 0x17,
+                                  ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
+
+       if (!arizona_is_enabled_fll(fll))
                pm_runtime_get(arizona->dev);
 
        /* Clear any pending completions */
@@ -1157,7 +1456,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
 
        regmap_update_bits(arizona->regmap, fll->base + 1,
                           ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
-       if (syncsrc >= 0)
+       if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
+           fll->ref_src != fll->sync_src)
                regmap_update_bits(arizona->regmap, fll->base + 0x11,
                                   ARIZONA_FLL1_SYNC_ENA,
                                   ARIZONA_FLL1_SYNC_ENA);
@@ -1166,10 +1466,88 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
                                          msecs_to_jiffies(250));
        if (ret == 0)
                arizona_fll_warn(fll, "Timed out waiting for lock\n");
+}
+
+static void arizona_disable_fll(struct arizona_fll *fll)
+{
+       struct arizona *arizona = fll->arizona;
+       bool change;
+
+       regmap_update_bits_check(arizona->regmap, fll->base + 1,
+                                ARIZONA_FLL1_ENA, 0, &change);
+       regmap_update_bits(arizona->regmap, fll->base + 0x11,
+                          ARIZONA_FLL1_SYNC_ENA, 0);
+
+       if (change)
+               pm_runtime_put_autosuspend(arizona->dev);
+}
+
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+                          unsigned int Fref, unsigned int Fout)
+{
+       struct arizona_fll_cfg ref, sync;
+       int ret;
+
+       if (fll->ref_src == source && fll->ref_freq == Fref)
+               return 0;
+
+       if (fll->fout && Fref > 0) {
+               ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
+               if (ret != 0)
+                       return ret;
+
+               if (fll->sync_src >= 0) {
+                       ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
+                                              fll->fout);
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       fll->ref_src = source;
+       fll->ref_freq = Fref;
 
-       fll->fref = Fref;
+       if (fll->fout && Fref > 0) {
+               arizona_enable_fll(fll, &ref, &sync);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
+
+int arizona_set_fll(struct arizona_fll *fll, int source,
+                   unsigned int Fref, unsigned int Fout)
+{
+       struct arizona_fll_cfg ref, sync;
+       int ret;
+
+       if (fll->sync_src == source &&
+           fll->sync_freq == Fref && fll->fout == Fout)
+               return 0;
+
+       if (Fout) {
+               if (fll->ref_src >= 0) {
+                       ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
+                                              Fout);
+                       if (ret != 0)
+                               return ret;
+               }
+
+               ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+               if (ret != 0)
+                       return ret;
+       }
+
+       fll->sync_src = source;
+       fll->sync_freq = Fref;
        fll->fout = Fout;
 
+       if (Fout) {
+               arizona_enable_fll(fll, &ref, &sync);
+       } else {
+               arizona_disable_fll(fll);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_set_fll);
@@ -1178,12 +1556,26 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
                     int ok_irq, struct arizona_fll *fll)
 {
        int ret;
+       unsigned int val;
 
        init_completion(&fll->ok);
 
        fll->id = id;
        fll->base = base;
        fll->arizona = arizona;
+       fll->sync_src = ARIZONA_FLL_SRC_NONE;
+
+       /* Configure default refclk to 32kHz if we have one */
+       regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
+       switch (val & ARIZONA_CLK_32K_SRC_MASK) {
+       case ARIZONA_CLK_SRC_MCLK1:
+       case ARIZONA_CLK_SRC_MCLK2:
+               fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
+               break;
+       default:
+               fll->ref_src = ARIZONA_FLL_SRC_NONE;
+       }
+       fll->ref_freq = 32768;
 
        snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
        snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
index 116372c..af39f10 100644 (file)
@@ -32,6 +32,7 @@
 #define ARIZONA_CLK_SRC_AIF2BCLK 0x9
 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa
 
+#define ARIZONA_FLL_SRC_NONE      -1
 #define ARIZONA_FLL_SRC_MCLK1      0
 #define ARIZONA_FLL_SRC_MCLK2      1
 #define ARIZONA_FLL_SRC_SLIMCLK    3
 #define ARIZONA_MIXER_VOL_SHIFT                 1
 #define ARIZONA_MIXER_VOL_WIDTH                 7
 
+#define ARIZONA_CLK_6MHZ   0
+#define ARIZONA_CLK_12MHZ  1
+#define ARIZONA_CLK_24MHZ  2
+#define ARIZONA_CLK_49MHZ  3
+#define ARIZONA_CLK_73MHZ  4
+#define ARIZONA_CLK_98MHZ  5
+#define ARIZONA_CLK_147MHZ 6
+
 #define ARIZONA_MAX_DAI  4
 #define ARIZONA_MAX_ADSP 4
 
@@ -64,6 +73,12 @@ struct arizona_priv {
        int sysclk;
        int asyncclk;
        struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
+
+       int num_inputs;
+       unsigned int in_pending;
+
+       unsigned int spk_ena:2;
+       unsigned int spk_ena_pending:1;
 };
 
 #define ARIZONA_NUM_MIXER_INPUTS 99
@@ -165,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MIXER_ROUTES(name, name "L"), \
        ARIZONA_MIXER_ROUTES(name, name "R")
 
+#define ARIZONA_RATE_ENUM_SIZE 4
+extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+
+extern const struct soc_enum arizona_isrc_fsl[];
+
 extern const struct soc_enum arizona_in_vi_ramp;
 extern const struct soc_enum arizona_in_vd_ramp;
 
@@ -184,6 +205,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
 extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event);
+extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol,
+                        int event);
 
 extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                              int source, unsigned int freq, int dir);
@@ -198,8 +222,12 @@ struct arizona_fll {
        unsigned int base;
        unsigned int vco_mult;
        struct completion ok;
-       unsigned int fref;
+
        unsigned int fout;
+       int sync_src;
+       unsigned int sync_freq;
+       int ref_src;
+       unsigned int ref_freq;
 
        char lock_name[ARIZONA_FLL_NAME_LEN];
        char clock_ok_name[ARIZONA_FLL_NAME_LEN];
@@ -207,9 +235,13 @@ struct arizona_fll {
 
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
                            int lock_irq, int ok_irq, struct arizona_fll *fll);
+extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+                                 unsigned int Fref, unsigned int Fout);
 extern int arizona_set_fll(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout);
 
+extern int arizona_init_spk(struct snd_soc_codec *codec);
+
 extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
index 6361dab..3b20c86 100644 (file)
@@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
                priv->config[id].mmcc &= 0xC0;
                priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
                priv->config[id].spc &= 0xFC;
-               priv->config[id].spc |= MCK_SCLK_MCLK;
+               /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
+               if (priv->mclk >= 6400000)
+                       priv->config[id].spc |= MCK_SCLK_64FS;
+               else
+                       priv->config[id].spc |= MCK_SCLK_MCLK;
        } else {
                /* CS42L73 Slave */
                priv->config[id].spc &= 0xFC;
index fc17604..ce0d364 100644 (file)
@@ -23,8 +23,6 @@
 #include <sound/max98090.h>
 #include "max98090.h"
 
-#include <linux/version.h>
-
 #define DEBUG
 #define EXTMIC_METHOD
 #define EXTMIC_METHOD_TEST
@@ -509,16 +507,16 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const char * max98090_perf_pwr_text[] =
+static const char *max98090_perf_pwr_text[] =
        { "High Performance", "Low Power" };
-static const char * max98090_pwr_perf_text[] =
+static const char *max98090_pwr_perf_text[] =
        { "Low Power", "High Performance" };
 
 static const struct soc_enum max98090_vcmbandgap_enum =
        SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
                ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
 
-static const char * max98090_osr128_text[] = { "64*fs", "128*fs" };
+static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
 
 static const struct soc_enum max98090_osr128_enum =
        SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
@@ -535,28 +533,28 @@ static const struct soc_enum max98090_filter_dmic34mode_enum =
                M98090_FLT_DMIC34MODE_SHIFT,
                ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
 
-static const char * max98090_drcatk_text[] =
+static const char *max98090_drcatk_text[] =
        { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
 
 static const struct soc_enum max98090_drcatk_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
                ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
 
-static const char * max98090_drcrls_text[] =
+static const char *max98090_drcrls_text[] =
        { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
 
 static const struct soc_enum max98090_drcrls_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
                ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
 
-static const char * max98090_alccmp_text[] =
+static const char *max98090_alccmp_text[] =
        { "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
 
 static const struct soc_enum max98090_alccmp_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
                ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
 
-static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
+static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
 
 static const struct soc_enum max98090_drcexp_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
@@ -859,7 +857,7 @@ static const struct soc_enum mic2_mux_enum =
 static const struct snd_kcontrol_new max98090_mic2_mux =
        SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
 
-static const char * max98090_micpre_text[] = { "Off", "On" };
+static const char *max98090_micpre_text[] = { "Off", "On" };
 
 static const struct soc_enum max98090_pa1en_enum =
        SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
@@ -1703,9 +1701,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
                 * seen for the case of TDM mode. The remaining cases have
                 * normal logic.
                 */
-               if (max98090->tdm_slots > 1) {
+               if (max98090->tdm_slots > 1)
                        regval ^= M98090_BCI_MASK;
-               }
 
                snd_soc_write(codec,
                        M98090_REG_INTERFACE_FORMAT, regval);
@@ -2059,17 +2056,14 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
        if (!active)
                return IRQ_NONE;
 
-       if (active & M98090_CLD_MASK) {
+       if (active & M98090_CLD_MASK)
                dev_err(codec->dev, "M98090_CLD_MASK\n");
-       }
 
-       if (active & M98090_SLD_MASK) {
+       if (active & M98090_SLD_MASK)
                dev_dbg(codec->dev, "M98090_SLD_MASK\n");
-       }
 
-       if (active & M98090_ULK_MASK) {
+       if (active & M98090_ULK_MASK)
                dev_err(codec->dev, "M98090_ULK_MASK\n");
-       }
 
        if (active & M98090_JDET_MASK) {
                dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2080,13 +2074,11 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
                        msecs_to_jiffies(100));
        }
 
-       if (active & M98090_DRCACT_MASK) {
+       if (active & M98090_DRCACT_MASK)
                dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
-       }
 
-       if (active & M98090_DRCCLP_MASK) {
+       if (active & M98090_DRCCLP_MASK)
                dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
-       }
 
        return IRQ_HANDLED;
 }
@@ -2324,7 +2316,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
        max98090->pdata = i2c->dev.platform_data;
        max98090->irq = i2c->irq;
 
-       max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap);
+       max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
        if (IS_ERR(max98090->regmap)) {
                ret = PTR_ERR(max98090->regmap);
                dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
@@ -2334,18 +2326,13 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_max98090, max98090_dai,
                        ARRAY_SIZE(max98090_dai));
-       if (ret < 0)
-               regmap_exit(max98090->regmap);
-
 err_enable:
        return ret;
 }
 
 static int max98090_i2c_remove(struct i2c_client *client)
 {
-       struct max98090_priv *max98090 = dev_get_drvdata(&client->dev);
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(max98090->regmap);
        return 0;
 }
 
@@ -2369,7 +2356,7 @@ static int max98090_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static struct dev_pm_ops max98090_pm = {
+static const struct dev_pm_ops max98090_pm = {
        SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
                max98090_runtime_resume, NULL)
 };
index 566ea32..721587c 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
@@ -45,13 +64,23 @@ static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
        int err;
+       unsigned int val;
        struct si476x_core *core = codec->control_data;
 
        si476x_core_lock(core);
-       err = si476x_core_cmd_get_property(core, reg);
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, true);
+
+       err = regmap_read(core->regmap, reg, &val);
+
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, false);
        si476x_core_unlock(core);
 
-       return err;
+       if (err < 0)
+               return err;
+
+       return val;
 }
 
 static int si476x_codec_write(struct snd_soc_codec *codec,
@@ -61,7 +90,13 @@ static int si476x_codec_write(struct snd_soc_codec *codec,
        struct si476x_core *core = codec->control_data;
 
        si476x_core_lock(core);
-       err = si476x_core_cmd_set_property(core, reg, val);
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, true);
+
+       err = regmap_write(core->regmap, reg, val);
+
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, false);
        si476x_core_unlock(core);
 
        return err;
@@ -140,7 +175,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
                dev_err(codec_dai->codec->dev, "Failed to set output format\n");
                return err;
        }
-       
+
        return 0;
 }
 
@@ -182,7 +217,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 
        err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
                                  SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
-                                 (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | 
+                                 (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
                                  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
        if (err < 0) {
                dev_err(dai->codec->dev, "Failed to set output width\n");
@@ -251,6 +286,6 @@ static struct platform_driver si476x_platform_driver = {
 };
 module_platform_driver(si476x_platform_driver);
 
-MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
 MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
new file mode 100644 (file)
index 0000000..d447c4a
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * TAS5086 ASoC codec driver
+ *
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * TODO:
+ *  - implement DAPM and input muxing
+ *  - implement modulation limit
+ *  - implement non-default PWM start
+ *
+ * Note that this chip has a very unusual register layout, specifically
+ * because the registers are of unequal size, and multi-byte registers
+ * require bulk writes to take effect. Regmap does not support that kind
+ * of devices.
+ *
+ * Currently, the driver does not touch any of the registers >= 0x20, so
+ * it doesn't matter because the entire map can be accessed as 8-bit
+ * array. In case more features will be added in the future
+ * that require access to higher registers, the entire regmap H/W I/O
+ * routines have to be open-coded.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas5086.h>
+
+#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |                \
+                            SNDRV_PCM_FMTBIT_S20_3LE |         \
+                            SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define TAS5086_PCM_RATES   (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+                            SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+                            SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
+                            SNDRV_PCM_RATE_192000)
+
+/*
+ * TAS5086 registers
+ */
+#define TAS5086_CLOCK_CONTROL          0x00    /* Clock control register  */
+#define TAS5086_CLOCK_RATE(val)                (val << 5)
+#define TAS5086_CLOCK_RATE_MASK                (0x7 << 5)
+#define TAS5086_CLOCK_RATIO(val)       (val << 2)
+#define TAS5086_CLOCK_RATIO_MASK       (0x7 << 2)
+#define TAS5086_CLOCK_SCLK_RATIO_48    (1 << 1)
+#define TAS5086_CLOCK_VALID            (1 << 0)
+
+#define TAS5086_DEEMPH_MASK            0x03
+#define TAS5086_SOFT_MUTE_ALL          0x3f
+
+#define TAS5086_DEV_ID                 0x01    /* Device ID register */
+#define TAS5086_ERROR_STATUS           0x02    /* Error status register */
+#define TAS5086_SYS_CONTROL_1          0x03    /* System control register 1 */
+#define TAS5086_SERIAL_DATA_IF         0x04    /* Serial data interface register  */
+#define TAS5086_SYS_CONTROL_2          0x05    /* System control register 2 */
+#define TAS5086_SOFT_MUTE              0x06    /* Soft mute register */
+#define TAS5086_MASTER_VOL             0x07    /* Master volume  */
+#define TAS5086_CHANNEL_VOL(X)         (0x08 + (X))    /* Channel 1-6 volume */
+#define TAS5086_VOLUME_CONTROL         0x09    /* Volume control register */
+#define TAS5086_MOD_LIMIT              0x10    /* Modulation limit register */
+#define TAS5086_PWM_START              0x18    /* PWM start register */
+#define TAS5086_SURROUND               0x19    /* Surround register */
+#define TAS5086_SPLIT_CAP_CHARGE       0x1a    /* Split cap charge period register */
+#define TAS5086_OSC_TRIM               0x1b    /* Oscillator trim register */
+#define TAS5086_BKNDERR                0x1c
+
+/*
+ * Default TAS5086 power-up configuration
+ */
+static const struct reg_default tas5086_reg_defaults[] = {
+       { 0x00, 0x6c },
+       { 0x01, 0x03 },
+       { 0x02, 0x00 },
+       { 0x03, 0xa0 },
+       { 0x04, 0x05 },
+       { 0x05, 0x60 },
+       { 0x06, 0x00 },
+       { 0x07, 0xff },
+       { 0x08, 0x30 },
+       { 0x09, 0x30 },
+       { 0x0a, 0x30 },
+       { 0x0b, 0x30 },
+       { 0x0c, 0x30 },
+       { 0x0d, 0x30 },
+       { 0x0e, 0xb1 },
+       { 0x0f, 0x00 },
+       { 0x10, 0x02 },
+       { 0x11, 0x00 },
+       { 0x12, 0x00 },
+       { 0x13, 0x00 },
+       { 0x14, 0x00 },
+       { 0x15, 0x00 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+       { 0x18, 0x3f },
+       { 0x19, 0x00 },
+       { 0x1a, 0x18 },
+       { 0x1b, 0x82 },
+       { 0x1c, 0x05 },
+};
+
+static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+}
+
+static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TAS5086_DEV_ID:
+       case TAS5086_ERROR_STATUS:
+               return true;
+       }
+
+       return false;
+}
+
+static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
+{
+       return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
+}
+
+struct tas5086_private {
+       struct regmap   *regmap;
+       unsigned int    mclk, sclk;
+       unsigned int    format;
+       bool            deemph;
+       /* Current sample rate for de-emphasis control */
+       int             rate;
+       /* GPIO driving Reset pin, if any */
+       int             gpio_nreset;
+};
+
+static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int tas5086_set_deemph(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int i, val = 0;
+
+       if (priv->deemph)
+               for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++)
+                       if (tas5086_deemph[i] == priv->rate)
+                               val = i;
+
+       return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
+                                 TAS5086_DEEMPH_MASK, val);
+}
+
+static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->deemph;
+
+       return 0;
+}
+
+static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->deemph = ucontrol->value.enumerated.item[0];
+
+       return tas5086_set_deemph(codec);
+}
+
+
+static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case TAS5086_CLK_IDX_MCLK:
+               priv->mclk = freq;
+               break;
+       case TAS5086_CLK_IDX_SCLK:
+               priv->sclk = freq;
+               break;
+       }
+
+       return 0;
+}
+
+static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                              unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* The TAS5086 can only be slave to all clocks */
+       if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+               dev_err(codec->dev, "Invalid clocking mode\n");
+               return -EINVAL;
+       }
+
+       /* we need to refer to the data format from hw_params() */
+       priv->format = format;
+
+       return 0;
+}
+
+static const int tas5086_sample_rates[] = {
+       32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const int tas5086_ratios[] = {
+       64, 128, 192, 256, 384, 512
+};
+
+static int index_in_array(const int *array, int len, int needle)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (array[i] == needle)
+                       return i;
+
+       return -ENOENT;
+}
+
+static int tas5086_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val;
+       int ret;
+
+       priv->rate = params_rate(params);
+
+       /* Look up the sample rate and refer to the offset in the list */
+       val = index_in_array(tas5086_sample_rates,
+                            ARRAY_SIZE(tas5086_sample_rates), priv->rate);
+
+       if (val < 0) {
+               dev_err(codec->dev, "Invalid sample rate\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_RATE_MASK,
+                                TAS5086_CLOCK_RATE(val));
+       if (ret < 0)
+               return ret;
+
+       /* MCLK / Fs ratio */
+       val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
+                            priv->mclk / priv->rate);
+       if (val < 0) {
+               dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_RATIO_MASK,
+                                TAS5086_CLOCK_RATIO(val));
+       if (ret < 0)
+               return ret;
+
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_SCLK_RATIO_48,
+                                (priv->sclk == 48 * priv->rate) ? 
+                                       TAS5086_CLOCK_SCLK_RATIO_48 : 0);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The chip has a very unituitive register mapping and muxes information
+        * about data format and sample depth into the same register, but not on
+        * a logical bit-boundary. Hence, we have to refer to the format passed
+        * in the set_dai_fmt() callback and set up everything from here.
+        *
+        * First, determine the 'base' value, using the format ...
+        */
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = 0x00;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x03;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x06;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       /* ... then add the offset for the sample bit depth. */
+       switch (params_format(params)) {
+        case SNDRV_PCM_FORMAT_S16_LE:
+               val += 0;
+                break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val += 1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               val += 2;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid bit width\n");
+               return -EINVAL;
+       };
+
+       ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
+       if (ret < 0)
+               return ret;
+
+       /* clock is considered valid now */
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID);
+       if (ret < 0)
+               return ret;
+
+       return tas5086_set_deemph(codec);
+}
+
+static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int val = 0;
+
+       if (mute)
+               val = TAS5086_SOFT_MUTE_ALL;
+
+       return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
+}
+
+/* TAS5086 controls */
+static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5086_controls[] = {
+       SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
+                      0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+                        TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+                        TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+                        TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+                           tas5086_get_deemph, tas5086_put_deemph),
+};
+
+static const struct snd_soc_dai_ops tas5086_dai_ops = {
+       .hw_params      = tas5086_hw_params,
+       .set_sysclk     = tas5086_set_dai_sysclk,
+       .set_fmt        = tas5086_set_dai_fmt,
+       .mute_stream    = tas5086_mute_stream,
+};
+
+static struct snd_soc_dai_driver tas5086_dai = {
+       .name = "tas5086-hifi",
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 2,
+               .channels_max   = 6,
+               .rates          = TAS5086_PCM_RATES,
+               .formats        = TAS5086_PCM_FORMATS,
+       },
+       .ops = &tas5086_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int tas5086_soc_resume(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* Restore codec state */
+       return regcache_sync(priv->regmap);
+}
+#else
+#define tas5086_soc_resume     NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5086_dt_ids[] = {
+       { .compatible = "ti,tas5086", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
+#endif
+
+/* charge period values in microseconds */
+static const int tas5086_charge_period[] = {
+         13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200,
+        130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000,
+       1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+};
+
+static int tas5086_probe(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int charge_period = 1300000; /* hardware default is 1300 ms */
+       int i, ret;
+
+       if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
+               struct device_node *of_node = codec->dev->of_node;
+               of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+       }
+
+       /* lookup and set split-capacitor charge period */
+       if (charge_period == 0) {
+               regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+       } else {
+               i = index_in_array(tas5086_charge_period,
+                                  ARRAY_SIZE(tas5086_charge_period),
+                                  charge_period);
+               if (i >= 0)
+                       regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+                                    i + 0x08);
+               else
+                       dev_warn(codec->dev,
+                                "Invalid split-cap charge period of %d ns.\n",
+                                charge_period);
+       }
+
+       /* enable factory trim */
+       ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+       if (ret < 0)
+               return ret;
+
+       /* start all channels */
+       ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+       if (ret < 0)
+               return ret;
+
+       /* set master volume to 0 dB */
+       ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
+       if (ret < 0)
+               return ret;
+
+       /* mute all channels for now */
+       ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+                          TAS5086_SOFT_MUTE_ALL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int tas5086_remove(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(priv->gpio_nreset))
+               /* Set codec to the reset state */
+               gpio_set_value(priv->gpio_nreset, 0);
+
+       return 0;
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+       .probe                  = tas5086_probe,
+       .remove                 = tas5086_remove,
+       .resume                 = tas5086_soc_resume,
+       .controls               = tas5086_controls,
+       .num_controls           = ARRAY_SIZE(tas5086_controls),
+};
+
+static const struct i2c_device_id tas5086_i2c_id[] = {
+       { "tas5086", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
+
+static const struct regmap_config tas5086_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = ARRAY_SIZE(tas5086_reg_defaults),
+       .reg_defaults           = tas5086_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(tas5086_reg_defaults),
+       .cache_type             = REGCACHE_RBTREE,
+       .volatile_reg           = tas5086_volatile_reg,
+       .writeable_reg          = tas5086_writeable_reg,
+       .readable_reg           = tas5086_accessible_reg,
+};
+
+static int tas5086_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct tas5086_private *priv;
+       struct device *dev = &i2c->dev;
+       int gpio_nreset = -EINVAL;
+       int i, ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, priv);
+
+       if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
+               struct device_node *of_node = dev->of_node;
+               gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
+       }
+
+       if (gpio_is_valid(gpio_nreset))
+               if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
+                       gpio_nreset = -EINVAL;
+
+       if (gpio_is_valid(gpio_nreset)) {
+               /* Reset codec - minimum assertion time is 400ns */
+               gpio_direction_output(gpio_nreset, 0);
+               udelay(1);
+               gpio_set_value(gpio_nreset, 1);
+
+               /* Codec needs ~15ms to wake up */
+               msleep(15);
+       }
+
+       priv->gpio_nreset = gpio_nreset;
+
+       /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
+       ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
+       if (ret < 0)
+               return ret;
+
+       if (i != 0x3) {
+               dev_err(dev,
+                       "Failed to identify TAS5086 codec (got %02x)\n", i);
+               return -ENODEV;
+       }
+
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
+               &tas5086_dai, 1);
+}
+
+static int tas5086_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       return 0;
+}
+
+static struct i2c_driver tas5086_i2c_driver = {
+       .driver = {
+               .name   = "tas5086",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(tas5086_dt_ids),
+       },
+       .id_table       = tas5086_i2c_id,
+       .probe          = tas5086_i2c_probe,
+       .remove         = tas5086_i2c_remove,
+};
+
+module_i2c_driver(tas5086_i2c_driver);
+
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
index ad2fee4..8df2b6e 100644 (file)
@@ -342,7 +342,7 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
                data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
+static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 {
        struct spi_device *spi = to_spi_device(codec->dev);
        struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
@@ -361,8 +361,8 @@ static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
 
        ret = request_firmware(&fw, name, codec->dev);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request application: %d\n",
-                       ret);
+               dev_err(codec->dev, "Failed to request application(%s): %d\n",
+                       name, ret);
                return ret;
        }
 
index f2ac38b..7fefd76 100644 (file)
@@ -761,6 +761,8 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
        case WM2000_REG_SYS_CTL2:
        case WM2000_REG_ANC_STAT:
        case WM2000_REG_IF_CTL:
+       case WM2000_REG_ANA_MIC_CTL:
+       case WM2000_REG_SPK_CTL:
                return true;
        default:
                return false;
@@ -771,7 +773,7 @@ static const struct regmap_config wm2000_regmap = {
        .reg_bits = 16,
        .val_bits = 8,
 
-       .max_register = WM2000_REG_IF_CTL,
+       .max_register = WM2000_REG_SPK_CTL,
        .readable_reg = wm2000_readable_reg,
 };
 
index fb812cd..3870c0e 100644 (file)
@@ -30,6 +30,8 @@
 #define WM2000_REG_SYS_CTL2         0xf004
 #define WM2000_REG_ANC_STAT         0xf005
 #define WM2000_REG_IF_CTL           0xf006
+#define WM2000_REG_ANA_MIC_CTL      0xf028
+#define WM2000_REG_SPK_CTL          0xf034
 
 /* SPEECH_CLARITY */
 #define WM2000_SPEECH_CLARITY   0x01
index ddc98f0..57ba315 100644 (file)
@@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
+       ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
        if (ret != 0)
                return ret;
 
index 34d0201..e895d39 100644 (file)
@@ -36,9 +36,6 @@
 struct wm5102_priv {
        struct arizona_priv core;
        struct arizona_fll fll[2];
-
-       unsigned int spk_ena:2;
-       unsigned int spk_ena_pending:1;
 };
 
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
@@ -615,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static const char *wm5102_osr_text[] = {
+       "Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm5102_osr_val[] = {
+       0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm5102_hpout_osr[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+                             ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+                             ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+                             ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+};
+
 #define WM5102_NG_SRC(name, base) \
        SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
        SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
@@ -745,6 +762,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
 
@@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
 
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+          ARIZONA_OUT4_OSR_SHIFT, 1, 0),
 SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
           ARIZONA_OUT5_OSR_SHIFT, 1, 0),
 
@@ -790,6 +812,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
                 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
 
+SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
+SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
+
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
 
@@ -828,47 +854,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
 };
 
-static int wm5102_spk_ev(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol,
-                        int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
-
-       if (arizona->rev < 1)
-               return 0;
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (!wm5102->spk_ena) {
-                       snd_soc_write(codec, 0x4f5, 0x25a);
-                       wm5102->spk_ena_pending = true;
-               }
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               if (wm5102->spk_ena_pending) {
-                       msleep(75);
-                       snd_soc_write(codec, 0x4f5, 0xda);
-                       wm5102->spk_ena_pending = false;
-                       wm5102->spk_ena++;
-               }
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               wm5102->spk_ena--;
-               if (!wm5102->spk_ena)
-                       snd_soc_write(codec, 0x4f5, 0x25a);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               if (!wm5102->spk_ena)
-                       snd_soc_write(codec, 0x4f5, 0x0da);
-               break;
-       }
-
-       return 0;
-}
-
-
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
@@ -984,22 +969,28 @@ SND_SOC_DAPM_INPUT("IN3R"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
                    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
@@ -1131,11 +1122,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
@@ -1146,12 +1137,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -1494,6 +1479,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
        case WM5102_FLL2:
                return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
+       case WM5102_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref,
+                                             Fout);
+       case WM5102_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref,
+                                             Fout);
        default:
                return -EINVAL;
        }
@@ -1581,10 +1572,12 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
+       ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
        if (ret != 0)
                return ret;
 
+       arizona_init_spk(codec);
+
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
        priv->core.arizona->dapm = &codec->dapm;
@@ -1604,13 +1597,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec)
 #define WM5102_DIG_VU 0x0200
 
 static unsigned int wm5102_digital_vu[] = {
-       ARIZONA_ADC_DIGITAL_VOLUME_1L,
-       ARIZONA_ADC_DIGITAL_VOLUME_1R,
-       ARIZONA_ADC_DIGITAL_VOLUME_2L,
-       ARIZONA_ADC_DIGITAL_VOLUME_2R,
-       ARIZONA_ADC_DIGITAL_VOLUME_3L,
-       ARIZONA_ADC_DIGITAL_VOLUME_3R,
-
        ARIZONA_DAC_DIGITAL_VOLUME_1L,
        ARIZONA_DAC_DIGITAL_VOLUME_1R,
        ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1653,6 +1639,7 @@ static int wm5102_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, wm5102);
 
        wm5102->core.arizona = arizona;
+       wm5102->core.num_inputs = 6;
 
        wm5102->core.adsp[0].part = "wm5102";
        wm5102->core.adsp[0].num = 1;
@@ -1677,6 +1664,12 @@ static int wm5102_probe(struct platform_device *pdev)
                         ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
                         &wm5102->fll[1]);
 
+       /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+                          ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+                          ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
        for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++)
                arizona_init_dai(&wm5102->core, i);
 
index d30477f..adb3804 100644 (file)
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5102_FLL1 1
-#define WM5102_FLL2 2
+#define WM5102_FLL1        1
+#define WM5102_FLL2        2
+#define WM5102_FLL1_REFCLK 3
+#define WM5102_FLL2_REFCLK 4
 
 #endif
index cdeb301..731884e 100644 (file)
@@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
                    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
@@ -551,11 +559,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
@@ -569,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -880,6 +882,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
        case WM5110_FLL2:
                return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
+       case WM5110_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref,
+                                             Fout);
+       case WM5110_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref,
+                                             Fout);
        default:
                return -EINVAL;
        }
@@ -987,15 +995,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
 #define WM5110_DIG_VU 0x0200
 
 static unsigned int wm5110_digital_vu[] = {
-       ARIZONA_ADC_DIGITAL_VOLUME_1L,
-       ARIZONA_ADC_DIGITAL_VOLUME_1R,
-       ARIZONA_ADC_DIGITAL_VOLUME_2L,
-       ARIZONA_ADC_DIGITAL_VOLUME_2R,
-       ARIZONA_ADC_DIGITAL_VOLUME_3L,
-       ARIZONA_ADC_DIGITAL_VOLUME_3R,
-       ARIZONA_ADC_DIGITAL_VOLUME_4L,
-       ARIZONA_ADC_DIGITAL_VOLUME_4R,
-
        ARIZONA_DAC_DIGITAL_VOLUME_1L,
        ARIZONA_DAC_DIGITAL_VOLUME_1R,
        ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1040,6 +1039,7 @@ static int wm5110_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, wm5110);
 
        wm5110->core.arizona = arizona;
+       wm5110->core.num_inputs = 8;
 
        for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
                wm5110->fll[i].vco_mult = 3;
index 75e9351..e6c0cd4 100644 (file)
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5110_FLL1 1
-#define WM5110_FLL2 2
+#define WM5110_FLL1        1
+#define WM5110_FLL2        2
+#define WM5110_FLL1_REFCLK 3
+#define WM5110_FLL2_REFCLK 4
 
 #endif
index f8a31ad..9d88437 100644 (file)
@@ -478,6 +478,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
 static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
 
@@ -698,6 +700,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode),
 SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
 SOC_ENUM("DAC Companding Mode", dac_companding),
 SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
+              dac_boost_tlv),
 SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
                    wm8903_get_deemph, wm8903_put_deemph),
 
index a64b934..0a4ffdd 100644 (file)
@@ -204,6 +204,7 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
 static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
 
 static const struct snd_kcontrol_new wm8960_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
@@ -213,6 +214,15 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
        7, 1, 0),
 
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+              WM8960_INBMIX1, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+              WM8960_INBMIX1, 1, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+              WM8960_INBMIX2, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+              WM8960_INBMIX2, 1, 7, 0, boost_tlv),
+
 SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
                 0, 255, 0, dac_tlv),
 
index c9bd445..14094f5 100644 (file)
@@ -2209,7 +2209,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                vmid_reference(codec);
                                break;
                        case WM8958:
-                               if (wm8994->revision < 1)
+                               if (control->revision < 1)
                                        vmid_reference(codec);
                                break;
                        default:
@@ -2244,7 +2244,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                vmid_dereference(codec);
                                break;
                        case WM8958:
-                               if (wm8994->revision < 1)
+                               if (control->revision < 1)
                                        vmid_dereference(codec);
                                break;
                        default:
@@ -2268,10 +2268,26 @@ out:
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+               wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+               wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
+       } else if (wm8994->aifdiv[0]) {
+               snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+                                   WM8994_AIF1CLK_RATE_MASK,
+                                   wm8994->aifdiv[0]);
+               snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+                                   WM8994_AIF2CLK_RATE_MASK,
+                                   wm8994->aifdiv[1]);
+
+               wm8994->aifdiv[0] = 0;
+               wm8994->aifdiv[1] = 0;
        }
 
        return 0;
@@ -2368,10 +2384,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+               wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+               wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
+       } else if (wm8994->aifdiv[0]) {
+               snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+                                   WM8994_AIF1CLK_RATE_MASK,
+                                   wm8994->aifdiv[0]);
+               snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+                                   WM8994_AIF2CLK_RATE_MASK,
+                                   wm8994->aifdiv[1]);
+
+               wm8994->aifdiv[0] = 0;
+               wm8994->aifdiv[1] = 0;
        }
 
        return 0;
@@ -2411,7 +2443,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        switch (control->type) {
                        case WM8958:
-                               if (wm8994->revision == 0) {
+                               if (control->revision == 0) {
                                        /* Optimise performance for rev A */
                                        snd_soc_update_bits(codec,
                                                            WM8958_CHARGE_PUMP_2,
@@ -2656,6 +2688,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->wm8994;
+       struct wm8994_pdata *pdata = &control->pdata;
        int aif1_reg;
        int aif2_reg;
        int bclk_reg;
@@ -2723,7 +2757,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        }
 
        wm8994->channels[id] = params_channels(params);
-       switch (params_channels(params)) {
+       if (pdata->max_channels_clocked[id] &&
+           wm8994->channels[id] > pdata->max_channels_clocked[id]) {
+               dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
+                       pdata->max_channels_clocked[id], wm8994->channels[id]);
+               wm8994->channels[id] = pdata->max_channels_clocked[id];
+       }
+
+       switch (wm8994->channels[id]) {
        case 1:
        case 2:
                bclk_rate *= 2;
@@ -2745,7 +2786,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
                dai->id, wm8994->aifclk[id], bclk_rate);
 
-       if (params_channels(params) == 1 &&
+       if (wm8994->channels[id] == 1 &&
            (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
                aif2 |= WM8994_AIF1_MONO;
 
@@ -3053,7 +3094,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
        int i, ret;
        unsigned int val, mask;
 
-       if (wm8994->revision < 4) {
+       if (control->revision < 4) {
                /* force a HW read */
                ret = regmap_read(control->regmap,
                                  WM8994_POWER_MANAGEMENT_5, &val);
@@ -3870,7 +3911,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        codec->dapm.idle_bias_off = 1;
 
        /* Set revision-specific configuration */
-       wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
        switch (control->type) {
        case WM8994:
                /* Single ended line outputs should have VMID on. */
@@ -3878,7 +3918,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                    !control->pdata.lineout2_diff)
                        codec->dapm.idle_bias_off = 0;
 
-               switch (wm8994->revision) {
+               switch (control->revision) {
                case 2:
                case 3:
                        wm8994->hubs.dcs_codes_l = -5;
@@ -3897,7 +3937,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
 
-               switch (wm8994->revision) {
+               switch (control->revision) {
                case 0:
                        break;
                default:
@@ -4000,7 +4040,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        switch (control->type) {
        case WM1811:
-               if (control->cust_id > 1 || wm8994->revision > 1) {
+               if (control->cust_id > 1 || control->revision > 1) {
                        ret = wm8994_request_irq(wm8994->wm8994,
                                                 WM8994_IRQ_GPIO(6),
                                                 wm1811_jackdet_irq, "JACKDET",
@@ -4114,7 +4154,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8994:
                snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
                                          ARRAY_SIZE(wm8994_specific_dapm_widgets));
-               if (wm8994->revision < 4) {
+               if (control->revision < 4) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
@@ -4135,7 +4175,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm8958_snd_controls));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
-               if (wm8994->revision < 1) {
+               if (control->revision < 1) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
@@ -4174,7 +4214,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                        ARRAY_SIZE(wm8994_intercon));
 
-               if (wm8994->revision < 4) {
+               if (control->revision < 4) {
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
                                                ARRAY_SIZE(wm8994_revd_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
@@ -4185,7 +4225,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
                break;
        case WM8958:
-               if (wm8994->revision < 1) {
+               if (control->revision < 1) {
                        snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                                ARRAY_SIZE(wm8994_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
index 45f1927..55ddf4d 100644 (file)
@@ -79,6 +79,7 @@ struct wm8994_priv {
        int sysclk_rate[2];
        int mclk[2];
        int aifclk[2];
+       int aifdiv[2];
        int channels[2];
        struct wm8994_fll_config fll[2], fll_suspend[2];
        struct completion fll_locked[2];
@@ -146,8 +147,6 @@ struct wm8994_priv {
        wm1811_mic_id_cb mic_id_cb;
        void *mic_id_cb_data;
 
-       int revision;
-
        unsigned int aif1clk_enable:1;
        unsigned int aif2clk_enable:1;
 
index 9af1bdd..3470b64 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <linux/mfd/arizona/registers.h>
 
+#include "arizona.h"
 #include "wm_adsp.h"
 
 #define adsp_crit(_dsp, fmt, ...) \
@@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list)
 
 #define WM_ADSP_NUM_FW 4
 
+#define WM_ADSP_FW_MBC_VSS 0
+#define WM_ADSP_FW_TX      1
+#define WM_ADSP_FW_TX_SPK  2
+#define WM_ADSP_FW_RX_ANC  3
+
 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
-       "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
+       [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
+       [WM_ADSP_FW_TX] =      "Tx",
+       [WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
+       [WM_ADSP_FW_RX_ANC] =  "Rx ANC",
 };
 
 static struct {
        const char *file;
 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
-       { .file = "mbc-vss" },
-       { .file = "tx" },
-       { .file = "tx-spk" },
-       { .file = "rx-anc" },
+       [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
+       [WM_ADSP_FW_TX] =      { .file = "tx" },
+       [WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
+       [WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
 };
 
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 };
 
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
+const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
+       SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+};
+EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
+
+#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
+static const struct soc_enum wm_adsp2_rate_enum[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+};
+
+const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
        SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
        SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
        SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
        SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
 };
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
+#endif
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
@@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                buf_size = sizeof(adsp1_id);
 
                algs = be32_to_cpu(adsp1_id.algs);
+               dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         be32_to_cpu(adsp1_id.fw.id),
+                         dsp->fw_id,
                          (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
                          (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
                          be32_to_cpu(adsp1_id.fw.ver) & 0xff,
                          algs);
 
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP1_ZM;
+               region->alg = be32_to_cpu(adsp1_id.fw.id);
+               region->base = be32_to_cpu(adsp1_id.zm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP1_DM;
+               region->alg = be32_to_cpu(adsp1_id.fw.id);
+               region->base = be32_to_cpu(adsp1_id.dm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
                pos = sizeof(adsp1_id) / 2;
                term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
                break;
@@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                buf_size = sizeof(adsp2_id);
 
                algs = be32_to_cpu(adsp2_id.algs);
+               dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         be32_to_cpu(adsp2_id.fw.id),
+                         dsp->fw_id,
                          (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
                          (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
                          be32_to_cpu(adsp2_id.fw.ver) & 0xff,
                          algs);
 
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_XM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.xm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_YM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.ym);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_ZM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.zm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
                pos = sizeof(adsp2_id) / 2;
                term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
                break;
@@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                case (WMFW_INFO_TEXT << 8):
                        break;
                case (WMFW_ABSOLUTE << 8):
-                       region_name = "register";
-                       reg = offset;
+                       /*
+                        * Old files may use this for global
+                        * coefficients.
+                        */
+                       if (le32_to_cpu(blk->id) == dsp->fw_id &&
+                           offset == 0) {
+                               region_name = "global coefficients";
+                               mem = wm_adsp_find_region(dsp, type);
+                               if (!mem) {
+                                       adsp_err(dsp, "No ZM\n");
+                                       break;
+                               }
+                               reg = wm_adsp_region_to_reg(mem, 0);
+
+                       } else {
+                               region_name = "register";
+                               reg = offset;
+                       }
                        break;
 
                case WMFW_ADSP1_DM:
index cb8871a..fea5146 100644 (file)
@@ -46,6 +46,8 @@ struct wm_adsp {
 
        struct list_head alg_regions;
 
+       int fw_id;
+
        const struct wm_adsp_region *mem;
        int num_mems;
 
@@ -65,7 +67,8 @@ struct wm_adsp {
        .shift = num, .event = wm_adsp2_event, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
-extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
 
 int wm_adsp1_init(struct wm_adsp *adsp);
 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
index 867ae97..f5d81b9 100644 (file)
@@ -199,11 +199,12 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
        list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
-static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
                                  u16 *reg_l, u16 *reg_r)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        u16 dcs_reg, reg;
+       int ret = 0;
 
        switch (hubs->dcs_readback_mode) {
        case 2:
@@ -236,8 +237,9 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
                break;
        default:
                WARN(1, "Unknown DCS readback method\n");
-               return;
+               ret = -1;
        }
+       return ret;
 }
 
 /*
@@ -286,7 +288,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
                                  WM8993_DCS_TRIG_STARTUP_1);
        }
 
-       wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
+       if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
+               return;
 
        dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
index 8218312..ebe8294 100644 (file)
@@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_i2s_component = {
+       .name           = "davinci-i2s",
+};
+
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
        struct snd_platform_data *pdata = pdev->dev.platform_data;
@@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
+                                        &davinci_i2s_dai, 1);
        if (ret != 0)
                goto err_release_clk;
 
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
        clk_disable(dev->clk);
        clk_put(dev->clk);
@@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
 {
        struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        clk_disable(dev->clk);
index 9321e5c..aeb3a66 100644 (file)
 #define DISMOD         (val)(val<<2)
 #define TXSTATE                BIT(4)
 #define RXSTATE                BIT(5)
+#define SRMOD_MASK     3
+#define SRMOD_INACTIVE 0
 
 /*
  * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
@@ -643,26 +645,33 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
        /* mapping of the XSSZ bit-field as described in the datasheet */
        fmt = (word_length >> 1) - 1;
 
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-                                       RXSSZ(fmt), RXSSZ(0x0F));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-                                       TXSSZ(fmt), TXSSZ(0x0F));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
-                                                       TXROT(7));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
-                                                       RXROT(7));
+       if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+                               RXSSZ(fmt), RXSSZ(0x0F));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+                               TXSSZ(fmt), TXSSZ(0x0F));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+                               TXROT(rotate), TXROT(7));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+                               RXROT(rotate), RXROT(7));
+               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
+                               mask);
+       }
+
        mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
 
        return 0;
 }
 
-static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
+static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+                                   int channels)
 {
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
-
+       u8 ser;
+       u8 slots = dev->tdm_slots;
+       u8 max_active_serializers = (channels + slots - 1) / slots;
        /* Default configuration */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
@@ -682,17 +691,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
        for (i = 0; i < dev->num_serializer; i++) {
                mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
                                        dev->serial_dir[i]);
-               if (dev->serial_dir[i] == TX_MODE) {
+               if (dev->serial_dir[i] == TX_MODE &&
+                                       tx_ser < max_active_serializers) {
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        tx_ser++;
-               } else if (dev->serial_dir[i] == RX_MODE) {
+               } else if (dev->serial_dir[i] == RX_MODE &&
+                                       rx_ser < max_active_serializers) {
                        mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        rx_ser++;
+               } else {
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
+                                       SRMOD_INACTIVE, SRMOD_MASK);
                }
        }
 
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ser = tx_ser;
+       else
+               ser = rx_ser;
+
+       if (ser < max_active_serializers) {
+               dev_warn(dev->dev, "stream has more channels (%d) than are "
+                       "enabled in mcasp (%d)\n", channels, ser * slots);
+               return -EINVAL;
+       }
+
        if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (dev->txnumevt * tx_ser > 64)
                        dev->txnumevt = 1;
@@ -729,6 +754,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
                                ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
                }
        }
+
+       return 0;
 }
 
 static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
@@ -772,12 +799,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
 /* S/PDIF */
 static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
 {
-       /* Set the PDIR for Serialiser as output */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
-
-       /* TXMASK for 24 bits */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
-
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
@@ -812,8 +833,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
+       u8 slots = dev->tdm_slots;
+       int channels;
+       struct snd_interval *pcm_channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       channels = pcm_channels->min;
 
-       davinci_hw_common_param(dev, substream->stream);
+       if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+               return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = dev->txnumevt;
        else
@@ -862,6 +889,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                dma_params->acnt = dma_params->data_type;
 
        dma_params->fifo_level = fifo_level;
+       dma_params->active_serializers = (channels + slots - 1) / slots;
        davinci_config_channel_size(dev, word_length);
 
        return 0;
@@ -936,13 +964,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
                .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
                .capture        = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
@@ -962,6 +990,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
 };
 
+static const struct snd_soc_component_driver davinci_mcasp_component = {
+       .name           = "davinci-mcasp",
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
@@ -1015,8 +1047,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata->op_mode = val;
 
        ret = of_property_read_u32(np, "tdm-slots", &val);
-       if (ret >= 0)
+       if (ret >= 0) {
+               if (val < 2 || val > 32) {
+                       dev_err(&pdev->dev,
+                               "tdm-slots must be in rage [2-32]\n");
+                       ret = -EINVAL;
+                       goto nodata;
+               }
+
                pdata->tdm_slots = val;
+       }
 
        ret = of_property_read_u32(np, "num-serializer", &val);
        if (ret >= 0)
@@ -1170,7 +1210,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        dma_data->channel = res->start;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+                                        &davinci_mcasp_dai[pdata->op_mode], 1);
 
        if (ret != 0)
                goto err_release_clk;
@@ -1178,13 +1219,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -1194,7 +1235,7 @@ err_release_clk:
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        pm_runtime_put_sync(&pdev->dev);
index afab81f..078031d 100644 (file)
@@ -181,6 +181,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        unsigned short acnt;
        unsigned int count;
        unsigned int fifo_level;
+       unsigned char serializers = prtd->params->active_serializers;
 
        period_size = snd_pcm_lib_period_bytes(substream);
        dma_offset = prtd->period * period_size;
@@ -194,14 +195,14 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        data_type = prtd->params->data_type;
        count = period_size / data_type;
        if (fifo_level)
-               count /= fifo_level;
+               count /= fifo_level * serializers;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                src = dma_pos;
                dst = prtd->params->dma_addr;
                src_bidx = data_type;
-               dst_bidx = 0;
-               src_cidx = data_type * fifo_level;
+               dst_bidx = 4;
+               src_cidx = data_type * fifo_level * serializers;
                dst_cidx = 0;
        } else {
                src = prtd->params->dma_addr;
@@ -209,7 +210,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
                src_bidx = 0;
                dst_bidx = data_type;
                src_cidx = 0;
-               dst_cidx = data_type * fifo_level;
+               dst_cidx = data_type * fifo_level * serializers;
        }
 
        acnt = prtd->params->acnt;
@@ -223,9 +224,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
                edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
                                                        ASYNC);
        else
-               edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
-                                                       count, fifo_level,
-                                                       ABSYNC);
+               edma_set_transfer_params(prtd->asp_link[0], acnt,
+                                               fifo_level * serializers,
+                                               count, fifo_level * serializers,
+                                               ABSYNC);
 }
 
 static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
index b6ef703..32d7634 100644 (file)
@@ -27,6 +27,7 @@ struct davinci_pcm_dma_params {
        unsigned char data_type;        /* xfer data type */
        unsigned char convert_mono_stereo;
        unsigned int fifo_level;
+       unsigned char active_serializers; /* num. of active audio serializers */
 };
 
 int davinci_soc_platform_register(struct device *dev);
index 07bde2e..30587c0 100644 (file)
@@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_vcif_component = {
+       .name           = "davinci-vcif",
+};
+
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
        struct davinci_vc *davinci_vc = pdev->dev.platform_data;
@@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component,
+                                        &davinci_vcif_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "could not register dai\n");
                return ret;
@@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               snd_soc_unregister_dai(&pdev->dev);
+               snd_soc_unregister_component(&pdev->dev);
                return ret;
        }
 
@@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        return 0;
index deb30d5..593a3ea 100644 (file)
@@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .trigger        = dw_i2s_trigger,
 };
 
+static const struct snd_soc_component_driver dw_i2s_component = {
+       .name           = "dw-i2s",
+};
+
 #ifdef CONFIG_PM
 
 static int dw_i2s_suspend(struct snd_soc_dai *dai)
@@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
        dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+                                        dw_i2s_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "not able to register dai\n");
                goto err_set_drvdata;
@@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(dev->clk);
index ab27ffa..0f0bed6 100644 (file)
@@ -584,6 +584,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
        .ops = &fsl_ssi_dai_ops,
 };
 
+static const struct snd_soc_component_driver fsl_ssi_component = {
+       .name           = "fsl-ssi",
+};
+
 /* Show the statistics of a flag only if its interrupt is enabled.  The
  * compiler will optimze this code to a no-op if the interrupt is not
  * enabled.
@@ -797,7 +801,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        /* Register with ASoC */
        dev_set_drvdata(&pdev->dev, ssi_private);
 
-       ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+       ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
+                                        &ssi_private->cpu_dai_drv, 1);
        if (ret) {
                dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
                goto error_dev;
@@ -850,7 +855,7 @@ done:
 error_dai:
        if (ssi_private->ssi_on_imx)
                platform_device_unregister(ssi_private->imx_pcm_pdev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
        dev_set_drvdata(&pdev->dev, NULL);
@@ -888,7 +893,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
                clk_disable_unprepare(ssi_private->clk);
                clk_put(ssi_private->clk);
        }
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
        free_irq(ssi_private->irq, ssi_private);
index 935eee2..902fab0 100644 (file)
@@ -399,6 +399,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
        .ops = &imx_ssi_pcm_dai_ops,
 };
 
+static const struct snd_soc_component_driver imx_component = {
+       .name           = DRV_NAME,
+};
+
 static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
 {
        void __iomem *base = imx_ssi->base;
@@ -584,7 +588,8 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ssi);
 
-       ret = snd_soc_register_dai(&pdev->dev, dai);
+       ret = snd_soc_register_component(&pdev->dev, &imx_component,
+                                        dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                goto failed_register;
@@ -625,7 +630,7 @@ failed_pdev_alloc:
 failed_pdev_fiq_add:
        platform_device_put(ssi->soc_platform_pdev_fiq);
 failed_pdev_fiq_alloc:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 failed_register:
        release_mem_region(res->start, resource_size(res));
 failed_get_resource:
@@ -643,7 +648,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
        platform_device_unregister(ssi->soc_platform_pdev);
        platform_device_unregister(ssi->soc_platform_pdev_fiq);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
index a4aec04..4141b35 100644 (file)
@@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
        .ops = &psc_ac97_digital_ops,
 } };
 
+static const struct snd_soc_component_driver psc_ac97_component = {
+       .name           = DRV_NAME,
+};
 
 
 /* ---------------------------------------------------------------------
@@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op)
        if (rc != 0)
                return rc;
 
-       rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+       rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
+                                       psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
                return rc;
@@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
 static int psc_ac97_of_remove(struct platform_device *op)
 {
        mpc5200_audio_dma_destroy(op);
-       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+       snd_soc_unregister_component(&op->dev);
        return 0;
 }
 
index b95b966..f4efaad 100644 (file)
@@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
        .ops = &psc_i2s_dai_ops,
 } };
 
+static const struct snd_soc_component_driver psc_i2s_component = {
+       .name           = "mpc5200-i2s",
+};
+
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
  * - Probe/remove operations
@@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op)
        if (rc != 0)
                return rc;
 
-       rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+       rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
+                                       psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
                return rc;
@@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
 static int psc_i2s_of_remove(struct platform_device *op)
 {
        mpc5200_audio_dma_destroy(op);
-       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+       snd_soc_unregister_component(&op->dev);
        return 0;
 }
 
index 6cef491..9a12644 100644 (file)
@@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
        .resume = jz4740_i2s_resume,
 };
 
+static const struct snd_soc_component_driver jz4740_i2s_component = {
+       .name           = "jz4740-i2s",
+};
+
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s;
@@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, i2s);
-       ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
+                                        &jz4740_i2s_dai, 1);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to register DAI\n");
@@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
        clk_put(i2s->clk_aic);
index c74c890..befe68f 100644 (file)
@@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
        .ops = &kirkwood_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver kirkwood_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
        struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
@@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
        }
 
-       err = snd_soc_register_dai(&pdev->dev, soc_dai);
+       err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
+                                        soc_dai, 1);
        if (!err)
                return 0;
-       dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
+       dev_err(&pdev->dev, "snd_soc_register_component failed\n");
 
        if (!IS_ERR(priv->extclk)) {
                clk_disable_unprepare(priv->extclk);
@@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
        struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (!IS_ERR(priv->extclk)) {
                clk_disable_unprepare(priv->extclk);
index a263cbe..392fc0b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  sst_platform.c - Intel MID Platform driver
  *
- *  Copyright (C) 2010-2012 Intel Corp
+ *  Copyright (C) 2010-2013 Intel Corp
  *  Author: Vinod Koul <vinod.koul@intel.com>
  *  Author: Harsha Priya <priya.harsha@intel.com>
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 };
 
+static const struct snd_soc_component_driver sst_component = {
+       .name           = "sst",
+};
+
 /* helper functions */
 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
                                        int state)
@@ -652,11 +656,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
        return stream->compr_ops->get_codec_caps(codec);
 }
 
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+                                       struct snd_compr_metadata *metadata)
+{
+       struct sst_runtime_stream *stream  =
+                cstream->runtime->private_data;
+
+       return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
 static struct snd_compr_ops sst_platform_compr_ops = {
 
        .open = sst_platform_compr_open,
        .free = sst_platform_compr_free,
        .set_params = sst_platform_compr_set_params,
+       .set_metadata = sst_platform_compr_set_metadata,
        .trigger = sst_platform_compr_trigger,
        .pointer = sst_platform_compr_pointer,
        .ack = sst_platform_compr_ack,
@@ -683,7 +697,7 @@ static int sst_platform_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev,
+       ret = snd_soc_register_component(&pdev->dev, &sst_component,
                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
        if (ret) {
                pr_err("registering cpu dais failed\n");
@@ -695,7 +709,7 @@ static int sst_platform_probe(struct platform_device *pdev)
 static int sst_platform_remove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
+       snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
        pr_debug("sst_platform_remove success\n");
        return 0;
index d61c5d5..cacc906 100644 (file)
@@ -124,6 +124,8 @@ struct compress_sst_ops {
        int (*close) (unsigned int str_id);
        int (*get_caps) (struct snd_compr_caps *caps);
        int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+       int (*set_metadata) (unsigned int str_id,
+                       struct snd_compr_metadata *mdata);
 
 };
 
index f13bd87..abf4ddf 100644 (file)
@@ -627,6 +627,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = {
        .ops = &mxs_saif_dai_ops,
 };
 
+static const struct snd_soc_component_driver mxs_saif_component = {
+       .name           = "mxs-saif",
+};
+
 static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
 {
        struct mxs_saif *saif = dev_id;
@@ -763,7 +767,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, saif);
 
-       ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
+                                        &mxs_saif_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                return ret;
@@ -778,7 +783,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
        return 0;
 
 failed_pdev_alloc:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return ret;
 }
@@ -786,7 +791,7 @@ failed_pdev_alloc:
 static int mxs_saif_remove(struct platform_device *pdev)
 {
        mxs_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
index 0418467..fe3285c 100644 (file)
@@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = {
        .ops = &nuc900_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver nuc900_ac97_component = {
+       .name           = "nuc900-ac97",
+};
+
 static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 {
        struct nuc900_audio *nuc900_audio;
@@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 
        nuc900_ac97_data = nuc900_audio;
 
-       ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
+                                        &nuc900_ac97_dai, 1);
        if (ret)
                goto out3;
 
@@ -384,7 +389,7 @@ out0:
 
 static int nuc900_ac97_drvremove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(nuc900_ac97_data->clk);
        iounmap(nuc900_ac97_data->mmio);
index a2597fa..2ad0370 100644 (file)
@@ -444,6 +444,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
        .ops = &omap_dmic_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_dmic_component = {
+       .name           = "omap-dmic",
+};
+
 static int asoc_dmic_probe(struct platform_device *pdev)
 {
        struct omap_dmic *dmic;
@@ -495,7 +499,8 @@ static int asoc_dmic_probe(struct platform_device *pdev)
        if (IS_ERR(dmic->io_base))
                return PTR_ERR(dmic->io_base);
 
-       ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
+       ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
+                                        &omap_dmic_dai, 1);
        if (ret)
                goto err_put_clk;
 
@@ -510,7 +515,7 @@ static int asoc_dmic_remove(struct platform_device *pdev)
 {
        struct omap_dmic *dmic = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        clk_put(dmic->fclk);
 
        return 0;
index b4bfab9..ced3b88 100644 (file)
@@ -260,6 +260,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = {
        .ops = &omap_hdmi_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_hdmi_component = {
+       .name           = DRV_NAME,
+};
+
 static int omap_hdmi_probe(struct platform_device *pdev)
 {
        int ret;
@@ -317,7 +321,8 @@ static int omap_hdmi_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, hdmi_data);
-       ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+       ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
+                                        &omap_hdmi_dai, 1);
 
        return ret;
 }
@@ -326,7 +331,7 @@ static int omap_hdmi_remove(struct platform_device *pdev)
 {
        struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (hdmi_data == NULL) {
                dev_err(&pdev->dev, "cannot obtain HDMi data\n");
index 1e7b3e8..eadbfb6 100644 (file)
@@ -584,6 +584,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
        .ops = &mcbsp_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcbsp_component = {
+       .name           = "omap-mcbsp",
+};
+
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_info *uinfo)
 {
@@ -791,7 +795,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
 
        ret = omap_mcbsp_init(pdev);
        if (!ret)
-               return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+               return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+                                                 &omap_mcbsp_dai, 1);
 
        return ret;
 }
@@ -800,7 +805,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
 {
        struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
                mcbsp->pdata->ops->free(mcbsp->id);
index 49f102a..eb05c7e 100644 (file)
@@ -444,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
        .ops = &omap_mcpdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcpdm_component = {
+       .name           = "omap-mcpdm",
+};
+
 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
                                    u8 rx1, u8 rx2)
 {
@@ -501,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
        mcpdm->dev = &pdev->dev;
 
-       return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+       return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
+                                         &omap_mcpdm_dai, 1);
 }
 
 static int asoc_mcpdm_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 9140c4a..a647799 100644 (file)
@@ -405,6 +405,10 @@ struct snd_soc_dai_driver mmp_sspa_dai = {
        .ops = &mmp_sspa_dai_ops,
 };
 
+static const struct snd_soc_component_driver mmp_sspa_component = {
+       .name           = "mmp-sspa",
+};
+
 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
 {
        struct sspa_priv *priv;
@@ -450,7 +454,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
        priv->dai_fmt = (unsigned int) -1;
        platform_set_drvdata(pdev, priv);
 
-       return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
+       return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
+                                         &mmp_sspa_dai, 1);
 }
 
 static int asoc_mmp_sspa_remove(struct platform_device *pdev)
@@ -460,7 +465,7 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev)
        clk_disable(priv->audio_clk);
        clk_put(priv->audio_clk);
        clk_put(priv->sysclk);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index d3eb0c2..6f4dd75 100644 (file)
@@ -794,14 +794,19 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
                .ops = &pxa_ssp_dai_ops,
 };
 
+static const struct snd_soc_component_driver pxa_ssp_component = {
+       .name           = "pxa-ssp",
+};
+
 static int asoc_ssp_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+       return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+                                         &pxa_ssp_dai, 1);
 }
 
 static int asoc_ssp_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 4b0a009..57ea8e6 100644 (file)
@@ -47,6 +47,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
        .warm_reset     = pxa2xx_ac97_warm_reset,
        .reset  = pxa2xx_ac97_cold_reset,
 };
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
        .name                   = "AC97 PCM Stereo out",
@@ -232,7 +233,9 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
 },
 };
 
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
+static const struct snd_soc_component_driver pxa_ac97_component = {
+       .name           = "pxa-ac97",
+};
 
 static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -245,13 +248,13 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
         * driver to do interesting things with the clocking to get us up
         * and running.
         */
-       return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver,
-                       ARRAY_SIZE(pxa_ac97_dai_driver));
+       return snd_soc_register_component(&pdev->dev, &pxa_ac97_component,
+                                         pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver));
 }
 
 static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 6b1a06f..f7ca716 100644 (file)
@@ -360,14 +360,19 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver pxa_i2s_component = {
+       .name           = "pxa-i2s",
+};
+
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
+       return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+                                         &pxa_i2s_dai, 1);
 }
 
 static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index fee4d47..73bb99f 100644 (file)
@@ -436,6 +436,10 @@ static struct snd_soc_dai_driver s6000_i2s_dai = {
        .ops = &s6000_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s6000_i2s_component = {
+       .name           = "s6000-i2s",
+};
+
 static int s6000_i2s_probe(struct platform_device *pdev)
 {
        struct s6000_i2s_dev *dev;
@@ -543,7 +547,8 @@ static int s6000_i2s_probe(struct platform_device *pdev)
                         S6_I2S_INT_UNDERRUN |
                         S6_I2S_INT_OVERRUN);
 
-       ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component,
+                                        &s6000_i2s_dai, 1);
        if (ret)
                goto err_release_dev;
 
@@ -572,7 +577,7 @@ static void s6000_i2s_remove(struct platform_device *pdev)
        struct resource *region;
        void __iomem *mmio = dev->scbbase;
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        s6000_i2s_stop_channel(dev, 0);
        s6000_i2s_stop_channel(dev, 1);
index 90e7e66..475fb0d 100644 (file)
@@ -35,11 +35,10 @@ config SND_SAMSUNG_I2S
        tristate
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
-       tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
-       depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
+       tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
+       depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
        select SND_S3C24XX_I2S
        select SND_SOC_WM8753
-       select SND_SOC_LM4857 if MACH_NEO1973_GTA01
        select SND_SOC_DFBMCS320
        help
          Say Y here to enable audio support for the Openmoko Neo1973
index 0df3c56..cb88ead 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 
 #include <mach/dma.h>
-#include <plat/regs-ac97.h>
+#include "regs-ac97.h"
 #include <linux/platform_data/asoc-s3c.h>
 
 #include "dma.h"
@@ -370,6 +370,10 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
        },
 };
 
+static const struct snd_soc_component_driver s3c_ac97_component = {
+       .name           = "s3c-ac97",
+};
+
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
        struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
@@ -457,8 +461,8 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                goto err4;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
-                       ARRAY_SIZE(s3c_ac97_dai));
+       ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
+                                        s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
        if (ret)
                goto err5;
 
@@ -470,7 +474,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
 
        return 0;
 err6:
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_component(&pdev->dev);
 err5:
        free_irq(irq_res->start, NULL);
 err4:
@@ -490,7 +494,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
        struct resource *mem_res, *irq_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_component(&pdev->dev);
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq_res)
index d37ede5..415ad81 100644 (file)
@@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 };
 
+static const struct snd_soc_component_driver voice_component = {
+       .name           = "goni-voice",
+};
+
 static struct snd_soc_ops goni_voice_ops = {
        .hw_params = goni_voice_hw_params,
 };
@@ -270,7 +274,8 @@ static int __init goni_init(void)
                return -ENOMEM;
 
        /* register voice DAI here */
-       ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+       ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component,
+                                        &voice_dai, 1);
        if (ret) {
                platform_device_put(goni_snd_device);
                return ret;
@@ -280,7 +285,7 @@ static int __init goni_init(void)
        ret = platform_device_add(goni_snd_device);
 
        if (ret) {
-               snd_soc_unregister_dai(&goni_snd_device->dev);
+               snd_soc_unregister_component(&goni_snd_device->dev);
                platform_device_put(goni_snd_device);
        }
 
@@ -289,7 +294,7 @@ static int __init goni_init(void)
 
 static void __exit goni_exit(void)
 {
-       snd_soc_unregister_dai(&goni_snd_device->dev);
+       snd_soc_unregister_component(&goni_snd_device->dev);
        platform_device_unregister(goni_snd_device);
 }
 
index 15a3817..fa91376 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
index 6bbeb0b..82ebb1a 100644 (file)
@@ -963,6 +963,10 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
        .delay = i2s_delay,
 };
 
+static const struct snd_soc_component_driver samsung_i2s_component = {
+       .name           = "samsung-i2s",
+};
+
 #define SAMSUNG_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
 #define SAMSUNG_I2S_FMTS       (SNDRV_PCM_FMTBIT_S8 | \
@@ -1114,8 +1118,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "Unable to get drvdata\n");
                        return -EFAULT;
                }
-               snd_soc_register_dai(&sec_dai->pdev->dev,
-                       &sec_dai->i2s_dai_drv);
+               snd_soc_register_component(&sec_dai->pdev->dev,
+                                          &samsung_i2s_component,
+                                          &sec_dai->i2s_dai_drv, 1);
                asoc_dma_platform_register(&pdev->dev);
                return 0;
        }
@@ -1244,7 +1249,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                }
        }
 
-       snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
+       snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
+                                  &pri_dai->i2s_dai_drv, 1);
 
        pm_runtime_enable(&pdev->dev);
 
@@ -1283,7 +1289,7 @@ static int samsung_i2s_remove(struct platform_device *pdev)
        i2s->sec_dai = NULL;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
@@ -1298,7 +1304,7 @@ static struct platform_device_id samsung_i2s_driver_ids[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids);
+MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
 
 #ifdef CONFIG_OF
 static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
index a07950b..6e5fed3 100644 (file)
@@ -68,6 +68,8 @@ static struct idma_info {
        dma_addr_t      lp_tx_addr;
 } idma;
 
+static int idma_irq;
+
 static void idma_getpos(dma_addr_t *src)
 {
        *src = idma.lp_tx_addr +
@@ -305,7 +307,7 @@ static int idma_open(struct snd_pcm_substream *substream)
        if (prtd == NULL)
                return -ENOMEM;
 
-       ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
+       ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd);
        if (ret < 0) {
                pr_err("fail to claim i2s irq , ret = %d\n", ret);
                kfree(prtd);
@@ -324,7 +326,7 @@ static int idma_close(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct idma_ctrl *prtd = runtime->private_data;
 
-       free_irq(IRQ_I2S0, prtd);
+       free_irq(idma_irq, prtd);
 
        if (!prtd)
                pr_err("idma_close called with prtd == NULL\n");
@@ -409,6 +411,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
        idma.regs = regs;
        idma.lp_tx_addr = addr;
 }
+EXPORT_SYMBOL_GPL(idma_reg_addr_init);
 
 static struct snd_soc_platform_driver asoc_idma_platform = {
        .ops = &idma_ops,
@@ -418,6 +421,10 @@ static struct snd_soc_platform_driver asoc_idma_platform = {
 
 static int asoc_idma_platform_probe(struct platform_device *pdev)
 {
+       idma_irq = platform_get_irq(pdev, 0);
+       if (idma_irq < 0)
+               return idma_irq;
+
        return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
 }
 
index a301d8c..e591c38 100644 (file)
@@ -21,8 +21,7 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <plat/regs-iis.h>
-#include <mach/gta02.h>
+#include "regs-iis.h"
 
 #include "../codecs/wm8753.h"
 #include "s3c24xx-i2s.h"
index 13bab79..1566afe 100644 (file)
@@ -490,6 +490,10 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
        },
 };
 
+static const struct snd_soc_component_driver s3c_pcm_component = {
+       .name           = "s3c-pcm",
+};
+
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
        struct s3c_pcm_info *pcm;
@@ -583,7 +587,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+       ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
+                                        &s3c_pcm_dai[pdev->id], 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
                goto err5;
@@ -598,7 +603,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        return 0;
 
 err6:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 err5:
        clk_disable_unprepare(pcm->pclk);
        clk_put(pcm->pclk);
@@ -619,7 +624,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
        struct resource *mem_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
 
index a5826ea..704460a 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
index 7a73380..20e98d1 100644 (file)
@@ -731,8 +731,9 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #define s3c2412_i2s_resume  NULL
 #endif
 
-int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv)
+int s3c_i2sv2_register_component(struct device *dev, int id,
+                          struct snd_soc_component_driver *cmp_drv,
+                          struct snd_soc_dai_driver *dai_drv)
 {
        struct snd_soc_dai_ops *ops = drv->ops;
 
@@ -750,8 +751,8 @@ int s3c_i2sv2_register_dai(struct device *dev, int id,
        drv->suspend = s3c2412_i2s_suspend;
        drv->resume = s3c2412_i2s_resume;
 
-       return snd_soc_register_dai(dev, drv);
+       return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
 }
-EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
 
 MODULE_LICENSE("GPL");
index f8297d9..90abab3 100644 (file)
@@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
                           unsigned long base);
 
 /**
- * s3c_i2sv2_register_dai - register dai with soc core
+ * s3c_i2sv2_register_component - register component and dai with soc core
  * @dev: DAI device
  * @id: DAI ID
  * @drv: The driver structure to register
@@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
  * Fill in any missing fields and then register the given dai with the
  * soc core.
  */
-extern int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv);
+extern int s3c_i2sv2_register_component(struct device *dev, int id,
+                                       struct snd_soc_component_driver *cmp_drv,
+                                       struct snd_soc_dai_driver *dai_drv);
 
 #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
index 2213377..47e2386 100644 (file)
@@ -160,11 +160,17 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
        .ops = &s3c2412_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c2412_i2s_component = {
+       .name           = "s3c2412-i2s",
+};
+
 static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
 
-       ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai);
+       ret = s3c_i2sv2_register_component(&pdev->dev, -1,
+                                          &s3c2412_i2s_component,
+                                          &s3c2412_i2s_dai);
        if (ret) {
                pr_err("failed to register the dai\n");
                return ret;
@@ -178,14 +184,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return ret;
 }
 
 static int s3c2412_iis_dev_remove(struct platform_device *pdev)
 {
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 13f6dd1..8b34145 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/pcm_params.h>
 
 #include <mach/dma.h>
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "dma.h"
 #include "s3c24xx-i2s.h"
@@ -465,11 +465,16 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
        .ops = &s3c24xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c24xx_i2s_component = {
+       .name           = "s3c24xx-i2s",
+};
+
 static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
 
-       ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component,
+                                        &s3c24xx_i2s_dai, 1);
        if (ret) {
                pr_err("failed to register the dai\n");
                return ret;
@@ -483,14 +488,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return ret;
 }
 
 static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
 {
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 333e1b7..1b7b52b 100644 (file)
@@ -18,7 +18,7 @@
 #include <sound/soc.h>
 #include <sound/s3c24xx_uda134x.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "s3c24xx-i2s.h"
 
index 5008e5b..2e5ebb2 100644 (file)
@@ -357,6 +357,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = {
        .resume = spdif_resume,
 };
 
+static const struct snd_soc_component_driver samsung_spdif_component = {
+       .name           = "samsung-spdif",
+};
+
 static int spdif_probe(struct platform_device *pdev)
 {
        struct s3c_audio_pdata *spdif_pdata;
@@ -424,7 +428,8 @@ static int spdif_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, spdif);
 
-       ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component,
+                                        &samsung_spdif_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "fail to register dai\n");
                goto err4;
@@ -445,7 +450,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        return 0;
 err5:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 err4:
        iounmap(spdif->regs);
 err3:
@@ -466,7 +471,7 @@ static int spdif_remove(struct platform_device *pdev)
        struct resource *mem_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        iounmap(spdif->regs);
 
index c724026..f830c41 100644 (file)
@@ -296,7 +296,6 @@ struct fsi_core {
 
 struct fsi_master {
        void __iomem *base;
-       int irq;
        struct fsi_priv fsia;
        struct fsi_priv fsib;
        const struct fsi_core *core;
@@ -1886,6 +1885,10 @@ static struct snd_soc_platform_driver fsi_soc_platform = {
        .pcm_free       = fsi_pcm_free,
 };
 
+static const struct snd_soc_component_driver fsi_soc_component = {
+       .name           = "fsi",
+};
+
 /*
  *             platform function
  */
@@ -2002,7 +2005,6 @@ static int fsi_probe(struct platform_device *pdev)
        }
 
        /* master setting */
-       master->irq             = irq;
        master->core            = core;
        spin_lock_init(&master->lock);
 
@@ -2046,10 +2048,10 @@ static int fsi_probe(struct platform_device *pdev)
                goto exit_fsib;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai,
-                                   ARRAY_SIZE(fsi_soc_dai));
+       ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component,
+                                   fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot snd dai register\n");
+               dev_err(&pdev->dev, "cannot snd component register\n");
                goto exit_snd_soc;
        }
 
@@ -2074,7 +2076,7 @@ static int fsi_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+       snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
 
        fsi_stream_remove(&master->fsia);
index 4cc2d64..af19f77 100644 (file)
@@ -310,15 +310,19 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_hac_component = {
+       .name           = "sh4-hac",
+};
+
 static int hac_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
-                       ARRAY_SIZE(sh4_hac_dai));
+       return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+                                         sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
 }
 
 static int hac_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 8526e1e..5014a88 100644 (file)
@@ -153,7 +153,7 @@ static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link migor_dai = {
        .name = "wm8978",
        .stream_name = "WM8978",
-       .cpu_dai_name = "siu-i2s-dai",
+       .cpu_dai_name = "siu-pcm-audio",
        .codec_dai_name = "wm8978-hifi",
        .platform_name = "siu-pcm-audio",
        .codec_name = "wm8978.0-001a",
index 34facdc..9dc24ff 100644 (file)
@@ -726,6 +726,10 @@ static struct snd_soc_dai_driver siu_i2s_dai = {
        .ops = &siu_dai_ops,
 };
 
+static const struct snd_soc_component_driver siu_i2s_component = {
+       .name           = "siu-i2s",
+};
+
 static int siu_probe(struct platform_device *pdev)
 {
        const struct firmware *fw_entry;
@@ -783,7 +787,8 @@ static int siu_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, info);
 
        /* register using ARRAY version so we can keep dai name */
-       ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
+       ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+                                        &siu_i2s_dai, 1);
        if (ret < 0)
                goto edaiinit;
 
@@ -796,7 +801,7 @@ static int siu_probe(struct platform_device *pdev)
        return ret;
 
 esocregp:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 edaiinit:
        iounmap(info->reg);
 emapreg:
@@ -823,7 +828,7 @@ static int siu_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
        snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        iounmap(info->reg);
        iounmap(info->yram);
index c8e73a7..e889405 100644 (file)
@@ -379,15 +379,19 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_ssi_component = {
+       .name           = "sh4-ssi",
+};
+
 static int sh4_soc_dai_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
-                       ARRAY_SIZE(sh4_ssi_dai));
+       return snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
+                                         sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
 }
 
 static int sh4_soc_dai_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index ed0bfb0..29093a3 100644 (file)
@@ -330,11 +330,38 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
        return ret;
 }
 
+static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+                               struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
+               ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
+
+       return ret;
+}
+
+static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+                               struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
+               ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
+
+       return ret;
+}
 /* ASoC Compress operations */
 static struct snd_compr_ops soc_compr_ops = {
        .open           = soc_compr_open,
        .free           = soc_compr_free,
        .set_params     = soc_compr_set_params,
+       .set_metadata   = sst_compr_set_metadata,
+       .get_metadata   = sst_compr_get_metadata,
        .get_params     = soc_compr_get_params,
        .trigger        = soc_compr_trigger,
        .pointer        = soc_compr_pointer,
index 78468c6..d56bbea 100644 (file)
@@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
+static LIST_HEAD(component_list);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -3740,7 +3741,7 @@ static inline char *fmt_multiple_name(struct device *dev,
  *
  * @dai: DAI to register
  */
-int snd_soc_register_dai(struct device *dev,
+static int snd_soc_register_dai(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
        struct snd_soc_codec *codec;
@@ -3787,14 +3788,13 @@ int snd_soc_register_dai(struct device *dev,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 
 /**
  * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
  *
  * @dai: DAI to unregister
  */
-void snd_soc_unregister_dai(struct device *dev)
+static void snd_soc_unregister_dai(struct device *dev)
 {
        struct snd_soc_dai *dai;
 
@@ -3813,7 +3813,6 @@ found:
        kfree(dai->name);
        kfree(dai);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 
 /**
  * snd_soc_register_dais - Register multiple DAIs with the ASoC core
@@ -3821,7 +3820,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  * @dai: Array of DAIs to register
  * @count: Number of DAIs
  */
-int snd_soc_register_dais(struct device *dev,
+static int snd_soc_register_dais(struct device *dev,
                struct snd_soc_dai_driver *dai_drv, size_t count)
 {
        struct snd_soc_codec *codec;
@@ -3885,7 +3884,6 @@ err:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dais);
 
 /**
  * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
@@ -3893,14 +3891,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  * @dai: Array of DAIs to unregister
  * @count: Number of DAIs
  */
-void snd_soc_unregister_dais(struct device *dev, size_t count)
+static void snd_soc_unregister_dais(struct device *dev, size_t count)
 {
        int i;
 
        for (i = 0; i < count; i++)
                snd_soc_unregister_dai(dev);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 
 /**
  * snd_soc_add_platform - Add a platform to the ASoC core
@@ -4179,6 +4176,92 @@ found:
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
+
+/**
+ * snd_soc_register_component - Register a component with the ASoC core
+ *
+ */
+int snd_soc_register_component(struct device *dev,
+                        const struct snd_soc_component_driver *cmpnt_drv,
+                        struct snd_soc_dai_driver *dai_drv,
+                        int num_dai)
+{
+       struct snd_soc_component *cmpnt;
+       int ret;
+
+       dev_dbg(dev, "component register %s\n", dev_name(dev));
+
+       cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
+       if (!cmpnt) {
+               dev_err(dev, "ASoC: Failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       cmpnt->name = fmt_single_name(dev, &cmpnt->id);
+       if (!cmpnt->name) {
+               dev_err(dev, "ASoC: Failed to simplifying name\n");
+               return -ENOMEM;
+       }
+
+       cmpnt->dev      = dev;
+       cmpnt->driver   = cmpnt_drv;
+       cmpnt->num_dai  = num_dai;
+
+       /*
+        * snd_soc_register_dai()  uses fmt_single_name(), and
+        * snd_soc_register_dais() uses fmt_multiple_name()
+        * for dai->name which is used for name based matching
+        */
+       if (1 == num_dai)
+               ret = snd_soc_register_dai(dev, dai_drv);
+       else
+               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+       if (ret < 0) {
+               dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+               goto error_component_name;
+       }
+
+       mutex_lock(&client_mutex);
+       list_add(&cmpnt->list, &component_list);
+       mutex_unlock(&client_mutex);
+
+       dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
+
+       return ret;
+
+error_component_name:
+       kfree(cmpnt->name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_component);
+
+/**
+ * snd_soc_unregister_component - Unregister a component from the ASoC core
+ *
+ */
+void snd_soc_unregister_component(struct device *dev)
+{
+       struct snd_soc_component *cmpnt;
+
+       list_for_each_entry(cmpnt, &component_list, list) {
+               if (dev == cmpnt->dev)
+                       goto found;
+       }
+       return;
+
+found:
+       snd_soc_unregister_dais(dev, cmpnt->num_dai);
+
+       mutex_lock(&client_mutex);
+       list_del(&cmpnt->list);
+       mutex_unlock(&client_mutex);
+
+       dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+       kfree(cmpnt->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+
 /* Retrieve a card's name from device tree */
 int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                               const char *propname)
index 33acd8b..21779a6 100644 (file)
@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
-/* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+/*
+ * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
+ * create it. Either way, add the widget into the control's widget list
+ */
+static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
+       int kci, struct snd_soc_dapm_path *path)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
-       int i, ret = 0;
-       size_t name_len, prefix_len;
-       struct snd_soc_dapm_path *path;
        struct snd_card *card = dapm->card->snd_card;
        const char *prefix;
+       size_t prefix_len;
+       int shared;
+       struct snd_kcontrol *kcontrol;
        struct snd_soc_dapm_widget_list *wlist;
+       int wlistentries;
        size_t wlistsize;
+       bool wname_in_long_name, kcname_in_long_name;
+       size_t name_len;
+       char *long_name;
+       const char *name;
+       int ret;
 
        if (dapm->codec)
                prefix = dapm->codec->name_prefix;
@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
        else
                prefix_len = 0;
 
-       /* add kcontrol */
-       for (i = 0; i < w->num_kcontrols; i++) {
+       shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
+                                        &kcontrol);
 
-               /* match name */
-               list_for_each_entry(path, &w->sources, list_sink) {
+       if (kcontrol) {
+               wlist = kcontrol->private_data;
+               wlistentries = wlist->num_widgets + 1;
+       } else {
+               wlist = NULL;
+               wlistentries = 1;
+       }
 
-                       /* mixer/mux paths name must match control name */
-                       if (path->name != (char *)w->kcontrol_news[i].name)
-                               continue;
+       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+                       wlistentries * sizeof(struct snd_soc_dapm_widget *);
+       wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
+       if (wlist == NULL) {
+               dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
+                       w->name);
+               return -ENOMEM;
+       }
+       wlist->num_widgets = wlistentries;
+       wlist->widgets[wlistentries - 1] = w;
 
-                       if (w->kcontrols[i]) {
-                               path->kcontrol = w->kcontrols[i];
-                               continue;
+       if (!kcontrol) {
+               if (shared) {
+                       wname_in_long_name = false;
+                       kcname_in_long_name = true;
+               } else {
+                       switch (w->id) {
+                       case snd_soc_dapm_switch:
+                       case snd_soc_dapm_mixer:
+                               wname_in_long_name = true;
+                               kcname_in_long_name = true;
+                               break;
+                       case snd_soc_dapm_mixer_named_ctl:
+                               wname_in_long_name = false;
+                               kcname_in_long_name = true;
+                               break;
+                       case snd_soc_dapm_mux:
+                       case snd_soc_dapm_virt_mux:
+                       case snd_soc_dapm_value_mux:
+                               wname_in_long_name = true;
+                               kcname_in_long_name = false;
+                               break;
+                       default:
+                               kfree(wlist);
+                               return -EINVAL;
                        }
+               }
+
+               if (wname_in_long_name && kcname_in_long_name) {
+                       name_len = strlen(w->name) - prefix_len + 1 +
+                                  strlen(w->kcontrol_news[kci].name) + 1;
 
-                       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-                                   sizeof(struct snd_soc_dapm_widget *),
-                       wlist = kzalloc(wlistsize, GFP_KERNEL);
-                       if (wlist == NULL) {
-                               dev_err(dapm->dev,
-                                       "ASoC: can't allocate widget list for %s\n",
-                                       w->name);
+                       long_name = kmalloc(name_len, GFP_KERNEL);
+                       if (long_name == NULL) {
+                               kfree(wlist);
                                return -ENOMEM;
                        }
-                       wlist->num_widgets = 1;
-                       wlist->widgets[0] = w;
-
-                       /* add dapm control with long name.
-                        * for dapm_mixer this is the concatenation of the
-                        * mixer and kcontrol name.
-                        * for dapm_mixer_named_ctl this is simply the
-                        * kcontrol name.
+
+                       /*
+                        * The control will get a prefix from the control
+                        * creation process but we're also using the same
+                        * prefix for widgets so cut the prefix off the
+                        * front of the widget name.
                         */
-                       name_len = strlen(w->kcontrol_news[i].name) + 1;
-                       if (w->id != snd_soc_dapm_mixer_named_ctl)
-                               name_len += 1 + strlen(w->name);
+                       snprintf(long_name, name_len, "%s %s",
+                                w->name + prefix_len,
+                                w->kcontrol_news[kci].name);
+                       long_name[name_len - 1] = '\0';
+
+                       name = long_name;
+               } else if (wname_in_long_name) {
+                       long_name = NULL;
+                       name = w->name + prefix_len;
+               } else {
+                       long_name = NULL;
+                       name = w->kcontrol_news[kci].name;
+               }
 
-                       path->long_name = kmalloc(name_len, GFP_KERNEL);
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+                                       prefix);
+               ret = snd_ctl_add(card, kcontrol);
+               if (ret < 0) {
+                       dev_err(dapm->dev,
+                               "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
+                               w->name, name, ret);
+                       kfree(wlist);
+                       kfree(long_name);
+                       return ret;
+               }
 
-                       if (path->long_name == NULL) {
-                               kfree(wlist);
-                               return -ENOMEM;
-                       }
+               path->long_name = long_name;
+       }
 
-                       switch (w->id) {
-                       default:
-                               /* The control will get a prefix from
-                                * the control creation process but
-                                * we're also using the same prefix
-                                * for widgets so cut the prefix off
-                                * the front of the widget name.
-                                */
-                               snprintf((char *)path->long_name, name_len,
-                                        "%s %s", w->name + prefix_len,
-                                        w->kcontrol_news[i].name);
-                               break;
-                       case snd_soc_dapm_mixer_named_ctl:
-                               snprintf((char *)path->long_name, name_len,
-                                        "%s", w->kcontrol_news[i].name);
-                               break;
-                       }
+       kcontrol->private_data = wlist;
+       w->kcontrols[kci] = kcontrol;
+       path->kcontrol = kcontrol;
 
-                       ((char *)path->long_name)[name_len - 1] = '\0';
+       return 0;
+}
 
-                       path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
-                                                     wlist, path->long_name,
-                                                     prefix);
-                       ret = snd_ctl_add(card, path->kcontrol);
-                       if (ret < 0) {
-                               dev_err(dapm->dev, "ASoC: failed to add widget"
-                                       " %s dapm kcontrol %s: %d\n",
-                                       w->name, path->long_name, ret);
-                               kfree(wlist);
-                               kfree(path->long_name);
-                               path->long_name = NULL;
-                               return ret;
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+{
+       int i, ret;
+       struct snd_soc_dapm_path *path;
+
+       /* add kcontrol */
+       for (i = 0; i < w->num_kcontrols; i++) {
+               /* match name */
+               list_for_each_entry(path, &w->sources, list_sink) {
+                       /* mixer/mux paths name must match control name */
+                       if (path->name != (char *)w->kcontrol_news[i].name)
+                               continue;
+
+                       if (w->kcontrols[i]) {
+                               path->kcontrol = w->kcontrols[i];
+                               continue;
                        }
-                       w->kcontrols[i] = path->kcontrol;
+
+                       ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+                       if (ret < 0)
+                               return ret;
                }
        }
-       return ret;
+
+       return 0;
 }
 
 /* create new dapm mux control */
 static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_dapm_path *path = NULL;
-       struct snd_kcontrol *kcontrol;
-       struct snd_card *card = dapm->card->snd_card;
-       const char *prefix;
-       size_t prefix_len;
+       struct snd_soc_dapm_path *path;
        int ret;
-       struct snd_soc_dapm_widget_list *wlist;
-       int shared, wlistentries;
-       size_t wlistsize;
-       const char *name;
 
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
                return -EINVAL;
        }
 
-       shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
-                                        &kcontrol);
-       if (kcontrol) {
-               wlist = kcontrol->private_data;
-               wlistentries = wlist->num_widgets + 1;
-       } else {
-               wlist = NULL;
-               wlistentries = 1;
-       }
-       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-               wlistentries * sizeof(struct snd_soc_dapm_widget *),
-       wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
-       if (wlist == NULL) {
-               dev_err(dapm->dev,
-                       "ASoC: can't allocate widget list for %s\n", w->name);
-               return -ENOMEM;
-       }
-       wlist->num_widgets = wlistentries;
-       wlist->widgets[wlistentries - 1] = w;
-
-       if (!kcontrol) {
-               if (dapm->codec)
-                       prefix = dapm->codec->name_prefix;
-               else
-                       prefix = NULL;
-
-               if (shared) {
-                       name = w->kcontrol_news[0].name;
-                       prefix_len = 0;
-               } else {
-                       name = w->name;
-                       if (prefix)
-                               prefix_len = strlen(prefix) + 1;
-                       else
-                               prefix_len = 0;
-               }
-
-               /*
-                * The control will get a prefix from the control creation
-                * process but we're also using the same prefix for widgets so
-                * cut the prefix off the front of the widget name.
-                */
-               kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
-                                       name + prefix_len, prefix);
-               ret = snd_ctl_add(card, kcontrol);
-               if (ret < 0) {
-                       dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n",
-                               w->name, ret);
-                       kfree(wlist);
-                       return ret;
-               }
+       path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+                               list_sink);
+       if (!path) {
+               dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+               return -EINVAL;
        }
 
-       kcontrol->private_data = wlist;
-
-       w->kcontrols[0] = kcontrol;
+       ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+       if (ret < 0)
+               return ret;
 
        list_for_each_entry(path, &w->sources, list_sink)
-               path->kcontrol = kcontrol;
+               path->kcontrol = w->kcontrols[0];
 
        return 0;
 }
@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
 }
 
 /* reset 'walked' bit for each dapm path */
-static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
+static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
+                                  struct list_head *sink)
 {
        struct snd_soc_dapm_path *p;
 
-       list_for_each_entry(p, &dapm->card->paths, list)
-               p->walked = 0;
+       list_for_each_entry(p, sink, list_source) {
+               if (p->walked) {
+                       p->walked = 0;
+                       dapm_clear_walk_output(dapm, &p->sink->sinks);
+               }
+       }
 }
 
+static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
+                                 struct list_head *source)
+{
+       struct snd_soc_dapm_path *p;
+
+       list_for_each_entry(p, source, list_sink) {
+               if (p->walked) {
+                       p->walked = 0;
+                       dapm_clear_walk_input(dapm, &p->source->sources);
+               }
+       }
+}
+
+
 /* We implement power down on suspend by checking the power state of
  * the ALSA card - when we are suspending the ALSA state for the card
  * is set to D3.
@@ -995,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        dapm_reset(card);
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                paths = is_connected_output_ep(dai->playback_widget, list);
-       else
+               dapm_clear_walk_output(&card->dapm,
+                                      &dai->playback_widget->sinks);
+       } else {
                paths = is_connected_input_ep(dai->capture_widget, list);
+               dapm_clear_walk_input(&card->dapm,
+                                     &dai->capture_widget->sources);
+       }
 
        trace_snd_soc_dapm_connected(paths, stream);
-       dapm_clear_walk(&card->dapm);
        mutex_unlock(&card->dapm_mutex);
 
        return paths;
@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
        DAPM_UPDATE_STAT(w, power_checks);
 
        in = is_connected_input_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_output(w->dapm, &w->sinks);
        return out != 0 && in != 0;
 }
 
@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                in = is_connected_input_ep(w, NULL);
-               dapm_clear_walk(w->dapm);
+               dapm_clear_walk_input(w->dapm, &w->sources);
                return in != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                out = is_connected_output_ep(w, NULL);
-               dapm_clear_walk(w->dapm);
+               dapm_clear_walk_output(w->dapm, &w->sinks);
                return out != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
                        return 1;
        }
 
-       dapm_clear_walk(w->dapm);
-
        return 0;
 }
 
@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                return -ENOMEM;
 
        in = is_connected_input_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_output(w->dapm, &w->sinks);
 
        ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
                       w->name, w->power ? "On" : "Off",
index c7c4b20..14d57e8 100644 (file)
@@ -170,6 +170,10 @@ struct snd_soc_dai_driver spdif_in_dai = {
        .ops = &spdif_in_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_in_component = {
+       .name           = "spdif-in",
+};
+
 static irqreturn_t spdif_in_irq(int irq, void *arg)
 {
        struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
@@ -258,7 +262,8 @@ static int spdif_in_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
+       ret = snd_soc_register_component(&pdev->dev, &spdif_in_component,
+                                        &spdif_in_dai, 1);
        if (ret != 0) {
                clk_put(host->clk);
                return ret;
@@ -271,7 +276,7 @@ static int spdif_in_remove(struct platform_device *pdev)
 {
        struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(host->clk);
index 5eac4cd..1e3c3dd 100644 (file)
@@ -270,6 +270,10 @@ static struct snd_soc_dai_driver spdif_out_dai = {
        .ops = &spdif_out_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_out_component = {
+       .name           = "spdif-out",
+};
+
 static int spdif_out_probe(struct platform_device *pdev)
 {
        struct spdif_out_dev *host;
@@ -314,7 +318,8 @@ static int spdif_out_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, host);
 
-       ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai);
+       ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
+                                        &spdif_out_dai, 1);
        if (ret != 0) {
                clk_put(host->clk);
                return ret;
@@ -327,7 +332,7 @@ static int spdif_out_remove(struct platform_device *pdev)
 {
        struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(host->clk);
index d653763..2fbd489 100644 (file)
@@ -25,7 +25,7 @@
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 
-struct snd_pcm_hardware spear_pcm_hardware = {
+static struct snd_pcm_hardware spear_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
@@ -165,7 +165,7 @@ static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-struct snd_soc_platform_driver spear_soc_platform = {
+static struct snd_soc_platform_driver spear_soc_platform = {
        .ops            =       &spear_pcm_ops,
        .pcm_new        =       spear_pcm_new,
        .pcm_free       =       spear_pcm_free,
index 2d7b8c2..2f70ea7 100644 (file)
@@ -249,6 +249,10 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = {
        .ops = &tegra20_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_ac97_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -399,7 +403,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ac97->capture_dma_data.maxburst = 4;
        ac97->capture_dma_data.slave_id = of_dma[0];
 
-       ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
+                                        &tegra20_ac97_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -409,7 +414,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
@@ -435,8 +440,8 @@ err_asoc_utils_fini:
        tegra_asoc_utils_fini(&ac97->util_data);
 err_unregister_pcm:
        tegra_pcm_platform_unregister(&pdev->dev);
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_clk_put:
        clk_put(ac97->clk_ac97);
 err:
@@ -448,7 +453,7 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
        struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        tegra_asoc_utils_fini(&ac97->util_data);
 
index e6651e0..52af7f6 100644 (file)
@@ -277,6 +277,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra20_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -420,7 +424,8 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
+                                        &i2s->dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -430,13 +435,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra20_i2s_runtime_suspend(&pdev->dev);
@@ -457,7 +462,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
                tegra20_i2s_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
 
index b7b4743..5eaa12c 100644 (file)
@@ -183,6 +183,10 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
        .ops = &tegra20_spdif_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_spdif_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -330,7 +334,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,
+                                  &tegra20_spdif_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -340,13 +345,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra20_spdif_runtime_suspend(&pdev->dev);
@@ -367,7 +372,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev)
                tegra20_spdif_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(spdif->clk_spdif_out);
 
index 5e08f3e..23e592f 100644 (file)
@@ -287,16 +287,27 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
 }
 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
 
-static const char * const configlink_clocks[] = {
-       "i2s0",
-       "i2s1",
-       "i2s2",
-       "i2s3",
-       "i2s4",
-       "dam0",
-       "dam1",
-       "dam2",
-       "spdif_in",
+#define CLK_LIST_MASK_TEGRA30  BIT(0)
+#define CLK_LIST_MASK_TEGRA114 BIT(1)
+
+#define CLK_LIST_MASK_TEGRA30_OR_LATER \
+               (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114)
+
+static const struct {
+       const char *clk_name;
+       u32 clk_list_mask;
+} configlink_clocks[] = {
+       { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "amx", CLK_LIST_MASK_TEGRA114 },
+       { "adx", CLK_LIST_MASK_TEGRA114 },
 };
 
 #define LAST_REG(name) \
@@ -424,8 +435,24 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static struct tegra30_ahub_soc_data soc_data_tegra30 = {
+       .clk_list_mask = CLK_LIST_MASK_TEGRA30,
+};
+
+static struct tegra30_ahub_soc_data soc_data_tegra114 = {
+       .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+};
+
+static const struct of_device_id tegra30_ahub_of_match[] = {
+       { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
+       { .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
+       {},
+};
+
 static int tegra30_ahub_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
+       const struct tegra30_ahub_soc_data *soc_data;
        struct clk *clk;
        int i;
        struct resource *res0, *res1, *region;
@@ -436,16 +463,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
        if (ahub)
                return -ENODEV;
 
+       match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
+       if (!match)
+               return -EINVAL;
+       soc_data = match->data;
+
        /*
         * The AHUB hosts a register bus: the "configlink". For this to
         * operate correctly, all devices on this bus must be out of reset.
         * Ensure that here.
         */
        for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
-               clk = clk_get(&pdev->dev, configlink_clocks[i]);
+               if (!(configlink_clocks[i].clk_list_mask &
+                                       soc_data->clk_list_mask))
+                       continue;
+               clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name);
                if (IS_ERR(clk)) {
                        dev_err(&pdev->dev, "Can't get clock %s\n",
-                               configlink_clocks[i]);
+                               configlink_clocks[i].clk_name);
                        ret = PTR_ERR(clk);
                        goto err;
                }
@@ -592,11 +627,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id tegra30_ahub_of_match[] = {
-       { .compatible = "nvidia,tegra30-ahub", },
-       {},
-};
-
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
                           tegra30_ahub_runtime_resume, NULL)
index b7d7c1a..09766cd 100644 (file)
@@ -468,7 +468,23 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
                                          enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
 
+struct tegra30_ahub_soc_data {
+       u32 clk_list_mask;
+       /*
+        * FIXME: There are many more differences in HW, such as:
+        * - More APBIF channels.
+        * - Extra separate chunks of register address space to represent
+        *   the extra APBIF channels.
+        * - More units connected to the AHUB, so that tegra30_ahub_[rt]xcif
+        *   need expansion, coupled with there being more defined bits in
+        *   the AHUB routing registers.
+        * However, the driver doesn't support those new features yet, so we
+        * don't represent them here yet.
+        */
+};
+
 struct tegra30_ahub {
+       const struct tegra30_ahub_soc_data *soc_data;
        struct device *dev;
        struct clk *clk_d_audio;
        struct clk *clk_apbif;
index 857ec21..31d092d 100644 (file)
@@ -337,6 +337,10 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra30_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -465,7 +469,8 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component,
+                                  &i2s->dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -475,13 +480,13 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra30_i2s_runtime_suspend(&pdev->dev);
@@ -502,7 +507,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
                tegra30_i2s_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
 
index c80adb9..48d05d9 100644 (file)
@@ -161,20 +161,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
                        sizeof(struct tegra_alc5632), GFP_KERNEL);
        if (!alc5632) {
                dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, alc5632);
 
-       if (!(pdev->dev.of_node)) {
-               dev_err(&pdev->dev, "Must be instantiated using device tree\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
        alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
        if (alc5632->gpio_hp_det == -EPROBE_DEFER)
                return -EPROBE_DEFER;
@@ -197,11 +190,11 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_alc5632_dai.cpu_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,i2s-controller", 0);
+       tegra_alc5632_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
        if (!tegra_alc5632_dai.cpu_of_node) {
                dev_err(&pdev->dev,
-               "Property 'nvidia,i2s-controller' missing or invalid\n");
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
                goto err;
        }
index ba419f8..24fb001 100644 (file)
@@ -43,8 +43,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 88200:
                if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                        new_baseclock = 56448000;
-               else
+               else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
                        new_baseclock = 564480000;
+               else
+                       new_baseclock = 282240000;
                break;
        case 8000:
        case 16000:
@@ -54,8 +56,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 96000:
                if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                        new_baseclock = 73728000;
-               else
+               else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
                        new_baseclock = 552960000;
+               else
+                       new_baseclock = 368640000;
                break;
        default:
                return -EINVAL;
@@ -169,6 +173,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                          struct device *dev)
 {
        int ret;
+       bool new_clocks = false;
 
        data->dev = dev;
 
@@ -176,28 +181,37 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
        else if (of_machine_is_compatible("nvidia,tegra30"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
-       else if (!dev->of_node)
-               /* non-DT is always Tegra20 */
-               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
-       else
-               /* DT boot, but unknown SoC */
+       else if (of_machine_is_compatible("nvidia,tegra114")) {
+               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
+               new_clocks = true;
+       } else {
+               dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
                return -EINVAL;
+       }
 
-       data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+       if (new_clocks)
+               data->clk_pll_a = clk_get(dev, "pll_a");
+       else
+               data->clk_pll_a = clk_get_sys(NULL, "pll_a");
        if (IS_ERR(data->clk_pll_a)) {
                dev_err(data->dev, "Can't retrieve clk pll_a\n");
                ret = PTR_ERR(data->clk_pll_a);
                goto err;
        }
 
-       data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+       if (new_clocks)
+               data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
+       else
+               data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
        if (IS_ERR(data->clk_pll_a_out0)) {
                dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
                ret = PTR_ERR(data->clk_pll_a_out0);
                goto err_put_pll_a;
        }
 
-       if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+       if (new_clocks)
+               data->clk_cdev1 = clk_get(dev, "mclk");
+       else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
        else
                data->clk_cdev1 = clk_get_sys("extern1", NULL);
index 974c9f8..19fdcaf 100644 (file)
@@ -29,6 +29,7 @@ struct device;
 enum tegra_asoc_utils_soc {
        TEGRA_ASOC_UTILS_SOC_TEGRA20,
        TEGRA_ASOC_UTILS_SOC_TEGRA30,
+       TEGRA_ASOC_UTILS_SOC_TEGRA114,
 };
 
 struct tegra_asoc_utils_data {
index c8ef88a..f87fc53 100644 (file)
@@ -124,6 +124,7 @@ static struct snd_soc_card snd_soc_tegra_wm8753 = {
 
 static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_wm8753;
        struct tegra_wm8753 *machine;
        int ret;
@@ -132,8 +133,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                               GFP_KERNEL);
        if (!machine) {
                dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        card->dev = &pdev->dev;
@@ -148,8 +148,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       tegra_wm8753_dai.codec_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,audio-codec", 0);
+       tegra_wm8753_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
        if (!tegra_wm8753_dai.codec_of_node) {
                dev_err(&pdev->dev,
                        "Property 'nvidia,audio-codec' missing or invalid\n");
@@ -157,8 +157,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_wm8753_dai.cpu_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,i2s-controller", 0);
+       tegra_wm8753_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
        if (!tegra_wm8753_dai.cpu_of_node) {
                dev_err(&pdev->dev,
                        "Property 'nvidia,i2s-controller' missing or invalid\n");
@@ -166,8 +166,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_wm8753_dai.platform_of_node =
-                               tegra_wm8753_dai.cpu_of_node;
+       tegra_wm8753_dai.platform_of_node = tegra_wm8753_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
index bbd79bf..4ac7373 100644 (file)
@@ -39,7 +39,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/tegra_wm8903.h>
 
 #include "../codecs/wm8903.h"
 
 #define DRV_NAME "tegra-snd-wm8903"
 
 struct tegra_wm8903 {
-       struct tegra_wm8903_platform_data pdata;
+       int gpio_spkr_en;
+       int gpio_hp_det;
+       int gpio_hp_mute;
+       int gpio_int_mic_en;
+       int gpio_ext_mic_en;
        struct tegra_asoc_utils_data util_data;
 };
 
@@ -129,12 +132,11 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!gpio_is_valid(pdata->gpio_spkr_en))
+       if (!gpio_is_valid(machine->gpio_spkr_en))
                return 0;
 
-       gpio_set_value_cansleep(pdata->gpio_spkr_en,
+       gpio_set_value_cansleep(machine->gpio_spkr_en,
                                SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
@@ -146,12 +148,11 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!gpio_is_valid(pdata->gpio_hp_mute))
+       if (!gpio_is_valid(machine->gpio_hp_mute))
                return 0;
 
-       gpio_set_value_cansleep(pdata->gpio_hp_mute,
+       gpio_set_value_cansleep(machine->gpio_hp_mute,
                                !SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
@@ -163,17 +164,6 @@ static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Mic Jack", NULL),
 };
 
-static const struct snd_soc_dapm_route harmony_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "ROP"},
-       {"Int Spk", NULL, "RON"},
-       {"Int Spk", NULL, "LOP"},
-       {"Int Spk", NULL, "LON"},
-       {"Mic Jack", NULL, "MICBIAS"},
-       {"IN1L", NULL, "Mic Jack"},
-};
-
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
        SOC_DAPM_PIN_SWITCH("Int Spk"),
 };
@@ -185,10 +175,9 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (gpio_is_valid(pdata->gpio_hp_det)) {
-               tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
                snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
                                &tegra_wm8903_hp_jack);
                snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
@@ -226,9 +215,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
 static struct snd_soc_dai_link tegra_wm8903_dai = {
        .name = "WM8903",
        .stream_name = "WM8903 PCM",
-       .codec_name = "wm8903.0-001a",
-       .platform_name = "tegra20-i2s.0",
-       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "wm8903-hifi",
        .init = tegra_wm8903_init,
        .ops = &tegra_wm8903_ops,
@@ -257,96 +243,25 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_wm8903;
        struct tegra_wm8903 *machine;
-       struct tegra_wm8903_platform_data *pdata;
        int ret;
 
-       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
        machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
                               GFP_KERNEL);
        if (!machine) {
                dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
-       pdata = &machine->pdata;
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
 
-       if (pdev->dev.platform_data) {
-               memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
-       } else if (np) {
-               pdata->gpio_spkr_en = of_get_named_gpio(np,
-                                               "nvidia,spkr-en-gpios", 0);
-               if (pdata->gpio_spkr_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_hp_mute = of_get_named_gpio(np,
-                                               "nvidia,hp-mute-gpios", 0);
-               if (pdata->gpio_hp_mute == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_hp_det = of_get_named_gpio(np,
-                                               "nvidia,hp-det-gpios", 0);
-               if (pdata->gpio_hp_det == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_int_mic_en = of_get_named_gpio(np,
-                                               "nvidia,int-mic-en-gpios", 0);
-               if (pdata->gpio_int_mic_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_ext_mic_en = of_get_named_gpio(np,
-                                               "nvidia,ext-mic-en-gpios", 0);
-               if (pdata->gpio_ext_mic_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-       }
-
-       if (np) {
-               ret = snd_soc_of_parse_card_name(card, "nvidia,model");
-               if (ret)
-                       goto err;
-
-               ret = snd_soc_of_parse_audio_routing(card,
-                                                    "nvidia,audio-routing");
-               if (ret)
-                       goto err;
-
-               tegra_wm8903_dai.codec_name = NULL;
-               tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
-                               "nvidia,audio-codec", 0);
-               if (!tegra_wm8903_dai.codec_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,audio-codec' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               tegra_wm8903_dai.cpu_dai_name = NULL;
-               tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
-                               "nvidia,i2s-controller", 0);
-               if (!tegra_wm8903_dai.cpu_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,i2s-controller' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               tegra_wm8903_dai.platform_name = NULL;
-               tegra_wm8903_dai.platform_of_node =
-                                       tegra_wm8903_dai.cpu_of_node;
-       } else {
-               card->dapm_routes = harmony_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-       }
-
-       if (gpio_is_valid(pdata->gpio_spkr_en)) {
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en,
+       machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios",
+                                                 0);
+       if (machine->gpio_spkr_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_spkr_en)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_spkr_en,
                                            GPIOF_OUT_INIT_LOW, "spkr_en");
                if (ret) {
                        dev_err(card->dev, "cannot get spkr_en gpio\n");
@@ -354,8 +269,12 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_hp_mute)) {
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute,
+       machine->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios",
+                                                 0);
+       if (machine->gpio_hp_mute == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_hp_mute)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_mute,
                                            GPIOF_OUT_INIT_HIGH, "hp_mute");
                if (ret) {
                        dev_err(card->dev, "cannot get hp_mute gpio\n");
@@ -363,9 +282,18 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_int_mic_en = of_get_named_gpio(np,
+                                               "nvidia,int-mic-en-gpios", 0);
+       if (machine->gpio_int_mic_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_int_mic_en)) {
                /* Disable int mic; enable signal is active-high */
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en,
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           machine->gpio_int_mic_en,
                                            GPIOF_OUT_INIT_LOW, "int_mic_en");
                if (ret) {
                        dev_err(card->dev, "cannot get int_mic_en gpio\n");
@@ -373,9 +301,14 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+       machine->gpio_ext_mic_en = of_get_named_gpio(np,
+                                               "nvidia,ext-mic-en-gpios", 0);
+       if (machine->gpio_ext_mic_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_ext_mic_en)) {
                /* Enable ext mic; enable signal is active-low */
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en,
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           machine->gpio_ext_mic_en,
                                            GPIOF_OUT_INIT_LOW, "ext_mic_en");
                if (ret) {
                        dev_err(card->dev, "cannot get ext_mic_en gpio\n");
@@ -383,6 +316,34 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
+                                               "nvidia,audio-codec", 0);
+       if (!tegra_wm8903_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_wm8903_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8903_dai.platform_of_node = tegra_wm8903_dai.cpu_of_node;
+
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
                goto err;
index 68d4240..5e11963 100644 (file)
@@ -55,7 +55,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link tegra_wm9712_dai = {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "tegra-ac97-pcm",
+       .cpu_dai_name = "tegra20-ac97",
        .codec_dai_name = "wm9712-hifi",
        .codec_name = "wm9712-codec",
        .init = tegra_wm9712_init,
@@ -79,11 +79,6 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
        struct tegra_wm9712 *machine;
        int ret;
 
-       if (!pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
        machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712),
                               GFP_KERNEL);
        if (!machine) {
index 7fcf6c2..05c68aa 100644 (file)
@@ -97,9 +97,6 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = {
 static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .codec_name = "tlv320aic23-codec.2-001a",
-       .platform_name = "tegra20-i2s.0",
-       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .ops = &trimslice_asoc_ops,
        .dai_fmt = SND_SOC_DAIFMT_I2S |
@@ -122,6 +119,7 @@ static struct snd_soc_card snd_soc_trimslice = {
 
 static int tegra_snd_trimslice_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_trimslice;
        struct tegra_trimslice *trimslice;
        int ret;
@@ -130,44 +128,38 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
                                 GFP_KERNEL);
        if (!trimslice) {
                dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
-               ret = -ENOMEM;
+               return -ENOMEM;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, trimslice);
+
+       trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!trimslice_tlv320aic23_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
                goto err;
        }
 
-       if (pdev->dev.of_node) {
-               trimslice_tlv320aic23_dai.codec_name = NULL;
-               trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,audio-codec", 0);
-               if (!trimslice_tlv320aic23_dai.codec_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,audio-codec' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
-               trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,i2s-controller", 0);
-               if (!trimslice_tlv320aic23_dai.cpu_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,i2s-controller' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               trimslice_tlv320aic23_dai.platform_name = NULL;
-               trimslice_tlv320aic23_dai.platform_of_node =
-                               trimslice_tlv320aic23_dai.cpu_of_node;
+       trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!trimslice_tlv320aic23_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
        }
 
+       trimslice_tlv320aic23_dai.platform_of_node =
+                       trimslice_tlv320aic23_dai.cpu_of_node;
+
        ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
        if (ret)
                goto err;
 
-       card->dev = &pdev->dev;
-       platform_set_drvdata(pdev, card);
-       snd_soc_card_set_drvdata(card, trimslice);
-
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
index 16ab696..8a28403 100644 (file)
@@ -170,6 +170,10 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
        },
 };
 
+static const struct snd_soc_component_driver txx9aclc_ac97_component = {
+       .name           = "txx9aclc-ac97",
+};
+
 static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 {
        struct txx9aclc_plat_drvdata *drvdata;
@@ -205,12 +209,13 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
+       return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
+                                         &txx9aclc_ac97_dai, 1);
 }
 
 static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 94a3e57..f1e8a5e 100644 (file)
@@ -768,6 +768,11 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
        },
 };
 
+static const struct snd_soc_component_driver ux500_msp_component = {
+       .name           = "ux500-msp",
+};
+
+
 static int ux500_msp_drv_probe(struct platform_device *pdev)
 {
        struct ux500_msp_i2s_drvdata *drvdata;
@@ -825,8 +830,8 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        }
        dev_set_drvdata(&pdev->dev, drvdata);
 
-       ret = snd_soc_register_dai(&pdev->dev,
-                               &ux500_msp_dai_drv[drvdata->msp->id]);
+       ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
+                                        &ux500_msp_dai_drv[drvdata->msp->id], 1);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
                        __func__, drvdata->msp->id);
@@ -844,7 +849,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        return 0;
 
 err_reg_plat:
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+       snd_soc_unregister_component(&pdev->dev);
 err_init_msp:
        clk_put(drvdata->clk);
 err_clk:
@@ -861,7 +866,7 @@ static int ux500_msp_drv_remove(struct platform_device *pdev)
 
        ux500_pcm_unregister_platform(pdev);
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+       snd_soc_unregister_component(&pdev->dev);
 
        devm_regulator_put(drvdata->reg_vape);
        prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
index 9c778d9..f531043 100644 (file)
 #define FRAME_PER_8_SLOTS                              138
 #define FRAME_PER_16_SLOTS                             277
 
-#ifndef CONFIG_SND_SOC_UX500_AB5500
 #define UX500_MSP_INTERNAL_CLOCK_FREQ  40000000
 #define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
-#else
-#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
-#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
-#endif
 
 #define UX500_MSP_MIN_CHANNELS         1
 #define UX500_MSP_MAX_CHANNELS         8
index bb23009..359753f 100644 (file)
@@ -352,7 +352,9 @@ static struct sound_unit *chains[SOUND_STEP];
  *      @dev: device pointer
  *
  *     Allocate a special sound device by minor number from the sound
- *     subsystem. The allocated number is returned on success. On failure
+ *     subsystem.
+ *
+ *     Return: The allocated number is returned on success. On failure,
  *     a negative error code is returned.
  */
  
@@ -436,8 +438,10 @@ EXPORT_SYMBOL(register_sound_special);
  *     @dev: Unit number to allocate
  *
  *     Allocate a mixer device. Unit is the number of the mixer requested.
- *     Pass -1 to request the next free mixer unit. On success the allocated
- *     number is returned, on failure a negative error code is returned.
+ *     Pass -1 to request the next free mixer unit.
+ *
+ *     Return: On success, the allocated number is returned. On failure,
+ *     a negative error code is returned.
  */
 
 int register_sound_mixer(const struct file_operations *fops, int dev)
@@ -454,8 +458,10 @@ EXPORT_SYMBOL(register_sound_mixer);
  *     @dev: Unit number to allocate
  *
  *     Allocate a midi device. Unit is the number of the midi device requested.
- *     Pass -1 to request the next free midi unit. On success the allocated
- *     number is returned, on failure a negative error code is returned.
+ *     Pass -1 to request the next free midi unit.
+ *
+ *     Return: On success, the allocated number is returned. On failure,
+ *     a negative error code is returned.
  */
 
 int register_sound_midi(const struct file_operations *fops, int dev)
@@ -477,11 +483,13 @@ EXPORT_SYMBOL(register_sound_midi);
  *     @dev: Unit number to allocate
  *
  *     Allocate a DSP device. Unit is the number of the DSP requested.
- *     Pass -1 to request the next free DSP unit. On success the allocated
- *     number is returned, on failure a negative error code is returned.
+ *     Pass -1 to request the next free DSP unit.
  *
  *     This function allocates both the audio and dsp device entries together
  *     and will always allocate them as a matching pair - eg dsp3/audio3
+ *
+ *     Return: On success, the allocated number is returned. On failure,
+ *     a negative error code is returned.
  */
 
 int register_sound_dsp(const struct file_operations *fops, int dev)
index 4dd60d8..a1a24b9 100644 (file)
@@ -1075,10 +1075,11 @@ out:
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
+#ifdef CONFIG_PM_SLEEP
+
+static int snd_at73c213_suspend(struct device *dev)
 {
-       struct snd_card *card = dev_get_drvdata(&spi->dev);
+       struct snd_card *card = dev_get_drvdata(dev);
        struct snd_at73c213 *chip = card->private_data;
 
        ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
@@ -1087,9 +1088,9 @@ static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
        return 0;
 }
 
-static int snd_at73c213_resume(struct spi_device *spi)
+static int snd_at73c213_resume(struct device *dev)
 {
-       struct snd_card *card = dev_get_drvdata(&spi->dev);
+       struct snd_card *card = dev_get_drvdata(dev);
        struct snd_at73c213 *chip = card->private_data;
 
        clk_enable(chip->board->dac_clk);
@@ -1097,18 +1098,21 @@ static int snd_at73c213_resume(struct spi_device *spi)
 
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend,
+               snd_at73c213_resume);
+#define AT73C213_PM_OPS (&at73c213_pm_ops)
+
 #else
-#define snd_at73c213_suspend NULL
-#define snd_at73c213_resume NULL
+#define AT73C213_PM_OPS NULL
 #endif
 
 static struct spi_driver at73c213_driver = {
        .driver         = {
                .name   = "at73c213",
+               .pm     = AT73C213_PM_OPS,
        },
        .probe          = snd_at73c213_probe,
-       .suspend        = snd_at73c213_suspend,
-       .resume         = snd_at73c213_resume,
        .remove         = snd_at73c213_remove,
 };
 
index fde9a7a..67330af 100644 (file)
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -39,8 +40,8 @@
 #define ENDPOINT_CAPTURE       2
 #define ENDPOINT_PLAYBACK      6
 
-#define MAKE_CHECKBYTE(dev,stream,i) \
-       (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
+#define MAKE_CHECKBYTE(cdev,stream,i) \
+       (stream << 1) | (~(i / (cdev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
 
 static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
        .info           = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
@@ -60,32 +61,32 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
 };
 
 static void
-activate_substream(struct snd_usb_caiaqdev *dev,
+activate_substream(struct snd_usb_caiaqdev *cdev,
                   struct snd_pcm_substream *sub)
 {
-       spin_lock(&dev->spinlock);
+       spin_lock(&cdev->spinlock);
 
        if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dev->sub_playback[sub->number] = sub;
+               cdev->sub_playback[sub->number] = sub;
        else
-               dev->sub_capture[sub->number] = sub;
+               cdev->sub_capture[sub->number] = sub;
 
-       spin_unlock(&dev->spinlock);
+       spin_unlock(&cdev->spinlock);
 }
 
 static void
-deactivate_substream(struct snd_usb_caiaqdev *dev,
+deactivate_substream(struct snd_usb_caiaqdev *cdev,
                     struct snd_pcm_substream *sub)
 {
        unsigned long flags;
-       spin_lock_irqsave(&dev->spinlock, flags);
+       spin_lock_irqsave(&cdev->spinlock, flags);
 
        if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dev->sub_playback[sub->number] = NULL;
+               cdev->sub_playback[sub->number] = NULL;
        else
-               dev->sub_capture[sub->number] = NULL;
+               cdev->sub_capture[sub->number] = NULL;
 
-       spin_unlock_irqrestore(&dev->spinlock, flags);
+       spin_unlock_irqrestore(&cdev->spinlock, flags);
 }
 
 static int
@@ -98,28 +99,30 @@ all_substreams_zero(struct snd_pcm_substream **subs)
        return 1;
 }
 
-static int stream_start(struct snd_usb_caiaqdev *dev)
+static int stream_start(struct snd_usb_caiaqdev *cdev)
 {
        int i, ret;
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       debug("%s(%p)\n", __func__, dev);
+       dev_dbg(dev, "%s(%p)\n", __func__, cdev);
 
-       if (dev->streaming)
+       if (cdev->streaming)
                return -EINVAL;
 
-       memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
-       memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
-       dev->input_panic = 0;
-       dev->output_panic = 0;
-       dev->first_packet = 4;
-       dev->streaming = 1;
-       dev->warned = 0;
+       memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
+       memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
+       cdev->input_panic = 0;
+       cdev->output_panic = 0;
+       cdev->first_packet = 4;
+       cdev->streaming = 1;
+       cdev->warned = 0;
 
        for (i = 0; i < N_URBS; i++) {
-               ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC);
+               ret = usb_submit_urb(cdev->data_urbs_in[i], GFP_ATOMIC);
                if (ret) {
-                       log("unable to trigger read #%d! (ret %d)\n", i, ret);
-                       dev->streaming = 0;
+                       dev_err(dev, "unable to trigger read #%d! (ret %d)\n",
+                               i, ret);
+                       cdev->streaming = 0;
                        return -EPIPE;
                }
        }
@@ -127,46 +130,51 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
        return 0;
 }
 
-static void stream_stop(struct snd_usb_caiaqdev *dev)
+static void stream_stop(struct snd_usb_caiaqdev *cdev)
 {
        int i;
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       debug("%s(%p)\n", __func__, dev);
-       if (!dev->streaming)
+       dev_dbg(dev, "%s(%p)\n", __func__, cdev);
+       if (!cdev->streaming)
                return;
 
-       dev->streaming = 0;
+       cdev->streaming = 0;
 
        for (i = 0; i < N_URBS; i++) {
-               usb_kill_urb(dev->data_urbs_in[i]);
+               usb_kill_urb(cdev->data_urbs_in[i]);
 
-               if (test_bit(i, &dev->outurb_active_mask))
-                       usb_kill_urb(dev->data_urbs_out[i]);
+               if (test_bit(i, &cdev->outurb_active_mask))
+                       usb_kill_urb(cdev->data_urbs_out[i]);
        }
 
-       dev->outurb_active_mask = 0;
+       cdev->outurb_active_mask = 0;
 }
 
 static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
 {
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
-       debug("%s(%p)\n", __func__, substream);
-       substream->runtime->hw = dev->pcm_info;
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
+       struct device *dev = caiaqdev_to_dev(cdev);
+
+       dev_dbg(dev, "%s(%p)\n", __func__, substream);
+       substream->runtime->hw = cdev->pcm_info;
        snd_pcm_limit_hw_rates(substream->runtime);
+
        return 0;
 }
 
 static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 {
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       debug("%s(%p)\n", __func__, substream);
-       if (all_substreams_zero(dev->sub_playback) &&
-           all_substreams_zero(dev->sub_capture)) {
+       dev_dbg(dev, "%s(%p)\n", __func__, substream);
+       if (all_substreams_zero(cdev->sub_playback) &&
+           all_substreams_zero(cdev->sub_capture)) {
                /* when the last client has stopped streaming,
                 * all sample rates are allowed again */
-               stream_stop(dev);
-               dev->pcm_info.rates = dev->samplerates;
+               stream_stop(cdev);
+               cdev->pcm_info.rates = cdev->samplerates;
        }
 
        return 0;
@@ -175,15 +183,13 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
                                       struct snd_pcm_hw_params *hw_params)
 {
-       debug("%s(%p)\n", __func__, sub);
        return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
 }
 
 static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 {
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
-       debug("%s(%p)\n", __func__, sub);
-       deactivate_substream(dev, sub);
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
+       deactivate_substream(cdev, sub);
        return snd_pcm_lib_free_pages(sub);
 }
 
@@ -199,15 +205,16 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 {
        int bytes_per_sample, bpp, ret, i;
        int index = substream->number;
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       debug("%s(%p)\n", __func__, substream);
+       dev_dbg(dev, "%s(%p)\n", __func__, substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                int out_pos;
 
-               switch (dev->spec.data_alignment) {
+               switch (cdev->spec.data_alignment) {
                case 0:
                case 2:
                        out_pos = BYTES_PER_SAMPLE + 1;
@@ -218,12 +225,12 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
                        break;
                }
 
-               dev->period_out_count[index] = out_pos;
-               dev->audio_out_buf_pos[index] = out_pos;
+               cdev->period_out_count[index] = out_pos;
+               cdev->audio_out_buf_pos[index] = out_pos;
        } else {
                int in_pos;
 
-               switch (dev->spec.data_alignment) {
+               switch (cdev->spec.data_alignment) {
                case 0:
                        in_pos = BYTES_PER_SAMPLE + 2;
                        break;
@@ -236,44 +243,44 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
                        break;
                }
 
-               dev->period_in_count[index] = in_pos;
-               dev->audio_in_buf_pos[index] = in_pos;
+               cdev->period_in_count[index] = in_pos;
+               cdev->audio_in_buf_pos[index] = in_pos;
        }
 
-       if (dev->streaming)
+       if (cdev->streaming)
                return 0;
 
        /* the first client that opens a stream defines the sample rate
         * setting for all subsequent calls, until the last client closed. */
        for (i=0; i < ARRAY_SIZE(rates); i++)
                if (runtime->rate == rates[i])
-                       dev->pcm_info.rates = 1 << i;
+                       cdev->pcm_info.rates = 1 << i;
 
        snd_pcm_limit_hw_rates(runtime);
 
        bytes_per_sample = BYTES_PER_SAMPLE;
-       if (dev->spec.data_alignment >= 2)
+       if (cdev->spec.data_alignment >= 2)
                bytes_per_sample++;
 
        bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
-               * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams;
+               * bytes_per_sample * CHANNELS_PER_STREAM * cdev->n_streams;
 
        if (bpp > MAX_ENDPOINT_SIZE)
                bpp = MAX_ENDPOINT_SIZE;
 
-       ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate,
+       ret = snd_usb_caiaq_set_audio_params(cdev, runtime->rate,
                                             runtime->sample_bits, bpp);
        if (ret)
                return ret;
 
-       ret = stream_start(dev);
+       ret = stream_start(cdev);
        if (ret)
                return ret;
 
-       dev->output_running = 0;
-       wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ);
-       if (!dev->output_running) {
-               stream_stop(dev);
+       cdev->output_running = 0;
+       wait_event_timeout(cdev->prepare_wait_queue, cdev->output_running, HZ);
+       if (!cdev->output_running) {
+               stream_stop(cdev);
                return -EPIPE;
        }
 
@@ -282,18 +289,19 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
 {
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+       dev_dbg(dev, "%s(%p) cmd %d\n", __func__, sub, cmd);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               activate_substream(dev, sub);
+               activate_substream(cdev, sub);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               deactivate_substream(dev, sub);
+               deactivate_substream(cdev, sub);
                break;
        default:
                return -EINVAL;
@@ -306,25 +314,25 @@ static snd_pcm_uframes_t
 snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)
 {
        int index = sub->number;
-       struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+       struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
        snd_pcm_uframes_t ptr;
 
-       spin_lock(&dev->spinlock);
+       spin_lock(&cdev->spinlock);
 
-       if (dev->input_panic || dev->output_panic) {
+       if (cdev->input_panic || cdev->output_panic) {
                ptr = SNDRV_PCM_POS_XRUN;
                goto unlock;
        }
 
        if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
                ptr = bytes_to_frames(sub->runtime,
-                                       dev->audio_out_buf_pos[index]);
+                                       cdev->audio_out_buf_pos[index]);
        else
                ptr = bytes_to_frames(sub->runtime,
-                                       dev->audio_in_buf_pos[index]);
+                                       cdev->audio_in_buf_pos[index]);
 
 unlock:
-       spin_unlock(&dev->spinlock);
+       spin_unlock(&cdev->spinlock);
        return ptr;
 }
 
@@ -340,21 +348,21 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
        .pointer =      snd_usb_caiaq_pcm_pointer
 };
 
-static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
+static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
                                      struct snd_pcm_substream **subs)
 {
        int stream, pb, *cnt;
        struct snd_pcm_substream *sub;
 
-       for (stream = 0; stream < dev->n_streams; stream++) {
+       for (stream = 0; stream < cdev->n_streams; stream++) {
                sub = subs[stream];
                if (!sub)
                        continue;
 
                pb = snd_pcm_lib_period_bytes(sub);
                cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                                       &dev->period_out_count[stream] :
-                                       &dev->period_in_count[stream];
+                                       &cdev->period_out_count[stream] :
+                                       &cdev->period_in_count[stream];
 
                if (*cnt >= pb) {
                        snd_pcm_period_elapsed(sub);
@@ -363,7 +371,7 @@ static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
        }
 }
 
-static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode0(struct snd_usb_caiaqdev *cdev,
                              const struct urb *urb,
                              const struct usb_iso_packet_descriptor *iso)
 {
@@ -371,27 +379,27 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
        struct snd_pcm_substream *sub;
        int stream, i;
 
-       if (all_substreams_zero(dev->sub_capture))
+       if (all_substreams_zero(cdev->sub_capture))
                return;
 
        for (i = 0; i < iso->actual_length;) {
-               for (stream = 0; stream < dev->n_streams; stream++, i++) {
-                       sub = dev->sub_capture[stream];
+               for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+                       sub = cdev->sub_capture[stream];
                        if (sub) {
                                struct snd_pcm_runtime *rt = sub->runtime;
                                char *audio_buf = rt->dma_area;
                                int sz = frames_to_bytes(rt, rt->buffer_size);
-                               audio_buf[dev->audio_in_buf_pos[stream]++]
+                               audio_buf[cdev->audio_in_buf_pos[stream]++]
                                        = usb_buf[i];
-                               dev->period_in_count[stream]++;
-                               if (dev->audio_in_buf_pos[stream] == sz)
-                                       dev->audio_in_buf_pos[stream] = 0;
+                               cdev->period_in_count[stream]++;
+                               if (cdev->audio_in_buf_pos[stream] == sz)
+                                       cdev->audio_in_buf_pos[stream] = 0;
                        }
                }
        }
 }
 
-static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode2(struct snd_usb_caiaqdev *cdev,
                              const struct urb *urb,
                              const struct usb_iso_packet_descriptor *iso)
 {
@@ -401,48 +409,49 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
        int stream, i;
 
        for (i = 0; i < iso->actual_length;) {
-               if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
+               if (i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
                        for (stream = 0;
-                            stream < dev->n_streams;
+                            stream < cdev->n_streams;
                             stream++, i++) {
-                               if (dev->first_packet)
+                               if (cdev->first_packet)
                                        continue;
 
-                               check_byte = MAKE_CHECKBYTE(dev, stream, i);
+                               check_byte = MAKE_CHECKBYTE(cdev, stream, i);
 
                                if ((usb_buf[i] & 0x3f) != check_byte)
-                                       dev->input_panic = 1;
+                                       cdev->input_panic = 1;
 
                                if (usb_buf[i] & 0x80)
-                                       dev->output_panic = 1;
+                                       cdev->output_panic = 1;
                        }
                }
-               dev->first_packet = 0;
+               cdev->first_packet = 0;
 
-               for (stream = 0; stream < dev->n_streams; stream++, i++) {
-                       sub = dev->sub_capture[stream];
-                       if (dev->input_panic)
+               for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+                       sub = cdev->sub_capture[stream];
+                       if (cdev->input_panic)
                                usb_buf[i] = 0;
 
                        if (sub) {
                                struct snd_pcm_runtime *rt = sub->runtime;
                                char *audio_buf = rt->dma_area;
                                int sz = frames_to_bytes(rt, rt->buffer_size);
-                               audio_buf[dev->audio_in_buf_pos[stream]++] =
+                               audio_buf[cdev->audio_in_buf_pos[stream]++] =
                                        usb_buf[i];
-                               dev->period_in_count[stream]++;
-                               if (dev->audio_in_buf_pos[stream] == sz)
-                                       dev->audio_in_buf_pos[stream] = 0;
+                               cdev->period_in_count[stream]++;
+                               if (cdev->audio_in_buf_pos[stream] == sz)
+                                       cdev->audio_in_buf_pos[stream] = 0;
                        }
                }
        }
 }
 
-static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *cdev,
                              const struct urb *urb,
                              const struct usb_iso_packet_descriptor *iso)
 {
        unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+       struct device *dev = caiaqdev_to_dev(cdev);
        int stream, i;
 
        /* paranoia check */
@@ -450,12 +459,12 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
                return;
 
        for (i = 0; i < iso->actual_length;) {
-               for (stream = 0; stream < dev->n_streams; stream++) {
-                       struct snd_pcm_substream *sub = dev->sub_capture[stream];
+               for (stream = 0; stream < cdev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = cdev->sub_capture[stream];
                        char *audio_buf = NULL;
                        int c, n, sz = 0;
 
-                       if (sub && !dev->input_panic) {
+                       if (sub && !cdev->input_panic) {
                                struct snd_pcm_runtime *rt = sub->runtime;
                                audio_buf = rt->dma_area;
                                sz = frames_to_bytes(rt, rt->buffer_size);
@@ -465,23 +474,23 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
                                /* 3 audio data bytes, followed by 1 check byte */
                                if (audio_buf) {
                                        for (n = 0; n < BYTES_PER_SAMPLE; n++) {
-                                               audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+                                               audio_buf[cdev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
 
-                                               if (dev->audio_in_buf_pos[stream] == sz)
-                                                       dev->audio_in_buf_pos[stream] = 0;
+                                               if (cdev->audio_in_buf_pos[stream] == sz)
+                                                       cdev->audio_in_buf_pos[stream] = 0;
                                        }
 
-                                       dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+                                       cdev->period_in_count[stream] += BYTES_PER_SAMPLE;
                                }
 
                                i += BYTES_PER_SAMPLE;
 
                                if (usb_buf[i] != ((stream << 1) | c) &&
-                                   !dev->first_packet) {
-                                       if (!dev->input_panic)
-                                               printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
-                                                       ((stream << 1) | c), usb_buf[i], c, stream, i);
-                                       dev->input_panic = 1;
+                                   !cdev->first_packet) {
+                                       if (!cdev->input_panic)
+                                               dev_warn(dev, " EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+                                                        ((stream << 1) | c), usb_buf[i], c, stream, i);
+                                       cdev->input_panic = 1;
                                }
 
                                i++;
@@ -489,41 +498,43 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
                }
        }
 
-       if (dev->first_packet > 0)
-               dev->first_packet--;
+       if (cdev->first_packet > 0)
+               cdev->first_packet--;
 }
 
-static void read_in_urb(struct snd_usb_caiaqdev *dev,
+static void read_in_urb(struct snd_usb_caiaqdev *cdev,
                        const struct urb *urb,
                        const struct usb_iso_packet_descriptor *iso)
 {
-       if (!dev->streaming)
+       struct device *dev = caiaqdev_to_dev(cdev);
+
+       if (!cdev->streaming)
                return;
 
-       if (iso->actual_length < dev->bpp)
+       if (iso->actual_length < cdev->bpp)
                return;
 
-       switch (dev->spec.data_alignment) {
+       switch (cdev->spec.data_alignment) {
        case 0:
-               read_in_urb_mode0(dev, urb, iso);
+               read_in_urb_mode0(cdev, urb, iso);
                break;
        case 2:
-               read_in_urb_mode2(dev, urb, iso);
+               read_in_urb_mode2(cdev, urb, iso);
                break;
        case 3:
-               read_in_urb_mode3(dev, urb, iso);
+               read_in_urb_mode3(cdev, urb, iso);
                break;
        }
 
-       if ((dev->input_panic || dev->output_panic) && !dev->warned) {
-               debug("streaming error detected %s %s\n",
-                               dev->input_panic ? "(input)" : "",
-                               dev->output_panic ? "(output)" : "");
-               dev->warned = 1;
+       if ((cdev->input_panic || cdev->output_panic) && !cdev->warned) {
+               dev_warn(dev, "streaming error detected %s %s\n",
+                               cdev->input_panic ? "(input)" : "",
+                               cdev->output_panic ? "(output)" : "");
+               cdev->warned = 1;
        }
 }
 
-static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *cdev,
                                struct urb *urb,
                                const struct usb_iso_packet_descriptor *iso)
 {
@@ -532,32 +543,32 @@ static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
        int stream, i;
 
        for (i = 0; i < iso->length;) {
-               for (stream = 0; stream < dev->n_streams; stream++, i++) {
-                       sub = dev->sub_playback[stream];
+               for (stream = 0; stream < cdev->n_streams; stream++, i++) {
+                       sub = cdev->sub_playback[stream];
                        if (sub) {
                                struct snd_pcm_runtime *rt = sub->runtime;
                                char *audio_buf = rt->dma_area;
                                int sz = frames_to_bytes(rt, rt->buffer_size);
                                usb_buf[i] =
-                                       audio_buf[dev->audio_out_buf_pos[stream]];
-                               dev->period_out_count[stream]++;
-                               dev->audio_out_buf_pos[stream]++;
-                               if (dev->audio_out_buf_pos[stream] == sz)
-                                       dev->audio_out_buf_pos[stream] = 0;
+                                       audio_buf[cdev->audio_out_buf_pos[stream]];
+                               cdev->period_out_count[stream]++;
+                               cdev->audio_out_buf_pos[stream]++;
+                               if (cdev->audio_out_buf_pos[stream] == sz)
+                                       cdev->audio_out_buf_pos[stream] = 0;
                        } else
                                usb_buf[i] = 0;
                }
 
                /* fill in the check bytes */
-               if (dev->spec.data_alignment == 2 &&
-                   i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
-                       (dev->n_streams * CHANNELS_PER_STREAM))
-                       for (stream = 0; stream < dev->n_streams; stream++, i++)
-                               usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+               if (cdev->spec.data_alignment == 2 &&
+                   i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) ==
+                       (cdev->n_streams * CHANNELS_PER_STREAM))
+                       for (stream = 0; stream < cdev->n_streams; stream++, i++)
+                               usb_buf[i] = MAKE_CHECKBYTE(cdev, stream, i);
        }
 }
 
-static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *cdev,
                                struct urb *urb,
                                const struct usb_iso_packet_descriptor *iso)
 {
@@ -565,8 +576,8 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
        int stream, i;
 
        for (i = 0; i < iso->length;) {
-               for (stream = 0; stream < dev->n_streams; stream++) {
-                       struct snd_pcm_substream *sub = dev->sub_playback[stream];
+               for (stream = 0; stream < cdev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = cdev->sub_playback[stream];
                        char *audio_buf = NULL;
                        int c, n, sz = 0;
 
@@ -579,17 +590,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
                        for (c = 0; c < CHANNELS_PER_STREAM; c++) {
                                for (n = 0; n < BYTES_PER_SAMPLE; n++) {
                                        if (audio_buf) {
-                                               usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+                                               usb_buf[i+n] = audio_buf[cdev->audio_out_buf_pos[stream]++];
 
-                                               if (dev->audio_out_buf_pos[stream] == sz)
-                                                       dev->audio_out_buf_pos[stream] = 0;
+                                               if (cdev->audio_out_buf_pos[stream] == sz)
+                                                       cdev->audio_out_buf_pos[stream] = 0;
                                        } else {
                                                usb_buf[i+n] = 0;
                                        }
                                }
 
                                if (audio_buf)
-                                       dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+                                       cdev->period_out_count[stream] += BYTES_PER_SAMPLE;
 
                                i += BYTES_PER_SAMPLE;
 
@@ -600,17 +611,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
        }
 }
 
-static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+static inline void fill_out_urb(struct snd_usb_caiaqdev *cdev,
                                struct urb *urb,
                                const struct usb_iso_packet_descriptor *iso)
 {
-       switch (dev->spec.data_alignment) {
+       switch (cdev->spec.data_alignment) {
        case 0:
        case 2:
-               fill_out_urb_mode_0(dev, urb, iso);
+               fill_out_urb_mode_0(cdev, urb, iso);
                break;
        case 3:
-               fill_out_urb_mode_3(dev, urb, iso);
+               fill_out_urb_mode_3(cdev, urb, iso);
                break;
        }
 }
@@ -618,7 +629,8 @@ static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
 static void read_completed(struct urb *urb)
 {
        struct snd_usb_caiaq_cb_info *info = urb->context;
-       struct snd_usb_caiaqdev *dev;
+       struct snd_usb_caiaqdev *cdev;
+       struct device *dev;
        struct urb *out = NULL;
        int i, frame, len, send_it = 0, outframe = 0;
        size_t offset = 0;
@@ -626,20 +638,21 @@ static void read_completed(struct urb *urb)
        if (urb->status || !info)
                return;
 
-       dev = info->dev;
+       cdev = info->cdev;
+       dev = caiaqdev_to_dev(cdev);
 
-       if (!dev->streaming)
+       if (!cdev->streaming)
                return;
 
        /* find an unused output urb that is unused */
        for (i = 0; i < N_URBS; i++)
-               if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) {
-                       out = dev->data_urbs_out[i];
+               if (test_and_set_bit(i, &cdev->outurb_active_mask) == 0) {
+                       out = cdev->data_urbs_out[i];
                        break;
                }
 
        if (!out) {
-               log("Unable to find an output urb to use\n");
+               dev_err(dev, "Unable to find an output urb to use\n");
                goto requeue;
        }
 
@@ -656,12 +669,12 @@ static void read_completed(struct urb *urb)
                offset += len;
 
                if (len > 0) {
-                       spin_lock(&dev->spinlock);
-                       fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
-                       read_in_urb(dev, urb, &urb->iso_frame_desc[frame]);
-                       spin_unlock(&dev->spinlock);
-                       check_for_elapsed_periods(dev, dev->sub_playback);
-                       check_for_elapsed_periods(dev, dev->sub_capture);
+                       spin_lock(&cdev->spinlock);
+                       fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
+                       read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
+                       spin_unlock(&cdev->spinlock);
+                       check_for_elapsed_periods(cdev, cdev->sub_playback);
+                       check_for_elapsed_periods(cdev, cdev->sub_capture);
                        send_it = 1;
                }
 
@@ -674,7 +687,7 @@ static void read_completed(struct urb *urb)
                usb_submit_urb(out, GFP_ATOMIC);
        } else {
                struct snd_usb_caiaq_cb_info *oinfo = out->context;
-               clear_bit(oinfo->index, &dev->outurb_active_mask);
+               clear_bit(oinfo->index, &cdev->outurb_active_mask);
        }
 
 requeue:
@@ -693,21 +706,22 @@ requeue:
 static void write_completed(struct urb *urb)
 {
        struct snd_usb_caiaq_cb_info *info = urb->context;
-       struct snd_usb_caiaqdev *dev = info->dev;
+       struct snd_usb_caiaqdev *cdev = info->cdev;
 
-       if (!dev->output_running) {
-               dev->output_running = 1;
-               wake_up(&dev->prepare_wait_queue);
+       if (!cdev->output_running) {
+               cdev->output_running = 1;
+               wake_up(&cdev->prepare_wait_queue);
        }
 
-       clear_bit(info->index, &dev->outurb_active_mask);
+       clear_bit(info->index, &cdev->outurb_active_mask);
 }
 
-static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
+static struct urb **alloc_urbs(struct snd_usb_caiaqdev *cdev, int dir, int *ret)
 {
        int i, frame;
        struct urb **urbs;
-       struct usb_device *usb_dev = dev->chip.dev;
+       struct usb_device *usb_dev = cdev->chip.dev;
+       struct device *dev = caiaqdev_to_dev(cdev);
        unsigned int pipe;
 
        pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -716,7 +730,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
 
        urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL);
        if (!urbs) {
-               log("unable to kmalloc() urbs, OOM!?\n");
+               dev_err(dev, "unable to kmalloc() urbs, OOM!?\n");
                *ret = -ENOMEM;
                return NULL;
        }
@@ -724,7 +738,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
        for (i = 0; i < N_URBS; i++) {
                urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL);
                if (!urbs[i]) {
-                       log("unable to usb_alloc_urb(), OOM!?\n");
+                       dev_err(dev, "unable to usb_alloc_urb(), OOM!?\n");
                        *ret = -ENOMEM;
                        return urbs;
                }
@@ -732,7 +746,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
                urbs[i]->transfer_buffer =
                        kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);
                if (!urbs[i]->transfer_buffer) {
-                       log("unable to kmalloc() transfer buffer, OOM!?\n");
+                       dev_err(dev, "unable to kmalloc() transfer buffer, OOM!?\n");
                        *ret = -ENOMEM;
                        return urbs;
                }
@@ -749,7 +763,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
                urbs[i]->pipe = pipe;
                urbs[i]->transfer_buffer_length = FRAMES_PER_URB
                                                * BYTES_PER_FRAME;
-               urbs[i]->context = &dev->data_cb_info[i];
+               urbs[i]->context = &cdev->data_cb_info[i];
                urbs[i]->interval = 1;
                urbs[i]->transfer_flags = URB_ISO_ASAP;
                urbs[i]->number_of_packets = FRAMES_PER_URB;
@@ -780,110 +794,113 @@ static void free_urbs(struct urb **urbs)
        kfree(urbs);
 }
 
-int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
 {
        int i, ret;
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       dev->n_audio_in  = max(dev->spec.num_analog_audio_in,
-                              dev->spec.num_digital_audio_in) /
+       cdev->n_audio_in  = max(cdev->spec.num_analog_audio_in,
+                              cdev->spec.num_digital_audio_in) /
                                CHANNELS_PER_STREAM;
-       dev->n_audio_out = max(dev->spec.num_analog_audio_out,
-                              dev->spec.num_digital_audio_out) /
+       cdev->n_audio_out = max(cdev->spec.num_analog_audio_out,
+                              cdev->spec.num_digital_audio_out) /
                                CHANNELS_PER_STREAM;
-       dev->n_streams = max(dev->n_audio_in, dev->n_audio_out);
+       cdev->n_streams = max(cdev->n_audio_in, cdev->n_audio_out);
 
-       debug("dev->n_audio_in = %d\n", dev->n_audio_in);
-       debug("dev->n_audio_out = %d\n", dev->n_audio_out);
-       debug("dev->n_streams = %d\n", dev->n_streams);
+       dev_dbg(dev, "cdev->n_audio_in = %d\n", cdev->n_audio_in);
+       dev_dbg(dev, "cdev->n_audio_out = %d\n", cdev->n_audio_out);
+       dev_dbg(dev, "cdev->n_streams = %d\n", cdev->n_streams);
 
-       if (dev->n_streams > MAX_STREAMS) {
-               log("unable to initialize device, too many streams.\n");
+       if (cdev->n_streams > MAX_STREAMS) {
+               dev_err(dev, "unable to initialize device, too many streams.\n");
                return -EINVAL;
        }
 
-       ret = snd_pcm_new(dev->chip.card, dev->product_name, 0,
-                       dev->n_audio_out, dev->n_audio_in, &dev->pcm);
+       ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0,
+                       cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);
 
        if (ret < 0) {
-               log("snd_pcm_new() returned %d\n", ret);
+               dev_err(dev, "snd_pcm_new() returned %d\n", ret);
                return ret;
        }
 
-       dev->pcm->private_data = dev;
-       strlcpy(dev->pcm->name, dev->product_name, sizeof(dev->pcm->name));
+       cdev->pcm->private_data = cdev;
+       strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
 
-       memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
-       memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
+       memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
+       memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
 
-       memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware,
+       memcpy(&cdev->pcm_info, &snd_usb_caiaq_pcm_hardware,
                        sizeof(snd_usb_caiaq_pcm_hardware));
 
        /* setup samplerates */
-       dev->samplerates = dev->pcm_info.rates;
-       switch (dev->chip.usb_id) {
+       cdev->samplerates = cdev->pcm_info.rates;
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
-               dev->samplerates |= SNDRV_PCM_RATE_192000;
+               cdev->samplerates |= SNDRV_PCM_RATE_192000;
                /* fall thru */
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2):
-               dev->samplerates |= SNDRV_PCM_RATE_88200;
+               cdev->samplerates |= SNDRV_PCM_RATE_88200;
                break;
        }
 
-       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+       snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                &snd_usb_caiaq_ops);
-       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
+       snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &snd_usb_caiaq_ops);
 
-       snd_pcm_lib_preallocate_pages_for_all(dev->pcm,
+       snd_pcm_lib_preallocate_pages_for_all(cdev->pcm,
                                        SNDRV_DMA_TYPE_CONTINUOUS,
                                        snd_dma_continuous_data(GFP_KERNEL),
                                        MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
 
-       dev->data_cb_info =
+       cdev->data_cb_info =
                kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
                                        GFP_KERNEL);
 
-       if (!dev->data_cb_info)
+       if (!cdev->data_cb_info)
                return -ENOMEM;
 
-       dev->outurb_active_mask = 0;
-       BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8));
+       cdev->outurb_active_mask = 0;
+       BUILD_BUG_ON(N_URBS > (sizeof(cdev->outurb_active_mask) * 8));
 
        for (i = 0; i < N_URBS; i++) {
-               dev->data_cb_info[i].dev = dev;
-               dev->data_cb_info[i].index = i;
+               cdev->data_cb_info[i].cdev = cdev;
+               cdev->data_cb_info[i].index = i;
        }
 
-       dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret);
+       cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret);
        if (ret < 0) {
-               kfree(dev->data_cb_info);
-               free_urbs(dev->data_urbs_in);
+               kfree(cdev->data_cb_info);
+               free_urbs(cdev->data_urbs_in);
                return ret;
        }
 
-       dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
+       cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
        if (ret < 0) {
-               kfree(dev->data_cb_info);
-               free_urbs(dev->data_urbs_in);
-               free_urbs(dev->data_urbs_out);
+               kfree(cdev->data_cb_info);
+               free_urbs(cdev->data_urbs_in);
+               free_urbs(cdev->data_urbs_out);
                return ret;
        }
 
        return 0;
 }
 
-void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev)
+void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
 {
-       debug("%s(%p)\n", __func__, dev);
-       stream_stop(dev);
-       free_urbs(dev->data_urbs_in);
-       free_urbs(dev->data_urbs_out);
-       kfree(dev->data_cb_info);
+       struct device *dev = caiaqdev_to_dev(cdev);
+
+       dev_dbg(dev, "%s(%p)\n", __func__, cdev);
+       stream_stop(cdev);
+       free_urbs(cdev->data_urbs_in);
+       free_urbs(cdev->data_urbs_out);
+       kfree(cdev->data_cb_info);
 }
 
index 8ab1f8d..bdf1553 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef CAIAQ_AUDIO_H
 #define CAIAQ_AUDIO_H
 
-int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev);
+int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev);
 
 #endif /* CAIAQ_AUDIO_H */
index adb8d03..ae6b50f 100644 (file)
@@ -17,6 +17,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <sound/control.h>
@@ -32,7 +33,7 @@ static int control_info(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_info *uinfo)
 {
        struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
        int is_intval = pos & CNT_INTVAL;
        int maxval = 63;
@@ -40,7 +41,7 @@ static int control_info(struct snd_kcontrol *kcontrol,
        uinfo->count = 1;
        pos &= ~CNT_INTVAL;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
                if (pos == 0) {
@@ -78,15 +79,15 @@ static int control_get(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
 
        if (pos & CNT_INTVAL)
                ucontrol->value.integer.value[0]
-                       = dev->control_state[pos & ~CNT_INTVAL];
+                       = cdev->control_state[pos & ~CNT_INTVAL];
        else
                ucontrol->value.integer.value[0]
-                       = !!(dev->control_state[pos / 8] & (1 << pos % 8));
+                       = !!(cdev->control_state[pos / 8] & (1 << pos % 8));
 
        return 0;
 }
@@ -95,43 +96,43 @@ static int control_put(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
-       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
        int v = ucontrol->value.integer.value[0];
        unsigned char cmd = EP1_CMD_WRITE_IO;
 
-       if (dev->chip.usb_id ==
+       if (cdev->chip.usb_id ==
                USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
                cmd = EP1_CMD_DIMM_LEDS;
 
        if (pos & CNT_INTVAL) {
                int i = pos & ~CNT_INTVAL;
 
-               dev->control_state[i] = v;
+               cdev->control_state[i] = v;
 
-               if (dev->chip.usb_id ==
+               if (cdev->chip.usb_id ==
                        USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
                        int actual_len;
 
-                       dev->ep8_out_buf[0] = i;
-                       dev->ep8_out_buf[1] = v;
+                       cdev->ep8_out_buf[0] = i;
+                       cdev->ep8_out_buf[1] = v;
 
-                       usb_bulk_msg(dev->chip.dev,
-                                    usb_sndbulkpipe(dev->chip.dev, 8),
-                                    dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+                       usb_bulk_msg(cdev->chip.dev,
+                                    usb_sndbulkpipe(cdev->chip.dev, 8),
+                                    cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
                                     &actual_len, 200);
                } else {
-                       snd_usb_caiaq_send_command(dev, cmd,
-                                       dev->control_state, sizeof(dev->control_state));
+                       snd_usb_caiaq_send_command(cdev, cmd,
+                                       cdev->control_state, sizeof(cdev->control_state));
                }
        } else {
                if (v)
-                       dev->control_state[pos / 8] |= 1 << (pos % 8);
+                       cdev->control_state[pos / 8] |= 1 << (pos % 8);
                else
-                       dev->control_state[pos / 8] &= ~(1 << (pos % 8));
+                       cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
 
-               snd_usb_caiaq_send_command(dev, cmd,
-                               dev->control_state, sizeof(dev->control_state));
+               snd_usb_caiaq_send_command(cdev, cmd,
+                               cdev->control_state, sizeof(cdev->control_state));
        }
 
        return 1;
@@ -490,7 +491,7 @@ static struct caiaq_controller kontrols4_controller[] = {
 };
 
 static int add_controls(struct caiaq_controller *c, int num,
-                       struct snd_usb_caiaqdev *dev)
+                       struct snd_usb_caiaqdev *cdev)
 {
        int i, ret;
        struct snd_kcontrol *kc;
@@ -498,8 +499,8 @@ static int add_controls(struct caiaq_controller *c, int num,
        for (i = 0; i < num; i++, c++) {
                kcontrol_template.name = c->name;
                kcontrol_template.private_value = c->index;
-               kc = snd_ctl_new1(&kcontrol_template, dev);
-               ret = snd_ctl_add(dev->chip.card, kc);
+               kc = snd_ctl_new1(&kcontrol_template, cdev);
+               ret = snd_ctl_add(cdev->chip.card, kc);
                if (ret < 0)
                        return ret;
        }
@@ -507,50 +508,50 @@ static int add_controls(struct caiaq_controller *c, int num,
        return 0;
 }
 
-int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
 {
        int ret = 0;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                ret = add_controls(ak1_controller,
-                       ARRAY_SIZE(ak1_controller), dev);
+                       ARRAY_SIZE(ak1_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
                ret = add_controls(rk2_controller,
-                       ARRAY_SIZE(rk2_controller), dev);
+                       ARRAY_SIZE(rk2_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
                ret = add_controls(rk3_controller,
-                       ARRAY_SIZE(rk3_controller), dev);
+                       ARRAY_SIZE(rk3_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
                ret = add_controls(kore_controller,
-                       ARRAY_SIZE(kore_controller), dev);
+                       ARRAY_SIZE(kore_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
                ret = add_controls(a8dj_controller,
-                       ARRAY_SIZE(a8dj_controller), dev);
+                       ARRAY_SIZE(a8dj_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
                ret = add_controls(a4dj_controller,
-                       ARRAY_SIZE(a4dj_controller), dev);
+                       ARRAY_SIZE(a4dj_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                ret = add_controls(kontrolx1_controller,
-                       ARRAY_SIZE(kontrolx1_controller), dev);
+                       ARRAY_SIZE(kontrolx1_controller), cdev);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                ret = add_controls(kontrols4_controller,
-                       ARRAY_SIZE(kontrols4_controller), dev);
+                       ARRAY_SIZE(kontrols4_controller), cdev);
                break;
        }
 
index 2e7ab1a..501c488 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef CAIAQ_CONTROL_H
 #define CAIAQ_CONTROL_H
 
-int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev);
+int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev);
 
 #endif /* CAIAQ_CONTROL_H */
index e4d6dbb..48b63cc 100644 (file)
@@ -20,6 +20,7 @@
 */
 
 #include <linux/moduleparam.h>
+#include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -158,67 +159,68 @@ static struct usb_device_id snd_usb_id_table[] = {
 static void usb_ep1_command_reply_dispatch (struct urb* urb)
 {
        int ret;
-       struct snd_usb_caiaqdev *dev = urb->context;
+       struct device *dev = &urb->dev->dev;
+       struct snd_usb_caiaqdev *cdev = urb->context;
        unsigned char *buf = urb->transfer_buffer;
 
-       if (urb->status || !dev) {
-               log("received EP1 urb->status = %i\n", urb->status);
+       if (urb->status || !cdev) {
+               dev_warn(dev, "received EP1 urb->status = %i\n", urb->status);
                return;
        }
 
        switch(buf[0]) {
        case EP1_CMD_GET_DEVICE_INFO:
-               memcpy(&dev->spec, buf+1, sizeof(struct caiaq_device_spec));
-               dev->spec.fw_version = le16_to_cpu(dev->spec.fw_version);
-               debug("device spec (firmware %d): audio: %d in, %d out, "
+               memcpy(&cdev->spec, buf+1, sizeof(struct caiaq_device_spec));
+               cdev->spec.fw_version = le16_to_cpu(cdev->spec.fw_version);
+               dev_dbg(dev, "device spec (firmware %d): audio: %d in, %d out, "
                        "MIDI: %d in, %d out, data alignment %d\n",
-                       dev->spec.fw_version,
-                       dev->spec.num_analog_audio_in,
-                       dev->spec.num_analog_audio_out,
-                       dev->spec.num_midi_in,
-                       dev->spec.num_midi_out,
-                       dev->spec.data_alignment);
-
-               dev->spec_received++;
-               wake_up(&dev->ep1_wait_queue);
+                       cdev->spec.fw_version,
+                       cdev->spec.num_analog_audio_in,
+                       cdev->spec.num_analog_audio_out,
+                       cdev->spec.num_midi_in,
+                       cdev->spec.num_midi_out,
+                       cdev->spec.data_alignment);
+
+               cdev->spec_received++;
+               wake_up(&cdev->ep1_wait_queue);
                break;
        case EP1_CMD_AUDIO_PARAMS:
-               dev->audio_parm_answer = buf[1];
-               wake_up(&dev->ep1_wait_queue);
+               cdev->audio_parm_answer = buf[1];
+               wake_up(&cdev->ep1_wait_queue);
                break;
        case EP1_CMD_MIDI_READ:
-               snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]);
+               snd_usb_caiaq_midi_handle_input(cdev, buf[1], buf + 3, buf[2]);
                break;
        case EP1_CMD_READ_IO:
-               if (dev->chip.usb_id ==
+               if (cdev->chip.usb_id ==
                        USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) {
-                       if (urb->actual_length > sizeof(dev->control_state))
-                               urb->actual_length = sizeof(dev->control_state);
-                       memcpy(dev->control_state, buf + 1, urb->actual_length);
-                       wake_up(&dev->ep1_wait_queue);
+                       if (urb->actual_length > sizeof(cdev->control_state))
+                               urb->actual_length = sizeof(cdev->control_state);
+                       memcpy(cdev->control_state, buf + 1, urb->actual_length);
+                       wake_up(&cdev->ep1_wait_queue);
                        break;
                }
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        case EP1_CMD_READ_ERP:
        case EP1_CMD_READ_ANALOG:
-               snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length);
+               snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length);
 #endif
                break;
        }
 
-       dev->ep1_in_urb.actual_length = 0;
-       ret = usb_submit_urb(&dev->ep1_in_urb, GFP_ATOMIC);
+       cdev->ep1_in_urb.actual_length = 0;
+       ret = usb_submit_urb(&cdev->ep1_in_urb, GFP_ATOMIC);
        if (ret < 0)
-               log("unable to submit urb. OOM!?\n");
+               dev_err(dev, "unable to submit urb. OOM!?\n");
 }
 
-int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
                               unsigned char command,
                               const unsigned char *buffer,
                               int len)
 {
        int actual_len;
-       struct usb_device *usb_dev = dev->chip.dev;
+       struct usb_device *usb_dev = cdev->chip.dev;
 
        if (!usb_dev)
                return -EIO;
@@ -227,18 +229,19 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
                len = EP1_BUFSIZE - 1;
 
        if (buffer && len > 0)
-               memcpy(dev->ep1_out_buf+1, buffer, len);
+               memcpy(cdev->ep1_out_buf+1, buffer, len);
 
-       dev->ep1_out_buf[0] = command;
+       cdev->ep1_out_buf[0] = command;
        return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1),
-                          dev->ep1_out_buf, len+1, &actual_len, 200);
+                          cdev->ep1_out_buf, len+1, &actual_len, 200);
 }
 
-int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev,
                                    int rate, int depth, int bpp)
 {
        int ret;
        char tmp[5];
+       struct device *dev = caiaqdev_to_dev(cdev);
 
        switch (rate) {
        case 44100:     tmp[0] = SAMPLERATE_44100;   break;
@@ -259,49 +262,50 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
        tmp[3] = bpp >> 8;
        tmp[4] = 1; /* packets per microframe */
 
-       debug("setting audio params: %d Hz, %d bits, %d bpp\n",
+       dev_dbg(dev, "setting audio params: %d Hz, %d bits, %d bpp\n",
                rate, depth, bpp);
 
-       dev->audio_parm_answer = -1;
-       ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS,
+       cdev->audio_parm_answer = -1;
+       ret = snd_usb_caiaq_send_command(cdev, EP1_CMD_AUDIO_PARAMS,
                                         tmp, sizeof(tmp));
 
        if (ret)
                return ret;
 
-       if (!wait_event_timeout(dev->ep1_wait_queue,
-           dev->audio_parm_answer >= 0, HZ))
+       if (!wait_event_timeout(cdev->ep1_wait_queue,
+           cdev->audio_parm_answer >= 0, HZ))
                return -EPIPE;
 
-       if (dev->audio_parm_answer != 1)
-               debug("unable to set the device's audio params\n");
+       if (cdev->audio_parm_answer != 1)
+               dev_dbg(dev, "unable to set the device's audio params\n");
        else
-               dev->bpp = bpp;
+               cdev->bpp = bpp;
 
-       return dev->audio_parm_answer == 1 ? 0 : -EINVAL;
+       return cdev->audio_parm_answer == 1 ? 0 : -EINVAL;
 }
 
-int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,
                               int digital, int analog, int erp)
 {
        char tmp[3] = { digital, analog, erp };
-       return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG,
+       return snd_usb_caiaq_send_command(cdev, EP1_CMD_AUTO_MSG,
                                          tmp, sizeof(tmp));
 }
 
-static void setup_card(struct snd_usb_caiaqdev *dev)
+static void setup_card(struct snd_usb_caiaqdev *cdev)
 {
        int ret;
        char val[4];
+       struct device *dev = caiaqdev_to_dev(cdev);
 
        /* device-specific startup specials */
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
                /* RigKontrol2 - display centered dash ('-') */
                val[0] = 0x00;
                val[1] = 0x00;
                val[2] = 0x01;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3);
+               snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 3);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
                /* RigKontrol2 - display two centered dashes ('--') */
@@ -309,69 +313,69 @@ static void setup_card(struct snd_usb_caiaqdev *dev)
                val[1] = 0x40;
                val[2] = 0x40;
                val[3] = 0x00;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4);
+               snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 4);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                /* Audio Kontrol 1 - make USB-LED stop blinking */
                val[0] = 0x00;
-               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1);
+               snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 1);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
                /* Audio 8 DJ - trigger read of current settings */
-               dev->control_state[0] = 0xff;
-               snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0);
-               snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0);
+               cdev->control_state[0] = 0xff;
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 0);
+               snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0);
 
-               if (!wait_event_timeout(dev->ep1_wait_queue,
-                                       dev->control_state[0] != 0xff, HZ))
+               if (!wait_event_timeout(cdev->ep1_wait_queue,
+                                       cdev->control_state[0] != 0xff, HZ))
                        return;
 
                /* fix up some defaults */
-               if ((dev->control_state[1] != 2) ||
-                   (dev->control_state[2] != 3) ||
-                   (dev->control_state[4] != 2)) {
-                       dev->control_state[1] = 2;
-                       dev->control_state[2] = 3;
-                       dev->control_state[4] = 2;
-                       snd_usb_caiaq_send_command(dev,
-                               EP1_CMD_WRITE_IO, dev->control_state, 6);
+               if ((cdev->control_state[1] != 2) ||
+                   (cdev->control_state[2] != 3) ||
+                   (cdev->control_state[4] != 2)) {
+                       cdev->control_state[1] = 2;
+                       cdev->control_state[2] = 3;
+                       cdev->control_state[4] = 2;
+                       snd_usb_caiaq_send_command(cdev,
+                               EP1_CMD_WRITE_IO, cdev->control_state, 6);
                }
 
                break;
        }
 
-       if (dev->spec.num_analog_audio_out +
-           dev->spec.num_analog_audio_in +
-           dev->spec.num_digital_audio_out +
-           dev->spec.num_digital_audio_in > 0) {
-               ret = snd_usb_caiaq_audio_init(dev);
+       if (cdev->spec.num_analog_audio_out +
+           cdev->spec.num_analog_audio_in +
+           cdev->spec.num_digital_audio_out +
+           cdev->spec.num_digital_audio_in > 0) {
+               ret = snd_usb_caiaq_audio_init(cdev);
                if (ret < 0)
-                       log("Unable to set up audio system (ret=%d)\n", ret);
+                       dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);
        }
 
-       if (dev->spec.num_midi_in +
-           dev->spec.num_midi_out > 0) {
-               ret = snd_usb_caiaq_midi_init(dev);
+       if (cdev->spec.num_midi_in +
+           cdev->spec.num_midi_out > 0) {
+               ret = snd_usb_caiaq_midi_init(cdev);
                if (ret < 0)
-                       log("Unable to set up MIDI system (ret=%d)\n", ret);
+                       dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);
        }
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
-       ret = snd_usb_caiaq_input_init(dev);
+       ret = snd_usb_caiaq_input_init(cdev);
        if (ret < 0)
-               log("Unable to set up input system (ret=%d)\n", ret);
+               dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
 #endif
 
        /* finally, register the card and all its sub-instances */
-       ret = snd_card_register(dev->chip.card);
+       ret = snd_card_register(cdev->chip.card);
        if (ret < 0) {
-               log("snd_card_register() returned %d\n", ret);
-               snd_card_free(dev->chip.card);
+               dev_err(dev, "snd_card_register() returned %d\n", ret);
+               snd_card_free(cdev->chip.card);
        }
 
-       ret = snd_usb_caiaq_control_init(dev);
+       ret = snd_usb_caiaq_control_init(cdev);
        if (ret < 0)
-               log("Unable to set up control system (ret=%d)\n", ret);
+               dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
 }
 
 static int create_card(struct usb_device *usb_dev,
@@ -381,7 +385,7 @@ static int create_card(struct usb_device *usb_dev,
        int devnum;
        int err;
        struct snd_card *card;
-       struct snd_usb_caiaqdev *dev;
+       struct snd_usb_caiaqdev *cdev;
 
        for (devnum = 0; devnum < SNDRV_CARDS; devnum++)
                if (enable[devnum] && !snd_card_used[devnum])
@@ -395,65 +399,66 @@ static int create_card(struct usb_device *usb_dev,
        if (err < 0)
                return err;
 
-       dev = caiaqdev(card);
-       dev->chip.dev = usb_dev;
-       dev->chip.card = card;
-       dev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
+       cdev = caiaqdev(card);
+       cdev->chip.dev = usb_dev;
+       cdev->chip.card = card;
+       cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
                                  le16_to_cpu(usb_dev->descriptor.idProduct));
-       spin_lock_init(&dev->spinlock);
+       spin_lock_init(&cdev->spinlock);
        snd_card_set_dev(card, &intf->dev);
 
        *cardp = card;
        return 0;
 }
 
-static int init_card(struct snd_usb_caiaqdev *dev)
+static int init_card(struct snd_usb_caiaqdev *cdev)
 {
        char *c, usbpath[32];
-       struct usb_device *usb_dev = dev->chip.dev;
-       struct snd_card *card = dev->chip.card;
+       struct usb_device *usb_dev = cdev->chip.dev;
+       struct snd_card *card = cdev->chip.card;
+       struct device *dev = caiaqdev_to_dev(cdev);
        int err, len;
 
        if (usb_set_interface(usb_dev, 0, 1) != 0) {
-               log("can't set alt interface.\n");
+               dev_err(dev, "can't set alt interface.\n");
                return -EIO;
        }
 
-       usb_init_urb(&dev->ep1_in_urb);
-       usb_init_urb(&dev->midi_out_urb);
+       usb_init_urb(&cdev->ep1_in_urb);
+       usb_init_urb(&cdev->midi_out_urb);
 
-       usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev,
+       usb_fill_bulk_urb(&cdev->ep1_in_urb, usb_dev,
                          usb_rcvbulkpipe(usb_dev, 0x1),
-                         dev->ep1_in_buf, EP1_BUFSIZE,
-                         usb_ep1_command_reply_dispatch, dev);
+                         cdev->ep1_in_buf, EP1_BUFSIZE,
+                         usb_ep1_command_reply_dispatch, cdev);
 
-       usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev,
+       usb_fill_bulk_urb(&cdev->midi_out_urb, usb_dev,
                          usb_sndbulkpipe(usb_dev, 0x1),
-                         dev->midi_out_buf, EP1_BUFSIZE,
-                         snd_usb_caiaq_midi_output_done, dev);
+                         cdev->midi_out_buf, EP1_BUFSIZE,
+                         snd_usb_caiaq_midi_output_done, cdev);
 
-       init_waitqueue_head(&dev->ep1_wait_queue);
-       init_waitqueue_head(&dev->prepare_wait_queue);
+       init_waitqueue_head(&cdev->ep1_wait_queue);
+       init_waitqueue_head(&cdev->prepare_wait_queue);
 
-       if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0)
+       if (usb_submit_urb(&cdev->ep1_in_urb, GFP_KERNEL) != 0)
                return -EIO;
 
-       err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
+       err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
        if (err)
                return err;
 
-       if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ))
+       if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ))
                return -ENODEV;
 
        usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
-                  dev->vendor_name, CAIAQ_USB_STR_LEN);
+                  cdev->vendor_name, CAIAQ_USB_STR_LEN);
 
        usb_string(usb_dev, usb_dev->descriptor.iProduct,
-                  dev->product_name, CAIAQ_USB_STR_LEN);
+                  cdev->product_name, CAIAQ_USB_STR_LEN);
 
        strlcpy(card->driver, MODNAME, sizeof(card->driver));
-       strlcpy(card->shortname, dev->product_name, sizeof(card->shortname));
-       strlcpy(card->mixername, dev->product_name, sizeof(card->mixername));
+       strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname));
+       strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername));
 
        /* if the id was not passed as module option, fill it with a shortened
         * version of the product string which does not contain any
@@ -473,11 +478,10 @@ static int init_card(struct snd_usb_caiaqdev *dev)
        }
 
        usb_make_path(usb_dev, usbpath, sizeof(usbpath));
-       snprintf(card->longname, sizeof(card->longname),
-                      "%s %s (%s)",
-                      dev->vendor_name, dev->product_name, usbpath);
+       snprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
+                      cdev->vendor_name, cdev->product_name, usbpath);
 
-       setup_card(dev);
+       setup_card(cdev);
        return 0;
 }
 
@@ -486,9 +490,9 @@ static int snd_probe(struct usb_interface *intf,
 {
        int ret;
        struct snd_card *card = NULL;
-       struct usb_device *device = interface_to_usbdev(intf);
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
 
-       ret = create_card(device, intf, &card);
+       ret = create_card(usb_dev, intf, &card);
 
        if (ret < 0)
                return ret;
@@ -496,7 +500,7 @@ static int snd_probe(struct usb_interface *intf,
        usb_set_intfdata(intf, card);
        ret = init_card(caiaqdev(card));
        if (ret < 0) {
-               log("unable to init card! (ret=%d)\n", ret);
+               dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret);
                snd_card_free(card);
                return ret;
        }
@@ -506,24 +510,25 @@ static int snd_probe(struct usb_interface *intf,
 
 static void snd_disconnect(struct usb_interface *intf)
 {
-       struct snd_usb_caiaqdev *dev;
        struct snd_card *card = usb_get_intfdata(intf);
-
-       debug("%s(%p)\n", __func__, intf);
+       struct device *dev = intf->usb_dev;
+       struct snd_usb_caiaqdev *cdev;
 
        if (!card)
                return;
 
-       dev = caiaqdev(card);
+       cdev = caiaqdev(card);
+       dev_dbg(dev, "%s(%p)\n", __func__, intf);
+
        snd_card_disconnect(card);
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
-       snd_usb_caiaq_input_free(dev);
+       snd_usb_caiaq_input_free(cdev);
 #endif
-       snd_usb_caiaq_audio_free(dev);
+       snd_usb_caiaq_audio_free(cdev);
 
-       usb_kill_urb(&dev->ep1_in_urb);
-       usb_kill_urb(&dev->midi_out_urb);
+       usb_kill_urb(&cdev->ep1_in_urb);
+       usb_kill_urb(&cdev->midi_out_urb);
 
        snd_card_free(card);
        usb_reset_device(interface_to_usbdev(intf));
@@ -539,4 +544,3 @@ static struct usb_driver snd_usb_driver = {
 };
 
 module_usb_driver(snd_usb_driver);
-
index 562b0bf..ad102fa 100644 (file)
 #define CAIAQ_USB_STR_LEN 0xff
 #define MAX_STREAMS 32
 
-//#define      SND_USB_CAIAQ_DEBUG
-
 #define MODNAME "snd-usb-caiaq"
-#define log(x...) snd_printk(KERN_WARNING MODNAME" log: " x)
-
-#ifdef SND_USB_CAIAQ_DEBUG
-#define debug(x...) snd_printk(KERN_WARNING MODNAME " debug: " x)
-#else
-#define debug(x...) do { } while(0)
-#endif
 
 #define EP1_CMD_GET_DEVICE_INFO        0x1
 #define EP1_CMD_READ_ERP       0x2
@@ -124,15 +115,16 @@ struct snd_usb_caiaqdev {
 };
 
 struct snd_usb_caiaq_cb_info {
-       struct snd_usb_caiaqdev *dev;
+       struct snd_usb_caiaqdev *cdev;
        int index;
 };
 
 #define caiaqdev(c) ((struct snd_usb_caiaqdev*)(c)->private_data)
+#define caiaqdev_to_dev(d)     (d->chip.card->dev)
 
-int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp);
-int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp);
-int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev, int rate, int depth, int bbp);
+int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *cdev, int digital, int analog, int erp);
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
                               unsigned char command,
                               const unsigned char *buffer,
                               int len);
index 26a121b..efc70ae 100644 (file)
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/gfp.h>
 #include <linux/init.h>
 #include <linux/usb.h>
@@ -199,55 +200,55 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 #undef HIGH_PEAK
 #undef LOW_PEAK
 
-static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *cdev,
                                              int axis, const unsigned char *buf,
                                              int offset)
 {
-       input_report_abs(dev->input_dev, axis,
+       input_report_abs(cdev->input_dev, axis,
                         (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
 }
 
-static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *cdev,
                                        const unsigned char *buf,
                                        unsigned int len)
 {
-       struct input_dev *input_dev = dev->input_dev;
+       struct input_dev *input_dev = cdev->input_dev;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
-               snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
-               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
-               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
+               snd_caiaq_input_report_abs(cdev, ABS_X, buf, 2);
+               snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 0);
+               snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 1);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-               snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
-               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
-               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
+               snd_caiaq_input_report_abs(cdev, ABS_X, buf, 0);
+               snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 1);
+               snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 2);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
-               snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
-               snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
-               snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
-               snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
-               snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
-               snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
-               snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
-               snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT0X, buf, 4);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT0Y, buf, 2);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT1X, buf, 6);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT1Y, buf, 1);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT2X, buf, 7);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT2Y, buf, 0);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT3X, buf, 5);
+               snd_caiaq_input_report_abs(cdev, ABS_HAT3Y, buf, 3);
                break;
        }
 
        input_sync(input_dev);
 }
 
-static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
                                     const char *buf, unsigned int len)
 {
-       struct input_dev *input_dev = dev->input_dev;
+       struct input_dev *input_dev = cdev->input_dev;
        int i;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                i = decode_erp(buf[0], buf[1]);
                input_report_abs(input_dev, ABS_X, i);
@@ -299,10 +300,10 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
        }
 }
 
-static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
+static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
                                    unsigned char *buf, unsigned int len)
 {
-       struct input_dev *input_dev = dev->input_dev;
+       struct input_dev *input_dev = cdev->input_dev;
        unsigned short *keycode = input_dev->keycode;
        int i;
 
@@ -317,17 +318,17 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
                input_report_key(input_dev, keycode[i],
                                 buf[i / 8] & (1 << (i % 8)));
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-               input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
+               input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                /* rotary encoders */
-               input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf);
-               input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4);
-               input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf);
-               input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4);
+               input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
+               input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);
+               input_report_abs(cdev->input_dev, ABS_Z, buf[6] & 0xf);
+               input_report_abs(cdev->input_dev, ABS_MISC, buf[6] >> 4);
                break;
        }
 
@@ -336,10 +337,12 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
 
 #define TKS4_MSGBLOCK_SIZE     16
 
-static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
                                        const unsigned char *buf,
                                        unsigned int len)
 {
+       struct device *dev = caiaqdev_to_dev(cdev);
+
        while (len) {
                unsigned int i, block_id = (buf[0] << 8) | buf[1];
 
@@ -347,126 +350,126 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
                case 0:
                        /* buttons */
                        for (i = 0; i < KONTROLS4_BUTTONS; i++)
-                               input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+                               input_report_key(cdev->input_dev, KONTROLS4_BUTTON(i),
                                                 (buf[4 + (i / 8)] >> (i % 8)) & 1);
                        break;
 
                case 1:
                        /* left wheel */
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
                        /* right wheel */
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
 
                        /* rotary encoders */
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
-                       input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+                       input_report_abs(cdev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
 
                        break;
                case 2:
                        /* Volume Fader Channel D */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(0), buf, 1);
                        /* Volume Fader Channel B */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(1), buf, 2);
                        /* Volume Fader Channel A */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(2), buf, 3);
                        /* Volume Fader Channel C */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(3), buf, 4);
                        /* Loop Volume */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(4), buf, 6);
                        /* Crossfader */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(7), buf, 7);
 
                        break;
 
                case 3:
                        /* Tempo Fader R */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(6), buf, 3);
                        /* Tempo Fader L */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(5), buf, 4);
                        /* Mic Volume */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(8), buf, 6);
                        /* Cue Mix */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(9), buf, 7);
 
                        break;
 
                case 4:
                        /* Wheel distance sensor L */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(10), buf, 1);
                        /* Wheel distance sensor R */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(11), buf, 2);
                        /* Channel D EQ - Filter */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(12), buf, 3);
                        /* Channel D EQ - Low */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(13), buf, 4);
                        /* Channel D EQ - Mid */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(14), buf, 5);
                        /* Channel D EQ - Hi */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(15), buf, 6);
                        /* FX2 - dry/wet */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(16), buf, 7);
 
                        break;
 
                case 5:
                        /* FX2 - 1 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(17), buf, 1);
                        /* FX2 - 2 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(18), buf, 2);
                        /* FX2 - 3 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(19), buf, 3);
                        /* Channel B EQ - Filter */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(20), buf, 4);
                        /* Channel B EQ - Low */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(21), buf, 5);
                        /* Channel B EQ - Mid */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(22), buf, 6);
                        /* Channel B EQ - Hi */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(23), buf, 7);
 
                        break;
 
                case 6:
                        /* Channel A EQ - Filter */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(24), buf, 1);
                        /* Channel A EQ - Low */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(25), buf, 2);
                        /* Channel A EQ - Mid */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(26), buf, 3);
                        /* Channel A EQ - Hi */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(27), buf, 4);
                        /* Channel C EQ - Filter */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(28), buf, 5);
                        /* Channel C EQ - Low */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(29), buf, 6);
                        /* Channel C EQ - Mid */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(30), buf, 7);
 
                        break;
 
                case 7:
                        /* Channel C EQ - Hi */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(31), buf, 1);
                        /* FX1 - wet/dry */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(32), buf, 2);
                        /* FX1 - 1 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(33), buf, 3);
                        /* FX1 - 2 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(34), buf, 4);
                        /* FX1 - 3 */
-                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+                       snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(35), buf, 5);
 
                        break;
 
                default:
-                       debug("%s(): bogus block (id %d)\n",
+                       dev_dbg(dev, "%s(): bogus block (id %d)\n",
                                __func__, block_id);
                        return;
                }
@@ -475,12 +478,12 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
                buf += TKS4_MSGBLOCK_SIZE;
        }
 
-       input_sync(dev->input_dev);
+       input_sync(cdev->input_dev);
 }
 
 #define MASCHINE_MSGBLOCK_SIZE 2
 
-static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *cdev,
                                        const unsigned char *buf,
                                        unsigned int len)
 {
@@ -491,65 +494,66 @@ static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev,
                pressure = be16_to_cpu(buf[i * 2] << 8 | buf[(i * 2) + 1]);
                pad_id = pressure >> 12;
 
-               input_report_abs(dev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff);
+               input_report_abs(cdev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff);
        }
 
-       input_sync(dev->input_dev);
+       input_sync(cdev->input_dev);
 }
 
 static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
 {
-       struct snd_usb_caiaqdev *dev = urb->context;
+       struct snd_usb_caiaqdev *cdev = urb->context;
        unsigned char *buf = urb->transfer_buffer;
+       struct device *dev = &urb->dev->dev;
        int ret;
 
-       if (urb->status || !dev || urb != dev->ep4_in_urb)
+       if (urb->status || !cdev || urb != cdev->ep4_in_urb)
                return;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                if (urb->actual_length < 24)
                        goto requeue;
 
                if (buf[0] & 0x3)
-                       snd_caiaq_input_read_io(dev, buf + 1, 7);
+                       snd_caiaq_input_read_io(cdev, buf + 1, 7);
 
                if (buf[0] & 0x4)
-                       snd_caiaq_input_read_analog(dev, buf + 8, 16);
+                       snd_caiaq_input_read_analog(cdev, buf + 8, 16);
 
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
-               snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+               snd_usb_caiaq_tks4_dispatch(cdev, buf, urb->actual_length);
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
                if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE))
                        goto requeue;
 
-               snd_usb_caiaq_maschine_dispatch(dev, buf, urb->actual_length);
+               snd_usb_caiaq_maschine_dispatch(cdev, buf, urb->actual_length);
                break;
        }
 
 requeue:
-       dev->ep4_in_urb->actual_length = 0;
-       ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC);
+       cdev->ep4_in_urb->actual_length = 0;
+       ret = usb_submit_urb(cdev->ep4_in_urb, GFP_ATOMIC);
        if (ret < 0)
-               log("unable to submit urb. OOM!?\n");
+               dev_err(dev, "unable to submit urb. OOM!?\n");
 }
 
 static int snd_usb_caiaq_input_open(struct input_dev *idev)
 {
-       struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+       struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
 
-       if (!dev)
+       if (!cdev)
                return -EINVAL;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
-               if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
+               if (usb_submit_urb(cdev->ep4_in_urb, GFP_KERNEL) != 0)
                        return -EIO;
                break;
        }
@@ -559,43 +563,43 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
 
 static void snd_usb_caiaq_input_close(struct input_dev *idev)
 {
-       struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+       struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
 
-       if (!dev)
+       if (!cdev)
                return;
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
-               usb_kill_urb(dev->ep4_in_urb);
+               usb_kill_urb(cdev->ep4_in_urb);
                break;
        }
 }
 
-void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
+void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev,
                                  char *buf,
                                  unsigned int len)
 {
-       if (!dev->input_dev || len < 1)
+       if (!cdev->input_dev || len < 1)
                return;
 
        switch (buf[0]) {
        case EP1_CMD_READ_ANALOG:
-               snd_caiaq_input_read_analog(dev, buf + 1, len - 1);
+               snd_caiaq_input_read_analog(cdev, buf + 1, len - 1);
                break;
        case EP1_CMD_READ_ERP:
-               snd_caiaq_input_read_erp(dev, buf + 1, len - 1);
+               snd_caiaq_input_read_erp(cdev, buf + 1, len - 1);
                break;
        case EP1_CMD_READ_IO:
-               snd_caiaq_input_read_io(dev, buf + 1, len - 1);
+               snd_caiaq_input_read_io(cdev, buf + 1, len - 1);
                break;
        }
 }
 
-int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
 {
-       struct usb_device *usb_dev = dev->chip.dev;
+       struct usb_device *usb_dev = cdev->chip.dev;
        struct input_dev *input;
        int i, ret = 0;
 
@@ -603,49 +607,49 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
        if (!input)
                return -ENOMEM;
 
-       usb_make_path(usb_dev, dev->phys, sizeof(dev->phys));
-       strlcat(dev->phys, "/input0", sizeof(dev->phys));
+       usb_make_path(usb_dev, cdev->phys, sizeof(cdev->phys));
+       strlcat(cdev->phys, "/input0", sizeof(cdev->phys));
 
-       input->name = dev->product_name;
-       input->phys = dev->phys;
+       input->name = cdev->product_name;
+       input->phys = cdev->phys;
        usb_to_input_id(usb_dev, &input->id);
        input->dev.parent = &usb_dev->dev;
 
-       input_set_drvdata(input, dev);
+       input_set_drvdata(input, cdev);
 
-       switch (dev->chip.usb_id) {
+       switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
                input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                        BIT_MASK(ABS_Z);
-               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2));
-               memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2));
+               BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk2));
+               memcpy(cdev->keycode, keycode_rk2, sizeof(keycode_rk2));
                input->keycodemax = ARRAY_SIZE(keycode_rk2);
                input_set_abs_params(input, ABS_X, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
                input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                        BIT_MASK(ABS_Z);
-               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3));
-               memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3));
+               BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk3));
+               memcpy(cdev->keycode, keycode_rk3, sizeof(keycode_rk3));
                input->keycodemax = ARRAY_SIZE(keycode_rk3);
                input_set_abs_params(input, ABS_X, 0, 1024, 0, 10);
                input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10);
                input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10);
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
                input->absbit[0] = BIT_MASK(ABS_X);
-               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1));
-               memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1));
+               BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_ak1));
+               memcpy(cdev->keycode, keycode_ak1, sizeof(keycode_ak1));
                input->keycodemax = ARRAY_SIZE(keycode_ak1);
                input_set_abs_params(input, ABS_X, 0, 999, 0, 10);
-               snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 5);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
@@ -657,8 +661,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                                   BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                                   BIT_MASK(ABS_Z);
                input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
-               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore));
-               memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore));
+               BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_kore));
+               memcpy(cdev->keycode, keycode_kore, sizeof(keycode_kore));
                input->keycodemax = ARRAY_SIZE(keycode_kore);
                input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);
                input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10);
@@ -672,7 +676,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
@@ -683,9 +687,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                                   BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                                   BIT_MASK(ABS_Z);
                input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
-               BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS);
+               BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLX1_INPUTS);
                for (i = 0; i < KONTROLX1_INPUTS; i++)
-                       dev->keycode[i] = BTN_MISC + i;
+                       cdev->keycode[i] = BTN_MISC + i;
                input->keycodemax = KONTROLX1_INPUTS;
 
                /* analog potentiometers */
@@ -704,26 +708,26 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1);
                input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1);
 
-               dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!dev->ep4_in_urb) {
+               cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!cdev->ep4_in_urb) {
                        ret = -ENOMEM;
                        goto exit_free_idev;
                }
 
-               usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+               usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
                                  usb_rcvbulkpipe(usb_dev, 0x4),
-                                 dev->ep4_in_buf, EP4_BUFSIZE,
-                                 snd_usb_caiaq_ep4_reply_dispatch, dev);
+                                 cdev->ep4_in_buf, EP4_BUFSIZE,
+                                 snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-               BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+               BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLS4_BUTTONS);
                for (i = 0; i < KONTROLS4_BUTTONS; i++)
-                       dev->keycode[i] = KONTROLS4_BUTTON(i);
+                       cdev->keycode[i] = KONTROLS4_BUTTON(i);
                input->keycodemax = KONTROLS4_BUTTONS;
 
                for (i = 0; i < KONTROLS4_AXIS; i++) {
@@ -743,18 +747,18 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                for (i = 0; i < 9; i++)
                        input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
 
-               dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!dev->ep4_in_urb) {
+               cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!cdev->ep4_in_urb) {
                        ret = -ENOMEM;
                        goto exit_free_idev;
                }
 
-               usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+               usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
                                  usb_rcvbulkpipe(usb_dev, 0x4),
-                                 dev->ep4_in_buf, EP4_BUFSIZE,
-                                 snd_usb_caiaq_ep4_reply_dispatch, dev);
+                                 cdev->ep4_in_buf, EP4_BUFSIZE,
+                                 snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
 
                break;
 
@@ -767,8 +771,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                        BIT_MASK(ABS_RX) | BIT_MASK(ABS_RY) |
                        BIT_MASK(ABS_RZ);
 
-               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_maschine));
-               memcpy(dev->keycode, keycode_maschine, sizeof(keycode_maschine));
+               BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_maschine));
+               memcpy(cdev->keycode, keycode_maschine, sizeof(keycode_maschine));
                input->keycodemax = ARRAY_SIZE(keycode_maschine);
 
                for (i = 0; i < MASCHINE_PADS; i++) {
@@ -788,18 +792,18 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                input_set_abs_params(input, ABS_RY, 0, 999, 0, 10);
                input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10);
 
-               dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!dev->ep4_in_urb) {
+               cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!cdev->ep4_in_urb) {
                        ret = -ENOMEM;
                        goto exit_free_idev;
                }
 
-               usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+               usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
                                  usb_rcvbulkpipe(usb_dev, 0x4),
-                                 dev->ep4_in_buf, EP4_BUFSIZE,
-                                 snd_usb_caiaq_ep4_reply_dispatch, dev);
+                                 cdev->ep4_in_buf, EP4_BUFSIZE,
+                                 snd_usb_caiaq_ep4_reply_dispatch, cdev);
 
-               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+               snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);
                break;
 
        default:
@@ -809,12 +813,12 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 
        input->open = snd_usb_caiaq_input_open;
        input->close = snd_usb_caiaq_input_close;
-       input->keycode = dev->keycode;
+       input->keycode = cdev->keycode;
        input->keycodesize = sizeof(unsigned short);
        for (i = 0; i < input->keycodemax; i++)
-               __set_bit(dev->keycode[i], input->keybit);
+               __set_bit(cdev->keycode[i], input->keybit);
 
-       dev->input_dev = input;
+       cdev->input_dev = input;
 
        ret = input_register_device(input);
        if (ret < 0)
@@ -824,19 +828,19 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
 
 exit_free_idev:
        input_free_device(input);
-       dev->input_dev = NULL;
+       cdev->input_dev = NULL;
        return ret;
 }
 
-void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
+void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)
 {
-       if (!dev || !dev->input_dev)
+       if (!cdev || !cdev->input_dev)
                return;
 
-       usb_kill_urb(dev->ep4_in_urb);
-       usb_free_urb(dev->ep4_in_urb);
-       dev->ep4_in_urb = NULL;
+       usb_kill_urb(cdev->ep4_in_urb);
+       usb_free_urb(cdev->ep4_in_urb);
+       cdev->ep4_in_urb = NULL;
 
-       input_unregister_device(dev->input_dev);
-       dev->input_dev = NULL;
+       input_unregister_device(cdev->input_dev);
+       cdev->input_dev = NULL;
 }
index ced5355..6014e27 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef CAIAQ_INPUT_H
 #define CAIAQ_INPUT_H
 
-void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, char *buf, unsigned int len);
-int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev);
+void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len);
+int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev);
 
 #endif
index a1a4708..2d75884 100644 (file)
@@ -16,6 +16,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
+#include <linux/device.h>
 #include <linux/usb.h>
 #include <linux/gfp.h>
 #include <sound/rawmidi.h>
@@ -37,12 +38,12 @@ static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substrea
 
 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
+       struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
 
-       if (!dev)
+       if (!cdev)
                return;
 
-       dev->midi_receive_substream = up ? substream : NULL;
+       cdev->midi_receive_substream = up ? substream : NULL;
 }
 
 
@@ -53,49 +54,50 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea
 
 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
 {
-       struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
-       if (dev->midi_out_active) {
-               usb_kill_urb(&dev->midi_out_urb);
-               dev->midi_out_active = 0;
+       struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
+       if (cdev->midi_out_active) {
+               usb_kill_urb(&cdev->midi_out_urb);
+               cdev->midi_out_active = 0;
        }
        return 0;
 }
 
-static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
+static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
                                    struct snd_rawmidi_substream *substream)
 {
        int len, ret;
+       struct device *dev = caiaqdev_to_dev(cdev);
 
-       dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
-       dev->midi_out_buf[1] = 0; /* port */
-       len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
+       cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
+       cdev->midi_out_buf[1] = 0; /* port */
+       len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
                                   EP1_BUFSIZE - 3);
 
        if (len <= 0)
                return;
 
-       dev->midi_out_buf[2] = len;
-       dev->midi_out_urb.transfer_buffer_length = len+3;
+       cdev->midi_out_buf[2] = len;
+       cdev->midi_out_urb.transfer_buffer_length = len+3;
 
-       ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
+       ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
        if (ret < 0)
-               log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
-                   "ret=%d, len=%d\n",
-                   substream, ret, len);
+               dev_err(dev,
+                       "snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
+                       "ret=%d, len=%d\n", substream, ret, len);
        else
-               dev->midi_out_active = 1;
+               cdev->midi_out_active = 1;
 }
 
 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
+       struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
 
        if (up) {
-               dev->midi_out_substream = substream;
-               if (!dev->midi_out_active)
-                       snd_usb_caiaq_midi_send(dev, substream);
+               cdev->midi_out_substream = substream;
+               if (!cdev->midi_out_active)
+                       snd_usb_caiaq_midi_send(cdev, substream);
        } else {
-               dev->midi_out_substream = NULL;
+               cdev->midi_out_substream = NULL;
        }
 }
 
@@ -114,13 +116,13 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
        .trigger =      snd_usb_caiaq_midi_input_trigger,
 };
 
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
                                     int port, const char *buf, int len)
 {
-       if (!dev->midi_receive_substream)
+       if (!cdev->midi_receive_substream)
                return;
 
-       snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
+       snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
 }
 
 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
@@ -160,15 +162,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 
 void snd_usb_caiaq_midi_output_done(struct urb* urb)
 {
-       struct snd_usb_caiaqdev *dev = urb->context;
+       struct snd_usb_caiaqdev *cdev = urb->context;
 
-       dev->midi_out_active = 0;
+       cdev->midi_out_active = 0;
        if (urb->status != 0)
                return;
 
-       if (!dev->midi_out_substream)
+       if (!cdev->midi_out_substream)
                return;
 
-       snd_usb_caiaq_midi_send(dev, dev->midi_out_substream);
+       snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
 }
-
index 380f984..60bf344 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef CAIAQ_MIDI_H
 #define CAIAQ_MIDI_H
 
-int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev);
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len);
+int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *cdev);
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
+                                    int port, const char *buf, int len);
 void snd_usb_caiaq_midi_output_done(struct urb *urb);
 
 #endif /* CAIAQ_MIDI_H */
index 2da8ad7..5254b18 100644 (file)
@@ -82,6 +82,7 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int nrpacks = 8;                /* max. number of packets per urb */
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
 static bool ignore_ctl_error;
+static bool autoclock = true;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -100,6 +101,8 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 module_param(ignore_ctl_error, bool, 0444);
 MODULE_PARM_DESC(ignore_ctl_error,
                 "Ignore errors from USB controller for mixer interfaces.");
+module_param(autoclock, bool, 0444);
+MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");
 
 /*
  * we keep the snd_usb_audio_t instances by ourselves for merging
@@ -354,6 +357,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        chip->card = card;
        chip->setup = device_setup[idx];
        chip->nrpacks = nrpacks;
+       chip->autoclock = autoclock;
        chip->probing = 1;
 
        chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
@@ -645,7 +649,6 @@ void snd_usb_autosuspend(struct snd_usb_audio *chip)
 static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
-       struct list_head *p;
        struct snd_usb_stream *as;
        struct usb_mixer_interface *mixer;
 
@@ -655,8 +658,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
        if (!PMSG_IS_AUTO(message)) {
                snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
                if (!chip->num_suspended_intf++) {
-                       list_for_each(p, &chip->pcm_list) {
-                               as = list_entry(p, struct snd_usb_stream, list);
+                       list_for_each_entry(as, &chip->pcm_list, list) {
                                snd_pcm_suspend_all(as->pcm);
                                as->substream[0].need_setup_ep =
                                        as->substream[1].need_setup_ep = true;
@@ -716,8 +718,7 @@ static struct usb_device_id usb_audio_ids [] = {
       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },
     { }                                                /* Terminating entry */
 };
-
-MODULE_DEVICE_TABLE (usb, usb_audio_ids);
+MODULE_DEVICE_TABLE(usb, usb_audio_ids);
 
 /*
  * entry point for linux usb interface
index 8a751b4..bf2889a 100644 (file)
@@ -28,6 +28,8 @@ struct audioformat {
        unsigned int *rate_table;       /* rate table */
        unsigned char clock;            /* associated clock */
        struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */
+       bool dsd_dop;                   /* add DOP headers in case of DSD samples */
+       bool dsd_bitrev;                /* reverse the bits of each DSD sample */
 };
 
 struct snd_usb_substream;
@@ -116,6 +118,7 @@ struct snd_usb_substream {
        unsigned int altset_idx;     /* USB data format: index of alternate setting */
        unsigned int txfr_quirk:1;      /* allow sub-frame alignment */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
+       unsigned int pkt_offset_adj;    /* Bytes to drop from beginning of packets (for non-compliant devices) */
 
        unsigned int running: 1;        /* running status */
 
@@ -138,6 +141,12 @@ struct snd_usb_substream {
 
        int last_frame_number;          /* stored frame number */
        int last_delay;                 /* stored delay */
+
+       struct {
+               int marker;
+               int channel;
+               int byte_idx;
+       } dsd_dop;
 };
 
 struct snd_usb_stream {
index 9e2703a..b0ec364 100644 (file)
@@ -32,6 +32,7 @@
 #include "card.h"
 #include "helper.h"
 #include "clock.h"
+#include "quirks.h"
 
 static struct uac_clock_source_descriptor *
        snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
@@ -99,6 +100,41 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
        return buf;
 }
 
+static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
+                                       unsigned char pin)
+{
+       int ret;
+
+       ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+                             UAC2_CS_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                             UAC2_CX_CLOCK_SELECTOR << 8,
+                             snd_usb_ctrl_intf(chip) | (selector_id << 8),
+                             &pin, sizeof(pin));
+       if (ret < 0)
+               return ret;
+
+       if (ret != sizeof(pin)) {
+               snd_printk(KERN_ERR
+                       "usb-audio:%d: setting selector (id %d) unexpected length %d\n",
+                       chip->dev->devnum, selector_id, ret);
+               return -EINVAL;
+       }
+
+       ret = uac_clock_selector_get_val(chip, selector_id);
+       if (ret < 0)
+               return ret;
+
+       if (ret != pin) {
+               snd_printk(KERN_ERR
+                       "usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n",
+                       chip->dev->devnum, selector_id, pin, ret);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
 static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 {
        int err;
@@ -131,7 +167,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
 }
 
 static int __uac_clock_find_source(struct snd_usb_audio *chip,
-                                  int entity_id, unsigned long *visited)
+                                  int entity_id, unsigned long *visited,
+                                  bool validate)
 {
        struct uac_clock_source_descriptor *source;
        struct uac_clock_selector_descriptor *selector;
@@ -148,12 +185,19 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
 
        /* first, see if the ID we're looking for is a clock source already */
        source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
-       if (source)
-               return source->bClockID;
+       if (source) {
+               entity_id = source->bClockID;
+               if (validate && !uac_clock_source_is_valid(chip, entity_id)) {
+                       snd_printk(KERN_ERR "usb-audio:%d: clock source %d is not valid, cannot use\n",
+                                  chip->dev->devnum, entity_id);
+                       return -ENXIO;
+               }
+               return entity_id;
+       }
 
        selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
        if (selector) {
-               int ret;
+               int ret, i, cur;
 
                /* the entity ID we are looking for is a selector.
                 * find out what it currently selects */
@@ -164,22 +208,49 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
                /* Selector values are one-based */
 
                if (ret > selector->bNrInPins || ret < 1) {
-                       printk(KERN_ERR
+                       snd_printk(KERN_ERR
                                "%s(): selector reported illegal value, id %d, ret %d\n",
                                __func__, selector->bClockID, ret);
 
                        return -EINVAL;
                }
 
-               return __uac_clock_find_source(chip, selector->baCSourceID[ret-1],
-                                              visited);
+               cur = ret;
+               ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
+                                              visited, validate);
+               if (!validate || ret > 0 || !chip->autoclock)
+                       return ret;
+
+               /* The current clock source is invalid, try others. */
+               for (i = 1; i <= selector->bNrInPins; i++) {
+                       int err;
+
+                       if (i == cur)
+                               continue;
+
+                       ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
+                               visited, true);
+                       if (ret < 0)
+                               continue;
+
+                       err = uac_clock_selector_set_val(chip, entity_id, i);
+                       if (err < 0)
+                               continue;
+
+                       snd_printk(KERN_INFO
+                               "usb-audio:%d: found and selected valid clock source %d\n",
+                               chip->dev->devnum, ret);
+                       return ret;
+               }
+
+               return -ENXIO;
        }
 
        /* FIXME: multipliers only act as pass-thru element for now */
        multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
        if (multiplier)
                return __uac_clock_find_source(chip, multiplier->bCSourceID,
-                                               visited);
+                                               visited, validate);
 
        return -EINVAL;
 }
@@ -195,11 +266,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
  *
  * Returns the clock source UnitID (>=0) on success, or an error.
  */
-int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id)
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
+                             bool validate)
 {
        DECLARE_BITMAP(visited, 256);
        memset(visited, 0, sizeof(visited));
-       return __uac_clock_find_source(chip, entity_id, visited);
+       return __uac_clock_find_source(chip, entity_id, visited, validate);
 }
 
 static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
@@ -247,66 +319,71 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
        return 0;
 }
 
-static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
-                             struct usb_host_interface *alts,
-                             struct audioformat *fmt, int rate)
+static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface,
+                             int altsetting, int clock)
 {
        struct usb_device *dev = chip->dev;
-       unsigned char data[4];
-       int err, cur_rate, prev_rate;
-       int clock = snd_usb_clock_find_source(chip, fmt->clock);
-
-       if (clock < 0)
-               return clock;
-
-       if (!uac_clock_source_is_valid(chip, clock)) {
-               /* TODO: should we try to find valid clock setups by ourself? */
-               snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
-                          dev->devnum, iface, fmt->altsetting, clock);
-               return -ENXIO;
-       }
+       __le32 data;
+       int err;
 
        err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
                              UAC2_CS_CONTROL_SAM_FREQ << 8,
                              snd_usb_ctrl_intf(chip) | (clock << 8),
-                             data, sizeof(data));
+                             &data, sizeof(data));
        if (err < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
-                          dev->devnum, iface, fmt->altsetting);
-               prev_rate = 0;
-       } else {
-               prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2): err %d\n",
+                          dev->devnum, iface, altsetting, err);
+               return 0;
        }
 
-       data[0] = rate;
-       data[1] = rate >> 8;
-       data[2] = rate >> 16;
-       data[3] = rate >> 24;
-       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
-                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                                  UAC2_CS_CONTROL_SAM_FREQ << 8,
-                                  snd_usb_ctrl_intf(chip) | (clock << 8),
-                                  data, sizeof(data))) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
-                          dev->devnum, iface, fmt->altsetting, rate);
-               return err;
-       }
+       return le32_to_cpu(data);
+}
 
-       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
-                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-                             UAC2_CS_CONTROL_SAM_FREQ << 8,
-                             snd_usb_ctrl_intf(chip) | (clock << 8),
-                             data, sizeof(data));
-       if (err < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
-                          dev->devnum, iface, fmt->altsetting);
-               cur_rate = 0;
+static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
+                             struct usb_host_interface *alts,
+                             struct audioformat *fmt, int rate)
+{
+       struct usb_device *dev = chip->dev;
+       __le32 data;
+       int err, cur_rate, prev_rate;
+       int clock;
+       bool writeable;
+       struct uac_clock_source_descriptor *cs_desc;
+
+       clock = snd_usb_clock_find_source(chip, fmt->clock, true);
+       if (clock < 0)
+               return clock;
+
+       prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
+
+       cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
+       writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1);
+       if (writeable) {
+               data = cpu_to_le32(rate);
+               err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+                                     USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                     UAC2_CS_CONTROL_SAM_FREQ << 8,
+                                     snd_usb_ctrl_intf(chip) | (clock << 8),
+                                     &data, sizeof(data));
+               if (err < 0) {
+                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n",
+                                  dev->devnum, iface, fmt->altsetting, rate, err);
+                       return err;
+               }
+
+               cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
        } else {
-               cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+               cur_rate = prev_rate;
        }
 
        if (cur_rate != rate) {
+               if (!writeable) {
+                       snd_printk(KERN_WARNING
+                                  "%d:%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
+                                  dev->devnum, iface, fmt->altsetting, rate, cur_rate);
+                       return -ENXIO;
+               }
                snd_printd(KERN_WARNING
                           "current rate %d is different from the runtime rate %d\n",
                           cur_rate, rate);
@@ -316,7 +393,9 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
         * interface is active. */
        if (rate != prev_rate) {
                usb_set_interface(dev, iface, 0);
+               snd_usb_set_interface_quirk(dev);
                usb_set_interface(dev, iface, fmt->altsetting);
+               snd_usb_set_interface_quirk(dev);
        }
 
        return 0;
index 4663093..d592e4a 100644 (file)
@@ -5,6 +5,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
                             struct usb_host_interface *alts,
                             struct audioformat *fmt, int rate);
 
-int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id);
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
+                            bool validate);
 
 #endif /* __USBAUDIO_CLOCK_H */
index 21049b8..32d0b41 100644 (file)
@@ -128,7 +128,7 @@ static const char *usb_error_string(int err)
  * Determine whether an endpoint is driven by an implicit feedback
  * data endpoint source.
  */
-int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
+int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)
 {
        return  ep->sync_master &&
                ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
@@ -363,7 +363,7 @@ static void snd_complete_urb(struct urb *urb)
                if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
                        goto exit_clear;
 
-               if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+               if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
                        unsigned long flags;
 
                        spin_lock_irqsave(&ep->lock, flags);
@@ -415,14 +415,12 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                                              struct usb_host_interface *alts,
                                              int ep_num, int direction, int type)
 {
-       struct list_head *p;
        struct snd_usb_endpoint *ep;
        int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
 
        mutex_lock(&chip->mutex);
 
-       list_for_each(p, &chip->ep_list) {
-               ep = list_entry(p, struct snd_usb_endpoint, list);
+       list_for_each_entry(ep, &chip->ep_list, list) {
                if (ep->ep_num == ep_num &&
                    ep->iface == alts->desc.bInterfaceNumber &&
                    ep->alt_idx == alts->desc.bAlternateSetting) {
@@ -580,6 +578,15 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        int is_playback = usb_pipeout(ep->pipe);
        int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
+       if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
+               /*
+                * When operating in DSD DOP mode, the size of a sample frame
+                * in hardware differs from the actual physical format width
+                * because we need to make room for the DOP markers.
+                */
+               frame_bits += channels << 3;
+       }
+
        ep->datainterval = fmt->datainterval;
        ep->stride = frame_bits >> 3;
        ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
@@ -607,7 +614,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        else
                packs_per_ms = 1;
 
-       if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+       if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
                urb_packs = max(ep->chip->nrpacks, 1);
                urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
        } else {
@@ -616,11 +623,11 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 
        urb_packs *= packs_per_ms;
 
-       if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+       if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
                urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
 
        /* decide how many packets to be used */
-       if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+       if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
                unsigned int minsize, maxpacks;
                /* determine how small a packet can be */
                minsize = (ep->freqn >> (16 - ep->datainterval))
@@ -847,7 +854,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)
 
        set_bit(EP_FLAG_RUNNING, &ep->flags);
 
-       if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+       if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
                for (i = 0; i < ep->nurbs; i++) {
                        struct snd_urb_ctx *ctx = ep->urb + i;
                        list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
@@ -990,7 +997,7 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
         * and add it to the list of pending urbs. queue_pending_output_urbs()
         * will take care of them later.
         */
-       if (snd_usb_endpoint_implict_feedback_sink(ep) &&
+       if (snd_usb_endpoint_implicit_feedback_sink(ep) &&
            ep->use_count != 0) {
 
                /* implicit feedback case */
index 447902d..2287adf 100644 (file)
@@ -23,7 +23,7 @@ int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
 int  snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
 void snd_usb_endpoint_free(struct list_head *head);
 
-int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
 
 void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
index e831ee4..020ede0 100644 (file)
  */
 static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                                     struct audioformat *fp,
-                                    int format, void *_fmt,
+                                    unsigned int format, void *_fmt,
                                     int protocol)
 {
        int sample_width, sample_bytes;
-       u64 pcm_formats;
+       u64 pcm_formats = 0;
 
        switch (protocol) {
        case UAC_VERSION_1:
@@ -63,14 +63,17 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                struct uac_format_type_i_ext_descriptor *fmt = _fmt;
                sample_width = fmt->bBitResolution;
                sample_bytes = fmt->bSubslotSize;
+
+               if (format & UAC2_FORMAT_TYPE_I_RAW_DATA)
+                       pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL;
+
                format <<= 1;
                break;
        }
        }
 
-       pcm_formats = 0;
-
-       if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) {
+       if ((pcm_formats == 0) &&
+           (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
                /* some devices don't define this correctly... */
                snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
                            chip->dev->devnum, fp->iface, fp->altsetting);
@@ -133,6 +136,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
                           chip->dev->devnum, fp->iface, fp->altsetting, format);
        }
+
+       pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);
+
        return pcm_formats;
 }
 
@@ -277,7 +283,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
        struct usb_device *dev = chip->dev;
        unsigned char tmp[2], *data;
        int nr_triplets, data_size, ret = 0;
-       int clock = snd_usb_clock_find_source(chip, fp->clock);
+       int clock = snd_usb_clock_find_source(chip, fp->clock, false);
 
        if (clock < 0) {
                snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n",
@@ -353,7 +359,7 @@ err:
  * parse the format type I and III descriptors
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
-                               struct audioformat *fp, int format,
+                               struct audioformat *fp, unsigned int format,
                                struct uac_format_type_i_continuous_descriptor *fmt,
                                struct usb_host_interface *iface)
 {
@@ -473,8 +479,9 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
        return ret;
 }
 
-int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
-                              int format, struct uac_format_type_i_continuous_descriptor *fmt,
+int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
+                              struct audioformat *fp, unsigned int format,
+                              struct uac_format_type_i_continuous_descriptor *fmt,
                               int stream, struct usb_host_interface *iface)
 {
        int err;
index 387924f..6f31522 100644 (file)
@@ -2,7 +2,7 @@
 #define __USBAUDIO_FORMAT_H
 
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
-                              struct audioformat *fp, int format,
+                              struct audioformat *fp, unsigned int format,
                               struct uac_format_type_i_continuous_descriptor *fmt,
                               int stream, struct usb_host_interface *iface);
 
index 34b9bb7..8e01fa4 100644 (file)
@@ -126,7 +126,6 @@ struct snd_usb_midi {
                struct snd_usb_midi_in_endpoint *in;
        } endpoints[MIDI_MAX_ENDPOINTS];
        unsigned long input_triggered;
-       bool autopm_reference;
        unsigned int opened[2];
        unsigned char disconnected;
        unsigned char input_running;
@@ -1040,7 +1039,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
 {
        struct snd_usb_midi* umidi = substream->rmidi->private_data;
        struct snd_kcontrol *ctl;
-       int err;
 
        down_read(&umidi->disc_rwsem);
        if (umidi->disconnected) {
@@ -1051,13 +1049,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
        mutex_lock(&umidi->mutex);
        if (open) {
                if (!umidi->opened[0] && !umidi->opened[1]) {
-                       err = usb_autopm_get_interface(umidi->iface);
-                       umidi->autopm_reference = err >= 0;
-                       if (err < 0 && err != -EACCES) {
-                               mutex_unlock(&umidi->mutex);
-                               up_read(&umidi->disc_rwsem);
-                               return -EIO;
-                       }
                        if (umidi->roland_load_ctl) {
                                ctl = umidi->roland_load_ctl;
                                ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -1080,8 +1071,6 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir,
                                snd_ctl_notify(umidi->card,
                                       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
                        }
-                       if (umidi->autopm_reference)
-                               usb_autopm_put_interface(umidi->iface);
                }
        }
        mutex_unlock(&umidi->mutex);
@@ -1455,6 +1444,7 @@ void snd_usbmidi_disconnect(struct list_head* p)
        }
        del_timer_sync(&umidi->error_timer);
 }
+EXPORT_SYMBOL(snd_usbmidi_disconnect);
 
 static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
 {
@@ -1465,10 +1455,9 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
 static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,
                                                                int stream, int number)
 {
-       struct list_head* list;
+       struct snd_rawmidi_substream *substream;
 
-       list_for_each(list, &umidi->rmidi->streams[stream].substreams) {
-               struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
+       list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, list) {
                if (substream->number == number)
                        return substream;
        }
@@ -2091,6 +2080,7 @@ void snd_usbmidi_input_stop(struct list_head* p)
        }
        umidi->input_running = 0;
 }
+EXPORT_SYMBOL(snd_usbmidi_input_stop);
 
 static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
 {
@@ -2120,6 +2110,7 @@ void snd_usbmidi_input_start(struct list_head* p)
                snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
        umidi->input_running = 1;
 }
+EXPORT_SYMBOL(snd_usbmidi_input_start);
 
 /*
  * Creates and registers everything needed for a MIDI streaming interface.
@@ -2256,11 +2247,9 @@ int snd_usbmidi_create(struct snd_card *card,
                return err;
        }
 
+       usb_autopm_get_interface_no_resume(umidi->iface);
+
        list_add_tail(&umidi->list, midi_list);
        return 0;
 }
-
 EXPORT_SYMBOL(snd_usbmidi_create);
-EXPORT_SYMBOL(snd_usbmidi_input_stop);
-EXPORT_SYMBOL(snd_usbmidi_input_start);
-EXPORT_SYMBOL(snd_usbmidi_disconnect);
index f94397b..9723f3c 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/bitrev.h>
 #include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
@@ -94,13 +95,11 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
  */
 static struct audioformat *find_format(struct snd_usb_substream *subs)
 {
-       struct list_head *p;
+       struct audioformat *fp;
        struct audioformat *found = NULL;
        int cur_attr = 0, attr;
 
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
-               fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!(fp->formats & (1uLL << subs->pcm_format)))
                        continue;
                if (fp->channels != subs->channels)
@@ -350,6 +349,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                                fmt->iface, fmt->altsetting);
                subs->interface = fmt->iface;
                subs->altset_idx = fmt->altset_idx;
+
+               snd_usb_set_interface_quirk(dev);
        }
 
        subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
@@ -802,7 +803,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
                        struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
-       struct list_head *p;
+       struct audioformat *fp;
        struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        unsigned int rmin, rmax;
        int changed;
@@ -810,9 +811,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
        hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
        changed = 0;
        rmin = rmax = 0;
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
-               fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!hw_check_valid_format(subs, params, fp))
                        continue;
                if (changed++) {
@@ -856,7 +855,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
                            struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
-       struct list_head *p;
+       struct audioformat *fp;
        struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        unsigned int rmin, rmax;
        int changed;
@@ -864,9 +863,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
        hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max);
        changed = 0;
        rmin = rmax = 0;
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
-               fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!hw_check_valid_format(subs, params, fp))
                        continue;
                if (changed++) {
@@ -909,7 +906,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
                          struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
-       struct list_head *p;
+       struct audioformat *fp;
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        u64 fbits;
        u32 oldbits[2];
@@ -917,9 +914,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
 
        hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
        fbits = 0;
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
-               fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!hw_check_valid_format(subs, params, fp))
                        continue;
                fbits |= fp->formats;
@@ -1027,7 +1022,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
 
 static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
 {
-       struct list_head *p;
+       struct audioformat *fp;
        unsigned int pt, ptmin;
        int param_period_time_if_needed;
        int err;
@@ -1041,9 +1036,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
        runtime->hw.rates = 0;
        ptmin = UINT_MAX;
        /* check min/max rates and channels */
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
-               fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                runtime->hw.rates |= fp->rates;
                if (runtime->hw.rate_min > fp->rate_min)
                        runtime->hw.rate_min = fp->rate_min;
@@ -1128,6 +1121,12 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
        runtime->private_data = subs;
        subs->pcm_substream = substream;
        /* runtime PM is also done there */
+
+       /* initialize DSD/DOP context */
+       subs->dsd_dop.byte_idx = 0;
+       subs->dsd_dop.channel = 0;
+       subs->dsd_dop.marker = 1;
+
        return setup_hw_info(runtime, subs);
 }
 
@@ -1170,7 +1169,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
        stride = runtime->frame_bits >> 3;
 
        for (i = 0; i < urb->number_of_packets; i++) {
-               cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj;
                if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
                        snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
                        // continue;
@@ -1222,6 +1221,61 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
                snd_pcm_period_elapsed(subs->pcm_substream);
 }
 
+static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs,
+                                            struct urb *urb, unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+       unsigned int stride = runtime->frame_bits >> 3;
+       unsigned int dst_idx = 0;
+       unsigned int src_idx = subs->hwptr_done;
+       unsigned int wrap = runtime->buffer_size * stride;
+       u8 *dst = urb->transfer_buffer;
+       u8 *src = runtime->dma_area;
+       u8 marker[] = { 0x05, 0xfa };
+
+       /*
+        * The DSP DOP format defines a way to transport DSD samples over
+        * normal PCM data endpoints. It requires stuffing of marker bytes
+        * (0x05 and 0xfa, alternating per sample frame), and then expects
+        * 2 additional bytes of actual payload. The whole frame is stored
+        * LSB.
+        *
+        * Hence, for a stereo transport, the buffer layout looks like this,
+        * where L refers to left channel samples and R to right.
+        *
+        *   L1 L2 0x05   R1 R2 0x05   L3 L4 0xfa  R3 R4 0xfa
+        *   L5 L6 0x05   R5 R6 0x05   L7 L8 0xfa  R7 R8 0xfa
+        *   .....
+        *
+        */
+
+       while (bytes--) {
+               if (++subs->dsd_dop.byte_idx == 3) {
+                       /* frame boundary? */
+                       dst[dst_idx++] = marker[subs->dsd_dop.marker];
+                       src_idx += 2;
+                       subs->dsd_dop.byte_idx = 0;
+
+                       if (++subs->dsd_dop.channel % runtime->channels == 0) {
+                               /* alternate the marker */
+                               subs->dsd_dop.marker++;
+                               subs->dsd_dop.marker %= ARRAY_SIZE(marker);
+                               subs->dsd_dop.channel = 0;
+                       }
+               } else {
+                       /* stuff the DSD payload */
+                       int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap;
+
+                       if (subs->cur_audiofmt->dsd_bitrev)
+                               dst[dst_idx++] = bitrev8(src[idx]);
+                       else
+                               dst[dst_idx++] = src[idx];
+
+                       subs->hwptr_done++;
+               }
+       }
+}
+
 static void prepare_playback_urb(struct snd_usb_substream *subs,
                                 struct urb *urb)
 {
@@ -1244,8 +1298,8 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
                        counts = snd_usb_endpoint_next_packet_size(ep);
 
                /* set up descriptor */
-               urb->iso_frame_desc[i].offset = frames * stride;
-               urb->iso_frame_desc[i].length = counts * stride;
+               urb->iso_frame_desc[i].offset = frames * ep->stride;
+               urb->iso_frame_desc[i].length = counts * ep->stride;
                frames += counts;
                urb->number_of_packets++;
                subs->transfer_done += counts;
@@ -1259,14 +1313,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
                                        frames -= subs->transfer_done;
                                        counts -= subs->transfer_done;
                                        urb->iso_frame_desc[i].length =
-                                               counts * stride;
+                                               counts * ep->stride;
                                        subs->transfer_done = 0;
                                }
                                i++;
                                if (i < ctx->packets) {
                                        /* add a transfer delimiter */
                                        urb->iso_frame_desc[i].offset =
-                                               frames * stride;
+                                               frames * ep->stride;
                                        urb->iso_frame_desc[i].length = 0;
                                        urb->number_of_packets++;
                                }
@@ -1274,23 +1328,43 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
                        }
                }
                if (period_elapsed &&
-                   !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+                   !snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
                        break;
        }
-       bytes = frames * stride;
-       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-               /* err, the transferred area goes over buffer boundary. */
-               unsigned int bytes1 =
-                       runtime->buffer_size * stride - subs->hwptr_done;
-               memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done, bytes1);
-               memcpy(urb->transfer_buffer + bytes1,
-                      runtime->dma_area, bytes - bytes1);
+       bytes = frames * ep->stride;
+
+       if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE &&
+                    subs->cur_audiofmt->dsd_dop)) {
+               fill_playback_urb_dsd_dop(subs, urb, bytes);
+       } else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 &&
+                          subs->cur_audiofmt->dsd_bitrev)) {
+               /* bit-reverse the bytes */
+               u8 *buf = urb->transfer_buffer;
+               for (i = 0; i < bytes; i++) {
+                       int idx = (subs->hwptr_done + i)
+                               % (runtime->buffer_size * stride);
+                       buf[i] = bitrev8(runtime->dma_area[idx]);
+               }
+
+               subs->hwptr_done += bytes;
        } else {
-               memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done, bytes);
+               /* usual PCM */
+               if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+                       /* err, the transferred area goes over buffer boundary. */
+                       unsigned int bytes1 =
+                               runtime->buffer_size * stride - subs->hwptr_done;
+                       memcpy(urb->transfer_buffer,
+                              runtime->dma_area + subs->hwptr_done, bytes1);
+                       memcpy(urb->transfer_buffer + bytes1,
+                              runtime->dma_area, bytes - bytes1);
+               } else {
+                       memcpy(urb->transfer_buffer,
+                              runtime->dma_area + subs->hwptr_done, bytes);
+               }
+
+               subs->hwptr_done += bytes;
        }
-       subs->hwptr_done += bytes;
+
        if (subs->hwptr_done >= runtime->buffer_size * stride)
                subs->hwptr_done -= runtime->buffer_size * stride;
 
@@ -1318,8 +1392,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
 {
        unsigned long flags;
        struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
-       int stride = runtime->frame_bits >> 3;
-       int processed = urb->transfer_buffer_length / stride;
+       struct snd_usb_endpoint *ep = subs->data_endpoint;
+       int processed = urb->transfer_buffer_length / ep->stride;
        int est_delay;
 
        /* ignore the delay accounting when procssed=0 is given, i.e.
index d218f76..0182ef6 100644 (file)
@@ -73,15 +73,14 @@ void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
  */
 static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
-       struct list_head *p;
+       struct audioformat *fp;
        static char *sync_types[4] = {
                "NONE", "ASYNC", "ADAPTIVE", "SYNC"
        };
 
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *fp;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
                snd_pcm_format_t fmt;
-               fp = list_entry(p, struct audioformat, list);
+
                snd_iprintf(buffer, "  Interface %d\n", fp->iface);
                snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
                snd_iprintf(buffer, "    Format:");
index c39f898..86e4b8c 100644 (file)
@@ -2748,6 +2748,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
+       USB_DEVICE(0x1235, 0x0018),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Novation",
+               .product_name = "Twitch",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000,
+                                       .rate_min = 44100,
+                                       .rate_max = 48000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000
+                                       }
+                               }
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_MIDI_RAW_BYTES
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
        USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .vendor_name = "Novation",
@@ -2996,7 +3036,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
                                        .endpoint = 0x02,
                                        .ep_attr = 0x01,
-                                       .maxpacksize = 0x130,
                                        .rates = SNDRV_PCM_RATE_44100 |
                                                 SNDRV_PCM_RATE_48000,
                                        .rate_min = 44100,
@@ -3044,7 +3083,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .attributes = 0x00,
                                        .endpoint = 0x03,
                                        .ep_attr = USB_ENDPOINT_SYNC_ASYNC,
-                                       .maxpacksize = 0x128,
                                        .rates = SNDRV_PCM_RATE_48000,
                                        .rate_min = 48000,
                                        .rate_max = 48000,
@@ -3070,7 +3108,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
                                        .endpoint = 0x85,
                                        .ep_attr = USB_ENDPOINT_SYNC_SYNC,
-                                       .maxpacksize = 0x128,
                                        .rates = SNDRV_PCM_RATE_48000,
                                        .rate_min = 48000,
                                        .rate_max = 48000,
index 9c5ab22..3879eae 100644 (file)
@@ -165,8 +165,10 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                return -EINVAL;
        }
        alts = &iface->altsetting[fp->altset_idx];
-       fp->datainterval = snd_usb_parse_datainterval(chip, alts);
-       fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+       if (fp->datainterval == 0)
+               fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+       if (fp->maxpacksize == 0)
+               fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
        usb_set_interface(chip->dev, fp->iface, 0);
        snd_usb_init_pitch(chip, fp->iface, alts, fp);
        snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max);
@@ -446,6 +448,17 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 }
 
 /*
+ * Novation Twitch DJ controller
+ */
+static int snd_usb_twitch_boot_quirk(struct usb_device *dev)
+{
+       /* preemptively set up the device because otherwise the
+        * raw MIDI endpoints are not active */
+       usb_set_interface(dev, 0, 1);
+       return 0;
+}
+
+/*
  * This call will put the synth in "USB send" mode, i.e it will send MIDI
  * messages through USB (this is disabled at startup). The synth will
  * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
@@ -746,6 +759,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
                /* Digidesign Mbox 2 */
                return snd_usb_mbox2_boot_quirk(dev);
 
+       case USB_ID(0x1235, 0x0018):
+               /* Focusrite Novation Twitch */
+               return snd_usb_twitch_boot_quirk(dev);
+
        case USB_ID(0x133e, 0x0815):
                /* Access Music VirusTI Desktop */
                return snd_usb_accessmusic_boot_quirk(dev);
@@ -837,6 +854,7 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
                break;
        }
        snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
+       subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
 }
 
 void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
@@ -875,6 +893,16 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
                ep->skip_packets = 16;
 }
 
+void snd_usb_set_interface_quirk(struct usb_device *dev)
+{
+       /*
+        * "Playback Design" products need a 50ms delay after setting the
+        * USB interface.
+        */
+       if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba)
+               mdelay(50);
+}
+
 void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
                           __u8 request, __u8 requesttype, __u16 value,
                           __u16 index, void *data, __u16 size)
@@ -888,3 +916,31 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
                mdelay(20);
 }
 
+/*
+ * snd_usb_interface_dsd_format_quirks() is called from format.c to
+ * augment the PCM format bit-field for DSD types. The UAC standards
+ * don't have a designated bit field to denote DSD-capable interfaces,
+ * hence all hardware that is known to support this format has to be
+ * listed here.
+ */
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
+                                       struct audioformat *fp,
+                                       unsigned int sample_bytes)
+{
+       /* Playback Designs */
+       if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) {
+               switch (fp->altsetting) {
+               case 1:
+                       fp->dsd_dop = true;
+                       return SNDRV_PCM_FMTBIT_DSD_U16_LE;
+               case 2:
+                       fp->dsd_bitrev = true;
+                       return SNDRV_PCM_FMTBIT_DSD_U8;
+               case 3:
+                       fp->dsd_bitrev = true;
+                       return SNDRV_PCM_FMTBIT_DSD_U16_LE;
+               }
+       }
+
+       return 0;
+}
index 0ca9e91..665e972 100644 (file)
@@ -26,8 +26,13 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
 
 void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
 
+void snd_usb_set_interface_quirk(struct usb_device *dev);
 void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
                           __u8 request, __u8 requesttype, __u16 value,
                           __u16 index, void *data, __u16 size);
 
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
+                                       struct audioformat *fp,
+                                       unsigned int sample_bytes);
+
 #endif /* __USBAUDIO_QUIRKS_H */
index ad181d5..8951f77 100644 (file)
  */
 static void free_substream(struct snd_usb_substream *subs)
 {
-       struct list_head *p, *n;
+       struct audioformat *fp, *n;
 
        if (!subs->num_formats)
                return; /* not initialized */
-       list_for_each_safe(p, n, &subs->fmt_list) {
-               struct audioformat *fp = list_entry(p, struct audioformat, list);
+       list_for_each_entry_safe(fp, n, &subs->fmt_list, list) {
                kfree(fp->rate_table);
                kfree(fp->chmap);
                kfree(fp);
@@ -94,6 +93,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
        subs->dev = as->chip->dev;
        subs->txfr_quirk = as->chip->txfr_quirk;
        subs->speed = snd_usb_get_speed(subs->dev);
+       subs->pkt_offset_adj = 0;
 
        snd_usb_set_pcm_ops(as->pcm, stream);
 
@@ -313,14 +313,12 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                             int stream,
                             struct audioformat *fp)
 {
-       struct list_head *p;
        struct snd_usb_stream *as;
        struct snd_usb_substream *subs;
        struct snd_pcm *pcm;
        int err;
 
-       list_for_each(p, &chip->pcm_list) {
-               as = list_entry(p, struct snd_usb_stream, list);
+       list_for_each_entry(as, &chip->pcm_list, list) {
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
@@ -332,8 +330,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                }
        }
        /* look for an empty stream */
-       list_for_each(p, &chip->pcm_list) {
-               as = list_entry(p, struct snd_usb_stream, list);
+       list_for_each_entry(as, &chip->pcm_list, list) {
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
@@ -463,7 +460,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
        struct usb_host_interface *alts;
        struct usb_interface_descriptor *altsd;
        int i, altno, err, stream;
-       int format = 0, num_channels = 0;
+       unsigned int format = 0, num_channels = 0;
        struct audioformat *fp = NULL;
        int num, protocol, clock = 0;
        struct uac_format_type_i_continuous_descriptor *fmt;
index 1ac3fd9..bc43bca 100644 (file)
@@ -56,6 +56,7 @@ struct snd_usb_audio {
 
        int setup;                      /* from the 'device_setup' module param */
        int nrpacks;                    /* from the 'nrpacks' module param */
+       bool autoclock;                 /* from the 'autoclock' module param */
 
        struct usb_host_interface *ctrl_intf;   /* the audio control interface */
 };