audio: add new audio features
authorShuai Li <shuai.li@amlogic.com>
Wed, 7 Jun 2017 03:41:42 +0000 (20:41 -0700)
committerXing Wang <xing.wang@amlogic.com>
Wed, 28 Jun 2017 03:18:53 +0000 (11:18 +0800)
PD#145715: new audio features:
1. mute gpio
2. tas575x driver
3. multi-codec prefix name
4. tlv320adc3101 can revert bclk
5. set clkmsr to check mclk for AXG tdm

Change-Id: Ibd3d9ed8086715439c4bebeb574b998c1ffd1e45
Signed-off-by: Shuai Li <shuai.li@amlogic.com>
17 files changed:
MAINTAINERS
arch/arm64/boot/dts/amlogic/axg_s400.dts
arch/arm64/boot/dts/amlogic/axg_s420.dts
arch/arm64/configs/meson64_defconfig
drivers/amlogic/clk/clk_measure.c
include/linux/amlogic/clk_measure.h [new file with mode: 0644]
sound/soc/amlogic/auge/card.c
sound/soc/amlogic/auge/card_utils.c
sound/soc/amlogic/auge/card_utils.h
sound/soc/amlogic/auge/tdm.c
sound/soc/amlogic/auge/tdm_hw.c
sound/soc/codecs/amlogic/Kconfig
sound/soc/codecs/amlogic/Makefile
sound/soc/codecs/amlogic/pcm186x.c
sound/soc/codecs/amlogic/tas575x.c [new file with mode: 0644]
sound/soc/codecs/amlogic/tas575x.h [new file with mode: 0644]
sound/soc/codecs/amlogic/tlv320adc3101.c

index 92ce515..42e1b49 100644 (file)
@@ -13925,6 +13925,7 @@ M: xing wang <xing.wang@amlogic.com>
 F: sound/soc/amlogic/meson/*
 F: sound/soc/amlogic/auge/*
 F: sound/soc/codecs/amlogic/*
+F: sound/soc/codecs/amlogic/tas575x.c
 F: include/dt-bindings/clock/amlogic,axg-audio-clk.h
 
 AMLOGIC Security Support
@@ -13969,3 +13970,7 @@ F: drivers/amlogic/irblaster/irblaster.c
 F: drivers/amlogic/irblaster/irblaster.h
 F: drivers/amlogic/irblaster/Kconfig
 F: drivers/amlogic/irblaster/Makefile
+
+AMLOGIC AXG ADD CLKMSR INTERFACE
+M:     wang xing <xing.wang@amlogic.com>
+F:     include/linux/amlogic/clk_measure.h
\ No newline at end of file
index ecb54b8..298bbc4 100644 (file)
                        mclk-fs = <256>;
                        continuous-clock;
                        //bitclock-inversion;
-                       //frame-inversion;
+                       frame-inversion;
                        bitclock-master = <&aml_tdmb>;
                        frame-master = <&aml_tdmb>;
                        cpu {
                                system-clock-frequency = <12288000>;
                        };
                        codec {
+                               prefix-names = "3101_A", "3101_B",
+                                       "3101_C", "3101_D";
                                sound-dai = <&tlv320adc3101_32 &tlv320adc3101_30
                                        &tlv320adc3101_34 &tlv320adc3101_36>;
                        };
                        format = "i2s";
                        mclk-fs = <256>;
                        continuous-clock;
-                       bitclock-inversion;
+                       //bitclock-inversion;
                        frame-inversion;
                        //bitclock-master = <&aml_tdmc>;
                        //frame-master = <&aml_tdmc>;
                                system-clock-frequency = <12288000>;
                        };
                        codec {
+                               prefix-names = "5707_A", "5707_B";
                                sound-dai = <&tas5707_36 &tas5707_3a
                                                &dummy_codec>;
                        };
        aml_tdma: tdma {
                compatible = "amlogic, snd-tdma";
                #sound-dai-cells = <0>;
-               dai-tdm-lane-slot-mask = <1>;
+               dai-tdm-lane-slot-mask-in = <1>;
+               dai-tdm-lane-slot-mask-out = <1>;
                dai-tdm-clk-sel = <0>;
                tdm_from_ddr = <0>;
                tdm_to_ddr = <0>;
        aml_tdmb: tdmb {
                compatible = "amlogic, snd-tdmb";
                #sound-dai-cells = <0>;
-               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-lane-slot-mask-in = <1 1 1 1>;
                dai-tdm-clk-sel = <1>;
                tdm_from_ddr = <1>;
                tdm_to_ddr = <1>;
index c357107..710c2c4 100644 (file)
                //aml-audio-card,mclk-fs = <256>;
 
                aml-audio-card,dai-link@0 {
-                       format = "i2s";//"dsp_a";
+                       format = "dsp_a";
                        mclk-fs = <256>;//512
                        continuous-clock;
                        bitclock-inversion;
                        format = "i2s";
                        mclk-fs = <256>;
                        continuous-clock;
-                       bitclock-inversion;
-                       //frame-inversion;
+                       //bitclock-inversion;
+                       frame-inversion;
                        bitclock-master = <&aml_tdmb>;
                        frame-master = <&aml_tdmb>;
                        cpu {
                                system-clock-frequency = <12288000>;
                        };
                        codec {
-                               //sound-dai = <&dummy_codec &dummy_codec>;
-                               sound-dai = <&tas5707_36>;
+                               sound-dai = <&tas5707_36 &tlv320adc3101_32>;
                        };
                };
 
                        format = "i2s";
                        mclk-fs = <256>;
                        continuous-clock;
-                       bitclock-inversion;
-                       //frame-inversion;
+                       /* tdmb clk using tdmc so no bclk-inv */
+                       //bitclock-inversion;
+                       frame-inversion;
                        bitclock-master = <&aml_tdmc>;
                        frame-master = <&aml_tdmc>;
                        cpu {
                                system-clock-frequency = <12288000>;
                        };
                        codec {
-                               //sound-dai = <&tas5707_36 &tas5707_3a>;
-                               sound-dai = <&dummy_codec &dummy_codec>;
+                               sound-dai = <&dummy_codec>;
                        };
                };
 
                compatible = "ti,tlv320adc3101";
                #sound-dai-cells = <0>;
                reg = <0x19>;
-               status = "disabled";
+               status = "okay";
        };
 
        tas5707_36: tas5707_36@36 {
                compatible = "ti,tlv320adc3101";
                #sound-dai-cells = <0>;
                reg = <0x18>;
-               status = "okay";
+               status = "disable";
        };
        tlv320adc3101_34: tlv320adc3101_34@30 {
                compatible = "ti,tlv320adc3101";
                #sound-dai-cells = <0>;
                reg = <0x1a>;
-               status = "okay";
+               status = "disable";
        };
        tlv320adc3101_36: tlv320adc3101_36@30 {
                compatible = "ti,tlv320adc3101";
                #sound-dai-cells = <0>;
                reg = <0x1b>;
-               status = "okay";
+               status = "disable";
        };
 };
 
        aml_tdmb: tdmb {
                compatible = "amlogic, snd-tdmb";
                #sound-dai-cells = <0>;
-               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-lane-slot-mask-out = <1 0>;
+               dai-tdm-lane-slot-mask-in = <0 1>;
                dai-tdm-clk-sel = <2>;
                tdm_from_ddr = <1>;
                tdm_to_ddr = <1>;
                                GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
                interrupt-names = "tdmin", "tdmout";
                pinctrl-names = "tdm_pins";
-               pinctrl-0 = <&tdmb_mclk &tdmout_b>;
+               pinctrl-0 = <&tdmb_mclk &tdmout_b &tdmin_b>;
        };
 
        aml_tdmc: tdmc {
                compatible = "amlogic, snd-tdmc";
                #sound-dai-cells = <0>;
-               dai-tdm-lane-slot-mask = <1 1 1 1>;
+               dai-tdm-lane-slot-mask-out = <1 0>;
+               dai-tdm-lane-slot-mask-in = <0 1>;
                dai-tdm-clk-sel = <2>;
                tdm_from_ddr = <2>;
                tdm_to_ddr = <2>;
                                GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
                interrupt-names = "tdmin", "tdmout";
                pinctrl-names = "tdm_pins";
-               pinctrl-0 = <&tdmc_mclk &tdmout_c>;
+               pinctrl-0 = <&tdmc_mclk &tdmout_c &tdmin_c>;
        };
 
        aml_spdif: spdif {
 
        tdmout_b: tdmout_b {
                mux {
-                       pins = "GPIOA_8", "GPIOA_9", "GPIOA_10",
-                               "GPIOA_11";
+                       pins = "GPIOA_8", "GPIOA_9", "GPIOA_10";
                        function = "tdmb_out";
                };
        };
         *      };
         *};
         */
+       tdmin_b: tdmin_b {
+               mux {
+                       pins = "GPIOA_11";
+                       function = "tdmb_in";
+               };
+       };
 
        tdmc_mclk: tdmc_mclk {
                mux {
 
        tdmout_c:tdmout_c {
                mux {
-                       pins = "GPIOA_2", "GPIOA_3", "GPIOA_4",
-                               "GPIOA_5";
+                       pins = "GPIOA_2", "GPIOA_3", "GPIOA_4";
                        function = "tdmc_out";
                };
        };
 
-       /*
-        *tdmin_c:tdmin_c {
-        *      mux {
-        *              pins = "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7";
-        *              function = "tdmc_in";
-        *      };
-        *};
-        */
+       tdmin_c:tdmin_c {
+               mux {
+                       pins = "GPIOA_5";
+                       function = "tdmc_in";
+               };
+       };
 
        spdifout: spidfout {
                mux {
index c622932..ea86d33 100644 (file)
@@ -389,6 +389,7 @@ CONFIG_AMLOGIC_SND_SOC_TLV320ADC3101=y
 CONFIG_AMLOGIC_SND_SOC_PCM186X=y
 CONFIG_AMLOGIC_SND_SOC_SSM3515=y
 CONFIG_AMLOGIC_SND_SOC_SSM3525=y
+CONFIG_AMLOGIC_SND_SOC_TAS575X=y
 CONFIG_AMLOGIC_SND_SOC=y
 CONFIG_AMLOGIC_SND_SOC_MESON=y
 CONFIG_AMLOGIC_SND_SOC_AUGE=y
index 2b60aae..87ab692 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/platform_device.h>
 #include <linux/amlogic/cpu_version.h>
 #include <linux/amlogic/iomap.h>
+#include <linux/amlogic/clk_measure.h>
 
 #undef pr_fmt
 #define pr_fmt(fmt) "clkmsr: " fmt
diff --git a/include/linux/amlogic/clk_measure.h b/include/linux/amlogic/clk_measure.h
new file mode 100644 (file)
index 0000000..0a615a4
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * include/linux/amlogic/clk_measure.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __CLK_MEASURE_H__
+#define __CLK_MEASURE_H__
+
+extern int meson_clk_measure(unsigned int clk_mux);
+
+#endif
index f889069..5ec2464 100644 (file)
@@ -45,11 +45,15 @@ struct aml_card_data {
        struct aml_jack hp_jack;
        struct aml_jack mic_jack;
        struct snd_soc_dai_link *dai_link;
+       int spk_mute_gpio;
+       bool spk_mute_active_low;
 };
 
 #define aml_priv_to_dev(priv) ((priv)->snd_card.dev)
 #define aml_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
 #define aml_priv_to_props(priv, i) ((priv)->dai_props + (i))
+#define aml_card_to_priv(card) \
+       (container_of(card, struct aml_card_data, snd_card))
 
 #define DAI    "sound-dai"
 #define CELL   "#sound-dai-cells"
@@ -151,6 +155,7 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct aml_dai_props *dai_props =
@@ -158,7 +163,6 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
        unsigned int mclk, mclk_fs = 0;
        int i = 0, ret = 0;
 
-       pr_info("%s ..numcodec:%d\n", __func__, rtd->num_codecs);
        if (priv->mclk_fs)
                mclk_fs = priv->mclk_fs;
        else if (dai_props->mclk_fs)
@@ -168,7 +172,7 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
                mclk = params_rate(params) * mclk_fs;
 
                for (i = 0; i < rtd->num_codecs; i++) {
-                       struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+                       codec_dai = rtd->codec_dais[i];
 
                        ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
                                SND_SOC_CLOCK_IN);
@@ -176,6 +180,7 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
                        if (ret && ret != -ENOTSUPP)
                                goto err;
                }
+
                ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
                                             SND_SOC_CLOCK_OUT);
                if (ret && ret != -ENOTSUPP)
@@ -199,11 +204,15 @@ static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dai *cpu = rtd->cpu_dai;
        struct aml_dai_props *dai_props =
                aml_priv_to_props(priv, rtd->num);
-       int ret;
+       int ret, i;
 
-       ret = aml_card_init_dai(codec, &dai_props->codec_dai);
-       if (ret < 0)
-               return ret;
+       for (i = 0; i < rtd->num_codecs; i++) {
+               codec = rtd->codec_dais[i];
+
+               ret = aml_card_init_dai(codec, &dai_props->codec_dai);
+               if (ret < 0)
+                       return ret;
+       }
 
        ret = aml_card_init_dai(cpu, &dai_props->cpu_dai);
        if (ret < 0)
@@ -294,6 +303,10 @@ static int aml_card_dai_link_of(struct device_node *node,
        if (ret < 0)
                goto dai_link_of_err;
 
+       ret = aml_card_parse_codec_confs(codec, &priv->snd_card);
+       if (ret < 0)
+               goto dai_link_of_err;
+
        ret = aml_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
        if (ret < 0)
                goto dai_link_of_err;
@@ -366,6 +379,78 @@ static int aml_card_parse_aux_devs(struct device_node *node,
        return 0;
 }
 
+static int spk_mute_set(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *soc_card = snd_kcontrol_chip(kcontrol);
+       struct aml_card_data *priv = aml_card_to_priv(soc_card);
+       int gpio = priv->spk_mute_gpio;
+       bool active_low = priv->spk_mute_active_low;
+       bool mute = ucontrol->value.integer.value[0];
+
+       if (gpio_is_valid(gpio)) {
+               bool value = active_low ? !mute : mute;
+
+               gpio_set_value(gpio, value);
+               pr_info("spk_mute_set: mute flag = %d\n", mute);
+       }
+
+       return 0;
+}
+
+static int spk_mute_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *soc_card = snd_kcontrol_chip(kcontrol);
+       struct aml_card_data *priv = aml_card_to_priv(soc_card);
+       int gpio = priv->spk_mute_gpio;
+       bool active_low = priv->spk_mute_active_low;
+
+       if (gpio_is_valid(gpio)) {
+               bool value = gpio_get_value(gpio);
+               bool mute = active_low ? !value : value;
+
+               ucontrol->value.integer.value[0] = mute;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_SINGLE_BOOL_EXT("SPK mute", 0,
+                           spk_mute_get,
+                           spk_mute_set),
+};
+
+static int aml_card_parse_gpios(struct device_node *node,
+                                          struct aml_card_data *priv)
+{
+       struct device *dev = aml_priv_to_dev(priv);
+       struct snd_soc_card *soc_card = &priv->snd_card;
+       enum of_gpio_flags flags;
+       int gpio;
+       bool active_low;
+       int ret;
+
+       gpio = of_get_named_gpio_flags(node, "spk_mute", 0, &flags);
+       priv->spk_mute_gpio = gpio;
+
+       if (gpio_is_valid(gpio)) {
+               active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
+               flags = active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+               priv->spk_mute_active_low = active_low;
+
+               ret = devm_gpio_request_one(dev, gpio, flags, "spk_mute");
+               if (ret < 0)
+                       return ret;
+
+               ret = snd_soc_add_card_controls(soc_card, card_controls,
+                                       ARRAY_SIZE(card_controls));
+       }
+
+       return 0;
+}
+
 static int aml_card_parse_of(struct device_node *node,
                                     struct aml_card_data *priv)
 {
@@ -512,6 +597,11 @@ static int aml_card_probe(struct platform_device *pdev)
        snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
        ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+       if (ret < 0) {
+               goto err;
+       }
+
+       ret = aml_card_parse_gpios(np, priv);
        if (ret >= 0)
                return ret;
 err:
index 3b6b8e1..68cea02 100644 (file)
 #include "card_utils.h"
 
 int aml_card_parse_daifmt(struct device *dev,
-                                 struct device_node *node,
-                                 struct device_node *codec,
-                                 char *prefix,
-                                 unsigned int *retfmt)
+                       struct device_node *node,
+                       struct device_node *codec,
+                       char *prefix,
+                       unsigned int *retfmt)
 {
        struct device_node *bitclkmaster = NULL;
        struct device_node *framemaster = NULL;
@@ -63,8 +63,8 @@ int aml_card_parse_daifmt(struct device *dev,
 }
 
 int aml_card_set_dailink_name(struct device *dev,
-                                     struct snd_soc_dai_link *dai_link,
-                                     const char *fmt, ...)
+                       struct snd_soc_dai_link *dai_link,
+                       const char *fmt, ...)
 {
        va_list ap;
        char *name = NULL;
@@ -85,7 +85,7 @@ int aml_card_set_dailink_name(struct device *dev,
 }
 
 int aml_card_parse_card_name(struct snd_soc_card *card,
-                                    char *prefix)
+                       char *prefix)
 {
        char prop[128];
        int ret;
@@ -104,8 +104,8 @@ int aml_card_parse_card_name(struct snd_soc_card *card,
 }
 
 int aml_card_parse_clk(struct device_node *node,
-                              struct device_node *dai_of_node,
-                              struct aml_dai *aml_dai)
+                       struct device_node *dai_of_node,
+                       struct aml_dai *aml_dai)
 {
        struct clk *clk;
        u32 val;
@@ -133,11 +133,11 @@ int aml_card_parse_clk(struct device_node *node,
 }
 
 int aml_card_parse_dai(struct device_node *node,
-                                   struct device_node **dai_of_node,
-                                   const char **dai_name,
-                                   const char *list_name,
-                                   const char *cells_name,
-                                   int *is_single_link)
+                       struct device_node **dai_of_node,
+                       const char **dai_name,
+                       const char *list_name,
+                       const char *cells_name,
+                       int *is_single_link)
 {
        struct of_phandle_args args;
        int ret;
@@ -168,8 +168,50 @@ int aml_card_parse_dai(struct device_node *node,
        return 0;
 }
 
+int aml_card_parse_codec_confs(struct device_node *codec_np,
+                       struct snd_soc_card *card)
+{
+       struct snd_soc_codec_conf *confs;
+       int num_confs;
+       int i = 0, ret = 0;
+
+       num_confs = of_property_count_strings(codec_np, "prefix-names");
+       if (num_confs <= 0)
+               return 0;
+
+       confs = devm_kzalloc(card->dev,
+                       sizeof(*confs) * num_confs, GFP_KERNEL);
+       if (!confs) {
+               ret = -ENOMEM;
+               goto codec_confs_end;
+       }
+
+       card->codec_conf = confs;
+       card->num_configs = num_confs;
+       /*
+        * parse "prefix-names" and "sound-dai" pair
+        * add codec_conf by these two items
+        */
+       for (i = 0; i < num_confs; i++) {
+               ret = of_property_read_string_index(codec_np, "prefix-names", i,
+                                       &confs[i].name_prefix);
+               if (ret < 0)
+                       goto codec_confs_end;
+
+               confs[i].of_node = of_parse_phandle(codec_np, "sound-dai", i);
+               if (!confs[i].of_node) {
+                       ret = -ENODATA;
+                       goto codec_confs_end;
+               }
+       }
+
+codec_confs_end:
+
+       return ret;
+}
+
 int aml_card_init_dai(struct snd_soc_dai *dai,
-                             struct aml_dai *aml_dai)
+                       struct aml_dai *aml_dai)
 {
        int ret;
 
@@ -210,7 +252,7 @@ int aml_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
 }
 
 void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
-                                      int is_single_links)
+                       int is_single_links)
 {
        /*
         * In soc_bind_dai_link() will check cpu name after
@@ -228,7 +270,8 @@ void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
 int aml_card_clean_reference(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *dai_link;
-       int num_links;
+       struct snd_soc_codec_conf *codec_conf;
+       int num_links, num_confs;
 
        for (num_links = 0, dai_link = card->dai_link;
             num_links < card->num_links;
@@ -236,5 +279,12 @@ int aml_card_clean_reference(struct snd_soc_card *card)
                of_node_put(dai_link->cpu_of_node);
                of_node_put(dai_link->codec_of_node);
        }
+
+       for (num_confs = 0, codec_conf = card->codec_conf;
+               num_confs < card->num_configs;
+               num_confs++, codec_conf++) {
+               of_node_put(codec_conf->of_node);
+       }
+
        return 0;
 }
index c88dcf8..49dafd6 100644 (file)
@@ -31,24 +31,24 @@ struct aml_dai {
 };
 
 int aml_card_parse_daifmt(struct device *dev,
-                                 struct device_node *node,
-                                 struct device_node *codec,
-                                 char *prefix,
-                                 unsigned int *retfmt);
+                               struct device_node *node,
+                               struct device_node *codec,
+                               char *prefix,
+                               unsigned int *retfmt);
 __printf(3, 4)
 int aml_card_set_dailink_name(struct device *dev,
-                                     struct snd_soc_dai_link *dai_link,
-                                     const char *fmt, ...);
+                               struct snd_soc_dai_link *dai_link,
+                               const char *fmt, ...);
 int aml_card_parse_card_name(struct snd_soc_card *card,
-                                    char *prefix);
+                               char *prefix);
 
 #define aml_card_parse_clk_cpu(node, dai_link, aml_dai)                \
        aml_card_parse_clk(node, dai_link->cpu_of_node, aml_dai)
 #define aml_card_parse_clk_codec(node, dai_link, aml_dai)              \
        aml_card_parse_clk(node, dai_link->codec_of_node, aml_dai)
 int aml_card_parse_clk(struct device_node *node,
-                              struct device_node *dai_of_node,
-                              struct aml_dai *aml_dai);
+                               struct device_node *dai_of_node,
+                               struct aml_dai *aml_dai);
 
 #define aml_card_parse_cpu(node, dai_link,                             \
                        list_name, cells_name, is_single_link)  \
@@ -61,18 +61,20 @@ int aml_card_parse_clk(struct device_node *node,
        aml_card_parse_dai(node, &dai_link->platform_of_node,           \
                NULL, list_name, cells_name, NULL)
 int aml_card_parse_dai(struct device_node *node,
-                                 struct device_node **endpoint_np,
-                                 const char **dai_name,
-                                 const char *list_name,
-                                 const char *cells_name,
-                                 int *is_single_links);
+                               struct device_node **endpoint_np,
+                               const char **dai_name,
+                               const char *list_name,
+                               const char *cells_name,
+                               int *is_single_links);
+int aml_card_parse_codec_confs(struct device_node *codec_np,
+                               struct snd_soc_card *card);
 
 int aml_card_init_dai(struct snd_soc_dai *dai,
-                             struct aml_dai *aml_dai);
+                               struct aml_dai *aml_dai);
 
 int aml_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link);
 void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
-                                     int is_single_links);
+                               int is_single_links);
 
 int aml_card_clean_reference(struct snd_soc_card *card);
 
index 659500e..6ba4b42 100644 (file)
@@ -31,6 +31,8 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
+#include <linux/amlogic/clk_measure.h>
+
 #include "ddr_mngr.h"
 #include "tdm_hw.h"
 
@@ -91,10 +93,10 @@ static const struct snd_pcm_hardware aml_tdm_hardware = {
            SNDRV_PCM_FMTBIT_S32_LE,
 
        .period_bytes_min = 64,
-       .period_bytes_max = 128 * 1024,
+       .period_bytes_max = 256 * 1024,
        .periods_min = 2,
        .periods_max = 1024,
-       .buffer_bytes_max = 256 * 1024,
+       .buffer_bytes_max = 512 * 1024,
 
        .rate_min = 8000,
        .rate_max = 48000,
@@ -142,7 +144,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np,
        int i;
 
        if (!of_slot_mask)
-               return 0;
+               return -EINVAL;
 
        val /= sizeof(u32);
        for (i = 0; i < val; i++)
@@ -330,10 +332,6 @@ struct snd_soc_platform_driver aml_tdm_platform = {
 static int aml_dai_tdm_startup(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *cpu_dai)
 {
-       struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
-
-       aml_tdm_fifo_reset(p_tdm->actrl, substream->stream, p_tdm->id);
-
        return 0;
 }
 
@@ -434,8 +432,11 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               aml_tdm_enable(p_tdm->actrl,
-                       substream->stream, p_tdm->id, true);
+               /* reset fifo here.
+                * If not, xrun will cause channel mapping mismatch
+                */
+               aml_tdm_fifo_reset(p_tdm->actrl, substream->stream, p_tdm->id);
+
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        dev_info(substream->pcm->card->dev, "tdm playback enable\n");
                        aml_frddr_enable(p_tdm->fddr, 1);
@@ -444,6 +445,9 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
                        aml_toddr_enable(p_tdm->tddr, 1);
                }
 
+               aml_tdm_enable(p_tdm->actrl,
+                       substream->stream, p_tdm->id, true);
+
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -451,10 +455,10 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
                aml_tdm_enable(p_tdm->actrl,
                        substream->stream, p_tdm->id, false);
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       dev_info(substream->pcm->card->dev, "tdm playback enable\n");
+                       dev_info(substream->pcm->card->dev, "tdm playback stop\n");
                        aml_frddr_enable(p_tdm->fddr, 0);
                } else {
-                       dev_info(substream->pcm->card->dev, "tdm capture enable\n");
+                       dev_info(substream->pcm->card->dev, "tdm capture stop\n");
                        aml_toddr_enable(p_tdm->tddr, 0);
                }
                break;
@@ -468,14 +472,21 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
 static int pcm_setting_init(struct pcm_setting *setting, unsigned int rate,
                        unsigned int channels)
 {
-
+       unsigned int ratio = 0;
        setting->lrclk = rate;
        setting->bclk_lrclk_ratio = setting->slots * setting->slot_width;
        setting->bclk = setting->lrclk * setting->bclk_lrclk_ratio;
 
        /* calculate mclk */
-       setting->sysclk_bclk_ratio = 4;
-       setting->sysclk = 4 * setting->bclk;
+       if (setting->pcm_mode == SND_SOC_DAIFMT_DSP_A ||
+               setting->pcm_mode == SND_SOC_DAIFMT_DSP_B) {
+               /* for some TDM codec, mclk limites */
+               ratio = 2;
+       } else {
+               ratio = 4;
+       }
+       setting->sysclk_bclk_ratio = ratio;
+       setting->sysclk = ratio * setting->bclk;
 
        return 0;
 }
@@ -600,11 +611,31 @@ static int aml_dai_set_tdm_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        return 0;
 }
 
+/* mpll clk range from 5M to 500M */
+#define AML_MPLL_FREQ_MIN      5000000
+static unsigned int aml_mpll_mclk_ratio(unsigned int freq)
+{
+       unsigned int i, ratio = 2;
+       unsigned int mpll_freq = 0;
+
+       for (i = 1; i < 15; i++) {
+               ratio = 1 << i;
+               mpll_freq = freq * ratio;
+
+               if (mpll_freq > AML_MPLL_FREQ_MIN)
+                       break;
+       }
+
+       pr_info("TDM mpll/mclk = %d\n", ratio);
+
+       return ratio;
+}
+
 static void aml_tdm_set_mclk(struct aml_tdm *p_tdm)
 {
        struct aml_audio_controller *actrl = p_tdm->actrl;
        unsigned int clk_id, offset;
-       unsigned int mpll_freq = 0;
+       unsigned int mpll_freq = 0, sysclk_freq = 0;
 
        offset = p_tdm->clk_sel;
 
@@ -613,25 +644,17 @@ static void aml_tdm_set_mclk(struct aml_tdm *p_tdm)
                return;
 
        clk_id = p_tdm->id;
+       sysclk_freq = p_tdm->setting.sysclk;
 
-       if (p_tdm->setting.sysclk) {
-               unsigned int mul = 4;
+       if (sysclk_freq) {
+               unsigned int mul = aml_mpll_mclk_ratio(sysclk_freq);
 
-               mpll_freq = p_tdm->setting.sysclk * mul;
+               mpll_freq = sysclk_freq * mul;
                clk_set_rate(p_tdm->clk, mpll_freq);
                aml_audiobus_write(actrl, EE_AUDIO_MCLK_A_CTRL + offset,
                                                1 << 31 | //clk enable
                                                clk_id << 24 | // clk src
                                                (mul - 1)); //clk_div mclk
-
-               if (offset == 2) {
-                       //enable another mclka also;
-                       offset = 0;
-                       aml_audiobus_write(actrl, EE_AUDIO_MCLK_A_CTRL + offset,
-                                       1 << 31 | //clk enable
-                                       clk_id << 24 | // clk src
-                                       (mul - 1)); //clk_div mclk
-               }
        }
 }
 
@@ -913,6 +936,9 @@ static int aml_tdm_platform_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       /* complete mclk for tdm */
+       meson_clk_measure((1<<16) | 0x67);
+
        /* parse DTS configured ddr */
        ret = of_property_read_u32(node, "tdm_from_ddr",
                        &p_tdm->from_ddr_num);
index 25f24e4..6cf3b14 100644 (file)
@@ -227,7 +227,9 @@ void aml_tdm_set_format(
        // sclk_ph0 (pad) invert
        off_set = EE_AUDIO_MST_B_SCLK_CTRL1 - EE_AUDIO_MST_A_SCLK_CTRL1;
        reg_out = EE_AUDIO_MST_A_SCLK_CTRL1 + off_set * id;
-       aml_audiobus_update_bits(actrl, reg_out, 0x3f, binv);
+       aml_audiobus_update_bits(actrl, reg_out, 0x3f, !binv);
+       if (!binv)
+               bclkin_skew = 4;
 
        off_set = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
        reg_out = EE_AUDIO_TDMOUT_A_CTRL0 + off_set * id;
index 4dcd663..eafdb2a 100644 (file)
@@ -114,4 +114,13 @@ config AMLOGIC_SND_SOC_SSM3515
                Enable support for SSM3515 CODEC.
                Select this if SSM3515 is connected via an I2C bus.
 
+config AMLOGIC_SND_SOC_TAS575X
+       bool "Texas Instruments TAS575X"
+       depends on AMLOGIC_SND_SOC_CODECS
+       depends on I2C
+       default n
+       help
+               Enable Support for Texas INstruments TAS575X CODEC.
+               Select this if your TAS575X is connected via an I2C bus.
+
 #endif #AMLOGIC_SND_SOC_CODECS
index 9c3fc35..81ba8e5 100644 (file)
@@ -25,3 +25,5 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_TLV320ADC3101) += snd-soc-tlv320adc3101.o
 obj-$(CONFIG_AMLOGIC_SND_SOC_PCM186X) += snd-soc-pcm186x.o
 obj-$(CONFIG_AMLOGIC_SND_SOC_SSM3515) += snd-soc-ssm3515.o
 obj-$(CONFIG_AMLOGIC_SND_SOC_SSM3525) += snd-soc-ssm3525.o
+obj-$(CONFIG_AMLOGIC_SND_SOC_TAS575X) += tas575x.o
+
index ad9e99d..4fdc83a 100644 (file)
@@ -773,7 +773,6 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        unsigned int rate = params_rate(params);
        unsigned int format = params_format(params);
        unsigned int width = params_width(params);
@@ -786,7 +785,6 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
        unsigned int tdm_offset;
        unsigned int tdm_tx_sel;
        int ret;
-       unsigned int fmt;
 
        dev_dbg(codec->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
                __func__, rate, format, width, channels);
@@ -821,14 +819,6 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       fmt = SND_SOC_DAIFMT_DSP_A |
-               SND_SOC_DAIFMT_CBS_CFS |
-               SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CONT;
-
-       ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
-       if (ret)
-               return ret;
        /*
         * In DSP/TDM mode, the LRCLK divider must be 256 as per datasheet.
         * Also, complete the codec serial audio interface format configuration
diff --git a/sound/soc/codecs/amlogic/tas575x.c b/sound/soc/codecs/amlogic/tas575x.c
new file mode 100644 (file)
index 0000000..37de371
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * sound/soc/codecs/amlogic/tas575x.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * Author: Shuai Li <shuai.li@amlogic.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "tas575x.h"
+
+struct tas575x_private {
+       //const struct tas575x_chip      *chip;
+       struct regmap   *regmap;
+       unsigned int    format;
+       unsigned int    tx_slots_mask;
+       unsigned int    slot_width;
+};
+
+ /* Power-up register defaults */
+struct reg_default tas575x_reg_defaults[] = {
+       {TAS575X_MUTE,  0},
+};
+
+static int tas575x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+       struct tas575x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+
+       pr_info("%s, format:0x%x\n", __func__, format);
+       priv->format = format;
+
+       return 0;
+}
+
+static int tas575x_set_tdm_slot(struct snd_soc_dai *dai,
+               unsigned int tx_mask, unsigned int rx_mask,
+               int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas575x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int first_slot, last_slot, tdm_offset;
+       int ret;
+
+       tx_mask = priv->tx_slots_mask;
+       first_slot = __ffs(tx_mask);
+       last_slot = __fls(tx_mask);
+
+       dev_dbg(codec->dev,
+               "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
+               __func__, tx_mask, rx_mask, slots, slot_width);
+
+       if (last_slot - first_slot != hweight32(tx_mask) - 1) {
+               dev_err(codec->dev, "tdm tx mask must be contiguous\n");
+               return -EINVAL;
+       }
+
+       tdm_offset = first_slot * slot_width;
+
+       dev_info(codec->dev, "tdm_offset:%#x, width:%d\n",
+                       tdm_offset, slot_width);
+
+       if (tdm_offset > 255) {
+               dev_err(codec->dev, "tdm tx slot selection out of bounds\n");
+               return -EINVAL;
+       }
+
+       priv->slot_width = slot_width;
+       tdm_offset += 1;
+       ret = regmap_write(priv->regmap, TAS575X_I2S_SHIFT, tdm_offset);
+       if (ret < 0)
+               dev_err(codec->dev, "failed to write register: %d\n", ret);
+       return ret;
+}
+
+static int tas575x_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas575x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+       u32 val, width;
+       bool is_dsp = false;
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x00 << 4;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               val = 0x01 << 4;
+               is_dsp = true;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = 0x02 << 4;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x03 << 4;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       width = params_width(params);
+       if (is_dsp) {
+               /* in dsp format, bit width is fixed */
+               width = priv->slot_width;
+       } else {
+               width = params_width(params);
+       }
+
+       switch (width) {
+       case 16:
+               val |= 0x00;
+               break;
+       case 20:
+               val |= 0x01;
+               break;
+       case 24:
+               val |= 0x02;
+               break;
+       case 32:
+               val |= 0x03;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       pr_info("%s, val:0x%x\n", __func__, val);
+       return snd_soc_update_bits(codec, TAS575X_I2S_FMT,
+                                 0x33, val);
+}
+
+static int tas575x_probe(struct snd_soc_codec *codec)
+{
+       /* set stanby mode */
+       snd_soc_write(codec, TAS575X_STANDBY, 0x10);
+       /* reset */
+       snd_soc_write(codec, TAS575X_RESET, 0x01);
+       /* set for DAC path */
+       snd_soc_write(codec, TAS575X_DATA_PATH, 0x22);
+       /* vlome control default to -30db*/
+       snd_soc_write(codec, TAS575X_CH_B_DIG_VOL, 0x6c);
+       snd_soc_write(codec, TAS575X_CH_A_DIG_VOL, 0x6c);
+       /* exit stanby mode */
+       snd_soc_write(codec, TAS575X_STANDBY, 0x0);
+
+       return 0;
+}
+
+static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
+
+static const struct snd_kcontrol_new tas575x_snd_controls[] = {
+       SOC_SINGLE_TLV("Channel B Playback Volume",
+                      TAS575X_CH_B_DIG_VOL, 0, 0xff, 0, dac_tlv),
+       SOC_SINGLE_TLV("Channel A Playback Volume",
+                          TAS575X_CH_A_DIG_VOL, 0, 0xff, 0, dac_tlv),
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_tas575x = {
+       .probe = tas575x_probe,
+       //.remove = tas575x_remove,
+       //.suspend = tas575x_suspend,
+       //.resume = tas575x_resume,
+
+       .component_driver = {
+               .controls               = tas575x_snd_controls,
+               .num_controls           = ARRAY_SIZE(tas575x_snd_controls),
+               //.dapm_widgets         = tas575x_dapm_widgets,
+               //.num_dapm_widgets     = ARRAY_SIZE(tas575x_dapm_widgets),
+               //.dapm_routes          = tas575x_audio_route,
+               //.num_dapm_routes      = ARRAY_SIZE(tas575x_audio_route),
+       },
+};
+
+static const struct snd_soc_dai_ops tas575x_dai_ops = {
+       .set_fmt        = tas575x_set_dai_fmt,
+       .set_tdm_slot = tas575x_set_tdm_slot,
+       .hw_params      = tas575x_hw_params,
+       //.digital_mute = tas575x_mute,
+};
+
+static struct snd_soc_dai_driver tas575x_dai = {
+       .name = "tas575x-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tas575x_dai_ops,
+};
+
+static const struct regmap_config tas575x_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = 0xff,
+       .reg_defaults = tas575x_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(tas575x_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id tas575x_of_match[] = {
+       { .compatible = "ti, tas5754", 0 },
+       { .compatible = "ti, tas5756", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tas575x_of_match);
+
+static int tas575x_i2c_probe(struct i2c_client *client,
+                    const struct i2c_device_id *id)
+{
+       struct tas575x_private *priv;
+       struct device *dev = &client->dev;
+       struct device_node *node = dev->of_node;
+       int ret;
+       //const struct of_device_id *of_id;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       i2c_set_clientdata(client, priv);
+
+       priv->regmap = devm_regmap_init_i2c(client, &tas575x_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (of_property_read_bool(node, "tx_slots_mask")) {
+               ret = of_property_read_u32(node,
+                               "tx_slots_mask", &priv->tx_slots_mask);
+               pr_info("got tx_slot_mask %#x\n", priv->tx_slots_mask);
+       }
+
+       return snd_soc_register_codec(dev, &soc_codec_dev_tas575x,
+                                         &tas575x_dai, 1);
+
+}
+
+static int tas575x_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id tas575x_i2c_id[] = {
+       { "tas5754", (kernel_ulong_t) 0 },
+       { "tas5756", (kernel_ulong_t) 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tas575x_i2c_id);
+
+static struct i2c_driver tas575x_i2c_driver = {
+       .driver = {
+               .name = "tas575x",
+               .of_match_table = of_match_ptr(tas575x_of_match),
+       },
+       .probe = tas575x_i2c_probe,
+       .remove = tas575x_i2c_remove,
+       .id_table = tas575x_i2c_id,
+};
+module_i2c_driver(tas575x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TAS575x driver");
+MODULE_AUTHOR("Shuai Li <shuai.li@amlogic.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/amlogic/tas575x.h b/sound/soc/codecs/amlogic/tas575x.h
new file mode 100644 (file)
index 0000000..ff80ee8
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * sound/soc/codecs/amlogic/tas575x.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * Author: Shuai Li <shuai.li@amlogic.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __TAS575X_H__
+#define __TAS575X_H__
+
+/* Register Address Map */
+#define TAS575X_RESET                  1
+#define TAS575X_STANDBY                        2
+#define TAS575X_MUTE                   3
+#define TAS575X_PLL                            4
+#define TAS575X_DOUT                   7
+#define TAS575X_GPIO                   8
+#define TAS575X_CLK                            9
+#define TAS575X_MASTR_CLK              12
+#define TAS575X_PLL_REF                        13
+#define TAS575X_CLK_SRC                        14
+#define TAS575X_GPIO_SRC               18
+#define TAS575X_SYNC_REQ               19
+#define TAS575X_PLL_DIV_P              20
+#define TAS575X_PLL_DIV_J              21
+#define TAS575X_PLL_DIV_D              22
+#define TAS575X_PLL_DIV_R              24
+#define TAS575X_DSP_DIV                        27
+#define TAS575X_DAC_DIV                        28
+#define TAS575X_NCP_DIV                        29
+#define TAS575X_OSR_DIV                        30
+#define TAS575X_SCLK_DIV               32
+#define TAS575X_LRCLK_DIV              33
+#define TAS575X_16X_INTERP             34
+#define TAS575X_DSP_CLK_CYCLM  35
+#define TAS575X_DSP_CLK_CYCLL  36
+#define TAS575X_IGNORES                        37
+#define TAS575X_I2S_FMT                        40
+#define TAS575X_I2S_SHIFT              41
+#define TAS575X_DATA_PATH              42
+#define TAS575X_DSP_PROG_SEL   43
+#define TAS575X_CLK_DET_PRD            44
+#define TAS575X_MUTE_TIME              59
+#define TAS575X_DIG_VOL_CTRL   60
+#define TAS575X_CH_B_DIG_VOL   61
+#define TAS575X_CH_A_DIG_VOL   62
+#define TAS575X_VOL_NORM_RAMP  63
+#define TAS575X_VOL_EMRG_RAMP  64
+#define TAS575X_AUTO_MUTE_CTRL 65
+#define TAS575X_GPIO1_SEL              82
+#define TAS575X_GPIO0_SEL              83
+#define TAS575X_GPIO2_SEL              85
+#define TAS575X_GPIO_CTRL              86
+#define TAS575X_GPIO_INV               87
+#define TAS575X_CHANL_OVFLOW   90
+#define TAS575X_MCLK_DET               91
+#define TAS575X_SCLK_DET_MSB   92
+#define TAS575X_SCLK_DET_LSB   93
+#define TAS575X_CLK_DET_STAT   94
+#define TAS575X_CLK_STAT               95
+#define TAS575X_ANLG_MUTE_STAT 108
+#define TAS575X_SHORT_STAT             109
+#define TAS575X_SPK_MUTE_STAT  114
+#define TAS575X_FS_SPD_MODE            115
+#define TAS575X_PWR_STAT               117
+#define TAS575X_GPIO_STAT              119
+#define TAS575X_AUTO_MUTE              120
+#define TAS575X_DAC_MODE               121
+
+#endif /* __TAS575X_H__ */
index 67830f2..b377816 100644 (file)
@@ -322,6 +322,18 @@ static int adc3101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                pr_err("adc3101: invalid DAI master/slave interface\n");
                return -EINVAL;
        }
+       /* set lrclk/bclk invertion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_IF:
+       case SND_SOC_DAIFMT_IB_NF:
+               iface_reg_2 |= (1 << 3); /* invert bit clock */
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               break;
+       }
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S: