Merge remote-tracking branches 'asoc/topic/msm8916', 'asoc/topic/mtk', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:12 +0000 (16:15 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:12 +0000 (16:15 +0100)
15 files changed:
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
Documentation/devicetree/bindings/sound/nau8825.txt
include/sound/simple_card_utils.h
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/codecs/nau8824.c
sound/soc/codecs/nau8824.h
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-scu-card.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/generic/simple-scu-card.c
sound/soc/mediatek/mt2701/mt2701-cs42448.c

index bac4b1b1060f071be182c0e41e3f3ee22e5de6d7..6e6720aa33f19b03c81db761413db684267acc73 100644 (file)
@@ -10,6 +10,8 @@ see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
 Below are same as Simple-Card.
 
 - label
+- widgets
+- routing
 - dai-format
 - frame-master
 - bitclock-master
@@ -24,6 +26,9 @@ Required properties:
 - compatible                           : "audio-graph-card";
 - dais                                 : list of CPU DAI port{s}
 
+Optional properties:
+- pa-gpios: GPIO used to control external amplifier.
+
 Example: Single DAI case
 
        sound_card {
index b63c5594bbb35b4ce5c6eff255d6d7d15f0f0bb1..8b8afe9fcb315891b0e321152bbf56eefd5c6e30 100644 (file)
@@ -90,9 +90,12 @@ Example 2. 2 CPU 1 Codec (Mixing)
                ...
 
                port {
-                       codec_endpoint: endpoint {
+                       codec_endpoint0: endpoint {
                                remote-endpoint = <&cpu_endpoint0>;
                        };
+                       codec_endpoint1: endpoint {
+                               remote-endpoint = <&cpu_endpoint1>;
+                       };
                };
        };
 
@@ -101,7 +104,7 @@ Example 2. 2 CPU 1 Codec (Mixing)
                ports {
                        cpu_port0: port {
                                cpu_endpoint0: endpoint {
-                                       remote-endpoint = <&codec_endpoint>;
+                                       remote-endpoint = <&codec_endpoint0>;
 
                                        dai-format = "left_j";
                                        ...
@@ -109,6 +112,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
                        };
                        cpu_port1: port {
                                cpu_endpoint1: endpoint {
+                                       remote-endpoint = <&codec_endpoint1>;
+
                                        dai-format = "left_j";
                                        ...
                                };
index d3374231c871482afe0e4a72eb105ffe94ad010d..2f5e973285a648a3a7ea1bedb5d5cc9c79311589 100644 (file)
@@ -69,6 +69,8 @@ Optional properties:
   - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
   - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
 
+  - nuvoton,crosstalk-bypass: make crosstalk function bypass if set.
+
   - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
       clocks described in clock-names
   - clock-names: should include "mclk" for the MCLK master clock
@@ -96,6 +98,7 @@ Example:
       nuvoton,short-key-debounce = <2>;
       nuvoton,jack-insert-debounce = <7>;
       nuvoton,jack-eject-debounce = <7>;
+      nuvoton,crosstalk-bypass;
 
       clock-names = "mclk";
       clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
index 108cae459ed097c04c3e39a4b10882ccd6f3c190..42c6a6ac3ce60d6ab81fc4e726e6dfe0129804ff 100644 (file)
@@ -22,6 +22,11 @@ struct asoc_simple_dai {
        struct clk *clk;
 };
 
+struct asoc_simple_card_data {
+       u32 convert_rate;
+       u32 convert_channels;
+};
+
 int asoc_simple_card_parse_daifmt(struct device *dev,
                                  struct device_node *node,
                                  struct device_node *codec,
@@ -45,6 +50,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
                               struct device_node *dai_of_node,
                               struct asoc_simple_dai *simple_dai,
                               const char *name);
+int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
+void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
 
 #define asoc_simple_card_parse_cpu(node, dai_link,                             \
                                   list_name, cells_name, is_single_link)       \
@@ -73,6 +80,12 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
                                     struct device_node **endpoint_np,
                                     const char **dai_name);
 
+#define asoc_simple_card_of_parse_tdm(np, dai)                 \
+       snd_soc_of_parse_tdm_slot(np,   &(dai)->tx_slot_mask,   \
+                                       &(dai)->rx_slot_mask,   \
+                                       &(dai)->slots,          \
+                                       &(dai)->slot_width);
+
 int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
                              struct asoc_simple_dai *simple_dai);
 
@@ -82,4 +95,15 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
 
 int asoc_simple_card_clean_reference(struct snd_soc_card *card);
 
+void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
+                                     struct snd_pcm_hw_params *params);
+void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+                                   struct asoc_simple_card_data *data);
+
+int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
+                                     char *prefix,
+                                     int optional);
+int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
+                                     char *prefix);
+
 #endif /* __SIMPLE_CARD_UTILS_H */
index d8e8590746aff7b520f008bdb346da1d8330ffa0..a78802920c3cc098af2526a4ba335dba0df5a59f 100644 (file)
@@ -223,8 +223,8 @@ struct pm8916_wcd_analog_priv {
        u16 codec_version;
        struct clk *mclk;
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
-       bool micbias1_cap_mode;
-       bool micbias2_cap_mode;
+       unsigned int micbias1_cap_mode;
+       unsigned int micbias2_cap_mode;
 };
 
 static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -285,7 +285,7 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
 
 static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
                                                 *codec, int event,
-                                                int reg, u32 cap_mode)
+                                                int reg, unsigned int cap_mode)
 {
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index cca974d26136fbdaeb46f08aa4f972d1958fa668..3a309b18035e7ab29f5762e8d8331be388ae187e 100644 (file)
@@ -1124,6 +1124,57 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
+/**
+ * nau8824_set_tdm_slot - configure DAI TDM.
+ * @dai: DAI
+ * @tx_mask: Bitmask representing active TX slots. Ex.
+ *                 0xf for normal 4 channel TDM.
+ *                 0xf0 for shifted 4 channel TDM
+ * @rx_mask: Bitmask [0:1] representing active DACR RX slots.
+ *                 Bitmask [2:3] representing active DACL RX slots.
+ *                 00=CH0,01=CH1,10=CH2,11=CH3. Ex.
+ *                 0xf for DACL/R selecting TDM CH3.
+ *                 0xf0 for DACL/R selecting shifted TDM CH3.
+ * @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
+ *
+ * Configures a DAI for TDM operation. Only support 4 slots TDM.
+ */
+static int nau8824_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 nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+       unsigned int tslot_l = 0, ctrl_val = 0;
+
+       if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) ||
+               ((rx_mask & 0xf0) && (rx_mask & 0xf)) ||
+               ((rx_mask & 0xf0) && (tx_mask & 0xf)) ||
+               ((rx_mask & 0xf) && (tx_mask & 0xf0)))
+               return -EINVAL;
+
+       ctrl_val |= (NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN);
+       if (tx_mask & 0xf0) {
+               tslot_l = 4 * slot_width;
+               ctrl_val |= (tx_mask >> 4);
+       } else {
+               ctrl_val |= tx_mask;
+       }
+       if (rx_mask & 0xf0)
+               ctrl_val |= ((rx_mask >> 4) << NAU8824_TDM_DACR_RX_SFT);
+       else
+               ctrl_val |= (rx_mask << NAU8824_TDM_DACR_RX_SFT);
+
+       regmap_update_bits(nau8824->regmap, NAU8824_REG_TDM_CTRL,
+               NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN |
+               NAU8824_TDM_DACL_RX_MASK | NAU8824_TDM_DACR_RX_MASK |
+               NAU8824_TDM_TX_MASK, ctrl_val);
+       regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_LEFT_TIME_SLOT,
+               NAU8824_TSLOT_L_MASK, tslot_l);
+
+       return 0;
+}
+
 /**
  * nau8824_calc_fll_param - Calculate FLL parameters.
  * @fll_in: external clock provided to codec.
@@ -1440,6 +1491,7 @@ static struct snd_soc_codec_driver nau8824_codec_driver = {
 static const struct snd_soc_dai_ops nau8824_dai_ops = {
        .hw_params = nau8824_hw_params,
        .set_fmt = nau8824_set_fmt,
+       .set_tdm_slot = nau8824_set_tdm_slot,
 };
 
 #define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
index 87ac9a382aede5ab898d1a0861751c9d63e70a48..21eae2431c83a4d8db8ffe77761e3a460aa208e7 100644 (file)
 #define NAU8824_I2S_MS_SLAVE           (0 << NAU8824_I2S_MS_SFT)
 #define NAU8824_I2S_BLK_DIV_MASK       0x7
 
+/* PORT0_LEFT_TIME_SLOT (0x1E) */
+#define NAU8824_TSLOT_L_MASK   0x3ff
+
+/* TDM_CTRL (0x20) */
+#define NAU8824_TDM_MODE               (0x1 << 15)
+#define NAU8824_TDM_OFFSET_EN          (0x1 << 14)
+#define NAU8824_TDM_DACL_RX_SFT        6
+#define NAU8824_TDM_DACL_RX_MASK       (0x3 << NAU8824_TDM_DACL_RX_SFT)
+#define NAU8824_TDM_DACR_RX_SFT        4
+#define NAU8824_TDM_DACR_RX_MASK       (0x3 << NAU8824_TDM_DACR_RX_SFT)
+#define NAU8824_TDM_TX_MASK            0xf
+
 /* ADC_FILTER_CTRL (0x24) */
 #define NAU8824_ADC_SYNC_DOWN_MASK     0x3
 #define NAU8824_ADC_SYNC_DOWN_32       0
index 97fbeba9498fcd25b8a76d8de21540244867c9a7..46a30eaa7ace095a39e011790e992bcb1a3f87c9 100644 (file)
@@ -1612,7 +1612,6 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
                snd_soc_dapm_sync(dapm);
                break;
        case 2:
-       case 3:
                dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
                type = SND_JACK_HEADSET;
 
@@ -1632,6 +1631,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
                snd_soc_dapm_force_enable_pin(dapm, "SAR");
                snd_soc_dapm_sync(dapm);
                break;
+       case 3:
+               /* detect error case */
+               dev_err(nau8825->dev, "detection error; disable mic function\n");
+               type = SND_JACK_HEADPHONE;
+               break;
        }
 
        /* Leaving HPOL/R grounded after jack insert by default. They will be
@@ -1682,7 +1686,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
        } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
                if (nau8825_is_jack_inserted(regmap)) {
                        event |= nau8825_jack_insert(nau8825);
-                       if (!nau8825->high_imped) {
+                       if (!nau8825->xtalk_bypass && !nau8825->high_imped) {
                                /* Apply the cross talk suppression in the
                                 * headset without high impedance.
                                 */
@@ -2328,6 +2332,13 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_OFF:
+               /* Reset the configuration of jack type for detection */
+               /* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_MIC_BIAS,
+                       NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+               /* ground HPL/HPR, MICGRND1/2 */
+               regmap_update_bits(nau8825->regmap,
+                       NAU8825_REG_HSD_CTRL, 0xf, 0xf);
                /* Cancel and reset cross talk detection funciton */
                nau8825_xtalk_cancel(nau8825);
                /* Turn off all interruptions before system shutdown. Keep the
@@ -2351,6 +2362,10 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
 
        disable_irq(nau8825->irq);
        snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+       /* Power down codec power; don't suppoet button wakeup */
+       snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
+       snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
+       snd_soc_dapm_sync(nau8825->dapm);
        regcache_cache_only(nau8825->regmap, true);
        regcache_mark_dirty(nau8825->regmap);
 
@@ -2425,10 +2440,13 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
                        nau8825->jack_insert_debounce);
        dev_dbg(dev, "jack-eject-debounce:  %d\n",
                        nau8825->jack_eject_debounce);
+       dev_dbg(dev, "crosstalk-bypass:     %d\n",
+                       nau8825->xtalk_bypass);
 }
 
 static int nau8825_read_device_properties(struct device *dev,
        struct nau8825 *nau8825) {
+       int ret;
 
        nau8825->jkdet_enable = device_property_read_bool(dev,
                "nuvoton,jkdet-enable");
@@ -2436,30 +2454,60 @@ static int nau8825_read_device_properties(struct device *dev,
                "nuvoton,jkdet-pull-enable");
        nau8825->jkdet_pull_up = device_property_read_bool(dev,
                "nuvoton,jkdet-pull-up");
-       device_property_read_u32(dev, "nuvoton,jkdet-polarity",
+       ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
                &nau8825->jkdet_polarity);
-       device_property_read_u32(dev, "nuvoton,micbias-voltage",
+       if (ret)
+               nau8825->jkdet_polarity = 1;
+       ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
                &nau8825->micbias_voltage);
-       device_property_read_u32(dev, "nuvoton,vref-impedance",
+       if (ret)
+               nau8825->micbias_voltage = 6;
+       ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
                &nau8825->vref_impedance);
-       device_property_read_u32(dev, "nuvoton,sar-threshold-num",
+       if (ret)
+               nau8825->vref_impedance = 2;
+       ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
                &nau8825->sar_threshold_num);
-       device_property_read_u32_array(dev, "nuvoton,sar-threshold",
+       if (ret)
+               nau8825->sar_threshold_num = 4;
+       ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
                nau8825->sar_threshold, nau8825->sar_threshold_num);
-       device_property_read_u32(dev, "nuvoton,sar-hysteresis",
+       if (ret) {
+               nau8825->sar_threshold[0] = 0x08;
+               nau8825->sar_threshold[1] = 0x12;
+               nau8825->sar_threshold[2] = 0x26;
+               nau8825->sar_threshold[3] = 0x73;
+       }
+       ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
                &nau8825->sar_hysteresis);
-       device_property_read_u32(dev, "nuvoton,sar-voltage",
+       if (ret)
+               nau8825->sar_hysteresis = 0;
+       ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
                &nau8825->sar_voltage);
-       device_property_read_u32(dev, "nuvoton,sar-compare-time",
+       if (ret)
+               nau8825->sar_voltage = 6;
+       ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
                &nau8825->sar_compare_time);
-       device_property_read_u32(dev, "nuvoton,sar-sampling-time",
+       if (ret)
+               nau8825->sar_compare_time = 1;
+       ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
                &nau8825->sar_sampling_time);
-       device_property_read_u32(dev, "nuvoton,short-key-debounce",
+       if (ret)
+               nau8825->sar_sampling_time = 1;
+       ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
                &nau8825->key_debounce);
-       device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
+       if (ret)
+               nau8825->key_debounce = 3;
+       ret = device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
                &nau8825->jack_insert_debounce);
-       device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
+       if (ret)
+               nau8825->jack_insert_debounce = 7;
+       ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
                &nau8825->jack_eject_debounce);
+       if (ret)
+               nau8825->jack_eject_debounce = 0;
+       nau8825->xtalk_bypass = device_property_read_bool(dev,
+               "nuvoton,crosstalk-bypass");
 
        nau8825->mclk = devm_clk_get(dev, "mclk");
        if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
index 514fd13c2f4624bb96b237422dfd63fae52adf17..8aee5c8647aee153f151ac09175dc3f6a9fd25da 100644 (file)
@@ -476,6 +476,7 @@ struct nau8825 {
        int xtalk_event_mask;
        bool xtalk_protect;
        int imp_rms[NAU8825_XTALK_IMM];
+       int xtalk_bypass;
 };
 
 int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
index 0180b286bee351858d76b0fbe44ac606f4ed6095..105ec3a6e30df8340d62d1be45e1bb8577956672 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -30,6 +31,34 @@ struct graph_card_data {
                struct asoc_simple_dai codec_dai;
        } *dai_props;
        struct snd_soc_dai_link *dai_link;
+       struct gpio_desc *pa_gpio;
+};
+
+static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               gpiod_set_value_cansleep(priv->pa_gpio, 1);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               gpiod_set_value_cansleep(priv->pa_gpio, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
+       SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
+                              0, 0, NULL, 0, asoc_graph_card_outdrv_event,
+                              SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 };
 
 #define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -44,13 +73,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
        int ret;
 
-       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+       ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
        if (ret)
                return ret;
 
-       ret = clk_prepare_enable(dai_props->codec_dai.clk);
+       ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
        if (ret)
-               clk_disable_unprepare(dai_props->cpu_dai.clk);
+               asoc_simple_card_clk_disable(&dai_props->cpu_dai);
 
        return ret;
 }
@@ -61,9 +90,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
 
-       clk_disable_unprepare(dai_props->cpu_dai.clk);
+       asoc_simple_card_clk_disable(&dai_props->cpu_dai);
 
-       clk_disable_unprepare(dai_props->codec_dai.clk);
+       asoc_simple_card_clk_disable(&dai_props->codec_dai);
 }
 
 static struct snd_soc_ops asoc_graph_card_ops = {
@@ -100,7 +129,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
        struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
        struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
-       struct snd_soc_card *card = graph_priv_to_card(priv);
        struct device_node *cpu_ep    = of_get_next_child(cpu_port, NULL);
        struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
        struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
@@ -131,19 +159,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = snd_soc_of_parse_tdm_slot(cpu_ep,
-                                       &cpu_dai->tx_slot_mask,
-                                       &cpu_dai->rx_slot_mask,
-                                       &cpu_dai->slots,
-                                       &cpu_dai->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = snd_soc_of_parse_tdm_slot(codec_ep,
-                                       &codec_dai->tx_slot_mask,
-                                       &codec_dai->rx_slot_mask,
-                                       &codec_dai->slots,
-                                       &codec_dai->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
        if (ret < 0)
                goto dai_link_of_err;
 
@@ -170,7 +190,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
        dai_link->init = asoc_graph_card_dai_init;
 
        asoc_simple_card_canonicalize_cpu(dai_link,
-                                         card->num_links == 1);
+               of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
 
 dai_link_of_err:
        of_node_put(cpu_ep);
@@ -189,8 +209,16 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        int rc, idx = 0;
        int ret;
 
+       ret = asoc_simple_card_of_parse_widgets(card, NULL);
+       if (ret < 0)
+               return ret;
+
+       ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
+       if (ret < 0)
+               return ret;
+
        /*
-        * we need to consider "widgets", "routing", "mclk-fs" around here
+        * we need to consider "mclk-fs" around here
         * see simple-card
         */
 
@@ -242,6 +270,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
        if (!dai_props || !dai_link)
                return -ENOMEM;
 
+       priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->pa_gpio)) {
+               ret = PTR_ERR(priv->pa_gpio);
+               dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
+               return ret;
+       }
+
        priv->dai_props                 = dai_props;
        priv->dai_link                  = dai_link;
 
@@ -251,6 +286,8 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
        card->dev       = dev;
        card->dai_link  = dai_link;
        card->num_links = num;
+       card->dapm_widgets = asoc_graph_card_dapm_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
 
        ret = asoc_graph_card_parse_of(priv);
        if (ret < 0) {
index 0066102f5bc45809b07691d6075143f007ed2dcd..dcd2df37bc3bfbd78e1f0d7bbb50b5192a89cc2d 100644 (file)
@@ -30,8 +30,7 @@ struct graph_card_data {
        struct snd_soc_codec_conf codec_conf;
        struct asoc_simple_dai *dai_props;
        struct snd_soc_dai_link *dai_link;
-       u32 convert_rate;
-       u32 convert_channels;
+       struct asoc_simple_card_data adata;
 };
 
 #define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -45,7 +44,7 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
 
-       return clk_prepare_enable(dai_props->clk);
+       return asoc_simple_card_clk_enable(dai_props);
 }
 
 static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@@ -54,7 +53,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
 
-       clk_disable_unprepare(dai_props->clk);
+       asoc_simple_card_clk_disable(dai_props);
 }
 
 static struct snd_soc_ops asoc_graph_card_ops = {
@@ -83,18 +82,8 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                               struct snd_pcm_hw_params *params)
 {
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_interval *rate = hw_param_interval(params,
-                                                     SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                                         SNDRV_PCM_HW_PARAM_CHANNELS);
 
-       if (priv->convert_rate)
-               rate->min =
-               rate->max = priv->convert_rate;
-
-       if (priv->convert_channels)
-               channels->min =
-               channels->max = priv->convert_channels;
+       asoc_simple_card_convert_fixup(&priv->adata, params);
 
        return 0;
 }
@@ -136,7 +125,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
 
                /* card->num_links includes Codec */
                asoc_simple_card_canonicalize_cpu(dai_link,
-                                       (card->num_links - 1) == 1);
+                       of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
        } else {
                /* FE is dummy */
                dai_link->cpu_of_node           = NULL;
@@ -167,11 +156,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
                                              "prefix");
        }
 
-       ret = snd_soc_of_parse_tdm_slot(ep,
-                                       &dai_props->tx_slot_mask,
-                                       &dai_props->rx_slot_mask,
-                                       &dai_props->slots,
-                                       &dai_props->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(ep, dai_props);
        if (ret)
                return ret;
 
@@ -198,6 +183,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        struct device_node *cpu_ep;
        struct device_node *codec_ep;
        struct device_node *rcpu_ep;
+       struct device_node *codec_port;
+       struct device_node *codec_port_old;
        unsigned int daifmt = 0;
        int dai_idx, ret;
        int rc, codec;
@@ -210,15 +197,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
         * see simple-card
         */
 
-       ret = snd_soc_of_parse_audio_routing(card, "routing");
-       if (ret)
+       ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
+       if (ret < 0)
                return ret;
 
-       /* sampling rate convert */
-       of_property_read_u32(node, "convert-rate", &priv->convert_rate);
-
-       /* channels transfer */
-       of_property_read_u32(node, "convert-channels", &priv->convert_channels);
+       asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
 
        /*
         * it supports multi CPU, single CODEC only here
@@ -254,6 +237,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        }
 
        dai_idx = 0;
+       codec_port_old = NULL;
        for (codec = 0; codec < 2; codec++) {
                /*
                 * To listup valid sounds continuously,
@@ -264,15 +248,22 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
                        cpu_port = it.node;
                        cpu_ep   = of_get_next_child(cpu_port, NULL);
                        codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+                       codec_port = of_graph_get_port_parent(codec_ep);
 
                        of_node_put(cpu_port);
                        of_node_put(cpu_ep);
                        of_node_put(codec_ep);
+                       of_node_put(codec_port);
 
                        if (codec) {
-                               if (!codec_ep)
+                               if (!codec_port)
                                        continue;
 
+                               if (codec_port_old == codec_port)
+                                       continue;
+
+                               codec_port_old = codec_port;
+
                                /* Back-End (= Codec) */
                                ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
                                if (ret < 0)
@@ -290,9 +281,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        if (ret)
                goto parse_of_err;
 
-       dev_dbg(dev, "convert_rate     %d\n", priv->convert_rate);
-       dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
-
        ret = 0;
 
 parse_of_err:
@@ -306,22 +294,34 @@ static int asoc_graph_get_dais_count(struct device *dev)
        struct device_node *cpu_port;
        struct device_node *cpu_ep;
        struct device_node *codec_ep;
+       struct device_node *codec_port;
+       struct device_node *codec_port_old;
        int count = 0;
        int rc;
 
+       codec_port_old = NULL;
        of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
                cpu_port = it.node;
                cpu_ep   = of_get_next_child(cpu_port, NULL);
                codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+               codec_port = of_graph_get_port_parent(codec_ep);
 
                of_node_put(cpu_port);
                of_node_put(cpu_ep);
                of_node_put(codec_ep);
+               of_node_put(codec_port);
 
                if (cpu_ep)
                        count++;
-               if (codec_ep)
-                       count++;
+
+               if (!codec_port)
+                       continue;
+
+               if (codec_port_old == codec_port)
+                       continue;
+
+               count++;
+               codec_port_old = codec_port;
        }
 
        return count;
index d9d8b8a58348e27304a05763e42c12d168134c0a..26d64fa40c9cf1438f43a08d8f45b15ac0184fa9 100644 (file)
 #include <linux/of_graph.h>
 #include <sound/simple_card_utils.h>
 
+void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
+                                   struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       if (data->convert_rate)
+               rate->min =
+               rate->max = data->convert_rate;
+
+       if (data->convert_channels)
+               channels->min =
+               channels->max = data->convert_channels;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
+
+void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+                                   struct asoc_simple_card_data *data)
+{
+       struct device_node *np = dev->of_node;
+       char prop[128];
+
+       if (!prefix)
+               prefix = "";
+
+       /* sampling rate convert */
+       snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
+       of_property_read_u32(np, prop, &data->convert_rate);
+
+       /* channels transfer */
+       snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
+       of_property_read_u32(np, prop, &data->convert_channels);
+
+       dev_dbg(dev, "convert_rate     %d\n", data->convert_rate);
+       dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert);
+
 int asoc_simple_card_parse_daifmt(struct device *dev,
                                  struct device_node *node,
                                  struct device_node *codec,
@@ -110,6 +150,24 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
 
+static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
+                                         struct clk *clk)
+{
+       dai->clk = clk;
+}
+
+int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
+{
+       return clk_prepare_enable(dai->clk);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
+
+void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
+{
+       clk_disable_unprepare(dai->clk);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
+
 int asoc_simple_card_parse_clk(struct device *dev,
                               struct device_node *node,
                               struct device_node *dai_of_node,
@@ -128,7 +186,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
        clk = devm_get_clk_from_child(dev, node, NULL);
        if (!IS_ERR(clk)) {
                simple_dai->sysclk = clk_get_rate(clk);
-               simple_dai->clk = clk;
+
+               asoc_simple_card_clk_register(simple_dai, clk);
        } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
                simple_dai->sysclk = val;
        } else {
@@ -316,6 +375,47 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
 
+int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
+                                     char *prefix,
+                                     int optional)
+{
+       struct device_node *node = card->dev->of_node;
+       char prop[128];
+
+       if (!prefix)
+               prefix = "";
+
+       snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
+
+       if (!of_property_read_bool(node, prop)) {
+               if (optional)
+                       return 0;
+               return -EINVAL;
+       }
+
+       return snd_soc_of_parse_audio_routing(card, prop);
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing);
+
+int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
+                                     char *prefix)
+{
+       struct device_node *node = card->dev->of_node;
+       char prop[128];
+
+       if (!prefix)
+               prefix = "";
+
+       snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
+
+       if (of_property_read_bool(node, prop))
+               return snd_soc_of_parse_audio_simple_widgets(card, prop);
+
+       /* no widgets is not error */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
+
 /* Module information */
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
index 1df69701eb12885122a4155227b64aeb44bb1089..dfaf48ff88b02b8f23413acc6b22552058cf372b 100644 (file)
@@ -118,13 +118,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
                simple_priv_to_props(priv, rtd->num);
        int ret;
 
-       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+       ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
        if (ret)
                return ret;
 
-       ret = clk_prepare_enable(dai_props->codec_dai.clk);
+       ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
        if (ret)
-               clk_disable_unprepare(dai_props->cpu_dai.clk);
+               asoc_simple_card_clk_disable(&dai_props->cpu_dai);
 
        return ret;
 }
@@ -136,9 +136,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        struct simple_dai_props *dai_props =
                simple_priv_to_props(priv, rtd->num);
 
-       clk_disable_unprepare(dai_props->cpu_dai.clk);
+       asoc_simple_card_clk_disable(&dai_props->cpu_dai);
 
-       clk_disable_unprepare(dai_props->codec_dai.clk);
+       asoc_simple_card_clk_disable(&dai_props->codec_dai);
 }
 
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
@@ -233,13 +233,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
        snprintf(prop, sizeof(prop), "%scpu", prefix);
        cpu = of_get_child_by_name(node, prop);
 
+       if (!cpu) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+               goto dai_link_of_err;
+       }
+
        snprintf(prop, sizeof(prop), "%splat", prefix);
        plat = of_get_child_by_name(node, prop);
 
        snprintf(prop, sizeof(prop), "%scodec", prefix);
        codec = of_get_child_by_name(node, prop);
 
-       if (!cpu || !codec) {
+       if (!codec) {
                ret = -EINVAL;
                dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
                goto dai_link_of_err;
@@ -265,17 +271,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = snd_soc_of_parse_tdm_slot(cpu,    &cpu_dai->tx_slot_mask,
-                                               &cpu_dai->rx_slot_mask,
-                                               &cpu_dai->slots,
-                                               &cpu_dai->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = snd_soc_of_parse_tdm_slot(codec,  &codec_dai->tx_slot_mask,
-                                               &codec_dai->rx_slot_mask,
-                                               &codec_dai->slots,
-                                               &codec_dai->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
        if (ret < 0)
                goto dai_link_of_err;
 
@@ -341,12 +341,12 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
        return 0;
 }
 
-static int asoc_simple_card_parse_of(struct device_node *node,
-                                    struct simple_card_data *priv)
+static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 {
        struct device *dev = simple_priv_to_dev(priv);
        struct snd_soc_card *card = simple_priv_to_card(priv);
        struct device_node *dai_link;
+       struct device_node *node = dev->of_node;
        int ret;
 
        if (!node)
@@ -354,21 +354,13 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 
        dai_link = of_get_child_by_name(node, PREFIX "dai-link");
 
-       /* The off-codec widgets */
-       if (of_property_read_bool(node, PREFIX "widgets")) {
-               ret = snd_soc_of_parse_audio_simple_widgets(card,
-                                       PREFIX "widgets");
-               if (ret)
-                       goto card_parse_end;
-       }
+       ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
+       if (ret < 0)
+               goto card_parse_end;
 
-       /* DAPM routes */
-       if (of_property_read_bool(node, PREFIX "routing")) {
-               ret = snd_soc_of_parse_audio_routing(card,
-                                       PREFIX "routing");
-               if (ret)
-                       goto card_parse_end;
-       }
+       ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
+       if (ret < 0)
+               goto card_parse_end;
 
        /* Factor to mclk, used in hw_params() */
        of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
@@ -445,7 +437,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 
        if (np && of_device_is_available(np)) {
 
-               ret = asoc_simple_card_parse_of(np, priv);
+               ret = asoc_simple_card_parse_of(priv);
                if (ret < 0) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "parse error %d\n", ret);
index 5faf5d6c48a2f89f7697be11bcbdb7b3f8390bb9..a75b385455c4f62c0f473baea203f94b9c990a8b 100644 (file)
@@ -27,8 +27,7 @@ struct simple_card_data {
        struct snd_soc_codec_conf codec_conf;
        struct asoc_simple_dai *dai_props;
        struct snd_soc_dai_link *dai_link;
-       u32 convert_rate;
-       u32 convert_channels;
+       struct asoc_simple_card_data adata;
 };
 
 #define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -47,7 +46,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
        struct asoc_simple_dai *dai_props =
                simple_priv_to_props(priv, rtd->num);
 
-       return clk_prepare_enable(dai_props->clk);
+       return asoc_simple_card_clk_enable(dai_props);
 }
 
 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@@ -57,7 +56,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        struct asoc_simple_dai *dai_props =
                simple_priv_to_props(priv, rtd->num);
 
-       clk_disable_unprepare(dai_props->clk);
+       asoc_simple_card_clk_disable(dai_props);
 }
 
 static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -86,18 +85,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                        struct snd_pcm_hw_params *params)
 {
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_interval *rate = hw_param_interval(params,
-                                                     SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
 
-       if (priv->convert_rate)
-               rate->min =
-               rate->max = priv->convert_rate;
-
-       if (priv->convert_channels)
-               channels->min =
-               channels->max = priv->convert_channels;
+       asoc_simple_card_convert_fixup(&priv->adata, params);
 
        return 0;
 }
@@ -171,11 +160,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
                                              PREFIX "prefix");
        }
 
-       ret = snd_soc_of_parse_tdm_slot(np,
-                                       &dai_props->tx_slot_mask,
-                                       &dai_props->rx_slot_mask,
-                                       &dai_props->slots,
-                                       &dai_props->slot_width);
+       ret = asoc_simple_card_of_parse_tdm(np, dai_props);
        if (ret)
                return ret;
 
@@ -206,15 +191,11 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
        if (!node)
                return -EINVAL;
 
-       ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing");
+       ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
        if (ret < 0)
                return ret;
 
-       /* sampling rate convert */
-       of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
-
-       /* channels transfer */
-       of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
+       asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
 
        /* find 1st codec */
        np = of_get_child_by_name(node, PREFIX "codec");
@@ -241,9 +222,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
        if (ret < 0)
                return ret;
 
-       dev_dbg(dev, "convert_rate     %d\n", priv->convert_rate);
-       dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
-
        return 0;
 }
 
index aa5b31b121e322dd7d85fa4007841f2d7a977481..70f61d53fe05760cc20a1c8cb73acf5c7902cd8d 100644 (file)
@@ -107,7 +107,7 @@ static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
 
 static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
 
-static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
+static const struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
                .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
                .list = mt2701_cs42448_sampling_rates,
                .mask = 0,