Merge remote-tracking branches 'asoc/topic/adsp', 'asoc/topic/atmel', 'asoc/topic...
authorMark Brown <broonie@linaro.org>
Thu, 16 Jan 2014 12:44:01 +0000 (12:44 +0000)
committerMark Brown <broonie@linaro.org>
Thu, 16 Jan 2014 12:44:01 +0000 (12:44 +0000)
59 files changed:
Documentation/devicetree/bindings/sound/fsl,esai.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,ssi.txt
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/sound/alsa/soc/overview.txt
arch/arm/mach-ux500/board-mop500-audio.c
drivers/mfd/twl-core.c
include/linux/i2c/twl.h
include/linux/platform_data/asoc-ux500-msp.h
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel-pcm-pdc.c
sound/soc/bcm/Kconfig
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs42l51.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max9850.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_esai.c [new file with mode: 0644]
sound/soc/fsl/fsl_esai.h [new file with mode: 0644]
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/generic/simple-card.c
sound/soc/intel/sst_platform.c
sound/soc/intel/sst_platform.h
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mxs/mxs-pcm.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/rcar/core.c
sound/soc/ux500/mop500.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/soc/ux500/ux500_pcm.c

diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
new file mode 100644 (file)
index 0000000..d7b99fa
--- /dev/null
@@ -0,0 +1,50 @@
+Freescale Enhanced Serial Audio Interface (ESAI) Controller
+
+The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
+for serial communication with a variety of serial devices, including industry
+standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
+other DSPs. It has up to six transmitters and four receivers.
+
+Required properties:
+
+  - compatible : Compatible list, must contain "fsl,imx35-esai".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks: Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+       "core"          The core clock used to access registers
+       "extal"         The esai baud clock for esai controller used to derive
+                       HCK, SCK and FS.
+       "fsys"          The system clock derived from ahb clock used to derive
+                       HCK, SCK and FS.
+
+  - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
+    This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
+
+  - fsl,esai-synchronous: This is a boolean property. If present, indicating
+    that ESAI would work in the synchronous mode, which means all the settings
+    for Receiving would be duplicated from Transmition related registers.
+
+Example:
+
+esai: esai@02024000 {
+       compatible = "fsl,imx35-esai";
+       reg = <0x02024000 0x4000>;
+       interrupts = <0 51 0x04>;
+       clocks = <&clks 208>, <&clks 118>, <&clks 208>;
+       clock-names = "core", "extal", "fsys";
+       dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
+       dma-names = "rx", "tx";
+       fsl,fifo-depth = <128>;
+       fsl,esai-synchronous;
+       status = "disabled";
+};
index 4303b6ab6208e0856f81bc2fbc0ab8c4e81f519c..b93e9a91e30e2a5fc35e28dba0c5282d2e2c7a0e 100644 (file)
@@ -4,7 +4,12 @@ The SSI is a serial device that communicates with audio codecs.  It can
 be programmed in AC97, I2S, left-justified, or right-justified modes.
 
 Required properties:
-- compatible:       Compatible list, contains "fsl,ssi".
+- compatible:       Compatible list, should contain one of the following
+                    compatibles:
+                      fsl,mpc8610-ssi
+                      fsl,imx51-ssi
+                      fsl,imx35-ssi
+                      fsl,imx21-ssi
 - cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
 - reg:              Offset and length of the register set for the device.
 - interrupts:       <a b> where a is the interrupt number and b is a
index 2ee80c76ca6452e51a00e29a92a950ab89ca2eca..e9e20ec67d62b349d021099a755bbd5eca2a6b2a 100644 (file)
@@ -11,7 +11,7 @@ Optional properties:
 - simple-audio-card,format             : CPU/CODEC common audio format.
                                          "i2s", "right_j", "left_j" , "dsp_a"
                                          "dsp_b", "ac97", "pdm", "msb", "lsb"
-- simple-audio-routing                 : A list of the connections between audio components.
+- simple-audio-card,routing            : A list of the connections between audio components.
                                          Each entry is a pair of strings, the first being the
                                          connection's sink, the second being the connection's
                                          source.
index 5e6040c2c2e9c34019dceb93e439504e4e5af9ad..9d8ea14db49011cd95bb86d102461ece9abeca2d 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
 
 - compatible - "string" - One of:
     "ti,tlv320aic3x" - Generic TLV320AIC3x device
+    "ti,tlv320aic32x4" - TLV320AIC32x4
     "ti,tlv320aic33" - TLV320AIC33
     "ti,tlv320aic3007" - TLV320AIC3007
     "ti,tlv320aic3106" - TLV320AIC3106
index 138ac88c146126b4ca602de288fee60a3c2046a7..ff88f52eec9849e254796b1c56d77a19236ea6a4 100644 (file)
@@ -49,18 +49,23 @@ features :-
   * Machine specific controls: Allow machines to add controls to the sound card
     (e.g. volume control for speaker amplifier).
 
-To achieve all this, ASoC basically splits an embedded audio system into 3
-components :-
+To achieve all this, ASoC basically splits an embedded audio system into
+multiple re-usable component drivers :-
 
-  * Codec driver: The codec driver is platform independent and contains audio
-    controls, audio interface capabilities, codec DAPM definition and codec IO
-    functions.
+  * Codec class drivers: The codec class driver is platform independent and
+    contains audio controls, audio interface capabilities, codec DAPM
+    definition and codec IO functions. This class extends to BT, FM and MODEM
+    ICs if required. Codec class drivers should be generic code that can run
+    on any architecture and machine.
 
-  * Platform driver: The platform driver contains the audio DMA engine and audio
-    interface drivers (e.g. I2S, AC97, PCM) for that platform.
+  * Platform class drivers: The platform class driver includes the audio DMA
+    engine driver, digital audio interface (DAI) drivers (e.g. I2S, AC97, PCM)
+    and any audio DSP drivers for that platform.
 
-  * Machine driver: The machine driver handles any machine specific controls and
-    audio events (e.g. turning on an amp at start of playback).
+  * Machine class driver: The machine driver class acts as the glue that
+    decribes and binds the other component drivers together to form an ALSA
+    "sound card device". It handles any machine specific controls and
+    machine level audio events (e.g. turning on an amp at start of playback).
 
 
 Documentation
@@ -84,3 +89,7 @@ machine.txt: Machine driver internals.
 pop_clicks.txt: How to minimise audio artifacts.
 
 clocking.txt: ASoC clocking for best power performance.
+
+jack.txt: ASoC jack detection.
+
+DPCM.txt: Dynamic PCM - Describes DPCM with DSP examples.
index 154e15f59702c1010af74cce8fed51077c78e111..43d6cb8c381da9d4364afd45ae686dd155e1975d 100644 (file)
@@ -31,7 +31,7 @@ static struct stedma40_chan_cfg msp0_dma_tx = {
 };
 
 struct msp_i2s_platform_data msp0_platform_data = {
-       .id = MSP_I2S_0,
+       .id = 0,
        .msp_i2s_dma_rx = &msp0_dma_rx,
        .msp_i2s_dma_tx = &msp0_dma_tx,
 };
@@ -49,7 +49,7 @@ static struct stedma40_chan_cfg msp1_dma_tx = {
 };
 
 struct msp_i2s_platform_data msp1_platform_data = {
-       .id = MSP_I2S_1,
+       .id = 1,
        .msp_i2s_dma_rx = NULL,
        .msp_i2s_dma_tx = &msp1_dma_tx,
 };
@@ -69,13 +69,13 @@ static struct stedma40_chan_cfg msp2_dma_tx = {
 };
 
 struct msp_i2s_platform_data msp2_platform_data = {
-       .id = MSP_I2S_2,
+       .id = 2,
        .msp_i2s_dma_rx = &msp2_dma_rx,
        .msp_i2s_dma_tx = &msp2_dma_tx,
 };
 
 struct msp_i2s_platform_data msp3_platform_data = {
-       .id             = MSP_I2S_3,
+       .id             = 3,
        .msp_i2s_dma_rx = &msp1_dma_rx,
        .msp_i2s_dma_tx = NULL,
 };
index 29473c2c95ae0d92aa75184199486f70bdf5fc53..6ef7685a4cf8b346c129403c8155ada7f144d237 100644 (file)
@@ -47,6 +47,9 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
+/* Register descriptions for audio */
+#include <linux/mfd/twl4030-audio.h>
+
 #include "twl-core.h"
 
 /*
@@ -200,6 +203,105 @@ static struct twl_mapping twl4030_map[] = {
        { 2, TWL5031_BASEADD_INTERRUPTS },
 };
 
+static struct reg_default twl4030_49_defaults[] = {
+       /* Audio Registers */
+       { 0x01, 0x00}, /* CODEC_MODE    */
+       { 0x02, 0x00}, /* OPTION        */
+       /* 0x03  Unused */
+       { 0x04, 0x00}, /* MICBIAS_CTL   */
+       { 0x05, 0x00}, /* ANAMICL       */
+       { 0x06, 0x00}, /* ANAMICR       */
+       { 0x07, 0x00}, /* AVADC_CTL     */
+       { 0x08, 0x00}, /* ADCMICSEL     */
+       { 0x09, 0x00}, /* DIGMIXING     */
+       { 0x0a, 0x0f}, /* ATXL1PGA      */
+       { 0x0b, 0x0f}, /* ATXR1PGA      */
+       { 0x0c, 0x0f}, /* AVTXL2PGA     */
+       { 0x0d, 0x0f}, /* AVTXR2PGA     */
+       { 0x0e, 0x00}, /* AUDIO_IF      */
+       { 0x0f, 0x00}, /* VOICE_IF      */
+       { 0x10, 0x3f}, /* ARXR1PGA      */
+       { 0x11, 0x3f}, /* ARXL1PGA      */
+       { 0x12, 0x3f}, /* ARXR2PGA      */
+       { 0x13, 0x3f}, /* ARXL2PGA      */
+       { 0x14, 0x25}, /* VRXPGA        */
+       { 0x15, 0x00}, /* VSTPGA        */
+       { 0x16, 0x00}, /* VRX2ARXPGA    */
+       { 0x17, 0x00}, /* AVDAC_CTL     */
+       { 0x18, 0x00}, /* ARX2VTXPGA    */
+       { 0x19, 0x32}, /* ARXL1_APGA_CTL*/
+       { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/
+       { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/
+       { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/
+       { 0x1d, 0x00}, /* ATX2ARXPGA    */
+       { 0x1e, 0x00}, /* BT_IF         */
+       { 0x1f, 0x55}, /* BTPGA         */
+       { 0x20, 0x00}, /* BTSTPGA       */
+       { 0x21, 0x00}, /* EAR_CTL       */
+       { 0x22, 0x00}, /* HS_SEL        */
+       { 0x23, 0x00}, /* HS_GAIN_SET   */
+       { 0x24, 0x00}, /* HS_POPN_SET   */
+       { 0x25, 0x00}, /* PREDL_CTL     */
+       { 0x26, 0x00}, /* PREDR_CTL     */
+       { 0x27, 0x00}, /* PRECKL_CTL    */
+       { 0x28, 0x00}, /* PRECKR_CTL    */
+       { 0x29, 0x00}, /* HFL_CTL       */
+       { 0x2a, 0x00}, /* HFR_CTL       */
+       { 0x2b, 0x05}, /* ALC_CTL       */
+       { 0x2c, 0x00}, /* ALC_SET1      */
+       { 0x2d, 0x00}, /* ALC_SET2      */
+       { 0x2e, 0x00}, /* BOOST_CTL     */
+       { 0x2f, 0x00}, /* SOFTVOL_CTL   */
+       { 0x30, 0x13}, /* DTMF_FREQSEL  */
+       { 0x31, 0x00}, /* DTMF_TONEXT1H */
+       { 0x32, 0x00}, /* DTMF_TONEXT1L */
+       { 0x33, 0x00}, /* DTMF_TONEXT2H */
+       { 0x34, 0x00}, /* DTMF_TONEXT2L */
+       { 0x35, 0x79}, /* DTMF_TONOFF   */
+       { 0x36, 0x11}, /* DTMF_WANONOFF */
+       { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */
+       { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */
+       { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */
+       { 0x3a, 0x06}, /* APLL_CTL */
+       { 0x3b, 0x00}, /* DTMF_CTL */
+       { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */
+       { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */
+       { 0x3e, 0x00}, /* MISC_SET_1 */
+       { 0x3f, 0x00}, /* PCMBTMUX */
+       /* 0x40 - 0x42  Unused */
+       { 0x43, 0x00}, /* RX_PATH_SEL */
+       { 0x44, 0x32}, /* VDL_APGA_CTL */
+       { 0x45, 0x00}, /* VIBRA_CTL */
+       { 0x46, 0x00}, /* VIBRA_SET */
+       { 0x47, 0x00}, /* VIBRA_PWM_SET */
+       { 0x48, 0x00}, /* ANAMIC_GAIN   */
+       { 0x49, 0x00}, /* MISC_SET_2    */
+       /* End of Audio Registers */
+};
+
+static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0:
+       case 3:
+       case 40:
+       case 41:
+       case 42:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static const struct regmap_range twl4030_49_volatile_ranges[] = {
+       regmap_reg_range(TWL4030_BASEADD_TEST, 0xff),
+};
+
+static const struct regmap_access_table twl4030_49_volatile_table = {
+       .yes_ranges = twl4030_49_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges),
+};
+
 static struct regmap_config twl4030_regmap_config[4] = {
        {
                /* Address 0x48 */
@@ -212,6 +314,15 @@ static struct regmap_config twl4030_regmap_config[4] = {
                .reg_bits = 8,
                .val_bits = 8,
                .max_register = 0xff,
+
+               .readable_reg = twl4030_49_nop_reg,
+               .writeable_reg = twl4030_49_nop_reg,
+
+               .volatile_table = &twl4030_49_volatile_table,
+
+               .reg_defaults = twl4030_49_defaults,
+               .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults),
+               .cache_type = REGCACHE_RBTREE,
        },
        {
                /* Address 0x4a */
@@ -302,35 +413,50 @@ unsigned int twl_rev(void)
 EXPORT_SYMBOL(twl_rev);
 
 /**
- * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
+ * twl_get_regmap - Get the regmap associated with the given module
  * @mod_no: module number
- * @value: an array of num_bytes+1 containing data to write
- * @reg: register address (just offset will do)
- * @num_bytes: number of bytes to transfer
  *
- * Returns the result of operation - 0 is success
+ * Returns the regmap pointer or NULL in case of failure.
  */
-int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
+static struct regmap *twl_get_regmap(u8 mod_no)
 {
-       int ret;
        int sid;
        struct twl_client *twl;
 
        if (unlikely(!twl_priv || !twl_priv->ready)) {
                pr_err("%s: not initialized\n", DRIVER_NAME);
-               return -EPERM;
+               return NULL;
        }
        if (unlikely(mod_no >= twl_get_last_module())) {
                pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
-               return -EPERM;
+               return NULL;
        }
 
        sid = twl_priv->twl_map[mod_no].sid;
        twl = &twl_priv->twl_modules[sid];
 
-       ret = regmap_bulk_write(twl->regmap,
-                               twl_priv->twl_map[mod_no].base + reg, value,
-                               num_bytes);
+       return twl->regmap;
+}
+
+/**
+ * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
+{
+       struct regmap *regmap = twl_get_regmap(mod_no);
+       int ret;
+
+       if (!regmap)
+               return -EPERM;
+
+       ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg,
+                               value, num_bytes);
 
        if (ret)
                pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n",
@@ -351,25 +477,14 @@ EXPORT_SYMBOL(twl_i2c_write);
  */
 int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 {
+       struct regmap *regmap = twl_get_regmap(mod_no);
        int ret;
-       int sid;
-       struct twl_client *twl;
 
-       if (unlikely(!twl_priv || !twl_priv->ready)) {
-               pr_err("%s: not initialized\n", DRIVER_NAME);
-               return -EPERM;
-       }
-       if (unlikely(mod_no >= twl_get_last_module())) {
-               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+       if (!regmap)
                return -EPERM;
-       }
-
-       sid = twl_priv->twl_map[mod_no].sid;
-       twl = &twl_priv->twl_modules[sid];
 
-       ret = regmap_bulk_read(twl->regmap,
-                              twl_priv->twl_map[mod_no].base + reg, value,
-                              num_bytes);
+       ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg,
+                              value, num_bytes);
 
        if (ret)
                pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
@@ -379,6 +494,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 }
 EXPORT_SYMBOL(twl_i2c_read);
 
+/**
+ * twl_regcache_bypass - Configure the regcache bypass for the regmap associated
+ *                      with the module
+ * @mod_no: module number
+ * @enable: Regcache bypass state
+ *
+ * Returns 0 else failure.
+ */
+int twl_set_regcache_bypass(u8 mod_no, bool enable)
+{
+       struct regmap *regmap = twl_get_regmap(mod_no);
+
+       if (!regmap)
+               return -EPERM;
+
+       regcache_cache_bypass(regmap, enable);
+
+       return 0;
+}
+EXPORT_SYMBOL(twl_set_regcache_bypass);
+
 /*----------------------------------------------------------------------*/
 
 /**
index 673a3ce67f311df6567aa780dfdbf3d7adbe0cf9..ade1c06d4cebed9c30b47ea98c69fe51df89508c 100644 (file)
@@ -175,6 +175,9 @@ static inline int twl_class_is_ ##class(void)       \
 TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
 TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
 
+/* Set the regcache bypass for the regmap associated with the nodule */
+int twl_set_regcache_bypass(u8 mod_no, bool enable);
+
 /*
  * Read and write several 8-bit registers at once.
  */
@@ -667,8 +670,6 @@ struct twl4030_codec_data {
        unsigned int digimic_delay; /* in ms */
        unsigned int ramp_delay_value;
        unsigned int offset_cncl_path;
-       unsigned int check_defaults:1;
-       unsigned int reset_registers:1;
        unsigned int hs_extmute:1;
        int hs_extmute_gpio;
 };
index 9991aea3d577d7dff57481f823b25f521af34903..2f34bb98fe2ab6eb8993febc65dc1db0dd80fe22 100644 (file)
 
 #include <linux/platform_data/dma-ste-dma40.h>
 
-enum msp_i2s_id {
-       MSP_I2S_0 = 0,
-       MSP_I2S_1,
-       MSP_I2S_2,
-       MSP_I2S_3,
-};
-
 /* Platform data structure for a MSP I2S-device */
 struct msp_i2s_platform_data {
-       enum msp_i2s_id id;
+       int id;
        struct stedma40_chan_cfg *msp_i2s_dma_rx;
        struct stedma40_chan_cfg *msp_i2s_dma_tx;
 };
index 06082e5e5dcb7d726e2bdba6e5f2d7f816dcf262..b79a2a864513e4a071879a0cfcc0033678dc1be2 100644 (file)
@@ -50,7 +50,6 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
                                  SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_RESUME |
                                  SNDRV_PCM_INFO_PAUSE,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
        .period_bytes_min       = 256,          /* lighting DMA overhead */
        .period_bytes_max       = 2 * 0xffff,   /* if 2 bytes format */
        .periods_min            = 8,
index 054ea4d9326a2e34f8f9bc6f6ae51f18fb1d98dd..33ec592ecd75d8f6f27c567effcd86551ec1632b 100644 (file)
@@ -58,7 +58,6 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = {
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_PAUSE,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
        .periods_min            = 2,
index 3d82a29ce3a82154273e707a6a072f9fb269c5b3..6a834e109f1de47e533d17e87cdc73d8ee86fc4d 100644 (file)
@@ -1,7 +1,6 @@
 config SND_BCM2835_SOC_I2S
        tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
        depends on ARCH_BCM2835 || COMPILE_TEST
-       select SND_SOC_DMAENGINE_PCM
        select SND_SOC_GENERIC_DMAENGINE_PCM
        select REGMAP_MMIO
        help
index d7c983862cf0a4ca19bb3db19652f5e2c579900b..77f459868579ad7f90d262f683f32e07ae4506a8 100644 (file)
@@ -168,15 +168,15 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        int word_len = 0;
 
        /* bit size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                word_len = AD1836_WORD_LEN_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                word_len = AD1836_WORD_LEN_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 24:
+       case 32:
                word_len = AD1836_WORD_LEN_24;
                break;
        default:
index 12c27eb363dd13c54b9b1f9b297d02eff9643ef5..5a42dca535b77c43f8f63e7131ce09aeb7943e4b 100644 (file)
@@ -249,15 +249,15 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
        /* bit size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                word_len = 3;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                word_len = 1;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 24:
+       case 32:
                word_len = 0;
                break;
        }
index 59654b1e7f3fbcd1262dca4c1066e505980aee2b..eb836ed5271f448631ad1268ddd548b69db39c51 100644 (file)
@@ -1078,17 +1078,17 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
                ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
                (div << 2) | ADAU1373_BCLKDIV_64);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                ctrl = ADAU1373_DAI_WLEN_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                ctrl = ADAU1373_DAI_WLEN_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                ctrl = ADAU1373_DAI_WLEN_24;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                ctrl = ADAU1373_DAI_WLEN_32;
                break;
        default:
index adee866f463f385bb70d9099aa2826eded8de646..d71c59cf7bdd5210ac20ee2c3d76d8d7578385da 100644 (file)
@@ -299,20 +299,20 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
 }
 
 static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
-               snd_pcm_format_t format)
+                                          struct snd_pcm_hw_params *params)
 {
        struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
        unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
        unsigned int val;
 
-       switch (format) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                val = ADAU1701_SEROCTL_WORD_LEN_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                val = ADAU1701_SEROCTL_WORD_LEN_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                val = ADAU1701_SEROCTL_WORD_LEN_24;
                break;
        default:
@@ -320,14 +320,14 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
        }
 
        if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) {
-               switch (format) {
-               case SNDRV_PCM_FORMAT_S16_LE:
+               switch (params_width(params)) {
+               case 16:
                        val |= ADAU1701_SEROCTL_MSB_DEALY16;
                        break;
-               case SNDRV_PCM_FORMAT_S20_3LE:
+               case 20:
                        val |= ADAU1701_SEROCTL_MSB_DEALY12;
                        break;
-               case SNDRV_PCM_FORMAT_S24_LE:
+               case 24:
                        val |= ADAU1701_SEROCTL_MSB_DEALY8;
                        break;
                }
@@ -340,7 +340,7 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
 }
 
 static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
-                       snd_pcm_format_t format)
+                                           struct snd_pcm_hw_params *params)
 {
        struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
@@ -348,14 +348,14 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
        if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
                return 0;
 
-       switch (format) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                val = ADAU1701_SERICTL_RIGHTJ_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                val = ADAU1701_SERICTL_RIGHTJ_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                val = ADAU1701_SERICTL_RIGHTJ_24;
                break;
        default:
@@ -374,7 +374,6 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
        unsigned int clkdiv = adau1701->sysclk / params_rate(params);
-       snd_pcm_format_t format;
        unsigned int val;
        int ret;
 
@@ -406,11 +405,10 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
        regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
                ADAU1701_DSPCTRL_SR_MASK, val);
 
-       format = params_format(params);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return adau1701_set_playback_pcm_format(codec, format);
+               return adau1701_set_playback_pcm_format(codec, params);
        else
-               return adau1701_set_capture_pcm_format(codec, format);
+               return adau1701_set_capture_pcm_format(codec, params);
 }
 
 static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
index f7bf4555274982864478b43af4a710350662d7dc..f78b27a7c461d3e5580dad311fd583f30755a3b4 100644 (file)
@@ -453,22 +453,22 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
 }
 
 static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
-               struct snd_soc_dai *dai, snd_pcm_format_t format)
+               struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
 {
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
 
-       switch (format) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                val = ADAV80X_CAPTURE_WORD_LEN16;
                break;
-       case SNDRV_PCM_FORMAT_S18_3LE:
+       case 18:
                val = ADAV80X_CAPTRUE_WORD_LEN18;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                val = ADAV80X_CAPTURE_WORD_LEN20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                val = ADAV80X_CAPTURE_WORD_LEN24;
                break;
        default:
@@ -482,7 +482,7 @@ static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
 }
 
 static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
-               struct snd_soc_dai *dai, snd_pcm_format_t format)
+               struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
 {
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
@@ -490,17 +490,17 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
        if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
                return 0;
 
-       switch (format) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;
                break;
-       case SNDRV_PCM_FORMAT_S18_3LE:
+       case 18:
                val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
                break;
        default:
@@ -524,12 +524,10 @@ static int adav80x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               adav80x_set_playback_pcm_format(codec, dai,
-                       params_format(params));
+               adav80x_set_playback_pcm_format(codec, dai, params);
                adav80x_set_dac_clock(codec, rate);
        } else {
-               adav80x_set_capture_pcm_format(codec, dai,
-                       params_format(params));
+               adav80x_set_capture_pcm_format(codec, dai, params);
                adav80x_set_adc_clock(codec, rate);
        }
        adav80x->rate = rate;
index 256c364193a54ea6864adbf79640b3480983285a..d3036283482a10814453671ac33f991e46a54b89 100644 (file)
@@ -714,17 +714,17 @@ static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
        iface &= ~ALC5623_DAI_I2S_DL_MASK;
 
        /* bit size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                iface |= ALC5623_DAI_I2S_DL_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                iface |= ALC5623_DAI_I2S_DL_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                iface |= ALC5623_DAI_I2S_DL_24;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                iface |= ALC5623_DAI_I2S_DL_32;
                break;
        default:
index 19e9f222d09c0934cb184843b40ff0ad52b4a1ec..fb001c56cf8d63525d3350f54c96e117454d06bd 100644 (file)
@@ -869,14 +869,14 @@ static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
        iface &= ~ALC5632_DAI_I2S_DL_MASK;
 
        /* bit size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                iface |= ALC5632_DAI_I2S_DL_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                iface |= ALC5632_DAI_I2S_DL_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                iface |= ALC5632_DAI_I2S_DL_24;
                break;
        default:
index 10b398477203a43be5365eab324a0cfba805a1e4..16df0f9133537569c2a84f677e4fcb23d7af1b4e 100644 (file)
@@ -166,20 +166,21 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
 
 #define ARIZONA_DSP_ROUTES(name) \
-       { name, NULL, name " Aux 1" }, \
-       { name, NULL, name " Aux 2" }, \
-       { name, NULL, name " Aux 3" }, \
-       { name, NULL, name " Aux 4" }, \
-       { name, NULL, name " Aux 5" }, \
-       { name, NULL, name " Aux 6" }, \
+       { name, NULL, name " Preloader"}, \
+       { name " Preloader", NULL, name " Aux 1" }, \
+       { name " Preloader", NULL, name " Aux 2" }, \
+       { name " Preloader", NULL, name " Aux 3" }, \
+       { name " Preloader", NULL, name " Aux 4" }, \
+       { name " Preloader", NULL, name " Aux 5" }, \
+       { name " Preloader", NULL, name " Aux 6" }, \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
        ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
-       ARIZONA_MIXER_ROUTES(name, name "L"), \
-       ARIZONA_MIXER_ROUTES(name, name "R")
+       ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
+       ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
 
 #define ARIZONA_RATE_ENUM_SIZE 4
 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
index 1e0fa3b5f79a5e5659ec76acf5c4a70457fad328..6e9ea8379a91272de475985429a21643fbabec22 100644 (file)
@@ -423,21 +423,17 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
                intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               switch (params_format(params)) {
-               case SNDRV_PCM_FORMAT_S16_LE:
-               case SNDRV_PCM_FORMAT_S16_BE:
+               switch (params_width(params)) {
+               case 16:
                        fmt = CS42L51_DAC_DIF_RJ16;
                        break;
-               case SNDRV_PCM_FORMAT_S18_3LE:
-               case SNDRV_PCM_FORMAT_S18_3BE:
+               case 18:
                        fmt = CS42L51_DAC_DIF_RJ18;
                        break;
-               case SNDRV_PCM_FORMAT_S20_3LE:
-               case SNDRV_PCM_FORMAT_S20_3BE:
+               case 20:
                        fmt = CS42L51_DAC_DIF_RJ20;
                        break;
-               case SNDRV_PCM_FORMAT_S24_LE:
-               case SNDRV_PCM_FORMAT_S24_BE:
+               case 24:
                        fmt = CS42L51_DAC_DIF_RJ24;
                        break;
                default:
index 8166dcb2e4a393300b3210d0bcdf3dab5358cba9..e62e294a8033a02ed4e7a90c6c9b41317df79d18 100644 (file)
@@ -778,17 +778,17 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 
        dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                dai_cfg1 |= DA7210_DAI_WORD_S32_LE;
                break;
        default:
index 4a6f1daf911fc0685f16ea5f54fe774bc58581ac..0c77e7ad7423fcf9f7929bfe03d19e4d4427cff1 100644 (file)
@@ -1067,17 +1067,17 @@ static int da7213_hw_params(struct snd_pcm_substream *substream,
        u8 fs;
 
        /* Set DAI format */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE;
                break;
        default:
index dc0284dc9e6f85dde0fa61819b5e86145f55d608..f295b65699105897743fad1ecbc4439a71e58f0e 100644 (file)
@@ -973,17 +973,17 @@ static int da732x_hw_params(struct snd_pcm_substream *substream,
 
        reg_aif = dai->driver->base;
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                aif |= DA732X_AIF_WORD_16;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                aif |= DA732X_AIF_WORD_20;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                aif |= DA732X_AIF_WORD_24;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                aif |= DA732X_AIF_WORD_32;
                break;
        default:
index fc9802d1281dcad0d8ba57ea9d62a02322b5864a..52b79a487ac7db318dd252fe30befd6a3c56b2ec 100644 (file)
@@ -1058,17 +1058,17 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
        u8 aif_ctrl, fs;
        u32 sysclk;
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                aif_ctrl = DA9055_AIF_WORD_S16_LE;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                aif_ctrl = DA9055_AIF_WORD_S20_3LE;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                aif_ctrl = DA9055_AIF_WORD_S24_LE;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                aif_ctrl = DA9055_AIF_WORD_S32_LE;
                break;
        default:
index 53b455b8c07a76dfabd63e46d2ca934a418061bb..5839048ec4674e5d20cc5f06e206c2210977999e 100644 (file)
@@ -951,11 +951,11 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
                        ISABELLE_FS_RATE_MASK, fs_val);
 
        /* bit size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       switch (params_width(params)) {
+       case 20:
                aif |= ISABELLE_AIF_LENGTH_20;
                break;
-       case SNDRV_PCM_FORMAT_S32_LE:
+       case 32:
                aif |= ISABELLE_AIF_LENGTH_32;
                break;
        default:
index 53d7dab4e054ccd93a25986561fc2016da934316..ee660e2d3df3ba0ced0587ee13bab59fc86de6f9 100644 (file)
@@ -1233,12 +1233,12 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
 
        rate = params_rate(params);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
                        M98088_DAI_WS, 0);
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
                        M98088_DAI_WS, M98088_DAI_WS);
                break;
index 0569a4c3ae00e7ce8b8fb27952387d87913f4098..51f9b3d16b41dbf4cc80dddc6d0a081ccb83fe90 100644 (file)
@@ -1840,8 +1840,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 
        max98090->lrclk = params_rate(params);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT,
                        M98090_WS_MASK, 0);
                break;
index 67244315c721994f68ecd5f6df59720a8f03843f..3ba1170ebb53dcdb05d56e043121d83f3a20cbfe 100644 (file)
@@ -1213,12 +1213,12 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
 
        rate = params_rate(params);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
                        M98095_DAI_WS, 0);
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
                        M98095_DAI_WS, M98095_DAI_WS);
                break;
index c5dd61785f8d6318097ae3d0878f881d93e78c29..82757ebf0301df25ab7d2a15da0d6af5cc5623ce 100644 (file)
@@ -149,14 +149,14 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
        snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
        snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
 
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
+       switch (params_width(params)) {
+       case 16:
                da = 0;
                break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
+       case 20:
                da = 0x2;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case 24:
                da = 0x3;
                break;
        default:
index bae60164c7b7355408ab77676daa680bcb5946b0..582c2bbd42cb9eae83346b5fbcd4e497d6101493 100644 (file)
@@ -750,30 +750,26 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
        .num_dapm_routes = ARRAY_SIZE(mc13783_routes),
 };
 
-static int mc13783_codec_probe(struct platform_device *pdev)
+static int __init mc13783_codec_probe(struct platform_device *pdev)
 {
-       struct mc13xxx *mc13xxx;
        struct mc13783_priv *priv;
        struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
        int ret;
 
-       mc13xxx = dev_get_drvdata(pdev->dev.parent);
-
-
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-       if (priv == NULL)
+       if (!priv)
                return -ENOMEM;
 
-       dev_set_drvdata(&pdev->dev, priv);
-       priv->mc13xxx = mc13xxx;
        if (pdata) {
                priv->adc_ssi_port = pdata->adc_ssi_port;
                priv->dac_ssi_port = pdata->dac_ssi_port;
        } else {
-               priv->adc_ssi_port = MC13783_SSI1_PORT;
-               priv->dac_ssi_port = MC13783_SSI2_PORT;
+               return -ENOSYS;
        }
 
+       dev_set_drvdata(&pdev->dev, priv);
+       priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
        if (priv->adc_ssi_port == priv->dac_ssi_port)
                ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
                        mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
@@ -781,14 +777,6 @@ static int mc13783_codec_probe(struct platform_device *pdev)
                ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
                        mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
 
-       if (ret)
-               goto err_register_codec;
-
-       return 0;
-
-err_register_codec:
-       dev_err(&pdev->dev, "register codec failed with %d\n", ret);
-
        return ret;
 }
 
@@ -801,14 +789,12 @@ static int mc13783_codec_remove(struct platform_device *pdev)
 
 static struct platform_driver mc13783_codec_driver = {
        .driver = {
-                  .name = "mc13783-codec",
-                  .owner = THIS_MODULE,
-                  },
-       .probe = mc13783_codec_probe,
+               .name   = "mc13783-codec",
+               .owner  = THIS_MODULE,
+       },
        .remove = mc13783_codec_remove,
 };
-
-module_platform_driver(mc13783_codec_driver);
+module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);
 
 MODULE_DESCRIPTION("ASoC MC13783 driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
index c6dd48561884036c857c445034c3052a04b43a27..af76bbd1b24fbde13e686618c9ab2409a8e18624 100644 (file)
@@ -194,7 +194,7 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {
 };
 
 static const unsigned int ssm2602_rates_12288000[] = {
-       8000, 32000, 48000, 96000,
+       8000, 16000, 32000, 48000, 96000,
 };
 
 static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
@@ -231,6 +231,11 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = {
        {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
        {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
 
+       /* 16k */
+       {12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)},
+       {18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)},
+       {12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)},
+
        /* 8k */
        {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
        {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
@@ -473,9 +478,10 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
-               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-               SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+               SNDRV_PCM_RATE_96000)
 
 #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
index dfc51bb425da93b5dc6e2ac55af8ea3125b9e1b9..00665ada23e20bf37bc2b5e1af81b2a5afe3332e 100644 (file)
 
 #define TWL4030_CACHEREGNUM    (TWL4030_REG_MISC_SET_2 + 1)
 
-/*
- * twl4030 register cache & default register settings
- */
-static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
-       0x00, /* this register not used         */
-       0x00, /* REG_CODEC_MODE         (0x1)   */
-       0x00, /* REG_OPTION             (0x2)   */
-       0x00, /* REG_UNKNOWN            (0x3)   */
-       0x00, /* REG_MICBIAS_CTL        (0x4)   */
-       0x00, /* REG_ANAMICL            (0x5)   */
-       0x00, /* REG_ANAMICR            (0x6)   */
-       0x00, /* REG_AVADC_CTL          (0x7)   */
-       0x00, /* REG_ADCMICSEL          (0x8)   */
-       0x00, /* REG_DIGMIXING          (0x9)   */
-       0x0f, /* REG_ATXL1PGA           (0xA)   */
-       0x0f, /* REG_ATXR1PGA           (0xB)   */
-       0x0f, /* REG_AVTXL2PGA          (0xC)   */
-       0x0f, /* REG_AVTXR2PGA          (0xD)   */
-       0x00, /* REG_AUDIO_IF           (0xE)   */
-       0x00, /* REG_VOICE_IF           (0xF)   */
-       0x3f, /* REG_ARXR1PGA           (0x10)  */
-       0x3f, /* REG_ARXL1PGA           (0x11)  */
-       0x3f, /* REG_ARXR2PGA           (0x12)  */
-       0x3f, /* REG_ARXL2PGA           (0x13)  */
-       0x25, /* REG_VRXPGA             (0x14)  */
-       0x00, /* REG_VSTPGA             (0x15)  */
-       0x00, /* REG_VRX2ARXPGA         (0x16)  */
-       0x00, /* REG_AVDAC_CTL          (0x17)  */
-       0x00, /* REG_ARX2VTXPGA         (0x18)  */
-       0x32, /* REG_ARXL1_APGA_CTL     (0x19)  */
-       0x32, /* REG_ARXR1_APGA_CTL     (0x1A)  */
-       0x32, /* REG_ARXL2_APGA_CTL     (0x1B)  */
-       0x32, /* REG_ARXR2_APGA_CTL     (0x1C)  */
-       0x00, /* REG_ATX2ARXPGA         (0x1D)  */
-       0x00, /* REG_BT_IF              (0x1E)  */
-       0x55, /* REG_BTPGA              (0x1F)  */
-       0x00, /* REG_BTSTPGA            (0x20)  */
-       0x00, /* REG_EAR_CTL            (0x21)  */
-       0x00, /* REG_HS_SEL             (0x22)  */
-       0x00, /* REG_HS_GAIN_SET        (0x23)  */
-       0x00, /* REG_HS_POPN_SET        (0x24)  */
-       0x00, /* REG_PREDL_CTL          (0x25)  */
-       0x00, /* REG_PREDR_CTL          (0x26)  */
-       0x00, /* REG_PRECKL_CTL         (0x27)  */
-       0x00, /* REG_PRECKR_CTL         (0x28)  */
-       0x00, /* REG_HFL_CTL            (0x29)  */
-       0x00, /* REG_HFR_CTL            (0x2A)  */
-       0x05, /* REG_ALC_CTL            (0x2B)  */
-       0x00, /* REG_ALC_SET1           (0x2C)  */
-       0x00, /* REG_ALC_SET2           (0x2D)  */
-       0x00, /* REG_BOOST_CTL          (0x2E)  */
-       0x00, /* REG_SOFTVOL_CTL        (0x2F)  */
-       0x13, /* REG_DTMF_FREQSEL       (0x30)  */
-       0x00, /* REG_DTMF_TONEXT1H      (0x31)  */
-       0x00, /* REG_DTMF_TONEXT1L      (0x32)  */
-       0x00, /* REG_DTMF_TONEXT2H      (0x33)  */
-       0x00, /* REG_DTMF_TONEXT2L      (0x34)  */
-       0x79, /* REG_DTMF_TONOFF        (0x35)  */
-       0x11, /* REG_DTMF_WANONOFF      (0x36)  */
-       0x00, /* REG_I2S_RX_SCRAMBLE_H  (0x37)  */
-       0x00, /* REG_I2S_RX_SCRAMBLE_M  (0x38)  */
-       0x00, /* REG_I2S_RX_SCRAMBLE_L  (0x39)  */
-       0x06, /* REG_APLL_CTL           (0x3A)  */
-       0x00, /* REG_DTMF_CTL           (0x3B)  */
-       0x44, /* REG_DTMF_PGA_CTL2      (0x3C)  */
-       0x69, /* REG_DTMF_PGA_CTL1      (0x3D)  */
-       0x00, /* REG_MISC_SET_1         (0x3E)  */
-       0x00, /* REG_PCMBTMUX           (0x3F)  */
-       0x00, /* not used               (0x40)  */
-       0x00, /* not used               (0x41)  */
-       0x00, /* not used               (0x42)  */
-       0x00, /* REG_RX_PATH_SEL        (0x43)  */
-       0x32, /* REG_VDL_APGA_CTL       (0x44)  */
-       0x00, /* REG_VIBRA_CTL          (0x45)  */
-       0x00, /* REG_VIBRA_SET          (0x46)  */
-       0x00, /* REG_VIBRA_PWM_SET      (0x47)  */
-       0x00, /* REG_ANAMIC_GAIN        (0x48)  */
-       0x00, /* REG_MISC_SET_2         (0x49)  */
-};
-
 /* codec private data */
 struct twl4030_priv {
        unsigned int codec_powered;
@@ -150,81 +70,108 @@ struct twl4030_priv {
        u8 earpiece_enabled;
        u8 predrivel_enabled, predriver_enabled;
        u8 carkitl_enabled, carkitr_enabled;
+       u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1];
 
        struct twl4030_codec_data *pdata;
 };
 
-/*
- * read twl4030 register cache
- */
-static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
-       unsigned int reg)
+static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
 {
-       u8 *cache = codec->reg_cache;
-
-       if (reg >= TWL4030_CACHEREGNUM)
-               return -EIO;
+       int i;
+       u8 byte;
 
-       return cache[reg];
+       for (i = TWL4030_REG_EAR_CTL; i <= TWL4030_REG_PRECKR_CTL; i++) {
+               twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, i);
+               twl4030->ctl_cache[i - TWL4030_REG_EAR_CTL] = byte;
+       }
 }
 
-/*
- * write twl4030 register cache
- */
-static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
-                                               u8 reg, u8 value)
+static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg)
 {
-       u8 *cache = codec->reg_cache;
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+       u8 value = 0;
 
        if (reg >= TWL4030_CACHEREGNUM)
-               return;
-       cache[reg] = value;
+               return -EIO;
+
+       switch (reg) {
+       case TWL4030_REG_EAR_CTL:
+       case TWL4030_REG_PREDL_CTL:
+       case TWL4030_REG_PREDR_CTL:
+       case TWL4030_REG_PRECKL_CTL:
+       case TWL4030_REG_PRECKR_CTL:
+       case TWL4030_REG_HS_GAIN_SET:
+               value = twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL];
+               break;
+       default:
+               twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg);
+               break;
+       }
+
+       return value;
 }
 
-/*
- * write to the twl4030 register space
- */
-static int twl4030_write(struct snd_soc_codec *codec,
-                       unsigned int reg, unsigned int value)
+static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030,
+                                     unsigned int reg)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
-       int write_to_reg = 0;
+       bool write_to_reg = false;
 
-       twl4030_write_reg_cache(codec, reg, value);
        /* Decide if the given register can be written */
        switch (reg) {
        case TWL4030_REG_EAR_CTL:
                if (twl4030->earpiece_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        case TWL4030_REG_PREDL_CTL:
                if (twl4030->predrivel_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        case TWL4030_REG_PREDR_CTL:
                if (twl4030->predriver_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        case TWL4030_REG_PRECKL_CTL:
                if (twl4030->carkitl_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        case TWL4030_REG_PRECKR_CTL:
                if (twl4030->carkitr_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        case TWL4030_REG_HS_GAIN_SET:
                if (twl4030->hsl_enabled || twl4030->hsr_enabled)
-                       write_to_reg = 1;
+                       write_to_reg = true;
                break;
        default:
                /* All other register can be written */
-               write_to_reg = 1;
+               write_to_reg = true;
+               break;
+       }
+
+       return write_to_reg;
+}
+
+static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg,
+                        unsigned int value)
+{
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+
+       /* Update the ctl cache */
+       switch (reg) {
+       case TWL4030_REG_EAR_CTL:
+       case TWL4030_REG_PREDL_CTL:
+       case TWL4030_REG_PREDR_CTL:
+       case TWL4030_REG_PRECKL_CTL:
+       case TWL4030_REG_PRECKR_CTL:
+       case TWL4030_REG_HS_GAIN_SET:
+               twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL] = value;
+               break;
+       default:
                break;
        }
-       if (write_to_reg)
-               return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                           value, reg);
+
+       if (twl4030_can_write_to_chip(twl4030, reg))
+               return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
 
        return 0;
 }
@@ -252,46 +199,14 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
        else
                mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
 
-       if (mode >= 0) {
-               twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode);
+       if (mode >= 0)
                twl4030->codec_powered = enable;
-       }
 
        /* REVISIT: this delay is present in TI sample drivers */
        /* but there seems to be no TRM requirement for it     */
        udelay(10);
 }
 
-static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
-{
-       int i, difference = 0;
-       u8 val;
-
-       dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
-       for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
-               twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
-               if (val != twl4030_reg[i]) {
-                       difference++;
-                       dev_dbg(codec->dev,
-                                "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
-                                i, val, twl4030_reg[i]);
-               }
-       }
-       dev_dbg(codec->dev, "Found %d non-matching registers. %s\n",
-                difference, difference ? "Not OK" : "OK");
-}
-
-static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
-{
-       int i;
-
-       /* set all audio section registers to reasonable defaults */
-       for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
-               if (i != TWL4030_REG_APLL_CTL)
-                       twl4030_write(codec, i, twl4030_reg[i]);
-
-}
-
 static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
                                   struct device_node *node)
 {
@@ -372,27 +287,17 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
                }
        }
 
-       /* Check defaults, if instructed before anything else */
-       if (pdata && pdata->check_defaults)
-               twl4030_check_defaults(codec);
-
-       /* Reset registers, if no setup data or if instructed to do so */
-       if (!pdata || (pdata && pdata->reset_registers))
-               twl4030_reset_registers(codec);
-
-       /* Refresh APLL_CTL register from HW */
-       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
-                           TWL4030_REG_APLL_CTL);
-       twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
+       /* Initialize the local ctl register cache */
+       tw4030_init_ctl_cache(twl4030);
 
        /* anti-pop when changing analog gain */
-       reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+       reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1);
        twl4030_write(codec, TWL4030_REG_MISC_SET_1,
-               reg | TWL4030_SMOOTH_ANAVOL_EN);
+                     reg | TWL4030_SMOOTH_ANAVOL_EN);
 
        twl4030_write(codec, TWL4030_REG_OPTION,
-               TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
-               TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
+                     TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
+                     TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
 
        /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
        twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
@@ -403,19 +308,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 
        twl4030->pdata = pdata;
 
-       reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+       reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
        reg &= ~TWL4030_RAMP_DELAY;
        reg |= (pdata->ramp_delay_value << 2);
-       twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg);
 
        /* initiate offset cancellation */
        twl4030_codec_enable(codec, 1);
 
-       reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+       reg = twl4030_read(codec, TWL4030_REG_ANAMICL);
        reg &= ~TWL4030_OFFSET_CNCL_SEL;
        reg |= pdata->offset_cncl_path;
        twl4030_write(codec, TWL4030_REG_ANAMICL,
-               reg | TWL4030_CNCL_OFFSET_START);
+                     reg | TWL4030_CNCL_OFFSET_START);
 
        /*
         * Wait for offset cancellation to complete.
@@ -425,15 +330,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
        msleep(20);
        do {
                usleep_range(1000, 2000);
+               twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true);
                twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
-                                   TWL4030_REG_ANAMICL);
+                               TWL4030_REG_ANAMICL);
+               twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false);
        } while ((i++ < 100) &&
                 ((byte & TWL4030_CNCL_OFFSET_START) ==
                  TWL4030_CNCL_OFFSET_START));
 
-       /* Make sure that the reg_cache has the same value as the HW */
-       twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
-
        twl4030_codec_enable(codec, 0);
 }
 
@@ -453,9 +357,6 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
                        status = twl4030_audio_disable_resource(
                                                        TWL4030_AUDIO_RES_APLL);
        }
-
-       if (status >= 0)
-               twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
 }
 
 /* Earpiece */
@@ -671,20 +572,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
  */
 #define TWL4030_OUTPUT_PGA(pin_name, reg, mask)                                \
 static int pin_name##pga_event(struct snd_soc_dapm_widget *w,          \
-               struct snd_kcontrol *kcontrol, int event)               \
+                              struct snd_kcontrol *kcontrol, int event) \
 {                                                                      \
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
                                                                        \
        switch (event) {                                                \
        case SND_SOC_DAPM_POST_PMU:                                     \
                twl4030->pin_name##_enabled = 1;                        \
-               twl4030_write(w->codec, reg,                            \
-                       twl4030_read_reg_cache(w->codec, reg));         \
+               twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
                break;                                                  \
        case SND_SOC_DAPM_POST_PMD:                                     \
                twl4030->pin_name##_enabled = 0;                        \
-               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,            \
-                                       0, reg);                        \
+               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 0, reg);   \
                break;                                                  \
        }                                                               \
        return 0;                                                       \
@@ -700,7 +599,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 {
        unsigned char hs_ctl;
 
-       hs_ctl = twl4030_read_reg_cache(codec, reg);
+       hs_ctl = twl4030_read(codec, reg);
 
        if (ramp) {
                /* HF ramp-up */
@@ -727,7 +626,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 }
 
 static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                              struct snd_kcontrol *kcontrol, int event)
 {
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -741,7 +640,7 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 }
 
 static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                              struct snd_kcontrol *kcontrol, int event)
 {
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -755,14 +654,14 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 }
 
 static int vibramux_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                         struct snd_kcontrol *kcontrol, int event)
 {
        twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
        return 0;
 }
 
 static int apll_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                     struct snd_kcontrol *kcontrol, int event)
 {
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -776,11 +675,11 @@ static int apll_event(struct snd_soc_dapm_widget *w,
 }
 
 static int aif_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                    struct snd_kcontrol *kcontrol, int event)
 {
        u8 audio_if;
 
-       audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF);
+       audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                /* Enable AIF */
@@ -788,12 +687,12 @@ static int aif_event(struct snd_soc_dapm_widget *w,
                twl4030_apll_enable(w->codec, 1);
 
                twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
-                                               audio_if | TWL4030_AIF_EN);
+                             audio_if | TWL4030_AIF_EN);
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* disable the DAI before we stop it's source PLL */
                twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
-                                               audio_if &  ~TWL4030_AIF_EN);
+                             audio_if &  ~TWL4030_AIF_EN);
                twl4030_apll_enable(w->codec, 0);
                break;
        }
@@ -810,8 +709,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
                                    8388608, 16777216, 33554432, 67108864};
        unsigned int delay;
 
-       hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
-       hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+       hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET);
+       hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
        delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
                twl4030->sysclk) + 1;
 
@@ -831,9 +730,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
                hs_pop |= TWL4030_VMID_EN;
                twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
                /* Actually write to the register */
-               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                       hs_gain,
-                                       TWL4030_REG_HS_GAIN_SET);
+               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain,
+                                TWL4030_REG_HS_GAIN_SET);
                hs_pop |= TWL4030_RAMP_EN;
                twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
                /* Wait ramp delay time + 1, so the VMID can settle */
@@ -846,9 +744,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
                /* Wait ramp delay time + 1, so the VMID can settle */
                twl4030_wait_ms(delay);
                /* Bypass the reg_cache to mute the headset */
-               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                       hs_gain & (~0x0f),
-                                       TWL4030_REG_HS_GAIN_SET);
+               twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f),
+                                TWL4030_REG_HS_GAIN_SET);
 
                hs_pop &= ~TWL4030_VMID_EN;
                twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -866,7 +763,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 }
 
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                            struct snd_kcontrol *kcontrol, int event)
 {
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
 
@@ -890,7 +787,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 }
 
 static int headsetrpga_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                            struct snd_kcontrol *kcontrol, int event)
 {
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
 
@@ -914,7 +811,7 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 }
 
 static int digimic_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+                        struct snd_kcontrol *kcontrol, int event)
 {
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
        struct twl4030_codec_data *pdata = twl4030->pdata;
@@ -935,7 +832,7 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
  * Custom volsw and volsw_2r get/put functions to handle these gain bits.
  */
 static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -964,7 +861,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
 }
 
 static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -993,7 +890,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
 }
 
 static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -1020,7 +917,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 }
 
 static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -1751,11 +1648,11 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
 /* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
  * capture has to be enabled/disabled. */
 static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
-                               int enable)
+                              int enable)
 {
        u8 reg, mask;
 
-       reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+       reg = twl4030_read(codec, TWL4030_REG_OPTION);
 
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
                mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
@@ -1784,14 +1681,14 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
                if (twl4030->configured)
                        twl4030_constraints(twl4030, twl4030->master_substream);
        } else {
-               if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
+               if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) &
                        TWL4030_OPTION_1)) {
                        /* In option2 4 channel is not supported, set the
                         * constraint for the first stream for channels, the
                         * second stream will 'inherit' this cosntraint */
                        snd_pcm_hw_constraint_minmax(substream->runtime,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS,
-                                               2, 2);
+                                                    SNDRV_PCM_HW_PARAM_CHANNELS,
+                                                    2, 2);
                }
                twl4030->master_substream = substream;
        }
@@ -1823,8 +1720,8 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
 }
 
 static int twl4030_hw_params(struct snd_pcm_substream *substream,
-                          struct snd_pcm_hw_params *params,
-                          struct snd_soc_dai *dai)
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -1832,8 +1729,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 
         /* If the substream has 4 channel, do the necessary setup */
        if (params_channels(params) == 4) {
-               format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
-               mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+               format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+               mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE);
 
                /* Safety check: are we in the correct operating mode and
                 * the interface is in TDM mode? */
@@ -1849,8 +1746,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
                return 0;
 
        /* bit rate */
-       old_mode = twl4030_read_reg_cache(codec,
-                       TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+       old_mode = twl4030_read(codec,
+                               TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
        mode = old_mode & ~TWL4030_APLL_RATE;
 
        switch (params_rate(params)) {
@@ -1891,7 +1788,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* sample size */
-       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+       old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
        format = old_format;
        format &= ~TWL4030_DATA_WIDTH;
        switch (params_format(params)) {
@@ -1940,8 +1837,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
-               int clk_id, unsigned int freq, int dir)
+static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+                                 unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -1966,15 +1863,14 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
-                            unsigned int fmt)
+static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 old_format, format;
 
        /* get format */
-       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+       old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
        format = old_format;
 
        /* set master/slave audio interface */
@@ -2024,7 +1920,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+       u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
 
        if (tristate)
                reg |= TWL4030_AIF_TRI_EN;
@@ -2037,11 +1933,11 @@ static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
 /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
  * (VTXL, VTXR) for uplink has to be enabled/disabled. */
 static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
-                               int enable)
+                                int enable)
 {
        u8 reg, mask;
 
-       reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+       reg = twl4030_read(codec, TWL4030_REG_OPTION);
 
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
                mask = TWL4030_ARXL1_VRX_EN;
@@ -2057,7 +1953,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
 }
 
 static int twl4030_voice_startup(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
+                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2076,7 +1972,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
        /* If the codec mode is not option2, the voice PCM interface is not
         * available.
         */
-       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+       mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE)
                & TWL4030_OPT_MODE;
 
        if (mode != TWL4030_OPTION_2) {
@@ -2089,7 +1985,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
 }
 
 static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
+                                  struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
 
@@ -2098,7 +1994,8 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
 }
 
 static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2108,8 +2005,8 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
        twl4030_voice_enable(codec, substream->stream, 1);
 
        /* bit rate */
-       old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
-               & ~(TWL4030_CODECPDZ);
+       old_mode = twl4030_read(codec,
+                               TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
        mode = old_mode;
 
        switch (params_rate(params)) {
@@ -2143,7 +2040,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
 }
 
 static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
-               int clk_id, unsigned int freq, int dir)
+                                       int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2164,14 +2061,14 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 }
 
 static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
-               unsigned int fmt)
+                                    unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 old_format, format;
 
        /* get format */
-       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+       old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF);
        format = old_format;
 
        /* set master/slave audio interface */
@@ -2218,7 +2115,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+       u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF);
 
        if (tristate)
                reg |= TWL4030_VIF_TRI_EN;
@@ -2310,8 +2207,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        struct twl4030_codec_data *pdata = twl4030->pdata;
 
-       /* Reset registers to their chip default before leaving */
-       twl4030_reset_registers(codec);
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
@@ -2323,13 +2218,10 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
        .probe = twl4030_soc_probe,
        .remove = twl4030_soc_remove,
-       .read = twl4030_read_reg_cache,
+       .read = twl4030_read,
        .write = twl4030_write,
        .set_bias_level = twl4030_set_bias_level,
        .idle_bias_off = true,
-       .reg_cache_size = sizeof(twl4030_reg),
-       .reg_word_size = sizeof(u8),
-       .reg_cache_default = twl4030_reg,
 
        .controls = twl4030_snd_controls,
        .num_controls = ARRAY_SIZE(twl4030_snd_controls),
@@ -2342,7 +2234,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 static int twl4030_codec_probe(struct platform_device *pdev)
 {
        return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
-                       twl4030_dai, ARRAY_SIZE(twl4030_dai));
+                                     twl4030_dai, ARRAY_SIZE(twl4030_dai));
 }
 
 static int twl4030_codec_remove(struct platform_device *pdev)
index fb0c678939bf2eb12a4ad2dd12c2b262366fb3eb..444626fcab40d42aed3b6df03e9cf86f43dd3423 100644 (file)
@@ -1497,107 +1497,149 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
        return 0;
 }
 
-int wm_adsp2_event(struct snd_soc_dapm_widget *w,
-                  struct snd_kcontrol *kcontrol, int event)
+static void wm_adsp2_boot_work(struct work_struct *work)
 {
-       struct snd_soc_codec *codec = w->codec;
-       struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
-       struct wm_adsp *dsp = &dsps[w->shift];
-       struct wm_adsp_alg_region *alg_region;
-       struct wm_coeff_ctl *ctl;
-       unsigned int val;
+       struct wm_adsp *dsp = container_of(work,
+                                          struct wm_adsp,
+                                          boot_work);
        int ret;
+       unsigned int val;
 
-       dsp->card = codec->card;
+       /*
+        * For simplicity set the DSP clock rate to be the
+        * SYSCLK rate rather than making it configurable.
+        */
+       ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
+               return;
+       }
+       val = (val & ARIZONA_SYSCLK_FREQ_MASK)
+               >> ARIZONA_SYSCLK_FREQ_SHIFT;
 
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               /*
-                * For simplicity set the DSP clock rate to be the
-                * SYSCLK rate rather than making it configurable.
-                */
-               ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
-                                ret);
-                       return ret;
-               }
-               val = (val & ARIZONA_SYSCLK_FREQ_MASK)
-                       >> ARIZONA_SYSCLK_FREQ_SHIFT;
+       ret = regmap_update_bits_async(dsp->regmap,
+                                      dsp->base + ADSP2_CLOCKING,
+                                      ADSP2_CLK_SEL_MASK, val);
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+               return;
+       }
 
-               ret = regmap_update_bits_async(dsp->regmap,
-                                              dsp->base + ADSP2_CLOCKING,
-                                              ADSP2_CLK_SEL_MASK, val);
+       if (dsp->dvfs) {
+               ret = regmap_read(dsp->regmap,
+                                 dsp->base + ADSP2_CLOCKING, &val);
                if (ret != 0) {
-                       adsp_err(dsp, "Failed to set clock rate: %d\n",
-                                ret);
-                       return ret;
+                       dev_err(dsp->dev, "Failed to read clocking: %d\n", ret);
+                       return;
                }
 
-               if (dsp->dvfs) {
-                       ret = regmap_read(dsp->regmap,
-                                         dsp->base + ADSP2_CLOCKING, &val);
+               if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
+                       ret = regulator_enable(dsp->dvfs);
                        if (ret != 0) {
                                dev_err(dsp->dev,
-                                       "Failed to read clocking: %d\n", ret);
-                               return ret;
+                                       "Failed to enable supply: %d\n",
+                                       ret);
+                               return;
                        }
 
-                       if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
-                               ret = regulator_enable(dsp->dvfs);
-                               if (ret != 0) {
-                                       dev_err(dsp->dev,
-                                               "Failed to enable supply: %d\n",
-                                               ret);
-                                       return ret;
-                               }
-
-                               ret = regulator_set_voltage(dsp->dvfs,
-                                                           1800000,
-                                                           1800000);
-                               if (ret != 0) {
-                                       dev_err(dsp->dev,
-                                               "Failed to raise supply: %d\n",
-                                               ret);
-                                       return ret;
-                               }
+                       ret = regulator_set_voltage(dsp->dvfs,
+                                                   1800000,
+                                                   1800000);
+                       if (ret != 0) {
+                               dev_err(dsp->dev,
+                                       "Failed to raise supply: %d\n",
+                                       ret);
+                               return;
                        }
                }
+       }
 
-               ret = wm_adsp2_ena(dsp);
-               if (ret != 0)
-                       return ret;
+       ret = wm_adsp2_ena(dsp);
+       if (ret != 0)
+               return;
 
-               ret = wm_adsp_load(dsp);
-               if (ret != 0)
-                       goto err;
+       ret = wm_adsp_load(dsp);
+       if (ret != 0)
+               goto err;
 
-               ret = wm_adsp_setup_algs(dsp);
-               if (ret != 0)
-                       goto err;
+       ret = wm_adsp_setup_algs(dsp);
+       if (ret != 0)
+               goto err;
 
-               ret = wm_adsp_load_coeff(dsp);
-               if (ret != 0)
-                       goto err;
+       ret = wm_adsp_load_coeff(dsp);
+       if (ret != 0)
+               goto err;
 
-               /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp);
-               if (ret != 0)
-                       goto err;
+       /* Initialize caches for enabled and unset controls */
+       ret = wm_coeff_init_control_caches(dsp);
+       if (ret != 0)
+               goto err;
 
-               /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp);
-               if (ret != 0)
-                       goto err;
+       /* Sync set controls */
+       ret = wm_coeff_sync_controls(dsp);
+       if (ret != 0)
+               goto err;
+
+       ret = regmap_update_bits_async(dsp->regmap,
+                                      dsp->base + ADSP2_CONTROL,
+                                      ADSP2_CORE_ENA,
+                                      ADSP2_CORE_ENA);
+       if (ret != 0)
+               goto err;
+
+       dsp->running = true;
+
+       return;
+
+err:
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                          ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+}
+
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+       struct wm_adsp *dsp = &dsps[w->shift];
+
+       dsp->card = codec->card;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               queue_work(system_unbound_wq, &dsp->boot_work);
+               break;
+       default:
+               break;
+       };
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+       struct wm_adsp *dsp = &dsps[w->shift];
+       struct wm_adsp_alg_region *alg_region;
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               flush_work(&dsp->boot_work);
+
+               if (!dsp->running)
+                       return -EIO;
 
-               ret = regmap_update_bits_async(dsp->regmap,
-                                              dsp->base + ADSP2_CONTROL,
-                                              ADSP2_CORE_ENA | ADSP2_START,
-                                              ADSP2_CORE_ENA | ADSP2_START);
+               ret = regmap_update_bits(dsp->regmap,
+                                        dsp->base + ADSP2_CONTROL,
+                                        ADSP2_START,
+                                        ADSP2_START);
                if (ret != 0)
                        goto err;
-
-               dsp->running = true;
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
@@ -1668,6 +1710,7 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
 
        INIT_LIST_HEAD(&adsp->alg_regions);
        INIT_LIST_HEAD(&adsp->ctl_list);
+       INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
 
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
index d018dea6254de44c5997813fcb9b958eeca09706..a4f6b64deb61bcec9729d5d8355b135b647774c8 100644 (file)
@@ -59,6 +59,8 @@ struct wm_adsp {
        struct regulator *dvfs;
 
        struct list_head ctl_list;
+
+       struct work_struct boot_work;
 };
 
 #define WM_ADSP1(wname, num) \
@@ -66,8 +68,12 @@ struct wm_adsp {
                wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
 #define WM_ADSP2(wname, num) \
-       SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
-               wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+{      .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
+       .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU }, \
+{      .id = snd_soc_dapm_out_drv, .name = wname, \
+       .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
 extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
 extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
@@ -76,6 +82,8 @@ int wm_adsp1_init(struct wm_adsp *adsp);
 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event);
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 
index 514c275c6108ba52d2503870c4225afdc66b6dc9..324988dea4bd31bd8ad8f6d416c701c2f874966f 100644 (file)
@@ -8,6 +8,9 @@ config SND_SOC_FSL_SSI
 config SND_SOC_FSL_SPDIF
        tristate
 
+config SND_SOC_FSL_ESAI
+       tristate
+
 config SND_SOC_FSL_UTILS
        tristate
 
index aaccbee17006776a4bda27a779567d4c4c1655af..b12ad4b9b4daa56599cc7cd92b1a861a3b7ce785 100644 (file)
@@ -14,11 +14,13 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-spdif-objs := fsl_spdif.o
+snd-soc-fsl-esai-objs := fsl_esai.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
 obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
+obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
index d570f8c81dc666fb1f6653c7e9e2a5a128b3fb5a..6bb0ea59284f0b4fab317f1b8ee263f7d1f7c341 100644 (file)
                            SNDRV_PCM_FMTBIT_S32_BE     | \
                            SNDRV_PCM_FMTBIT_U32_LE     | \
                            SNDRV_PCM_FMTBIT_U32_BE)
-
-#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
-                         SNDRV_PCM_RATE_CONTINUOUS)
-
 struct dma_object {
        struct snd_soc_platform_driver dai;
        dma_addr_t ssi_stx_phys;
@@ -140,9 +136,6 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
                                  SNDRV_PCM_INFO_JOINT_DUPLEX |
                                  SNDRV_PCM_INFO_PAUSE,
        .formats                = FSLDMA_PCM_FORMATS,
-       .rates                  = FSLDMA_PCM_RATES,
-       .rate_min               = 5512,
-       .rate_max               = 192000,
        .period_bytes_min       = 512,          /* A reasonable limit */
        .period_bytes_max       = (u32) -1,
        .periods_min            = NUM_DMA_LINKS,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644 (file)
index 0000000..d0c72ed
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+ * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_esai.h"
+#include "imx-pcm.h"
+
+#define FSL_ESAI_RATES         SNDRV_PCM_RATE_8000_192000
+#define FSL_ESAI_FORMATS       (SNDRV_PCM_FMTBIT_S8 | \
+                               SNDRV_PCM_FMTBIT_S16_LE | \
+                               SNDRV_PCM_FMTBIT_S20_3LE | \
+                               SNDRV_PCM_FMTBIT_S24_LE)
+
+/**
+ * fsl_esai: ESAI private data
+ *
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @coreclk: clock source to access register
+ * @extalclk: esai clock source to derive HCK, SCK and FS
+ * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @fifo_depth: depth of tx/rx FIFO
+ * @slot_width: width of each DAI slot
+ * @hck_rate: clock rate of desired HCKx clock
+ * @sck_div: if using PSR/PM dividers for SCKx clock
+ * @slave_mode: if fully using DAI slave mode
+ * @synchronous: if using tx/rx synchronous mode
+ * @name: driver name
+ */
+struct fsl_esai {
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       struct clk *coreclk;
+       struct clk *extalclk;
+       struct clk *fsysclk;
+       u32 fifo_depth;
+       u32 slot_width;
+       u32 hck_rate[2];
+       bool sck_div[2];
+       bool slave_mode;
+       bool synchronous;
+       char name[32];
+};
+
+static irqreturn_t esai_isr(int irq, void *devid)
+{
+       struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
+       struct platform_device *pdev = esai_priv->pdev;
+       u32 esr;
+
+       regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
+
+       if (esr & ESAI_ESR_TINIT_MASK)
+               dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
+
+       if (esr & ESAI_ESR_RFF_MASK)
+               dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+
+       if (esr & ESAI_ESR_TFE_MASK)
+               dev_warn(&pdev->dev, "isr: Transmition underrun\n");
+
+       if (esr & ESAI_ESR_TLS_MASK)
+               dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
+
+       if (esr & ESAI_ESR_TDE_MASK)
+               dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
+
+       if (esr & ESAI_ESR_TED_MASK)
+               dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
+
+       if (esr & ESAI_ESR_TD_MASK)
+               dev_dbg(&pdev->dev, "isr: Transmitting data\n");
+
+       if (esr & ESAI_ESR_RLS_MASK)
+               dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
+
+       if (esr & ESAI_ESR_RDE_MASK)
+               dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
+
+       if (esr & ESAI_ESR_RED_MASK)
+               dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
+
+       if (esr & ESAI_ESR_RD_MASK)
+               dev_dbg(&pdev->dev, "isr: Receiving data\n");
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * This function is used to calculate the divisors of psr, pm, fp and it is
+ * supposed to be called in set_dai_sysclk() and set_bclk().
+ *
+ * @ratio: desired overall ratio for the paticipating dividers
+ * @usefp: for HCK setting, there is no need to set fp divider
+ * @fp: bypass other dividers by setting fp directly if fp != 0
+ * @tx: current setting is for playback or capture
+ */
+static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
+                               bool usefp, u32 fp)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
+
+       maxfp = usefp ? 16 : 1;
+
+       if (usefp && fp)
+               goto out_fp;
+
+       if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
+               dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
+                               2 * 8 * 256 * maxfp);
+               return -EINVAL;
+       } else if (ratio % 2) {
+               dev_err(dai->dev, "the raio must be even if using upper divider\n");
+               return -EINVAL;
+       }
+
+       ratio /= 2;
+
+       psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
+
+       /* Set the max fluctuation -- 0.1% of the max devisor */
+       savesub = (psr ? 1 : 8)  * 256 * maxfp / 1000;
+
+       /* Find the best value for PM */
+       for (i = 1; i <= 256; i++) {
+               for (j = 1; j <= maxfp; j++) {
+                       /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
+                       prod = (psr ? 1 : 8) * i * j;
+
+                       if (prod == ratio)
+                               sub = 0;
+                       else if (prod / ratio == 1)
+                               sub = prod - ratio;
+                       else if (ratio / prod == 1)
+                               sub = ratio - prod;
+                       else
+                               continue;
+
+                       /* Calculate the fraction */
+                       sub = sub * 1000 / ratio;
+                       if (sub < savesub) {
+                               savesub = sub;
+                               pm = i;
+                               fp = j;
+                       }
+
+                       /* We are lucky */
+                       if (savesub == 0)
+                               goto out;
+               }
+       }
+
+       if (pm == 999) {
+               dev_err(dai->dev, "failed to calculate proper divisors\n");
+               return -EINVAL;
+       }
+
+out:
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+                          ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+                          psr | ESAI_xCCR_xPM(pm));
+
+out_fp:
+       /* Bypass fp if not being required */
+       if (maxfp <= 1)
+               return 0;
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+                          ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+
+       return 0;
+}
+
+/**
+ * This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
+ *
+ * @Parameters:
+ * clk_id: The clock source of HCKT/HCKR
+ *       (Input from outside; output from inside, FSYS or EXTAL)
+ * freq: The required clock rate of HCKT/HCKR
+ * dir: The clock direction of HCKT/HCKR
+ *
+ * Note: If the direction is input, we do not care about clk_id.
+ */
+static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                  unsigned int freq, int dir)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       struct clk *clksrc = esai_priv->extalclk;
+       bool tx = clk_id <= ESAI_HCKT_EXTAL;
+       bool in = dir == SND_SOC_CLOCK_IN;
+       u32 ret, ratio, ecr = 0;
+       unsigned long clk_rate;
+
+       /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
+       esai_priv->sck_div[tx] = true;
+
+       /* Set the direction of HCKT/HCKR pins */
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+                          ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
+
+       if (in)
+               goto out;
+
+       switch (clk_id) {
+       case ESAI_HCKT_FSYS:
+       case ESAI_HCKR_FSYS:
+               clksrc = esai_priv->fsysclk;
+               break;
+       case ESAI_HCKT_EXTAL:
+               ecr |= ESAI_ECR_ETI;
+       case ESAI_HCKR_EXTAL:
+               ecr |= ESAI_ECR_ERI;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (IS_ERR(clksrc)) {
+               dev_err(dai->dev, "no assigned %s clock\n",
+                               clk_id % 2 ? "extal" : "fsys");
+               return PTR_ERR(clksrc);
+       }
+       clk_rate = clk_get_rate(clksrc);
+
+       ratio = clk_rate / freq;
+       if (ratio * freq > clk_rate)
+               ret = ratio * freq - clk_rate;
+       else if (ratio * freq < clk_rate)
+               ret = clk_rate - ratio * freq;
+       else
+               ret = 0;
+
+       /* Block if clock source can not be divided into the required rate */
+       if (ret != 0 && clk_rate / ret < 1000) {
+               dev_err(dai->dev, "failed to derive required HCK%c rate\n",
+                               tx ? 'T' : 'R');
+               return -EINVAL;
+       }
+
+       if (ratio == 1) {
+               /* Bypass all the dividers if not being needed */
+               ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
+               goto out;
+       }
+
+       ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
+       if (ret)
+               return ret;
+
+       esai_priv->sck_div[tx] = false;
+
+out:
+       esai_priv->hck_rate[tx] = freq;
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
+                          tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :
+                          ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
+
+       return 0;
+}
+
+/**
+ * This function configures the related dividers according to the bclk rate
+ */
+static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       u32 hck_rate = esai_priv->hck_rate[tx];
+       u32 sub, ratio = hck_rate / freq;
+
+       /* Don't apply for fully slave mode*/
+       if (esai_priv->slave_mode)
+               return 0;
+
+       if (ratio * freq > hck_rate)
+               sub = ratio * freq - hck_rate;
+       else if (ratio * freq < hck_rate)
+               sub = hck_rate - ratio * freq;
+       else
+               sub = 0;
+
+       /* Block if clock source can not be divided into the required rate */
+       if (sub != 0 && hck_rate / sub < 1000) {
+               dev_err(dai->dev, "failed to derive required SCK%c rate\n",
+                               tx ? 'T' : 'R');
+               return -EINVAL;
+       }
+
+       if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
+               dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
+               return -EINVAL;
+       }
+
+       return fsl_esai_divisor_cal(dai, tx, ratio, true,
+                       esai_priv->sck_div[tx] ? 0 : ratio);
+}
+
+static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
+                                    u32 rx_mask, int slots, int slot_width)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+                          ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
+                          ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
+                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+                          ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
+                          ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
+                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+
+       esai_priv->slot_width = slot_width;
+
+       return 0;
+}
+
+static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       u32 xcr = 0, xccr = 0, mask;
+
+       /* DAI mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               /* Data on rising edge of bclk, frame low, 1clk before data */
+               xcr |= ESAI_xCR_xFSR;
+               xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* Data on rising edge of bclk, frame high */
+               xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               /* Data on rising edge of bclk, frame high, right aligned */
+               xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* Data on rising edge of bclk, frame high, 1clk before data */
+               xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+               xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               /* Data on rising edge of bclk, frame high */
+               xcr |= ESAI_xCR_xFSL;
+               xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* DAI clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /* Nothing to do for both normal cases */
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               /* Invert bit clock */
+               xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               /* Invert frame clock */
+               xccr ^= ESAI_xCCR_xFSP;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               /* Invert both clocks */
+               xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       esai_priv->slave_mode = false;
+
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               esai_priv->slave_mode = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               xccr |= ESAI_xCCR_xCKD;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               xccr |= ESAI_xCCR_xFSD;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
+
+       mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
+               ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
+
+       return 0;
+}
+
+static int fsl_esai_startup(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+       /*
+        * Some platforms might use the same bit to gate all three or two of
+        * clocks, so keep all clocks open/close at the same time for safety
+        */
+       clk_prepare_enable(esai_priv->coreclk);
+       if (!IS_ERR(esai_priv->extalclk))
+               clk_prepare_enable(esai_priv->extalclk);
+       if (!IS_ERR(esai_priv->fsysclk))
+               clk_prepare_enable(esai_priv->fsysclk);
+
+       if (!dai->active) {
+               /* Reset Port C */
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
+                                  ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
+                                  ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
+
+               /* Set synchronous mode */
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
+                                  ESAI_SAICR_SYNC, esai_priv->synchronous ?
+                                  ESAI_SAICR_SYNC : 0);
+
+               /* Set a default slot number -- 2 */
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+                                  ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+                                  ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+       }
+
+       return 0;
+}
+
+static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *dai)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u32 width = snd_pcm_format_width(params_format(params));
+       u32 channels = params_channels(params);
+       u32 bclk, mask, val, ret;
+
+       bclk = params_rate(params) * esai_priv->slot_width * 2;
+
+       ret = fsl_esai_set_bclk(dai, tx, bclk);
+       if (ret)
+               return ret;
+
+       /* Use Normal mode to support monaural audio */
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+                          ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
+                          ESAI_xCR_xMOD_NETWORK : 0);
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+                          ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
+
+       mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
+             (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
+       val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
+            (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
+
+       mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
+       val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+
+       regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+
+       return 0;
+}
+
+static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+       if (!IS_ERR(esai_priv->fsysclk))
+               clk_disable_unprepare(esai_priv->fsysclk);
+       if (!IS_ERR(esai_priv->extalclk))
+               clk_disable_unprepare(esai_priv->extalclk);
+       clk_disable_unprepare(esai_priv->coreclk);
+}
+
+static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u8 i, channels = substream->runtime->channels;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+                                  ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
+
+               /* Write initial words reqiured by ESAI as normal procedure */
+               for (i = 0; tx && i < channels; i++)
+                       regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
+
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+                                  tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
+                                  tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+                                  tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
+
+               /* Disable and reset FIFO */
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+                                  ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
+               regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+                                  ESAI_xFCR_xFR, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+       .startup = fsl_esai_startup,
+       .shutdown = fsl_esai_shutdown,
+       .trigger = fsl_esai_trigger,
+       .hw_params = fsl_esai_hw_params,
+       .set_sysclk = fsl_esai_set_dai_sysclk,
+       .set_fmt = fsl_esai_set_dai_fmt,
+       .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
+static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
+{
+       struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
+                                 &esai_priv->dma_params_rx);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+       .probe = fsl_esai_dai_probe,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 12,
+               .rates = FSL_ESAI_RATES,
+               .formats = FSL_ESAI_FORMATS,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = FSL_ESAI_RATES,
+               .formats = FSL_ESAI_FORMATS,
+       },
+       .ops = &fsl_esai_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_esai_component = {
+       .name           = "fsl-esai",
+};
+
+static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_ESAI_ERDR:
+       case REG_ESAI_ECR:
+       case REG_ESAI_ESR:
+       case REG_ESAI_TFCR:
+       case REG_ESAI_TFSR:
+       case REG_ESAI_RFCR:
+       case REG_ESAI_RFSR:
+       case REG_ESAI_RX0:
+       case REG_ESAI_RX1:
+       case REG_ESAI_RX2:
+       case REG_ESAI_RX3:
+       case REG_ESAI_SAISR:
+       case REG_ESAI_SAICR:
+       case REG_ESAI_TCR:
+       case REG_ESAI_TCCR:
+       case REG_ESAI_RCR:
+       case REG_ESAI_RCCR:
+       case REG_ESAI_TSMA:
+       case REG_ESAI_TSMB:
+       case REG_ESAI_RSMA:
+       case REG_ESAI_RSMB:
+       case REG_ESAI_PRRC:
+       case REG_ESAI_PCRC:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_ESAI_ETDR:
+       case REG_ESAI_ECR:
+       case REG_ESAI_TFCR:
+       case REG_ESAI_RFCR:
+       case REG_ESAI_TX0:
+       case REG_ESAI_TX1:
+       case REG_ESAI_TX2:
+       case REG_ESAI_TX3:
+       case REG_ESAI_TX4:
+       case REG_ESAI_TX5:
+       case REG_ESAI_TSR:
+       case REG_ESAI_SAICR:
+       case REG_ESAI_TCR:
+       case REG_ESAI_TCCR:
+       case REG_ESAI_RCR:
+       case REG_ESAI_RCCR:
+       case REG_ESAI_TSMA:
+       case REG_ESAI_TSMB:
+       case REG_ESAI_RSMA:
+       case REG_ESAI_RSMB:
+       case REG_ESAI_PRRC:
+       case REG_ESAI_PCRC:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config fsl_esai_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .max_register = REG_ESAI_PCRC,
+       .readable_reg = fsl_esai_readable_reg,
+       .writeable_reg = fsl_esai_writeable_reg,
+};
+
+static int fsl_esai_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct fsl_esai *esai_priv;
+       struct resource *res;
+       const uint32_t *iprop;
+       void __iomem *regs;
+       int irq, ret;
+
+       esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
+       if (!esai_priv)
+               return -ENOMEM;
+
+       esai_priv->pdev = pdev;
+       strcpy(esai_priv->name, np->name);
+
+       /* Get the addresses and IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "core", regs, &fsl_esai_regmap_config);
+       if (IS_ERR(esai_priv->regmap)) {
+               dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+                               PTR_ERR(esai_priv->regmap));
+               return PTR_ERR(esai_priv->regmap);
+       }
+
+       esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+       if (IS_ERR(esai_priv->coreclk)) {
+               dev_err(&pdev->dev, "failed to get core clock: %ld\n",
+                               PTR_ERR(esai_priv->coreclk));
+               return PTR_ERR(esai_priv->coreclk);
+       }
+
+       esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
+       if (IS_ERR(esai_priv->extalclk))
+               dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
+                               PTR_ERR(esai_priv->extalclk));
+
+       esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
+       if (IS_ERR(esai_priv->fsysclk))
+               dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
+                               PTR_ERR(esai_priv->fsysclk));
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
+                              esai_priv->name, esai_priv);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               return ret;
+       }
+
+       /* Set a default slot size */
+       esai_priv->slot_width = 32;
+
+       /* Set a default master/slave state */
+       esai_priv->slave_mode = true;
+
+       /* Determine the FIFO depth */
+       iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+       if (iprop)
+               esai_priv->fifo_depth = be32_to_cpup(iprop);
+       else
+               esai_priv->fifo_depth = 64;
+
+       esai_priv->dma_params_tx.maxburst = 16;
+       esai_priv->dma_params_rx.maxburst = 16;
+       esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
+       esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
+
+       esai_priv->synchronous =
+               of_property_read_bool(np, "fsl,esai-synchronous");
+
+       /* Implement full symmetry for synchronous mode */
+       if (esai_priv->synchronous) {
+               fsl_esai_dai.symmetric_rates = 1;
+               fsl_esai_dai.symmetric_channels = 1;
+               fsl_esai_dai.symmetric_samplebits = 1;
+       }
+
+       dev_set_drvdata(&pdev->dev, esai_priv);
+
+       /* Reset ESAI unit */
+       ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * We need to enable ESAI so as to access some of its registers.
+        * Otherwise, we would fail to dump regmap from user space.
+        */
+       ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
+                                             &fsl_esai_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+               return ret;
+       }
+
+       ret = imx_pcm_dma_init(pdev);
+       if (ret)
+               dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+       return ret;
+}
+
+static const struct of_device_id fsl_esai_dt_ids[] = {
+       { .compatible = "fsl,imx35-esai", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
+
+static struct platform_driver fsl_esai_driver = {
+       .probe = fsl_esai_probe,
+       .driver = {
+               .name = "fsl-esai-dai",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_esai_dt_ids,
+       },
+};
+
+module_platform_driver(fsl_esai_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-esai-dai");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644 (file)
index 0000000..9c9f957
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_ESAI_DAI_H
+#define _FSL_ESAI_DAI_H
+
+/* ESAI Register Map */
+#define REG_ESAI_ETDR          0x00
+#define REG_ESAI_ERDR          0x04
+#define REG_ESAI_ECR           0x08
+#define REG_ESAI_ESR           0x0C
+#define REG_ESAI_TFCR          0x10
+#define REG_ESAI_TFSR          0x14
+#define REG_ESAI_RFCR          0x18
+#define REG_ESAI_RFSR          0x1C
+#define REG_ESAI_xFCR(tx)      (tx ? REG_ESAI_TFCR : REG_ESAI_RFCR)
+#define REG_ESAI_xFSR(tx)      (tx ? REG_ESAI_TFSR : REG_ESAI_RFSR)
+#define REG_ESAI_TX0           0x80
+#define REG_ESAI_TX1           0x84
+#define REG_ESAI_TX2           0x88
+#define REG_ESAI_TX3           0x8C
+#define REG_ESAI_TX4           0x90
+#define REG_ESAI_TX5           0x94
+#define REG_ESAI_TSR           0x98
+#define REG_ESAI_RX0           0xA0
+#define REG_ESAI_RX1           0xA4
+#define REG_ESAI_RX2           0xA8
+#define REG_ESAI_RX3           0xAC
+#define REG_ESAI_SAISR         0xCC
+#define REG_ESAI_SAICR         0xD0
+#define REG_ESAI_TCR           0xD4
+#define REG_ESAI_TCCR          0xD8
+#define REG_ESAI_RCR           0xDC
+#define REG_ESAI_RCCR          0xE0
+#define REG_ESAI_xCR(tx)       (tx ? REG_ESAI_TCR : REG_ESAI_RCR)
+#define REG_ESAI_xCCR(tx)      (tx ? REG_ESAI_TCCR : REG_ESAI_RCCR)
+#define REG_ESAI_TSMA          0xE4
+#define REG_ESAI_TSMB          0xE8
+#define REG_ESAI_RSMA          0xEC
+#define REG_ESAI_RSMB          0xF0
+#define REG_ESAI_xSMA(tx)      (tx ? REG_ESAI_TSMA : REG_ESAI_RSMA)
+#define REG_ESAI_xSMB(tx)      (tx ? REG_ESAI_TSMB : REG_ESAI_RSMB)
+#define REG_ESAI_PRRC          0xF8
+#define REG_ESAI_PCRC          0xFC
+
+/* ESAI Control Register -- REG_ESAI_ECR 0x8 */
+#define ESAI_ECR_ETI_SHIFT     19
+#define ESAI_ECR_ETI_MASK      (1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETI           (1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETO_SHIFT     18
+#define ESAI_ECR_ETO_MASK      (1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ETO           (1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ERI_SHIFT     17
+#define ESAI_ECR_ERI_MASK      (1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERI           (1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERO_SHIFT     16
+#define ESAI_ECR_ERO_MASK      (1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERO           (1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERST_SHIFT    1
+#define ESAI_ECR_ERST_MASK     (1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ERST          (1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ESAIEN_SHIFT  0
+#define ESAI_ECR_ESAIEN_MASK   (1 << ESAI_ECR_ESAIEN_SHIFT)
+#define ESAI_ECR_ESAIEN                (1 << ESAI_ECR_ESAIEN_SHIFT)
+
+/* ESAI Status Register -- REG_ESAI_ESR 0xC */
+#define ESAI_ESR_TINIT_SHIFT   10
+#define ESAI_ESR_TINIT_MASK    (1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_TINIT         (1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_RFF_SHIFT     9
+#define ESAI_ESR_RFF_MASK      (1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_RFF           (1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_TFE_SHIFT     8
+#define ESAI_ESR_TFE_MASK      (1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TFE           (1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TLS_SHIFT     7
+#define ESAI_ESR_TLS_MASK      (1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TLS           (1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TDE_SHIFT     6
+#define ESAI_ESR_TDE_MASK      (1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TDE           (1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TED_SHIFT     5
+#define ESAI_ESR_TED_MASK      (1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TED           (1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TD_SHIFT      4
+#define ESAI_ESR_TD_MASK       (1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_TD            (1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_RLS_SHIFT     3
+#define ESAI_ESR_RLS_MASK      (1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RLS           (1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RDE_SHIFT     2
+#define ESAI_ESR_RDE_MASK      (1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RDE           (1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RED_SHIFT     1
+#define ESAI_ESR_RED_MASK      (1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RED           (1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RD_SHIFT      0
+#define ESAI_ESR_RD_MASK       (1 << ESAI_ESR_RD_SHIFT)
+#define ESAI_ESR_RD            (1 << ESAI_ESR_RD_SHIFT)
+
+/*
+ * Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10
+ * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18
+ */
+#define ESAI_xFCR_TIEN_SHIFT   19
+#define ESAI_xFCR_TIEN_MASK    (1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_TIEN         (1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_REXT_SHIFT   19
+#define ESAI_xFCR_REXT_MASK    (1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_REXT         (1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_xWA_SHIFT    16
+#define ESAI_xFCR_xWA_WIDTH    3
+#define ESAI_xFCR_xWA_MASK     (((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT)
+#define ESAI_xFCR_xWA(v)       (((8 - ((v) >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK)
+#define ESAI_xFCR_xFWM_SHIFT   8
+#define ESAI_xFCR_xFWM_WIDTH   8
+#define ESAI_xFCR_xFWM_MASK    (((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT)
+#define ESAI_xFCR_xFWM(v)      ((((v) - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK)
+#define ESAI_xFCR_xE_SHIFT     2
+#define ESAI_xFCR_TE_WIDTH     6
+#define ESAI_xFCR_RE_WIDTH     4
+#define ESAI_xFCR_TE_MASK      (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_RE_MASK      (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_TE(x)        ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x)        ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_xFR_SHIFT    1
+#define ESAI_xFCR_xFR_MASK     (1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFR          (1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFEN_SHIFT   0
+#define ESAI_xFCR_xFEN_MASK    (1 << ESAI_xFCR_xFEN_SHIFT)
+#define ESAI_xFCR_xFEN         (1 << ESAI_xFCR_xFEN_SHIFT)
+
+/*
+ * Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14
+ * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C
+ */
+#define ESAI_xFSR_NTFO_SHIFT   12
+#define ESAI_xFSR_NRFI_SHIFT   12
+#define ESAI_xFSR_NTFI_SHIFT   8
+#define ESAI_xFSR_NRFO_SHIFT   8
+#define ESAI_xFSR_NTFx_WIDTH   3
+#define ESAI_xFSR_NRFx_WIDTH   2
+#define ESAI_xFSR_NTFO_MASK    (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT)
+#define ESAI_xFSR_NTFI_MASK    (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT)
+#define ESAI_xFSR_NRFO_MASK    (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT)
+#define ESAI_xFSR_NRFI_MASK    (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT)
+#define ESAI_xFSR_xFCNT_SHIFT  0
+#define ESAI_xFSR_xFCNT_WIDTH  8
+#define ESAI_xFSR_xFCNT_MASK   (((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT)
+
+/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */
+#define ESAI_TSR_SHIFT         0
+#define ESAI_TSR_WIDTH         24
+#define ESAI_TSR_MASK          (((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT)
+
+/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */
+#define ESAI_SAISR_TODFE_SHIFT 17
+#define ESAI_SAISR_TODFE_MASK  (1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TODFE       (1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TEDE_SHIFT  16
+#define ESAI_SAISR_TEDE_MASK   (1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TEDE                (1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TDE_SHIFT   15
+#define ESAI_SAISR_TDE_MASK    (1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TDE         (1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TUE_SHIFT   14
+#define ESAI_SAISR_TUE_MASK    (1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TUE         (1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TFS_SHIFT   13
+#define ESAI_SAISR_TFS_MASK    (1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_TFS         (1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_RODF_SHIFT  10
+#define ESAI_SAISR_RODF_MASK   (1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_RODF                (1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_REDF_SHIFT  9
+#define ESAI_SAISR_REDF_MASK   (1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_REDF                (1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_RDF_SHIFT   8
+#define ESAI_SAISR_RDF_MASK    (1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_RDF         (1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_ROE_SHIFT   7
+#define ESAI_SAISR_ROE_MASK    (1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_ROE         (1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_RFS_SHIFT   6
+#define ESAI_SAISR_RFS_MASK    (1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_RFS         (1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_IF2_SHIFT   2
+#define ESAI_SAISR_IF2_MASK    (1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF2         (1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF1_SHIFT   1
+#define ESAI_SAISR_IF1_MASK    (1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF1         (1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF0_SHIFT   0
+#define ESAI_SAISR_IF0_MASK    (1 << ESAI_SAISR_IF0_SHIFT)
+#define ESAI_SAISR_IF0         (1 << ESAI_SAISR_IF0_SHIFT)
+
+/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */
+#define ESAI_SAICR_ALC_SHIFT   8
+#define ESAI_SAICR_ALC_MASK    (1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_ALC         (1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_TEBE_SHIFT  7
+#define ESAI_SAICR_TEBE_MASK   (1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_TEBE                (1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_SYNC_SHIFT  6
+#define ESAI_SAICR_SYNC_MASK   (1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_SYNC                (1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_OF2_SHIFT   2
+#define ESAI_SAICR_OF2_MASK    (1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF2         (1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF1_SHIFT   1
+#define ESAI_SAICR_OF1_MASK    (1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF1         (1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF0_SHIFT   0
+#define ESAI_SAICR_OF0_MASK    (1 << ESAI_SAICR_OF0_SHIFT)
+#define ESAI_SAICR_OF0         (1 << ESAI_SAICR_OF0_SHIFT)
+
+/*
+ * Transmit Control Register -- REG_ESAI_TCR 0xD4
+ * Receive Control Register -- REG_ESAI_RCR 0xDC
+ */
+#define ESAI_xCR_xLIE_SHIFT    23
+#define ESAI_xCR_xLIE_MASK     (1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xLIE          (1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xIE_SHIFT     22
+#define ESAI_xCR_xIE_MASK      (1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xIE           (1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xEDIE_SHIFT   21
+#define ESAI_xCR_xEDIE_MASK    (1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEDIE         (1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEIE_SHIFT    20
+#define ESAI_xCR_xEIE_MASK     (1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xEIE          (1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xPR_SHIFT     19
+#define ESAI_xCR_xPR_MASK      (1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_xPR           (1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_PADC_SHIFT    17
+#define ESAI_xCR_PADC_MASK     (1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_PADC          (1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_xFSR_SHIFT    16
+#define ESAI_xCR_xFSR_MASK     (1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSR          (1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSL_SHIFT    15
+#define ESAI_xCR_xFSL_MASK     (1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xFSL          (1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xSWS_SHIFT    10
+#define ESAI_xCR_xSWS_WIDTH    5
+#define ESAI_xCR_xSWS_MASK     (((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xSWS(s, w)    ((w < 24 ? (s - w + ((w - 8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xMOD_SHIFT    8
+#define ESAI_xCR_xMOD_WIDTH    2
+#define ESAI_xCR_xMOD_MASK     (((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_ONDEMAND (0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_NETWORK  (0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_AC97     (0x3 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xWA_SHIFT     7
+#define ESAI_xCR_xWA_MASK      (1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xWA           (1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xSHFD_SHIFT   6
+#define ESAI_xCR_xSHFD_MASK    (1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xSHFD         (1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xE_SHIFT      0
+#define ESAI_xCR_TE_WIDTH      6
+#define ESAI_xCR_RE_WIDTH      4
+#define ESAI_xCR_TE_MASK       (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_RE_MASK       (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_TE(x)                 ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x)                 ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+
+/*
+ * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
+ * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0
+ */
+#define ESAI_xCCR_xHCKD_SHIFT  23
+#define ESAI_xCCR_xHCKD_MASK   (1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xHCKD                (1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xFSD_SHIFT   22
+#define ESAI_xCCR_xFSD_MASK    (1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xFSD         (1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xCKD_SHIFT   21
+#define ESAI_xCCR_xCKD_MASK    (1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xCKD         (1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xHCKP_SHIFT  20
+#define ESAI_xCCR_xHCKP_MASK   (1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xHCKP                (1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xFSP_SHIFT   19
+#define ESAI_xCCR_xFSP_MASK    (1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xFSP         (1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xCKP_SHIFT   18
+#define ESAI_xCCR_xCKP_MASK    (1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xCKP         (1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xFP_SHIFT    14
+#define ESAI_xCCR_xFP_WIDTH    4
+#define ESAI_xCCR_xFP_MASK     (((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
+#define ESAI_xCCR_xFP(v)       ((((v) - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
+#define ESAI_xCCR_xDC_SHIFT     9
+#define ESAI_xCCR_xDC_WIDTH    4
+#define ESAI_xCCR_xDC_MASK     (((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
+#define ESAI_xCCR_xDC(v)       ((((v) - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
+#define ESAI_xCCR_xPSR_SHIFT   8
+#define ESAI_xCCR_xPSR_MASK    (1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_BYPASS  (1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_DIV8    (0 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPM_SHIFT     0
+#define ESAI_xCCR_xPM_WIDTH     8
+#define ESAI_xCCR_xPM_MASK     (((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT)
+#define ESAI_xCCR_xPM(v)       ((((v) - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK)
+
+/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 ~ 0xF0 */
+#define ESAI_xSMA_xS_SHIFT     0
+#define ESAI_xSMA_xS_WIDTH     16
+#define ESAI_xSMA_xS_MASK      (((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT)
+#define ESAI_xSMA_xS(v)                ((v) & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS_SHIFT     0
+#define ESAI_xSMB_xS_WIDTH     16
+#define ESAI_xSMB_xS_MASK      (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
+#define ESAI_xSMB_xS(v)                (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+
+/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
+#define ESAI_PRRC_PDC_SHIFT    0
+#define ESAI_PRRC_PDC_WIDTH    12
+#define ESAI_PRRC_PDC_MASK     (((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT)
+#define ESAI_PRRC_PDC(v)       ((v) & ESAI_PRRC_PDC_MASK)
+
+/* Port C Control Register -- REG_ESAI_PCRC 0xFC */
+#define ESAI_PCRC_PC_SHIFT     0
+#define ESAI_PCRC_PC_WIDTH     12
+#define ESAI_PCRC_PC_MASK      (((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT)
+#define ESAI_PCRC_PC(v)                ((v) & ESAI_PCRC_PC_MASK)
+
+#define ESAI_GPIO              0xfff
+
+/* ESAI clock source */
+#define ESAI_HCKT_FSYS         0
+#define ESAI_HCKT_EXTAL                1
+#define ESAI_HCKR_FSYS         2
+#define ESAI_HCKR_EXTAL                3
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR                0
+#define ESAI_TX_DIV_PM         1
+#define ESAI_TX_DIV_FP         2
+#define ESAI_RX_DIV_PSR                3
+#define ESAI_RX_DIV_PM         4
+#define ESAI_RX_DIV_FP         5
+#endif /* _FSL_ESAI_DAI_H */
index 5d38a6749b9f2b31d1fbfb88b2bc95645177aac3..cdd3fa8307044d715b196b4c060d1e1c831f8e75 100644 (file)
@@ -62,26 +62,25 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                reg_cr2 = FSL_SAI_RCR2;
 
        val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+       val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+
        switch (clk_id) {
        case FSL_SAI_CLK_BUS:
-               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
                val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
                break;
        case FSL_SAI_CLK_MAST1:
-               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
                val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
                break;
        case FSL_SAI_CLK_MAST2:
-               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
                val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
                break;
        case FSL_SAI_CLK_MAST3:
-               val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
                val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
                break;
        default:
                return -EINVAL;
        }
+
        sai_writel(sai, val_cr2, sai->base + reg_cr2);
 
        return 0;
index 76e56b39db01a46122f619321d0108c795130741..f9090b167ad7c1ba2c3e91f1af2e042356c25841 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -106,12 +107,33 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
 #endif
 
-/* SIER bitflag of interrupts to enable */
-#define SIER_FLAGS (CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | \
-                   CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | \
-                   CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | \
-                   CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \
-                   CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
+               CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
+               CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
+#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
+               CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
+               CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
+#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS)
+
+
+enum fsl_ssi_type {
+       FSL_SSI_MCP8610,
+       FSL_SSI_MX21,
+       FSL_SSI_MX35,
+       FSL_SSI_MX51,
+};
+
+struct fsl_ssi_reg_val {
+       u32 sier;
+       u32 srcr;
+       u32 stcr;
+       u32 scr;
+};
+
+struct fsl_ssi_rxtx_reg_val {
+       struct fsl_ssi_reg_val rx;
+       struct fsl_ssi_reg_val tx;
+};
 
 /**
  * fsl_ssi_private: per-SSI private data
@@ -132,14 +154,16 @@ struct fsl_ssi_private {
        unsigned int irq;
        unsigned int fifo_depth;
        struct snd_soc_dai_driver cpu_dai_drv;
-       struct device_attribute dev_attr;
        struct platform_device *pdev;
 
+       enum fsl_ssi_type hw_type;
        bool new_binding;
        bool ssi_on_imx;
        bool imx_ac97;
        bool use_dma;
        bool baudclk_locked;
+       bool irq_stats;
+       bool offline_config;
        u8 i2s_mode;
        spinlock_t baudclk_lock;
        struct clk *baudclk;
@@ -149,6 +173,8 @@ struct fsl_ssi_private {
        struct imx_dma_data filter_data_tx;
        struct imx_dma_data filter_data_rx;
        struct imx_pcm_fiq_params fiq_params;
+       /* Register values for rx/tx configuration */
+       struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
 
        struct {
                unsigned int rfrc;
@@ -173,10 +199,21 @@ struct fsl_ssi_private {
                unsigned int tfe1;
                unsigned int tfe0;
        } stats;
+       struct dentry *dbg_dir;
+       struct dentry *dbg_stats;
 
        char name[1];
 };
 
+static const struct of_device_id fsl_ssi_ids[] = {
+       { .compatible = "fsl,mpc8610-ssi", .data = (void *) FSL_SSI_MCP8610},
+       { .compatible = "fsl,imx51-ssi", .data = (void *) FSL_SSI_MX51},
+       { .compatible = "fsl,imx35-ssi", .data = (void *) FSL_SSI_MX35},
+       { .compatible = "fsl,imx21-ssi", .data = (void *) FSL_SSI_MX21},
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
 /**
  * fsl_ssi_isr: SSI interrupt handler
  *
@@ -195,23 +232,40 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
        irqreturn_t ret = IRQ_NONE;
        __be32 sisr;
-       __be32 sisr2 = 0;
+       __be32 sisr2;
+       __be32 sisr_write_mask = 0;
+
+       switch (ssi_private->hw_type) {
+       case FSL_SSI_MX21:
+               sisr_write_mask = 0;
+               break;
+
+       case FSL_SSI_MCP8610:
+       case FSL_SSI_MX35:
+               sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
+                       CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
+                       CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
+               break;
+
+       case FSL_SSI_MX51:
+               sisr_write_mask = CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
+                       CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
+               break;
+       }
 
        /* We got an interrupt, so read the status register to see what we
           were interrupted for.  We mask it with the Interrupt Enable register
           so that we only check for events that we're interested in.
         */
-       sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
+       sisr = read_ssi(&ssi->sisr) & FSLSSI_SISR_MASK;
 
        if (sisr & CCSR_SSI_SISR_RFRC) {
                ssi_private->stats.rfrc++;
-               sisr2 |= CCSR_SSI_SISR_RFRC;
                ret = IRQ_HANDLED;
        }
 
        if (sisr & CCSR_SSI_SISR_TFRC) {
                ssi_private->stats.tfrc++;
-               sisr2 |= CCSR_SSI_SISR_TFRC;
                ret = IRQ_HANDLED;
        }
 
@@ -252,25 +306,21 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 
        if (sisr & CCSR_SSI_SISR_ROE1) {
                ssi_private->stats.roe1++;
-               sisr2 |= CCSR_SSI_SISR_ROE1;
                ret = IRQ_HANDLED;
        }
 
        if (sisr & CCSR_SSI_SISR_ROE0) {
                ssi_private->stats.roe0++;
-               sisr2 |= CCSR_SSI_SISR_ROE0;
                ret = IRQ_HANDLED;
        }
 
        if (sisr & CCSR_SSI_SISR_TUE1) {
                ssi_private->stats.tue1++;
-               sisr2 |= CCSR_SSI_SISR_TUE1;
                ret = IRQ_HANDLED;
        }
 
        if (sisr & CCSR_SSI_SISR_TUE0) {
                ssi_private->stats.tue0++;
-               sisr2 |= CCSR_SSI_SISR_TUE0;
                ret = IRQ_HANDLED;
        }
 
@@ -314,6 +364,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
                ret = IRQ_HANDLED;
        }
 
+       sisr2 = sisr & sisr_write_mask;
        /* Clear the bits that we set */
        if (sisr2)
                write_ssi(sisr2, &ssi->sisr);
@@ -321,6 +372,245 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
        return ret;
 }
 
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+/* Show the statistics of a flag only if its interrupt is enabled.  The
+ * compiler will optimze this code to a no-op if the interrupt is not
+ * enabled.
+ */
+#define SIER_SHOW(flag, name) \
+       do { \
+               if (FSLSSI_SISR_MASK & CCSR_SSI_SIER_##flag) \
+                       seq_printf(s, #name "=%u\n", ssi_private->stats.name); \
+       } while (0)
+
+
+/**
+ * fsl_sysfs_ssi_show: display SSI statistics
+ *
+ * Display the statistics for the current SSI device.  To avoid confusion,
+ * we only show those counts that are enabled.
+ */
+static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
+{
+       struct fsl_ssi_private *ssi_private = s->private;
+
+       SIER_SHOW(RFRC_EN, rfrc);
+       SIER_SHOW(TFRC_EN, tfrc);
+       SIER_SHOW(CMDAU_EN, cmdau);
+       SIER_SHOW(CMDDU_EN, cmddu);
+       SIER_SHOW(RXT_EN, rxt);
+       SIER_SHOW(RDR1_EN, rdr1);
+       SIER_SHOW(RDR0_EN, rdr0);
+       SIER_SHOW(TDE1_EN, tde1);
+       SIER_SHOW(TDE0_EN, tde0);
+       SIER_SHOW(ROE1_EN, roe1);
+       SIER_SHOW(ROE0_EN, roe0);
+       SIER_SHOW(TUE1_EN, tue1);
+       SIER_SHOW(TUE0_EN, tue0);
+       SIER_SHOW(TFS_EN, tfs);
+       SIER_SHOW(RFS_EN, rfs);
+       SIER_SHOW(TLS_EN, tls);
+       SIER_SHOW(RLS_EN, rls);
+       SIER_SHOW(RFF1_EN, rff1);
+       SIER_SHOW(RFF0_EN, rff0);
+       SIER_SHOW(TFE1_EN, tfe1);
+       SIER_SHOW(TFE0_EN, tfe0);
+
+       return 0;
+}
+
+static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fsl_ssi_stats_show, inode->i_private);
+}
+
+static const struct file_operations fsl_ssi_stats_ops = {
+       .open = fsl_ssi_stats_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
+               struct device *dev)
+{
+       ssi_private->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
+       if (!ssi_private->dbg_dir)
+               return -ENOMEM;
+
+       ssi_private->dbg_stats = debugfs_create_file("stats", S_IRUGO,
+                       ssi_private->dbg_dir, ssi_private, &fsl_ssi_stats_ops);
+       if (!ssi_private->dbg_stats) {
+               debugfs_remove(ssi_private->dbg_dir);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
+{
+       debugfs_remove(ssi_private->dbg_stats);
+       debugfs_remove(ssi_private->dbg_dir);
+}
+
+#else
+
+static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
+               struct device *dev)
+{
+       return 0;
+}
+
+static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
+
+/*
+ * Enable/Disable all rx/tx config flags at once.
+ */
+static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
+               bool enable)
+{
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
+
+       if (enable) {
+               write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier);
+               write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr);
+               write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr);
+       } else {
+               write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0);
+               write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0);
+               write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0);
+       }
+}
+
+/*
+ * Enable/Disable a ssi configuration. You have to pass either
+ * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
+ */
+static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
+               struct fsl_ssi_reg_val *vals)
+{
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       struct fsl_ssi_reg_val *avals;
+       u32 scr_val = read_ssi(&ssi->scr);
+       int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
+                               !!(scr_val & CCSR_SSI_SCR_RE);
+
+       /* Find the other direction values rx or tx which we do not want to
+        * modify */
+       if (&ssi_private->rxtx_reg_val.rx == vals)
+               avals = &ssi_private->rxtx_reg_val.tx;
+       else
+               avals = &ssi_private->rxtx_reg_val.rx;
+
+       /* If vals should be disabled, start with disabling the unit */
+       if (!enable) {
+               u32 scr = vals->scr & (vals->scr ^ avals->scr);
+               write_ssi_mask(&ssi->scr, scr, 0);
+       }
+
+       /*
+        * We are running on a SoC which does not support online SSI
+        * reconfiguration, so we have to enable all necessary flags at once
+        * even if we do not use them later (capture and playback configuration)
+        */
+       if (ssi_private->offline_config) {
+               if ((enable && !nr_active_streams) ||
+                               (!enable && nr_active_streams == 1))
+                       fsl_ssi_rxtx_config(ssi_private, enable);
+
+               goto config_done;
+       }
+
+       /*
+        * Configure single direction units while the SSI unit is running
+        * (online configuration)
+        */
+       if (enable) {
+               write_ssi_mask(&ssi->sier, 0, vals->sier);
+               write_ssi_mask(&ssi->srcr, 0, vals->srcr);
+               write_ssi_mask(&ssi->stcr, 0, vals->stcr);
+       } else {
+               u32 sier;
+               u32 srcr;
+               u32 stcr;
+
+               /*
+                * Disabling the necessary flags for one of rx/tx while the
+                * other stream is active is a little bit more difficult. We
+                * have to disable only those flags that differ between both
+                * streams (rx XOR tx) and that are set in the stream that is
+                * disabled now. Otherwise we could alter flags of the other
+                * stream
+                */
+
+               /* These assignments are simply vals without bits set in avals*/
+               sier = vals->sier & (vals->sier ^ avals->sier);
+               srcr = vals->srcr & (vals->srcr ^ avals->srcr);
+               stcr = vals->stcr & (vals->stcr ^ avals->stcr);
+
+               write_ssi_mask(&ssi->srcr, srcr, 0);
+               write_ssi_mask(&ssi->stcr, stcr, 0);
+               write_ssi_mask(&ssi->sier, sier, 0);
+       }
+
+config_done:
+       /* Enabling of subunits is done after configuration */
+       if (enable)
+               write_ssi_mask(&ssi->scr, 0, vals->scr);
+}
+
+
+static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
+{
+       fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
+}
+
+static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
+{
+       fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
+}
+
+/*
+ * Setup rx/tx register values used to enable/disable the streams. These will
+ * be used later in fsl_ssi_config to setup the streams without the need to
+ * check for all different SSI modes.
+ */
+static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private)
+{
+       struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val;
+
+       reg->rx.sier = CCSR_SSI_SIER_RFF0_EN;
+       reg->rx.srcr = CCSR_SSI_SRCR_RFEN0;
+       reg->rx.scr = 0;
+       reg->tx.sier = CCSR_SSI_SIER_TFE0_EN;
+       reg->tx.stcr = CCSR_SSI_STCR_TFEN0;
+       reg->tx.scr = 0;
+
+       if (!ssi_private->imx_ac97) {
+               reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE;
+               reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN;
+               reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE;
+               reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN;
+       }
+
+       if (ssi_private->use_dma) {
+               reg->rx.sier |= CCSR_SSI_SIER_RDMAE;
+               reg->tx.sier |= CCSR_SSI_SIER_TDMAE;
+       } else {
+               reg->rx.sier |= CCSR_SSI_SIER_RIE;
+               reg->tx.sier |= CCSR_SSI_SIER_TIE;
+       }
+
+       reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS;
+       reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS;
+}
+
 static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
 {
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -357,6 +647,8 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
        u8 wm;
        int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
 
+       fsl_ssi_setup_reg_vals(ssi_private);
+
        if (ssi_private->imx_ac97)
                ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
        else
@@ -380,13 +672,12 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
                ssi_private->i2s_mode |
                (synchronous ? CCSR_SSI_SCR_SYN : 0));
 
-       write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
-                CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-                CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+       write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI |
+                       CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+
+       write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI |
+                       CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
 
-       write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
-                CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-                CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
        /*
         * The DC and PM bits are only used if the SSI is the clock master.
         */
@@ -419,6 +710,17 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
        if (ssi_private->imx_ac97)
                fsl_ssi_setup_ac97(ssi_private);
 
+       /*
+        * Set a default slot number so that there is no need for those common
+        * cases like I2S mode to call the extra set_tdm_slot() any more.
+        */
+       if (!ssi_private->imx_ac97) {
+               write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+                               CCSR_SSI_SxCCR_DC(2));
+               write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+                               CCSR_SSI_SxCCR_DC(2));
+       }
+
        return 0;
 }
 
@@ -761,50 +1063,26 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-       unsigned int sier_bits;
        unsigned long flags;
 
-       /*
-        *  Enable only the interrupts and DMA requests
-        *  that are needed for the channel. As the fiq
-        *  is polling for this bits, we have to ensure
-        *  that this are aligned with the preallocated
-        *  buffers
-        */
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (ssi_private->use_dma)
-                       sier_bits = SIER_FLAGS;
-               else
-                       sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN;
-       } else {
-               if (ssi_private->use_dma)
-                       sier_bits = SIER_FLAGS;
-               else
-                       sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN;
-       }
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       write_ssi_mask(&ssi->scr, 0,
-                               CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
+                       fsl_ssi_tx_config(ssi_private, true);
                else
-                       write_ssi_mask(&ssi->scr, 0,
-                               CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
+                       fsl_ssi_rx_config(ssi_private, true);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
+                       fsl_ssi_tx_config(ssi_private, false);
                else
-                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
+                       fsl_ssi_rx_config(ssi_private, false);
 
                if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
                                        (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
-                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
                        spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
                        ssi_private->baudclk_locked = false;
                        spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
@@ -815,7 +1093,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                return -EINVAL;
        }
 
-       write_ssi(sier_bits, &ssi->sier);
+       if (ssi_private->imx_ac97) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
+               else
+                       write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
+       }
 
        return 0;
 }
@@ -863,58 +1146,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
        .name           = "fsl-ssi",
 };
 
-/**
- * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit.
- *
- * This function is called by ALSA to start, stop, pause, and resume the
- * transfer of data.
- */
-static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
-                          struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(
-                       rtd->cpu_dai);
-       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE |
-                                       CCSR_SSI_SIER_TFE0_EN);
-               else
-                       write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE |
-                                       CCSR_SSI_SIER_RFF0_EN);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE |
-                                       CCSR_SSI_SIER_TFE0_EN, 0);
-               else
-                       write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE |
-                                       CCSR_SSI_SIER_RFF0_EN, 0);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
-       else
-               write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = {
-       .startup        = fsl_ssi_startup,
-       .trigger        = fsl_ssi_ac97_trigger,
-};
-
 static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
        .ac97_control = 1,
        .playback = {
@@ -931,7 +1162,7 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
                .rates = SNDRV_PCM_RATE_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       .ops = &fsl_ssi_ac97_dai_ops,
+       .ops = &fsl_ssi_dai_ops,
 };
 
 
@@ -989,56 +1220,6 @@ static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
        .write          = fsl_ssi_ac97_write,
 };
 
-/* Show the statistics of a flag only if its interrupt is enabled.  The
- * compiler will optimze this code to a no-op if the interrupt is not
- * enabled.
- */
-#define SIER_SHOW(flag, name) \
-       do { \
-               if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \
-                       length += sprintf(buf + length, #name "=%u\n", \
-                               ssi_private->stats.name); \
-       } while (0)
-
-
-/**
- * fsl_sysfs_ssi_show: display SSI statistics
- *
- * Display the statistics for the current SSI device.  To avoid confusion,
- * we only show those counts that are enabled.
- */
-static ssize_t fsl_sysfs_ssi_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct fsl_ssi_private *ssi_private =
-               container_of(attr, struct fsl_ssi_private, dev_attr);
-       ssize_t length = 0;
-
-       SIER_SHOW(RFRC_EN, rfrc);
-       SIER_SHOW(TFRC_EN, tfrc);
-       SIER_SHOW(CMDAU_EN, cmdau);
-       SIER_SHOW(CMDDU_EN, cmddu);
-       SIER_SHOW(RXT_EN, rxt);
-       SIER_SHOW(RDR1_EN, rdr1);
-       SIER_SHOW(RDR0_EN, rdr0);
-       SIER_SHOW(TDE1_EN, tde1);
-       SIER_SHOW(TDE0_EN, tde0);
-       SIER_SHOW(ROE1_EN, roe1);
-       SIER_SHOW(ROE0_EN, roe0);
-       SIER_SHOW(TUE1_EN, tue1);
-       SIER_SHOW(TUE0_EN, tue0);
-       SIER_SHOW(TFS_EN, tfs);
-       SIER_SHOW(RFS_EN, rfs);
-       SIER_SHOW(TLS_EN, tls);
-       SIER_SHOW(RLS_EN, rls);
-       SIER_SHOW(RFF1_EN, rff1);
-       SIER_SHOW(RFF0_EN, rff0);
-       SIER_SHOW(TFE1_EN, tfe1);
-       SIER_SHOW(TFE0_EN, tfe0);
-
-       return length;
-}
-
 /**
  * Make every character in a string lower-case
  */
@@ -1060,6 +1241,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        int ret = 0;
        struct device_attribute *dev_attr = NULL;
        struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id;
+       enum fsl_ssi_type hw_type;
        const char *p, *sprop;
        const uint32_t *iprop;
        struct resource res;
@@ -1074,6 +1257,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        if (!of_device_is_available(np))
                return -ENODEV;
 
+       of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
+       if (!of_id)
+               return -EINVAL;
+       hw_type = (enum fsl_ssi_type) of_id->data;
+
        /* We only support the SSI in "I2S Slave" mode */
        sprop = of_get_property(np, "fsl,mode", NULL);
        if (!sprop) {
@@ -1100,6 +1288,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        ssi_private->use_dma = !of_property_read_bool(np,
                        "fsl,fiq-stream-filter");
+       ssi_private->hw_type = hw_type;
 
        if (ac97) {
                memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
@@ -1153,7 +1342,34 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        ssi_private->baudclk_locked = false;
        spin_lock_init(&ssi_private->baudclk_lock);
 
-       if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
+       /*
+        * imx51 and later SoCs have a slightly different IP that allows the
+        * SSI configuration while the SSI unit is running.
+        *
+        * More important, it is necessary on those SoCs to configure the
+        * sperate TX/RX DMA bits just before starting the stream
+        * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
+        * sends any DMA requests to the SDMA unit, otherwise it is not defined
+        * how the SDMA unit handles the DMA request.
+        *
+        * SDMA units are present on devices starting at imx35 but the imx35
+        * reference manual states that the DMA bits should not be changed
+        * while the SSI unit is running (SSIEN). So we support the necessary
+        * online configuration of fsl-ssi starting at imx51.
+        */
+       switch (hw_type) {
+       case FSL_SSI_MCP8610:
+       case FSL_SSI_MX21:
+       case FSL_SSI_MX35:
+               ssi_private->offline_config = true;
+               break;
+       case FSL_SSI_MX51:
+               ssi_private->offline_config = false;
+               break;
+       }
+
+       if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX51 ||
+                       hw_type == FSL_SSI_MX35) {
                u32 dma_events[2];
                ssi_private->ssi_on_imx = true;
 
@@ -1175,7 +1391,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                 */
                ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
                if (IS_ERR(ssi_private->baudclk))
-                       dev_warn(&pdev->dev, "could not get baud clock: %d\n", ret);
+                       dev_warn(&pdev->dev, "could not get baud clock: %ld\n",
+                                PTR_ERR(ssi_private->baudclk));
                else
                        clk_prepare_enable(ssi_private->baudclk);
 
@@ -1217,32 +1434,25 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                        dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
                imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
                        dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
-       } else if (ssi_private->use_dma) {
+       }
+
+       /*
+        * Enable interrupts only for MCP8610 and MX51. The other MXs have
+        * different writeable interrupt status registers.
+        */
+       if (ssi_private->use_dma) {
                /* The 'name' should not have any slashes in it. */
                ret = devm_request_irq(&pdev->dev, ssi_private->irq,
                                        fsl_ssi_isr, 0, ssi_private->name,
                                        ssi_private);
+               ssi_private->irq_stats = true;
                if (ret < 0) {
                        dev_err(&pdev->dev, "could not claim irq %u\n",
                                        ssi_private->irq);
-                       goto error_irqmap;
+                       goto error_clk;
                }
        }
 
-       /* Initialize the the device_attribute structure */
-       dev_attr = &ssi_private->dev_attr;
-       sysfs_attr_init(&dev_attr->attr);
-       dev_attr->attr.name = "statistics";
-       dev_attr->attr.mode = S_IRUGO;
-       dev_attr->show = fsl_sysfs_ssi_show;
-
-       ret = device_create_file(&pdev->dev, dev_attr);
-       if (ret) {
-               dev_err(&pdev->dev, "could not create sysfs %s file\n",
-                       ssi_private->dev_attr.attr.name);
-               goto error_clk;
-       }
-
        /* Register with ASoC */
        dev_set_drvdata(&pdev->dev, ssi_private);
 
@@ -1253,6 +1463,10 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                goto error_dev;
        }
 
+       ret = fsl_ssi_debugfs_create(ssi_private, &pdev->dev);
+       if (ret)
+               goto error_dbgfs;
+
        if (ssi_private->ssi_on_imx) {
                if (!ssi_private->use_dma) {
 
@@ -1272,11 +1486,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
                        ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
                        if (ret)
-                               goto error_dev;
+                               goto error_pcm;
                } else {
                        ret = imx_pcm_dma_init(pdev);
                        if (ret)
-                               goto error_dev;
+                               goto error_pcm;
                }
        }
 
@@ -1318,6 +1532,13 @@ done:
        return 0;
 
 error_dai:
+       if (ssi_private->ssi_on_imx && !ssi_private->use_dma)
+               imx_pcm_fiq_exit(pdev);
+
+error_pcm:
+       fsl_ssi_debugfs_remove(ssi_private);
+
+error_dbgfs:
        snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
@@ -1331,7 +1552,8 @@ error_clk:
        }
 
 error_irqmap:
-       irq_dispose_mapping(ssi_private->irq);
+       if (ssi_private->irq_stats)
+               irq_dispose_mapping(ssi_private->irq);
 
        return ret;
 }
@@ -1340,27 +1562,22 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 {
        struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
+       fsl_ssi_debugfs_remove(ssi_private);
+
        if (!ssi_private->new_binding)
                platform_device_unregister(ssi_private->pdev);
        snd_soc_unregister_component(&pdev->dev);
-       device_remove_file(&pdev->dev, &ssi_private->dev_attr);
        if (ssi_private->ssi_on_imx) {
                if (!IS_ERR(ssi_private->baudclk))
                        clk_disable_unprepare(ssi_private->baudclk);
                clk_disable_unprepare(ssi_private->clk);
        }
-       irq_dispose_mapping(ssi_private->irq);
+       if (ssi_private->irq_stats)
+               irq_dispose_mapping(ssi_private->irq);
 
        return 0;
 }
 
-static const struct of_device_id fsl_ssi_ids[] = {
-       { .compatible = "fsl,mpc8610-ssi", },
-       { .compatible = "fsl,imx21-ssi", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
-
 static struct platform_driver fsl_ssi_driver = {
        .driver = {
                .name = "fsl-ssi-dai",
index c5e47f866b4b756beaa515b1c29ba4177572cb10..2585ae44e634feb6bab623b6afdf93c58c3b288f 100644 (file)
@@ -41,9 +41,6 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
                SNDRV_PCM_INFO_PAUSE |
                SNDRV_PCM_INFO_RESUME,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       .rate_min = 8000,
-       .channels_min = 2,
-       .channels_max = 2,
        .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
        .period_bytes_min = 128,
        .period_bytes_max = 65535, /* Limited by SDMA engine */
index c75d43bb2e92de772a97865e98227176473135a4..6553202dd48c09d19fe2916447f553023276a897 100644 (file)
@@ -162,9 +162,6 @@ static struct snd_pcm_hardware snd_imx_hardware = {
                SNDRV_PCM_INFO_PAUSE |
                SNDRV_PCM_INFO_RESUME,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       .rate_min = 8000,
-       .channels_min = 2,
-       .channels_max = 2,
        .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
        .period_bytes_min = 128,
        .period_bytes_max = 16 * 1024,
index 71bf2f248cd47be5fb025baa6535296b49d75bbd..f2b5d756b1f3360846ef3bb1f8f43a4efd8547b1 100644 (file)
@@ -200,10 +200,6 @@ static const struct snd_pcm_hardware psc_dma_hardware = {
                SNDRV_PCM_INFO_BATCH,
        .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
                SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
-       .rate_min = 8000,
-       .rate_max = 48000,
-       .channels_min = 1,
-       .channels_max = 2,
        .period_bytes_max       = 1024 * 1024,
        .period_bytes_min       = 32,
        .periods_min            = 2,
index c0d928138c88c4eadef6243098350f09f19eaa1c..2a1b1b5b5221089f32e395087e9c4651ddd00799 100644 (file)
@@ -9,14 +9,12 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/module.h>
+#include <linux/string.h>
 #include <sound/simple_card.h>
 
-#define asoc_simple_get_card_info(p) \
-       container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
-
 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
                                       struct asoc_simple_dai *set,
                                       unsigned int daifmt)
@@ -41,7 +39,8 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd);
+       struct asoc_simple_card_info *info =
+                               snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_dai *codec = rtd->codec_dai;
        struct snd_soc_dai *cpu = rtd->cpu_dai;
        unsigned int daifmt = info->daifmt;
@@ -106,12 +105,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                                     &dai->sysclk);
        } else {
                clk = of_clk_get(*node, 0);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       goto parse_error;
-               }
-
-               dai->sysclk = clk_get_rate(clk);
+               if (!IS_ERR(clk))
+                       dai->sysclk = clk_get_rate(clk);
        }
 
        ret = 0;
@@ -138,10 +133,12 @@ static int asoc_simple_card_parse_of(struct device_node *node,
                (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
 
        /* DAPM routes */
-       ret = snd_soc_of_parse_audio_routing(&info->snd_card,
-                                       "simple-audio-routing");
-       if (ret)
-               return ret;
+       if (of_property_read_bool(node, "simple-audio-card,routing")) {
+               ret = snd_soc_of_parse_audio_routing(&info->snd_card,
+                                       "simple-audio-card,routing");
+               if (ret)
+                       return ret;
+       }
 
        /* CPU sub-node */
        ret = -EINVAL;
@@ -197,34 +194,37 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct device_node *of_cpu, *of_codec, *of_platform;
        struct device *dev = &pdev->dev;
+       int ret;
 
        cinfo           = NULL;
        of_cpu          = NULL;
        of_codec        = NULL;
        of_platform     = NULL;
+
+       cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
+       if (!cinfo)
+               return -ENOMEM;
+
        if (np && of_device_is_available(np)) {
-               cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
-               if (cinfo) {
-                       int ret;
-                       cinfo->snd_card.dev = &pdev->dev;
-                       ret = asoc_simple_card_parse_of(np, cinfo, dev,
-                                                       &of_cpu,
-                                                       &of_codec,
-                                                       &of_platform);
-                       if (ret < 0) {
-                               if (ret != -EPROBE_DEFER)
-                                       dev_err(dev, "parse error %d\n", ret);
-                               return ret;
-                       }
+               cinfo->snd_card.dev = dev;
+
+               ret = asoc_simple_card_parse_of(np, cinfo, dev,
+                                               &of_cpu,
+                                               &of_codec,
+                                               &of_platform);
+               if (ret < 0) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "parse error %d\n", ret);
+                       return ret;
                }
        } else {
-               cinfo->snd_card.dev = &pdev->dev;
-               cinfo = pdev->dev.platform_data;
-       }
+               if (!dev->platform_data) {
+                       dev_err(dev, "no info for asoc-simple-card\n");
+                       return -EINVAL;
+               }
 
-       if (!cinfo) {
-               dev_err(dev, "no info for asoc-simple-card\n");
-               return -EINVAL;
+               memcpy(cinfo, dev->platform_data, sizeof(*cinfo));
+               cinfo->snd_card.dev = dev;
        }
 
        if (!cinfo->name        ||
@@ -259,6 +259,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        cinfo->snd_card.dai_link        = &cinfo->snd_link;
        cinfo->snd_card.num_links       = 1;
 
+       snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo);
+
        return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card);
 }
 
index b6b5eb698d33227af2193196847b64be291e595a..f465a81808636e0cf59e8644d4fa8f08e6cb2904 100644 (file)
@@ -89,16 +89,6 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = {
                        SNDRV_PCM_INFO_MMAP_VALID |
                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
                        SNDRV_PCM_INFO_SYNC_START),
-       .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
-                       SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
-                       SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
-       .rates = (SNDRV_PCM_RATE_8000|
-                       SNDRV_PCM_RATE_44100 |
-                       SNDRV_PCM_RATE_48000),
-       .rate_min = SST_MIN_RATE,
-       .rate_max = SST_MAX_RATE,
-       .channels_min = SST_MIN_CHANNEL,
-       .channels_max = SST_MAX_CHANNEL,
        .buffer_bytes_max = SST_MAX_BUFFER,
        .period_bytes_min = SST_MIN_PERIOD_BYTES,
        .period_bytes_max = SST_MAX_PERIOD_BYTES,
index cacc9066ec524a5ad6747f650b77615899d776d6..bee64fb7d2ef54871973952bb68c9a797486e390 100644 (file)
 #define SST_STEREO             2
 #define SST_MAX_CAP            5
 
-#define SST_MIN_RATE           8000
-#define SST_MAX_RATE           48000
-#define SST_MIN_CHANNEL                1
-#define SST_MAX_CHANNEL                5
 #define SST_MAX_BUFFER         (800*1024)
 #define SST_MIN_BUFFER         (800*1024)
 #define SST_MIN_PERIOD_BYTES   32
index 4af1936cf0f4fdbbaafe0bee2879872418efadd7..aac22fccdcdc3e3954b35493df9773d4fd8c98fe 100644 (file)
 #include <sound/soc.h>
 #include "kirkwood.h"
 
-#define KIRKWOOD_RATES \
-       (SNDRV_PCM_RATE_8000_192000 |           \
-        SNDRV_PCM_RATE_CONTINUOUS |            \
-        SNDRV_PCM_RATE_KNOT)
-
-#define KIRKWOOD_FORMATS \
-       (SNDRV_PCM_FMTBIT_S16_LE | \
-        SNDRV_PCM_FMTBIT_S24_LE | \
-        SNDRV_PCM_FMTBIT_S32_LE)
-
 static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
 {
        struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
@@ -43,12 +33,6 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
                 SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_PAUSE),
-       .formats                = KIRKWOOD_FORMATS,
-       .rates                  = KIRKWOOD_RATES,
-       .rate_min               = 8000,
-       .rate_max               = 384000,
-       .channels_min           = 1,
-       .channels_max           = 8,
        .buffer_bytes_max       = KIRKWOOD_SND_MAX_BUFFER_BYTES,
        .period_bytes_min       = KIRKWOOD_SND_MIN_PERIOD_BYTES,
        .period_bytes_max       = KIRKWOOD_SND_MAX_PERIOD_BYTES,
index 04a6b0d60944e1b13350dac3fd2fa708dd3c64d5..a371b4f91c534d22e1e13aacfff93a490dfb461d 100644 (file)
@@ -36,11 +36,6 @@ static const struct snd_pcm_hardware snd_mxs_hardware = {
                                  SNDRV_PCM_INFO_RESUME |
                                  SNDRV_PCM_INFO_INTERLEAVED |
                                  SNDRV_PCM_INFO_HALF_DUPLEX,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                 SNDRV_PCM_FMTBIT_S20_3LE |
-                                 SNDRV_PCM_FMTBIT_S24_LE,
-       .channels_min           = 2,
-       .channels_max           = 2,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
        .periods_min            = 1,
@@ -57,7 +52,6 @@ static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
 int mxs_pcm_platform_register(struct device *dev)
 {
        return devm_snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
-               SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
                SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
index f588ee45b4fdd610d21c316f469b81b687da40a9..f434ed79d1b613bc64470cfa3041f4808b237f47 100644 (file)
@@ -32,9 +32,6 @@ static const struct snd_pcm_hardware nuc900_pcm_hardware = {
                                        SNDRV_PCM_INFO_MMAP_VALID |
                                        SNDRV_PCM_INFO_PAUSE |
                                        SNDRV_PCM_INFO_RESUME,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .channels_min           = 1,
-       .channels_max           = 2,
        .buffer_bytes_max       = 4*1024,
        .period_bytes_min       = 1*1024,
        .period_bytes_max       = 4*1024,
index 1a8b03e4b41b9c3f7ce38fcc79130307d757cb51..c85f8eb66c972892654b7a4e37e2818b779f2b65 100644 (file)
@@ -89,29 +89,12 @@ struct camelot_pcm {
 #define DMABRG_PREALLOC_BUFFER         32 * 1024
 #define DMABRG_PREALLOC_BUFFER_MAX     32 * 1024
 
-/* support everything the SSI supports */
-#define DMABRG_RATES   \
-       SNDRV_PCM_RATE_8000_192000
-
-#define DMABRG_FMTS    \
-       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
-        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
-        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
-        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
-        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
-
 static struct snd_pcm_hardware camelot_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_BATCH),
-       .formats =      DMABRG_FMTS,
-       .rates =        DMABRG_RATES,
-       .rate_min =             8000,
-       .rate_max =             192000,
-       .channels_min =         2,
-       .channels_max =         8,              /* max of the SSI */
        .buffer_bytes_max =     DMABRG_PERIOD_MAX,
        .period_bytes_min =     DMABRG_PERIOD_MIN,
        .period_bytes_max =     DMABRG_PERIOD_MAX / 2,
index 6101055aae1dc6fe4e0f7851bd17dde646624f79..1967f44e7cd4d18fd078a71c52c3f0faf472b95f 100644 (file)
@@ -1787,12 +1787,6 @@ static struct snd_pcm_hardware fsi_pcm_hardware = {
                        SNDRV_PCM_INFO_MMAP             |
                        SNDRV_PCM_INFO_MMAP_VALID       |
                        SNDRV_PCM_INFO_PAUSE,
-       .formats                = FSI_FMTS,
-       .rates                  = FSI_RATES,
-       .rate_min               = 8000,
-       .rate_max               = 192000,
-       .channels_min           = 2,
-       .channels_max           = 2,
        .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
index b3653d37f75f087cffd3880a5c22e06c693c78fe..743de5e3b1e1ed4cba8f5dcfce3a5d3cfd9471bf 100644 (file)
@@ -628,12 +628,6 @@ static struct snd_pcm_hardware rsnd_pcm_hardware = {
                        SNDRV_PCM_INFO_MMAP             |
                        SNDRV_PCM_INFO_MMAP_VALID       |
                        SNDRV_PCM_INFO_PAUSE,
-       .formats                = RSND_FMTS,
-       .rates                  = RSND_RATES,
-       .rate_min               = 8000,
-       .rate_max               = 192000,
-       .channels_min           = 2,
-       .channels_max           = 2,
        .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
index 178d1bad62591565589803f52c859a2062044df2..b3b66aa98dce7d8b3f6844eb9f65a7d59a728cd8 100644 (file)
@@ -91,6 +91,8 @@ static int mop500_of_probe(struct platform_device *pdev,
        for (i = 0; i < 2; i++) {
                mop500_dai_links[i].cpu_of_node = msp_np[i];
                mop500_dai_links[i].cpu_dai_name = NULL;
+               mop500_dai_links[i].platform_of_node = msp_np[i];
+               mop500_dai_links[i].platform_name = NULL;
                mop500_dai_links[i].codec_of_node = codec_np;
                mop500_dai_links[i].codec_name = NULL;
        }
index c6fb5cce980e365f4fa84a02fa2b4254a9887e66..5f4807b2c0072b00b29619fb4d224e475ddfab3f 100644 (file)
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/platform_data/asoc-ux500-msp.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "ux500_msp_i2s.h"
 #include "ux500_msp_dai.h"
@@ -654,16 +656,52 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       struct snd_dmaengine_dai_dma_data *playback_dma_data;
+       struct snd_dmaengine_dai_dma_data *capture_dma_data;
+
+       playback_dma_data = devm_kzalloc(dai->dev,
+                                        sizeof(*playback_dma_data),
+                                        GFP_KERNEL);
+       if (!playback_dma_data)
+               return -ENOMEM;
+
+       capture_dma_data = devm_kzalloc(dai->dev,
+                                       sizeof(*capture_dma_data),
+                                       GFP_KERNEL);
+       if (!capture_dma_data)
+               return -ENOMEM;
+
+       playback_dma_data->addr = drvdata->msp->playback_dma_data.tx_rx_addr;
+       capture_dma_data->addr = drvdata->msp->capture_dma_data.tx_rx_addr;
+
+       playback_dma_data->maxburst = 4;
+       capture_dma_data->maxburst = 4;
+
+       snd_soc_dai_init_dma_data(dai, playback_dma_data, capture_dma_data);
+
+       return 0;
+}
+
 static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
 {
        struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       struct msp_i2s_platform_data *pdata = dai->dev->platform_data;
+       int ret;
 
-       dai->playback_dma_data = &drvdata->msp->playback_dma_data;
-       dai->capture_dma_data = &drvdata->msp->capture_dma_data;
+       if (!pdata) {
+               ret = ux500_msp_dai_of_probe(dai);
+               return ret;
+       }
 
        drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
        drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
 
+       snd_soc_dai_init_dma_data(dai,
+                                 &drvdata->msp->playback_dma_data,
+                                 &drvdata->msp->capture_dma_data);
        return 0;
 }
 
@@ -680,87 +718,19 @@ static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
        }
 };
 
-static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
-       {
-               .name = "ux500-msp-i2s.0",
-               .probe = ux500_msp_dai_probe,
-               .id = 0,
-               .suspend = NULL,
-               .resume = NULL,
-               .playback = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .capture = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .ops = ux500_msp_dai_ops,
-       },
-       {
-               .name = "ux500-msp-i2s.1",
-               .probe = ux500_msp_dai_probe,
-               .id = 1,
-               .suspend = NULL,
-               .resume = NULL,
-               .playback = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .capture = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .ops = ux500_msp_dai_ops,
-       },
-       {
-               .name = "ux500-msp-i2s.2",
-               .id = 2,
-               .probe = ux500_msp_dai_probe,
-               .suspend = NULL,
-               .resume = NULL,
-               .playback = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .capture = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .ops = ux500_msp_dai_ops,
-       },
-       {
-               .name = "ux500-msp-i2s.3",
-               .probe = ux500_msp_dai_probe,
-               .id = 3,
-               .suspend = NULL,
-               .resume = NULL,
-               .playback = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .capture = {
-                       .channels_min = UX500_MSP_MIN_CHANNELS,
-                       .channels_max = UX500_MSP_MAX_CHANNELS,
-                       .rates = UX500_I2S_RATES,
-                       .formats = UX500_I2S_FORMATS,
-               },
-               .ops = ux500_msp_dai_ops,
-       },
+static struct snd_soc_dai_driver ux500_msp_dai_drv = {
+       .probe                 = ux500_msp_dai_probe,
+       .suspend               = NULL,
+       .resume                = NULL,
+       .playback.channels_min = UX500_MSP_MIN_CHANNELS,
+       .playback.channels_max = UX500_MSP_MAX_CHANNELS,
+       .playback.rates        = UX500_I2S_RATES,
+       .playback.formats      = UX500_I2S_FORMATS,
+       .capture.channels_min  = UX500_MSP_MIN_CHANNELS,
+       .capture.channels_max  = UX500_MSP_MAX_CHANNELS,
+       .capture.rates         = UX500_I2S_RATES,
+       .capture.formats       = UX500_I2S_FORMATS,
+       .ops                   = ux500_msp_dai_ops,
 };
 
 static const struct snd_soc_component_driver ux500_msp_component = {
@@ -771,10 +741,14 @@ static const struct snd_soc_component_driver ux500_msp_component = {
 static int ux500_msp_drv_probe(struct platform_device *pdev)
 {
        struct ux500_msp_i2s_drvdata *drvdata;
+       struct msp_i2s_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
        int ret = 0;
 
-       dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__,
-               pdev->name);
+       if (!pdata && !np) {
+               dev_err(&pdev->dev, "No platform data or Device Tree found\n");
+               return -ENODEV;
+       }
 
        drvdata = devm_kzalloc(&pdev->dev,
                                sizeof(struct ux500_msp_i2s_drvdata),
@@ -826,7 +800,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, drvdata);
 
        ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
-                                        &ux500_msp_dai_drv[drvdata->msp->id], 1);
+                                        &ux500_msp_dai_drv, 1);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
                        __func__, drvdata->msp->id);
index 1ca8b08ae993d34a100b22032315b9c94ce9ec03..959d7b4edf56a94d167d09ea07ca7a597a64bbce 100644 (file)
@@ -646,6 +646,34 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
 
 }
 
+static int ux500_msp_i2s_of_init_msp(struct platform_device *pdev,
+                               struct ux500_msp *msp,
+                               struct msp_i2s_platform_data **platform_data)
+{
+       struct msp_i2s_platform_data *pdata;
+
+       *platform_data = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct msp_i2s_platform_data),
+                                    GFP_KERNEL);
+       pdata = *platform_data;
+       if (!pdata)
+               return -ENOMEM;
+
+       msp->playback_dma_data.dma_cfg = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct stedma40_chan_cfg),
+                                       GFP_KERNEL);
+       if (!msp->playback_dma_data.dma_cfg)
+               return -ENOMEM;
+
+       msp->capture_dma_data.dma_cfg = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct stedma40_chan_cfg),
+                                       GFP_KERNEL);
+       if (!msp->capture_dma_data.dma_cfg)
+               return -ENOMEM;
+
+       return 0;
+}
+
 int ux500_msp_i2s_init_msp(struct platform_device *pdev,
                        struct ux500_msp **msp_p,
                        struct msp_i2s_platform_data *platform_data)
@@ -653,30 +681,28 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
        struct resource *res = NULL;
        struct device_node *np = pdev->dev.of_node;
        struct ux500_msp *msp;
+       int ret;
 
        *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
        msp = *msp_p;
        if (!msp)
                return -ENOMEM;
 
-       if (np) {
-               if (!platform_data) {
-                       platform_data = devm_kzalloc(&pdev->dev,
-                               sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
-                       if (!platform_data)
-                               return -ENOMEM;
-               }
-       } else
-               if (!platform_data)
+       if (!platform_data) {
+               if (np) {
+                       ret = ux500_msp_i2s_of_init_msp(pdev, msp,
+                                                       &platform_data);
+                       if (ret)
+                               return ret;
+               } else
                        return -EINVAL;
+       } else {
+               msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
+               msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
+               msp->id = platform_data->id;
+       }
 
-       dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
-               pdev->name, platform_data->id);
-
-       msp->id = platform_data->id;
        msp->dev = &pdev->dev;
-       msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
-       msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
index 258d0bcee0bd540aed67c757742f1a0f698f3a5f..875de0f68b8567dd3ec1d89213fbe849775ec563 100644 (file)
@@ -475,7 +475,7 @@ struct ux500_msp_dma_params {
 };
 
 struct ux500_msp {
-       enum msp_i2s_id id;
+       int id;
        void __iomem *registers;
        struct device *dev;
        struct ux500_msp_dma_params playback_dma_data;
index ce554de5d9dc5a131aa52e9f3d9c1da87b8ddb8c..51a66a87305ae0ad96b26206108f13bcec5a189f 100644 (file)
 #include "ux500_msp_i2s.h"
 #include "ux500_pcm.h"
 
-#define UX500_PLATFORM_MIN_RATE 8000
-#define UX500_PLATFORM_MAX_RATE 48000
-
-#define UX500_PLATFORM_MIN_CHANNELS 1
-#define UX500_PLATFORM_MAX_CHANNELS 8
-
 #define UX500_PLATFORM_PERIODS_BYTES_MIN       128
 #define UX500_PLATFORM_PERIODS_BYTES_MAX       (64 * PAGE_SIZE)
 #define UX500_PLATFORM_PERIODS_MIN             2
@@ -45,15 +39,6 @@ static const struct snd_pcm_hardware ux500_pcm_hw = {
                SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_RESUME |
                SNDRV_PCM_INFO_PAUSE,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE |
-               SNDRV_PCM_FMTBIT_U16_LE |
-               SNDRV_PCM_FMTBIT_S16_BE |
-               SNDRV_PCM_FMTBIT_U16_BE,
-       .rates = SNDRV_PCM_RATE_KNOT,
-       .rate_min = UX500_PLATFORM_MIN_RATE,
-       .rate_max = UX500_PLATFORM_MAX_RATE,
-       .channels_min = UX500_PLATFORM_MIN_CHANNELS,
-       .channels_max = UX500_PLATFORM_MAX_CHANNELS,
        .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
        .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
        .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
@@ -65,14 +50,10 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
        struct snd_pcm_substream *substream)
 {
        struct snd_soc_dai *dai = rtd->cpu_dai;
-       struct device *dev = dai->dev;
        u16 per_data_width, mem_data_width;
        struct stedma40_chan_cfg *dma_cfg;
        struct ux500_msp_dma_params *dma_params;
 
-       dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
-               snd_pcm_stream_str(substream));
-
        dma_params = snd_soc_dai_get_dma_data(dai, substream);
        dma_cfg = dma_params->dma_cfg;
 
@@ -108,26 +89,36 @@ static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
                struct dma_slave_config *slave_config)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ux500_msp_dma_params *dma_params;
-       struct stedma40_chan_cfg *dma_cfg;
+       struct msp_i2s_platform_data *pdata = rtd->cpu_dai->dev->platform_data;
+       struct snd_dmaengine_dai_dma_data *snd_dma_params;
+       struct ux500_msp_dma_params *ste_dma_params;
+       dma_addr_t dma_addr;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       dma_cfg = dma_params->dma_cfg;
+       if (pdata) {
+               ste_dma_params =
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+               dma_addr = ste_dma_params->tx_rx_addr;
+       } else {
+               snd_dma_params =
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+               dma_addr = snd_dma_params->addr;
+       }
 
        ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
        if (ret)
                return ret;
 
        slave_config->dst_maxburst = 4;
-       slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
        slave_config->src_maxburst = 4;
-       slave_config->src_addr_width = dma_cfg->src_info.data_width;
+
+       slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+       slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               slave_config->dst_addr = dma_params->tx_rx_addr;
+               slave_config->dst_addr = dma_addr;
        else
-               slave_config->src_addr = dma_params->tx_rx_addr;
+               slave_config->src_addr = dma_addr;
 
        return 0;
 }
@@ -139,15 +130,25 @@ static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
        .prepare_slave_config = ux500_pcm_prepare_slave_config,
 };
 
+static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = {
+       .compat_request_channel = ux500_pcm_request_chan,
+       .prepare_slave_config = ux500_pcm_prepare_slave_config,
+};
+
 int ux500_pcm_register_platform(struct platform_device *pdev)
 {
+       const struct snd_dmaengine_pcm_config *pcm_config;
+       struct device_node *np = pdev->dev.of_node;
        int ret;
 
-       ret = snd_dmaengine_pcm_register(&pdev->dev,
-                       &ux500_dmaengine_pcm_config,
-                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-                       SND_DMAENGINE_PCM_FLAG_COMPAT |
-                       SND_DMAENGINE_PCM_FLAG_NO_DT);
+       if (np)
+               pcm_config = &ux500_dmaengine_of_pcm_config;
+       else
+               pcm_config = &ux500_dmaengine_pcm_config;
+
+       ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config,
+                                        SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+                                        SND_DMAENGINE_PCM_FLAG_COMPAT);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "%s: ERROR: Failed to register platform '%s' (%d)!\n",