Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Feb 2013 19:34:25 +0000 (11:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Feb 2013 19:34:25 +0000 (11:34 -0800)
Pull sound updates from Takashi Iwai:
 "The biggest change in this update is the unification of HD-audio codec
  parsers.  Now the HD-audio codec is parsed in a generic parser code
  which is invoked by each HD-audio codec driver.

  Some background information is found in David Henningsson's blog
  entry:

      http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/

  Other than that, some random updates/fixes like USB-audio and a bunch
  of small AoC updates as usual.

  Highlights:

   - Unification of HD-audio parser code (aka generic parser)

   - Support of new Intel HD-audio controller, new IDT codecs

   - Fixes for HD-audio HDMI audio hotplug

   - Haswell HDMI audio fixup

   - Support of Creative CA0132 DSP code

   - A few fixes of HDSP driver

   - USB-audio fix for Roland A-PRO, M-Audio FT C600

   - Support PM for aloop driver (and fixes Oops)

   - Compress API updates for gapless playback support

  For ASoC part:

   - Support for a wider range of hardware in the compressed stream code

   - The ability to mute capture streams as well as playback streams
     while inactive

   - DT support for AK4642, FSI, Samsung I2S and WM8962

   - AC'97 support for Tegra

   - New driver for max98090, replacing the stub which was there

   - A new driver from Dialog

  Note that due to dependencies, DTification of DMA support for Samsung
  platforms (used only by the and I2S driver and SPI) is merged here as
  well."

Fix up trivial conflict in drivers/spi/spi-s3c64xx.c due to removed code
being changed.

* tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (453 commits)
  ALSA: usb: Fix Processing Unit Descriptor parsers
  ALSA: hda - hdmi: Notify userspace when ELD control changes
  ALSA: hda - hdmi: Protect ELD buffer
  ALSA: hda - hdmi: Refactor hdmi_eld into parsed_hdmi_eld
  ALSA: hda - hdmi: Do not expose eld data when eld is invalid
  ALSA: hda - hdmi: ELD shouldn't be valid after unplug
  ALSA: hda - Fix the silent speaker output on Fujitsu S7020 laptop
  ALSA: hda - add quirks for mute LED on two HP machines
  ALSA: usb/quirks, fix out-of-bounds access
  ASoC: codecs: Add da7213 codec
  ALSA: au88x0 - Define channel map for au88x0
  ALSA: compress: add support for gapless playback
  ALSA: hda - Remove speaker clicks on CX20549
  ALSA: hda - Disable runtime PM for Intel 5 Series/3400
  ALSA: hda - Increase badness for missing multi-io
  ASoC: arizona: Automatically manage input mutes
  ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts
  ALSA: hda/ca0132 - Add missing \n to debug prints
  ALSA: hda/ca0132 - Fix type of INVALID_CHIP_ADDRESS
  ALSA: hda - update documentation for no-primary-hp fixup
  ...

175 files changed:
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/devicetree/bindings/sound/ak4642.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs4271.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-twl4030.txt
Documentation/devicetree/bindings/sound/renesas,fsi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/samsung-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/wm8962.txt [new file with mode: 0644]
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sound/alsa/compress_offload.txt
arch/arm/boot/dts/exynos5250-smdk5250.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/mach-exynos/mach-exynos5-dt.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/plat-samsung/dma-ops.c
arch/arm/plat-samsung/include/plat/dma-ops.h
arch/arm/plat-samsung/s3c-dma-ops.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-se/7724/setup.c
drivers/misc/Kconfig
drivers/misc/atmel-ssc.c
drivers/spi/spi-s3c64xx.c
include/linux/mfd/arizona/pdata.h
include/sound/compress_driver.h
include/sound/core.h
include/sound/cs4271.h
include/sound/da7213.h [new file with mode: 0644]
include/sound/max98090.h [new file with mode: 0755]
include/sound/memalloc.h
include/sound/saif.h [deleted file]
include/sound/sh_fsi.h
include/sound/simple_card.h
include/sound/soc-dai.h
include/sound/soc.h
include/sound/tlv320aic3x.h
include/sound/wm2000.h
include/sound/wm2200.h
include/uapi/linux/usb/audio.h
include/uapi/sound/compress_offload.h
sound/arm/pxa2xx-ac97-lib.c
sound/core/compress_offload.c
sound/drivers/aloop.c
sound/drivers/vx/vx_core.c
sound/pci/Kconfig
sound/pci/ali5451/ali5451.c
sound/pci/atiixp.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/hda/Kconfig
sound/pci/hda/ca0132_regs.h [new file with mode: 0644]
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h [new file with mode: 0644]
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.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/ice1712/wm8766.c
sound/pci/intel8x0.c
sound/pci/maestro3.c
sound/pci/nm256/nm256.c
sound/pci/pcxhr/pcxhr_core.c
sound/pci/rme32.c
sound/pci/rme9652/hdsp.c
sound/pci/via82xx.c
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-pcm-pdc.c
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ak4642.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/da7213.c [new file with mode: 0644]
sound/soc/codecs/da7213.h [new file with mode: 0644]
sound/soc/codecs/max98090.c [changed mode: 0644->0755]
sound/soc/codecs/max98090.h [new file with mode: 0755]
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wmfw.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/imx-audmux.c
sound/soc/generic/simple-card.c
sound/soc/mxs/mxs-saif.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/n810.c
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-twl4030.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/rx51.c
sound/soc/omap/sdp3430.c [deleted file]
sound/soc/omap/zoom2.c [deleted file]
sound/soc/pxa/palm27x.c
sound/soc/samsung/Kconfig
sound/soc/samsung/dma.c
sound/soc/samsung/dma.h
sound/soc/samsung/i2s.c
sound/soc/samsung/i2s.h
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/sh/fsi.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra20_ac97.c [new file with mode: 0644]
sound/soc/tegra/tegra20_ac97.h [new file with mode: 0644]
sound/soc/tegra/tegra20_das.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_wm9712.c [new file with mode: 0644]
sound/soc/ux500/mop500.c
sound/usb/caiaq/device.c
sound/usb/card.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c

index fb32aea..bd6fee2 100644 (file)
       <para>
       This function itself doesn't allocate the data space. The data
       must be allocated manually beforehand, and its pointer is passed
-      as the argument. This pointer is used as the
-      (<parameter>chip</parameter> identifier in the above example)
-      for the instance. 
+      as the argument. This pointer (<parameter>chip</parameter> in the
+      above example) is used as the identifier for the instance.
       </para>
 
       <para>
@@ -2304,7 +2303,7 @@ struct _snd_pcm_runtime {
         <constant>SNDRV_PCM_INFO_XXX</constant>. Here, at least, you
         have to specify whether the mmap is supported and which
         interleaved format is supported.
-        When the is supported, add the
+        When the hardware supports mmap, add the
         <constant>SNDRV_PCM_INFO_MMAP</constant> flag here. When the
         hardware supports the interleaved or the non-interleaved
         formats, <constant>SNDRV_PCM_INFO_INTERLEAVED</constant> or
@@ -2898,7 +2897,7 @@ struct _snd_pcm_runtime {
 
         <para>
           When the pcm supports the pause operation (given in the info
-        field of the hardware table), the <constant>PAUSE_PUSE</constant>
+        field of the hardware table), the <constant>PAUSE_PUSH</constant>
         and <constant>PAUSE_RELEASE</constant> commands must be
         handled here, too. The former is the command to pause the pcm,
         and the latter to restart the pcm again. 
@@ -3085,7 +3084,7 @@ struct _snd_pcm_runtime {
       <section id="pcm-interface-interrupt-handler-timer">
         <title>High frequency timer interrupts</title>
         <para>
-       This happense when the hardware doesn't generate interrupts
+       This happens when the hardware doesn't generate interrupts
         at the period boundary but issues timer interrupts at a fixed
         timer rate (e.g. es1968 or ymfpci drivers). 
         In this case, you need to check the current hardware
@@ -3251,18 +3250,19 @@ struct _snd_pcm_runtime {
          <title>Example of Hardware Constraints for Channels</title>
          <programlisting>
 <![CDATA[
-  static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
+  static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
                                         struct snd_pcm_hw_rule *rule)
   {
           struct snd_interval *c = hw_param_interval(params,
-                SNDRV_PCM_HW_PARAM_CHANNELS);
+                        SNDRV_PCM_HW_PARAM_CHANNELS);
           struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-          struct snd_mask fmt;
+          struct snd_interval ch;
 
-          snd_mask_any(&fmt);    /* Init the struct */
-          if (c->min < 2) {
-                  fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
-                  return snd_mask_refine(f, &fmt);
+          snd_interval_any(&ch);
+          if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
+                  ch.min = ch.max = 1;
+                  ch.integer = 1;
+                  return snd_interval_refine(c, &ch);
           }
           return 0;
   }
@@ -3278,35 +3278,35 @@ struct _snd_pcm_runtime {
         <programlisting>
 <![CDATA[
   snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                      hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-                      -1);
+                      hw_rule_channels_by_format, NULL,
+                      SNDRV_PCM_HW_PARAM_FORMAT, -1);
 ]]>
           </programlisting>
         </informalexample>
       </para>
 
       <para>
-        The rule function is called when an application sets the number of
-        channels. But an application can set the format before the number of
-        channels. Thus you also need to define the inverse rule:
+        The rule function is called when an application sets the PCM
+       format, and it refines the number of channels accordingly.
+        But an application may set the number of channels before
+       setting the format. Thus you also need to define the inverse rule:
 
        <example>
-        <title>Example of Hardware Constraints for Channels</title>
+        <title>Example of Hardware Constraints for Formats</title>
         <programlisting>
 <![CDATA[
-  static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
+  static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
                                         struct snd_pcm_hw_rule *rule)
   {
           struct snd_interval *c = hw_param_interval(params,
-                        SNDRV_PCM_HW_PARAM_CHANNELS);
+                SNDRV_PCM_HW_PARAM_CHANNELS);
           struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-          struct snd_interval ch;
+          struct snd_mask fmt;
 
-          snd_interval_any(&ch);
-          if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
-                  ch.min = ch.max = 1;
-                  ch.integer = 1;
-                  return snd_interval_refine(c, &ch);
+          snd_mask_any(&fmt);    /* Init the struct */
+          if (c->min < 2) {
+                  fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
+                  return snd_mask_refine(f, &fmt);
           }
           return 0;
   }
@@ -3321,8 +3321,8 @@ struct _snd_pcm_runtime {
         <programlisting>
 <![CDATA[
   snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-                      hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                      -1);
+                      hw_rule_format_by_channels, NULL,
+                      SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 ]]>
           </programlisting>
         </informalexample>
diff --git a/Documentation/devicetree/bindings/sound/ak4642.txt b/Documentation/devicetree/bindings/sound/ak4642.txt
new file mode 100644 (file)
index 0000000..623d4e7
--- /dev/null
@@ -0,0 +1,17 @@
+AK4642 I2C transmitter
+
+This device supports I2C mode only.
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
+  - reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+       ak4648: ak4648@0x12 {
+               compatible = "asahi-kasei,ak4642";
+               reg = <0x12>;
+       };
+};
index a850fb9..e2cd1d7 100644 (file)
@@ -20,6 +20,18 @@ Optional properties:
                !RESET pin
  - cirrus,amuteb-eq-bmutec:    When given, the Codec's AMUTEB=BMUTEC flag
                                is enabled.
+ - cirrus,enable-soft-reset:
+       The CS4271 requires its LRCLK and MCLK to be stable before its RESET
+       line is de-asserted. That also means that clocks cannot be changed
+       without putting the chip back into hardware reset, which also requires
+       a complete re-initialization of all registers.
+
+       One (undocumented) workaround is to assert and de-assert the PDN bit
+       in the MODE2 register. This workaround can be enabled with this DT
+       property.
+
+       Note that this is not needed in case the clocks are stable
+       throughout the entire runtime of the codec.
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt
new file mode 100644 (file)
index 0000000..be35d34
--- /dev/null
@@ -0,0 +1,51 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm9712"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM9712's pins, and the jacks on the board:
+
+  WM9712 pins:
+
+  * MONOOUT
+  * HPOUTL
+  * HPOUTR
+  * LOUT2
+  * ROUT2
+  * OUT3
+  * LINEINL
+  * LINEINR
+  * PHONE
+  * PCBEEP
+  * MIC1
+  * MIC2
+  * Mic Bias
+
+  Board connectors:
+
+  * Headphone
+  * LineIn
+  * Mic
+
+- nvidia,ac97-controller : The phandle of the Tegra AC97 controller
+
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-wm9712-colibri_t20",
+                        "nvidia,tegra-audio-wm9712";
+       nvidia,model = "Toradex Colibri T20";
+
+       nvidia,audio-routing =
+               "Headphone", "HPOUTL",
+               "Headphone", "HPOUTR",
+               "LineIn", "LINEINL",
+               "LineIn", "LINEINR",
+               "Mic", "MIC1";
+
+       nvidia,ac97-controller = <&ac97>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt
new file mode 100644 (file)
index 0000000..c145497
--- /dev/null
@@ -0,0 +1,22 @@
+NVIDIA Tegra 20 AC97 controller
+
+Required properties:
+- compatible : "nvidia,tegra20-ac97"
+- reg : Should contain AC97 controller registers location and length
+- interrupts : Should contain AC97 interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+  request selector for the AC97 controller
+- nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number
+  of the GPIO used to reset the external AC97 codec
+- nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number
+  of the GPIO corresponding with the AC97 DAP _FS line
+Example:
+
+ac97@70002000 {
+       compatible = "nvidia,tegra20-ac97";
+       reg = <0x70002000 0x200>;
+       interrupts = <0 81 0x04>;
+       nvidia,dma-request-selector = <&apbdma 12>;
+       nvidia,codec-reset-gpio = <&gpio 170 0>;
+       nvidia,codec-sync-gpio = <&gpio 120 0>;
+};
index 6fae51c..1ab6bc8 100644 (file)
@@ -6,6 +6,52 @@ Required properties:
 - ti,mcbsp: phandle for the McBSP node
 - ti,codec: phandle for the twl4030 audio node
 
+Optional properties:
+- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl
+- ti, jack-det-gpio: Jack detect GPIO
+- ti,audio-routing: List of connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source.
+  If the routing is not provided all possible connection will be available
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earpiece Spk
+ * Handsfree Spk
+ * Ext Spk
+ * Main Mic
+ * Sub Mic
+ * Headset Mic
+ * Carkit Mic
+ * Digital0 Mic
+ * Digital1 Mic
+ * Line In
+
+twl4030 pins:
+ * HSOL
+ * HSOR
+ * EARPIECE
+ * HFL
+ * HFR
+ * PREDRIVEL
+ * PREDRIVER
+ * CARKITL
+ * CARKITR
+ * MAINMIC
+ * SUBMIC
+ * HSMIC
+ * DIGIMIC0
+ * DIGIMIC1
+ * CARKITMIC
+ * AUXL
+ * AUXR
+
+ * Headset Mic Bias
+ * Mic Bias 1 /* Used for Main Mic or Digimic0 */
+ * Mic Bias 2 /* Used for Sub Mic or Digimic1 */
+
 Example:
 
 sound {
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
new file mode 100644 (file)
index 0000000..c5be003
--- /dev/null
@@ -0,0 +1,26 @@
+Renesas FSI
+
+Required properties:
+- compatible                   : "renesas,sh_fsi2" or "renesas,sh_fsi"
+- reg                          : Should contain the register physical address and length
+- interrupts                   : Should contain FSI interrupt
+
+- fsia,spdif-connection                : FSI is connected by S/PDFI
+- fsia,stream-mode-support     : FSI supports 16bit stream mode.
+- fsia,use-internal-clock      : FSI uses internal clock when master mode.
+
+- fsib,spdif-connection                : same as fsia
+- fsib,stream-mode-support     : same as fsia
+- fsib,use-internal-clock      : same as fsia
+
+Example:
+
+sh_fsi2: sh_fsi2@0xec230000 {
+       compatible = "renesas,sh_fsi2";
+       reg = <0xec230000 0x400>;
+       interrupts = <0 146 0x4>;
+
+       fsia,spdif-connection;
+       fsia,stream-mode-support;
+       fsia,use-internal-clock;
+};
diff --git a/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt b/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt
new file mode 100644 (file)
index 0000000..4686646
--- /dev/null
@@ -0,0 +1,14 @@
+Samsung SMDK audio complex
+
+Required properties:
+- compatible : "samsung,smdk-wm8994"
+- samsung,i2s-controller: The phandle of the Samsung I2S0 controller
+- samsung,audio-codec: The phandle of the WM8994 audio codec
+Example:
+
+sound {
+               compatible = "samsung,smdk-wm8994";
+
+               samsung,i2s-controller = <&i2s0>;
+               samsung,audio-codec = <&wm8994>;
+};
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
new file mode 100644 (file)
index 0000000..3070046
--- /dev/null
@@ -0,0 +1,63 @@
+* Samsung I2S controller
+
+Required SoC Specific Properties:
+
+- compatible : "samsung,i2s-v5"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- dmas: list of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: identifier string for each DMA request line in the dmas property.
+  These strings correspond 1:1 with the ordered pairs in dmas.
+
+Optional SoC Specific Properties:
+
+- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
+  support, this flag is enabled.
+- samsung,supports-rstclr: This flag should be set if I2S software reset bit
+  control is required. When this flag is set I2S software reset bit will be
+  enabled or disabled based on need.
+- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
+  then this flag is enabled.
+- samsung,idma-addr: Internal DMA register base address of the audio
+  sub system(used in secondary sound source).
+
+Required Board Specific Properties:
+
+- gpios: The gpio specifier for data out,data in, LRCLK, CDCLK and SCLK
+  interface lines. The format of the gpio specifier depends on the gpio
+  controller.
+  The syntax of samsung gpio specifier is
+       <[phandle of the gpio controller node]
+        [pin number within the gpio controller]
+        [mux function]
+        [flags and pull up/down]
+        [drive strength]>
+
+Example:
+
+- SoC Specific Portion:
+
+i2s@03830000 {
+       compatible = "samsung,i2s-v5";
+       reg = <0x03830000 0x100>;
+       dmas = <&pdma0 10
+               &pdma0 9
+               &pdma0 8>;
+       dma-names = "tx", "rx", "tx-sec";
+       samsung,supports-6ch;
+       samsung,supports-rstclr;
+       samsung,supports-secdai;
+       samsung,idma-addr = <0x03000000>;
+};
+
+- Board Specific Portion:
+
+i2s@03830000 {
+       gpios = <&gpz 0 2 0 0>, /* I2S_0_SCLK */
+               <&gpz 1 2 0 0>, /* I2S_0_CDCLK */
+               <&gpz 2 2 0 0>, /* I2S_0_LRCK */
+               <&gpz 3 2 0 0>, /* I2S_0_SDI */
+               <&gpz 4 2 0 0>, /* I2S_0_SDO[1] */
+               <&gpz 5 2 0 0>, /* I2S_0_SDO[2] */
+               <&gpz 6 2 0 0>; /* I2S_0_SDO[3] */
+};
index e7b98f4..f47c3f5 100644 (file)
@@ -11,6 +11,12 @@ Optional properties:
 
 - gpio-reset - gpio pin number used for codec reset
 - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+- ai3x-micbias-vg - MicBias Voltage required.
+       1 - MICBIAS output is powered to 2.0V,
+       2 - MICBIAS output is powered to 2.5V,
+       3 - MICBIAS output is connected to AVDD,
+       If this node is not mentioned or if the value is incorrect, then MicBias
+       is powered down.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/wm8962.txt b/Documentation/devicetree/bindings/sound/wm8962.txt
new file mode 100644 (file)
index 0000000..dceb3b1
--- /dev/null
@@ -0,0 +1,16 @@
+WM8962 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "wlf,wm8962"
+
+  - reg : the I2C address of the device.
+
+Example:
+
+codec: wm8962@1a {
+       compatible = "wlf,wm8962";
+       reg = <0x1a>;
+};
index b9cfd33..ce6581c 100644 (file)
@@ -890,8 +890,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
     power_save - Automatic power-saving timeout (in second, 0 =
                disable)
-    power_save_controller - Reset HD-audio controller in power-saving mode
-               (default = on)
+    power_save_controller - Support runtime D3 of HD-audio controller
+               (-1 = on for supported chip (default), false = off,
+                true = force to on even for unsupported hardware)
     align_buffer_size - Force rounding of buffer/period sizes to multiples
                      of 128 bytes. This is more efficient in terms of memory
                      access but isn't required by the HDA spec and prevents
index 16dfe57..bb8b0dc 100644 (file)
@@ -53,7 +53,7 @@ ALC882/883/885/888/889
   acer-aspire-8930g    Acer Aspire 8330G/6935G
   acer-aspire          Acer Aspire others
   inv-dmic     Inverted internal mic workaround
-  no-primary-hp                VAIO Z workaround (for fixed speaker DAC)
+  no-primary-hp                VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
 
 ALC861/660
 ==========
index 7813c06..d4faa63 100644 (file)
@@ -176,14 +176,14 @@ support the automatic probing (yet as of 2.6.28).  And, BIOS is often,
 yes, pretty often broken.  It sets up wrong values and screws up the
 driver.
 
-The preset model is provided basically to overcome such a situation.
-When the matching preset model is found in the white-list, the driver
-assumes the static configuration of that preset and builds the mixer
-elements and PCM streams based on the static information.  Thus, if
-you have a newer machine with a slightly different PCI SSID from the
-existing one, you may have a good chance to re-use the same model.
-You can pass the `model` option to specify the preset model instead of
-PCI SSID look-up.
+The preset model (or recently called as "fix-up") is provided
+basically to overcome such a situation.  When the matching preset
+model is found in the white-list, the driver assumes the static
+configuration of that preset with the correct pin setup, etc.
+Thus, if you have a newer machine with a slightly different PCI SSID
+(or codec SSID) from the existing one, you may have a good chance to
+re-use the same model.  You can pass the `model` option to specify the
+preset model instead of PCI (and codec-) SSID look-up.
 
 What `model` option values are available depends on the codec chip.
 Check your codec chip from the codec proc file (see "Codec Proc-File"
@@ -199,17 +199,12 @@ non-working HD-audio hardware is to check HD-audio codec and several
 different `model` option values.  If you have any luck, some of them
 might suit with your device well.
 
-Some codecs such as ALC880 have a special model option `model=test`.
-This configures the driver to provide as many mixer controls as
-possible for every single pin feature except for the unsolicited
-events (and maybe some other specials).  Adjust each mixer element and
-try the I/O in the way of trial-and-error until figuring out the whole
-I/O pin mappings.
+There are a few special model option values:
+- when 'nofixup' is passed, the device-specific fixups in the codec
+  parser are skipped.
+- when `generic` is passed, the codec-specific parser is skipped and
+  only the generic parser is used.
 
-Note that `model=generic` has a special meaning.  It means to use the
-generic parser regardless of the codec.  Usually the codec-specific
-parser is much better than the generic parser (as now).  Thus this
-option is more about the debugging purpose.
 
 Speaker and Headphone Output
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -387,9 +382,8 @@ init_verbs::
   (separated with a space).
 hints::
   Shows / stores hint strings for codec parsers for any use.
-  Its format is `key = value`.  For example, passing `hp_detect = yes`
-  to IDT/STAC codec parser will result in the disablement of the
-  headphone detection.
+  Its format is `key = value`.  For example, passing `jack_detect = no`
+  will disable the jack detection of the machine completely.
 init_pin_configs::
   Shows the initial pin default config values set by BIOS.
 driver_pin_configs::
@@ -421,6 +415,61 @@ re-configure based on that state, run like below:
 ------------------------------------------------------------------------
 
 
+Hint Strings
+~~~~~~~~~~~~
+The codec parser have several switches and adjustment knobs for
+matching better with the actual codec or device behavior.  Many of
+them can be adjusted dynamically via "hints" strings as mentioned in
+the section above.  For example, by passing `jack_detect = no` string
+via sysfs or a patch file, you can disable the jack detection, thus
+the codec parser will skip the features like auto-mute or mic
+auto-switch.  As a boolean value, either `yes`, `no`, `true`, `false`,
+`1` or `0` can be passed.
+
+The generic parser supports the following hints:
+
+- jack_detect (bool): specify whether the jack detection is available
+  at all on this machine; default true
+- inv_jack_detect (bool): indicates that the jack detection logic is
+  inverted
+- trigger_sense (bool): indicates that the jack detection needs the
+  explicit call of AC_VERB_SET_PIN_SENSE verb
+- inv_eapd (bool): indicates that the EAPD is implemented in the
+  inverted logic
+- pcm_format_first (bool): sets the PCM format before the stream tag
+  and channel ID
+- sticky_stream (bool): keep the PCM format, stream tag and ID as long
+  as possible; default true
+- spdif_status_reset (bool): reset the SPDIF status bits at each time
+  the SPDIF stream is set up
+-  pin_amp_workaround (bool): the output pin may have multiple amp
+  values
+- single_adc_amp (bool): ADCs can have only single input amps
+- auto_mute (bool): enable/disable the headphone auto-mute feature;
+  default true
+- auto_mic (bool): enable/disable the mic auto-switch feature; default
+  true
+- line_in_auto_switch (bool): enable/disable the line-in auto-switch
+  feature; default false
+- need_dac_fix (bool): limits the DACs depending on the channel count
+- primary_hp (bool): probe headphone jacks as the primary outputs;
+  default true
+- multi_cap_vol (bool): provide multiple capture volumes
+- inv_dmic_split (bool): provide split internal mic volume/switch for
+  phase-inverted digital mics
+- indep_hp (bool): provide the independent headphone PCM stream and
+  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
+- power_down_unused (bool): power down the unused widgets
+- mixer_nid (int): specifies the widget NID of the analog-loopback
+  mixer
+
+
 Early Patching
 ~~~~~~~~~~~~~~
 When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
@@ -445,7 +494,7 @@ A patch file is a plain text file which looks like below:
   0x20 0x400 0xff
 
   [hint]
-  hp_detect = yes
+  jack_detect = no
 ------------------------------------------------------------------------
 
 The file needs to have a line `[codec]`.  The next line should contain
@@ -531,6 +580,13 @@ cable is unplugged.  Thus, if you hear noises, suspect first the
 power-saving.  See /sys/module/snd_hda_intel/parameters/power_save to
 check the current value.  If it's non-zero, the feature is turned on.
 
+The recent kernel supports the runtime PM for the HD-audio controller
+chip, too.  It means that the HD-audio controller is also powered up /
+down dynamically.  The feature is enabled only for certain controller
+chips like Intel LynxPoint.  You can enable/disable this feature
+forcibly by setting `power_save_controller` option, which is also
+available at /sys/module/snd_hda_intel/parameters directory.
+
 
 Tracepoints
 ~~~~~~~~~~~
@@ -587,8 +643,9 @@ The latest development codes for HD-audio are found on sound git tree:
 - git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 
 The master branch or for-next branches can be used as the main
-development branches in general while the HD-audio specific patches
-are committed in topic/hda branch.
+development branches in general while the development for the current
+and next kernels are found in for-linus and for-next branches,
+respectively.
 
 If you are using the latest Linus tree, it'd be better to pull the
 above GIT tree onto it.  If you are using the older kernels, an easy
@@ -699,7 +756,11 @@ won't be always updated.  For example, the volume values are usually
 cached in the driver, and thus changing the widget amp value directly
 via hda-verb won't change the mixer value.
 
-The hda-verb program is found in the ftp directory:
+The hda-verb program is included now in alsa-tools:
+
+- git://git.alsa-project.org/alsa-tools.git
+
+Also, the old stand-alone package is found in the ftp directory:
 
 - ftp://ftp.suse.com/pub/people/tiwai/misc/
 
@@ -777,3 +838,18 @@ A git repository is available:
 
 See README file in the tarball for more details about hda-emu
 program.
+
+
+hda-jack-retask
+~~~~~~~~~~~~~~~
+hda-jack-retask is a user-friendly GUI program to manipulate the
+HD-audio pin control for jack retasking.  If you have a problem about
+the jack assignment, try this program and check whether you can get
+useful results.  Once when you figure out the proper pin assignment,
+it can be fixed either in the driver code statically or via passing a
+firmware patch file (see "Early Patching" section).
+
+The program is included in alsa-tools now:
+
+- git://git.alsa-project.org/alsa-tools.git
+
index 90e9b3a..0bcc551 100644 (file)
@@ -145,6 +145,52 @@ Modifications include:
 - Addition of encoding options when required (derived from OpenMAX IL)
 - Addition of rateControlSupported (missing in OpenMAX AL)
 
+Gapless Playback
+================
+When playing thru an album, the decoders have the ability to skip the encoder
+delay and padding and directly move from one track content to another. The end
+user can perceive this as gapless playback as we dont have silence while
+switching from one track to another
+
+Also, there might be low-intensity noises due to encoding. Perfect gapless is
+difficult to reach with all types of compressed data, but works fine with most
+music content. The decoder needs to know the encoder delay and encoder padding.
+So we need to pass this to DSP. This metadata is extracted from ID3/MP4 headers
+and are not present by default in the bitstream, hence the need for a new
+interface to pass this information to the DSP. Also DSP and userspace needs to
+switch from one track to another and start using data for second track.
+
+The main additions are:
+
+- set_metadata
+This routine sets the encoder delay and encoder padding. This can be used by
+decoder to strip the silence. This needs to be set before the data in the track
+is written.
+
+- set_next_track
+This routine tells DSP that metadata and write operation sent after this would
+correspond to subsequent track
+
+- partial drain
+This is called when end of file is reached. The userspace can inform DSP that
+EOF is reached and now DSP can start skipping padding delay. Also next write
+data would belong to next track
+
+Sequence flow for gapless would be:
+- Open
+- Get caps / codec caps
+- Set params
+- Set metadata of the first track
+- Fill data of the first track
+- Trigger start
+- User-space finished sending all,
+- Indicaite next track data by sending set_next_track
+- Set metadata of the next track
+- then call partial_drain to flush most of buffer in DSP
+- Fill data of the next track
+- DSP switches to second track
+(note: order for partial_drain and write for next track can be reversed as well)
+
 Not supported:
 
 - Support for VoIP/circuit-switched calls is not the target of this
index e05b18f..4db9db0 100644 (file)
                        compatible = "samsung,s524ad0xd1";
                        reg = <0x51>;
                };
+
+               wm8994: wm8994@1a {
+                        compatible = "wlf,wm8994";
+                        reg = <0x1a>;
+               };
        };
 
        i2c@121D0000 {
                samsung,mfc-r = <0x43000000 0x800000>;
                samsung,mfc-l = <0x51000000 0x800000>;
        };
+
+       i2s0: i2s@03830000 {
+               gpios = <&gpz 0 2 0 0>, <&gpz 1 2 0 0>, <&gpz 2 2 0 0>,
+                       <&gpz 3 2 0 0>, <&gpz 4 2 0 0>, <&gpz 5 2 0 0>,
+                       <&gpz 6 2 0 0>;
+       };
+
+       i2s1: i2s@12D60000 {
+               status = "disabled";
+       };
+
+       i2s2: i2s@12D70000 {
+               status = "disabled";
+       };
+
+       sound {
+               compatible = "samsung,smdk-wm8994";
+
+               samsung,i2s-controller = <&i2s0>;
+               samsung,audio-codec = <&wm8994>;
+       };
 };
index 3acf594..f50b4e8 100644 (file)
                compatible = "samsung,exynos4210-spi";
                reg = <0x12d20000 0x100>;
                interrupts = <0 66 0>;
-               tx-dma-channel = <&pdma0 5>; /* preliminary */
-               rx-dma-channel = <&pdma0 4>; /* preliminary */
+               dmas = <&pdma0 5
+                       &pdma0 4>;
+               dma-names = "tx", "rx";
                #address-cells = <1>;
                #size-cells = <0>;
        };
                compatible = "samsung,exynos4210-spi";
                reg = <0x12d30000 0x100>;
                interrupts = <0 67 0>;
-               tx-dma-channel = <&pdma1 5>; /* preliminary */
-               rx-dma-channel = <&pdma1 4>; /* preliminary */
+               dmas = <&pdma1 5
+                       &pdma1 4>;
+               dma-names = "tx", "rx";
                #address-cells = <1>;
                #size-cells = <0>;
        };
                compatible = "samsung,exynos4210-spi";
                reg = <0x12d40000 0x100>;
                interrupts = <0 68 0>;
-               tx-dma-channel = <&pdma0 7>; /* preliminary */
-               rx-dma-channel = <&pdma0 6>; /* preliminary */
+               dmas = <&pdma0 7
+                       &pdma0 6>;
+               dma-names = "tx", "rx";
                #address-cells = <1>;
                #size-cells = <0>;
        };
                #size-cells = <0>;
        };
 
+       i2s0: i2s@03830000 {
+               compatible = "samsung,i2s-v5";
+               reg = <0x03830000 0x100>;
+               dmas = <&pdma0 10
+                       &pdma0 9
+                       &pdma0 8>;
+               dma-names = "tx", "rx", "tx-sec";
+               samsung,supports-6ch;
+               samsung,supports-rstclr;
+               samsung,supports-secdai;
+               samsung,idma-addr = <0x03000000>;
+       };
+
+       i2s1: i2s@12D60000 {
+               compatible = "samsung,i2s-v5";
+               reg = <0x12D60000 0x100>;
+               dmas = <&pdma1 12
+                       &pdma1 11>;
+               dma-names = "tx", "rx";
+       };
+
+       i2s2: i2s@12D70000 {
+               compatible = "samsung,i2s-v5";
+               reg = <0x12D70000 0x100>;
+               dmas = <&pdma0 12
+                       &pdma0 11>;
+               dma-names = "tx", "rx";
+       };
+
        amba {
                #address-cells = <1>;
                #size-cells = <1>;
index e99d3d8..ea9e302 100644 (file)
@@ -104,6 +104,12 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
        OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL),
        OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000,
                                "exynos-tmu", NULL),
+       OF_DEV_AUXDATA("samsung,i2s-v5", 0x03830000,
+                               "samsung-i2s.0", NULL),
+       OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D60000,
+                               "samsung-i2s.1", NULL),
+       OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D70000,
+                               "samsung-i2s.2", NULL),
        {},
 };
 
index 616cb87..69985b0 100644 (file)
@@ -53,17 +53,25 @@ static unsigned long ac97_reset_config[] = {
        GPIO95_AC97_nRESET,
 };
 
-void pxa27x_assert_ac97reset(int reset_gpio, int on)
+void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
 {
+       /*
+        * This helper function is used to work around a bug in the pxa27x's
+        * ac97 controller during a warm reset.  The configuration of the
+        * reset_gpio is changed as follows:
+        * to_gpio == true: configured to generic output gpio and driven high
+        * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET
+        */
+
        if (reset_gpio == 113)
-               pxa2xx_mfp_config(on ? &ac97_reset_config[0] :
-                                      &ac97_reset_config[1], 1);
+               pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] :
+                                 &ac97_reset_config[1], 1);
 
        if (reset_gpio == 95)
-               pxa2xx_mfp_config(on ? &ac97_reset_config[2] :
-                                      &ac97_reset_config[3], 1);
+               pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] :
+                                 &ac97_reset_config[3], 1);
 }
-EXPORT_SYMBOL_GPL(pxa27x_assert_ac97reset);
+EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
 
 /* Crystal clock: 13MHz */
 #define BASE_CLK       13000000
index 99ef190..08294fa 100644 (file)
@@ -657,14 +657,8 @@ static struct platform_device lcdc_device = {
 /* FSI */
 #define IRQ_FSI                evt2irq(0x1840)
 static struct sh_fsi_platform_info fsi_info = {
-       .port_a = {
-               .flags          = SH_FSI_BRS_INV,
-       },
        .port_b = {
-               .flags          = SH_FSI_BRS_INV |
-                                 SH_FSI_BRM_INV |
-                                 SH_FSI_LRS_INV |
-                                 SH_FSI_CLK_CPG |
+               .flags          = SH_FSI_CLK_CPG |
                                  SH_FSI_FMT_SPDIF,
        },
 };
@@ -692,21 +686,21 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
-       .fmt            = SND_SOC_DAIFMT_LEFT_J,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
-       .sysclk         = 11289600,
-};
-
 static struct asoc_simple_card_info fsi2_ak4643_info = {
        .name           = "AK4643",
        .card           = "FSI2A-AK4643",
-       .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0013",
        .platform       = "sh_fsi2",
-       .codec_dai      = "ak4642-hifi",
-       .init           = &fsi2_ak4643_init_info,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .cpu_dai = {
+               .name   = "fsia-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS,
+       },
+       .codec_dai = {
+               .name   = "ak4642-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+               .sysclk = 11289600,
+       },
 };
 
 static struct platform_device fsi_ak4643_device = {
@@ -815,18 +809,18 @@ static struct platform_device lcdc1_device = {
        },
 };
 
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
-};
-
 static struct asoc_simple_card_info fsi2_hdmi_info = {
        .name           = "HDMI",
        .card           = "FSI2B-HDMI",
-       .cpu_dai        = "fsib-dai",
        .codec          = "sh-mobile-hdmi",
        .platform       = "sh_fsi2",
-       .codec_dai      = "sh_mobile_hdmi-hifi",
-       .init           = &fsi2_hdmi_init_info,
+       .cpu_dai = {
+               .name   = "fsib-dai",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
+       },
+       .codec_dai = {
+               .name   = "sh_mobile_hdmi-hifi",
+       },
 };
 
 static struct platform_device fsi_hdmi_device = {
index 5353adf..0679ca6 100644 (file)
@@ -806,21 +806,21 @@ static struct platform_device fsi_device = {
 };
 
 /* FSI-WM8978 */
-static struct asoc_simple_dai_init_info fsi_wm8978_init_info = {
-       .fmt            = SND_SOC_DAIFMT_I2S,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
-       .sysclk         = 12288000,
-};
-
 static struct asoc_simple_card_info fsi_wm8978_info = {
        .name           = "wm8978",
        .card           = "FSI2A-WM8978",
-       .cpu_dai        = "fsia-dai",
        .codec          = "wm8978.0-001a",
        .platform       = "sh_fsi2",
-       .codec_dai      = "wm8978-hifi",
-       .init           = &fsi_wm8978_init_info,
+       .daifmt         = SND_SOC_DAIFMT_I2S,
+       .cpu_dai = {
+               .name   = "fsia-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+       },
+       .codec_dai = {
+               .name   = "wm8978-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
+               .sysclk = 12288000,
+       },
 };
 
 static struct platform_device fsi_wm8978_device = {
@@ -832,18 +832,18 @@ static struct platform_device fsi_wm8978_device = {
 };
 
 /* FSI-HDMI */
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
-};
-
 static struct asoc_simple_card_info fsi2_hdmi_info = {
        .name           = "HDMI",
        .card           = "FSI2B-HDMI",
-       .cpu_dai        = "fsib-dai",
        .codec          = "sh-mobile-hdmi",
        .platform       = "sh_fsi2",
-       .codec_dai      = "sh_mobile_hdmi-hifi",
-       .init           = &fsi2_hdmi_init_info,
+       .cpu_dai = {
+               .name   = "fsib-dai",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+       },
+       .codec_dai = {
+               .name = "sh_mobile_hdmi-hifi",
+       },
 };
 
 static struct platform_device fsi_hdmi_device = {
index c02448d..f41b71e 100644 (file)
@@ -525,21 +525,21 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = {
-       .fmt            = SND_SOC_DAIFMT_LEFT_J,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
-       .sysclk         = 11289600,
-};
-
 static struct asoc_simple_card_info fsi2_ak4648_info = {
        .name           = "AK4648",
        .card           = "FSI2A-AK4648",
-       .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0012",
        .platform       = "sh_fsi2",
-       .codec_dai      = "ak4642-hifi",
-       .init           = &fsi2_ak4648_init_info,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .cpu_dai = {
+               .name   = "fsia-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS,
+       },
+       .codec_dai = {
+               .name   = "ak4642-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+               .sysclk = 11289600,
+       },
 };
 
 static struct platform_device fsi_ak4648_device = {
index 2fed62f..3fd716d 100644 (file)
@@ -502,18 +502,18 @@ static struct platform_device hdmi_lcdc_device = {
        },
 };
 
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
-};
-
 static struct asoc_simple_card_info fsi2_hdmi_info = {
        .name           = "HDMI",
        .card           = "FSI2B-HDMI",
-       .cpu_dai        = "fsib-dai",
        .codec          = "sh-mobile-hdmi",
        .platform       = "sh_fsi2",
-       .codec_dai      = "sh_mobile_hdmi-hifi",
-       .init           = &fsi2_hdmi_init_info,
+       .cpu_dai = {
+               .name   = "fsib-dai",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
+       },
+       .codec_dai = {
+               .name   = "sh_mobile_hdmi-hifi",
+       },
 };
 
 static struct platform_device fsi_hdmi_device = {
@@ -858,16 +858,12 @@ static struct platform_device leds_device = {
 #define IRQ_FSI evt2irq(0x1840)
 static struct sh_fsi_platform_info fsi_info = {
        .port_a = {
-               .flags = SH_FSI_BRS_INV,
                .tx_id = SHDMA_SLAVE_FSIA_TX,
                .rx_id = SHDMA_SLAVE_FSIA_RX,
        },
        .port_b = {
-               .flags = SH_FSI_BRS_INV |
-                       SH_FSI_BRM_INV  |
-                       SH_FSI_LRS_INV  |
-                       SH_FSI_CLK_CPG  |
-                       SH_FSI_FMT_SPDIF,
+               .flags = SH_FSI_CLK_CPG |
+                        SH_FSI_FMT_SPDIF,
        }
 };
 
@@ -896,21 +892,21 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
-       .fmt            = SND_SOC_DAIFMT_LEFT_J,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
-       .sysclk         = 11289600,
-};
-
 static struct asoc_simple_card_info fsi2_ak4643_info = {
        .name           = "AK4643",
        .card           = "FSI2A-AK4643",
-       .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0013",
        .platform       = "sh_fsi2",
-       .codec_dai      = "ak4642-hifi",
-       .init           = &fsi2_ak4643_init_info,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .cpu_dai = {
+               .name   = "fsia-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS,
+       },
+       .codec_dai = {
+               .name   = "ak4642-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+               .sysclk = 11289600,
+       },
 };
 
 static struct platform_device fsi_ak4643_device = {
index d088afa..71d58dd 100644 (file)
@@ -19,7 +19,8 @@
 #include <mach/dma.h>
 
 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
-                               struct samsung_dma_req *param)
+                               struct samsung_dma_req *param,
+                               struct device *dev, char *ch_name)
 {
        dma_cap_mask_t mask;
        void *filter_param;
@@ -33,7 +34,12 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
         */
        filter_param = (dma_ch == DMACH_DT_PROP) ?
                (void *)param->dt_dmach_prop : (void *)dma_ch;
-       return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
+
+       if (dev->of_node)
+               return (unsigned)dma_request_slave_channel(dev, ch_name);
+       else
+               return (unsigned)dma_request_channel(mask, pl330_filter,
+                                                       filter_param);
 }
 
 static int samsung_dmadev_release(unsigned ch, void *param)
index f5144cd..1141782 100644 (file)
@@ -39,7 +39,8 @@ struct samsung_dma_config {
 };
 
 struct samsung_dma_ops {
-       unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
+       unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param,
+                               struct device *dev, char *ch_name);
        int (*release)(unsigned ch, void *param);
        int (*config)(unsigned ch, struct samsung_dma_config *param);
        int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
index f99448c..0cc40ae 100644 (file)
@@ -36,7 +36,8 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
 }
 
 static unsigned s3c_dma_request(enum dma_ch dma_ch,
-                                       struct samsung_dma_req *param)
+                               struct samsung_dma_req *param,
+                               struct device *dev, char *ch_name)
 {
        struct cb_data *data;
 
index a0fa579..aaff767 100644 (file)
@@ -887,12 +887,6 @@ static struct platform_device camera_devices[] = {
 };
 
 /* FSI */
-static struct sh_fsi_platform_info fsi_info = {
-       .port_b = {
-               .flags = SH_FSI_BRS_INV,
-       },
-};
-
 static struct resource fsi_resources[] = {
        [0] = {
                .name   = "FSI",
@@ -911,25 +905,22 @@ static struct platform_device fsi_device = {
        .id             = 0,
        .num_resources  = ARRAY_SIZE(fsi_resources),
        .resource       = fsi_resources,
-       .dev    = {
-               .platform_data  = &fsi_info,
-       },
-};
-
-static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
-       .fmt            = SND_SOC_DAIFMT_I2S,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
 };
 
 static struct asoc_simple_card_info fsi_da7210_info = {
        .name           = "DA7210",
        .card           = "FSIB-DA7210",
-       .cpu_dai        = "fsib-dai",
        .codec          = "da7210.0-001a",
        .platform       = "sh_fsi.0",
-       .codec_dai      = "da7210-hifi",
-       .init           = &fsi_da7210_init_info,
+       .daifmt         = SND_SOC_DAIFMT_I2S,
+       .cpu_dai = {
+               .name   = "fsib-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+       },
+       .codec_dai = {
+               .name   = "da7210-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+       },
 };
 
 static struct platform_device fsi_da7210_device = {
index 35f6efa..4010e63 100644 (file)
@@ -279,12 +279,6 @@ static struct platform_device ceu1_device = {
 
 /* FSI */
 /* change J20, J21, J22 pin to 1-2 connection to use slave mode */
-static struct sh_fsi_platform_info fsi_info = {
-       .port_a = {
-               .flags = SH_FSI_BRS_INV,
-       },
-};
-
 static struct resource fsi_resources[] = {
        [0] = {
                .name   = "FSI",
@@ -303,26 +297,23 @@ static struct platform_device fsi_device = {
        .id             = 0,
        .num_resources  = ARRAY_SIZE(fsi_resources),
        .resource       = fsi_resources,
-       .dev    = {
-               .platform_data  = &fsi_info,
-       },
-};
-
-static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
-       .fmt            = SND_SOC_DAIFMT_LEFT_J,
-       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
-       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
-       .sysclk         = 11289600,
 };
 
 static struct asoc_simple_card_info fsi_ak4642_info = {
        .name           = "AK4642",
        .card           = "FSIA-AK4642",
-       .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0012",
        .platform       = "sh_fsi.0",
-       .codec_dai      = "ak4642-hifi",
-       .init           = &fsi2_ak4642_init_info,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .cpu_dai = {
+               .name   = "fsia-dai",
+               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+       },
+       .codec_dai = {
+               .name   = "ak4642-hifi",
+               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
+               .sysclk = 11289600,
+       },
 };
 
 static struct platform_device fsi_ak4642_device = {
index b151b7c..8f59d88 100644 (file)
@@ -192,7 +192,7 @@ config ICS932S401
 
 config ATMEL_SSC
        tristate "Device driver for Atmel SSC peripheral"
-       depends on AVR32 || ARCH_AT91
+       depends on HAS_IOMEM
        ---help---
          This option enables device driver support for Atmel Synchronized
          Serial Communication peripheral (SSC).
index 3c09cbb..bd90dd2 100644 (file)
@@ -175,7 +175,7 @@ static int ssc_probe(struct platform_device *pdev)
 
        /* disable all interrupts */
        clk_enable(ssc->clk);
-       ssc_writel(ssc->regs, IDR, ~0UL);
+       ssc_writel(ssc->regs, IDR, -1);
        ssc_readl(ssc->regs, SR);
        clk_disable(ssc->clk);
 
index 8f492ed..7cfbe9d 100644 (file)
@@ -134,7 +134,6 @@ struct s3c64xx_spi_dma_data {
        unsigned                ch;
        enum dma_transfer_direction direction;
        enum dma_ch     dmach;
-       struct property         *dma_prop;
 };
 
 /**
@@ -319,16 +318,15 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
        struct samsung_dma_req req;
+       struct device *dev = &sdd->pdev->dev;
 
        sdd->ops = samsung_dma_get_ops();
 
        req.cap = DMA_SLAVE;
        req.client = &s3c64xx_spi_dma_client;
 
-       req.dt_dmach_prop = sdd->rx_dma.dma_prop;
-       sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
-       req.dt_dmach_prop = sdd->tx_dma.dma_prop;
-       sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
+       sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
+       sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
 
        return 1;
 }
@@ -1053,49 +1051,6 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
        flush_fifo(sdd);
 }
 
-static int s3c64xx_spi_get_dmares(
-                       struct s3c64xx_spi_driver_data *sdd, bool tx)
-{
-       struct platform_device *pdev = sdd->pdev;
-       struct s3c64xx_spi_dma_data *dma_data;
-       struct property *prop;
-       struct resource *res;
-       char prop_name[15], *chan_str;
-
-       if (tx) {
-               dma_data = &sdd->tx_dma;
-               dma_data->direction = DMA_MEM_TO_DEV;
-               chan_str = "tx";
-       } else {
-               dma_data = &sdd->rx_dma;
-               dma_data->direction = DMA_DEV_TO_MEM;
-               chan_str = "rx";
-       }
-
-       if (!sdd->pdev->dev.of_node) {
-               res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
-               if (!res) {
-                       dev_err(&pdev->dev, "Unable to get SPI-%s dma resource\n",
-                               chan_str);
-                       return -ENXIO;
-               }
-               dma_data->dmach = res->start;
-               return 0;
-       }
-
-       sprintf(prop_name, "%s-dma-channel", chan_str);
-       prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
-       if (!prop) {
-               dev_err(&pdev->dev, "%s dma channel property not specified\n",
-                                       chan_str);
-               return -ENXIO;
-       }
-
-       dma_data->dmach = DMACH_DT_PROP;
-       dma_data->dma_prop = prop;
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
 {
@@ -1194,6 +1149,7 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
 static int s3c64xx_spi_probe(struct platform_device *pdev)
 {
        struct resource *mem_res;
+       struct resource *res;
        struct s3c64xx_spi_driver_data *sdd;
        struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
        struct spi_master *master;
@@ -1252,13 +1208,26 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
 
        sdd->cur_bpw = 8;
 
-       ret = s3c64xx_spi_get_dmares(sdd, true);
-       if (ret)
-               goto err0;
+       if (!sdd->pdev->dev.of_node) {
+               res = platform_get_resource(pdev, IORESOURCE_DMA,  0);
+               if (!res) {
+                       dev_err(&pdev->dev, "Unable to get SPI tx dma "
+                                       "resource\n");
+                       return -ENXIO;
+               }
+               sdd->tx_dma.dmach = res->start;
 
-       ret = s3c64xx_spi_get_dmares(sdd, false);
-       if (ret)
-               goto err0;
+               res = platform_get_resource(pdev, IORESOURCE_DMA,  1);
+               if (!res) {
+                       dev_err(&pdev->dev, "Unable to get SPI rx dma "
+                                       "resource\n");
+                       return -ENXIO;
+               }
+               sdd->rx_dma.dmach = res->start;
+       }
+
+       sdd->tx_dma.direction = DMA_MEM_TO_DEV;
+       sdd->rx_dma.direction = DMA_DEV_TO_MEM;
 
        master->dev.of_node = pdev->dev.of_node;
        master->bus_num = sdd->port_id;
index 8b1d1da..ec3e2a2 100644 (file)
@@ -62,6 +62,8 @@
 
 #define ARIZONA_MAX_OUTPUT 6
 
+#define ARIZONA_MAX_AIF 3
+
 #define ARIZONA_HAP_ACT_ERM 0
 #define ARIZONA_HAP_ACT_LRA 2
 
@@ -96,6 +98,13 @@ struct arizona_pdata {
        /** Pin state for GPIO pins */
        int gpio_defaults[ARIZONA_MAX_GPIO];
 
+       /**
+        * 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[ARIZONA_MAX_AIF];
+
        /** GPIO for mic detection polarity */
        int micd_pol_gpio;
 
index f2912ab..ff6c741 100644 (file)
@@ -71,6 +71,8 @@ struct snd_compr_runtime {
  * @runtime: pointer to runtime structure
  * @device: device pointer
  * @direction: stream direction, playback/recording
+ * @metadata_set: metadata set flag, true when set
+ * @next_track: has userspace signall next track transistion, true when set
  * @private_data: pointer to DSP private data
  */
 struct snd_compr_stream {
@@ -79,6 +81,8 @@ struct snd_compr_stream {
        struct snd_compr_runtime *runtime;
        struct snd_compr *device;
        enum snd_compr_direction direction;
+       bool metadata_set;
+       bool next_track;
        void *private_data;
 };
 
@@ -110,6 +114,10 @@ struct snd_compr_ops {
                        struct snd_compr_params *params);
        int (*get_params)(struct snd_compr_stream *stream,
                        struct snd_codec *params);
+       int (*set_metadata)(struct snd_compr_stream *stream,
+                       struct snd_compr_metadata *metadata);
+       int (*get_metadata)(struct snd_compr_stream *stream,
+                       struct snd_compr_metadata *metadata);
        int (*trigger)(struct snd_compr_stream *stream, int cmd);
        int (*pointer)(struct snd_compr_stream *stream,
                        struct snd_compr_tstamp *tstamp);
index 93896ad..7cede2d 100644 (file)
@@ -394,8 +394,11 @@ void __snd_printk(unsigned int level, const char *file, int line,
 
 #else /* !CONFIG_SND_DEBUG */
 
-#define snd_printd(fmt, args...)       do { } while (0)
-#define _snd_printd(level, fmt, args...) do { } while (0)
+__printf(1, 2)
+static inline void snd_printd(const char *format, ...) {}
+__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)
 {
@@ -416,7 +419,8 @@ static inline int __snd_bug_on(int cond)
 #define snd_printdd(format, args...) \
        __snd_printk(2, __FILE__, __LINE__, format, ##args)
 #else
-#define snd_printdd(format, args...)   do { } while (0)
+__printf(1, 2)
+static inline void snd_printdd(const char *format, ...) {}
 #endif
 
 
@@ -454,6 +458,7 @@ struct snd_pci_quirk {
 #define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val)                        \
        {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev),                       \
                        .value = (val), .name = (xname)}
+#define snd_pci_quirk_name(q)  ((q)->name)
 #else
 #define SND_PCI_QUIRK(vend,dev,xname,val) \
        {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
@@ -461,6 +466,7 @@ struct snd_pci_quirk {
        {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), .value = (val)}
 #define SND_PCI_QUIRK_VENDOR(vend, xname, val)                 \
        {_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val)}
+#define snd_pci_quirk_name(q)  ""
 #endif
 
 const struct snd_pci_quirk *
index dd8c48d..70f4535 100644 (file)
 struct cs4271_platform_data {
        int gpio_nreset;        /* GPIO driving Reset pin, if any */
        bool amutec_eq_bmutec;  /* flag to enable AMUTEC=BMUTEC */
+
+       /*
+        * The CS4271 requires its LRCLK and MCLK to be stable before its RESET
+        * line is de-asserted. That also means that clocks cannot be changed
+        * without putting the chip back into hardware reset, which also requires
+        * a complete re-initialization of all registers.
+        *
+        * One (undocumented) workaround is to assert and de-assert the PDN bit
+        * in the MODE2 register. This workaround can be enabled with the
+        * following flag.
+        *
+        * Note that this is not needed in case the clocks are stable
+        * throughout the entire runtime of the codec.
+        */
+       bool enable_soft_reset;
 };
 
 #endif /* __CS4271_H */
diff --git a/include/sound/da7213.h b/include/sound/da7213.h
new file mode 100644 (file)
index 0000000..673f5c3
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * da7213.h - DA7213 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2013 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef _DA7213_PDATA_H
+#define _DA7213_PDATA_H
+
+enum da7213_micbias_voltage {
+       DA7213_MICBIAS_1_6V = 0,
+       DA7213_MICBIAS_2_2V = 1,
+       DA7213_MICBIAS_2_5V = 2,
+       DA7213_MICBIAS_3_0V = 3,
+};
+
+enum da7213_dmic_data_sel {
+       DA7213_DMIC_DATA_LRISE_RFALL = 0,
+       DA7213_DMIC_DATA_LFALL_RRISE = 1,
+};
+
+enum da7213_dmic_samplephase {
+       DA7213_DMIC_SAMPLE_ON_CLKEDGE = 0,
+       DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE = 1,
+};
+
+enum da7213_dmic_clk_rate {
+       DA7213_DMIC_CLK_3_0MHZ = 0,
+       DA7213_DMIC_CLK_1_5MHZ = 1,
+};
+
+struct da7213_platform_data {
+       /* Mic Bias voltage */
+       enum da7213_micbias_voltage micbias1_lvl;
+       enum da7213_micbias_voltage micbias2_lvl;
+
+       /* DMIC config */
+       enum da7213_dmic_data_sel dmic_data_sel;
+       enum da7213_dmic_samplephase dmic_samplephase;
+       enum da7213_dmic_clk_rate dmic_clk_rate;
+
+       /* MCLK squaring config */
+       bool mclk_squaring;
+};
+
+#endif /* _DA7213_PDATA_H */
diff --git a/include/sound/max98090.h b/include/sound/max98090.h
new file mode 100755 (executable)
index 0000000..95efb13
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Platform data for MAX98090
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ *  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.
+ *
+ */
+
+#ifndef __SOUND_MAX98090_PDATA_H__
+#define __SOUND_MAX98090_PDATA_H__
+
+/* codec platform data */
+struct max98090_pdata {
+
+       /* Analog/digital microphone configuration:
+        * 0 = analog microphone input (normal setting)
+        * 1 = digital microphone input
+        */
+       unsigned int digmic_left_mode:1;
+       unsigned int digmic_right_mode:1;
+       unsigned int digmic_3_mode:1;
+       unsigned int digmic_4_mode:1;
+};
+
+#endif
index 844af65..cf15b82 100644 (file)
@@ -37,7 +37,7 @@ struct snd_dma_device {
 #ifndef snd_dma_pci_data
 #define snd_dma_pci_data(pci)  (&(pci)->dev)
 #define snd_dma_isa_data()     NULL
-#define snd_dma_continuous_data(x)     ((struct device *)(unsigned long)(x))
+#define snd_dma_continuous_data(x)     ((struct device *)(__force unsigned long)(x))
 #endif
 
 
diff --git a/include/sound/saif.h b/include/sound/saif.h
deleted file mode 100644 (file)
index f22f3e1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * 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.
- */
-
-#ifndef __SOUND_SAIF_H__
-#define __SOUND_SAIF_H__
-
-struct mxs_saif_platform_data {
-       bool master_mode;       /* if true use master mode */
-       int master_id;          /* id of the master if in slave mode */
-};
-#endif
index cc1c919..7a9710b 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-#define FSI_PORT_A     0
-#define FSI_PORT_B     1
-
 #include <linux/clk.h>
 #include <sound/soc.h>
 
 /*
- * flags format
- *
- * 0x00000CBA
- *
- * A:  inversion
- * B:  format mode
- * C:  chip specific
- * D:  clock selecter if master mode
+ * flags
  */
-
-/* A: clock inversion */
-#define SH_FSI_INVERSION_MASK  0x0000000F
-#define SH_FSI_LRM_INV         (1 << 0)
-#define SH_FSI_BRM_INV         (1 << 1)
-#define SH_FSI_LRS_INV         (1 << 2)
-#define SH_FSI_BRS_INV         (1 << 3)
-
-/* B: format mode */
-#define SH_FSI_FMT_MASK                0x000000F0
-#define SH_FSI_FMT_DAI         (0 << 4)
-#define SH_FSI_FMT_SPDIF       (1 << 4)
-
-/* C: chip specific */
-#define SH_FSI_OPTION_MASK     0x00000F00
-#define SH_FSI_ENABLE_STREAM_MODE      (1 << 8) /* for 16bit data */
-
-/* D:  clock selecter if master mode */
-#define SH_FSI_CLK_MASK                0x0000F000
-#define SH_FSI_CLK_EXTERNAL    (0 << 12)
-#define SH_FSI_CLK_CPG         (1 << 12) /* FSIxCK + FSI-DIV */
-
-/*
- * set_rate return value
- *
- * see ACKMD/BPFMD on
- *     ACK_MD (FSI2)
- *     CKG1   (FSI)
- *
- * err         : return value <  0
- * no change   : return value == 0
- * change xMD  : return value >  0
- *
- * 0x-00000AB
- *
- * A:  ACKMD value
- * B:  BPFMD value
- */
-
-#define SH_FSI_ACKMD_MASK      (0xF << 0)
-#define SH_FSI_ACKMD_512       (1 << 0)
-#define SH_FSI_ACKMD_256       (2 << 0)
-#define SH_FSI_ACKMD_128       (3 << 0)
-#define SH_FSI_ACKMD_64                (4 << 0)
-#define SH_FSI_ACKMD_32                (5 << 0)
-
-#define SH_FSI_BPFMD_MASK      (0xF << 4)
-#define SH_FSI_BPFMD_512       (1 << 4)
-#define SH_FSI_BPFMD_256       (2 << 4)
-#define SH_FSI_BPFMD_128       (3 << 4)
-#define SH_FSI_BPFMD_64                (4 << 4)
-#define SH_FSI_BPFMD_32                (5 << 4)
-#define SH_FSI_BPFMD_16                (6 << 4)
+#define SH_FSI_FMT_SPDIF               (1 << 0) /* spdif for HDMI */
+#define SH_FSI_ENABLE_STREAM_MODE      (1 << 1) /* for 16bit data */
+#define SH_FSI_CLK_CPG                 (1 << 2) /* FSIxCK + FSI-DIV */
 
 struct sh_fsi_port_info {
        unsigned long flags;
        int tx_id;
        int rx_id;
-       int (*set_rate)(struct device *dev, int rate, int enable);
 };
 
 struct sh_fsi_platform_info {
index 4b62b8d..6c74527 100644 (file)
 
 #include <sound/soc.h>
 
-struct asoc_simple_dai_init_info {
+struct asoc_simple_dai {
+       const char *name;
        unsigned int fmt;
-       unsigned int cpu_daifmt;
-       unsigned int codec_daifmt;
        unsigned int sysclk;
 };
 
 struct asoc_simple_card_info {
        const char *name;
        const char *card;
-       const char *cpu_dai;
        const char *codec;
        const char *platform;
-       const char *codec_dai;
-       struct asoc_simple_dai_init_info *init; /* for snd_link.init */
+
+       unsigned int daifmt;
+       struct asoc_simple_dai cpu_dai;
+       struct asoc_simple_dai codec_dai;
 
        /* used in simple-card.c */
        struct snd_soc_dai_link snd_link;
index 3953cea..3d84808 100644 (file)
@@ -45,7 +45,7 @@ struct snd_compr_stream;
  * sending or receiving PCM data in a frame. This can be used to save power.
  */
 #define SND_SOC_DAIFMT_CONT            (1 << 4) /* continuous clock */
-#define SND_SOC_DAIFMT_GATED           (2 << 4) /* clock is gated */
+#define SND_SOC_DAIFMT_GATED           (0 << 4) /* clock is gated */
 
 /*
  * DAI hardware signal inversions.
@@ -53,7 +53,7 @@ struct snd_compr_stream;
  * Specifies whether the DAI can also support inverted clocks for the specified
  * format.
  */
-#define SND_SOC_DAIFMT_NB_NF           (1 << 8) /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_NF           (0 << 8) /* normal bit clock + frame */
 #define SND_SOC_DAIFMT_NB_IF           (2 << 8) /* normal BCLK + inv FRM */
 #define SND_SOC_DAIFMT_IB_NF           (3 << 8) /* invert BCLK + nor FRM */
 #define SND_SOC_DAIFMT_IB_IF           (4 << 8) /* invert BCLK + FRM */
@@ -126,7 +126,8 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 
 /* Digital Audio Interface mute */
-int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
+int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
+                            int direction);
 
 struct snd_soc_dai_ops {
        /*
@@ -157,6 +158,7 @@ struct snd_soc_dai_ops {
         * Called by soc-core to minimise any pops.
         */
        int (*digital_mute)(struct snd_soc_dai *dai, int mute);
+       int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
 
        /*
         * ALSA PCM audio operations - all optional.
index bc56738..a6a059c 100644 (file)
@@ -906,8 +906,8 @@ struct snd_soc_dai_link {
                        struct snd_pcm_hw_params *params);
 
        /* machine stream operations */
-       struct snd_soc_ops *ops;
-       struct snd_soc_compr_ops *compr_ops;
+       const struct snd_soc_ops *ops;
+       const struct snd_soc_compr_ops *compr_ops;
 };
 
 struct snd_soc_codec_conf {
@@ -1171,6 +1171,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                               const char *propname);
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname);
+unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
+                                    const char *prefix);
 
 #include <sound/soc-dai.h>
 
index ffd9bc7..9407fd0 100644 (file)
@@ -46,6 +46,13 @@ enum {
        AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
 };
 
+enum aic3x_micbias_voltage {
+       AIC3X_MICBIAS_OFF = 0,
+       AIC3X_MICBIAS_2_0V = 1,
+       AIC3X_MICBIAS_2_5V = 2,
+       AIC3X_MICBIAS_AVDDV = 3,
+};
+
 struct aic3x_setup_data {
        unsigned int gpio_func[2];
 };
@@ -53,6 +60,9 @@ struct aic3x_setup_data {
 struct aic3x_pdata {
        int gpio_reset; /* < 0 if not used */
        struct aic3x_setup_data *setup;
+
+       /* Selects the micbias voltage */
+       enum aic3x_micbias_voltage micbias_vg;
 };
 
 #endif
index aa388ca..4de81f4 100644 (file)
@@ -15,9 +15,6 @@ struct wm2000_platform_data {
        /** Filename for system-specific image to download to device. */
        const char *download_file;
 
-       /** Divide MCLK by 2 for system clock? */
-       unsigned int mclkdiv2:1;
-
        /** Disable speech clarity enhancement, for use when an
         * external algorithm is used. */
        unsigned int speech_enh_disable:1;
index 79bf55b..bc7ab1a 100644 (file)
@@ -12,6 +12,7 @@
 #define __LINUX_SND_WM2200_H
 
 #define WM2200_GPIO_SET 0x10000
+#define WM2200_MAX_MICBIAS 2
 
 enum wm2200_in_mode {
        WM2200_IN_SE = 0,
@@ -25,6 +26,24 @@ enum wm2200_dmic_sup {
        WM2200_DMIC_SUP_MICBIAS2 = 2,
 };
 
+enum wm2200_mbias_lvl {
+       WM2200_MBIAS_LVL_1V5 = 1,
+       WM2200_MBIAS_LVL_1V8 = 2,
+       WM2200_MBIAS_LVL_1V9 = 3,
+       WM2200_MBIAS_LVL_2V0 = 4,
+       WM2200_MBIAS_LVL_2V2 = 5,
+       WM2200_MBIAS_LVL_2V4 = 6,
+       WM2200_MBIAS_LVL_2V5 = 7,
+       WM2200_MBIAS_LVL_2V6 = 8,
+};
+
+struct wm2200_micbias {
+       enum wm2200_mbias_lvl mb_lvl;      /** Regulated voltage */
+       unsigned int discharge:1;          /** Actively discharge */
+       unsigned int fast_start:1;         /** Enable aggressive startup ramp rate */
+       unsigned int bypass:1;             /** Use bypass mode */
+};
+
 struct wm2200_pdata {
        int reset;      /** GPIO controlling /RESET, if any */
        int ldo_ena;    /** GPIO controlling LODENA, if any */
@@ -35,7 +54,8 @@ struct wm2200_pdata {
        enum wm2200_in_mode in_mode[3];
        enum wm2200_dmic_sup dmic_sup[3];
 
-       int micbias_cfg[2];  /** Register value to configure MICBIAS */
+       /** MICBIAS configurations */
+       struct wm2200_micbias micbias[WM2200_MAX_MICBIAS];
 };
 
 #endif
index ac90037..d2314be 100644 (file)
@@ -384,14 +384,16 @@ static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_de
                                                   int protocol)
 {
        __u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
-       return desc->baSourceID[desc->bNrInPins + control_size];
+       return *(uac_processing_unit_bmControls(desc, protocol)
+                       + control_size);
 }
 
 static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc,
                                                 int protocol)
 {
        __u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
-       return &desc->baSourceID[desc->bNrInPins + control_size + 1];
+       return uac_processing_unit_bmControls(desc, protocol)
+                       + control_size + 1;
 }
 
 /* 4.5.2 Class-Specific AS Interface Descriptor */
index 05341a4..d630163 100644 (file)
@@ -30,7 +30,7 @@
 #include <sound/compress_params.h>
 
 
-#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 1)
 /**
  * struct snd_compressed_buffer: compressed buffer
  * @fragment_size: size of buffer fragment in bytes
@@ -121,6 +121,27 @@ struct snd_compr_codec_caps {
        struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
 };
 
+/**
+ * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
+ * end of the track
+ * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
+ * beginning of the track
+ */
+enum {
+       SNDRV_COMPRESS_ENCODER_PADDING = 1,
+       SNDRV_COMPRESS_ENCODER_DELAY = 2,
+};
+
+/**
+ * struct snd_compr_metadata: compressed stream metadata
+ * @key: key id
+ * @value: key value
+ */
+struct snd_compr_metadata {
+        __u32 key;
+        __u32 value[8];
+};
+
 /**
  * compress path ioctl definitions
  * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
@@ -145,6 +166,10 @@ struct snd_compr_codec_caps {
                                                struct snd_compr_codec_caps)
 #define SNDRV_COMPRESS_SET_PARAMS      _IOW('C', 0x12, struct snd_compr_params)
 #define SNDRV_COMPRESS_GET_PARAMS      _IOR('C', 0x13, struct snd_codec)
+#define SNDRV_COMPRESS_SET_METADATA    _IOW('C', 0x14,\
+                                                struct snd_compr_metadata)
+#define SNDRV_COMPRESS_GET_METADATA    _IOWR('C', 0x15,\
+                                                struct snd_compr_metadata)
 #define SNDRV_COMPRESS_TSTAMP          _IOR('C', 0x20, struct snd_compr_tstamp)
 #define SNDRV_COMPRESS_AVAIL           _IOR('C', 0x21, struct snd_compr_avail)
 #define SNDRV_COMPRESS_PAUSE           _IO('C', 0x30)
@@ -152,10 +177,14 @@ struct snd_compr_codec_caps {
 #define SNDRV_COMPRESS_START           _IO('C', 0x32)
 #define SNDRV_COMPRESS_STOP            _IO('C', 0x33)
 #define SNDRV_COMPRESS_DRAIN           _IO('C', 0x34)
+#define SNDRV_COMPRESS_NEXT_TRACK      _IO('C', 0x35)
+#define SNDRV_COMPRESS_PARTIAL_DRAIN   _IO('C', 0x36)
 /*
  * TODO
  * 1. add mmap support
  *
  */
 #define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
+#define SND_COMPR_TRIGGER_NEXT_TRACK 8
+#define SND_COMPR_TRIGGER_PARTIAL_DRAIN 9
 #endif
index fff7753..e6f4633 100644 (file)
@@ -34,7 +34,7 @@ static struct clk *ac97_clk;
 static struct clk *ac97conf_clk;
 static int reset_gpio;
 
-extern void pxa27x_assert_ac97reset(int reset_gpio, int on);
+extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
 
 /*
  * Beware PXA27x bugs:
@@ -140,10 +140,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
        gsr_bits = 0;
 
        /* warm reset broken on Bulverde, so manually keep AC97 reset high */
-       pxa27x_assert_ac97reset(reset_gpio, 1);
+       pxa27x_configure_ac97reset(reset_gpio, true);
        udelay(10);
        GCR |= GCR_WARM_RST;
-       pxa27x_assert_ac97reset(reset_gpio, 0);
+       pxa27x_configure_ac97reset(reset_gpio, false);
        udelay(500);
 }
 
@@ -358,7 +358,7 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
                               __func__, ret);
                        goto err_conf;
                }
-               pxa27x_assert_ac97reset(reset_gpio, 0);
+               pxa27x_configure_ac97reset(reset_gpio, false);
 
                ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
                if (IS_ERR(ac97conf_clk)) {
index ad11dc9..c84abc8 100644 (file)
@@ -144,16 +144,17 @@ static int snd_compr_free(struct inode *inode, struct file *f)
        return 0;
 }
 
-static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
+static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
                struct snd_compr_tstamp *tstamp)
 {
        if (!stream->ops->pointer)
-               return;
+               return -ENOTSUPP;
        stream->ops->pointer(stream, tstamp);
        pr_debug("dsp consumed till %d total %d bytes\n",
                tstamp->byte_offset, tstamp->copied_total);
        stream->runtime->hw_pointer = tstamp->byte_offset;
        stream->runtime->total_bytes_transferred = tstamp->copied_total;
+       return 0;
 }
 
 static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
@@ -161,7 +162,9 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 {
        long avail_calc; /*this needs to be signed variable */
 
+       memset(avail, 0, sizeof(*avail));
        snd_compr_update_tstamp(stream, &avail->tstamp);
+       /* Still need to return avail even if tstamp can't be filled in */
 
        /* FIXME: This needs to be different for capture stream,
           available is # of compressed data, for playback it's
@@ -483,6 +486,8 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
                if (retval)
                        goto out;
                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+               stream->metadata_set = false;
+               stream->next_track = false;
        } else {
                return -EPERM;
        }
@@ -514,14 +519,60 @@ out:
        return retval;
 }
 
+static int
+snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_compr_metadata metadata;
+       int retval;
+
+       if (!stream->ops->get_metadata)
+               return -ENXIO;
+
+       if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
+               return -EFAULT;
+
+       retval = stream->ops->get_metadata(stream, &metadata);
+       if (retval != 0)
+               return retval;
+
+       if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int
+snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_compr_metadata metadata;
+       int retval;
+
+       if (!stream->ops->set_metadata)
+               return -ENXIO;
+       /*
+       * we should allow parameter change only when stream has been
+       * opened not in other cases
+       */
+       if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
+               return -EFAULT;
+
+       retval = stream->ops->set_metadata(stream, &metadata);
+       stream->metadata_set = true;
+
+       return retval;
+}
+
 static inline int
 snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
 {
-       struct snd_compr_tstamp tstamp;
+       struct snd_compr_tstamp tstamp = {0};
+       int ret;
 
-       snd_compr_update_tstamp(stream, &tstamp);
-       return copy_to_user((struct snd_compr_tstamp __user *)arg,
-               &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
+       ret = snd_compr_update_tstamp(stream, &tstamp);
+       if (ret == 0)
+               ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
+                       &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
+       return ret;
 }
 
 static int snd_compr_pause(struct snd_compr_stream *stream)
@@ -594,6 +645,44 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
        return retval;
 }
 
+static int snd_compr_next_track(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       /* only a running stream can transition to next track */
+       if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+               return -EPERM;
+
+       /* you can signal next track isf this is intended to be a gapless stream
+        * and current track metadata is set
+        */
+       if (stream->metadata_set == false)
+               return -EPERM;
+
+       retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
+       if (retval != 0)
+               return retval;
+       stream->metadata_set = false;
+       stream->next_track = true;
+       return 0;
+}
+
+static int snd_compr_partial_drain(struct snd_compr_stream *stream)
+{
+       int retval;
+       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+               return -EPERM;
+       /* stream can be drained only when next track has been signalled */
+       if (stream->next_track == false)
+               return -EPERM;
+
+       retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
+
+       stream->next_track = false;
+       return retval;
+}
+
 static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
        struct snd_compr_file *data = f->private_data;
@@ -623,6 +712,12 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
                retval = snd_compr_get_params(stream, arg);
                break;
+       case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
+               retval = snd_compr_set_metadata(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
+               retval = snd_compr_get_metadata(stream, arg);
+               break;
        case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
                retval = snd_compr_tstamp(stream, arg);
                break;
@@ -644,6 +739,13 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_COMPRESS_DRAIN):
                retval = snd_compr_drain(stream);
                break;
+       case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
+               retval = snd_compr_partial_drain(stream);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
+               retval = snd_compr_next_track(stream);
+               break;
+
        }
        mutex_unlock(&stream->device->lock);
        return retval;
index 3d82232..64d5347 100644 (file)
@@ -286,12 +286,14 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
                        loopback_active_notify(dpcm);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                spin_lock(&cable->lock);        
                cable->pause |= stream;
                loopback_timer_stop(dpcm);
                spin_unlock(&cable->lock);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
                spin_lock(&cable->lock);
                dpcm->last_jiffies = jiffies;
                cable->pause &= ~stream;
@@ -563,7 +565,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
 static struct snd_pcm_hardware loopback_pcm_hardware =
 {
        .info =         (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
-                        SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+                        SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
+                        SNDRV_PCM_INFO_RESUME),
        .formats =      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
                         SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
                         SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
index de5055a..c39961c 100644 (file)
@@ -52,7 +52,6 @@ MODULE_LICENSE("GPL");
 int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time)
 {
        unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
-#ifdef CONFIG_SND_DEBUG
        static char *reg_names[VX_REG_MAX] = {
                "ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL",
                "DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ",
@@ -60,7 +59,7 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
                "MIC3", "INTCSR", "CNTRL", "GPIOC",
                "LOFREQ", "HIFREQ", "CSUER", "RUER"
        };
-#endif
+
        do {
                if ((snd_vx_inb(chip, reg) & mask) == bit)
                        return 0;
index 947cfb4..fe6fa93 100644 (file)
@@ -678,6 +678,7 @@ config SND_LOLA
 
 config SND_LX6464ES
        tristate "Digigram LX6464ES"
+       depends on HAS_IOPORT
        select SND_PCM
        help
          Say Y here to include support for Digigram LX6464ES boards.
index 136a393..e760af9 100644 (file)
@@ -1435,7 +1435,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
 
        spin_lock(&codec->reg_lock);
        if (!pvoice->running) {
-               spin_unlock_irq(&codec->reg_lock);
+               spin_unlock(&codec->reg_lock);
                return 0;
        }
        outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
index a677431..6e78c67 100644 (file)
@@ -567,8 +567,9 @@ static int ac97_probing_bugs(struct pci_dev *pci)
 
        q = snd_pci_quirk_lookup(pci, atiixp_quirks);
        if (q) {
-               snd_printdd(KERN_INFO "Atiixp quirk for %s.  "
-                           "Forcing codec %d\n", q->name, q->value);
+               snd_printdd(KERN_INFO
+                           "Atiixp quirk for %s.  Forcing codec %d\n",
+                           snd_pci_quirk_name(q), q->value);
                return q->value;
        }
        /* this hardware doesn't need workarounds.  Probe for codec */
index a4184bb..b46dc9b 100644 (file)
@@ -650,6 +650,29 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
                                              snd_dma_pci_data(chip->pci_dev),
                                              0x10000, 0x10000);
 
+       switch (VORTEX_PCM_TYPE(pcm)) {
+       case VORTEX_PCM_ADB:
+               err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                            snd_pcm_std_chmaps,
+                                            VORTEX_IS_QUAD(chip) ? 4 : 2,
+                                            0, NULL);
+               if (err < 0)
+                       return err;
+               err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                                            snd_pcm_std_chmaps, 2, 0, NULL);
+               if (err < 0)
+                       return err;
+               break;
+#ifdef CHIP_AU8830
+       case VORTEX_PCM_A3D:
+               err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                            snd_pcm_std_chmaps, 1, 0, NULL);
+               if (err < 0)
+                       return err;
+               break;
+#endif
+       };
+
        if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
                for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
                        kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
index 6eeb889..80a7d44 100644 (file)
@@ -15,6 +15,9 @@ menuconfig SND_HDA_INTEL
 
 if SND_HDA_INTEL
 
+config SND_HDA_DSP_LOADER
+       bool
+
 config SND_HDA_PREALLOC_SIZE
        int "Pre-allocated buffer size for HD-audio driver"
        range 0 32768
@@ -86,6 +89,7 @@ config SND_HDA_PATCH_LOADER
 config SND_HDA_CODEC_REALTEK
        bool "Build Realtek HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include Realtek HD-audio codec support in
          snd-hda-intel driver, such as ALC880.
@@ -98,6 +102,7 @@ config SND_HDA_CODEC_REALTEK
 config SND_HDA_CODEC_ANALOG
        bool "Build Analog Device HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include Analog Device HD-audio codec support in
          snd-hda-intel driver, such as AD1986A.
@@ -110,6 +115,7 @@ config SND_HDA_CODEC_ANALOG
 config SND_HDA_CODEC_SIGMATEL
        bool "Build IDT/Sigmatel HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include IDT (Sigmatel) HD-audio codec support in
          snd-hda-intel driver, such as STAC9200.
@@ -122,6 +128,7 @@ config SND_HDA_CODEC_SIGMATEL
 config SND_HDA_CODEC_VIA
        bool "Build VIA HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include VIA HD-audio codec support in
          snd-hda-intel driver, such as VT1708.
@@ -147,8 +154,8 @@ config SND_HDA_CODEC_HDMI
 
 config SND_HDA_CODEC_CIRRUS
        bool "Build Cirrus Logic codec support"
-       depends on SND_HDA_INTEL
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include Cirrus Logic codec support in
          snd-hda-intel driver, such as CS4206.
@@ -161,6 +168,7 @@ config SND_HDA_CODEC_CIRRUS
 config SND_HDA_CODEC_CONEXANT
        bool "Build Conexant HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include Conexant HD-audio codec support in
          snd-hda-intel driver, such as CX20549.
@@ -172,8 +180,8 @@ config SND_HDA_CODEC_CONEXANT
 
 config SND_HDA_CODEC_CA0110
        bool "Build Creative CA0110-IBG codec support"
-       depends on SND_HDA_INTEL
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include Creative CA0110-IBG codec support in
          snd-hda-intel driver, found on some Creative X-Fi cards.
@@ -185,7 +193,6 @@ config SND_HDA_CODEC_CA0110
 
 config SND_HDA_CODEC_CA0132
        bool "Build Creative CA0132 codec support"
-       depends on SND_HDA_INTEL
        default y
        help
          Say Y here to include Creative CA0132 codec support in
@@ -196,9 +203,21 @@ config SND_HDA_CODEC_CA0132
          snd-hda-codec-ca0132.
          This module is automatically loaded at probing.
 
+config SND_HDA_CODEC_CA0132_DSP
+       bool "Support new DSP code for CA0132 codec"
+       depends on SND_HDA_CODEC_CA0132 && FW_LOADER
+       select SND_HDA_DSP_LOADER
+       help
+         Say Y here to enable the DSP for Creative CA0132 for extended
+         features like equalizer or echo cancellation.
+
+         Note that this option requires the external firmware file
+         (ctefx.bin).
+
 config SND_HDA_CODEC_CMEDIA
        bool "Build C-Media HD-audio codec support"
        default y
+       select SND_HDA_GENERIC
        help
          Say Y here to include C-Media HD-audio codec support in
          snd-hda-intel driver, such as CMI9880.
diff --git a/sound/pci/hda/ca0132_regs.h b/sound/pci/hda/ca0132_regs.h
new file mode 100644 (file)
index 0000000..07e7609
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * HD audio interface patch for Creative CA0132 chip.
+ * CA0132 registers defines.
+ *
+ * Copyright (c) 2011, Creative Technology Ltd.
+ *
+ *  This driver 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 driver 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __CA0132_REGS_H
+#define __CA0312_REGS_H
+
+#define DSP_CHIP_OFFSET                0x100000
+#define DSP_DBGCNTL_MODULE_OFFSET      0xE30
+#define DSP_DBGCNTL_INST_OFFSET \
+       (DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET)
+
+#define DSP_DBGCNTL_EXEC_LOBIT         0x0
+#define DSP_DBGCNTL_EXEC_HIBIT         0x3
+#define DSP_DBGCNTL_EXEC_MASK          0xF
+
+#define DSP_DBGCNTL_SS_LOBIT           0x4
+#define DSP_DBGCNTL_SS_HIBIT           0x7
+#define DSP_DBGCNTL_SS_MASK            0xF0
+
+#define DSP_DBGCNTL_STATE_LOBIT        0xA
+#define DSP_DBGCNTL_STATE_HIBIT        0xD
+#define DSP_DBGCNTL_STATE_MASK         0x3C00
+
+#define XRAM_CHIP_OFFSET               0x0
+#define XRAM_XRAM_CHANNEL_COUNT        0xE000
+#define XRAM_XRAM_MODULE_OFFSET        0x0
+#define XRAM_XRAM_CHAN_INCR            4
+#define XRAM_XRAM_INST_OFFSET(_chan) \
+       (XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \
+       (_chan * XRAM_XRAM_CHAN_INCR))
+
+#define YRAM_CHIP_OFFSET               0x40000
+#define YRAM_YRAM_CHANNEL_COUNT        0x8000
+#define YRAM_YRAM_MODULE_OFFSET        0x0
+#define YRAM_YRAM_CHAN_INCR            4
+#define YRAM_YRAM_INST_OFFSET(_chan) \
+       (YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \
+       (_chan * YRAM_YRAM_CHAN_INCR))
+
+#define UC_CHIP_OFFSET                 0x80000
+#define UC_UC_CHANNEL_COUNT            0x10000
+#define UC_UC_MODULE_OFFSET            0x0
+#define UC_UC_CHAN_INCR                4
+#define UC_UC_INST_OFFSET(_chan) \
+       (UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \
+       (_chan * UC_UC_CHAN_INCR))
+
+#define AXRAM_CHIP_OFFSET              0x3C000
+#define AXRAM_AXRAM_CHANNEL_COUNT      0x1000
+#define AXRAM_AXRAM_MODULE_OFFSET      0x0
+#define AXRAM_AXRAM_CHAN_INCR          4
+#define AXRAM_AXRAM_INST_OFFSET(_chan) \
+       (AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \
+       (_chan * AXRAM_AXRAM_CHAN_INCR))
+
+#define AYRAM_CHIP_OFFSET              0x78000
+#define AYRAM_AYRAM_CHANNEL_COUNT      0x1000
+#define AYRAM_AYRAM_MODULE_OFFSET      0x0
+#define AYRAM_AYRAM_CHAN_INCR          4
+#define AYRAM_AYRAM_INST_OFFSET(_chan) \
+       (AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \
+       (_chan * AYRAM_AYRAM_CHAN_INCR))
+
+#define DSPDMAC_CHIP_OFFSET            0x110000
+#define DSPDMAC_DMA_CFG_CHANNEL_COUNT  12
+#define DSPDMAC_DMACFG_MODULE_OFFSET   0xF00
+#define DSPDMAC_DMACFG_CHAN_INCR       0x10
+#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DMACFG_CHAN_INCR))
+
+#define DSPDMAC_DMACFG_DBADR_LOBIT     0x0
+#define DSPDMAC_DMACFG_DBADR_HIBIT     0x10
+#define DSPDMAC_DMACFG_DBADR_MASK      0x1FFFF
+#define DSPDMAC_DMACFG_LP_LOBIT        0x11
+#define DSPDMAC_DMACFG_LP_HIBIT        0x11
+#define DSPDMAC_DMACFG_LP_MASK         0x20000
+
+#define DSPDMAC_DMACFG_AINCR_LOBIT     0x12
+#define DSPDMAC_DMACFG_AINCR_HIBIT     0x12
+#define DSPDMAC_DMACFG_AINCR_MASK      0x40000
+
+#define DSPDMAC_DMACFG_DWR_LOBIT       0x13
+#define DSPDMAC_DMACFG_DWR_HIBIT       0x13
+#define DSPDMAC_DMACFG_DWR_MASK        0x80000
+
+#define DSPDMAC_DMACFG_AJUMP_LOBIT     0x14
+#define DSPDMAC_DMACFG_AJUMP_HIBIT     0x17
+#define DSPDMAC_DMACFG_AJUMP_MASK      0xF00000
+
+#define DSPDMAC_DMACFG_AMODE_LOBIT     0x18
+#define DSPDMAC_DMACFG_AMODE_HIBIT     0x19
+#define DSPDMAC_DMACFG_AMODE_MASK      0x3000000
+
+#define DSPDMAC_DMACFG_LK_LOBIT        0x1A
+#define DSPDMAC_DMACFG_LK_HIBIT        0x1A
+#define DSPDMAC_DMACFG_LK_MASK         0x4000000
+
+#define DSPDMAC_DMACFG_AICS_LOBIT      0x1B
+#define DSPDMAC_DMACFG_AICS_HIBIT      0x1F
+#define DSPDMAC_DMACFG_AICS_MASK       0xF8000000
+
+#define DSPDMAC_DMACFG_LP_SINGLE                 0
+#define DSPDMAC_DMACFG_LP_LOOPING                1
+
+#define DSPDMAC_DMACFG_AINCR_XANDY               0
+#define DSPDMAC_DMACFG_AINCR_XORY                1
+
+#define DSPDMAC_DMACFG_DWR_DMA_RD                0
+#define DSPDMAC_DMACFG_DWR_DMA_WR                1
+
+#define DSPDMAC_DMACFG_AMODE_LINEAR              0
+#define DSPDMAC_DMACFG_AMODE_RSV1                1
+#define DSPDMAC_DMACFG_AMODE_WINTLV              2
+#define DSPDMAC_DMACFG_AMODE_GINTLV              3
+
+#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADROFS_CHAN_INCR    0x10
+#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADROFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADROFS_COFS_LOBIT   0x0
+#define DSPDMAC_DSPADROFS_COFS_HIBIT   0xF
+#define DSPDMAC_DSPADROFS_COFS_MASK    0xFFFF
+
+#define DSPDMAC_DSPADROFS_BOFS_LOBIT   0x10
+#define DSPDMAC_DSPADROFS_BOFS_HIBIT   0x1F
+#define DSPDMAC_DSPADROFS_BOFS_MASK    0xFFFF0000
+
+#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADRWOFS_CHAN_INCR   0x10
+
+#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0
+#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA
+#define DSPDMAC_DSPADRWOFS_WCOFS_MASK  0x7FF
+
+#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB
+#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF
+#define DSPDMAC_DSPADRWOFS_WCBFR_MASK  0xF800
+
+#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10
+#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A
+#define DSPDMAC_DSPADRWOFS_WBOFS_MASK  0x7FF0000
+
+#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B
+#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F
+#define DSPDMAC_DSPADRWOFS_WBBFR_MASK  0xF8000000
+
+#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADRGOFS_CHAN_INCR   0x10
+#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0
+#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9
+#define DSPDMAC_DSPADRGOFS_GCOFS_MASK  0x3FF
+
+#define DSPDMAC_DSPADRGOFS_GCS_LOBIT   0xA
+#define DSPDMAC_DSPADRGOFS_GCS_HIBIT   0xC
+#define DSPDMAC_DSPADRGOFS_GCS_MASK    0x1C00
+
+#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD
+#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF
+#define DSPDMAC_DSPADRGOFS_GCBFR_MASK  0xE000
+
+#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10
+#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19
+#define DSPDMAC_DSPADRGOFS_GBOFS_MASK  0x3FF0000
+
+#define DSPDMAC_DSPADRGOFS_GBS_LOBIT   0x1A
+#define DSPDMAC_DSPADRGOFS_GBS_HIBIT   0x1C
+#define DSPDMAC_DSPADRGOFS_GBS_MASK    0x1C000000
+
+#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D
+#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F
+#define DSPDMAC_DSPADRGOFS_GBBFR_MASK  0xE0000000
+
+#define DSPDMAC_XFR_CNT_CHANNEL_COUNT  12
+#define DSPDMAC_XFRCNT_MODULE_OFFSET   0xF08
+#define DSPDMAC_XFRCNT_CHAN_INCR       0x10
+
+#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \
+       (_chan * DSPDMAC_XFRCNT_CHAN_INCR))
+
+#define DSPDMAC_XFRCNT_CCNT_LOBIT      0x0
+#define DSPDMAC_XFRCNT_CCNT_HIBIT      0xF
+#define DSPDMAC_XFRCNT_CCNT_MASK       0xFFFF
+
+#define DSPDMAC_XFRCNT_BCNT_LOBIT      0x10
+#define DSPDMAC_XFRCNT_BCNT_HIBIT      0x1F
+#define DSPDMAC_XFRCNT_BCNT_MASK       0xFFFF0000
+
+#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT  12
+#define DSPDMAC_IRQCNT_MODULE_OFFSET   0xF0C
+#define DSPDMAC_IRQCNT_CHAN_INCR       0x10
+#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \
+       (_chan * DSPDMAC_IRQCNT_CHAN_INCR))
+
+#define DSPDMAC_IRQCNT_CICNT_LOBIT     0x0
+#define DSPDMAC_IRQCNT_CICNT_HIBIT     0xF
+#define DSPDMAC_IRQCNT_CICNT_MASK      0xFFFF
+
+#define DSPDMAC_IRQCNT_BICNT_LOBIT     0x10
+#define DSPDMAC_IRQCNT_BICNT_HIBIT     0x1F
+#define DSPDMAC_IRQCNT_BICNT_MASK      0xFFFF0000
+
+#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12
+#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0
+#define DSPDMAC_AUDCHSEL_CHAN_INCR     0x4
+#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \
+       (_chan * DSPDMAC_AUDCHSEL_CHAN_INCR))
+
+#define DSPDMAC_AUDCHSEL_ACS_LOBIT     0x0
+#define DSPDMAC_AUDCHSEL_ACS_HIBIT     0x1F
+#define DSPDMAC_AUDCHSEL_ACS_MASK      0xFFFFFFFF
+
+#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0
+#define DSPDMAC_CHNLSTART_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLSTART_EN_LOBIT     0x0
+#define DSPDMAC_CHNLSTART_EN_HIBIT     0xB
+#define DSPDMAC_CHNLSTART_EN_MASK      0xFFF
+
+#define DSPDMAC_CHNLSTART_VAI1_LOBIT   0xC
+#define DSPDMAC_CHNLSTART_VAI1_HIBIT   0xF
+#define DSPDMAC_CHNLSTART_VAI1_MASK    0xF000
+
+#define DSPDMAC_CHNLSTART_DIS_LOBIT    0x10
+#define DSPDMAC_CHNLSTART_DIS_HIBIT    0x1B
+#define DSPDMAC_CHNLSTART_DIS_MASK     0xFFF0000
+
+#define DSPDMAC_CHNLSTART_VAI2_LOBIT   0x1C
+#define DSPDMAC_CHNLSTART_VAI2_HIBIT   0x1F
+#define DSPDMAC_CHNLSTART_VAI2_MASK    0xF0000000
+
+#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4
+#define DSPDMAC_CHNLSTATUS_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLSTATUS_ISC_LOBIT   0x0
+#define DSPDMAC_CHNLSTATUS_ISC_HIBIT   0xB
+#define DSPDMAC_CHNLSTATUS_ISC_MASK    0xFFF
+
+#define DSPDMAC_CHNLSTATUS_AOO_LOBIT   0xC
+#define DSPDMAC_CHNLSTATUS_AOO_HIBIT   0xC
+#define DSPDMAC_CHNLSTATUS_AOO_MASK    0x1000
+
+#define DSPDMAC_CHNLSTATUS_AOU_LOBIT   0xD
+#define DSPDMAC_CHNLSTATUS_AOU_HIBIT   0xD
+#define DSPDMAC_CHNLSTATUS_AOU_MASK    0x2000
+
+#define DSPDMAC_CHNLSTATUS_AIO_LOBIT   0xE
+#define DSPDMAC_CHNLSTATUS_AIO_HIBIT   0xE
+#define DSPDMAC_CHNLSTATUS_AIO_MASK    0x4000
+
+#define DSPDMAC_CHNLSTATUS_AIU_LOBIT   0xF
+#define DSPDMAC_CHNLSTATUS_AIU_HIBIT   0xF
+#define DSPDMAC_CHNLSTATUS_AIU_MASK    0x8000
+
+#define DSPDMAC_CHNLSTATUS_IEN_LOBIT   0x10
+#define DSPDMAC_CHNLSTATUS_IEN_HIBIT   0x1B
+#define DSPDMAC_CHNLSTATUS_IEN_MASK    0xFFF0000
+
+#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT  0x1C
+#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT  0x1F
+#define DSPDMAC_CHNLSTATUS_VAI0_MASK   0xF0000000
+
+#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8
+#define DSPDMAC_CHNLPROP_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLPROP_DCON_LOBIT    0x0
+#define DSPDMAC_CHNLPROP_DCON_HIBIT    0xB
+#define DSPDMAC_CHNLPROP_DCON_MASK     0xFFF
+
+#define DSPDMAC_CHNLPROP_FFS_LOBIT     0xC
+#define DSPDMAC_CHNLPROP_FFS_HIBIT     0xC
+#define DSPDMAC_CHNLPROP_FFS_MASK      0x1000
+
+#define DSPDMAC_CHNLPROP_NAJ_LOBIT     0xD
+#define DSPDMAC_CHNLPROP_NAJ_HIBIT     0xD
+#define DSPDMAC_CHNLPROP_NAJ_MASK      0x2000
+
+#define DSPDMAC_CHNLPROP_ENH_LOBIT     0xE
+#define DSPDMAC_CHNLPROP_ENH_HIBIT     0xE
+#define DSPDMAC_CHNLPROP_ENH_MASK      0x4000
+
+#define DSPDMAC_CHNLPROP_MSPCE_LOBIT   0x10
+#define DSPDMAC_CHNLPROP_MSPCE_HIBIT   0x1B
+#define DSPDMAC_CHNLPROP_MSPCE_MASK    0xFFF0000
+
+#define DSPDMAC_CHNLPROP_AC_LOBIT      0x1C
+#define DSPDMAC_CHNLPROP_AC_HIBIT      0x1F
+#define DSPDMAC_CHNLPROP_AC_MASK       0xF0000000
+
+#define DSPDMAC_ACTIVE_MODULE_OFFSET   0xFFC
+#define DSPDMAC_ACTIVE_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET)
+
+#define DSPDMAC_ACTIVE_AAR_LOBIT       0x0
+#define DSPDMAC_ACTIVE_AAR_HIBIT       0xB
+#define DSPDMAC_ACTIVE_AAR_MASK        0xFFF
+
+#define DSPDMAC_ACTIVE_WFR_LOBIT       0xC
+#define DSPDMAC_ACTIVE_WFR_HIBIT       0x17
+#define DSPDMAC_ACTIVE_WFR_MASK        0xFFF000
+
+#define DSP_AUX_MEM_BASE            0xE000
+#define INVALID_CHIP_ADDRESS        (~0U)
+
+#define X_SIZE  (XRAM_XRAM_CHANNEL_COUNT   * XRAM_XRAM_CHAN_INCR)
+#define Y_SIZE  (YRAM_YRAM_CHANNEL_COUNT   * YRAM_YRAM_CHAN_INCR)
+#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR)
+#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR)
+#define UC_SIZE (UC_UC_CHANNEL_COUNT       * UC_UC_CHAN_INCR)
+
+#define XEXT_SIZE (X_SIZE + AX_SIZE)
+#define YEXT_SIZE (Y_SIZE + AY_SIZE)
+
+#define U64K 0x10000UL
+
+#define X_END  (XRAM_CHIP_OFFSET  + X_SIZE)
+#define X_EXT  (XRAM_CHIP_OFFSET  + XEXT_SIZE)
+#define AX_END (XRAM_CHIP_OFFSET  + U64K*4)
+
+#define Y_END  (YRAM_CHIP_OFFSET  + Y_SIZE)
+#define Y_EXT  (YRAM_CHIP_OFFSET  + YEXT_SIZE)
+#define AY_END (YRAM_CHIP_OFFSET  + U64K*4)
+
+#define UC_END (UC_CHIP_OFFSET    + UC_SIZE)
+
+#define X_RANGE_MAIN(a, s) \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_END))
+#define X_RANGE_AUX(a, s)  \
+       (((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
+#define X_RANGE_EXT(a, s)  \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_EXT))
+#define X_RANGE_ALL(a, s)  \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
+
+#define Y_RANGE_MAIN(a, s) \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_END))
+#define Y_RANGE_AUX(a, s)  \
+       (((a) >= Y_END) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
+#define Y_RANGE_EXT(a, s)  \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_EXT))
+#define Y_RANGE_ALL(a, s)  \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
+
+#define UC_RANGE(a, s) \
+       (((a) >= UC_CHIP_OFFSET) && \
+       ((a)+((s)-1)*UC_UC_CHAN_INCR     < UC_END))
+
+#define X_OFF(a) \
+       (((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR)
+#define AX_OFF(a) \
+       (((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \
+       AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR)
+
+#define Y_OFF(a) \
+       (((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR)
+#define AY_OFF(a) \
+       (((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \
+       AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR)
+
+#define UC_OFF(a)  (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR)
+
+#define X_EXT_MAIN_SIZE(a)  (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a))
+#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a))
+
+#define Y_EXT_MAIN_SIZE(a)  (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a))
+#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a))
+
+#endif
index 7da883a..a3ea76a 100644 (file)
@@ -97,6 +97,28 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
        }
 }
 
+/* check whether the given pin has a proper pin I/O capability bit */
+static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
+                                 unsigned int dev)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
+
+       /* some old hardware don't return the proper pincaps */
+       if (!pincap)
+               return true;
+
+       switch (dev) {
+       case AC_JACK_LINE_OUT:
+       case AC_JACK_SPEAKER:
+       case AC_JACK_HP_OUT:
+       case AC_JACK_SPDIF_OUT:
+       case AC_JACK_DIG_OTHER_OUT:
+               return !!(pincap & AC_PINCAP_OUT);
+       default:
+               return !!(pincap & AC_PINCAP_IN);
+       }
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -126,6 +148,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)];
        int i;
 
+       if (!snd_hda_get_int_hint(codec, "parser_flags", &i))
+               cond_flags = i;
+
        memset(cfg, 0, sizeof(*cfg));
 
        memset(line_out, 0, sizeof(line_out));
@@ -156,10 +181,14 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 
                /* workaround for buggy BIOS setups */
                if (dev == AC_JACK_LINE_OUT) {
-                       if (conn == AC_JACK_PORT_FIXED)
+                       if (conn == AC_JACK_PORT_FIXED ||
+                           conn == AC_JACK_PORT_BOTH)
                                dev = AC_JACK_SPEAKER;
                }
 
+               if (!check_pincap_validity(codec, nid, dev))
+                       continue;
+
                switch (dev) {
                case AC_JACK_LINE_OUT:
                        seq = get_defcfg_sequence(def_conf);
@@ -363,7 +392,7 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
 {
        unsigned int def_conf;
        static const char * const mic_names[] = {
-               "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+               "Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic"
        };
        int attr;
 
@@ -394,6 +423,8 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
                return "SPDIF In";
        case AC_JACK_DIG_OTHER_IN:
                return "Digital In";
+       case AC_JACK_HP_OUT:
+               return "Headphone Mic";
        default:
                return "Misc";
        }
@@ -552,6 +583,9 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
        return 1;
 }
 
+#define is_hdmi_cfg(conf) \
+       (get_defcfg_location(conf) == AC_JACK_LOC_HDMI)
+
 /**
  * snd_hda_get_pin_label - Get a label for the given I/O pin
  *
@@ -572,6 +606,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
        unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
        const char *name = NULL;
        int i;
+       bool hdmi;
 
        if (indexp)
                *indexp = 0;
@@ -590,16 +625,18 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
                                           label, maxlen, indexp);
        case AC_JACK_SPDIF_OUT:
        case AC_JACK_DIG_OTHER_OUT:
-               if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
-                       name = "HDMI";
-               else
-                       name = "SPDIF";
-               if (cfg && indexp) {
-                       i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
-                                                cfg->dig_outs);
-                       if (i >= 0)
-                               *indexp = i;
-               }
+               hdmi = is_hdmi_cfg(def_conf);
+               name = hdmi ? "HDMI" : "SPDIF";
+               if (cfg && indexp)
+                       for (i = 0; i < cfg->dig_outs; i++) {
+                               hda_nid_t pin = cfg->dig_out_pins[i];
+                               unsigned int c;
+                               if (pin == nid)
+                                       break;
+                               c = snd_hda_codec_get_pincfg(codec, pin);
+                               if (hdmi == is_hdmi_cfg(c))
+                                       (*indexp)++;
+                       }
                break;
        default:
                if (cfg) {
@@ -622,28 +659,27 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
 
-int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
-                         const struct hda_verb *list)
+int snd_hda_add_verbs(struct hda_codec *codec,
+                     const struct hda_verb *list)
 {
        const struct hda_verb **v;
-       v = snd_array_new(&spec->verbs);
+       v = snd_array_new(&codec->verbs);
        if (!v)
                return -ENOMEM;
        *v = list;
        return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
+EXPORT_SYMBOL_HDA(snd_hda_add_verbs);
 
-void snd_hda_gen_apply_verbs(struct hda_codec *codec)
+void snd_hda_apply_verbs(struct hda_codec *codec)
 {
-       struct hda_gen_spec *spec = codec->spec;
        int i;
-       for (i = 0; i < spec->verbs.used; i++) {
-               struct hda_verb **v = snd_array_elem(&spec->verbs, i);
+       for (i = 0; i < codec->verbs.used; i++) {
+               struct hda_verb **v = snd_array_elem(&codec->verbs, i);
                snd_hda_sequence_write(codec, *v);
        }
 }
-EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
+EXPORT_SYMBOL_HDA(snd_hda_apply_verbs);
 
 void snd_hda_apply_pincfgs(struct hda_codec *codec,
                           const struct hda_pintbl *cfg)
@@ -653,20 +689,22 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
 
-void snd_hda_apply_fixup(struct hda_codec *codec, int action)
+static void set_pin_targets(struct hda_codec *codec,
+                           const struct hda_pintbl *cfg)
 {
-       struct hda_gen_spec *spec = codec->spec;
-       int id = spec->fixup_id;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       const char *modelname = spec->fixup_name;
-#endif
-       int depth = 0;
+       for (; cfg->nid; cfg++)
+               snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val);
+}
 
-       if (!spec->fixup_list)
-               return;
+static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
+{
+       const char *modelname = codec->fixup_name;
 
        while (id >= 0) {
-               const struct hda_fixup *fix = spec->fixup_list + id;
+               const struct hda_fixup *fix = codec->fixup_list + id;
+
+               if (fix->chained_before)
+                       apply_fixup(codec, fix->chain_id, action, depth + 1);
 
                switch (fix->type) {
                case HDA_FIXUP_PINS:
@@ -683,7 +721,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
                        snd_printdd(KERN_INFO SFX
                                    "%s: Apply fix-verbs for %s\n",
                                    codec->chip_name, modelname);
-                       snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
+                       snd_hda_add_verbs(codec, fix->v.verbs);
                        break;
                case HDA_FIXUP_FUNC:
                        if (!fix->v.func)
@@ -693,19 +731,33 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
                                    codec->chip_name, modelname);
                        fix->v.func(codec, fix, action);
                        break;
+               case HDA_FIXUP_PINCTLS:
+                       if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
+                               break;
+                       snd_printdd(KERN_INFO SFX
+                                   "%s: Apply pinctl for %s\n",
+                                   codec->chip_name, modelname);
+                       set_pin_targets(codec, fix->v.pins);
+                       break;
                default:
                        snd_printk(KERN_ERR SFX
                                   "%s: Invalid fixup type %d\n",
                                   codec->chip_name, fix->type);
                        break;
                }
-               if (!fix->chained)
+               if (!fix->chained || fix->chained_before)
                        break;
                if (++depth > 10)
                        break;
                id = fix->chain_id;
        }
 }
+
+void snd_hda_apply_fixup(struct hda_codec *codec, int action)
+{
+       if (codec->fixup_list)
+               apply_fixup(codec, codec->fixup_id, action, 0);
+}
 EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
 
 void snd_hda_pick_fixup(struct hda_codec *codec,
@@ -713,15 +765,14 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                        const struct snd_pci_quirk *quirk,
                        const struct hda_fixup *fixlist)
 {
-       struct hda_gen_spec *spec = codec->spec;
        const struct snd_pci_quirk *q;
        int id = -1;
        const char *name = NULL;
 
        /* when model=nofixup is given, don't pick up any fixups */
        if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
-               spec->fixup_list = NULL;
-               spec->fixup_id = -1;
+               codec->fixup_list = NULL;
+               codec->fixup_id = -1;
                return;
        }
 
@@ -759,10 +810,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                }
        }
 
-       spec->fixup_id = id;
+       codec->fixup_id = id;
        if (id >= 0) {
-               spec->fixup_list = fixlist;
-               spec->fixup_name = name;
+               codec->fixup_list = fixlist;
+               codec->fixup_name = name;
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
index 632ad0a..f748071 100644 (file)
@@ -51,8 +51,9 @@ enum {
        INPUT_PIN_ATTR_INT,     /* internal mic/line-in */
        INPUT_PIN_ATTR_DOCK,    /* docking mic/line-in */
        INPUT_PIN_ATTR_NORMAL,  /* mic/line-in jack */
-       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
        INPUT_PIN_ATTR_REAR,    /* mic/line-in jack in rear */
+       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
+       INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT,
 };
 
 int snd_hda_get_input_pin_attr(unsigned int def_conf);
@@ -89,82 +90,4 @@ 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)
 
-/*
- */
-
-struct hda_gen_spec {
-       /* fix-up list */
-       int fixup_id;
-       const struct hda_fixup *fixup_list;
-       const char *fixup_name;
-
-       /* additional init verbs */
-       struct snd_array verbs;
-};
-
-
-/*
- * Fix-up pin default configurations and add default verbs
- */
-
-struct hda_pintbl {
-       hda_nid_t nid;
-       u32 val;
-};
-
-struct hda_model_fixup {
-       const int id;
-       const char *name;
-};
-
-struct hda_fixup {
-       int type;
-       bool chained;
-       int chain_id;
-       union {
-               const struct hda_pintbl *pins;
-               const struct hda_verb *verbs;
-               void (*func)(struct hda_codec *codec,
-                            const struct hda_fixup *fix,
-                            int action);
-       } v;
-};
-
-/* fixup types */
-enum {
-       HDA_FIXUP_INVALID,
-       HDA_FIXUP_PINS,
-       HDA_FIXUP_VERBS,
-       HDA_FIXUP_FUNC,
-};
-
-/* fixup action definitions */
-enum {
-       HDA_FIXUP_ACT_PRE_PROBE,
-       HDA_FIXUP_ACT_PROBE,
-       HDA_FIXUP_ACT_INIT,
-       HDA_FIXUP_ACT_BUILD,
-};
-
-int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
-                         const struct hda_verb *list);
-void snd_hda_gen_apply_verbs(struct hda_codec *codec);
-void snd_hda_apply_pincfgs(struct hda_codec *codec,
-                          const struct hda_pintbl *cfg);
-void snd_hda_apply_fixup(struct hda_codec *codec, int action);
-void snd_hda_pick_fixup(struct hda_codec *codec,
-                       const struct hda_model_fixup *models,
-                       const struct snd_pci_quirk *quirk,
-                       const struct hda_fixup *fixlist);
-
-static inline void snd_hda_gen_init(struct hda_gen_spec *spec)
-{
-       snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
-}
-
-static inline void snd_hda_gen_free(struct hda_gen_spec *spec)
-{
-       snd_array_free(&spec->verbs);
-}
-
 #endif /* __SOUND_HDA_AUTO_PARSER_H */
index 822df97..04b5738 100644 (file)
@@ -222,8 +222,14 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  again:
        snd_hda_power_up(codec);
        mutex_lock(&bus->cmd_mutex);
-       trace_hda_send_cmd(codec, cmd);
-       err = bus->ops.command(bus, cmd);
+       for (;;) {
+               trace_hda_send_cmd(codec, cmd);
+               err = bus->ops.command(bus, cmd);
+               if (err != -EAGAIN)
+                       break;
+               /* process pending verbs */
+               bus->ops.get_response(bus, codec->addr);
+       }
        if (!err && res) {
                *res = bus->ops.get_response(bus, codec->addr);
                trace_hda_get_response(codec, *res);
@@ -328,32 +334,116 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 
+/* connection list element */
+struct hda_conn_list {
+       struct list_head list;
+       int len;
+       hda_nid_t nid;
+       hda_nid_t conns[0];
+};
+
 /* look up the cached results */
-static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
+static struct hda_conn_list *
+lookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
 {
-       int i, len;
-       for (i = 0; i < array->used; ) {
-               hda_nid_t *p = snd_array_elem(array, i);
-               if (nid == *p)
+       struct hda_conn_list *p;
+       list_for_each_entry(p, &codec->conn_list, list) {
+               if (p->nid == nid)
                        return p;
-               len = p[1];
-               i += len + 2;
        }
        return NULL;
 }
 
+static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
+                        const hda_nid_t *list)
+{
+       struct hda_conn_list *p;
+
+       p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->len = len;
+       p->nid = nid;
+       memcpy(p->conns, list, len * sizeof(hda_nid_t));
+       list_add(&p->list, &codec->conn_list);
+       return 0;
+}
+
+static void remove_conn_list(struct hda_codec *codec)
+{
+       while (!list_empty(&codec->conn_list)) {
+               struct hda_conn_list *p;
+               p = list_first_entry(&codec->conn_list, typeof(*p), list);
+               list_del(&p->list);
+               kfree(p);
+       }
+}
+
 /* read the connection and add to the cache */
 static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 {
-       hda_nid_t list[HDA_MAX_CONNECTIONS];
+       hda_nid_t list[32];
+       hda_nid_t *result = list;
        int len;
 
        len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
-       if (len < 0)
-               return len;
-       return snd_hda_override_conn_list(codec, nid, len, list);
+       if (len == -ENOSPC) {
+               len = snd_hda_get_num_raw_conns(codec, nid);
+               result = kmalloc(sizeof(hda_nid_t) * len, GFP_KERNEL);
+               if (!result)
+                       return -ENOMEM;
+               len = snd_hda_get_raw_connections(codec, nid, result, len);
+       }
+       if (len >= 0)
+               len = snd_hda_override_conn_list(codec, nid, len, result);
+       if (result != list)
+               kfree(result);
+       return len;
 }
 
+/**
+ * snd_hda_get_conn_list - get connection list
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @len: number of connection list entries
+ * @listp: the pointer to store NID list
+ *
+ * Parses the connection list of the given widget and stores the pointer
+ * to the list of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ *
+ * Note that the returned pointer isn't protected against the list
+ * modification.  If snd_hda_override_conn_list() might be called
+ * concurrently, protect with a mutex appropriately.
+ */
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+                         const hda_nid_t **listp)
+{
+       bool added = false;
+
+       for (;;) {
+               int err;
+               const struct hda_conn_list *p;
+
+               /* if the connection-list is already cached, read it */
+               p = lookup_conn_list(codec, nid);
+               if (p) {
+                       if (listp)
+                               *listp = p->conns;
+                       return p->len;
+               }
+               if (snd_BUG_ON(added))
+                       return -EINVAL;
+
+               err = read_and_add_raw_conns(codec, nid);
+               if (err < 0)
+                       return err;
+               added = true;
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
+
 /**
  * snd_hda_get_connections - copy connection list
  * @codec: the HDA codec
@@ -369,42 +459,44 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                            hda_nid_t *conn_list, int max_conns)
 {
-       struct snd_array *array = &codec->conn_lists;
-       int len;
-       hda_nid_t *p;
-       bool added = false;
+       const hda_nid_t *list;
+       int len = snd_hda_get_conn_list(codec, nid, &list);
 
- again:
-       mutex_lock(&codec->hash_mutex);
-       len = -1;
-       /* if the connection-list is already cached, read it */
-       p = lookup_conn_list(array, nid);
-       if (p) {
-               len = p[1];
-               if (conn_list && len > max_conns) {
+       if (len > 0 && conn_list) {
+               if (len > max_conns) {
                        snd_printk(KERN_ERR "hda_codec: "
                                   "Too many connections %d for NID 0x%x\n",
                                   len, nid);
-                       mutex_unlock(&codec->hash_mutex);
                        return -EINVAL;
                }
-               if (conn_list && len)
-                       memcpy(conn_list, p + 2, len * sizeof(hda_nid_t));
+               memcpy(conn_list, list, len * sizeof(hda_nid_t));
        }
-       mutex_unlock(&codec->hash_mutex);
-       if (len >= 0)
-               return len;
-       if (snd_BUG_ON(added))
-               return -EINVAL;
 
-       len = read_and_add_raw_conns(codec, nid);
-       if (len < 0)
-               return len;
-       added = true;
-       goto again;
+       return len;
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
+/* return CONNLIST_LEN parameter of the given widget */
+static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       unsigned int parm;
+
+       if (!(wcaps & AC_WCAP_CONN_LIST) &&
+           get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+               return 0;
+
+       parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
+       if (parm == -1)
+               parm = 0;
+       return parm;
+}
+
+int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+       return get_num_conns(codec, nid) & AC_CLIST_LENGTH;
+}
+
 /**
  * snd_hda_get_raw_connections - copy connection list without cache
  * @codec: the HDA codec
@@ -422,18 +514,16 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
        unsigned int parm;
        int i, conn_len, conns;
        unsigned int shift, num_elems, mask;
-       unsigned int wcaps;
        hda_nid_t prev_nid;
+       int null_count = 0;
 
        if (snd_BUG_ON(!conn_list || max_conns <= 0))
                return -EINVAL;
 
-       wcaps = get_wcaps(codec, nid);
-       if (!(wcaps & AC_WCAP_CONN_LIST) &&
-           get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+       parm = get_num_conns(codec, nid);
+       if (!parm)
                return 0;
 
-       parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
                /* long form */
                shift = 16;
@@ -474,7 +564,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                }
                range_val = !!(parm & (1 << (shift-1))); /* ranges */
                val = parm & mask;
-               if (val == 0) {
+               if (val == 0 && null_count++) {  /* no second chance */
                        snd_printk(KERN_WARNING "hda_codec: "
                                   "invalid CONNECT_LIST verb %x[%i]:%x\n",
                                    nid, i, parm);
@@ -490,21 +580,13 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                                continue;
                        }
                        for (n = prev_nid + 1; n <= val; n++) {
-                               if (conns >= max_conns) {
-                                       snd_printk(KERN_ERR "hda_codec: "
-                                                  "Too many connections %d for NID 0x%x\n",
-                                                  conns, nid);
-                                       return -EINVAL;
-                               }
+                               if (conns >= max_conns)
+                                       return -ENOSPC;
                                conn_list[conns++] = n;
                        }
                } else {
-                       if (conns >= max_conns) {
-                               snd_printk(KERN_ERR "hda_codec: "
-                                          "Too many connections %d for NID 0x%x\n",
-                                          conns, nid);
-                               return -EINVAL;
-                       }
+                       if (conns >= max_conns)
+                               return -ENOSPC;
                        conn_list[conns++] = val;
                }
                prev_nid = val;
@@ -512,15 +594,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
        return conns;
 }
 
-static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
-{
-       hda_nid_t *p = snd_array_new(array);
-       if (!p)
-               return false;
-       *p = nid;
-       return true;
-}
-
 /**
  * snd_hda_override_conn_list - add/modify the connection-list to cache
  * @codec: the HDA codec
@@ -536,28 +609,15 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
                               const hda_nid_t *list)
 {
-       struct snd_array *array = &codec->conn_lists;
-       hda_nid_t *p;
-       int i, old_used;
+       struct hda_conn_list *p;
 
-       mutex_lock(&codec->hash_mutex);
-       p = lookup_conn_list(array, nid);
-       if (p)
-               *p = -1; /* invalidate the old entry */
-
-       old_used = array->used;
-       if (!add_conn_list(array, nid) || !add_conn_list(array, len))
-               goto error_add;
-       for (i = 0; i < len; i++)
-               if (!add_conn_list(array, list[i]))
-                       goto error_add;
-       mutex_unlock(&codec->hash_mutex);
-       return 0;
+       p = lookup_conn_list(codec, nid);
+       if (p) {
+               list_del(&p->list);
+               kfree(p);
+       }
 
- error_add:
-       array->used = old_used;
-       mutex_unlock(&codec->hash_mutex);
-       return -ENOMEM;
+       return add_conn_list(codec, nid, len, list);
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
 
@@ -575,16 +635,16 @@ EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
                           hda_nid_t nid, int recursive)
 {
-       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+       const hda_nid_t *conn;
        int i, nums;
 
-       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+       nums = snd_hda_get_conn_list(codec, mux, &conn);
        for (i = 0; i < nums; i++)
                if (conn[i] == nid)
                        return i;
        if (!recursive)
                return -1;
-       if (recursive > 5) {
+       if (recursive > 10) {
                snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
                return -1;
        }
@@ -1046,9 +1106,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
        struct hda_pincfg *pin;
 
 #ifdef CONFIG_SND_HDA_HWDEP
-       pin = look_up_pincfg(codec, &codec->user_pins, nid);
-       if (pin)
-               return pin->cfg;
+       {
+               unsigned int cfg = 0;
+               mutex_lock(&codec->user_mutex);
+               pin = look_up_pincfg(codec, &codec->user_pins, nid);
+               if (pin)
+                       cfg = pin->cfg;
+               mutex_unlock(&codec->user_mutex);
+               if (cfg)
+                       return cfg;
+       }
 #endif
        pin = look_up_pincfg(codec, &codec->driver_pins, nid);
        if (pin)
@@ -1060,6 +1127,32 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
 
+/* remember the current pinctl target value */
+int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int val)
+{
+       struct hda_pincfg *pin;
+
+       pin = look_up_pincfg(codec, &codec->init_pins, nid);
+       if (!pin)
+               return -EINVAL;
+       pin->target = val;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_set_pin_target);
+
+/* return the current pinctl target value */
+int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_pincfg *pin;
+
+       pin = look_up_pincfg(codec, &codec->init_pins, nid);
+       if (!pin)
+               return 0;
+       return pin->target;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_get_pin_target);
+
 /**
  * snd_hda_shutup_pins - Shut up all pins
  * @codec: the HDA codec
@@ -1179,8 +1272,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        snd_array_free(&codec->mixers);
        snd_array_free(&codec->nids);
        snd_array_free(&codec->cvt_setups);
-       snd_array_free(&codec->conn_lists);
        snd_array_free(&codec->spdif_out);
+       remove_conn_list(codec);
        codec->bus->caddr_tbl[codec->addr] = NULL;
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
@@ -1203,6 +1296,8 @@ 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
@@ -1250,9 +1345,11 @@ int snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
-       snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
        snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
        snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
+       snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
+       INIT_LIST_HEAD(&codec->conn_list);
+
        INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
 
 #ifdef CONFIG_PM
@@ -1321,6 +1418,7 @@ 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);
@@ -1343,6 +1441,30 @@ int snd_hda_codec_new(struct hda_bus *bus,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_new);
 
+int snd_hda_codec_update_widgets(struct hda_codec *codec)
+{
+       hda_nid_t fg;
+       int err;
+
+       /* Assume the function group node does not change,
+        * only the widget nodes may change.
+        */
+       kfree(codec->wcaps);
+       fg = codec->afg ? codec->afg : codec->mfg;
+       err = read_widget_caps(codec, fg);
+       if (err < 0) {
+               snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
+               return err;
+       }
+
+       snd_array_free(&codec->init_pins);
+       err = read_pin_defaults(codec);
+
+       return err;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets);
+
+
 /**
  * snd_hda_codec_configure - (Re-)configure the HD-audio codec
  * @codec: the HDA codec
@@ -1451,7 +1573,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
                    "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
                    nid, stream_tag, channel_id, format);
        p = get_hda_cvt_setup(codec, nid);
-       if (!p)
+       if (!p || p->active)
                return;
 
        if (codec->pcm_format_first)
@@ -1498,7 +1620,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
 
        snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
        p = get_hda_cvt_setup(codec, nid);
-       if (p) {
+       if (p && p->active) {
                /* here we just clear the active flag when do_now isn't set;
                 * actual clean-ups will be done later in
                 * purify_inactive_streams() called from snd_hda_codec_prpapre()
@@ -1610,6 +1732,7 @@ static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
                cur = snd_array_index(&cache->buf, info);
                info->key = key;
                info->val = 0;
+               info->dirty = 0;
                idx = key % (u16)ARRAY_SIZE(cache->hash);
                info->next = cache->hash[idx];
                cache->hash[idx] = cur;
@@ -1764,7 +1887,7 @@ EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
  */
 static struct hda_amp_info *
 update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
-               int direction, int index)
+               int direction, int index, bool init_only)
 {
        struct hda_amp_info *info;
        unsigned int parm, val = 0;
@@ -1790,14 +1913,15 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
                }
                info->vol[ch] = val;
                info->head.val |= INFO_AMP_VOL(ch);
-       }
+       } else if (init_only)
+               return NULL;
        return info;
 }
 
 /*
  * write the current volume in info to the h/w
  */
-static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
+static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps,
                         hda_nid_t nid, int ch, int direction, int index,
                         int val)
 {
@@ -1806,8 +1930,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
        parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
        parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
        parm |= index << AC_AMP_SET_INDEX_SHIFT;
-       if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) &&
-           (info->amp_caps & AC_AMPCAP_MIN_MUTE))
+       if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) &&
+           (amp_caps & AC_AMPCAP_MIN_MUTE))
                ; /* set the zero value as a fake mute */
        else
                parm |= val;
@@ -1831,7 +1955,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
        unsigned int val = 0;
 
        mutex_lock(&codec->hash_mutex);
-       info = update_amp_hash(codec, nid, ch, direction, index);
+       info = update_amp_hash(codec, nid, ch, direction, index, false);
        if (info)
                val = info->vol[ch];
        mutex_unlock(&codec->hash_mutex);
@@ -1839,30 +1963,20 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
 
-/**
- * snd_hda_codec_amp_update - update the AMP value
- * @codec: HD-audio codec
- * @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @idx: the index value (only for input direction)
- * @mask: bit mask to set
- * @val: the bits value to set
- *
- * Update the AMP value with a bit mask.
- * Returns 0 if the value is unchanged, 1 if changed.
- */
-int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
-                            int direction, int idx, int mask, int val)
+static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
+                           int direction, int idx, int mask, int val,
+                           bool init_only)
 {
        struct hda_amp_info *info;
+       unsigned int caps;
+       unsigned int cache_only;
 
        if (snd_BUG_ON(mask & ~0xff))
                mask &= 0xff;
        val &= mask;
 
        mutex_lock(&codec->hash_mutex);
-       info = update_amp_hash(codec, nid, ch, direction, idx);
+       info = update_amp_hash(codec, nid, ch, direction, idx, init_only);
        if (!info) {
                mutex_unlock(&codec->hash_mutex);
                return 0;
@@ -1873,10 +1987,32 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                return 0;
        }
        info->vol[ch] = val;
+       cache_only = info->head.dirty = codec->cached_write;
+       caps = info->amp_caps;
        mutex_unlock(&codec->hash_mutex);
-       put_vol_mute(codec, info, nid, ch, direction, idx, val);
+       if (!cache_only)
+               put_vol_mute(codec, caps, nid, ch, direction, idx, val);
        return 1;
 }
+
+/**
+ * snd_hda_codec_amp_update - update the AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP value with a bit mask.
+ * Returns 0 if the value is unchanged, 1 if changed.
+ */
+int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
+                            int direction, int idx, int mask, int val)
+{
+       return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false);
+}
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update);
 
 /**
@@ -1905,7 +2041,31 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
 
-#ifdef CONFIG_PM
+/* Works like snd_hda_codec_amp_update() but it writes the value only at
+ * the first access.  If the amp was already initialized / updated beforehand,
+ * this does nothing.
+ */
+int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
+                          int dir, int idx, int mask, int val)
+{
+       return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init);
+
+int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
+                                 int dir, int idx, int mask, int val)
+{
+       int ch, ret = 0;
+
+       if (snd_BUG_ON(mask & ~0xff))
+               mask &= 0xff;
+       for (ch = 0; ch < 2; ch++)
+               ret |= snd_hda_codec_amp_init(codec, nid, ch, dir,
+                                             idx, mask, val);
+       return ret;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo);
+
 /**
  * snd_hda_codec_resume_amp - Resume all AMP commands from the cache
  * @codec: HD-audio codec
@@ -1914,28 +2074,40 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
  */
 void snd_hda_codec_resume_amp(struct hda_codec *codec)
 {
-       struct hda_amp_info *buffer = codec->amp_cache.buf.list;
        int i;
 
-       for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) {
-               u32 key = buffer->head.key;
+       mutex_lock(&codec->hash_mutex);
+       codec->cached_write = 0;
+       for (i = 0; i < codec->amp_cache.buf.used; i++) {
+               struct hda_amp_info *buffer;
+               u32 key;
                hda_nid_t nid;
                unsigned int idx, dir, ch;
+               struct hda_amp_info info;
+
+               buffer = snd_array_elem(&codec->amp_cache.buf, i);
+               if (!buffer->head.dirty)
+                       continue;
+               buffer->head.dirty = 0;
+               info = *buffer;
+               key = info.head.key;
                if (!key)
                        continue;
                nid = key & 0xff;
                idx = (key >> 16) & 0xff;
                dir = (key >> 24) & 0xff;
                for (ch = 0; ch < 2; ch++) {
-                       if (!(buffer->head.val & INFO_AMP_VOL(ch)))
+                       if (!(info.head.val & INFO_AMP_VOL(ch)))
                                continue;
-                       put_vol_mute(codec, buffer, nid, ch, dir, idx,
-                                    buffer->vol[ch]);
+                       mutex_unlock(&codec->hash_mutex);
+                       put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx,
+                                    info.vol[ch]);
+                       mutex_lock(&codec->hash_mutex);
                }
        }
+       mutex_unlock(&codec->hash_mutex);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
-#endif /* CONFIG_PM */
 
 static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
                             unsigned int ofs)
@@ -2160,11 +2332,12 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
 static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
-                                   int dev)
+                                   int start_idx)
 {
-       int idx;
-       for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */
-               if (!find_mixer_ctl(codec, name, dev, idx))
+       int i, idx;
+       /* 16 ctlrs should be large enough */
+       for (i = 0, idx = start_idx; i < 16; i++, idx++) {
+               if (!find_mixer_ctl(codec, name, 0, idx))
                        return idx;
        }
        return -EBUSY;
@@ -2362,6 +2535,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        snd_array_free(&codec->driver_pins);
        snd_array_free(&codec->cvt_setups);
        snd_array_free(&codec->spdif_out);
+       snd_array_free(&codec->verbs);
        codec->num_pcms = 0;
        codec->pcm_info = NULL;
        codec->preset = NULL;
@@ -3132,30 +3306,29 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
        int err;
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_new *dig_mix;
-       int idx, dev = 0;
-       const int spdif_pcm_dev = 1;
+       int idx = 0;
+       const int spdif_index = 16;
        struct hda_spdif_out *spdif;
+       struct hda_bus *bus = codec->bus;
 
-       if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
+       if (bus->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
            type == HDA_PCM_TYPE_SPDIF) {
-               dev = spdif_pcm_dev;
-       } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
+               idx = spdif_index;
+       } else if (bus->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
                   type == HDA_PCM_TYPE_HDMI) {
-               for (idx = 0; idx < codec->spdif_out.used; idx++) {
-                       spdif = snd_array_elem(&codec->spdif_out, idx);
-                       for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
-                               kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx);
-                               if (!kctl)
-                                       break;
-                               kctl->id.device = spdif_pcm_dev;
-                       }
+               /* suppose a single SPDIF device */
+               for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+                       kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0);
+                       if (!kctl)
+                               break;
+                       kctl->id.index = spdif_index;
                }
-               codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
+               bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
        }
-       if (!codec->primary_dig_out_type)
-               codec->primary_dig_out_type = type;
+       if (!bus->primary_dig_out_type)
+               bus->primary_dig_out_type = type;
 
-       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev);
+       idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx);
        if (idx < 0) {
                printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
                return -EBUSY;
@@ -3165,7 +3338,6 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
                kctl = snd_ctl_new1(dig_mix, codec);
                if (!kctl)
                        return -ENOMEM;
-               kctl->id.device = dev;
                kctl->id.index = idx;
                kctl->private_value = codec->spdif_out.used - 1;
                err = snd_hda_ctl_add(codec, associated_nid, kctl);
@@ -3375,12 +3547,11 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 
-#ifdef CONFIG_PM
 /*
  * command cache
  */
 
-/* build a 32bit cache key with the widget id and the command parameter */
+/* build a 31bit cache key with the widget id and the command parameter */
 #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid)
 #define get_cmd_cache_nid(key)         ((key) & 0xff)
 #define get_cmd_cache_cmd(key)         (((key) >> 8) & 0xffff)
@@ -3400,20 +3571,28 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm)
 {
-       int err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+       int err;
        struct hda_cache_head *c;
        u32 key;
+       unsigned int cache_only;
+
+       cache_only = codec->cached_write;
+       if (!cache_only) {
+               err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+               if (err < 0)
+                       return err;
+       }
 
-       if (err < 0)
-               return err;
        /* parm may contain the verb stuff for get/set amp */
        verb = verb | (parm >> 8);
        parm &= 0xff;
        key = build_cmd_cache_key(nid, verb);
        mutex_lock(&codec->bus->cmd_mutex);
        c = get_alloc_hash(&codec->cmd_cache, key);
-       if (c)
+       if (c) {
                c->val = parm;
+               c->dirty = cache_only;
+       }
        mutex_unlock(&codec->bus->cmd_mutex);
        return 0;
 }
@@ -3462,16 +3641,27 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
  */
 void snd_hda_codec_resume_cache(struct hda_codec *codec)
 {
-       struct hda_cache_head *buffer = codec->cmd_cache.buf.list;
        int i;
 
-       for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) {
-               u32 key = buffer->key;
+       mutex_lock(&codec->hash_mutex);
+       codec->cached_write = 0;
+       for (i = 0; i < codec->cmd_cache.buf.used; i++) {
+               struct hda_cache_head *buffer;
+               u32 key;
+
+               buffer = snd_array_elem(&codec->cmd_cache.buf, i);
+               key = buffer->key;
                if (!key)
                        continue;
+               if (!buffer->dirty)
+                       continue;
+               buffer->dirty = 0;
+               mutex_unlock(&codec->hash_mutex);
                snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0,
                                    get_cmd_cache_cmd(key), buffer->val);
+               mutex_lock(&codec->hash_mutex);
        }
+       mutex_unlock(&codec->hash_mutex);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache);
 
@@ -3492,32 +3682,36 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
                                          seq->param);
 }
 EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
-#endif /* CONFIG_PM */
+
+/**
+ * snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs
+ * @codec: HD-audio codec
+ */
+void snd_hda_codec_flush_cache(struct hda_codec *codec)
+{
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache);
 
 void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
-                                   unsigned int power_state,
-                                   bool eapd_workaround)
+                                   unsigned int power_state)
 {
        hda_nid_t nid = codec->start_nid;
        int i;
 
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int state = power_state;
                if (!(wcaps & AC_WCAP_POWER))
                        continue;
-               /* don't power down the widget if it controls eapd and
-                * EAPD_BTLENABLE is set.
-                */
-               if (eapd_workaround && power_state == AC_PWRST_D3 &&
-                   get_wcaps_type(wcaps) == AC_WID_PIN &&
-                   (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
-                       int eapd = snd_hda_codec_read(codec, nid, 0,
-                                               AC_VERB_GET_EAPD_BTLENABLE, 0);
-                       if (eapd & 0x02)
+               if (codec->power_filter) {
+                       state = codec->power_filter(codec, nid, power_state);
+                       if (state != power_state && power_state == AC_PWRST_D3)
                                continue;
                }
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
-                                   power_state);
+                                   state);
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
@@ -3564,6 +3758,21 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
        return state;
 }
 
+/* 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)
+{
+       if (power_state == AC_PWRST_D3 &&
+           get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
+           (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
+               int eapd = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_EAPD_BTLENABLE, 0);
+               if (eapd & 0x02)
+                       return AC_PWRST_D0;
+       }
+       return power_state;
+}
+
 /*
  * set power state of the codec, and return the power state
  */
@@ -3589,8 +3798,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
                        snd_hda_codec_read(codec, fg, 0,
                                           AC_VERB_SET_POWER_STATE,
                                           power_state);
-                       snd_hda_codec_set_power_to_all(codec, fg, power_state,
-                                                      true);
+                       snd_hda_codec_set_power_to_all(codec, fg, power_state);
                }
                state = hda_sync_power_state(codec, fg, power_state);
                if (!(state & AC_PWRST_ERROR))
@@ -3600,6 +3808,32 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
        return state;
 }
 
+/* sync power states of all widgets;
+ * this is called at the end of codec parsing
+ */
+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)
+               return;
+
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int target;
+               if (!(wcaps & AC_WCAP_POWER))
+                       continue;
+               target = codec->power_filter(codec, nid, AC_PWRST_D0);
+               if (target == AC_PWRST_D0)
+                       continue;
+               if (!snd_hda_check_power_state(codec, nid, target))
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_POWER_STATE, target);
+       }
+}
+
 #ifdef CONFIG_SND_HDA_HWDEP
 /* execute additional init verbs */
 static void hda_exec_init_verbs(struct hda_codec *codec)
@@ -3640,6 +3874,22 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
        return state;
 }
 
+/* mark all entries of cmd and amp caches dirty */
+static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
+{
+       int i;
+       for (i = 0; i < codec->cmd_cache.buf.used; i++) {
+               struct hda_cache_head *cmd;
+               cmd = snd_array_elem(&codec->cmd_cache.buf, i);
+               cmd->dirty = 1;
+       }
+       for (i = 0; i < codec->amp_cache.buf.used; i++) {
+               struct hda_amp_info *amp;
+               amp = snd_array_elem(&codec->amp_cache.buf, i);
+               amp->head.dirty = 1;
+       }
+}
+
 /*
  * kick up codec; used both from PM and power-save
  */
@@ -3647,6 +3897,8 @@ static void hda_call_codec_resume(struct hda_codec *codec)
 {
        codec->in_pm = 1;
 
+       hda_mark_cmd_cache_dirty(codec);
+
        /* set as if powered on for avoiding re-entering the resume
         * in the resume / power-save sequence
         */
@@ -3769,6 +4021,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
                hda_jackpoll_work(&codec->jackpoll_work.work);
        else
                snd_hda_jack_report_sync(codec); /* call at the last init point */
+       sync_power_up_states(codec);
        return 0;
 }
 
@@ -5120,23 +5373,62 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
 
-int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
-                        unsigned int val, bool cached)
+/* correct the pin ctl value for matching with the pin cap */
+unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
+                                    hda_nid_t pin, unsigned int val)
 {
-       if (val) {
-               unsigned int cap = snd_hda_query_pin_caps(codec, pin);
-               if (cap && (val & AC_PINCTL_OUT_EN)) {
-                       if (!(cap & AC_PINCAP_OUT))
-                               val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
-                       else if ((val & AC_PINCTL_HP_EN) &&
-                                !(cap & AC_PINCAP_HP_DRV))
-                               val &= ~AC_PINCTL_HP_EN;
-               }
-               if (cap && (val & AC_PINCTL_IN_EN)) {
-                       if (!(cap & AC_PINCAP_IN))
-                               val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
+       static unsigned int cap_lists[][2] = {
+               { AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 },
+               { AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 },
+               { AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 },
+               { AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD },
+       };
+       unsigned int cap;
+
+       if (!val)
+               return 0;
+       cap = snd_hda_query_pin_caps(codec, pin);
+       if (!cap)
+               return val; /* don't know what to do... */
+
+       if (val & AC_PINCTL_OUT_EN) {
+               if (!(cap & AC_PINCAP_OUT))
+                       val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+               else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV))
+                       val &= ~AC_PINCTL_HP_EN;
+       }
+
+       if (val & AC_PINCTL_IN_EN) {
+               if (!(cap & AC_PINCAP_IN))
+                       val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
+               else {
+                       unsigned int vcap, vref;
+                       int i;
+                       vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+                       vref = val & AC_PINCTL_VREFEN;
+                       for (i = 0; i < ARRAY_SIZE(cap_lists); i++) {
+                               if (vref == cap_lists[i][0] &&
+                                   !(vcap & cap_lists[i][1])) {
+                                       if (i == ARRAY_SIZE(cap_lists) - 1)
+                                               vref = AC_PINCTL_VREF_HIZ;
+                                       else
+                                               vref = cap_lists[i + 1][0];
+                               }
+                       }
+                       val &= ~AC_PINCTL_VREFEN;
+                       val |= vref;
                }
        }
+
+       return val;
+}
+EXPORT_SYMBOL_HDA(snd_hda_correct_pin_ctl);
+
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+                        unsigned int val, bool cached)
+{
+       val = snd_hda_correct_pin_ctl(codec, pin, val);
+       snd_hda_codec_set_pin_target(codec, pin, val);
        if (cached)
                return snd_hda_codec_update_cache(codec, pin, 0,
                                AC_VERB_SET_PIN_WIDGET_CONTROL, val);
index 8665540..23ca172 100644 (file)
@@ -551,9 +551,6 @@ enum {
        AC_JACK_PORT_BOTH,
 };
 
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS    32
-
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS  0x0f
 
@@ -618,6 +615,17 @@ struct hda_bus_ops {
        /* notify power-up/down from codec to controller */
        void (*pm_notify)(struct hda_bus *bus, bool power_up);
 #endif
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       /* prepare DSP transfer */
+       int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
+                               unsigned int byte_size,
+                               struct snd_dma_buffer *bufp);
+       /* start/stop DSP transfer */
+       void (*load_dsp_trigger)(struct hda_bus *bus, bool start);
+       /* clean up DSP transfer */
+       void (*load_dsp_cleanup)(struct hda_bus *bus,
+                                struct snd_dma_buffer *dmab);
+#endif
 };
 
 /* template to pass to the bus constructor */
@@ -671,6 +679,8 @@ struct hda_bus {
        unsigned int response_reset:1;  /* controller was reset */
        unsigned int in_reset:1;        /* during reset operation */
        unsigned int power_keep_link_on:1; /* don't power off HDA link */
+
+       int primary_dig_out_type;       /* primary digital out PCM type */
 };
 
 /*
@@ -719,9 +729,10 @@ struct hda_codec_ops {
 
 /* record for amp information cache */
 struct hda_cache_head {
-       u32 key;                /* hash key */
+       u32 key:31;             /* hash key */
+       u32 dirty:1;
        u16 val;                /* assigned value */
-       u16 next;               /* next link; -1 = terminal */
+       u16 next;
 };
 
 struct hda_amp_info {
@@ -830,20 +841,20 @@ struct hda_codec {
        struct hda_cache_rec amp_cache; /* cache for amp access */
        struct hda_cache_rec cmd_cache; /* cache for other commands */
 
-       struct snd_array conn_lists;    /* connection-list array */
+       struct list_head conn_list;     /* linked-list of connection-list */
 
        struct mutex spdif_mutex;
        struct mutex control_mutex;
        struct mutex hash_mutex;
        struct snd_array spdif_out;
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
-       int primary_dig_out_type;       /* primary digital out PCM type */
        const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
        struct snd_array init_pins;     /* initial (BIOS) pin configurations */
        struct snd_array driver_pins;   /* pin configs set by codec parser */
        struct snd_array cvt_setups;    /* audio convert setups */
 
 #ifdef CONFIG_SND_HDA_HWDEP
+       struct mutex user_mutex;
        struct snd_hwdep *hwdep;        /* assigned hwdep device */
        struct snd_array init_verbs;    /* additional init verbs */
        struct snd_array hints;         /* additional hints */
@@ -865,8 +876,11 @@ struct hda_codec {
        unsigned int pins_shutup:1;     /* pins are shut up */
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
        unsigned int no_jack_detect:1;  /* Machine has no jack-detection */
+       unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */
+       unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */
        unsigned int pcm_format_first:1; /* PCM format must be set first */
        unsigned int epss:1;            /* supporting EPSS? */
+       unsigned int cached_write:1;    /* write only to caches */
 #ifdef CONFIG_PM
        unsigned int power_on :1;       /* current (global) power-state */
        unsigned int d3_stop_clk:1;     /* support D3 operation without BCLK */
@@ -881,6 +895,10 @@ struct hda_codec {
        spinlock_t power_lock;
 #endif
 
+       /* filter the requested power state per nid */
+       unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid,
+                                    unsigned int power_state);
+
        /* codec-specific additional proc output */
        void (*proc_widget_hook)(struct snd_info_buffer *buffer,
                                 struct hda_codec *codec, hda_nid_t nid);
@@ -894,6 +912,14 @@ struct hda_codec {
        /* jack detection */
        struct snd_array jacks;
 #endif
+
+       /* fix-up list */
+       int fixup_id;
+       const struct hda_fixup *fixup_list;
+       const char *fixup_name;
+
+       /* additional init verbs */
+       struct snd_array verbs;
 };
 
 /* direction */
@@ -910,6 +936,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
 int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
                      struct hda_codec **codecp);
 int snd_hda_codec_configure(struct hda_codec *codec);
+int snd_hda_codec_update_widgets(struct hda_codec *codec);
 
 /*
  * low level functions
@@ -930,8 +957,11 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
 {
        return snd_hda_get_connections(codec, nid, NULL, 0);
 }
+int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                            hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+                         const hda_nid_t **listp);
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
                          const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@@ -952,7 +982,6 @@ void snd_hda_sequence_write(struct hda_codec *codec,
 int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
 
 /* cached write */
-#ifdef CONFIG_PM
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
@@ -960,17 +989,14 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
 int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
-#else
-#define snd_hda_codec_write_cache      snd_hda_codec_write
-#define snd_hda_codec_update_cache     snd_hda_codec_write
-#define snd_hda_sequence_write_cache   snd_hda_sequence_write
-#endif
+/* both for cmd & amp caches */
+void snd_hda_codec_flush_cache(struct hda_codec *codec);
 
 /* the struct for codec->pin_configs */
 struct hda_pincfg {
        hda_nid_t nid;
-       unsigned char ctrl;     /* current pin control value */
-       unsigned char pad;      /* reserved */
+       unsigned char ctrl;     /* original pin control value */
+       unsigned char target;   /* target pin control value */
        unsigned int cfg;       /* default configuration */
 };
 
@@ -1036,8 +1062,7 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
 void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
 void snd_hda_bus_reboot_notify(struct hda_bus *bus);
 void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
-                                   unsigned int power_state,
-                                   bool eapd_workaround);
+                                   unsigned int power_state);
 
 int snd_hda_lock_devices(struct hda_bus *bus);
 void snd_hda_unlock_devices(struct hda_bus *bus);
@@ -1136,6 +1161,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec)
 int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
 #endif
 
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+static inline int
+snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
+                               unsigned int size,
+                               struct snd_dma_buffer *bufp)
+{
+       return codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp);
+}
+static inline void
+snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start)
+{
+       return codec->bus->ops.load_dsp_trigger(codec->bus, start);
+}
+static inline void
+snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
+                               struct snd_dma_buffer *dmab)
+{
+       return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab);
+}
+#else
+static inline int
+snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
+                               unsigned int size,
+                               struct snd_dma_buffer *bufp)
+{
+       return -ENOSYS;
+}
+static inline void
+snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {}
+static inline void
+snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
+                               struct snd_dma_buffer *dmab) {}
+#endif
+
 /*
  * Codec modularization
  */
index 4c054f4..7dd8463 100644 (file)
@@ -246,8 +246,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a,
 /*
  * Be careful, ELD buf could be totally rubbish!
  */
-static int hdmi_update_eld(struct hdmi_eld *e,
-                          const unsigned char *buf, int size)
+int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e,
+                         const unsigned char *buf, int size)
 {
        int mnl;
        int i;
@@ -260,7 +260,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
                goto out_fail;
        }
 
-       e->eld_size = size;
        e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
        mnl             = GRAB_BITS(buf, 4, 0, 5);
        e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
@@ -305,7 +304,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
        if (!e->spk_alloc)
                e->spk_alloc = 0xffff;
 
-       e->eld_valid = true;
        return 0;
 
 out_fail:
@@ -318,17 +316,16 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
                                                 AC_DIPSIZE_ELD_BUF);
 }
 
-int snd_hdmi_get_eld(struct hdmi_eld *eld,
-                    struct hda_codec *codec, hda_nid_t nid)
+int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
+                    unsigned char *buf, int *eld_size)
 {
        int i;
        int ret;
        int size;
-       unsigned char *buf;
 
        /*
         * ELD size is initialized to zero in caller function. If no errors and
-        * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
+        * ELD is valid, actual eld_size is assigned.
         */
 
        size = snd_hdmi_get_eld_size(codec, nid);
@@ -343,8 +340,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        }
 
        /* set ELD buffer */
-       buf = eld->eld_buffer;
-
        for (i = 0; i < size; i++) {
                unsigned int val = hdmi_get_eld_data(codec, nid, i);
                /*
@@ -372,8 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
                buf[i] = val;
        }
 
-       ret = hdmi_update_eld(eld, buf, size);
-
+       *eld_size = size;
 error:
        return ret;
 }
@@ -438,7 +432,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
        buf[j] = '\0';  /* necessary when j == 0 */
 }
 
-void snd_hdmi_show_eld(struct hdmi_eld *e)
+void snd_hdmi_show_eld(struct parsed_hdmi_eld *e)
 {
        int i;
 
@@ -487,10 +481,11 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
 static void hdmi_print_eld_info(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       struct hdmi_eld *e = entry->private_data;
+       struct hdmi_eld *eld = entry->private_data;
+       struct parsed_hdmi_eld *e = &eld->info;
        char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
        int i;
-       static char *eld_versoin_names[32] = {
+       static char *eld_version_names[32] = {
                "reserved",
                "reserved",
                "CEA-861D or below",
@@ -505,15 +500,18 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
                [4 ... 7] = "reserved"
        };
 
-       snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
-       snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
-       if (!e->eld_valid)
+       mutex_lock(&eld->lock);
+       snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
+       snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
+       if (!eld->eld_valid) {
+               mutex_unlock(&eld->lock);
                return;
+       }
        snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
        snd_iprintf(buffer, "connection_type\t\t%s\n",
                                eld_connection_type_names[e->conn_type]);
        snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
-                                       eld_versoin_names[e->eld_ver]);
+                                       eld_version_names[e->eld_ver]);
        snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
                                cea_edid_version_names[e->cea_edid_ver]);
        snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
@@ -530,18 +528,21 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
 
        for (i = 0; i < e->sad_count; i++)
                hdmi_print_sad_info(i, e->sad + i, buffer);
+       mutex_unlock(&eld->lock);
 }
 
 static void hdmi_write_eld_info(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       struct hdmi_eld *e = entry->private_data;
+       struct hdmi_eld *eld = entry->private_data;
+       struct parsed_hdmi_eld *e = &eld->info;
        char line[64];
        char name[64];
        char *sname;
        long long val;
        unsigned int n;
 
+       mutex_lock(&eld->lock);
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
                if (sscanf(line, "%s %llx", name, &val) != 2)
                        continue;
@@ -551,9 +552,9 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
                 *      eld_version edid_version
                 */
                if (!strcmp(name, "monitor_present"))
-                       e->monitor_present = val;
+                       eld->monitor_present = val;
                else if (!strcmp(name, "eld_valid"))
-                       e->eld_valid = val;
+                       eld->eld_valid = val;
                else if (!strcmp(name, "connection_type"))
                        e->conn_type = val;
                else if (!strcmp(name, "port_id"))
@@ -593,6 +594,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
                                e->sad_count = n + 1;
                }
        }
+       mutex_unlock(&eld->lock);
 }
 
 
@@ -627,7 +629,7 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 #endif /* CONFIG_PROC_FS */
 
 /* update PCM info based on ELD */
-void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
+void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
                              struct hda_pcm_stream *hinfo)
 {
        u32 rates;
@@ -644,8 +646,8 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
        formats = SNDRV_PCM_FMTBIT_S16_LE;
        maxbps = 16;
        channels_max = 2;
-       for (i = 0; i < eld->sad_count; i++) {
-               struct cea_sad *a = &eld->sad[i];
+       for (i = 0; i < e->sad_count; i++) {
+               struct cea_sad *a = &e->sad[i];
                rates |= a->rates;
                if (a->channels > channels_max)
                        channels_max = a->channels;
index b81d3d0..78897d0 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/sort.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "hda_generic.h"
 
-/* widget node for parsing */
-struct hda_gnode {
-       hda_nid_t nid;          /* NID of this widget */
-       unsigned short nconns;  /* number of input connections */
-       hda_nid_t *conn_list;
-       hda_nid_t slist[2];     /* temporay list */
-       unsigned int wid_caps;  /* widget capabilities */
-       unsigned char type;     /* widget type */
-       unsigned char pin_ctl;  /* pin controls */
-       unsigned char checked;  /* the flag indicates that the node is already parsed */
-       unsigned int pin_caps;  /* pin widget capabilities */
-       unsigned int def_cfg;   /* default configuration */
-       unsigned int amp_out_caps;      /* AMP out capabilities */
-       unsigned int amp_in_caps;       /* AMP in capabilities */
-       struct list_head list;
-};
 
-/* patch-specific record */
+/* initialize hda_gen_spec struct */
+int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
+{
+       snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+       snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
+       snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
+       mutex_init(&spec->pcm_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
 
-#define MAX_PCM_VOLS   2
-struct pcm_vol {
-       struct hda_gnode *node; /* Node for PCM volume */
-       unsigned int index;     /* connection of PCM volume */
-};
+struct snd_kcontrol_new *
+snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
+                    const struct snd_kcontrol_new *temp)
+{
+       struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
+       if (!knew)
+               return NULL;
+       *knew = *temp;
+       if (name)
+               knew->name = kstrdup(name, GFP_KERNEL);
+       else if (knew->name)
+               knew->name = kstrdup(knew->name, GFP_KERNEL);
+       if (!knew->name)
+               return NULL;
+       return knew;
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
 
-struct hda_gspec {
-       struct hda_gnode *dac_node[2];  /* DAC node */
-       struct hda_gnode *out_pin_node[2];      /* Output pin (Line-Out) node */
-       struct pcm_vol pcm_vol[MAX_PCM_VOLS];   /* PCM volumes */
-       unsigned int pcm_vol_nodes;     /* number of PCM volumes */
+static void free_kctls(struct hda_gen_spec *spec)
+{
+       if (spec->kctls.list) {
+               struct snd_kcontrol_new *kctl = spec->kctls.list;
+               int i;
+               for (i = 0; i < spec->kctls.used; i++)
+                       kfree(kctl[i].name);
+       }
+       snd_array_free(&spec->kctls);
+}
 
-       struct hda_gnode *adc_node;     /* ADC node */
-       struct hda_gnode *cap_vol_node; /* Node for capture volume */
-       unsigned int cur_cap_src;       /* current capture source */
-       struct hda_input_mux input_mux;
+void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
+{
+       if (!spec)
+               return;
+       free_kctls(spec);
+       snd_array_free(&spec->paths);
+       snd_array_free(&spec->loopback_list);
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
 
-       unsigned int def_amp_in_caps;
-       unsigned int def_amp_out_caps;
+/*
+ * store user hints
+ */
+static void parse_user_hints(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int val;
 
-       struct hda_pcm pcm_rec;         /* PCM information */
+       val = snd_hda_get_bool_hint(codec, "jack_detect");
+       if (val >= 0)
+               codec->no_jack_detect = !val;
+       val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
+       if (val >= 0)
+               codec->inv_jack_detect = !!val;
+       val = snd_hda_get_bool_hint(codec, "trigger_sense");
+       if (val >= 0)
+               codec->no_trigger_sense = !val;
+       val = snd_hda_get_bool_hint(codec, "inv_eapd");
+       if (val >= 0)
+               codec->inv_eapd = !!val;
+       val = snd_hda_get_bool_hint(codec, "pcm_format_first");
+       if (val >= 0)
+               codec->pcm_format_first = !!val;
+       val = snd_hda_get_bool_hint(codec, "sticky_stream");
+       if (val >= 0)
+               codec->no_sticky_stream = !val;
+       val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
+       if (val >= 0)
+               codec->spdif_status_reset = !!val;
+       val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
+       if (val >= 0)
+               codec->pin_amp_workaround = !!val;
+       val = snd_hda_get_bool_hint(codec, "single_adc_amp");
+       if (val >= 0)
+               codec->single_adc_amp = !!val;
 
-       struct list_head nid_list;      /* list of widgets */
+       val = snd_hda_get_bool_hint(codec, "auto_mute");
+       if (val >= 0)
+               spec->suppress_auto_mute = !val;
+       val = snd_hda_get_bool_hint(codec, "auto_mic");
+       if (val >= 0)
+               spec->suppress_auto_mic = !val;
+       val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
+       if (val >= 0)
+               spec->line_in_auto_switch = !!val;
+       val = snd_hda_get_bool_hint(codec, "need_dac_fix");
+       if (val >= 0)
+               spec->need_dac_fix = !!val;
+       val = snd_hda_get_bool_hint(codec, "primary_hp");
+       if (val >= 0)
+               spec->no_primary_hp = !val;
+       val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
+       if (val >= 0)
+               spec->multi_cap_vol = !!val;
+       val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
+       if (val >= 0)
+               spec->inv_dmic_split = !!val;
+       val = snd_hda_get_bool_hint(codec, "indep_hp");
+       if (val >= 0)
+               spec->indep_hp = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
+       if (val >= 0)
+               spec->add_stereo_mix_input = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
+       if (val >= 0)
+               spec->add_out_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
+       if (val >= 0)
+               spec->add_in_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "power_down_unused");
+       if (val >= 0)
+               spec->power_down_unused = !!val;
 
-#ifdef CONFIG_PM
-#define MAX_LOOPBACK_AMPS      7
-       struct hda_loopback_check loopback;
-       int num_loopbacks;
-       struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1];
-#endif
-};
+       if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
+               spec->mixer_nid = val;
+}
 
 /*
- * retrieve the default device type from the default config value
+ * pin control value accesses
  */
-#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \
-                          AC_DEFCFG_DEVICE_SHIFT)
-#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \
-                              AC_DEFCFG_LOCATION_SHIFT)
-#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \
-                               AC_DEFCFG_PORT_CONN_SHIFT)
 
-/*
- * destructor
- */
-static void snd_hda_generic_free(struct hda_codec *codec)
+#define update_pin_ctl(codec, pin, val) \
+       snd_hda_codec_update_cache(codec, pin, 0, \
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+/* restore the pinctl based on the cached value */
+static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
 {
-       struct hda_gspec *spec = codec->spec;
-       struct hda_gnode *node, *n;
+       update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
+}
 
-       if (! spec)
+/* set the pinctl target value and write it if requested */
+static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
+                          unsigned int val, bool do_write)
+{
+       if (!pin)
                return;
-       /* free all widgets */
-       list_for_each_entry_safe(node, n, &spec->nid_list, list) {
-               if (node->conn_list != node->slist)
-                       kfree(node->conn_list);
-               kfree(node);
-       }
-       kfree(spec);
+       val = snd_hda_correct_pin_ctl(codec, pin, val);
+       snd_hda_codec_set_pin_target(codec, pin, val);
+       if (do_write)
+               update_pin_ctl(codec, pin, val);
 }
 
+/* set pinctl target values for all given pins */
+static void set_pin_targets(struct hda_codec *codec, int num_pins,
+                           hda_nid_t *pins, unsigned int val)
+{
+       int i;
+       for (i = 0; i < num_pins; i++)
+               set_pin_target(codec, pins[i], val, false);
+}
 
 /*
- * add a new widget node and read its attributes
+ * parsing paths
  */
-static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid)
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
 {
-       struct hda_gnode *node;
-       int nconns;
-       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
 
-       node = kzalloc(sizeof(*node), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
-       node->nid = nid;
-       node->wid_caps = get_wcaps(codec, nid);
-       node->type = get_wcaps_type(node->wid_caps);
-       if (node->wid_caps & AC_WCAP_CONN_LIST) {
-               nconns = snd_hda_get_connections(codec, nid, conn_list,
-                                                HDA_MAX_CONNECTIONS);
-               if (nconns < 0) {
-                       kfree(node);
-                       return nconns;
-               }
-       } else {
-               nconns = 0;
-       }
-       if (nconns <= ARRAY_SIZE(node->slist))
-               node->conn_list = node->slist;
-       else {
-               node->conn_list = kmalloc(sizeof(hda_nid_t) * nconns,
-                                         GFP_KERNEL);
-               if (! node->conn_list) {
-                       snd_printk(KERN_ERR "hda-generic: cannot malloc\n");
-                       kfree(node);
-                       return -ENOMEM;
-               }
-       }
-       memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
-       node->nconns = nconns;
+/* return true if the given NID is contained in the path */
+static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
+{
+       return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
+}
 
-       if (node->type == AC_WID_PIN) {
-               node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
-               node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid);
-       }
+static struct nid_path *get_nid_path(struct hda_codec *codec,
+                                    hda_nid_t from_nid, hda_nid_t to_nid,
+                                    int anchor_nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
 
-       if (node->wid_caps & AC_WCAP_OUT_AMP) {
-               if (node->wid_caps & AC_WCAP_AMP_OVRD)
-                       node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP);
-               if (! node->amp_out_caps)
-                       node->amp_out_caps = spec->def_amp_out_caps;
-       }
-       if (node->wid_caps & AC_WCAP_IN_AMP) {
-               if (node->wid_caps & AC_WCAP_AMP_OVRD)
-                       node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP);
-               if (! node->amp_in_caps)
-                       node->amp_in_caps = spec->def_amp_in_caps;
+       for (i = 0; i < spec->paths.used; i++) {
+               struct nid_path *path = snd_array_elem(&spec->paths, i);
+               if (path->depth <= 0)
+                       continue;
+               if ((!from_nid || path->path[0] == from_nid) &&
+                   (!to_nid || path->path[path->depth - 1] == to_nid)) {
+                       if (!anchor_nid ||
+                           (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
+                           (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
+                               return path;
+               }
        }
-       list_add_tail(&node->list, &spec->nid_list);
-       return 0;
+       return NULL;
 }
 
-/*
- * build the AFG subtree
+/* get the path between the given NIDs;
+ * passing 0 to either @pin or @dac behaves as a wildcard
  */
-static int build_afg_tree(struct hda_codec *codec)
+struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
+                                     hda_nid_t from_nid, hda_nid_t to_nid)
 {
-       struct hda_gspec *spec = codec->spec;
-       int i, nodes, err;
-       hda_nid_t nid;
-
-       if (snd_BUG_ON(!spec))
-               return -EINVAL;
+       return get_nid_path(codec, from_nid, to_nid, 0);
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
 
-       spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP);
-       spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP);
+/* get the index number corresponding to the path instance;
+ * the index starts from 1, for easier checking the invalid value
+ */
+int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *array = spec->paths.list;
+       ssize_t idx;
 
-       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
-       if (! nid || nodes < 0) {
-               printk(KERN_ERR "Invalid AFG subtree\n");
-               return -EINVAL;
-       }
+       if (!spec->paths.used)
+               return 0;
+       idx = path - array;
+       if (idx < 0 || idx >= spec->paths.used)
+               return 0;
+       return idx + 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_path_idx);
 
-       /* parse all nodes belonging to the AFG */
-       for (i = 0; i < nodes; i++, nid++) {
-               if ((err = add_new_node(codec, spec, nid)) < 0)
-                       return err;
-       }
+/* get the path instance corresponding to the given index number */
+struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
 
-       return 0;
+       if (idx <= 0 || idx > spec->paths.used)
+               return NULL;
+       return snd_array_elem(&spec->paths, idx - 1);
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx);
 
-
-/*
- * look for the node record for the given NID
- */
-/* FIXME: should avoid the braindead linear search */
-static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid)
+/* check whether the given DAC is already found in any existing paths */
+static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
 {
-       struct hda_gnode *node;
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
 
-       list_for_each_entry(node, &spec->nid_list, list) {
-               if (node->nid == nid)
-                       return node;
+       for (i = 0; i < spec->paths.used; i++) {
+               struct nid_path *path = snd_array_elem(&spec->paths, i);
+               if (path->path[0] == nid)
+                       return true;
        }
-       return NULL;
+       return false;
 }
 
-/*
- * unmute (and set max vol) the output amplifier
- */
-static int unmute_output(struct hda_codec *codec, struct hda_gnode *node)
-{
-       unsigned int val, ofs;
-       snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid);
-       val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
-       ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
-       if (val >= ofs)
-               val -= ofs;
-       snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val);
-       return 0;
+/* check whether the given two widgets can be connected */
+static bool is_reachable_path(struct hda_codec *codec,
+                             hda_nid_t from_nid, hda_nid_t to_nid)
+{
+       if (!from_nid || !to_nid)
+               return false;
+       return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
 }
 
-/*
- * unmute (and set max vol) the input amplifier
- */
-static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index)
-{
-       unsigned int val, ofs;
-       snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index);
-       val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
-       ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
-       if (val >= ofs)
-               val -= ofs;
-       snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val);
-       return 0;
+/* nid, dir and idx */
+#define AMP_VAL_COMPARE_MASK   (0xffff | (1U << 18) | (0x0f << 19))
+
+/* check whether the given ctl is already assigned in any path elements */
+static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       val &= AMP_VAL_COMPARE_MASK;
+       for (i = 0; i < spec->paths.used; i++) {
+               struct nid_path *path = snd_array_elem(&spec->paths, i);
+               if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
+                       return true;
+       }
+       return false;
 }
 
-/*
- * select the input connection of the given node.
- */
-static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node,
-                                  unsigned int index)
+/* check whether a control with the given (nid, dir, idx) was assigned */
+static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
+                             int dir, int idx, int type)
 {
-       snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index);
-       return snd_hda_codec_write_cache(codec, node->nid, 0,
-                                        AC_VERB_SET_CONNECT_SEL, index);
+       unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+       return is_ctl_used(codec, val, type);
 }
 
-/*
- * clear checked flag of each node in the node list
- */
-static void clear_check_flags(struct hda_gspec *spec)
+static void print_nid_path(const char *pfx, struct nid_path *path)
 {
-       struct hda_gnode *node;
+       char buf[40];
+       int i;
 
-       list_for_each_entry(node, &spec->nid_list, list) {
-               node->checked = 0;
+
+       buf[0] = 0;
+       for (i = 0; i < path->depth; i++) {
+               char tmp[4];
+               sprintf(tmp, ":%02x", path->path[i]);
+               strlcat(buf, tmp, sizeof(buf));
        }
+       snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
 }
 
-/*
- * parse the output path recursively until reach to an audio output widget
- *
- * returns 0 if not found, 1 if found, or a negative error code.
- */
-static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
-                            struct hda_gnode *node, int dac_idx)
+/* called recursively */
+static bool __parse_nid_path(struct hda_codec *codec,
+                            hda_nid_t from_nid, hda_nid_t to_nid,
+                            int anchor_nid, struct nid_path *path,
+                            int depth)
 {
-       int i, err;
-       struct hda_gnode *child;
+       const hda_nid_t *conn;
+       int i, nums;
 
-       if (node->checked)
-               return 0;
+       if (to_nid == anchor_nid)
+               anchor_nid = 0; /* anchor passed */
+       else if (to_nid == (hda_nid_t)(-anchor_nid))
+               return false; /* hit the exclusive nid */
 
-       node->checked = 1;
-       if (node->type == AC_WID_AUD_OUT) {
-               if (node->wid_caps & AC_WCAP_DIGITAL) {
-                       snd_printdd("Skip Digital OUT node %x\n", node->nid);
-                       return 0;
-               }
-               snd_printdd("AUD_OUT found %x\n", node->nid);
-               if (spec->dac_node[dac_idx]) {
-                       /* already DAC node is assigned, just unmute & connect */
-                       return node == spec->dac_node[dac_idx];
-               }
-               spec->dac_node[dac_idx] = node;
-               if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
-                   spec->pcm_vol_nodes < MAX_PCM_VOLS) {
-                       spec->pcm_vol[spec->pcm_vol_nodes].node = node;
-                       spec->pcm_vol[spec->pcm_vol_nodes].index = 0;
-                       spec->pcm_vol_nodes++;
+       nums = snd_hda_get_conn_list(codec, to_nid, &conn);
+       for (i = 0; i < nums; i++) {
+               if (conn[i] != from_nid) {
+                       /* special case: when from_nid is 0,
+                        * try to find an empty DAC
+                        */
+                       if (from_nid ||
+                           get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
+                           is_dac_already_used(codec, conn[i]))
+                               continue;
                }
-               return 1; /* found */
+               /* anchor is not requested or already passed? */
+               if (anchor_nid <= 0)
+                       goto found;
        }
-
-       for (i = 0; i < node->nconns; i++) {
-               child = hda_get_node(spec, node->conn_list[i]);
-               if (! child)
+       if (depth >= MAX_NID_PATH_DEPTH)
+               return false;
+       for (i = 0; i < nums; i++) {
+               unsigned int type;
+               type = get_wcaps_type(get_wcaps(codec, conn[i]));
+               if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
+                   type == AC_WID_PIN)
                        continue;
-               err = parse_output_path(codec, spec, child, dac_idx);
-               if (err < 0)
-                       return err;
-               else if (err > 0) {
-                       /* found one,
-                        * select the path, unmute both input and output
-                        */
-                       if (node->nconns > 1)
-                               select_input_connection(codec, node, i);
-                       unmute_input(codec, node, i);
-                       unmute_output(codec, node);
-                       if (spec->dac_node[dac_idx] &&
-                           spec->pcm_vol_nodes < MAX_PCM_VOLS &&
-                           !(spec->dac_node[dac_idx]->wid_caps &
-                             AC_WCAP_OUT_AMP)) {
-                               if ((node->wid_caps & AC_WCAP_IN_AMP) ||
-                                   (node->wid_caps & AC_WCAP_OUT_AMP)) {
-                                       int n = spec->pcm_vol_nodes;
-                                       spec->pcm_vol[n].node = node;
-                                       spec->pcm_vol[n].index = i;
-                                       spec->pcm_vol_nodes++;
-                               }
-                       }
-                       return 1;
-               }
+               if (__parse_nid_path(codec, from_nid, conn[i],
+                                    anchor_nid, path, depth + 1))
+                       goto found;
        }
-       return 0;
+       return false;
+
+ found:
+       path->path[path->depth] = conn[i];
+       path->idx[path->depth + 1] = i;
+       if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
+               path->multi[path->depth + 1] = 1;
+       path->depth++;
+       return true;
 }
 
-/*
- * Look for the output PIN widget with the given jack type
- * and parse the output path to that PIN.
- *
- * Returns the PIN node when the path to DAC is established.
+/* parse the widget path from the given nid to the target nid;
+ * when @from_nid is 0, try to find an empty DAC;
+ * when @anchor_nid is set to a positive value, only paths through the widget
+ * with the given value are evaluated.
+ * when @anchor_nid is set to a negative value, paths through the widget
+ * with the negative of given value are excluded, only other paths are chosen.
+ * when @anchor_nid is zero, no special handling about path selection.
  */
-static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
-                                          struct hda_gspec *spec,
-                                          int jack_type)
+bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
+                           hda_nid_t to_nid, int anchor_nid,
+                           struct nid_path *path)
 {
-       struct hda_gnode *node;
-       int err;
-
-       list_for_each_entry(node, &spec->nid_list, list) {
-               if (node->type != AC_WID_PIN)
-                       continue;
-               /* output capable? */
-               if (! (node->pin_caps & AC_PINCAP_OUT))
-                       continue;
-               if (defcfg_port_conn(node) == AC_JACK_PORT_NONE)
-                       continue; /* unconnected */
-               if (jack_type >= 0) {
-                       if (jack_type != defcfg_type(node))
-                               continue;
-                       if (node->wid_caps & AC_WCAP_DIGITAL)
-                               continue; /* skip SPDIF */
-               } else {
-                       /* output as default? */
-                       if (! (node->pin_ctl & AC_PINCTL_OUT_EN))
-                               continue;
-               }
-               clear_check_flags(spec);
-               err = parse_output_path(codec, spec, node, 0);
-               if (err < 0)
-                       return NULL;
-               if (! err && spec->out_pin_node[0]) {
-                       err = parse_output_path(codec, spec, node, 1);
-                       if (err < 0)
-                               return NULL;
-               }
-               if (err > 0) {
-                       /* unmute the PIN output */
-                       unmute_output(codec, node);
-                       /* set PIN-Out enable */
-                       snd_hda_codec_write_cache(codec, node->nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           AC_PINCTL_OUT_EN |
-                                           ((node->pin_caps & AC_PINCAP_HP_DRV) ?
-                                            AC_PINCTL_HP_EN : 0));
-                       return node;
-               }
+       if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
+               path->path[path->depth] = to_nid;
+               path->depth++;
+               return true;
        }
-       return NULL;
+       return false;
 }
-
+EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
 
 /*
- * parse outputs
+ * parse the path between the given NIDs and add to the path list.
+ * if no valid path is found, return NULL
  */
-static int parse_output(struct hda_codec *codec)
+struct nid_path *
+snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
+                    hda_nid_t to_nid, int anchor_nid)
 {
-       struct hda_gspec *spec = codec->spec;
-       struct hda_gnode *node;
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
 
-       /*
-        * Look for the output PIN widget
-        */
-       /* first, look for the line-out pin */
-       node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT);
-       if (node) /* found, remember the PIN node */
-               spec->out_pin_node[0] = node;
-       else {
-               /* if no line-out is found, try speaker out */
-               node = parse_output_jack(codec, spec, AC_JACK_SPEAKER);
-               if (node)
-                       spec->out_pin_node[0] = node;
-       }
-       /* look for the HP-out pin */
-       node = parse_output_jack(codec, spec, AC_JACK_HP_OUT);
-       if (node) {
-               if (! spec->out_pin_node[0])
-                       spec->out_pin_node[0] = node;
-               else
-                       spec->out_pin_node[1] = node;
-       }
+       if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
+               return NULL;
 
-       if (! spec->out_pin_node[0]) {
-               /* no line-out or HP pins found,
-                * then choose for the first output pin
-                */
-               spec->out_pin_node[0] = parse_output_jack(codec, spec, -1);
-               if (! spec->out_pin_node[0])
-                       snd_printd("hda_generic: no proper output path found\n");
-       }
+       /* check whether the path has been already added */
+       path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
+       if (path)
+               return path;
+
+       path = snd_array_new(&spec->paths);
+       if (!path)
+               return NULL;
+       memset(path, 0, sizeof(*path));
+       if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
+               return path;
+       /* push back */
+       spec->paths.used--;
+       return NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
+
+/* clear the given path as invalid so that it won't be picked up later */
+static void invalidate_nid_path(struct hda_codec *codec, int idx)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
+       if (!path)
+               return;
+       memset(path, 0, sizeof(*path));
+}
 
+/* look for an empty DAC slot */
+static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
+                             bool is_digital)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       bool cap_digital;
+       int i;
+
+       for (i = 0; i < spec->num_all_dacs; i++) {
+               hda_nid_t nid = spec->all_dacs[i];
+               if (!nid || is_dac_already_used(codec, nid))
+                       continue;
+               cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
+               if (is_digital != cap_digital)
+                       continue;
+               if (is_reachable_path(codec, nid, pin))
+                       return nid;
+       }
        return 0;
 }
 
-/*
- * input MUX
- */
+/* replace the channels in the composed amp value with the given number */
+static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
+{
+       val &= ~(0x3U << 16);
+       val |= chs << 16;
+       return val;
+}
 
-/* control callbacks */
-static int capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+/* check whether the widget has the given amp capability for the direction */
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int bits)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gspec *spec = codec->spec;
-       return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+       if (!nid)
+               return false;
+       if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+               if (query_amp_caps(codec, nid, dir) & bits)
+                       return true;
+       return false;
 }
 
-static int capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
+                         hda_nid_t nid2, int dir)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gspec *spec = codec->spec;
+       if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
+               return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
+       return (query_amp_caps(codec, nid1, dir) ==
+               query_amp_caps(codec, nid2, dir));
+}
+
+#define nid_has_mute(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+#define nid_has_volume(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
+
+/* look for a widget suitable for assigning a mute switch in the path */
+static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
+                                      struct nid_path *path)
+{
+       int i;
 
-       ucontrol->value.enumerated.item[0] = spec->cur_cap_src;
+       for (i = path->depth - 1; i >= 0; i--) {
+               if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
+                       return path->path[i];
+               if (i != path->depth - 1 && i != 0 &&
+                   nid_has_mute(codec, path->path[i], HDA_INPUT))
+                       return path->path[i];
+       }
        return 0;
 }
 
-static int capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+/* look for a widget suitable for assigning a volume ctl in the path */
+static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
+                                     struct nid_path *path)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gspec *spec = codec->spec;
-       return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
-                                    spec->adc_node->nid, &spec->cur_cap_src);
-}
+       int i;
 
-/*
- * return the string name of the given input PIN widget
- */
-static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
-{
-       unsigned int location = defcfg_location(node);
-       switch (defcfg_type(node)) {
-       case AC_JACK_LINE_IN:
-               if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-                       return "Front Line";
-               return "Line";
-       case AC_JACK_CD:
-#if 0
-               if (pinctl)
-                       *pinctl |= AC_PINCTL_VREF_GRD;
-#endif
-               return "CD";
-       case AC_JACK_AUX:
-               if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-                       return "Front Aux";
-               return "Aux";
-       case AC_JACK_MIC_IN:
-               if (pinctl &&
-                   (node->pin_caps &
-                    (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT)))
-                       *pinctl |= AC_PINCTL_VREF_80;
-               if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-                       return "Front Mic";
-               return "Mic";
-       case AC_JACK_SPDIF_IN:
-               return "SPDIF";
-       case AC_JACK_DIG_OTHER_IN:
-               return "Digital";
+       for (i = path->depth - 1; i >= 0; i--) {
+               if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
+                       return path->path[i];
        }
-       return NULL;
+       return 0;
 }
 
 /*
- * parse the nodes recursively until reach to the input PIN
- *
- * returns 0 if not found, 1 if found, or a negative error code.
+ * path activation / deactivation
  */
-static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
-                              struct hda_gnode *node, int idx)
+
+/* can have the amp-in capability? */
+static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
 {
-       int i, err;
-       unsigned int pinctl;
-       const char *type;
+       hda_nid_t nid = path->path[idx];
+       unsigned int caps = get_wcaps(codec, nid);
+       unsigned int type = get_wcaps_type(caps);
 
-       if (node->checked)
-               return 0;
+       if (!(caps & AC_WCAP_IN_AMP))
+               return false;
+       if (type == AC_WID_PIN && idx > 0) /* only for input pins */
+               return false;
+       return true;
+}
 
-       node->checked = 1;
-       if (node->type != AC_WID_PIN) {
-               for (i = 0; i < node->nconns; i++) {
-                       struct hda_gnode *child;
-                       child = hda_get_node(spec, node->conn_list[i]);
-                       if (! child)
-                               continue;
-                       err = parse_adc_sub_nodes(codec, spec, child, idx);
-                       if (err < 0)
-                               return err;
-                       if (err > 0) {
-                               /* found one,
-                                * select the path, unmute both input and output
-                                */
-                               if (node->nconns > 1)
-                                       select_input_connection(codec, node, i);
-                               unmute_input(codec, node, i);
-                               unmute_output(codec, node);
-                               return err;
+/* can have the amp-out capability? */
+static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
+{
+       hda_nid_t nid = path->path[idx];
+       unsigned int caps = get_wcaps(codec, nid);
+       unsigned int type = get_wcaps_type(caps);
+
+       if (!(caps & AC_WCAP_OUT_AMP))
+               return false;
+       if (type == AC_WID_PIN && !idx) /* only for output pins */
+               return false;
+       return true;
+}
+
+/* check whether the given (nid,dir,idx) is active */
+static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
+                         unsigned int dir, unsigned int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i, n;
+
+       for (n = 0; n < spec->paths.used; n++) {
+               struct nid_path *path = snd_array_elem(&spec->paths, n);
+               if (!path->active)
+                       continue;
+               for (i = 0; i < path->depth; i++) {
+                       if (path->path[i] == nid) {
+                               if (dir == HDA_OUTPUT || path->idx[i] == idx)
+                                       return true;
+                               break;
                        }
                }
-               return 0;
        }
+       return false;
+}
 
-       /* input capable? */
-       if (! (node->pin_caps & AC_PINCAP_IN))
-               return 0;
-
-       if (defcfg_port_conn(node) == AC_JACK_PORT_NONE)
-               return 0; /* unconnected */
-
-       if (node->wid_caps & AC_WCAP_DIGITAL)
-               return 0; /* skip SPDIF */
+/* get the default amp value for the target state */
+static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
+                                  int dir, unsigned int caps, bool enable)
+{
+       unsigned int val = 0;
 
-       if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) {
-               snd_printk(KERN_ERR "hda_generic: Too many items for capture\n");
-               return -EINVAL;
+       if (caps & AC_AMPCAP_NUM_STEPS) {
+               /* set to 0dB */
+               if (enable)
+                       val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
        }
-
-       pinctl = AC_PINCTL_IN_EN;
-       /* create a proper capture source label */
-       type = get_input_type(node, &pinctl);
-       if (! type) {
-               /* input as default? */
-               if (! (node->pin_ctl & AC_PINCTL_IN_EN))
-                       return 0;
-               type = "Input";
+       if (caps & AC_AMPCAP_MUTE) {
+               if (!enable)
+                       val |= HDA_AMP_MUTE;
        }
-       snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
-
-       /* unmute the PIN external input */
-       unmute_input(codec, node, 0); /* index = 0? */
-       /* set PIN-In enable */
-       snd_hda_codec_write_cache(codec, node->nid, 0,
-                                 AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+       return val;
+}
 
-       return 1; /* found */
+/* initialize the amp value (only at the first time) */
+static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
+{
+       unsigned int caps = query_amp_caps(codec, nid, dir);
+       int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
+       snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
 }
 
-/*
- * parse input
+/* calculate amp value mask we can modify;
+ * if the given amp is controlled by mixers, don't touch it
  */
-static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
+static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
+                                          hda_nid_t nid, int dir, int idx,
+                                          unsigned int caps)
 {
-       struct hda_gspec *spec = codec->spec;
-       struct hda_gnode *node;
-       int i, err;
+       unsigned int mask = 0xff;
 
-       snd_printdd("AUD_IN = %x\n", adc_node->nid);
-       clear_check_flags(spec);
-
-       // awk added - fixed no recording due to muted widget
-       unmute_input(codec, adc_node, 0);
-       
-       /*
-        * check each connection of the ADC
-        * if it reaches to a proper input PIN, add the path as the
-        * input path.
-        */
-       /* first, check the direct connections to PIN widgets */
-       for (i = 0; i < adc_node->nconns; i++) {
-               node = hda_get_node(spec, adc_node->conn_list[i]);
-               if (node && node->type == AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node, i);
-                       if (err < 0)
-                               return err;
-               }
+       if (caps & AC_AMPCAP_MUTE) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
+                       mask &= ~0x80;
        }
-       /* ... then check the rests, more complicated connections */
-       for (i = 0; i < adc_node->nconns; i++) {
-               node = hda_get_node(spec, adc_node->conn_list[i]);
-               if (node && node->type != AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node, i);
-                       if (err < 0)
-                               return err;
-               }
+       if (caps & AC_AMPCAP_NUM_STEPS) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+                   is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+                       mask &= ~0x7f;
        }
+       return mask;
+}
+
+static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
+                        int idx, int idx_to_check, bool enable)
+{
+       unsigned int caps;
+       unsigned int mask, val;
 
-       if (! spec->input_mux.num_items)
-               return 0; /* no input path found... */
+       if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
+               return;
 
-       snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items);
-       for (i = 0; i < spec->input_mux.num_items; i++)
-               snd_printdd("  [%s] IDX=0x%x\n", spec->input_mux.items[i].label,
-                           spec->input_mux.items[i].index);
+       caps = query_amp_caps(codec, nid, dir);
+       val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
+       mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
+       if (!mask)
+               return;
 
-       spec->adc_node = adc_node;
-       return 1;
+       val &= mask;
+       snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
 }
 
-/*
- * parse input
- */
-static int parse_input(struct hda_codec *codec)
+static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
+                            int i, bool enable)
 {
-       struct hda_gspec *spec = codec->spec;
-       struct hda_gnode *node;
-       int err;
+       hda_nid_t nid = path->path[i];
+       init_amp(codec, nid, HDA_OUTPUT, 0);
+       activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
+}
 
-       /*
-        * At first we look for an audio input widget.
-        * If it reaches to certain input PINs, we take it as the
-        * input path.
+static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
+                           int i, bool enable, bool add_aamix)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const hda_nid_t *conn;
+       int n, nums, idx;
+       int type;
+       hda_nid_t nid = path->path[i];
+
+       nums = snd_hda_get_conn_list(codec, nid, &conn);
+       type = get_wcaps_type(get_wcaps(codec, nid));
+       if (type == AC_WID_PIN ||
+           (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
+               nums = 1;
+               idx = 0;
+       } else
+               idx = path->idx[i];
+
+       for (n = 0; n < nums; n++)
+               init_amp(codec, nid, HDA_INPUT, n);
+
+       /* here is a little bit tricky in comparison with activate_amp_out();
+        * when aa-mixer is available, we need to enable the path as well
         */
-       list_for_each_entry(node, &spec->nid_list, list) {
-               if (node->wid_caps & AC_WCAP_DIGITAL)
-                       continue; /* skip SPDIF */
-               if (node->type == AC_WID_AUD_IN) {
-                       err = parse_input_path(codec, node);
-                       if (err < 0)
-                               return err;
-                       else if (err > 0)
-                               return 0;
-               }
+       for (n = 0; n < nums; n++) {
+               if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid))
+                       continue;
+               activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
        }
-       snd_printd("hda_generic: no proper input path found\n");
-       return 0;
 }
 
-#ifdef CONFIG_PM
-static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid,
-                              int dir, int idx)
+/* activate or deactivate the given path
+ * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
+ */
+void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
+                          bool enable, bool add_aamix)
 {
-       struct hda_gspec *spec = codec->spec;
-       struct hda_amp_list *p;
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
 
-       if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) {
-               snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n");
-               return;
+       if (!enable)
+               path->active = false;
+
+       for (i = path->depth - 1; i >= 0; i--) {
+               hda_nid_t nid = path->path[i];
+               if (enable && spec->power_down_unused) {
+                       /* make sure the widget is powered up */
+                       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0))
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_POWER_STATE,
+                                                   AC_PWRST_D0);
+               }
+               if (enable && path->multi[i])
+                       snd_hda_codec_write_cache(codec, nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           path->idx[i]);
+               if (has_amp_in(codec, path, i))
+                       activate_amp_in(codec, path, i, enable, add_aamix);
+               if (has_amp_out(codec, path, i))
+                       activate_amp_out(codec, path, i, enable);
        }
-       p = &spec->loopback_list[spec->num_loopbacks++];
-       p->nid = nid;
-       p->dir = dir;
-       p->idx = idx;
-       spec->loopback.amplist = spec->loopback_list;
+
+       if (enable)
+               path->active = true;
 }
-#else
-#define add_input_loopback(codec,nid,dir,idx)
-#endif
+EXPORT_SYMBOL_HDA(snd_hda_activate_path);
 
-/*
- * create mixer controls if possible
- */
-static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
-                       unsigned int index, const char *type,
-                       const char *dir_sfx, int is_loopback)
+/* if the given path is inactive, put widgets into D3 (only if suitable) */
+static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
 {
-       char name[32];
-       int err;
-       int created = 0;
-       struct snd_kcontrol_new knew;
+       struct hda_gen_spec *spec = codec->spec;
+       bool changed;
+       int i;
 
-       if (type)
-               sprintf(name, "%s %s Switch", type, dir_sfx);
-       else
-               sprintf(name, "%s Switch", dir_sfx);
-       if ((node->wid_caps & AC_WCAP_IN_AMP) &&
-           (node->amp_in_caps & AC_AMPCAP_MUTE)) {
-               knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT);
-               if (is_loopback)
-                       add_input_loopback(codec, node->nid, HDA_INPUT, index);
-               snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-               err = snd_hda_ctl_add(codec, node->nid,
-                                       snd_ctl_new1(&knew, codec));
-               if (err < 0)
-                       return err;
-               created = 1;
-       } else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
-                  (node->amp_out_caps & AC_AMPCAP_MUTE)) {
-               knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT);
-               if (is_loopback)
-                       add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
-               snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-               err = snd_hda_ctl_add(codec, node->nid,
-                                       snd_ctl_new1(&knew, codec));
-               if (err < 0)
-                       return err;
-               created = 1;
+       if (!spec->power_down_unused || path->active)
+               return;
+
+       for (i = 0; i < path->depth; i++) {
+               hda_nid_t nid = path->path[i];
+               if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3)) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+                       changed = true;
+               }
        }
 
-       if (type)
-               sprintf(name, "%s %s Volume", type, dir_sfx);
-       else
-               sprintf(name, "%s Volume", dir_sfx);
-       if ((node->wid_caps & AC_WCAP_IN_AMP) &&
-           (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
-               knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
-               snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-               err = snd_hda_ctl_add(codec, node->nid,
-                                       snd_ctl_new1(&knew, codec));
-               if (err < 0)
-                       return err;
-               created = 1;
-       } else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
-                  (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
-               knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
-               snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-               err = snd_hda_ctl_add(codec, node->nid,
-                                       snd_ctl_new1(&knew, codec));
-               if (err < 0)
-                       return err;
-               created = 1;
+       if (changed) {
+               msleep(10);
+               snd_hda_codec_read(codec, path->path[0], 0,
+                                  AC_VERB_GET_POWER_STATE, 0);
        }
+}
 
-       return created;
+/* turn on/off EAPD on the given pin */
+static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->own_eapd_ctl ||
+           !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
+               return;
+       if (codec->inv_eapd)
+               enable = !enable;
+       snd_hda_codec_update_cache(codec, pin, 0,
+                                  AC_VERB_SET_EAPD_BTLENABLE,
+                                  enable ? 0x02 : 0x00);
 }
 
-/*
- * check whether the controls with the given name and direction suffix already exist
- */
-static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir)
-{
-       struct snd_ctl_elem_id id;
-       memset(&id, 0, sizeof(id));
-       sprintf(id.name, "%s %s Volume", type, dir);
-       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       if (snd_ctl_find_id(codec->bus->card, &id))
-               return 1;
-       sprintf(id.name, "%s %s Switch", type, dir);
-       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       if (snd_ctl_find_id(codec->bus->card, &id))
-               return 1;
-       return 0;
+/* re-initialize the path specified by the given path index */
+static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (path)
+               snd_hda_activate_path(codec, path, path->active, false);
 }
 
+
 /*
- * build output mixer controls
+ * Helper functions for creating mixer ctl elements
  */
-static int create_output_mixers(struct hda_codec *codec,
-                               const char * const *names)
+
+enum {
+       HDA_CTL_WIDGET_VOL,
+       HDA_CTL_WIDGET_MUTE,
+       HDA_CTL_BIND_MUTE,
+};
+static const struct snd_kcontrol_new control_templates[] = {
+       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+       HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       HDA_BIND_MUTE(NULL, 0, 0, 0),
+};
+
+/* add dynamic controls from template */
+static struct snd_kcontrol_new *
+add_control(struct hda_gen_spec *spec, int type, const char *name,
+                      int cidx, unsigned long val)
 {
-       struct hda_gspec *spec = codec->spec;
-       int i, err;
+       struct snd_kcontrol_new *knew;
 
-       for (i = 0; i < spec->pcm_vol_nodes; i++) {
-               err = create_mixer(codec, spec->pcm_vol[i].node,
-                                  spec->pcm_vol[i].index,
-                                  names[i], "Playback", 0);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
+       knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
+       if (!knew)
+               return NULL;
+       knew->index = cidx;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+       knew->private_value = val;
+       return knew;
 }
 
-static int build_output_controls(struct hda_codec *codec)
+static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
+                               const char *pfx, const char *dir,
+                               const char *sfx, int cidx, unsigned long val)
 {
-       struct hda_gspec *spec = codec->spec;
-       static const char * const types_speaker[] = { "Speaker", "Headphone" };
-       static const char * const types_line[] = { "Front", "Headphone" };
+       char name[32];
+       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       if (!add_control(spec, type, name, cidx, val))
+               return -ENOMEM;
+       return 0;
+}
 
-       switch (spec->pcm_vol_nodes) {
+#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
+
+static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
+                      unsigned int chs, struct nid_path *path)
+{
+       unsigned int val;
+       if (!path)
+               return 0;
+       val = path->ctls[NID_PATH_VOL_CTL];
+       if (!val)
+               return 0;
+       val = amp_val_replace_channels(val, chs);
+       return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
+}
+
+/* return the channel bits suitable for the given path->ctls[] */
+static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
+                              int type)
+{
+       int chs = 1; /* mono (left only) */
+       if (path) {
+               hda_nid_t nid = get_amp_nid_(path->ctls[type]);
+               if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
+                       chs = 3; /* stereo */
+       }
+       return chs;
+}
+
+static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
+                         struct nid_path *path)
+{
+       int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
+       return add_vol_ctl(codec, pfx, cidx, chs, path);
+}
+
+/* create a mute-switch for the given mixer widget;
+ * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
+ */
+static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
+                     unsigned int chs, struct nid_path *path)
+{
+       unsigned int val;
+       int type = HDA_CTL_WIDGET_MUTE;
+
+       if (!path)
+               return 0;
+       val = path->ctls[NID_PATH_MUTE_CTL];
+       if (!val)
+               return 0;
+       val = amp_val_replace_channels(val, chs);
+       if (get_amp_direction_(val) == HDA_INPUT) {
+               hda_nid_t nid = get_amp_nid_(val);
+               int nums = snd_hda_get_num_conns(codec, nid);
+               if (nums > 1) {
+                       type = HDA_CTL_BIND_MUTE;
+                       val |= nums << 19;
+               }
+       }
+       return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
+}
+
+static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
+                                 int cidx, struct nid_path *path)
+{
+       int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
+       return add_sw_ctl(codec, pfx, cidx, chs, path);
+}<