Merge remote-tracking branch 'sound-current/for-linus'
authorStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 22:59:35 +0000 (09:59 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 22:59:35 +0000 (09:59 +1100)
308 files changed:
Documentation/DocBook/alsa-driver-api.tmpl
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/devicetree/bindings/sound/ak4613.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ak4642.txt
Documentation/devicetree/bindings/sound/atmel-classd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7213.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7219.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
Documentation/devicetree/bindings/sound/nau8825.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/rockchip-i2s.txt
Documentation/devicetree/bindings/sound/rockchip-spdif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt
Documentation/devicetree/bindings/sound/sun4i-codec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tdm-slot.txt
Documentation/sound/alsa/hda_codec.txt [deleted file]
MAINTAINERS
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_audio.c
drivers/spi/spi-atmel.c
include/drm/i915_component.h
include/linux/mod_devicetable.h
include/sound/da7213.h
include/sound/da7219-aad.h [new file with mode: 0644]
include/sound/da7219.h [new file with mode: 0644]
include/sound/designware_i2s.h
include/sound/hda_regmap.h
include/sound/hdaudio.h
include/sound/hdaudio_ext.h
include/sound/pcm.h
include/sound/pxa2xx-lib.h
include/sound/rt5640.h
include/sound/rt5645.h
include/sound/simple_card.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/uapi/sound/asoc.h
include/uapi/sound/asound.h
include/uapi/sound/emu10k1.h
include/uapi/sound/firewire.h
include/uapi/sound/hdspm.h
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm-lib.c
sound/arm/pxa2xx-pcm.c
sound/arm/pxa2xx-pcm.h
sound/core/Kconfig
sound/core/Makefile
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_writeq.c
sound/firewire/Kconfig
sound/firewire/Makefile
sound/firewire/amdtp-am824.c [new file with mode: 0644]
sound/firewire/amdtp-am824.h [new file with mode: 0644]
sound/firewire/amdtp-stream.c [moved from sound/firewire/amdtp.c with 70% similarity]
sound/firewire/amdtp-stream.h [moved from sound/firewire/amdtp.h with 78% similarity]
sound/firewire/bebob/Makefile
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob.h
sound/firewire/bebob/bebob_focusrite.c
sound/firewire/bebob/bebob_maudio.c
sound/firewire/bebob/bebob_midi.c
sound/firewire/bebob/bebob_pcm.c
sound/firewire/bebob/bebob_proc.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/bebob/bebob_terratec.c
sound/firewire/bebob/bebob_yamaha.c
sound/firewire/dice/Makefile
sound/firewire/dice/dice-midi.c
sound/firewire/dice/dice-pcm.c
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.c
sound/firewire/dice/dice.h
sound/firewire/digi00x/Makefile [new file with mode: 0644]
sound/firewire/digi00x/amdtp-dot.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-hwdep.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-midi.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-pcm.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-proc.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-stream.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-transaction.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x.h [new file with mode: 0644]
sound/firewire/fcp.c
sound/firewire/fireworks/Makefile
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_command.c
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/fireworks/fireworks_pcm.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/lib.c
sound/firewire/lib.h
sound/firewire/oxfw/Makefile
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw-pcm.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/firewire/oxfw/oxfw.h
sound/firewire/tascam/Makefile [new file with mode: 0644]
sound/firewire/tascam/amdtp-tascam.c [new file with mode: 0644]
sound/firewire/tascam/tascam-hwdep.c [new file with mode: 0644]
sound/firewire/tascam/tascam-midi.c [new file with mode: 0644]
sound/firewire/tascam/tascam-pcm.c [new file with mode: 0644]
sound/firewire/tascam/tascam-proc.c [new file with mode: 0644]
sound/firewire/tascam/tascam-stream.c [new file with mode: 0644]
sound/firewire/tascam/tascam-transaction.c [new file with mode: 0644]
sound/firewire/tascam/tascam.c [new file with mode: 0644]
sound/firewire/tascam/tascam.h [new file with mode: 0644]
sound/hda/ext/hdac_ext_stream.c
sound/hda/hda_bus_type.c
sound/hda/hdac_bus.c
sound/hda/hdac_device.c
sound/hda/hdac_i915.c
sound/hda/hdac_regmap.c
sound/hda/hdac_stream.c
sound/hda/hdac_sysfs.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_sysfs.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_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/korg1212/korg1212.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-classd.c [new file with mode: 0644]
sound/soc/atmel/atmel-classd.h [new file with mode: 0644]
sound/soc/atmel/atmel_wm8904.c
sound/soc/au1x/db1000.c
sound/soc/au1x/db1200.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bfin-eval-adau1373.c
sound/soc/blackfin/bfin-eval-adau1701.c
sound/soc/blackfin/bfin-eval-adav80x.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad193x-i2c.c
sound/soc/codecs/ad193x-spi.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4613.c [new file with mode: 0644]
sound/soc/codecs/ak4642.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/da7213.c
sound/soc/codecs/da7213.h
sound/soc/codecs/da7219-aad.c [new file with mode: 0644]
sound/soc/codecs/da7219-aad.h [new file with mode: 0644]
sound/soc/codecs/da7219.c [new file with mode: 0644]
sound/soc/codecs/da7219.h [new file with mode: 0644]
sound/soc/codecs/es8328.c
sound/soc/codecs/hdmi.c [deleted file]
sound/soc/codecs/nau8825.c [new file with mode: 0644]
sound/soc/codecs/nau8825.h [new file with mode: 0644]
sound/soc/codecs/rl6347a.c
sound/soc/codecs/rl6347a.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/ssm2518.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8998.c [new file with mode: 0644]
sound/soc/codecs/wm8998.h [new file with mode: 0644]
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-spdif.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/skl_rt286.c [new file with mode: 0644]
sound/soc/intel/common/Makefile
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.h
sound/soc/intel/common/sst-firmware.c
sound/soc/intel/skylake/Makefile
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-topology.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/armada-370-db.c
sound/soc/mediatek/mt8173-max98090.c
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/omap/n810.c
sound/soc/omap/rx51.c
sound/soc/pxa/brownstone.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/imote2.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/ttc-dkb.c
sound/soc/qcom/lpass-cpu.c
sound/soc/rockchip/Kconfig
sound/soc/rockchip/Makefile
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_i2s.h
sound/soc/rockchip/rockchip_spdif.c [new file with mode: 0644]
sound/soc/rockchip/rockchip_spdif.h [new file with mode: 0644]
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/sh/Kconfig
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rcar_snd.h [moved from include/sound/rcar_snd.h with 98% similarity]
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/siu_dai.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sunxi/Kconfig [new file with mode: 0644]
sound/soc/sunxi/Makefile [new file with mode: 0644]
sound/soc/sunxi/sun4i-codec.c [new file with mode: 0644]
sound/soc/ux500/mop500.c
sound/soc/ux500/ux500_msp_dai.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/midi.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/stream.c
sound/usb/usbaudio.h

index e94a10b..53f439d 100644 (file)
 !Esound/soc/soc-devres.c
 !Esound/soc/soc-io.c
 !Esound/soc/soc-pcm.c
+!Esound/soc/soc-ops.c
+!Esound/soc/soc-compress.c
      </sect1>
      <sect1><title>ASoC DAPM API</title>
 !Esound/soc/soc-dapm.c
index 84ef6a9..a27ab9f 100644 (file)
@@ -2181,10 +2181,6 @@ struct _snd_pcm_runtime {
        struct snd_pcm_hardware hw;
        struct snd_pcm_hw_constraints hw_constraints;
 
-       /* -- interrupt callbacks -- */
-       void (*transfer_ack_begin)(struct snd_pcm_substream *substream);
-       void (*transfer_ack_end)(struct snd_pcm_substream *substream);
-
        /* -- timer -- */
        unsigned int timer_resolution;  /* timer resolution */
 
@@ -2209,9 +2205,8 @@ struct _snd_pcm_runtime {
          For the operators (callbacks) of each sound driver, most of
        these records are supposed to be read-only.  Only the PCM
        middle-layer changes / updates them.  The exceptions are
-       the hardware description (hw), interrupt callbacks
-       (transfer_ack_xxx), DMA buffer information, and the private
-       data.  Besides, if you use the standard buffer allocation
+       the hardware description (hw) DMA buffer information and the
+       private data.  Besides, if you use the standard buffer allocation
        method via <function>snd_pcm_lib_malloc_pages()</function>,
        you don't need to set the DMA buffer information by yourself.
        </para>
@@ -2538,16 +2533,6 @@ struct _snd_pcm_runtime {
         </para>
        </section>
 
-       <section id="pcm-interface-runtime-intr">
-       <title>Interrupt Callbacks</title>
-       <para>
-       The field <structfield>transfer_ack_begin</structfield> and
-       <structfield>transfer_ack_end</structfield> are called at
-       the beginning and at the end of
-       <function>snd_pcm_period_elapsed()</function>, respectively. 
-       </para>
-       </section>
-
     </section>
 
     <section id="pcm-interface-operators">
diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt
new file mode 100644 (file)
index 0000000..15a9195
--- /dev/null
@@ -0,0 +1,17 @@
+AK4613 I2C transmitter
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak4613"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+       ak4613: ak4613@0x10 {
+               compatible = "asahi-kasei,ak4613";
+               reg = <0x10>;
+       };
+};
index 623d4e7..340784d 100644 (file)
@@ -7,7 +7,14 @@ Required properties:
   - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
   - reg : The chip select number on the I2C bus
 
-Example:
+Optional properties:
+
+  - #clock-cells :             common clock binding; shall be set to 0
+  - clocks :                   common clock binding; MCKI clock
+  - clock-frequency :          common clock binding; frequency of MCKO
+  - clock-output-names :       common clock binding; MCKO clock name
+
+Example 1:
 
 &i2c {
        ak4648: ak4648@0x12 {
@@ -15,3 +22,16 @@ Example:
                reg = <0x12>;
        };
 };
+
+Example 2:
+
+&i2c {
+       ak4643: codec@12 {
+               compatible = "asahi-kasei,ak4643";
+               reg = <0x12>;
+               #clock-cells = <0>;
+               clocks = <&audio_clock>;
+               clock-frequency = <12288000>;
+               clock-output-names = "ak4643_mcko";
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-classd.txt b/Documentation/devicetree/bindings/sound/atmel-classd.txt
new file mode 100644 (file)
index 0000000..0018451
--- /dev/null
@@ -0,0 +1,52 @@
+* Atmel ClassD driver under ALSA SoC architecture
+
+Required properties:
+- compatible
+       Should be "atmel,sama5d2-classd".
+- reg
+       Should contain ClassD registers location and length.
+- interrupts
+       Should contain the IRQ line for the ClassD.
+- dmas
+       One DMA specifiers as described in atmel-dma.txt and dma.txt files.
+- dma-names
+       Must be "tx".
+- clock-names
+       Tuple listing input clock names.
+       Required elements: "pclk", "gclk" and "aclk".
+- clocks
+       Please refer to clock-bindings.txt.
+
+Optional properties:
+- pinctrl-names, pinctrl-0
+       Please refer to pinctrl-bindings.txt.
+- atmel,model
+       The user-visible name of this sound complex.
+       The default value is "CLASSD".
+- atmel,pwm-type
+       PWM modulation type, "single" or "diff".
+       The default value is "single".
+- atmel,non-overlap-time
+       Set non-overlapping time, the unit is nanosecond(ns).
+       There are four values,
+       <5>, <10>, <15>, <20>, the default value is <10>.
+       Non-overlapping will be disabled if not specified.
+
+Example:
+classd: classd@fc048000 {
+               compatible = "atmel,sama5d2-classd";
+               reg = <0xfc048000 0x100>;
+               interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
+               dmas = <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(47))>;
+               dma-names = "tx";
+               clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
+               clock-names = "pclk", "gclk", "aclk";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_classd_default>;
+               atmel,model = "classd @ SAMA5D2-Xplained";
+               atmel,pwm-type = "diff";
+               atmel,non-overlap-time = <10>;
+};
diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt
new file mode 100644 (file)
index 0000000..5890280
--- /dev/null
@@ -0,0 +1,41 @@
+Dialog Semiconductor DA7213 Audio Codec bindings
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7213"
+- reg: Specifies the I2C slave address
+
+Optional properties:
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1
+       [<1600>, <2200>, <2500>, <3000>]
+- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2
+       [<1600>, <2200>, <2500>, <3000>]
+- dlg,dmic-data-sel : DMIC channel select based on clock edge.
+       ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic-samplephase : When to sample audio from DMIC.
+       ["on_clkedge", "between_clkedge"]
+- dlg,dmic-clkrate : DMIC clock frequency (Hz).
+       [<1500000>, <3000000>]
+
+======
+
+Example:
+
+       codec_i2c: da7213@1a {
+               compatible = "dlg,da7213";
+               reg = <0x1a>;
+
+               clocks = <&clks 201>;
+               clock-names = "mclk";
+
+               dlg,micbias1-lvl = <2500>;
+               dlg,micbias2-lvl = <2500>;
+
+               dlg,dmic-data-sel = "lrise_rfall";
+               dlg,dmic-samplephase = "between_clkedge";
+               dlg,dmic-clkrate = <3000000>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt
new file mode 100644 (file)
index 0000000..1b70309
--- /dev/null
@@ -0,0 +1,106 @@
+Dialog Semiconductor DA7219 Audio Codec bindings
+
+DA7219 is an audio codec with advanced accessory detect features.
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7219"
+- reg: Specifies the I2C slave address
+
+- interrupt-parent : Specifies the phandle of the interrupt controller to which
+  the IRQs from DA7219 are delivered to.
+- interrupts : IRQ line info for DA7219.
+  (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+   further information relating to interrupt properties)
+
+- VDD-supply: VDD power supply for the device
+- VDDMIC-supply: VDDMIC power supply for the device
+- VDDIO-supply: VDDIO power supply for the device
+  (See Documentation/devicetree/bindings/regulator/regulator.txt for further
+   information relating to regulators)
+
+Optional properties:
+- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
+  interrupt is to be used to wake system, otherwise "irq" should be used.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
+
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
+       [<1050>, <1100>, <1200>, <1400>]
+- dlg,micbias-lvl : Voltage (mV) for Mic Bias
+       [<1800>, <2000>, <2200>, <2400>, <2600>]
+- dlg,mic-amp-in-sel : Mic input source type
+       ["diff", "se_p", "se_n"]
+
+======
+
+Child node - 'da7219_aad':
+
+Optional properties:
+- dlg,micbias-pulse-lvl : Mic bias higher voltage pulse level (mV).
+       [<2800>, <2900>]
+- dlg,micbias-pulse-time : Mic bias higher voltage pulse duration (ms)
+- dlg,btn-cfg : Periodic button press measurements for 4-pole jack (ms)
+       [<2>, <5>, <10>, <50>, <100>, <200>, <500>]
+- dlg,mic-det-thr : Impedance threshold for mic detection measurement (Ohms)
+       [<200>, <500>, <750>, <1000>]
+- dlg,jack-ins-deb : Debounce time for jack insertion (ms)
+       [<5>, <10>, <20>, <50>, <100>, <200>, <500>, <1000>]
+- dlg,jack-det-rate: Jack type detection latency (3/4 pole)
+       ["32ms_64ms", "64ms_128ms", "128ms_256ms", "256ms_512ms"]
+- dlg,jack-rem-deb : Debounce time for jack removal (ms)
+       [<1>, <5>, <10>, <20>]
+- dlg,a-d-btn-thr : Impedance threshold between buttons A and D
+       [0x0 - 0xFF]
+- dlg,d-b-btn-thr : Impedance threshold between buttons D and B
+       [0x0 - 0xFF]
+- dlg,b-c-btn-thr : Impedance threshold between buttons B and C
+       [0x0 - 0xFF]
+- dlg,c-mic-btn-thr : Impedance threshold between button C and Mic
+       [0x0 - 0xFF]
+- dlg,btn-avg : Number of 8-bit readings for averaged button measurement
+       [<1>, <2>, <4>, <8>]
+- dlg,adc-1bit-rpt : Repeat count for 1-bit button measurement
+       [<1>, <2>, <4>, <8>]
+
+======
+
+Example:
+
+       codec: da7219@1a {
+               compatible = "dlg,da7219";
+               reg = <0x1a>;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+
+               VDD-supply = <&reg_audio>;
+               VDDMIC-supply = <&reg_audio>;
+               VDDIO-supply = <&reg_audio>;
+
+               clocks = <&clks 201>;
+               clock-names = "mclk";
+
+               dlg,ldo-lvl = <1200>;
+               dlg,micbias-lvl = <2600>;
+               dlg,mic-amp-in-sel = "diff";
+
+               da7219_aad {
+                       dlg,btn-cfg = <50>;
+                       dlg,mic-det-thr = <500>;
+                       dlg,jack-ins-deb = <20>;
+                       dlg,jack-det-rate = "32ms_64ms";
+                       dlg,jack-rem-deb = <1>;
+
+                       dlg,a-d-btn-thr = <0xa>;
+                       dlg,d-b-btn-thr = <0x16>;
+                       dlg,b-c-btn-thr = <0x21>;
+                       dlg,c-mic-btn-thr = <0x3E>;
+
+                       dlg,btn-avg = <4>;
+                       dlg,adc-1bit-rpt = <1>;
+               };
+       };
index a96774c..ce55c0a 100644 (file)
@@ -13,13 +13,15 @@ So having this generic sound card allows all Freescale SoC users to benefit
 from the simplification of a new card support and the capability of the wide
 sample rates support through ASRC.
 
-Note: The card is initially designed for those sound cards who use I2S and
-      PCM DAI formats. However, it'll be also possible to support those non
-      I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
-      as the driver has been properly upgraded.
+Note: The card is initially designed for those sound cards who use AC'97, I2S
+      and PCM DAI formats. However, it'll be also possible to support those non
+      AC'97/I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as
+      long as the driver has been properly upgraded.
 
 
 The compatible list for this generic sound card currently:
+ "fsl,imx-audio-ac97"
+
  "fsl,imx-audio-cs42888"
 
  "fsl,imx-audio-wm8962"
diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt
new file mode 100644 (file)
index 0000000..d337423
--- /dev/null
@@ -0,0 +1,102 @@
+Nuvoton NAU8825 audio codec
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "nuvoton,nau8825"
+
+  - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1).
+
+Optional properties:
+  - nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
+  - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
+      otherwise pin in high impedance state.
+  - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
+  - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
+
+  - nuvoton,vref-impedance: VREF Impedance selection
+      0 - Open
+      1 - 25 kOhm
+      2 - 125 kOhm
+      3 - 2.5 kOhm
+
+  - nuvoton,micbias-voltage: Micbias voltage level.
+      0 - VDDA
+      1 - VDDA
+      2 - VDDA * 1.1
+      3 - VDDA * 1.2
+      4 - VDDA * 1.3
+      5 - VDDA * 1.4
+      6 - VDDA * 1.53
+      7 - VDDA * 1.53
+
+  - nuvoton,sar-threshold-num: Number of buttons supported
+  - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as
+    SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R)
+    where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance.
+    Refer datasheet section 10.2 for more information about threshold calculation.
+
+  - nuvoton,sar-hysteresis: Button impedance measurement hysteresis.
+
+  - nuvoton,sar-voltage: Reference voltage for button impedance measurement.
+      0 - VDDA
+      1 - VDDA
+      2 - VDDA * 1.1
+      3 - VDDA * 1.2
+      4 - VDDA * 1.3
+      5 - VDDA * 1.4
+      6 - VDDA * 1.53
+      7 - VDDA * 1.53
+
+  - nuvoton,sar-compare-time: SAR compare time
+      0 - 500 ns
+      1 - 1 us
+      2 - 2 us
+      3 - 4 us
+
+  - nuvoton,sar-sampling-time: SAR sampling time
+      0 - 2 us
+      1 - 4 us
+      2 - 8 us
+      3 - 16 us
+
+  - nuvoton,short-key-debounce: Button short key press debounce time.
+      0 - 30 ms
+      1 - 50 ms
+      2 - 100 ms
+      3 - 30 ms
+
+  - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
+  - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
+
+  - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
+      clocks described in clock-names
+  - clock-names: should include "mclk" for the MCLK master clock
+
+Example:
+
+  headset: nau8825@1a {
+      compatible = "nuvoton,nau8825";
+      reg = <0x1a>;
+      interrupt-parent = <&gpio>;
+      interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
+      nuvoton,jkdet-enable;
+      nuvoton,jkdet-pull-enable;
+      nuvoton,jkdet-pull-up;
+      nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+      nuvoton,vref-impedance = <2>;
+      nuvoton,micbias-voltage = <6>;
+      // Setup 4 buttons impedance according to Android specification
+      nuvoton,sar-threshold-num = <4>;
+      nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
+      nuvoton,sar-hysteresis = <1>;
+      nuvoton,sar-voltage = <0>;
+      nuvoton,sar-compare-time = <0>;
+      nuvoton,sar-sampling-time = <0>;
+      nuvoton,short-key-debounce = <2>;
+      nuvoton,jack-insert-debounce = <7>;
+      nuvoton,jack-eject-debounce = <7>;
+
+      clock-names = "mclk";
+      clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+  };
index 1173395..c57cbd6 100644 (file)
@@ -4,10 +4,12 @@ Required properties:
 - compatible                   : "renesas,rcar_sound-<soctype>", fallbacks
                                  "renesas,rcar_sound-gen1" if generation1, and
                                  "renesas,rcar_sound-gen2" if generation2
+                                 "renesas,rcar_sound-gen3" if generation3
                                  Examples with soctypes are:
                                    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
                                    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
+                                   - "renesas,rcar_sound-r8a7795" (R-Car H3)
 - reg                          : Should contain the register physical address.
                                  required register is
                                   SRU/ADG/SSI      if generation1
@@ -30,6 +32,11 @@ Required properties:
 - rcar_sound,dai               : DAI contents.
                                  The number of DAI subnode should be same as HW.
                                  see below for detail.
+- #sound-dai-cells             : it must be 0 if your system is using single DAI
+                                 it must be 1 if your system is using multi  DAI
+- #clock-cells                 : it must be 0 if your system has audio_clkout
+                                 it must be 1 if your system has audio_clkout0/1/2/3
+- clock-frequency              : for all audio_clkout0/1/2/3
 
 SSI subnode properties:
 - interrupts                   : Should contain SSI interrupt for PIO transfer
index 9b82c20..2267d24 100644 (file)
@@ -12,8 +12,6 @@ Required properties:
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
-- #address-cells: should be 1.
-- #size-cells: should be 0.
 - dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
        Documentation/devicetree/bindings/dma/dma.txt
 - dma-names: should include "tx" and "rx".
@@ -21,6 +19,7 @@ Required properties:
 - clock-names: should contain followings:
    - "i2s_hclk": clock for I2S BUS
    - "i2s_clk" : clock for I2S controller
+- rockchip,capture-channels: max capture channels, if not set, 2 channels default.
 
 Example for rk3288 I2S controller:
 
@@ -28,10 +27,9 @@ i2s@ff890000 {
        compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
        reg = <0xff890000 0x10000>;
        interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
-       #address-cells = <1>;
-       #size-cells = <0>;
        dmas = <&pdma1 0>, <&pdma1 1>;
        dma-names = "tx", "rx";
        clock-names = "i2s_hclk", "i2s_clk";
        clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+       rockchip,capture-channels = <2>;
 };
diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt
new file mode 100644 (file)
index 0000000..e64dbde
--- /dev/null
@@ -0,0 +1,40 @@
+* Rockchip SPDIF transceiver
+
+The S/PDIF audio block is a stereo transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+- compatible: should be one of the following:
+   - "rockchip,rk3288-spdif", "rockchip,rk3188-spdif" or
+     "rockchip,rk3066-spdif"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: should contain the SPDIF interrupt.
+- dmas: DMA specifiers for tx dma. See the DMA client binding,
+  Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: should be "tx"
+- clocks: a list of phandle + clock-specifier pairs, one for each entry
+  in clock-names.
+- clock-names: should contain following:
+   - "hclk": clock for SPDIF controller
+   - "mclk" : clock for SPDIF bus
+
+Required properties on RK3288:
+  - rockchip,grf: the phandle of the syscon node for the general register
+                   file (GRF)
+
+Example for the rk3188 SPDIF controller:
+
+spdif: spdif@0x1011e000 {
+       compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif";
+       reg = <0x1011e000 0x2000>;
+       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&dmac1_s 8>;
+       dma-names = "tx";
+       clock-names = "hclk", "mclk";
+       clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>;
+       status = "disabled";
+       #sound-dai-cells = <0>;
+};
index bac4d9a..9e62f6e 100644 (file)
@@ -14,7 +14,8 @@ Optional properties:
 
 - realtek,in1-differential
 - realtek,in2-differential
-  Boolean. Indicate MIC1/2 input are differential, rather than single-ended.
+- realtek,in3-differential
+  Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended.
 
 - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
 
@@ -24,9 +25,11 @@ Pins on the device (for linking into audio routes) for RT5639/RT5640:
   * DMIC2
   * MICBIAS1
   * IN1P
-  * IN1R
+  * IN1N
   * IN2P
-  * IN2R
+  * IN2N
+  * IN3P
+  * IN3N
   * HPOL
   * HPOR
   * LOUTL
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
new file mode 100644 (file)
index 0000000..c92966b
--- /dev/null
@@ -0,0 +1,27 @@
+* Allwinner A10 Codec
+
+Required properties:
+- compatible: must be either "allwinner,sun4i-a10-codec" or
+  "allwinner,sun7i-a20-codec"
+- reg: must contain the registers location and length
+- interrupts: must contain the codec interrupt
+- dmas: DMA channels for tx and rx dma. See the DMA client binding,
+       Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: should include "tx" and "rx".
+- clocks: a list of phandle + clock-specifer pairs, one for each entry
+  in clock-names.
+- clock-names: should contain followings:
+   - "apb": the parent APB clock for this controller
+   - "codec": the parent module clock
+
+Example:
+codec: codec@01c22c00 {
+       #sound-dai-cells = <0>;
+       compatible = "allwinner,sun7i-a20-codec";
+       reg = <0x01c22c00 0x40>;
+       interrupts = <0 30 4>;
+       clocks = <&apb0_gates 0>, <&codec_clk>;
+       clock-names = "apb", "codec";
+       dmas = <&dma 0 19>, <&dma 0 19>;
+       dma-names = "rx", "tx";
+};
index 6a2c842..34cf70e 100644 (file)
@@ -4,11 +4,15 @@ This specifies audio DAI's TDM slot.
 
 TDM slot properties:
 dai-tdm-slot-num : Number of slots in use.
-dai-tdm-slot-width :  Width in bits for each slot.
+dai-tdm-slot-width : Width in bits for each slot.
+dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
+dai-tdm-slot-rx-mask : Receive direction slot mask, optional
 
 For instance:
        dai-tdm-slot-num = <2>;
        dai-tdm-slot-width = <8>;
+       dai-tdm-slot-tx-mask = <0 1>;
+       dai-tdm-slot-rx-mask = <1 0>;
 
 And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
 to specify a explicit mapping of the channels and the slots. If it's absent
@@ -18,3 +22,8 @@ tx and rx masks.
 For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
 for an active slot as default, and the default active bits are at the LSB of
 the masks.
+
+The explicit masks are given as array of integers, where the first
+number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
+number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
+does not do anything, if either mask is set non zero value.
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
deleted file mode 100644 (file)
index de8efbc..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-Notes on Universal Interface for Intel High Definition Audio Codec
-------------------------------------------------------------------
-
-Takashi Iwai <tiwai@suse.de>
-
-
-[Still a draft version]
-
-
-General
-=======
-
-The snd-hda-codec module supports the generic access function for the
-High Definition (HD) audio codecs.  It's designed to be independent
-from the controller code like ac97 codec module.  The real accessors
-from/to the controller must be implemented in the lowlevel driver.
-
-The structure of this module is similar with ac97_codec module.
-Each codec chip belongs to a bus class which communicates with the
-controller.
-
-
-Initialization of Bus Instance
-==============================
-
-The card driver has to create struct hda_bus at first.  The template
-struct should be filled and passed to the constructor:
-
-struct hda_bus_template {
-       void *private_data;
-       struct pci_dev *pci;
-       const char *modelname;
-       struct hda_bus_ops ops;
-};
-
-The card driver can set and use the private_data field to retrieve its
-own data in callback functions.  The pci field is used when the patch
-needs to check the PCI subsystem IDs, so on.  For non-PCI system, it
-doesn't have to be set, of course.
-The modelname field specifies the board's specific configuration.  The
-string is passed to the codec parser, and it depends on the parser how
-the string is used.
-These fields, private_data, pci and modelname are all optional.
-
-The ops field contains the callback functions as the following:
-
-struct hda_bus_ops {
-       int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
-                      unsigned int verb, unsigned int parm);
-       unsigned int (*get_response)(struct hda_codec *codec);
-       void (*private_free)(struct hda_bus *);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       void (*pm_notify)(struct hda_codec *codec);
-#endif
-};
-
-The command callback is called when the codec module needs to send a
-VERB to the controller.  It's always a single command.
-The get_response callback is called when the codec requires the answer
-for the last command.  These two callbacks are mandatory and have to
-be given.
-The third, private_free callback, is optional.  It's called in the
-destructor to release any necessary data in the lowlevel driver.
-
-The pm_notify callback is available only with
-CONFIG_SND_HDA_POWER_SAVE kconfig.  It's called when the codec needs
-to power up or may power down.  The controller should check the all
-belonging codecs on the bus whether they are actually powered off
-(check codec->power_on), and optionally the driver may power down the
-controller side, too.
-
-The bus instance is created via snd_hda_bus_new().  You need to pass
-the card instance, the template, and the pointer to store the
-resultant bus instance.
-
-int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
-                   struct hda_bus **busp);
-
-It returns zero if successful.  A negative return value means any
-error during creation.
-
-
-Creation of Codec Instance
-==========================
-
-Each codec chip on the board is then created on the BUS instance.
-To create a codec instance, call snd_hda_codec_new().
-
-int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-                     struct hda_codec **codecp);
-
-The first argument is the BUS instance, the second argument is the
-address of the codec, and the last one is the pointer to store the
-resultant codec instance (can be NULL if not needed).
-
-The codec is stored in a linked list of bus instance.  You can follow
-the codec list like:
-
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               ...
-       }
-
-The codec isn't initialized at this stage properly.  The
-initialization sequence is called when the controls are built later.
-
-
-Codec Access
-============
-
-To access codec, use snd_hda_codec_read() and snd_hda_codec_write().
-snd_hda_param_read() is for reading parameters.
-For writing a sequence of verbs, use snd_hda_sequence_write().
-
-There are variants of cached read/write, snd_hda_codec_write_cache(),
-snd_hda_sequence_write_cache().  These are used for recording the
-register states for the power-management resume.  When no PM is needed,
-these are equivalent with non-cached version.
-
-To retrieve the number of sub nodes connected to the given node, use
-snd_hda_get_sub_nodes().  The connection list can be obtained via
-snd_hda_get_connections() call.
-
-When an unsolicited event happens, pass the event via
-snd_hda_queue_unsol_event() so that the codec routines will process it
-later.
-
-
-(Mixer) Controls
-================
-
-To create mixer controls of all codecs, call
-snd_hda_build_controls().  It then builds the mixers and does
-initialization stuff on each codec.
-
-
-PCM Stuff
-=========
-
-snd_hda_build_pcms() gives the necessary information to create PCM
-streams.  When it's called, each codec belonging to the bus stores 
-codec->num_pcms and codec->pcm_info fields.  The num_pcms indicates
-the number of elements in pcm_info array.  The card driver is supposed
-to traverse the codec linked list, read the pcm information in
-pcm_info array, and build pcm instances according to them. 
-
-The pcm_info array contains the following record:
-
-/* PCM information for each substream */
-struct hda_pcm_stream {
-       unsigned int substreams;        /* number of substreams, 0 = not exist */
-       unsigned int channels_min;      /* min. number of channels */
-       unsigned int channels_max;      /* max. number of channels */
-       hda_nid_t nid;  /* default NID to query rates/formats/bps, or set up */
-       u32 rates;      /* supported rates */
-       u64 formats;    /* supported formats (SNDRV_PCM_FMTBIT_) */
-       unsigned int maxbps;    /* supported max. bit per sample */
-       struct hda_pcm_ops ops;
-};
-
-/* for PCM creation */
-struct hda_pcm {
-       char *name;
-       struct hda_pcm_stream stream[2];
-};
-
-The name can be passed to snd_pcm_new().  The stream field contains
-the information  for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and
-capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions.  The card driver
-should pass substreams to snd_pcm_new() for the number of substreams
-to create.
-
-The channels_min, channels_max, rates and formats should be copied to
-runtime->hw record.  They and maxbps fields are used also to compute
-the format value for the HDA codec and controller.  Call
-snd_hda_calc_stream_format() to get the format value.
-
-The ops field contains the following callback functions:
-
-struct hda_pcm_ops {
-       int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                   struct snd_pcm_substream *substream);
-       int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                    struct snd_pcm_substream *substream);
-       int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                      unsigned int stream_tag, unsigned int format,
-                      struct snd_pcm_substream *substream);
-       int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                      struct snd_pcm_substream *substream);
-};
-
-All are non-NULL, so you can call them safely without NULL check.
-
-The open callback should be called in PCM open after runtime->hw is
-set up.  It may override some setting and constraints additionally.
-Similarly, the close callback should be called in the PCM close.
-
-The prepare callback should be called in PCM prepare.  This will set
-up the codec chip properly for the operation.  The cleanup should be
-called in hw_free to clean up the configuration.
-
-The caller should check the return value, at least for open and
-prepare callbacks.  When a negative value is returned, some error
-occurred.
-
-
-Proc Files
-==========
-
-Each codec dumps the widget node information in
-/proc/asound/card*/codec#* file.  This information would be really
-helpful for debugging.  Please provide its contents together with the
-bug report.
-
-
-Power Management
-================
-
-It's simple:
-Call snd_hda_suspend() in the PM suspend callback.
-Call snd_hda_resume() in the PM resume callback.
-
-
-Codec Preset (Patch)
-====================
-
-To set up and handle the codec functionality fully, each codec may
-have a codec preset (patch).  It's defined in struct hda_codec_preset:
-
-       struct hda_codec_preset {
-               unsigned int id;
-               unsigned int mask;
-               unsigned int subs;
-               unsigned int subs_mask;
-               unsigned int rev;
-               const char *name;
-               int (*patch)(struct hda_codec *codec);
-       };
-
-When the codec id and codec subsystem id match with the given id and
-subs fields bitwise (with bitmask mask and subs_mask), the callback
-patch is called.  The patch callback should initialize the codec and
-set the codec->patch_ops field.  This is defined as below:
-
-       struct hda_codec_ops {
-               int (*build_controls)(struct hda_codec *codec);
-               int (*build_pcms)(struct hda_codec *codec);
-               int (*init)(struct hda_codec *codec);
-               void (*free)(struct hda_codec *codec);
-               void (*unsol_event)(struct hda_codec *codec, unsigned int res);
-       #ifdef CONFIG_PM
-               int (*suspend)(struct hda_codec *codec, pm_message_t state);
-               int (*resume)(struct hda_codec *codec);
-       #endif
-       #ifdef CONFIG_SND_HDA_POWER_SAVE
-               int (*check_power_status)(struct hda_codec *codec,
-                                         hda_nid_t nid);
-       #endif
-       };
-
-The build_controls callback is called from snd_hda_build_controls().
-Similarly, the build_pcms callback is called from
-snd_hda_build_pcms().  The init callback is called after
-build_controls to initialize the hardware.
-The free callback is called as a destructor.
-
-The unsol_event callback is called when an unsolicited event is
-received.
-
-The suspend and resume callbacks are for power management.
-They can be NULL if no special sequence is required.  When the resume
-callback is NULL, the driver calls the init callback and resumes the
-registers from the cache.  If other handling is needed, you'd need to
-write your own resume callback.  There, the amp values can be resumed
-via
-       void snd_hda_codec_resume_amp(struct hda_codec *codec);
-and the other codec registers via
-       void snd_hda_codec_resume_cache(struct hda_codec *codec);
-
-The check_power_status callback is called when the amp value of the
-given widget NID is changed.  The codec code can turn on/off the power
-appropriately from this information.
-
-Each entry can be NULL if not necessary to be called.
-
-
-Generic Parser
-==============
-
-When the device doesn't match with any given presets, the widgets are
-parsed via th generic parser (hda_generic.c).  Its support is
-limited: no multi-channel support, for example.
-
-
-Digital I/O
-===========
-
-Call snd_hda_create_spdif_out_ctls() from the patch to create controls
-related with SPDIF out.
-
-
-Helper Functions
-================
-
-snd_hda_get_codec_name() stores the codec name on the given string.
-
-snd_hda_check_board_config() can be used to obtain the configuration
-information matching with the device.  Define the model string table
-and the table with struct snd_pci_quirk entries (zero-terminated),
-and pass it to the function.  The function checks the modelname given
-as a module parameter, and PCI subsystem IDs.  If the matching entry
-is found, it returns the config field value.
-
-snd_hda_add_new_ctls() can be used to create and add control entries.
-Pass the zero-terminated array of struct snd_kcontrol_new
-
-Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be
-used for the entry of struct snd_kcontrol_new.
-
-The input MUX helper callbacks for such a control are provided, too:
-snd_hda_input_mux_info() and snd_hda_input_mux_put().  See
-patch_realtek.c for example.
index 5974a0f..a17f58c 100644 (file)
@@ -3378,6 +3378,7 @@ M:        Support Opensource <support.opensource@diasemi.com>
 W:     http://www.dialog-semiconductor.com/products
 S:     Supported
 F:     Documentation/hwmon/da90??
+F:     Documentation/devicetree/bindings/sound/da[79]*.txt
 F:     drivers/gpio/gpio-da90??.c
 F:     drivers/hwmon/da90??-hwmon.c
 F:     drivers/iio/adc/da91??-*.c
index ab37d11..990f656 100644 (file)
@@ -832,6 +832,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        mutex_init(&dev_priv->sb_lock);
        mutex_init(&dev_priv->modeset_restore_lock);
        mutex_init(&dev_priv->csr_lock);
+       mutex_init(&dev_priv->av_mutex);
 
        intel_pm_setup(dev);
 
index e1db8de..22dd704 100644 (file)
@@ -1885,6 +1885,11 @@ struct drm_i915_private {
        /* hda/i915 audio component */
        struct i915_audio_component *audio_component;
        bool audio_component_registered;
+       /**
+        * av_mutex - mutex for audio/video sync
+        *
+        */
+       struct mutex av_mutex;
 
        uint32_t hw_context_size;
        struct list_head context_list;
index 2a5c76f..ae8df0a 100644 (file)
@@ -68,6 +68,31 @@ static const struct {
        { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
 };
 
+/* HDMI N/CTS table */
+#define TMDS_297M 297000
+#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
+static const struct {
+       int sample_rate;
+       int clock;
+       int n;
+       int cts;
+} aud_ncts[] = {
+       { 44100, TMDS_296M, 4459, 234375 },
+       { 44100, TMDS_297M, 4704, 247500 },
+       { 48000, TMDS_296M, 5824, 281250 },
+       { 48000, TMDS_297M, 5120, 247500 },
+       { 32000, TMDS_296M, 5824, 421875 },
+       { 32000, TMDS_297M, 3072, 222750 },
+       { 88200, TMDS_296M, 8918, 234375 },
+       { 88200, TMDS_297M, 9408, 247500 },
+       { 96000, TMDS_296M, 11648, 281250 },
+       { 96000, TMDS_297M, 10240, 247500 },
+       { 176400, TMDS_296M, 17836, 234375 },
+       { 176400, TMDS_297M, 18816, 247500 },
+       { 192000, TMDS_296M, 23296, 281250 },
+       { 192000, TMDS_297M, 20480, 247500 },
+};
+
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
 static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
 {
@@ -90,6 +115,45 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
        return hdmi_audio_clock[i].config;
 }
 
+static int audio_config_get_n(const struct drm_display_mode *mode, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) {
+               if ((rate == aud_ncts[i].sample_rate) &&
+                       (mode->clock == aud_ncts[i].clock)) {
+                       return aud_ncts[i].n;
+               }
+       }
+       return 0;
+}
+
+static uint32_t audio_config_setup_n_reg(int n, uint32_t val)
+{
+       int n_low, n_up;
+       uint32_t tmp = val;
+
+       n_low = n & 0xfff;
+       n_up = (n >> 12) & 0xff;
+       tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK);
+       tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) |
+                       (n_low << AUD_CONFIG_LOWER_N_SHIFT) |
+                       AUD_CONFIG_N_PROG_ENABLE);
+       return tmp;
+}
+
+/* check whether N/CTS/M need be set manually */
+static bool audio_rate_need_prog(struct intel_crtc *crtc,
+                                const struct drm_display_mode *mode)
+{
+       if (((mode->clock == TMDS_297M) ||
+                (mode->clock == TMDS_296M)) &&
+               intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
+               return true;
+       else
+               return false;
+}
+
 static bool intel_eld_uptodate(struct drm_connector *connector,
                               int reg_eldv, uint32_t bits_eldv,
                               int reg_elda, uint32_t bits_elda,
@@ -184,6 +248,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
 
        DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe));
 
+       mutex_lock(&dev_priv->av_mutex);
+
        /* Disable timestamps */
        tmp = I915_READ(HSW_AUD_CFG(pipe));
        tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
@@ -199,6 +265,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
        tmp &= ~AUDIO_ELD_VALID(pipe);
        tmp &= ~AUDIO_OUTPUT_ENABLE(pipe);
        I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
 }
 
 static void hsw_audio_codec_enable(struct drm_connector *connector,
@@ -208,13 +276,20 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        enum pipe pipe = intel_crtc->pipe;
+       struct i915_audio_component *acomp = dev_priv->audio_component;
        const uint8_t *eld = connector->eld;
+       struct intel_digital_port *intel_dig_port =
+               enc_to_dig_port(&encoder->base);
+       enum port port = intel_dig_port->port;
        uint32_t tmp;
        int len, i;
+       int n, rate;
 
        DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n",
                      pipe_name(pipe), drm_eld_size(eld));
 
+       mutex_lock(&dev_priv->av_mutex);
+
        /* Enable audio presence detect, invalidate ELD */
        tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
        tmp |= AUDIO_OUTPUT_ENABLE(pipe);
@@ -246,13 +321,32 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
        /* Enable timestamps */
        tmp = I915_READ(HSW_AUD_CFG(pipe));
        tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
-       tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
        tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
        if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
                tmp |= AUD_CONFIG_N_VALUE_INDEX;
        else
                tmp |= audio_config_hdmi_pixel_clock(mode);
+
+       tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+       if (audio_rate_need_prog(intel_crtc, mode)) {
+               if (!acomp)
+                       rate = 0;
+               else if (port >= PORT_A && port <= PORT_E)
+                       rate = acomp->aud_sample_rate[port];
+               else {
+                       DRM_ERROR("invalid port: %d\n", port);
+                       rate = 0;
+               }
+               n = audio_config_get_n(mode, rate);
+               if (n != 0)
+                       tmp = audio_config_setup_n_reg(n, tmp);
+               else
+                       DRM_DEBUG_KMS("no suitable N value is found\n");
+       }
+
        I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
 }
 
 static void ilk_audio_codec_disable(struct intel_encoder *encoder)
@@ -527,12 +621,91 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
        return ret;
 }
 
+static int i915_audio_component_sync_audio_rate(struct device *dev,
+                                               int port, int rate)
+{
+       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_device *drm_dev = dev_priv->dev;
+       struct intel_encoder *intel_encoder;
+       struct intel_digital_port *intel_dig_port;
+       struct intel_crtc *crtc;
+       struct drm_display_mode *mode;
+       struct i915_audio_component *acomp = dev_priv->audio_component;
+       enum pipe pipe = -1;
+       u32 tmp;
+       int n;
+
+       /* HSW, BDW SKL need this fix */
+       if (!IS_SKYLAKE(dev_priv) &&
+               !IS_BROADWELL(dev_priv) &&
+               !IS_HASWELL(dev_priv))
+               return 0;
+
+       mutex_lock(&dev_priv->av_mutex);
+       /* 1. get the pipe */
+       for_each_intel_encoder(drm_dev, intel_encoder) {
+               if (intel_encoder->type != INTEL_OUTPUT_HDMI)
+                       continue;
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               if (port == intel_dig_port->port) {
+                       crtc = to_intel_crtc(intel_encoder->base.crtc);
+                       if (!crtc) {
+                               DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__);
+                               continue;
+                       }
+                       pipe = crtc->pipe;
+                       break;
+               }
+       }
+
+       if (pipe == INVALID_PIPE) {
+               DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
+               mutex_unlock(&dev_priv->av_mutex);
+               return -ENODEV;
+       }
+       DRM_DEBUG_KMS("pipe %c connects port %c\n",
+                                 pipe_name(pipe), port_name(port));
+       mode = &crtc->config->base.adjusted_mode;
+
+       /* port must be valid now, otherwise the pipe will be invalid */
+       acomp->aud_sample_rate[port] = rate;
+
+       /* 2. check whether to set the N/CTS/M manually or not */
+       if (!audio_rate_need_prog(crtc, mode)) {
+               tmp = I915_READ(HSW_AUD_CFG(pipe));
+               tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+               I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+               mutex_unlock(&dev_priv->av_mutex);
+               return 0;
+       }
+
+       n = audio_config_get_n(mode, rate);
+       if (n == 0) {
+               DRM_DEBUG_KMS("Using automatic mode for N value on port %c\n",
+                                         port_name(port));
+               tmp = I915_READ(HSW_AUD_CFG(pipe));
+               tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+               I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+               mutex_unlock(&dev_priv->av_mutex);
+               return 0;
+       }
+
+       /* 3. set the N/CTS/M */
+       tmp = I915_READ(HSW_AUD_CFG(pipe));
+       tmp = audio_config_setup_n_reg(n, tmp);
+       I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
+       return 0;
+}
+
 static const struct i915_audio_component_ops i915_audio_component_ops = {
        .owner          = THIS_MODULE,
        .get_power      = i915_audio_component_get_power,
        .put_power      = i915_audio_component_put_power,
        .codec_wake_override = i915_audio_component_codec_wake_override,
        .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
+       .sync_audio_rate = i915_audio_component_sync_audio_rate,
 };
 
 static int i915_audio_component_bind(struct device *i915_dev,
@@ -540,6 +713,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
 {
        struct i915_audio_component *acomp = data;
        struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
+       int i;
 
        if (WARN_ON(acomp->ops || acomp->dev))
                return -EEXIST;
@@ -547,6 +721,9 @@ static int i915_audio_component_bind(struct device *i915_dev,
        drm_modeset_lock_all(dev_priv->dev);
        acomp->ops = &i915_audio_component_ops;
        acomp->dev = i915_dev;
+       BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
+       for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
+               acomp->aud_sample_rate[i] = 0;
        dev_priv->audio_component = acomp;
        drm_modeset_unlock_all(dev_priv->dev);
 
index 63318e2..41e37a6 100644 (file)
@@ -871,14 +871,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
         * Calculate the lowest divider that satisfies the
         * constraint, assuming div32/fdiv/mbz == 0.
         */
-       if (xfer->speed_hz)
-               scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
-       else
-               /*
-                * This can happend if max_speed is null.
-                * In this case, we set the lowest possible speed
-                */
-               scbr = 0xff;
+       scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
 
        /*
         * If the resulting divider doesn't fit into the
@@ -1300,14 +1293,12 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                return -EINVAL;
        }
 
-       if (xfer->bits_per_word) {
-               asd = spi->controller_state;
-               bits = (asd->csr >> 4) & 0xf;
-               if (bits != xfer->bits_per_word - 8) {
-                       dev_dbg(&spi->dev,
+       asd = spi->controller_state;
+       bits = (asd->csr >> 4) & 0xf;
+       if (bits != xfer->bits_per_word - 8) {
+               dev_dbg(&spi->dev,
                        "you can't yet change bits_per_word in transfers\n");
-                       return -ENOPROTOOPT;
-               }
+               return -ENOPROTOOPT;
        }
 
        /*
index b2d56dd..89dc7d6 100644 (file)
 #ifndef _I915_COMPONENT_H_
 #define _I915_COMPONENT_H_
 
+/* MAX_PORT is the number of port
+ * It must be sync with I915_MAX_PORTS defined i915_drv.h
+ * 5 should be enough as only HSW, BDW, SKL need such fix.
+ */
+#define MAX_PORTS 5
+
 struct i915_audio_component {
        struct device *dev;
+       /**
+        * @aud_sample_rate: the array of audio sample rate per port
+        */
+       int aud_sample_rate[MAX_PORTS];
 
        const struct i915_audio_component_ops {
                struct module *owner;
@@ -33,6 +43,13 @@ struct i915_audio_component {
                void (*put_power)(struct device *);
                void (*codec_wake_override)(struct device *, bool enable);
                int (*get_cdclk_freq)(struct device *);
+               /**
+                * @sync_audio_rate: set n/cts based on the sample rate
+                *
+                * Called from audio driver. After audio driver sets the
+                * sample rate, it will call this function to set n/cts
+                */
+               int (*sync_audio_rate)(struct device *, int port, int rate);
        } *ops;
 
        const struct i915_audio_component_audio_ops {
index 688997a..0082567 100644 (file)
@@ -219,6 +219,14 @@ struct serio_device_id {
        __u8 proto;
 };
 
+struct hda_device_id {
+       __u32 vendor_id;
+       __u32 rev_id;
+       __u8 api_version;
+       const char *name;
+       unsigned long driver_data;
+};
+
 /*
  * Struct used for matching a device
  */
index 673f5c3..e7eac89 100644 (file)
@@ -44,9 +44,6 @@ struct da7213_platform_data {
        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/da7219-aad.h b/include/sound/da7219-aad.h
new file mode 100644 (file)
index 0000000..17802fb
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * da7219-aad.h - DA7322 ASoC Codec AAD Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_AAD_PDATA_H
+#define __DA7219_AAD_PDATA_H
+
+enum da7219_aad_micbias_pulse_lvl {
+       DA7219_AAD_MICBIAS_PULSE_LVL_OFF = 0,
+       DA7219_AAD_MICBIAS_PULSE_LVL_2_8V = 6,
+       DA7219_AAD_MICBIAS_PULSE_LVL_2_9V,
+};
+
+enum da7219_aad_btn_cfg {
+       DA7219_AAD_BTN_CFG_2MS = 1,
+       DA7219_AAD_BTN_CFG_5MS,
+       DA7219_AAD_BTN_CFG_10MS,
+       DA7219_AAD_BTN_CFG_50MS,
+       DA7219_AAD_BTN_CFG_100MS,
+       DA7219_AAD_BTN_CFG_200MS,
+       DA7219_AAD_BTN_CFG_500MS,
+};
+
+enum da7219_aad_mic_det_thr {
+       DA7219_AAD_MIC_DET_THR_200_OHMS = 0,
+       DA7219_AAD_MIC_DET_THR_500_OHMS,
+       DA7219_AAD_MIC_DET_THR_750_OHMS,
+       DA7219_AAD_MIC_DET_THR_1000_OHMS,
+};
+
+enum da7219_aad_jack_ins_deb {
+       DA7219_AAD_JACK_INS_DEB_5MS = 0,
+       DA7219_AAD_JACK_INS_DEB_10MS,
+       DA7219_AAD_JACK_INS_DEB_20MS,
+       DA7219_AAD_JACK_INS_DEB_50MS,
+       DA7219_AAD_JACK_INS_DEB_100MS,
+       DA7219_AAD_JACK_INS_DEB_200MS,
+       DA7219_AAD_JACK_INS_DEB_500MS,
+       DA7219_AAD_JACK_INS_DEB_1S,
+};
+
+enum da7219_aad_jack_det_rate {
+       DA7219_AAD_JACK_DET_RATE_32_64MS = 0,
+       DA7219_AAD_JACK_DET_RATE_64_128MS,
+       DA7219_AAD_JACK_DET_RATE_128_256MS,
+       DA7219_AAD_JACK_DET_RATE_256_512MS,
+};
+
+enum da7219_aad_jack_rem_deb {
+       DA7219_AAD_JACK_REM_DEB_1MS = 0,
+       DA7219_AAD_JACK_REM_DEB_5MS,
+       DA7219_AAD_JACK_REM_DEB_10MS,
+       DA7219_AAD_JACK_REM_DEB_20MS,
+};
+
+enum da7219_aad_btn_avg {
+       DA7219_AAD_BTN_AVG_1 = 0,
+       DA7219_AAD_BTN_AVG_2,
+       DA7219_AAD_BTN_AVG_4,
+       DA7219_AAD_BTN_AVG_8,
+};
+
+enum da7219_aad_adc_1bit_rpt {
+       DA7219_AAD_ADC_1BIT_RPT_1 = 0,
+       DA7219_AAD_ADC_1BIT_RPT_2,
+       DA7219_AAD_ADC_1BIT_RPT_4,
+       DA7219_AAD_ADC_1BIT_RPT_8,
+};
+
+struct da7219_aad_pdata {
+       int irq;
+
+       enum da7219_aad_micbias_pulse_lvl micbias_pulse_lvl;
+       u32 micbias_pulse_time;
+       enum da7219_aad_btn_cfg btn_cfg;
+       enum da7219_aad_mic_det_thr mic_det_thr;
+       enum da7219_aad_jack_ins_deb jack_ins_deb;
+       enum da7219_aad_jack_det_rate jack_det_rate;
+       enum da7219_aad_jack_rem_deb jack_rem_deb;
+
+       u8 a_d_btn_thr;
+       u8 d_b_btn_thr;
+       u8 b_c_btn_thr;
+       u8 c_mic_btn_thr;
+
+       enum da7219_aad_btn_avg btn_avg;
+       enum da7219_aad_adc_1bit_rpt adc_1bit_rpt;
+};
+
+#endif /* __DA7219_AAD_PDATA_H */
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
new file mode 100644 (file)
index 0000000..3f39e13
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * da7219.h - DA7219 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2015 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_PDATA_H
+#define __DA7219_PDATA_H
+
+/* LDO */
+enum da7219_ldo_lvl_sel {
+       DA7219_LDO_LVL_SEL_1_05V = 0,
+       DA7219_LDO_LVL_SEL_1_10V,
+       DA7219_LDO_LVL_SEL_1_20V,
+       DA7219_LDO_LVL_SEL_1_40V,
+};
+
+/* Mic Bias */
+enum da7219_micbias_voltage {
+       DA7219_MICBIAS_1_8V = 1,
+       DA7219_MICBIAS_2_0V,
+       DA7219_MICBIAS_2_2V,
+       DA7219_MICBIAS_2_4V,
+       DA7219_MICBIAS_2_6V,
+};
+
+/* Mic input type */
+enum da7219_mic_amp_in_sel {
+       DA7219_MIC_AMP_IN_SEL_DIFF = 0,
+       DA7219_MIC_AMP_IN_SEL_SE_P,
+       DA7219_MIC_AMP_IN_SEL_SE_N,
+};
+
+struct da7219_aad_pdata;
+
+struct da7219_pdata {
+       /* Internal LDO */
+       enum da7219_ldo_lvl_sel ldo_lvl_sel;
+
+       /* Mic */
+       enum da7219_micbias_voltage micbias_lvl;
+       enum da7219_mic_amp_in_sel mic_amp_in_sel;
+
+       /* AAD */
+       struct da7219_aad_pdata *aad_pdata;
+};
+
+#endif /* __DA7219_PDATA_H */
index 3a8fca9..8966ba7 100644 (file)
@@ -38,6 +38,8 @@ struct i2s_clk_config_data {
 struct i2s_platform_data {
        #define DWC_I2S_PLAY    (1 << 0)
        #define DWC_I2S_RECORD  (1 << 1)
+       #define DW_I2S_SLAVE    (1 << 2)
+       #define DW_I2S_MASTER   (1 << 3)
        unsigned int cap;
        int channel;
        u32 snd_fmts;
index df70590..2767c55 100644 (file)
@@ -67,7 +67,7 @@ int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
  * @reg: verb to write
  * @val: value to write
  *
- * For writing an amp value, use snd_hda_regmap_amp_update().
+ * For writing an amp value, use snd_hdac_regmap_update_amp().
  */
 static inline int
 snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
@@ -85,7 +85,7 @@ snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
  * @mask: bit mask to update
  * @val: value to update
  *
- * For updating an amp value, use snd_hda_regmap_amp_update().
+ * For updating an amp value, use snd_hdac_regmap_update_amp().
  */
 static inline int
 snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
index 49bc836..e2b712c 100644 (file)
@@ -21,22 +21,13 @@ struct hdac_stream;
 struct hdac_device;
 struct hdac_driver;
 struct hdac_widget_tree;
+struct hda_device_id;
 
 /*
  * exported bus type
  */
 extern struct bus_type snd_hda_bus_type;
 
-/*
- * HDA device table
- */
-struct hda_device_id {
-       __u32 vendor_id;
-       __u32 rev_id;
-       const char *name;
-       unsigned long driver_data;
-};
-
 /*
  * generic arrays
  */
@@ -117,6 +108,8 @@ int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
 void snd_hdac_device_exit(struct hdac_device *dev);
 int snd_hdac_device_register(struct hdac_device *codec);
 void snd_hdac_device_unregister(struct hdac_device *codec);
+int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name);
+int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size);
 
 int snd_hdac_refresh_widgets(struct hdac_device *codec);
 int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec);
@@ -147,6 +140,12 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
 bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
                                  unsigned int format);
 
+int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm);
+int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm);
+bool snd_hdac_check_power_state(struct hdac_device *hdac,
+               hda_nid_t nid, unsigned int target_state);
 /**
  * snd_hdac_read_parm - read a codec parameter
  * @codec: the codec object
index 94210dc..a4cadd9 100644 (file)
@@ -40,6 +40,13 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
 #define hbus_to_ebus(_bus) \
        container_of(_bus, struct hdac_ext_bus, bus)
 
+#define HDA_CODEC_REV_EXT_ENTRY(_vid, _rev, _name, drv_data) \
+       { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
+         .api_version = HDA_DEV_ASOC, \
+         .driver_data = (unsigned long)(drv_data) }
+#define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
+       HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)
+
 int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus);
 void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
index 691e7ee..b0be092 100644 (file)
@@ -265,12 +265,12 @@ struct snd_ratden {
 
 struct snd_pcm_hw_constraint_ratnums {
        int nrats;
-       struct snd_ratnum *rats;
+       const struct snd_ratnum *rats;
 };
 
 struct snd_pcm_hw_constraint_ratdens {
        int nrats;
-       struct snd_ratden *rats;
+       const struct snd_ratden *rats;
 };
 
 struct snd_pcm_hw_constraint_list {
@@ -285,8 +285,6 @@ struct snd_pcm_hw_constraint_ranges {
        unsigned int mask;
 };
 
-struct snd_pcm_hwptr_log;
-
 /*
  * userspace-provided audio timestamp config to kernel,
  * structure is for internal use only and filled with dedicated unpack routine
@@ -404,10 +402,6 @@ struct snd_pcm_runtime {
        struct snd_pcm_hardware hw;
        struct snd_pcm_hw_constraints hw_constraints;
 
-       /* -- interrupt callbacks -- */
-       void (*transfer_ack_begin)(struct snd_pcm_substream *substream);
-       void (*transfer_ack_end)(struct snd_pcm_substream *substream);
-
        /* -- timer -- */
        unsigned int timer_resolution;  /* timer resolution */
        int tstamp_type;                /* timestamp type */
@@ -428,10 +422,6 @@ struct snd_pcm_runtime {
        /* -- OSS things -- */
        struct snd_pcm_oss_runtime oss;
 #endif
-
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       struct snd_pcm_hwptr_log *hwptr_log;
-#endif
 };
 
 struct snd_pcm_group {         /* keep linked substreams */
@@ -980,7 +970,7 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 int snd_interval_ranges(struct snd_interval *i, unsigned int count,
                        const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
-                       unsigned int rats_count, struct snd_ratnum *rats,
+                       unsigned int rats_count, const struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp);
 
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
@@ -1010,11 +1000,11 @@ int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratnums *r);
+                                 const struct snd_pcm_hw_constraint_ratnums *r);
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratdens *r);
+                                 const struct snd_pcm_hw_constraint_ratdens *r);
 int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
                                 unsigned int cond,
                                 unsigned int width,
@@ -1034,6 +1024,22 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime,
                        snd_pcm_hw_rule_func_t func, void *private,
                        int dep, ...);
 
+/**
+ * snd_pcm_hw_constraint_single() - Constrain parameter to a single value
+ * @runtime: PCM runtime instance
+ * @var: The hw_params variable to constrain
+ * @val: The value to constrain to
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+static inline int snd_pcm_hw_constraint_single(
+       struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
+       unsigned int val)
+{
+       return snd_pcm_hw_constraint_minmax(runtime, var, val, val);
+}
+
 int snd_pcm_format_signed(snd_pcm_format_t format);
 int snd_pcm_format_unsigned(snd_pcm_format_t format);
 int snd_pcm_format_linear(snd_pcm_format_t format);
@@ -1117,10 +1123,16 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
  *  Timer interface
  */
 
+#ifdef CONFIG_SND_PCM_TIMER
 void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
 void snd_pcm_timer_init(struct snd_pcm_substream *substream);
 void snd_pcm_timer_done(struct snd_pcm_substream *substream);
-
+#else
+static inline void
+snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
+#endif
 /**
  * snd_pcm_gettime - Fill the timespec depending on the timestamp mode
  * @runtime: PCM runtime instance
index 56e818e..6ef629b 100644 (file)
@@ -12,7 +12,6 @@ extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
 extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
 extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
-extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id);
 extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
 extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
index 59d26dd..e3c84b9 100644 (file)
 #define __LINUX_SND_RT5640_H
 
 struct rt5640_platform_data {
-       /* IN1 & IN2 can optionally be differential */
+       /* IN1 & IN2 & IN3 can optionally be differential */
        bool in1_diff;
        bool in2_diff;
+       bool in3_diff;
 
        bool dmic_en;
        bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */
index 22734bc..a5cf615 100644 (file)
@@ -21,6 +21,8 @@ struct rt5645_platform_data {
        /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
 
        unsigned int jd_mode;
+       /* Invert JD when jack insert */
+       bool jd_invert;
 };
 
 #endif
index b9b4f28..0399352 100644 (file)
@@ -19,6 +19,8 @@ struct asoc_simple_dai {
        unsigned int sysclk;
        int slots;
        int slot_width;
+       unsigned int tx_slot_mask;
+       unsigned int rx_slot_mask;
        struct clk *clk;
 };
 
index 2df96b1..212eaaf 100644 (file)
@@ -48,10 +48,25 @@ struct snd_compr_stream;
 #define SND_SOC_DAIFMT_GATED           (0 << 4) /* clock is gated */
 
 /*
- * DAI hardware signal inversions.
+ * DAI hardware signal polarity.
  *
  * Specifies whether the DAI can also support inverted clocks for the specified
  * format.
+ *
+ * BCLK:
+ * - "normal" polarity means signal is available at rising edge of BCLK
+ * - "inverted" polarity means signal is available at falling edge of BCLK
+ *
+ * FSYNC "normal" polarity depends on the frame format:
+ * - I2S: frame consists of left then right channel data. Left channel starts
+ *      with falling FSYNC edge, right channel starts with rising FSYNC edge.
+ * - Left/Right Justified: frame consists of left then right channel data.
+ *      Left channel starts with rising FSYNC edge, right channel starts with
+ *      falling FSYNC edge.
+ * - DSP A/B: Frame starts with rising FSYNC edge.
+ * - AC97: Frame starts with rising FSYNC edge.
+ *
+ * "Negative" FSYNC polarity is the one opposite of "normal" polarity.
  */
 #define SND_SOC_DAIFMT_NB_NF           (0 << 8) /* normal bit clock + frame */
 #define SND_SOC_DAIFMT_NB_IF           (2 << 8) /* normal BCLK + inv FRM */
@@ -214,7 +229,7 @@ struct snd_soc_dai_driver {
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
        /* compress dai */
-       bool compress_dai;
+       int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
        /* DAI is also used for the control bus */
        bool bus_control;
 
index 5abba03..7855cfe 100644 (file)
@@ -451,6 +451,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
        struct snd_kcontrol *kcontrol);
 
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
+               struct snd_kcontrol *kcontrol);
+
 int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
        enum snd_soc_bias_level level);
 
index 26ede14..a8b4b9c 100644 (file)
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = \
                SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
+#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+        xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
+                                           xmax, xinvert) }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
+#define SOC_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \
+                                xhandler_get, xhandler_put, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_range, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .rreg = xreg, .shift = xshift, \
+                .rshift = xshift, .min = xmin, .max = xmax, \
+                .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -440,7 +459,9 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,
 int snd_soc_platform_write(struct snd_soc_platform *platform,
                                        unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
-int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
+#ifdef CONFIG_SND_SOC_COMPRESS
+int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
+#endif
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
                const char *dai_link, int stream);
@@ -593,7 +614,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
-int snd_soc_limit_volume(struct snd_soc_codec *codec,
+int snd_soc_limit_volume(struct snd_soc_card *card,
        const char *name, int max);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo);
@@ -1603,6 +1624,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                                          const char *propname);
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *tx_mask,
+                             unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width);
 void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
index 247c50b..26539a7 100644 (file)
@@ -83,7 +83,7 @@
 #define SND_SOC_TPLG_NUM_TEXTS         16
 
 /* ABI version */
-#define SND_SOC_TPLG_ABI_VERSION       0x3
+#define SND_SOC_TPLG_ABI_VERSION       0x4
 
 /* Max size of TLV data */
 #define SND_SOC_TPLG_TLV_SIZE          32
 #define SND_SOC_TPLG_TYPE_PCM          7
 #define SND_SOC_TPLG_TYPE_MANIFEST     8
 #define SND_SOC_TPLG_TYPE_CODEC_LINK   9
-#define SND_SOC_TPLG_TYPE_PDATA                10
+#define SND_SOC_TPLG_TYPE_BACKEND_LINK 10
+#define SND_SOC_TPLG_TYPE_PDATA                11
 #define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_PDATA
 
 /* vendor block IDs - please add new vendor types to end */
@@ -198,7 +199,7 @@ struct snd_soc_tplg_ctl_hdr {
 struct snd_soc_tplg_stream_caps {
        __le32 size;            /* in bytes of this structure */
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       __le64 formats[SND_SOC_TPLG_MAX_FORMATS];       /* supported formats SNDRV_PCM_FMTBIT_* */
+       __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */
        __le32 rates;           /* supported rates SNDRV_PCM_RATE_* */
        __le32 rate_min;        /* min rate */
        __le32 rate_max;        /* max rate */
@@ -217,23 +218,12 @@ struct snd_soc_tplg_stream_caps {
  */
 struct snd_soc_tplg_stream {
        __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* Name of the stream */
        __le64 format;          /* SNDRV_PCM_FMTBIT_* */
        __le32 rate;            /* SNDRV_PCM_RATE_* */
        __le32 period_bytes;    /* size of period in bytes */
        __le32 buffer_bytes;    /* size of buffer in bytes */
        __le32 channels;        /* channels */
-       __le32 tdm_slot;        /* optional BE bitmask of supported TDM slots */
-       __le32 dai_fmt;         /* SND_SOC_DAIFMT_  */
-} __attribute__((packed));
-
-/*
- * Duplex stream configuration supported by SW/FW.
- */
-struct snd_soc_tplg_stream_config {
-       __le32 size;            /* in bytes of this structure */
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       struct snd_soc_tplg_stream playback;
-       struct snd_soc_tplg_stream capture;
 } __attribute__((packed));
 
 /*
@@ -366,11 +356,11 @@ struct snd_soc_tplg_dapm_widget {
        __le32 shift;           /* bits to shift */
        __le32 mask;            /* non-shifted mask */
        __le32 subseq;          /* sort within widget type */
-       __u32 invert;           /* invert the power bit */
-       __u32 ignore_suspend;   /* kept enabled over suspend */
-       __u16 event_flags;
-       __u16 event_type;
-       __u16 num_kcontrols;
+       __le32 invert;          /* invert the power bit */
+       __le32 ignore_suspend;  /* kept enabled over suspend */
+       __le16 event_flags;
+       __le16 event_type;
+       __le32 num_kcontrols;
        struct snd_soc_tplg_private priv;
        /*
         * kcontrols that relate to this widget
@@ -378,30 +368,46 @@ struct snd_soc_tplg_dapm_widget {
         */
 } __attribute__((packed));
 
-struct snd_soc_tplg_pcm_cfg_caps {
-       struct snd_soc_tplg_stream_caps caps;
-       struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
-       __le32 num_configs;     /* number of configs */
-} __attribute__((packed));
 
 /*
- * Describes SW/FW specific features of PCM or DAI link.
+ * Describes SW/FW specific features of PCM (FE DAI & DAI link).
  *
- * File block representation for PCM/DAI-Link :-
+ * File block representation for PCM :-
  * +-----------------------------------+-----+
  * | struct snd_soc_tplg_hdr           |  1  |
  * +-----------------------------------+-----+
- * | struct snd_soc_tplg_dapm_pcm_dai  |  N  |
+ * | struct snd_soc_tplg_pcm           |  N  |
  * +-----------------------------------+-----+
  */
-struct snd_soc_tplg_pcm_dai {
+struct snd_soc_tplg_pcm {
        __le32 size;            /* in bytes of this structure */
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       __le32 id;                      /* unique ID - used to match */
-       __le32 playback;                /* supports playback mode */
-       __le32 capture;                 /* supports capture mode */
-       __le32 compress;                /* 1 = compressed; 0 = PCM */
-       struct snd_soc_tplg_pcm_cfg_caps capconf[2];    /* capabilities and configs */
+       char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 pcm_id;          /* unique ID - used to match */
+       __le32 dai_id;          /* unique ID - used to match */
+       __le32 playback;        /* supports playback mode */
+       __le32 capture;         /* supports capture mode */
+       __le32 compress;        /* 1 = compressed; 0 = PCM */
+       struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */
+       __le32 num_streams;     /* number of streams */
+       struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */
 } __attribute__((packed));
 
+
+/*
+ * Describes the BE or CC link runtime supported configs or params
+ *
+ * File block representation for BE/CC link config :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_link_config   |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_link_config {
+       __le32 size;            /* in bytes of this structure */
+       __le32 id;              /* unique ID - used to match */
+       struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */
+       __le32 num_streams;     /* number of streams */
+} __attribute__((packed));
 #endif
index a45be6b..a82108e 100644 (file)
@@ -100,9 +100,11 @@ enum {
        SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */
        SNDRV_HWDEP_IFACE_FW_BEBOB,     /* BridgeCo BeBoB based device */
        SNDRV_HWDEP_IFACE_FW_OXFW,      /* Oxford OXFW970/971 based device */
+       SNDRV_HWDEP_IFACE_FW_DIGI00X,   /* Digidesign Digi 002/003 family */
+       SNDRV_HWDEP_IFACE_FW_TASCAM,    /* TASCAM FireWire series */
 
        /* Don't forget to change the following: */
-       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_OXFW
+       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_TASCAM
 };
 
 struct snd_hwdep_info {
index ec1535b..5175e16 100644 (file)
 
 #define EMU10K1_FX8010_PCM_COUNT               8
 
+/*
+ * Following definition is copied from linux/types.h to support compiling
+ * this header file in userspace since they are not generally available for
+ * uapi headers.
+ */
+#define __EMU10K1_DECLARE_BITMAP(name,bits) \
+       unsigned long name[(bits) / (sizeof(unsigned long) * 8)]
+
 /* instruction set */
 #define iMAC0   0x00   /* R = A + (X * Y >> 31)   ; saturation */
 #define iMAC1   0x01   /* R = A + (-X * Y >> 31)  ; saturation */
@@ -300,7 +308,7 @@ struct snd_emu10k1_fx8010_control_old_gpr {
 struct snd_emu10k1_fx8010_code {
        char name[128];
 
-       DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
+       __EMU10K1_DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
        __u32 __user *gpr_map;          /* initializers */
 
        unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */
@@ -313,11 +321,11 @@ struct snd_emu10k1_fx8010_code {
        unsigned int gpr_list_control_total; /* total count of GPR controls */
        struct snd_emu10k1_fx8010_control_gpr __user *gpr_list_controls; /* listed GPR controls */
 
-       DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
+       __EMU10K1_DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
        __u32 __user *tram_data_map;      /* data initializers */
        __u32 __user *tram_addr_map;      /* map initializers */
 
-       DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
+       __EMU10K1_DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
        __u32 __user *code;               /* one instruction - 64 bits */
 };
 
index 49122df..db79a12 100644 (file)
@@ -9,6 +9,7 @@
 #define SNDRV_FIREWIRE_EVENT_LOCK_STATUS       0x000010cc
 #define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e
 #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE      0x4e617475
+#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE   0x746e736c
 
 struct snd_firewire_event_common {
        unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -40,11 +41,17 @@ struct snd_firewire_event_efw_response {
        __be32 response[0];     /* some responses */
 };
 
+struct snd_firewire_event_digi00x_message {
+       unsigned int type;
+       __u32 message;  /* Digi00x-specific message */
+};
+
 union snd_firewire_event {
        struct snd_firewire_event_common            common;
        struct snd_firewire_event_lock_status       lock_status;
        struct snd_firewire_event_dice_notification dice_notification;
        struct snd_firewire_event_efw_response      efw_response;
+       struct snd_firewire_event_digi00x_message   digi00x_message;
 };
 
 
@@ -56,6 +63,8 @@ union snd_firewire_event {
 #define SNDRV_FIREWIRE_TYPE_FIREWORKS  2
 #define SNDRV_FIREWIRE_TYPE_BEBOB      3
 #define SNDRV_FIREWIRE_TYPE_OXFW       4
+#define SNDRV_FIREWIRE_TYPE_DIGI00X    5
+#define SNDRV_FIREWIRE_TYPE_TASCAM     6
 /* RME, MOTU, ... */
 
 struct snd_firewire_get_info {
index 5737332..c4db6f5 100644 (file)
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
 
 /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
 #define HDSPM_MAX_CHANNELS      64
@@ -46,15 +42,15 @@ enum hdspm_speed {
 /* -------------------- IOCTL Peak/RMS Meters -------------------- */
 
 struct hdspm_peak_rms {
-       uint32_t input_peaks[64];
-       uint32_t playback_peaks[64];
-       uint32_t output_peaks[64];
+       __u32 input_peaks[64];
+       __u32 playback_peaks[64];
+       __u32 output_peaks[64];
 
-       uint64_t input_rms[64];
-       uint64_t playback_rms[64];
-       uint64_t output_rms[64];
+       __u64 input_rms[64];
+       __u64 playback_rms[64];
+       __u64 output_rms[64];
 
-       uint8_t speed; /* enum {ss, ds, qs} */
+       __u8 speed; /* enum {ss, ds, qs} */
        int status2;
 };
 
@@ -155,21 +151,21 @@ enum hdspm_syncsource {
 };
 
 struct hdspm_status {
-       uint8_t card_type; /* enum hdspm_io_type */
+       __u8 card_type; /* enum hdspm_io_type */
        enum hdspm_syncsource autosync_source;
 
-       uint64_t card_clock;
-       uint32_t master_period;
+       __u64 card_clock;
+       __u32 master_period;
 
        union {
                struct {
-                       uint8_t sync_wc; /* enum hdspm_sync */
-                       uint8_t sync_madi; /* enum hdspm_sync */
-                       uint8_t sync_tco; /* enum hdspm_sync */
-                       uint8_t sync_in; /* enum hdspm_sync */
-                       uint8_t madi_input; /* enum hdspm_madi_input */
-                       uint8_t channel_format; /* enum hdspm_madi_channel_format */
-                       uint8_t frame_format; /* enum hdspm_madi_frame_format */
+                       __u8 sync_wc; /* enum hdspm_sync */
+                       __u8 sync_madi; /* enum hdspm_sync */
+                       __u8 sync_tco; /* enum hdspm_sync */
+                       __u8 sync_in; /* enum hdspm_sync */
+                       __u8 madi_input; /* enum hdspm_madi_input */
+                       __u8 channel_format; /* enum hdspm_madi_channel_format */
+                       __u8 frame_format; /* enum hdspm_madi_frame_format */
                } madi;
        } card_specific;
 };
@@ -184,7 +180,7 @@ struct hdspm_status {
 #define HDSPM_ADDON_TCO 1
 
 struct hdspm_version {
-       uint8_t card_type; /* enum hdspm_io_type */
+       __u8 card_type; /* enum hdspm_io_type */
        char cardname[20];
        unsigned int serial;
        unsigned short firmware_rev;
index e70fcd1..e1a5110 100644 (file)
@@ -196,5 +196,10 @@ int main(void)
        DEVID_FIELD(ulpi_device_id, vendor);
        DEVID_FIELD(ulpi_device_id, product);
 
+       DEVID(hda_device_id);
+       DEVID_FIELD(hda_device_id, vendor_id);
+       DEVID_FIELD(hda_device_id, rev_id);
+       DEVID_FIELD(hda_device_id, api_version);
+
        return 0;
 }
index 5f20882..fc51d4b 100644 (file)
@@ -1250,6 +1250,23 @@ static int do_ulpi_entry(const char *filename, void *symval,
 }
 ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry);
 
+/* Looks like: hdaudio:vNrNaN */
+static int do_hda_entry(const char *filename, void *symval, char *alias)
+{
+       DEF_FIELD(symval, hda_device_id, vendor_id);
+       DEF_FIELD(symval, hda_device_id, rev_id);
+       DEF_FIELD(symval, hda_device_id, api_version);
+
+       strcpy(alias, "hdaudio:");
+       ADD(alias, "v", vendor_id != 0, vendor_id);
+       ADD(alias, "r", rev_id != 0, rev_id);
+       ADD(alias, "a", api_version != 0, api_version);
+
+       add_wildcard(alias);
+       return 1;
+}
+ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index 38590b3..fbd5dad 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,7 +44,11 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_reset,
 };
 
-static unsigned long pxa2xx_ac97_pcm_out_req = 12;
+static struct pxad_param pxa2xx_ac97_pcm_out_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 12,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -51,7 +56,11 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
        .filter_data    = &pxa2xx_ac97_pcm_out_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_in_req = 11;
+static struct pxad_param pxa2xx_ac97_pcm_in_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 11,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
index 01f8fdc..e9b98af 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -15,8 +16,6 @@
 #include <sound/pxa2xx-lib.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <mach/dma.h>
-
 #include "pxa2xx-pcm.h"
 
 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
@@ -31,7 +30,7 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192 - 32,
        .periods_min            = 1,
-       .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
+       .periods_max            = 256,
        .buffer_bytes_max       = 128 * 1024,
        .fifo_size              = 32,
 };
@@ -39,65 +38,29 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
 int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-       size_t totsize = params_buffer_bytes(params);
-       size_t period = params_period_bytes(params);
-       pxa_dma_desc *dma_desc;
-       dma_addr_t dma_buff_phys, next_desc_phys;
-       u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+       struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_dmaengine_dai_dma_data *dma_params;
+       struct dma_slave_config config;
+       int ret;
 
-       /* temporary transition hack */
-       switch (rtd->params->addr_width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-               dcmd |= DCMD_WIDTH1;
-               break;
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-               dcmd |= DCMD_WIDTH2;
-               break;
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-               dcmd |= DCMD_WIDTH4;
-               break;
-       default:
-               /* can't happen */
-               break;
-       }
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       if (!dma_params)
+               return 0;
 
-       switch (rtd->params->maxburst) {
-       case 8:
-               dcmd |= DCMD_BURST8;
-               break;
-       case 16:
-               dcmd |= DCMD_BURST16;
-               break;
-       case 32:
-               dcmd |= DCMD_BURST32;
-               break;
-       }
+       ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
+       if (ret)
+               return ret;
 
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = totsize;
+       snd_dmaengine_pcm_set_config_from_dai_data(substream,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+                       &config);
 
-       dma_desc = rtd->dma_desc_array;
-       next_desc_phys = rtd->dma_desc_array_phys;
-       dma_buff_phys = runtime->dma_addr;
-       do {
-               next_desc_phys += sizeof(pxa_dma_desc);
-               dma_desc->ddadr = next_desc_phys;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       dma_desc->dsadr = dma_buff_phys;
-                       dma_desc->dtadr = rtd->params->addr;
-               } else {
-                       dma_desc->dsadr = rtd->params->addr;
-                       dma_desc->dtadr = dma_buff_phys;
-               }
-               if (period > totsize)
-                       period = totsize;
-               dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
-               dma_desc++;
-               dma_buff_phys += period;
-       } while (totsize -= period);
-       dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+       ret = dmaengine_slave_config(chan, &config);
+       if (ret)
+               return ret;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
        return 0;
 }
@@ -105,13 +68,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
 
 int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-
-       if (rtd && rtd->params && rtd->params->filter_data) {
-               unsigned long req = *(unsigned long *) rtd->params->filter_data;
-               DRCMR(req) = 0;
-       }
-
        snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
 }
@@ -119,100 +75,36 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
 
 int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) = DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
+       return snd_dmaengine_pcm_trigger(substream, cmd);
 }
 EXPORT_SYMBOL(pxa2xx_pcm_trigger);
 
 snd_pcm_uframes_t
 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-       dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                        DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
-       snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-
-       if (x == runtime->buffer_size)
-               x = 0;
-       return x;
+       return snd_dmaengine_pcm_pointer(substream);
 }
 EXPORT_SYMBOL(pxa2xx_pcm_pointer);
 
 int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       unsigned long req;
-
-       if (!prtd || !prtd->params)
-               return 0;
-
-       if (prtd->dma_ch == -1)
-               return -EINVAL;
-
-       DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-       DCSR(prtd->dma_ch) = 0;
-       DCMD(prtd->dma_ch) = 0;
-       req = *(unsigned long *) prtd->params->filter_data;
-       DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
-
        return 0;
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
 
-void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       int dcsr;
-
-       dcsr = DCSR(dma_ch);
-       DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-       if (dcsr & DCSR_ENDINTR) {
-               snd_pcm_period_elapsed(substream);
-       } else {
-               printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
-                       dma_ch, dcsr);
-               snd_pcm_stop_xrun(substream);
-       }
-}
-EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
-
 int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd;
+       struct snd_dmaengine_dai_dma_data *dma_params;
        int ret;
 
        runtime->hw = pxa2xx_pcm_hardware;
 
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       if (!dma_params)
+               return 0;
+
        /*
         * For mysterious reasons (and despite what the manual says)
         * playback samples are lost if the DMA count is not a multiple
@@ -221,48 +113,27 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
        ret = snd_pcm_hw_constraint_step(runtime, 0,
                SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
        if (ret)
-               goto out;
+               return ret;
 
        ret = snd_pcm_hw_constraint_step(runtime, 0,
                SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
        if (ret)
-               goto out;
+               return ret;
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0)
-               goto out;
-
-       ret = -ENOMEM;
-       rtd = kzalloc(sizeof(*rtd), GFP_KERNEL);
-       if (!rtd)
-               goto out;
-       rtd->dma_desc_array =
-               dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                                      &rtd->dma_desc_array_phys, GFP_KERNEL);
-       if (!rtd->dma_desc_array)
-               goto err1;
+               return ret;
 
-       rtd->dma_ch = -1;
-       runtime->private_data = rtd;
-       return 0;
-
- err1:
-       kfree(rtd);
- out:
-       return ret;
+       return snd_dmaengine_pcm_open_request_chan(substream,
+                                       pxad_filter_fn,
+                                       dma_params->filter_data);
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_open);
 
 int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-
-       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                             rtd->dma_desc_array, rtd->dma_desc_array_phys);
-       kfree(rtd);
-       return 0;
+       return snd_dmaengine_pcm_close_release_chan(substream);
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_close);
 
index 83be8e3..83fcfac 100644 (file)
@@ -46,17 +46,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 
        rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                      client->playback_params : client->capture_params;
-       ret = pxa_request_dma("dma", DMA_PRIO_LOW,
-                             pxa2xx_pcm_dma_irq, substream);
-       if (ret < 0)
-               goto err2;
-       rtd->dma_ch = ret;
 
        ret = client->startup(substream);
        if (!ret)
-               goto out;
+               goto err2;
+
+       return 0;
 
-       pxa_free_dma(rtd->dma_ch);
  err2:
        __pxa2xx_pcm_close(substream);
  out:
@@ -66,9 +62,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_pcm_client *client = substream->private_data;
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-       pxa_free_dma(rtd->dma_ch);
        client->shutdown(substream);
 
        return __pxa2xx_pcm_close(substream);
index 0033098..8fa2b7c 100644 (file)
@@ -13,8 +13,6 @@
 struct pxa2xx_runtime_data {
        int dma_ch;
        struct snd_dmaengine_dai_dma_data *params;
-       struct pxa_dma_desc *dma_desc_array;
-       dma_addr_t dma_desc_array_phys;
 };
 
 struct pxa2xx_pcm_client {
index 6c96fee..e3e9491 100644 (file)
@@ -4,7 +4,7 @@ config SND_TIMER
 
 config SND_PCM
        tristate
-       select SND_TIMER
+       select SND_TIMER if SND_PCM_TIMER
 
 config SND_PCM_ELD
        bool
@@ -93,6 +93,17 @@ config SND_PCM_OSS_PLUGINS
           support conversion of channels, formats and rates. It will
           behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
 
+config SND_PCM_TIMER
+       bool "PCM timer interface" if EXPERT
+       default y
+       help
+         If you disable this option, pcm timer will be inavailable, so
+         those stubs used pcm timer (e.g. dmix, dsnoop & co) may work
+         incorrectlly.
+
+         For some embedded device, we may disable it to reduce memory
+         footprint, about 20KB on x86_64 platform.
+
 config SND_SEQUENCER_OSS
        bool "OSS Sequencer API"
        depends on SND_SEQUENCER
index 3354f91..48ab4b8 100644 (file)
@@ -13,8 +13,9 @@ snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
 snd-$(CONFIG_SND_VMASTER) += vmaster.o
 snd-$(CONFIG_SND_JACK)   += ctljack.o jack.o
 
-snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
+snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_misc.o \
                pcm_memory.o memalloc.o
+snd-pcm-$(CONFIG_SND_PCM_TIMER) += pcm_timer.o
 snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
 snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o
 snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
index a99f720..7a8c79d 100644 (file)
@@ -1177,7 +1177,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
        struct snd_mixer_oss *mixer = entry->private_data;
        char line[128], str[32], idxstr[16];
        const char *cptr;
-       int ch, idx;
+       unsigned int idx;
+       int ch;
        struct snd_mixer_oss_assign_table *tbl;
        struct slot *slot;
 
index 02bd969..308c9ec 100644 (file)
@@ -1014,9 +1014,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        snd_free_pages((void*)runtime->control,
                       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
        kfree(runtime->hw_constraints.rules);
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       kfree(runtime->hwptr_log);
-#endif
        kfree(runtime);
        substream->runtime = NULL;
        put_pid(substream->pid);
index 7d45645..6b5a811 100644 (file)
@@ -801,7 +801,7 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
  * negative error code.
  */
 int snd_interval_ratnum(struct snd_interval *i,
-                       unsigned int rats_count, struct snd_ratnum *rats,
+                       unsigned int rats_count, const struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp)
 {
        unsigned int best_num, best_den;
@@ -920,7 +920,8 @@ EXPORT_SYMBOL(snd_interval_ratnum);
  * negative error code.
  */
 static int snd_interval_ratden(struct snd_interval *i,
-                              unsigned int rats_count, struct snd_ratden *rats,
+                              unsigned int rats_count,
+                              const struct snd_ratden *rats,
                               unsigned int *nump, unsigned int *denp)
 {
        unsigned int best_num, best_diff, best_den;
@@ -1339,7 +1340,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hw_constraint_ratnums *r = rule->private;
+       const struct snd_pcm_hw_constraint_ratnums *r = rule->private;
        unsigned int num = 0, den = 0;
        int err;
        err = snd_interval_ratnum(hw_param_interval(params, rule->var),
@@ -1363,10 +1364,10 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratnums *r)
+                                 const struct snd_pcm_hw_constraint_ratnums *r)
 {
        return snd_pcm_hw_rule_add(runtime, cond, var,
-                                  snd_pcm_hw_rule_ratnums, r,
+                                  snd_pcm_hw_rule_ratnums, (void *)r,
                                   var, -1);
 }
 
@@ -1375,7 +1376,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
 static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hw_constraint_ratdens *r = rule->private;
+       const struct snd_pcm_hw_constraint_ratdens *r = rule->private;
        unsigned int num = 0, den = 0;
        int err = snd_interval_ratden(hw_param_interval(params, rule->var),
                                  r->nrats, r->rats, &num, &den);
@@ -1398,10 +1399,10 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratdens *r)
+                                 const struct snd_pcm_hw_constraint_ratdens *r)
 {
        return snd_pcm_hw_rule_add(runtime, cond, var,
-                                  snd_pcm_hw_rule_ratdens, r,
+                                  snd_pcm_hw_rule_ratdens, (void *)r,
                                   var, -1);
 }
 
@@ -1875,20 +1876,17 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
                return;
        runtime = substream->runtime;
 
-       if (runtime->transfer_ack_begin)
-               runtime->transfer_ack_begin(substream);
-
        snd_pcm_stream_lock_irqsave(substream, flags);
        if (!snd_pcm_running(substream) ||
            snd_pcm_update_hw_ptr0(substream, 1) < 0)
                goto _end;
 
+#ifdef CONFIG_SND_PCM_TIMER
        if (substream->timer_running)
                snd_timer_interrupt(substream->timer, 1);
+#endif
  _end:
        snd_pcm_stream_unlock_irqrestore(substream, flags);
-       if (runtime->transfer_ack_end)
-               runtime->transfer_ack_end(substream);
        kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
 }
 
index 75888dd..a8b27cd 100644 (file)
@@ -486,6 +486,16 @@ static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
        snd_pcm_stream_unlock_irq(substream);
 }
 
+static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
+                                       int event)
+{
+#ifdef CONFIG_SND_PCM_TIMER
+       if (substream->timer)
+               snd_timer_notify(substream->timer, event,
+                                       &substream->runtime->trigger_tstamp);
+#endif
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -650,7 +660,8 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
        }
        snd_pcm_stream_unlock_irq(substream);
 
-       if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
+       if (params->tstamp_mode < 0 ||
+           params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
                return -EINVAL;
        if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
            params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
@@ -1042,9 +1053,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, ULONG_MAX);
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
 }
 
 static struct action_ops snd_pcm_action_start = {
@@ -1092,9 +1101,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
        if (runtime->status->state != state) {
                snd_pcm_trigger_tstamp(substream);
                runtime->status->state = state;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
        }
        wake_up(&runtime->sleep);
        wake_up(&runtime->tsleep);
@@ -1208,18 +1215,12 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
        snd_pcm_trigger_tstamp(substream);
        if (push) {
                runtime->status->state = SNDRV_PCM_STATE_PAUSED;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer,
-                                        SNDRV_TIMER_EVENT_MPAUSE,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE);
                wake_up(&runtime->sleep);
                wake_up(&runtime->tsleep);
        } else {
                runtime->status->state = SNDRV_PCM_STATE_RUNNING;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer,
-                                        SNDRV_TIMER_EVENT_MCONTINUE,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE);
        }
 }
 
@@ -1267,9 +1268,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
        snd_pcm_trigger_tstamp(substream);
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND);
        wake_up(&runtime->sleep);
        wake_up(&runtime->tsleep);
 }
@@ -1373,9 +1372,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        runtime->status->state = runtime->status->suspended_state;
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
 }
 
 static struct action_ops snd_pcm_action_resume = {
@@ -2226,7 +2223,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
 
        snd_pcm_drop(substream);
        if (substream->hw_opened) {
-               if (substream->ops->hw_free != NULL)
+               if (substream->ops->hw_free &&
+                   substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
                        substream->ops->hw_free(substream);
                substream->ops->close(substream);
                substream->hw_opened = 0;
index ccd8935..046cb58 100644 (file)
@@ -91,8 +91,7 @@ snd_seq_oss_readq_clear(struct seq_oss_readq *q)
                q->head = q->tail = 0;
        }
        /* if someone sleeping, wake'em up */
-       if (waitqueue_active(&q->midi_sleep))
-               wake_up(&q->midi_sleep);
+       wake_up(&q->midi_sleep);
        q->input_time = (unsigned long)-1;
 }
 
@@ -138,8 +137,7 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
        q->qlen++;
 
        /* wake up sleeper */
-       if (waitqueue_active(&q->midi_sleep))
-               wake_up(&q->midi_sleep);
+       wake_up(&q->midi_sleep);
 
        spin_unlock_irqrestore(&q->lock, flags);
 
index d50338b..1f6788a 100644 (file)
@@ -138,9 +138,7 @@ snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
        spin_lock_irqsave(&q->sync_lock, flags);
        q->sync_time = time;
        q->sync_event_put = 0;
-       if (waitqueue_active(&q->sync_sleep)) {
-               wake_up(&q->sync_sleep);
-       }
+       wake_up(&q->sync_sleep);
        spin_unlock_irqrestore(&q->sync_lock, flags);
 }
 
index 8850b7d..bee0e5f 100644 (file)
@@ -120,4 +120,31 @@ config SND_BEBOB
           To compile this driver as a module, choose M here: the module
           will be called snd-bebob.
 
+config SND_FIREWIRE_DIGI00X
+       tristate "Digidesign Digi 002/003 family support"
+       select SND_FIREWIRE_LIB
+       select SND_HWDEP
+       help
+        Say Y here to include support for Digidesign Digi 002/003 family.
+         * Digi 002 Console
+         * Digi 002 Rack
+         * Digi 003 Console
+         * Digi 003 Rack
+         * Digi 003 Rack+
+
+        To compile this driver as a module, choose M here: the module
+        will be called snd-firewire-digi00x.
+
+config SND_FIREWIRE_TASCAM
+       tristate "TASCAM FireWire series support"
+       select SND_FIREWIRE_LIB
+       select SND_HWDEP
+       help
+        Say Y here to include support for TASCAM.
+         * FW-1884
+         * FW-1082
+
+        To compile this driver as a module, choose M here: the module
+        will be called snd-firewire-tascam.
+
 endif # SND_FIREWIRE
index 8b37f08..f5fb625 100644 (file)
@@ -1,6 +1,5 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
-                        fcp.o cmp.o amdtp.o
-snd-oxfw-objs := oxfw.o
+                        fcp.o cmp.o amdtp-stream.o amdtp-am824.o
 snd-isight-objs := isight.o
 snd-scs1x-objs := scs1x.o
 
@@ -11,3 +10,5 @@ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
 obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
 obj-$(CONFIG_SND_FIREWORKS) += fireworks/
 obj-$(CONFIG_SND_BEBOB) += bebob/
+obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/
+obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c
new file mode 100644 (file)
index 0000000..bebddc6
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/slab.h>
+
+#include "amdtp-am824.h"
+
+#define CIP_FMT_AM             0x10
+
+/* "Clock-based rate control mode" is just supported. */
+#define AMDTP_FDF_AM824                0x00
+
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND  3093
+
+/*
+ * Several devices look only at the first eight data blocks.
+ * In any case, this is more than enough for the MIDI data rate.
+ */
+#define MAX_MIDI_RX_BLOCKS     8
+
+struct amdtp_am824 {
+       struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8];
+       int midi_fifo_limit;
+       int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8];
+       unsigned int pcm_channels;
+       unsigned int midi_ports;
+
+       u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM];
+       u8 midi_position;
+
+       void (*transfer_samples)(struct amdtp_stream *s,
+                                struct snd_pcm_substream *pcm,
+                                __be32 *buffer, unsigned int frames);
+
+       unsigned int frame_multiplier;
+};
+
+/**
+ * amdtp_am824_set_parameters - set stream parameters
+ * @s: the AMDTP stream to configure
+ * @rate: the sample rate
+ * @pcm_channels: the number of PCM samples in each data block, to be encoded
+ *                as AM824 multi-bit linear audio
+ * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
+ * @double_pcm_frames: one data block transfers two PCM frames
+ *
+ * The parameters must be set before the stream is started, and must not be
+ * changed while the stream is running.
+ */
+int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                              unsigned int pcm_channels,
+                              unsigned int midi_ports,
+                              bool double_pcm_frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int midi_channels;
+       unsigned int i;
+       int err;
+
+       if (amdtp_stream_running(s))
+               return -EINVAL;
+
+       if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM)
+               return -EINVAL;
+
+       midi_channels = DIV_ROUND_UP(midi_ports, 8);
+       if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)
+               return -EINVAL;
+
+       if (WARN_ON(amdtp_stream_running(s)) ||
+           WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) ||
+           WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI))
+               return -EINVAL;
+
+       err = amdtp_stream_set_parameters(s, rate,
+                                         pcm_channels + midi_channels);
+       if (err < 0)
+               return err;
+
+       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+
+       p->pcm_channels = pcm_channels;
+       p->midi_ports = midi_ports;
+
+       /*
+        * In IEC 61883-6, one data block represents one event. In ALSA, one
+        * event equals to one PCM frame. But Dice has a quirk at higher
+        * sampling rate to transfer two PCM frames in one data block.
+        */
+       if (double_pcm_frames)
+               p->frame_multiplier = 2;
+       else
+               p->frame_multiplier = 1;
+
+       /* init the position map for PCM and MIDI channels */
+       for (i = 0; i < pcm_channels; i++)
+               p->pcm_positions[i] = i;
+       p->midi_position = p->pcm_channels;
+
+       /*
+        * We do not know the actual MIDI FIFO size of most devices.  Just
+        * assume two bytes, i.e., one byte can be received over the bus while
+        * the previous one is transmitted over MIDI.
+        * (The value here is adjusted for midi_ratelimit_per_packet().)
+        */
+       p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
+
+/**
+ * amdtp_am824_set_pcm_position - set an index of data channel for a channel
+ *                               of PCM frame
+ * @s: the AMDTP stream
+ * @index: the index of data channel in an data block
+ * @position: the channel of PCM frame
+ */
+void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
+                                unsigned int position)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (index < p->pcm_channels)
+               p->pcm_positions[index] = position;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position);
+
+/**
+ * amdtp_am824_set_midi_position - set a index of data channel for MIDI
+ *                                conformant data channel
+ * @s: the AMDTP stream
+ * @position: the index of data channel in an data block
+ */
+void amdtp_am824_set_midi_position(struct amdtp_stream *s,
+                                  unsigned int position)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       p->midi_position = position;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position);
+
+static void write_pcm_s32(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u32 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[p->pcm_positions[c]] =
+                                       cpu_to_be32((*src >> 8) | 0x40000000);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_s16(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u16 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[p->pcm_positions[c]] =
+                                       cpu_to_be32((*src << 8) | 0x42000000);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void read_pcm_s32(struct amdtp_stream *s,
+                        struct snd_pcm_substream *pcm,
+                        __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       u32 *dst;
+
+       channels = p->pcm_channels;
+       dst  = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8;
+                       dst++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       dst = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s,
+                             __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int i, c, channels = p->pcm_channels;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c)
+                       buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000);
+               buffer += s->data_block_quadlets;
+       }
+}
+
+/**
+ * amdtp_am824_set_pcm_format - set the PCM format
+ * @s: the AMDTP stream to configure
+ * @format: the format of the ALSA PCM device
+ *
+ * The sample format must be set after the other parameters (rate/PCM channels/
+ * MIDI) and before the stream is started, and must not be changed while the
+ * stream is running.
+ */
+void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (WARN_ON(amdtp_stream_pcm_running(s)))
+               return;
+
+       switch (format) {
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S16:
+               if (s->direction == AMDTP_OUT_STREAM) {
+                       p->transfer_samples = write_pcm_s16;
+                       break;
+               }
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32:
+               if (s->direction == AMDTP_OUT_STREAM)
+                       p->transfer_samples = write_pcm_s32;
+               else
+                       p->transfer_samples = read_pcm_s32;
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format);
+
+/**
+ * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream
+ * @s:         the AMDTP stream for AM824 data block, must be initialized.
+ * @runtime:   the PCM substream runtime
+ *
+ */
+int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                      struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
+       if (err < 0)
+               return err;
+
+       /* AM824 in IEC 61883-6 can deliver 24bit data. */
+       return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints);
+
+/**
+ * amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device
+ * @s: the AMDTP stream
+ * @port: index of MIDI port
+ * @midi: the MIDI device to be started, or %NULL to stop the current device
+ *
+ * Call this function on a running isochronous stream to enable the actual
+ * transmission of MIDI data.  This function should be called from the MIDI
+ * device's .trigger callback.
+ */
+void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                             struct snd_rawmidi_substream *midi)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (port < p->midi_ports)
+               ACCESS_ONCE(p->midi[port]) = midi;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
+
+/*
+ * To avoid sending MIDI bytes at too high a rate, assume that the receiving
+ * device has a FIFO, and track how much it is filled.  This values increases
+ * by one whenever we send one byte in a packet, but the FIFO empties at
+ * a constant rate independent of our packet rate.  One packet has syt_interval
+ * samples, so the number of bytes that empty out of the FIFO, per packet(!),
+ * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
+ * fractional values, the values in midi_fifo_used[] are measured in bytes
+ * multiplied by the sample rate.
+ */
+static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_am824 *p = s->protocol;
+       int used;
+
+       used = p->midi_fifo_used[port];
+       if (used == 0) /* common shortcut */
+               return true;
+
+       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
+       used = max(used, 0);
+       p->midi_fifo_used[port] = used;
+
+       return used < p->midi_fifo_limit;
+}
+
+static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       p->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
+}
+
+static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                               unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int f, port;
+       u8 *b;
+
+       for (f = 0; f < frames; f++) {
+               b = (u8 *)&buffer[p->midi_position];
+
+               port = (s->data_block_counter + f) % 8;
+               if (f < MAX_MIDI_RX_BLOCKS &&
+                   midi_ratelimit_per_packet(s, port) &&
+                   p->midi[port] != NULL &&
+                   snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) {
+                       midi_rate_use_one_byte(s, port);
+                       b[0] = 0x81;
+               } else {
+                       b[0] = 0x80;
+                       b[1] = 0;
+               }
+               b[2] = 0;
+               b[3] = 0;
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static void read_midi_messages(struct amdtp_stream *s,
+                              __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int f, port;
+       int len;
+       u8 *b;
+
+       for (f = 0; f < frames; f++) {
+               port = (s->data_block_counter + f) % 8;
+               b = (u8 *)&buffer[p->midi_position];
+
+               len = b[0] - 0x80;
+               if ((1 <= len) &&  (len <= 3) && (p->midi[port]))
+                       snd_rawmidi_receive(p->midi[port], b + 1, len);
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
+                                          unsigned int data_blocks, unsigned int *syt)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       unsigned int pcm_frames;
+
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks * p->frame_multiplier;
+       } else {
+               write_pcm_silence(s, buffer, data_blocks);
+               pcm_frames = 0;
+       }
+
+       if (p->midi_ports)
+               write_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
+                                          unsigned int data_blocks, unsigned int *syt)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       unsigned int pcm_frames;
+
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks * p->frame_multiplier;
+       } else {
+               pcm_frames = 0;
+       }
+
+       if (p->midi_ports)
+               read_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+/**
+ * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824
+ *                   data block
+ * @s: the AMDTP stream to initialize
+ * @unit: the target of the stream
+ * @dir: the direction of stream
+ * @flags: the packet transmission method to use
+ */
+int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
+                    enum amdtp_stream_direction dir, enum cip_flags flags)
+{
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+
+       if (dir == AMDTP_IN_STREAM)
+               process_data_blocks = process_tx_data_blocks;
+       else
+               process_data_blocks = process_rx_data_blocks;
+
+       return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
+                                process_data_blocks,
+                                sizeof(struct amdtp_am824));
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_init);
diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h
new file mode 100644 (file)
index 0000000..73b07b3
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
+#define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
+
+#include <sound/pcm.h>
+#include <sound/rawmidi.h>
+
+#include "amdtp-stream.h"
+
+#define AM824_IN_PCM_FORMAT_BITS       SNDRV_PCM_FMTBIT_S32
+
+#define AM824_OUT_PCM_FORMAT_BITS      (SNDRV_PCM_FMTBIT_S16 | \
+                                        SNDRV_PCM_FMTBIT_S32)
+
+/*
+ * This module supports maximum 64 PCM channels for one PCM stream
+ * This is for our convenience.
+ */
+#define AM824_MAX_CHANNELS_FOR_PCM     64
+
+/*
+ * AMDTP packet can include channels for MIDI conformant data.
+ * Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
+ * Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
+ *
+ * This module supports maximum 1 MIDI conformant data channels.
+ * Then this AMDTP packets can transfer maximum 8 MIDI data streams.
+ */
+#define AM824_MAX_CHANNELS_FOR_MIDI    1
+
+int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                              unsigned int pcm_channels,
+                              unsigned int midi_ports,
+                              bool double_pcm_frames);
+
+void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
+                                unsigned int position);
+
+void amdtp_am824_set_midi_position(struct amdtp_stream *s,
+                                  unsigned int position);
+
+int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                      struct snd_pcm_runtime *runtime);
+
+void amdtp_am824_set_pcm_format(struct amdtp_stream *s,
+                               snd_pcm_format_t format);
+
+void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                             struct snd_rawmidi_substream *midi);
+
+int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
+                    enum amdtp_stream_direction dir, enum cip_flags flags);
+#endif
similarity index 70%
rename from sound/firewire/amdtp.c
rename to sound/firewire/amdtp-stream.c
index 2a153d2..ed29026 100644 (file)
 #include <linux/firewire.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/rawmidi.h>
-#include "amdtp.h"
+#include "amdtp-stream.h"
 
 #define TICKS_PER_CYCLE                3072
 #define CYCLES_PER_SECOND      8000
 #define TICKS_PER_SECOND       (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
 
-/*
- * Nominally 3125 bytes/second, but the MIDI port's clock might be
- * 1% too slow, and the bus clock 100 ppm too fast.
- */
-#define MIDI_BYTES_PER_SECOND  3093
-
-/*
- * Several devices look only at the first eight data blocks.
- * In any case, this is more than enough for the MIDI data rate.
- */
-#define MAX_MIDI_RX_BLOCKS     8
-
 #define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
 
 /* isochronous header parameters */
 #define CIP_SYT_MASK           0x0000ffff
 #define CIP_SYT_NO_INFO                0xffff
 
-/*
- * Audio and Music transfer protocol specific parameters
- * only "Clock-based rate control mode" is supported
- */
-#define CIP_FMT_AM             (0x10 << CIP_FMT_SHIFT)
-#define AMDTP_FDF_AM824                (0 << (CIP_FDF_SHIFT + 3))
+/* Audio and Music transfer protocol specific parameters */
+#define CIP_FMT_AM             0x10
 #define AMDTP_FDF_NO_DATA      0xff
 
 /* TODO: make these configurable */
@@ -78,10 +60,23 @@ static void pcm_period_tasklet(unsigned long data);
  * @unit: the target of the stream
  * @dir: the direction of stream
  * @flags: the packet transmission method to use
+ * @fmt: the value of fmt field in CIP header
+ * @process_data_blocks: callback handler to process data blocks
+ * @protocol_size: the size to allocate newly for protocol
  */
 int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
-                     enum amdtp_stream_direction dir, enum cip_flags flags)
+                     enum amdtp_stream_direction dir, enum cip_flags flags,
+                     unsigned int fmt,
+                     amdtp_stream_process_data_blocks_t process_data_blocks,
+                     unsigned int protocol_size)
 {
+       if (process_data_blocks == NULL)
+               return -EINVAL;
+
+       s->protocol = kzalloc(protocol_size, GFP_KERNEL);
+       if (!s->protocol)
+               return -ENOMEM;
+
        s->unit = unit;
        s->direction = dir;
        s->flags = flags;
@@ -94,6 +89,9 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
        s->callbacked = false;
        s->sync_slave = NULL;
 
+       s->fmt = fmt;
+       s->process_data_blocks = process_data_blocks;
+
        return 0;
 }
 EXPORT_SYMBOL(amdtp_stream_init);
@@ -105,6 +103,7 @@ EXPORT_SYMBOL(amdtp_stream_init);
 void amdtp_stream_destroy(struct amdtp_stream *s)
 {
        WARN_ON(amdtp_stream_running(s));
+       kfree(s->protocol);
        mutex_destroy(&s->mutex);
 }
 EXPORT_SYMBOL(amdtp_stream_destroy);
@@ -141,11 +140,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 {
        int err;
 
-       /* AM824 in IEC 61883-6 can deliver 24bit data */
-       err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
-       if (err < 0)
-               goto end;
-
        /*
         * Currently firewire-lib processes 16 packets in one software
         * interrupt callback. This equals to 2msec but actually the
@@ -190,39 +184,25 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints);
  * amdtp_stream_set_parameters - set stream parameters
  * @s: the AMDTP stream to configure
  * @rate: the sample rate
- * @pcm_channels: the number of PCM samples in each data block, to be encoded
- *                as AM824 multi-bit linear audio
- * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
+ * @data_block_quadlets: the size of a data block in quadlet unit
  *
  * The parameters must be set before the stream is started, and must not be
  * changed while the stream is running.
  */
-void amdtp_stream_set_parameters(struct amdtp_stream *s,
-                                unsigned int rate,
-                                unsigned int pcm_channels,
-                                unsigned int midi_ports)
+int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                               unsigned int data_block_quadlets)
 {
-       unsigned int i, sfc, midi_channels;
+       unsigned int sfc;
 
-       midi_channels = DIV_ROUND_UP(midi_ports, 8);
-
-       if (WARN_ON(amdtp_stream_running(s)) |
-           WARN_ON(pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM) |
-           WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI))
-               return;
-
-       for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc)
+       for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) {
                if (amdtp_rate_table[sfc] == rate)
-                       goto sfc_found;
-       WARN_ON(1);
-       return;
+                       break;
+       }
+       if (sfc == ARRAY_SIZE(amdtp_rate_table))
+               return -EINVAL;
 
-sfc_found:
-       s->pcm_channels = pcm_channels;
        s->sfc = sfc;
-       s->data_block_quadlets = s->pcm_channels + midi_channels;
-       s->midi_ports = midi_ports;
-
+       s->data_block_quadlets = data_block_quadlets;
        s->syt_interval = amdtp_syt_intervals[sfc];
 
        /* default buffering in the device */
@@ -231,18 +211,7 @@ sfc_found:
                /* additional buffering needed to adjust for no-data packets */
                s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
 
-       /* init the position map for PCM and MIDI channels */
-       for (i = 0; i < pcm_channels; i++)
-               s->pcm_positions[i] = i;
-       s->midi_position = s->pcm_channels;
-
-       /*
-        * We do not know the actual MIDI FIFO size of most devices.  Just
-        * assume two bytes, i.e., one byte can be received over the bus while
-        * the previous one is transmitted over MIDI.
-        * (The value here is adjusted for midi_ratelimit_per_packet().)
-        */
-       s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
+       return 0;
 }
 EXPORT_SYMBOL(amdtp_stream_set_parameters);
 
@@ -264,52 +233,6 @@ unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
 }
 EXPORT_SYMBOL(amdtp_stream_get_max_payload);
 
-static void write_pcm_s16(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames);
-static void write_pcm_s32(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames);
-static void read_pcm_s32(struct amdtp_stream *s,
-                        struct snd_pcm_substream *pcm,
-                        __be32 *buffer, unsigned int frames);
-
-/**
- * amdtp_stream_set_pcm_format - set the PCM format
- * @s: the AMDTP stream to configure
- * @format: the format of the ALSA PCM device
- *
- * The sample format must be set after the other parameters (rate/PCM channels/
- * MIDI) and before the stream is started, and must not be changed while the
- * stream is running.
- */
-void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
-                                snd_pcm_format_t format)
-{
-       if (WARN_ON(amdtp_stream_pcm_running(s)))
-               return;
-
-       switch (format) {
-       default:
-               WARN_ON(1);
-               /* fall through */
-       case SNDRV_PCM_FORMAT_S16:
-               if (s->direction == AMDTP_OUT_STREAM) {
-                       s->transfer_samples = write_pcm_s16;
-                       break;
-               }
-               WARN_ON(1);
-               /* fall through */
-       case SNDRV_PCM_FORMAT_S32:
-               if (s->direction == AMDTP_OUT_STREAM)
-                       s->transfer_samples = write_pcm_s32;
-               else
-                       s->transfer_samples = read_pcm_s32;
-               break;
-       }
-}
-EXPORT_SYMBOL(amdtp_stream_set_pcm_format);
-
 /**
  * amdtp_stream_pcm_prepare - prepare PCM device for running
  * @s: the AMDTP stream
@@ -412,182 +335,12 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
        }
 }
 
-static void write_pcm_s32(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       const u32 *src;
-
-       channels = s->pcm_channels;
-       src = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       buffer[s->pcm_positions[c]] =
-                                       cpu_to_be32((*src >> 8) | 0x40000000);
-                       src++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       src = (void *)runtime->dma_area;
-       }
-}
-
-static void write_pcm_s16(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       const u16 *src;
-
-       channels = s->pcm_channels;
-       src = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       buffer[s->pcm_positions[c]] =
-                                       cpu_to_be32((*src << 8) | 0x42000000);
-                       src++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       src = (void *)runtime->dma_area;
-       }
-}
-
-static void read_pcm_s32(struct amdtp_stream *s,
-                        struct snd_pcm_substream *pcm,
-                        __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       u32 *dst;
-
-       channels = s->pcm_channels;
-       dst  = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       *dst = be32_to_cpu(buffer[s->pcm_positions[c]]) << 8;
-                       dst++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       dst = (void *)runtime->dma_area;
-       }
-}
-
-static void write_pcm_silence(struct amdtp_stream *s,
-                             __be32 *buffer, unsigned int frames)
-{
-       unsigned int i, c;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < s->pcm_channels; ++c)
-                       buffer[s->pcm_positions[c]] = cpu_to_be32(0x40000000);
-               buffer += s->data_block_quadlets;
-       }
-}
-
-/*
- * To avoid sending MIDI bytes at too high a rate, assume that the receiving
- * device has a FIFO, and track how much it is filled.  This values increases
- * by one whenever we send one byte in a packet, but the FIFO empties at
- * a constant rate independent of our packet rate.  One packet has syt_interval
- * samples, so the number of bytes that empty out of the FIFO, per packet(!),
- * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
- * fractional values, the values in midi_fifo_used[] are measured in bytes
- * multiplied by the sample rate.
- */
-static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
-{
-       int used;
-
-       used = s->midi_fifo_used[port];
-       if (used == 0) /* common shortcut */
-               return true;
-
-       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
-       used = max(used, 0);
-       s->midi_fifo_used[port] = used;
-
-       return used < s->midi_fifo_limit;
-}
-
-static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
-{
-       s->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
-}
-
-static void write_midi_messages(struct amdtp_stream *s,
-                               __be32 *buffer, unsigned int frames)
-{
-       unsigned int f, port;
-       u8 *b;
-
-       for (f = 0; f < frames; f++) {
-               b = (u8 *)&buffer[s->midi_position];
-
-               port = (s->data_block_counter + f) % 8;
-               if (f < MAX_MIDI_RX_BLOCKS &&
-                   midi_ratelimit_per_packet(s, port) &&
-                   s->midi[port] != NULL &&
-                   snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) {
-                       midi_rate_use_one_byte(s, port);
-                       b[0] = 0x81;
-               } else {
-                       b[0] = 0x80;
-                       b[1] = 0;
-               }
-               b[2] = 0;
-               b[3] = 0;
-
-               buffer += s->data_block_quadlets;
-       }
-}
-
-static void read_midi_messages(struct amdtp_stream *s,
-                              __be32 *buffer, unsigned int frames)
-{
-       unsigned int f, port;
-       int len;
-       u8 *b;
-
-       for (f = 0; f < frames; f++) {
-               port = (s->data_block_counter + f) % 8;
-               b = (u8 *)&buffer[s->midi_position];
-
-               len = b[0] - 0x80;
-               if ((1 <= len) &&  (len <= 3) && (s->midi[port]))
-                       snd_rawmidi_receive(s->midi[port], b + 1, len);
-
-               buffer += s->data_block_quadlets;
-       }
-}
-
 static void update_pcm_pointers(struct amdtp_stream *s,
                                struct snd_pcm_substream *pcm,
                                unsigned int frames)
 {
        unsigned int ptr;
 
-       /*
-        * In IEC 61883-6, one data block represents one event. In ALSA, one
-        * event equals to one PCM frame. But Dice has a quirk to transfer
-        * two PCM frames in one data block.
-        */
-       if (s->double_pcm_frames)
-               frames *= 2;
-
        ptr = s->pcm_buffer_pointer + frames;
        if (ptr >= pcm->runtime->buffer_size)
                ptr -= pcm->runtime->buffer_size;
@@ -656,23 +409,19 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
 {
        __be32 *buffer;
        unsigned int payload_length;
+       unsigned int pcm_frames;
        struct snd_pcm_substream *pcm;
 
        buffer = s->buffer.packets[s->packet_index].buffer;
+       pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
+
        buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
                                (s->data_block_quadlets << CIP_DBS_SHIFT) |
                                s->data_block_counter);
-       buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 |
-                               (s->sfc << CIP_FDF_SHIFT) | syt);
-       buffer += 2;
-
-       pcm = ACCESS_ONCE(s->pcm);
-       if (pcm)
-               s->transfer_samples(s, pcm, buffer, data_blocks);
-       else
-               write_pcm_silence(s, buffer, data_blocks);
-       if (s->midi_ports)
-               write_midi_messages(s, buffer, data_blocks);
+       buffer[1] = cpu_to_be32(CIP_EOH |
+                               ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
+                               ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
+                               (syt & CIP_SYT_MASK));
 
        s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
 
@@ -680,8 +429,9 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
        if (queue_out_packet(s, payload_length, false) < 0)
                return -EIO;
 
-       if (pcm)
-               update_pcm_pointers(s, pcm, data_blocks);
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm && pcm_frames > 0)
+               update_pcm_pointers(s, pcm, pcm_frames);
 
        /* No need to return the number of handled data blocks. */
        return 0;
@@ -689,11 +439,13 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
 
 static int handle_in_packet(struct amdtp_stream *s,
                            unsigned int payload_quadlets, __be32 *buffer,
-                           unsigned int *data_blocks)
+                           unsigned int *data_blocks, unsigned int syt)
 {
        u32 cip_header[2];
+       unsigned int fmt, fdf;
        unsigned int data_block_quadlets, data_block_counter, dbc_interval;
-       struct snd_pcm_substream *pcm = NULL;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
        bool lost;
 
        cip_header[0] = be32_to_cpu(buffer[0]);
@@ -704,19 +456,30 @@ static int handle_in_packet(struct amdtp_stream *s,
         * For convenience, also check FMT field is AM824 or not.
         */
        if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
-           ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH) ||
-           ((cip_header[1] & CIP_FMT_MASK) != CIP_FMT_AM)) {
+           ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) {
                dev_info_ratelimited(&s->unit->device,
                                "Invalid CIP header for AMDTP: %08X:%08X\n",
                                cip_header[0], cip_header[1]);
                *data_blocks = 0;
+               pcm_frames = 0;
+               goto end;
+       }
+
+       /* Check valid protocol or not. */
+       fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT;
+       if (fmt != s->fmt) {
+               dev_info_ratelimited(&s->unit->device,
+                                    "Detect unexpected protocol: %08x %08x\n",
+                                    cip_header[0], cip_header[1]);
+               *data_blocks = 0;
+               pcm_frames = 0;
                goto end;
        }
 
        /* Calculate data blocks */
+       fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT;
        if (payload_quadlets < 3 ||
-           ((cip_header[1] & CIP_FDF_MASK) ==
-                               (AMDTP_FDF_NO_DATA << CIP_FDF_SHIFT))) {
+           (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) {
                *data_blocks = 0;
        } else {
                data_block_quadlets =
@@ -763,16 +526,7 @@ static int handle_in_packet(struct amdtp_stream *s,
                return -EIO;
        }
 
-       if (*data_blocks > 0) {
-               buffer += 2;
-
-               pcm = ACCESS_ONCE(s->pcm);
-               if (pcm)
-                       s->transfer_samples(s, pcm, buffer, *data_blocks);
-
-               if (s->midi_ports)
-                       read_midi_messages(s, buffer, *data_blocks);
-       }
+       pcm_frames = s->process_data_blocks(s, buffer + 2, *data_blocks, &syt);
 
        if (s->flags & CIP_DBC_IS_END_EVENT)
                s->data_block_counter = data_block_counter;
@@ -783,8 +537,9 @@ end:
        if (queue_in_packet(s) < 0)
                return -EIO;
 
-       if (pcm)
-               update_pcm_pointers(s, pcm, *data_blocks);
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm && pcm_frames > 0)
+               update_pcm_pointers(s, pcm, pcm_frames);
 
        return 0;
 }
@@ -854,15 +609,15 @@ static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
                        break;
                }
 
+               syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
                if (handle_in_packet(s, payload_quadlets, buffer,
-                                                       &data_blocks) < 0) {
+                                               &data_blocks, syt) < 0) {
                        s->packet_index = -1;
                        break;
                }
 
                /* Process sync slave stream */
                if (s->sync_slave && s->sync_slave->callbacked) {
-                       syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
                        if (handle_out_packet(s->sync_slave,
                                              data_blocks, syt) < 0) {
                                s->packet_index = -1;
similarity index 78%
rename from sound/firewire/amdtp.h
rename to sound/firewire/amdtp-stream.h
index b2cf9e7..8775704 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
 #include <sound/asound.h>
 #include "packets-buffer.h"
 
@@ -80,100 +81,78 @@ enum cip_sfc {
        CIP_SFC_COUNT
 };
 
-#define AMDTP_IN_PCM_FORMAT_BITS       SNDRV_PCM_FMTBIT_S32
-
-#define AMDTP_OUT_PCM_FORMAT_BITS      (SNDRV_PCM_FMTBIT_S16 | \
-                                        SNDRV_PCM_FMTBIT_S32)
-
-
-/*
- * This module supports maximum 64 PCM channels for one PCM stream
- * This is for our convenience.
- */
-#define AMDTP_MAX_CHANNELS_FOR_PCM     64
-
-/*
- * AMDTP packet can include channels for MIDI conformant data.
- * Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
- * Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
- *
- * This module supports maximum 1 MIDI conformant data channels.
- * Then this AMDTP packets can transfer maximum 8 MIDI data streams.
- */
-#define AMDTP_MAX_CHANNELS_FOR_MIDI    1
-
 struct fw_unit;
 struct fw_iso_context;
 struct snd_pcm_substream;
 struct snd_pcm_runtime;
-struct snd_rawmidi_substream;
 
 enum amdtp_stream_direction {
        AMDTP_OUT_STREAM = 0,
        AMDTP_IN_STREAM
 };
 
+struct amdtp_stream;
+typedef unsigned int (*amdtp_stream_process_data_blocks_t)(
+                                               struct amdtp_stream *s,
+                                               __be32 *buffer,
+                                               unsigned int data_blocks,
+                                               unsigned int *syt);
 struct amdtp_stream {
        struct fw_unit *unit;
        enum cip_flags flags;
        enum amdtp_stream_direction direction;
-       struct fw_iso_context *context;
        struct mutex mutex;
 
-       enum cip_sfc sfc;
-       unsigned int data_block_quadlets;
-       unsigned int pcm_channels;
-       unsigned int midi_ports;
-       void (*transfer_samples)(struct amdtp_stream *s,
-                                struct snd_pcm_substream *pcm,
-                                __be32 *buffer, unsigned int frames);
-       u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM];
-       u8 midi_position;
-
-       unsigned int syt_interval;
-       unsigned int transfer_delay;
-       unsigned int source_node_id_field;
+       /* For packet processing. */
+       struct fw_iso_context *context;
        struct iso_packets_buffer buffer;
-
-       struct snd_pcm_substream *pcm;
-       struct tasklet_struct period_tasklet;
-
        int packet_index;
+
+       /* For CIP headers. */
+       unsigned int source_node_id_field;
+       unsigned int data_block_quadlets;
        unsigned int data_block_counter;
+       unsigned int fmt;
+       unsigned int fdf;
+       /* quirk: fixed interval of dbc between previos/current packets. */
+       unsigned int tx_dbc_interval;
+       /* quirk: indicate the value of dbc field in a first packet. */
+       unsigned int tx_first_dbc;
 
+       /* Internal flags. */
+       enum cip_sfc sfc;
+       unsigned int syt_interval;
+       unsigned int transfer_delay;
        unsigned int data_block_state;
-
        unsigned int last_syt_offset;
        unsigned int syt_offset_state;
 
+       /* For a PCM substream processing. */
+       struct snd_pcm_substream *pcm;
+       struct tasklet_struct period_tasklet;
        unsigned int pcm_buffer_pointer;
        unsigned int pcm_period_pointer;
        bool pointer_flush;
-       bool double_pcm_frames;
-
-       struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
-       int midi_fifo_limit;
-       int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
-
-       /* quirk: fixed interval of dbc between previos/current packets. */
-       unsigned int tx_dbc_interval;
-       /* quirk: indicate the value of dbc field in a first packet. */
-       unsigned int tx_first_dbc;
 
+       /* To wait for first packet. */
        bool callbacked;
        wait_queue_head_t callback_wait;
        struct amdtp_stream *sync_slave;
+
+       /* For backends to process data blocks. */
+       void *protocol;
+       amdtp_stream_process_data_blocks_t process_data_blocks;
 };
 
 int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
-                     enum amdtp_stream_direction dir,
-                     enum cip_flags flags);
+                     enum amdtp_stream_direction dir, enum cip_flags flags,
+                     unsigned int fmt,
+                     amdtp_stream_process_data_blocks_t process_data_blocks,
+                     unsigned int protocol_size);
 void amdtp_stream_destroy(struct amdtp_stream *s);
 
-void amdtp_stream_set_parameters(struct amdtp_stream *s,
-                                unsigned int rate,
-                                unsigned int pcm_channels,
-                                unsigned int midi_ports);
+int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                               unsigned int data_block_quadlets);
 unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
 
 int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed);
@@ -182,8 +161,7 @@ void amdtp_stream_stop(struct amdtp_stream *s);
 
 int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
                                        struct snd_pcm_runtime *runtime);
-void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
-                                snd_pcm_format_t format);
+
 void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
 unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
 void amdtp_stream_pcm_abort(struct amdtp_stream *s);
@@ -240,24 +218,6 @@ static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s,
        ACCESS_ONCE(s->pcm) = pcm;
 }
 
-/**
- * amdtp_stream_midi_trigger - start/stop playback/capture with a MIDI device
- * @s: the AMDTP stream
- * @port: index of MIDI port
- * @midi: the MIDI device to be started, or %NULL to stop the current device
- *
- * Call this function on a running isochronous stream to enable the actual
- * transmission of MIDI data.  This function should be called from the MIDI
- * device's .trigger callback.
- */
-static inline void amdtp_stream_midi_trigger(struct amdtp_stream *s,
-                                            unsigned int port,
-                                            struct snd_rawmidi_substream *midi)
-{
-       if (port < s->midi_ports)
-               ACCESS_ONCE(s->midi[port]) = midi;
-}
-
 static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
 {
        return sfc & 1;
index 6cf470c..af7ed66 100644 (file)
@@ -1,4 +1,4 @@
 snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
                  bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \
                  bebob_focusrite.o bebob_maudio.o bebob.o
-obj-m += snd-bebob.o
+obj-$(CONFIG_SND_BEBOB) += snd-bebob.o
index 27a04ac..091290d 100644 (file)
@@ -41,7 +41,8 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
 #define VEN_EDIROL     0x000040ab
 #define VEN_PRESONUS   0x00000a92
 #define VEN_BRIDGECO   0x000007f5
-#define VEN_MACKIE     0x0000000f
+#define VEN_MACKIE1    0x0000000f
+#define VEN_MACKIE2    0x00000ff2
 #define VEN_STANTON    0x00001260
 #define VEN_TASCAM     0x0000022e
 #define VEN_BEHRINGER  0x00001564
@@ -334,7 +335,7 @@ static void bebob_remove(struct fw_unit *unit)
        snd_card_free_when_closed(bebob->card);
 }
 
-static struct snd_bebob_rate_spec normal_rate_spec = {
+static const struct snd_bebob_rate_spec normal_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate
 };
@@ -360,9 +361,9 @@ static const struct ieee1394_device_id bebob_id_table[] = {
        /* BridgeCo, Audio5 */
        SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
        /* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
-       SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
+       SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal),
        /* Mackie, d.2 (Firewire Option) */
-       SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
+       SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal),
        /* Stanton, ScratchAmp */
        SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
        /* Tascam, IF-FW DM */
index d23caca..4d8fcc7 100644 (file)
@@ -31,7 +31,7 @@
 #include "../fcp.h"
 #include "../packets-buffer.h"
 #include "../iso-resources.h"
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../cmp.h"
 
 /* basic register addresses on DM1000/DM1100/DM1500 */
@@ -70,9 +70,9 @@ struct snd_bebob_meter_spec {
        int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size);
 };
 struct snd_bebob_spec {
-       struct snd_bebob_clock_spec *clock;
-       struct snd_bebob_rate_spec *rate;
-       struct snd_bebob_meter_spec *meter;
+       const struct snd_bebob_clock_spec *clock;
+       const struct snd_bebob_rate_spec *rate;
+       const struct snd_bebob_meter_spec *meter;
 };
 
 struct snd_bebob {
@@ -235,19 +235,19 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob);
 int snd_bebob_create_hwdep_device(struct snd_bebob *bebob);
 
 /* model specific operations */
-extern struct snd_bebob_spec phase88_rack_spec;
-extern struct snd_bebob_spec phase24_series_spec;
-extern struct snd_bebob_spec yamaha_go_spec;
-extern struct snd_bebob_spec saffirepro_26_spec;
-extern struct snd_bebob_spec saffirepro_10_spec;
-extern struct snd_bebob_spec saffire_le_spec;
-extern struct snd_bebob_spec saffire_spec;
-extern struct snd_bebob_spec maudio_fw410_spec;
-extern struct snd_bebob_spec maudio_audiophile_spec;
-extern struct snd_bebob_spec maudio_solo_spec;
-extern struct snd_bebob_spec maudio_ozonic_spec;
-extern struct snd_bebob_spec maudio_nrv10_spec;
-extern struct snd_bebob_spec maudio_special_spec;
+extern const struct snd_bebob_spec phase88_rack_spec;
+extern const struct snd_bebob_spec phase24_series_spec;
+extern const struct snd_bebob_spec yamaha_go_spec;
+extern const struct snd_bebob_spec saffirepro_26_spec;
+extern const struct snd_bebob_spec saffirepro_10_spec;
+extern const struct snd_bebob_spec saffire_le_spec;
+extern const struct snd_bebob_spec saffire_spec;
+extern const struct snd_bebob_spec maudio_fw410_spec;
+extern const struct snd_bebob_spec maudio_audiophile_spec;
+extern const struct snd_bebob_spec maudio_solo_spec;
+extern const struct snd_bebob_spec maudio_ozonic_spec;
+extern const struct snd_bebob_spec maudio_nrv10_spec;
+extern const struct snd_bebob_spec maudio_special_spec;
 int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
 int snd_bebob_maudio_load_firmware(struct fw_unit *unit);
 
index a1a3949..f110900 100644 (file)
@@ -200,7 +200,7 @@ end:
        return err;
 }
 
-struct snd_bebob_spec saffire_le_spec;
+const struct snd_bebob_spec saffire_le_spec;
 static enum snd_bebob_clock_type saffire_both_clk_src_types[] = {
        SND_BEBOB_CLOCK_TYPE_INTERNAL,
        SND_BEBOB_CLOCK_TYPE_EXTERNAL,
@@ -229,7 +229,7 @@ static const char *const saffire_meter_labels[] = {
 static int
 saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
 {
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        unsigned int channels;
        u64 offset;
        int err;
@@ -260,60 +260,60 @@ saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
        return err;
 }
 
-static struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
+static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
        .get    = &saffirepro_both_clk_freq_get,
        .set    = &saffirepro_both_clk_freq_set,
 };
 /* Saffire Pro 26 I/O  */
-static struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
+static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
        .num    = ARRAY_SIZE(saffirepro_26_clk_src_types),
        .types  = saffirepro_26_clk_src_types,
        .get    = &saffirepro_both_clk_src_get,
 };
-struct snd_bebob_spec saffirepro_26_spec = {
+const struct snd_bebob_spec saffirepro_26_spec = {
        .clock  = &saffirepro_26_clk_spec,
        .rate   = &saffirepro_both_rate_spec,
        .meter  = NULL
 };
 /* Saffire Pro 10 I/O */
-static struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
+static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
        .num    = ARRAY_SIZE(saffirepro_10_clk_src_types),
        .types  = saffirepro_10_clk_src_types,
        .get    = &saffirepro_both_clk_src_get,
 };
-struct snd_bebob_spec saffirepro_10_spec = {
+const struct snd_bebob_spec saffirepro_10_spec = {
        .clock  = &saffirepro_10_clk_spec,
        .rate   = &saffirepro_both_rate_spec,
        .meter  = NULL
 };
 
-static struct snd_bebob_rate_spec saffire_both_rate_spec = {
+static const struct snd_bebob_rate_spec saffire_both_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-static struct snd_bebob_clock_spec saffire_both_clk_spec = {
+static const struct snd_bebob_clock_spec saffire_both_clk_spec = {
        .num    = ARRAY_SIZE(saffire_both_clk_src_types),
        .types  = saffire_both_clk_src_types,
        .get    = &saffire_both_clk_src_get,
 };
 /* Saffire LE */
-static struct snd_bebob_meter_spec saffire_le_meter_spec = {
+static const struct snd_bebob_meter_spec saffire_le_meter_spec = {
        .num    = ARRAY_SIZE(saffire_le_meter_labels),
        .labels = saffire_le_meter_labels,
        .get    = &saffire_meter_get,
 };
-struct snd_bebob_spec saffire_le_spec = {
+const struct snd_bebob_spec saffire_le_spec = {
        .clock  = &saffire_both_clk_spec,
        .rate   = &saffire_both_rate_spec,
        .meter  = &saffire_le_meter_spec
 };
 /* Saffire */
-static struct snd_bebob_meter_spec saffire_meter_spec = {
+static const struct snd_bebob_meter_spec saffire_meter_spec = {
        .num    = ARRAY_SIZE(saffire_meter_labels),
        .labels = saffire_meter_labels,
        .get    = &saffire_meter_get,
 };
-struct snd_bebob_spec saffire_spec = {
+const struct snd_bebob_spec saffire_spec = {
        .clock  = &saffire_both_clk_spec,
        .rate   = &saffire_both_rate_spec,
        .meter  = &saffire_meter_spec
index 057495d..07e5abd 100644 (file)
@@ -628,7 +628,7 @@ static const char *const special_meter_labels[] = {
 static int
 special_meter_get(struct snd_bebob *bebob, u32 *target, unsigned int size)
 {
-       u16 *buf;
+       __be16 *buf;
        unsigned int i, c, channels;
        int err;
 
@@ -687,7 +687,7 @@ static const char *const nrv10_meter_labels[] = {
 static int
 normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
 {
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        unsigned int c, channels;
        int err;
 
@@ -712,85 +712,85 @@ end:
 }
 
 /* for special customized devices */
-static struct snd_bebob_rate_spec special_rate_spec = {
+static const struct snd_bebob_rate_spec special_rate_spec = {
        .get    = &special_get_rate,
        .set    = &special_set_rate,
 };
-static struct snd_bebob_clock_spec special_clk_spec = {
+static const struct snd_bebob_clock_spec special_clk_spec = {
        .num    = ARRAY_SIZE(special_clk_types),
        .types  = special_clk_types,
        .get    = &special_clk_get,
 };
-static struct snd_bebob_meter_spec special_meter_spec = {
+static const struct snd_bebob_meter_spec special_meter_spec = {
        .num    = ARRAY_SIZE(special_meter_labels),
        .labels = special_meter_labels,
        .get    = &special_meter_get
 };
-struct snd_bebob_spec maudio_special_spec = {
+const struct snd_bebob_spec maudio_special_spec = {
        .clock  = &special_clk_spec,
        .rate   = &special_rate_spec,
        .meter  = &special_meter_spec
 };
 
 /* Firewire 410 specification */
-static struct snd_bebob_rate_spec usual_rate_spec = {
+static const struct snd_bebob_rate_spec usual_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-static struct snd_bebob_meter_spec fw410_meter_spec = {
+static const struct snd_bebob_meter_spec fw410_meter_spec = {
        .num    = ARRAY_SIZE(fw410_meter_labels),
        .labels = fw410_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_fw410_spec = {
+const struct snd_bebob_spec maudio_fw410_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &fw410_meter_spec
 };
 
 /* Firewire Audiophile specification */
-static struct snd_bebob_meter_spec audiophile_meter_spec = {
+static const struct snd_bebob_meter_spec audiophile_meter_spec = {
        .num    = ARRAY_SIZE(audiophile_meter_labels),
        .labels = audiophile_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_audiophile_spec = {
+const struct snd_bebob_spec maudio_audiophile_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &audiophile_meter_spec
 };
 
 /* Firewire Solo specification */
-static struct snd_bebob_meter_spec solo_meter_spec = {
+static const struct snd_bebob_meter_spec solo_meter_spec = {
        .num    = ARRAY_SIZE(solo_meter_labels),
        .labels = solo_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_solo_spec = {
+const struct snd_bebob_spec maudio_solo_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &solo_meter_spec
 };
 
 /* Ozonic specification */
-static struct snd_bebob_meter_spec ozonic_meter_spec = {
+static const struct snd_bebob_meter_spec ozonic_meter_spec = {
        .num    = ARRAY_SIZE(ozonic_meter_labels),
        .labels = ozonic_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_ozonic_spec = {
+const struct snd_bebob_spec maudio_ozonic_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &ozonic_meter_spec
 };
 
 /* NRV10 specification */
-static struct snd_bebob_meter_spec nrv10_meter_spec = {
+static const struct snd_bebob_meter_spec nrv10_meter_spec = {
        .num    = ARRAY_SIZE(nrv10_meter_labels),
        .labels = nrv10_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_nrv10_spec = {
+const struct snd_bebob_spec maudio_nrv10_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &nrv10_meter_spec
index 5681143..90d95be 100644 (file)
@@ -72,11 +72,11 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&bebob->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&bebob->tx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&bebob->tx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&bebob->tx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&bebob->tx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&bebob->lock, flags);
 }
@@ -89,11 +89,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&bebob->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&bebob->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&bebob->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&bebob->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&bebob->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&bebob->lock, flags);
 }
index c0f018a..ef224d6 100644 (file)
@@ -122,11 +122,11 @@ pcm_init_hw_params(struct snd_bebob *bebob,
                           SNDRV_PCM_INFO_MMAP_VALID;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
                s = &bebob->tx_stream;
                formations = bebob->tx_stream_formations;
        } else {
-               runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
                s = &bebob->rx_stream;
                formations = bebob->rx_stream_formations;
        }
@@ -146,7 +146,7 @@ pcm_init_hw_params(struct snd_bebob *bebob,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
 end:
        return err;
 }
@@ -155,7 +155,7 @@ static int
 pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
-       struct snd_bebob_rate_spec *spec = bebob->spec->rate;
+       const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
        unsigned int sampling_rate;
        enum snd_bebob_clock_type src;
        int err;
@@ -220,8 +220,8 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&bebob->substreams_counter);
-       amdtp_stream_set_pcm_format(&bebob->tx_stream,
-                                   params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&bebob->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -239,8 +239,8 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&bebob->substreams_counter);
-       amdtp_stream_set_pcm_format(&bebob->rx_stream,
-                                   params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&bebob->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 301cc6a..ec24f96 100644 (file)
@@ -73,7 +73,7 @@ proc_read_meters(struct snd_info_entry *entry,
                 struct snd_info_buffer *buffer)
 {
        struct snd_bebob *bebob = entry->private_data;
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        u32 *buf;
        unsigned int i, c, channels, size;
 
@@ -138,8 +138,8 @@ proc_read_clock(struct snd_info_entry *entry,
                "SYT-Match",
        };
        struct snd_bebob *bebob = entry->private_data;
-       struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        enum snd_bebob_clock_type src;
        unsigned int rate;
 
index 5be5242..926e5dc 100644 (file)
@@ -119,7 +119,7 @@ end:
 int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
                                   enum snd_bebob_clock_type *src)
 {
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
        unsigned int id;
        enum avc_bridgeco_plug_type type;
@@ -338,7 +338,7 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
                                        err = -ENOSYS;
                                        goto end;
                                }
-                               s->midi_position = stm_pos;
+                               amdtp_am824_set_midi_position(s, stm_pos);
                                midi = stm_pos;
                                break;
                        /* for PCM data channel */
@@ -354,11 +354,12 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
                        case 0x09:      /* Digital */
                        default:
                                location = pcm + sec_loc;
-                               if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) {
+                               if (location >= AM824_MAX_CHANNELS_FOR_PCM) {
                                        err = -ENOSYS;
                                        goto end;
                                }
-                               s->pcm_positions[location] = stm_pos;
+                               amdtp_am824_set_pcm_position(s, location,
+                                                            stm_pos);
                                break;
                        }
                }
@@ -427,12 +428,19 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate)
        index = get_formation_index(rate);
        pcm_channels = bebob->tx_stream_formations[index].pcm;
        midi_channels = bebob->tx_stream_formations[index].midi;
-       amdtp_stream_set_parameters(&bebob->tx_stream,
-                                   rate, pcm_channels, midi_channels * 8);
+       err = amdtp_am824_set_parameters(&bebob->tx_stream, rate,
+                                        pcm_channels, midi_channels * 8,
+                                        false);
+       if (err < 0)
+               goto end;
+
        pcm_channels = bebob->rx_stream_formations[index].pcm;
        midi_channels = bebob->rx_stream_formations[index].midi;
-       amdtp_stream_set_parameters(&bebob->rx_stream,
-                                   rate, pcm_channels, midi_channels * 8);
+       err = amdtp_am824_set_parameters(&bebob->rx_stream, rate,
+                                        pcm_channels, midi_channels * 8,
+                                        false);
+       if (err < 0)
+               goto end;
 
        /* establish connections for both streams */
        err = cmp_connection_establish(&bebob->out_conn,
@@ -530,8 +538,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_init(&bebob->tx_stream, bebob->unit,
-                               AMDTP_IN_STREAM, CIP_BLOCKING);
+       err = amdtp_am824_init(&bebob->tx_stream, bebob->unit,
+                              AMDTP_IN_STREAM, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(&bebob->tx_stream);
                destroy_both_connections(bebob);
@@ -559,8 +567,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
        if (bebob->maudio_special_quirk)
                bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
 
-       err = amdtp_stream_init(&bebob->rx_stream, bebob->unit,
-                               AMDTP_OUT_STREAM, CIP_BLOCKING);
+       err = amdtp_am824_init(&bebob->rx_stream, bebob->unit,
+                              AMDTP_OUT_STREAM, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(&bebob->tx_stream);
                amdtp_stream_destroy(&bebob->rx_stream);
@@ -572,7 +580,7 @@ end:
 
 int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
 {
-       struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
+       const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
        struct amdtp_stream *master, *slave;
        enum cip_flags sync_mode;
        unsigned int curr_rate;
@@ -864,8 +872,8 @@ parse_stream_formation(u8 *buf, unsigned int len,
                }
        }
 
-       if (formation[i].pcm  > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
+       if (formation[i].pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
+           formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI)
                return -ENOSYS;
 
        return 0;
@@ -959,7 +967,7 @@ end:
 
 int snd_bebob_stream_discover(struct snd_bebob *bebob)
 {
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
        enum avc_bridgeco_plug_type type;
        unsigned int i;
index 9242e33..c38358b 100644 (file)
@@ -55,30 +55,30 @@ phase24_series_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
        return 0;
 }
 
-static struct snd_bebob_rate_spec phase_series_rate_spec = {
+static const struct snd_bebob_rate_spec phase_series_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
 
 /* PHASE 88 Rack FW */
-static struct snd_bebob_clock_spec phase88_rack_clk = {
+static const struct snd_bebob_clock_spec phase88_rack_clk = {
        .num    = ARRAY_SIZE(phase88_rack_clk_src_types),
        .types  = phase88_rack_clk_src_types,
        .get    = &phase88_rack_clk_src_get,
 };
-struct snd_bebob_spec phase88_rack_spec = {
+const struct snd_bebob_spec phase88_rack_spec = {
        .clock  = &phase88_rack_clk,
        .rate   = &phase_series_rate_spec,
        .meter  = NULL
 };
 
 /* 'PHASE 24 FW' and 'PHASE X24 FW' */
-static struct snd_bebob_clock_spec phase24_series_clk = {
+static const struct snd_bebob_clock_spec phase24_series_clk = {
        .num    = ARRAY_SIZE(phase24_series_clk_src_types),
        .types  = phase24_series_clk_src_types,
        .get    = &phase24_series_clk_src_get,
 };
-struct snd_bebob_spec phase24_series_spec = {
+const struct snd_bebob_spec phase24_series_spec = {
        .clock  = &phase24_series_clk,
        .rate   = &phase_series_rate_spec,
        .meter  = NULL
index 5810170..90d4404 100644 (file)
@@ -46,16 +46,16 @@ clk_src_get(struct snd_bebob *bebob, unsigned int *id)
 
        return 0;
 }
-static struct snd_bebob_clock_spec clock_spec = {
+static const struct snd_bebob_clock_spec clock_spec = {
        .num    = ARRAY_SIZE(clk_src_types),
        .types  = clk_src_types,
        .get    = &clk_src_get,
 };
-static struct snd_bebob_rate_spec rate_spec = {
+static const struct snd_bebob_rate_spec rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-struct snd_bebob_spec yamaha_go_spec = {
+const struct snd_bebob_spec yamaha_go_spec = {
        .clock  = &clock_spec,
        .rate   = &rate_spec,
        .meter  = NULL
index 9ef228e..55b4be9 100644 (file)
@@ -1,3 +1,3 @@
 snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
                 dice-pcm.o dice-hwdep.o dice.o
-obj-m += snd-dice.o
+obj-$(CONFIG_SND_DICE) += snd-dice.o
index fe43ce7..151b09f 100644 (file)
@@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&dice->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&dice->tx_stream,
+               amdtp_am824_midi_trigger(&dice->tx_stream,
                                          substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&dice->tx_stream,
+               amdtp_am824_midi_trigger(&dice->tx_stream,
                                          substrm->number, NULL);
 
        spin_unlock_irqrestore(&dice->lock, flags);
@@ -69,11 +69,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&dice->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&dice->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&dice->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&dice->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&dice->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&dice->lock, flags);
 }
index 4e67b1d..9b34319 100644 (file)
@@ -133,11 +133,11 @@ static int init_hw_info(struct snd_dice *dice,
                   SNDRV_PCM_INFO_BLOCK_TRANSFER;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               hw->formats = AMDTP_IN_PCM_FORMAT_BITS;
+               hw->formats = AM824_IN_PCM_FORMAT_BITS;
                stream = &dice->tx_stream;
                pcm_channels = dice->tx_channels;
        } else {
-               hw->formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               hw->formats = AM824_OUT_PCM_FORMAT_BITS;
                stream = &dice->rx_stream;
                pcm_channels = dice->rx_channels;
        }
@@ -156,7 +156,7 @@ static int init_hw_info(struct snd_dice *dice,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 end:
        return err;
 }
@@ -243,8 +243,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&dice->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&dice->tx_stream,
-                                   params_format(hw_params));
+       amdtp_am824_set_pcm_format(&dice->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -265,8 +264,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&dice->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&dice->rx_stream,
-                                   params_format(hw_params));
+       amdtp_am824_set_pcm_format(&dice->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 07dbd01..a6a39f7 100644 (file)
@@ -44,16 +44,16 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
 static void release_resources(struct snd_dice *dice,
                              struct fw_iso_resources *resources)
 {
-       unsigned int channel;
+       __be32 channel;
 
        /* Reset channel number */
        channel = cpu_to_be32((u32)-1);
        if (resources == &dice->tx_resources)
                snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-                                             &channel, 4);
+                                             &channel, sizeof(channel));
        else
                snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-                                             &channel, 4);
+                                             &channel, sizeof(channel));
 
        fw_iso_resources_free(resources);
 }
@@ -62,7 +62,7 @@ static int keep_resources(struct snd_dice *dice,
                          struct fw_iso_resources *resources,
                          unsigned int max_payload_bytes)
 {
-       unsigned int channel;
+       __be32 channel;
        int err;
 
        err = fw_iso_resources_allocate(resources, max_payload_bytes,
@@ -74,10 +74,10 @@ static int keep_resources(struct snd_dice *dice,
        channel = cpu_to_be32(resources->channel);
        if (resources == &dice->tx_resources)
                err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-                                                   &channel, 4);
+                                                   &channel, sizeof(channel));
        else
                err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-                                                   &channel, 4);
+                                                   &channel, sizeof(channel));
        if (err < 0)
                release_resources(dice, resources);
 end:
@@ -100,6 +100,7 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 {
        struct fw_iso_resources *resources;
        unsigned int i, mode, pcm_chs, midi_ports;
+       bool double_pcm_frames;
        int err;
 
        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
@@ -125,21 +126,24 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
         * For this quirk, blocking mode is required and PCM buffer size should
         * be aligned to SYT_INTERVAL.
         */
-       if (mode > 1) {
+       double_pcm_frames = mode > 1;
+       if (double_pcm_frames) {
                rate /= 2;
                pcm_chs *= 2;
-               stream->double_pcm_frames = true;
-       } else {
-               stream->double_pcm_frames = false;
        }
 
-       amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
-       if (mode > 1) {
+       err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
+                                        double_pcm_frames);
+       if (err < 0)
+               goto end;
+
+       if (double_pcm_frames) {
                pcm_chs /= 2;
 
                for (i = 0; i < pcm_chs; i++) {
-                       stream->pcm_positions[i] = i * 2;
-                       stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
+                       amdtp_am824_set_pcm_position(stream, i, i * 2);
+                       amdtp_am824_set_pcm_position(stream, i + pcm_chs,
+                                                    i * 2 + 1);
                }
        }
 
@@ -302,7 +306,7 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
                goto end;
        resources->channels_mask = 0x00000000ffffffffuLL;
 
-       err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
+       err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(stream);
                fw_iso_resources_destroy(resources);
index 70a111d..5d99436 100644 (file)
@@ -29,7 +29,8 @@ static int dice_interface_check(struct fw_unit *unit)
        struct fw_csr_iterator it;
        int key, val, vendor = -1, model = -1, err;
        unsigned int category, i;
-       __be32 *pointers, value;
+       __be32 *pointers;
+       u32 value;
        __be32 version;
 
        pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
index ecf5dc8..101550a 100644 (file)
@@ -34,7 +34,7 @@
 #include <sound/pcm_params.h>
 #include <sound/rawmidi.h>
 
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../iso-resources.h"
 #include "../lib.h"
 #include "dice-interface.h"
diff --git a/sound/firewire/digi00x/Makefile b/sound/firewire/digi00x/Makefile
new file mode 100644 (file)
index 0000000..1123e68
--- /dev/null
@@ -0,0 +1,4 @@
+snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
+                            digi00x-pcm.o digi00x-hwdep.o \
+                            digi00x-transaction.o digi00x-midi.o digi00x.o
+obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c
new file mode 100644 (file)
index 0000000..b02a5e8
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ * Copyright (C) 2012 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <sound/pcm.h>
+#include "digi00x.h"
+
+#define CIP_FMT_AM             0x10
+
+/* 'Clock-based rate control mode' is just supported. */
+#define AMDTP_FDF_AM824                0x00
+
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND  3093
+
+/*
+ * Several devices look only at the first eight data blocks.
+ * In any case, this is more than enough for the MIDI data rate.
+ */
+#define MAX_MIDI_RX_BLOCKS     8
+
+/*
+ * The double-oh-three algorithm was discovered by Robin Gareus and Damien
+ * Zammit in 2012, with reverse-engineering for Digi 003 Rack.
+ */
+struct dot_state {
+       u8 carry;
+       u8 idx;
+       unsigned int off;
+};
+
+struct amdtp_dot {
+       unsigned int pcm_channels;
+       struct dot_state state;
+
+       unsigned int midi_ports;
+       /* 2 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) */
+       struct snd_rawmidi_substream *midi[2];
+       int midi_fifo_used[2];
+       int midi_fifo_limit;
+
+       void (*transfer_samples)(struct amdtp_stream *s,
+                                struct snd_pcm_substream *pcm,
+                                __be32 *buffer, unsigned int frames);
+};
+
+/*
+ * double-oh-three look up table
+ *
+ * @param idx index byte (audio-sample data) 0x00..0xff
+ * @param off channel offset shift
+ * @return salt to XOR with given data
+ */
+#define BYTE_PER_SAMPLE (4)
+#define MAGIC_DOT_BYTE (2)
+#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
+static const u8 dot_scrt(const u8 idx, const unsigned int off)
+{
+       /*
+        * the length of the added pattern only depends on the lower nibble
+        * of the last non-zero data
+        */
+       static const u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14,
+                                  12, 10, 8, 6, 4, 2, 0};
+
+       /*
+        * the lower nibble of the salt. Interleaved sequence.
+        * this is walked backwards according to len[]
+        */
+       static const u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4,
+                                  0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf};
+
+       /* circular list for the salt's hi nibble. */
+       static const u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4,
+                                  0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa};
+
+       /*
+        * start offset for upper nibble mapping.
+        * note: 9 is /special/. In the case where the high nibble == 0x9,
+        * hir[] is not used and - coincidentally - the salt's hi nibble is
+        * 0x09 regardless of the offset.
+        */
+       static const u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4,
+                                  3, 0x00, 14, 13, 8, 9, 10, 2};
+
+       const u8 ln = idx & 0xf;
+       const u8 hn = (idx >> 4) & 0xf;
+       const u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15];
+
+       if (len[ln] < off)
+               return 0x00;
+
+       return ((nib[14 + off - len[ln]]) | (hr << 4));
+}
+
+static void dot_encode_step(struct dot_state *state, __be32 *const buffer)
+{
+       u8 * const data = (u8 *) buffer;
+
+       if (data[MAGIC_DOT_BYTE] != 0x00) {
+               state->off = 0;
+               state->idx = data[MAGIC_DOT_BYTE] ^ state->carry;
+       }
+       data[MAGIC_DOT_BYTE] ^= state->carry;
+       state->carry = dot_scrt(state->idx, ++(state->off));
+}
+
+int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                            unsigned int pcm_channels)
+{
+       struct amdtp_dot *p = s->protocol;
+       int err;
+
+       if (amdtp_stream_running(s))
+               return -EBUSY;
+
+       /*
+        * A first data channel is for MIDI conformant data channel, the rest is
+        * Multi Bit Linear Audio data channel.
+        */
+       err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1);
+       if (err < 0)
+               return err;
+
+       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+
+       p->pcm_channels = pcm_channels;
+
+       if (s->direction == AMDTP_IN_STREAM)
+               p->midi_ports = DOT_MIDI_IN_PORTS;
+       else
+               p->midi_ports = DOT_MIDI_OUT_PORTS;
+
+       /*
+        * We do not know the actual MIDI FIFO size of most devices.  Just
+        * assume two bytes, i.e., one byte can be received over the bus while
+        * the previous one is transmitted over MIDI.
+        * (The value here is adjusted for midi_ratelimit_per_packet().)
+        */
+       p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
+
+       return 0;
+}
+
+static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u32 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000);
+                       dot_encode_step(&p->state, &buffer[c]);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_s16(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u16 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32((*src << 8) | 0x40000000);
+                       dot_encode_step(&p->state, &buffer[c]);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                        __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       u32 *dst;
+
+       channels = p->pcm_channels;
+       dst  = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *dst = be32_to_cpu(buffer[c]) << 8;
+                       dst++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       dst = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
+                             unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int channels, i, c;
+
+       channels = p->pcm_channels;
+
+       buffer++;
+       for (i = 0; i < data_blocks; ++i) {
+               for (c = 0; c < channels; ++c)
+                       buffer[c] = cpu_to_be32(0x40000000);
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_dot *p = s->protocol;
+       int used;
+
+       used = p->midi_fifo_used[port];
+       if (used == 0)
+               return true;
+
+       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
+       used = max(used, 0);
+       p->midi_fifo_used[port] = used;
+
+       return used < p->midi_fifo_limit;
+}
+
+static inline void midi_use_bytes(struct amdtp_stream *s,
+                                 unsigned int port, unsigned int count)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       p->midi_fifo_used[port] += amdtp_rate_table[s->sfc] * count;
+}
+
+static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                               unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int f, port;
+       int len;
+       u8 *b;
+
+       for (f = 0; f < data_blocks; f++) {
+               port = (s->data_block_counter + f) % 8;
+               b = (u8 *)&buffer[0];
+
+               len = 0;
+               if (port < p->midi_ports &&
+                   midi_ratelimit_per_packet(s, port) &&
+                   p->midi[port] != NULL)
+                       len = snd_rawmidi_transmit(p->midi[port], b + 1, 2);
+
+               if (len > 0) {
+                       b[3] = (0x10 << port) | len;
+                       midi_use_bytes(s, port, len);
+               } else {
+                       b[1] = 0;
+                       b[2] = 0;
+                       b[3] = 0;
+               }
+               b[0] = 0x80;
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                              unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int f, port, len;
+       u8 *b;
+
+       for (f = 0; f < data_blocks; f++) {
+               b = (u8 *)&buffer[0];
+               port = b[3] >> 4;
+               len = b[3] & 0x0f;
+
+               if (port < p->midi_ports && p->midi[port] && len > 0)
+                       snd_rawmidi_receive(p->midi[port], b + 1, len);
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                    struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       /* This protocol delivers 24 bit data in 32bit data channel. */
+       err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+       if (err < 0)
+               return err;
+
+       return amdtp_stream_add_pcm_hw_constraints(s, runtime);
+}
+
+void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       if (WARN_ON(amdtp_stream_pcm_running(s)))
+               return;
+
+       switch (format) {
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S16:
+               if (s->direction == AMDTP_OUT_STREAM) {
+                       p->transfer_samples = write_pcm_s16;
+                       break;
+               }
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32:
+               if (s->direction == AMDTP_OUT_STREAM)
+                       p->transfer_samples = write_pcm_s32;
+               else
+                       p->transfer_samples = read_pcm_s32;
+               break;
+       }
+}
+
+void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                         struct snd_rawmidi_substream *midi)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       if (port < p->midi_ports)
+               ACCESS_ONCE(p->midi[port]) = midi;
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks;
+       } else {
+               pcm_frames = 0;
+       }
+
+       read_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks;
+       } else {
+               write_pcm_silence(s, buffer, data_blocks);
+               pcm_frames = 0;
+       }
+
+       write_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
+                enum amdtp_stream_direction dir)
+{
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+       enum cip_flags flags;
+
+       /* Use different mode between incoming/outgoing. */
+       if (dir == AMDTP_IN_STREAM) {
+               flags = CIP_NONBLOCKING | CIP_SKIP_INIT_DBC_CHECK;
+               process_data_blocks = process_tx_data_blocks;
+       } else {
+               flags = CIP_BLOCKING;
+               process_data_blocks = process_rx_data_blocks;
+       }
+
+       return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
+                                process_data_blocks, sizeof(struct amdtp_dot));
+}
+
+void amdtp_dot_reset(struct amdtp_stream *s)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       p->state.carry = 0x00;
+       p->state.idx = 0x00;
+       p->state.off = 0;
+}
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
new file mode 100644 (file)
index 0000000..f188e47
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes give three functionality.
+ *
+ * 1.get firewire node information
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock stream
+ * 4.get asynchronous messaging
+ */
+
+#include "digi00x.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
+                      loff_t *offset)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+       DEFINE_WAIT(wait);
+       union snd_firewire_event event;
+
+       spin_lock_irq(&dg00x->lock);
+
+       while (!dg00x->dev_lock_changed && dg00x->msg == 0) {
+               prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+               spin_unlock_irq(&dg00x->lock);
+               schedule();
+               finish_wait(&dg00x->hwdep_wait, &wait);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               spin_lock_irq(&dg00x->lock);
+       }
+
+       memset(&event, 0, sizeof(event));
+       if (dg00x->dev_lock_changed) {
+               event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+               event.lock_status.status = (dg00x->dev_lock_count > 0);
+               dg00x->dev_lock_changed = false;
+
+               count = min_t(long, count, sizeof(event.lock_status));
+       } else {
+               event.digi00x_message.type =
+                                       SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE;
+               event.digi00x_message.message = dg00x->msg;
+               dg00x->msg = 0;
+
+               count = min_t(long, count, sizeof(event.digi00x_message));
+       }
+
+       spin_unlock_irq(&dg00x->lock);
+
+       if (copy_to_user(buf, &event, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+                              poll_table *wait)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+       unsigned int events;
+
+       poll_wait(file, &dg00x->hwdep_wait, wait);
+
+       spin_lock_irq(&dg00x->lock);
+       if (dg00x->dev_lock_changed || dg00x->msg)
+               events = POLLIN | POLLRDNORM;
+       else
+               events = 0;
+       spin_unlock_irq(&dg00x->lock);
+
+       return events;
+}
+
+static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
+{
+       struct fw_device *dev = fw_parent_device(dg00x->unit);
+       struct snd_firewire_get_info info;
+
+       memset(&info, 0, sizeof(info));
+       info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;
+       info.card = dev->card->index;
+       *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+       *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+       strlcpy(info.device_name, dev_name(&dev->device),
+               sizeof(info.device_name));
+
+       if (copy_to_user(arg, &info, sizeof(info)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int hwdep_lock(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       spin_lock_irq(&dg00x->lock);
+
+       if (dg00x->dev_lock_count == 0) {
+               dg00x->dev_lock_count = -1;
+               err = 0;
+       } else {
+               err = -EBUSY;
+       }
+
+       spin_unlock_irq(&dg00x->lock);
+
+       return err;
+}
+
+static int hwdep_unlock(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       spin_lock_irq(&dg00x->lock);
+
+       if (dg00x->dev_lock_count == -1) {
+               dg00x->dev_lock_count = 0;
+               err = 0;
+       } else {
+               err = -EBADFD;
+       }