Merge remote-tracking branches 'asoc/topic/max98926', 'asoc/topic/mtk', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Sun, 13 Mar 2016 08:17:18 +0000 (15:17 +0700)
committerMark Brown <broonie@kernel.org>
Sun, 13 Mar 2016 08:17:18 +0000 (15:17 +0700)
14 files changed:
Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mt8173-rt5650.txt [new file with mode: 0644]
sound/soc/codecs/max98926.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/mediatek/Kconfig
sound/soc/mediatek/Makefile
sound/soc/mediatek/mt8173-rt5650-rt5514.c [new file with mode: 0644]
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mt8173-rt5650.c [new file with mode: 0644]
sound/soc/mediatek/mtk-afe-common.h
sound/soc/mediatek/mtk-afe-pcm.c
sound/soc/mxs/mxs-saif.c
sound/soc/omap/omap-hdmi-audio.c

diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt
new file mode 100644 (file)
index 0000000..e8b3c80
--- /dev/null
@@ -0,0 +1,15 @@
+MT8173 with RT5650 RT5514 CODECS
+
+Required properties:
+- compatible : "mediatek,mt8173-rt5650-rt5514"
+- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs
+- mediatek,platform: the phandle of MT8173 ASoC platform
+
+Example:
+
+       sound {
+               compatible = "mediatek,mt8173-rt5650-rt5514";
+               mediatek,audio-codec = <&rt5650 &rt5514>;
+               mediatek,platform = <&afe>;
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
new file mode 100644 (file)
index 0000000..fe5a5ef
--- /dev/null
@@ -0,0 +1,15 @@
+MT8173 with RT5650 CODECS
+
+Required properties:
+- compatible : "mediatek,mt8173-rt5650"
+- mediatek,audio-codec: the phandles of rt5650 codecs
+- mediatek,platform: the phandle of MT8173 ASoC platform
+
+Example:
+
+       sound {
+               compatible = "mediatek,mt8173-rt5650";
+               mediatek,audio-codec = <&rt5650>;
+               mediatek,platform = <&afe>;
+       };
+
index 5245e10..8d14ada 100644 (file)
@@ -40,7 +40,7 @@ static const char *const max98926_hpf_cutoff_txt[] = {
        "200Hz", "400Hz", "800Hz",
 };
 
-static struct reg_default max98926_reg[] = {
+static const struct reg_default max98926_reg[] = {
        { 0x0B, 0x00 }, /* IRQ Enable0 */
        { 0x0C, 0x00 }, /* IRQ Enable1 */
        { 0x0D, 0x00 }, /* IRQ Enable2 */
@@ -506,7 +506,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98926 = {
        .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets),
 };
 
-static struct regmap_config max98926_regmap = {
+static const struct regmap_config max98926_regmap = {
        .reg_bits       = 8,
        .val_bits       = 8,
        .max_register   = MAX98926_VERSION,
index c1b87c5..1c87299 100644 (file)
@@ -84,6 +84,7 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = {
 
 static const struct reg_default nau8825_reg_defaults[] = {
        { NAU8825_REG_ENA_CTRL, 0x00ff },
+       { NAU8825_REG_IIC_ADDR_SET, 0x0 },
        { NAU8825_REG_CLK_DIVIDER, 0x0050 },
        { NAU8825_REG_FLL1, 0x0 },
        { NAU8825_REG_FLL2, 0x3126 },
@@ -158,8 +159,7 @@ static const struct reg_default nau8825_reg_defaults[] = {
 static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case NAU8825_REG_ENA_CTRL:
-       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_ENA_CTRL ... NAU8825_REG_FLL_VCO_RSV:
        case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
        case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL:
        case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
@@ -184,8 +184,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
 static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case NAU8825_REG_RESET ... NAU8825_REG_ENA_CTRL:
-       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_RESET ... NAU8825_REG_FLL_VCO_RSV:
        case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
        case NAU8825_REG_INTERRUPT_MASK:
        case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL:
@@ -227,10 +226,42 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
 static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Prevent startup click by letting charge pump to ramp up */
                msleep(10);
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+                       NAU8825_JAMNODCLOW, NAU8825_JAMNODCLOW);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+                       NAU8825_JAMNODCLOW, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Disables the TESTDAC to let DAC signal pass through. */
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+                       NAU8825_BIAS_TESTDAC_EN, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+                       NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
                break;
        default:
                return -EINVAL;
@@ -316,10 +347,10 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL,
                NAU8825_SAR_ADC_EN_SFT, 0),
 
-       SND_SOC_DAPM_DAC("ADACL", NULL, NAU8825_REG_RDAC, 12, 0),
-       SND_SOC_DAPM_DAC("ADACR", NULL, NAU8825_REG_RDAC, 13, 0),
-       SND_SOC_DAPM_SUPPLY("ADACL Clock", NAU8825_REG_RDAC, 8, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ADACR Clock", NAU8825_REG_RDAC, 9, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACL Clock", 3, NAU8825_REG_RDAC, 8, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACR Clock", 3, NAU8825_REG_RDAC, 9, 0, NULL, 0),
 
        SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL,
                NAU8825_ENABLE_DACR_SFT, 0),
@@ -330,29 +361,48 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux),
        SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux),
 
-       SND_SOC_DAPM_PGA("HP amp L", NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("HP amp R", NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("HP amp power", NAU8825_REG_CLASSG_CTRL, 0, 0, NULL,
-               0),
+       SND_SOC_DAPM_PGA_S("HP amp L", 0,
+               NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("HP amp R", 0,
+               NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
 
-       SND_SOC_DAPM_SUPPLY("Charge Pump", NAU8825_REG_CHARGE_PUMP, 5, 0,
-               nau8825_pump_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8825_REG_CHARGE_PUMP, 5, 0,
+               nau8825_pump_event, SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_PRE_PMD),
 
-       SND_SOC_DAPM_PGA("Output Driver R Stage 1",
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 1", 4,
                NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver L Stage 1",
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 1", 4,
                NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver R Stage 2",
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 2", 5,
                NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver L Stage 2",
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 2", 5,
                NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 1,
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 6,
                NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 1,
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 6,
                NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_PGA_S("Output DACL", 2, NAU8825_REG_CHARGE_PUMP, 8, 1, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output DACR", 2, NAU8825_REG_CHARGE_PUMP, 9, 1, NULL, 0),
+       SND_SOC_DAPM_PGA_S("Output DACL", 7,
+               NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_S("Output DACR", 7,
+               NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */
+       SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8,
+               NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0),
+       SND_SOC_DAPM_PGA_S("HPOR Pulldown", 8,
+               NAU8825_REG_HSD_CTRL, 1, 1, NULL, 0),
+
+       /* High current HPOL/R boost driver */
+       SND_SOC_DAPM_PGA_S("HP Boost Driver", 9,
+               NAU8825_REG_BOOST, 9, 1, NULL, 0),
+
+       /* Class G operation control*/
+       SND_SOC_DAPM_PGA_S("Class G", 10,
+               NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, 0),
 
        SND_SOC_DAPM_OUTPUT("HPOL"),
        SND_SOC_DAPM_OUTPUT("HPOR"),
@@ -375,24 +425,27 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
        {"DACR Mux", "DACR", "DDACR"},
        {"HP amp L", NULL, "DACL Mux"},
        {"HP amp R", NULL, "DACR Mux"},
-       {"HP amp L", NULL, "HP amp power"},
-       {"HP amp R", NULL, "HP amp power"},
-       {"ADACL", NULL, "HP amp L"},
-       {"ADACR", NULL, "HP amp R"},
-       {"ADACL", NULL, "ADACL Clock"},
-       {"ADACR", NULL, "ADACR Clock"},
-       {"Output Driver L Stage 1", NULL, "ADACL"},
-       {"Output Driver R Stage 1", NULL, "ADACR"},
+       {"Charge Pump", NULL, "HP amp L"},
+       {"Charge Pump", NULL, "HP amp R"},
+       {"ADACL", NULL, "Charge Pump"},
+       {"ADACR", NULL, "Charge Pump"},
+       {"ADACL Clock", NULL, "ADACL"},
+       {"ADACR Clock", NULL, "ADACR"},
+       {"Output Driver L Stage 1", NULL, "ADACL Clock"},
+       {"Output Driver R Stage 1", NULL, "ADACR Clock"},
        {"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"},
        {"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"},
        {"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"},
        {"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"},
        {"Output DACL", NULL, "Output Driver L Stage 3"},
        {"Output DACR", NULL, "Output Driver R Stage 3"},
-       {"HPOL", NULL, "Output DACL"},
-       {"HPOR", NULL, "Output DACR"},
-       {"HPOL", NULL, "Charge Pump"},
-       {"HPOR", NULL, "Charge Pump"},
+       {"HPOL Pulldown", NULL, "Output DACL"},
+       {"HPOR Pulldown", NULL, "Output DACR"},
+       {"HP Boost Driver", NULL, "HPOL Pulldown"},
+       {"HP Boost Driver", NULL, "HPOR Pulldown"},
+       {"Class G", NULL, "HP Boost Driver"},
+       {"HPOL", NULL, "Class G"},
+       {"HPOR", NULL, "Class G"},
 };
 
 static int nau8825_hw_params(struct snd_pcm_substream *substream,
@@ -659,11 +712,10 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
                break;
        }
 
-       if (type & SND_JACK_HEADPHONE) {
-               /* Unground HPL/R */
-               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0x3, 0);
-       }
-
+       /* Leaving HPOL/R grounded after jack insert by default. They will be
+        * ungrounded as part of the widget power up sequence at the beginning
+        * of playback to reduce pop.
+        */
        return type;
 }
 
@@ -768,6 +820,8 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
 {
        struct regmap *regmap = nau8825->regmap;
 
+       /* Latch IIC LSB value */
+       regmap_write(regmap, NAU8825_REG_IIC_ADDR_SET, 0x0001);
        /* Enable Bias/Vmid */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
                NAU8825_BIAS_VMID, NAU8825_BIAS_VMID);
@@ -780,10 +834,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT);
        /* Disable Boost Driver, Automatic Short circuit protection enable */
        regmap_update_bits(regmap, NAU8825_REG_BOOST,
-               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
-               NAU8825_SHORT_SHUTDOWN_EN,
-               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
-               NAU8825_SHORT_SHUTDOWN_EN);
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+               NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN,
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+               NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN);
 
        regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
                NAU8825_JKDET_OUTPUT_EN,
@@ -822,6 +876,35 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128);
        regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
                NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128);
+       /* Disable DACR/L power */
+       regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
+               NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+               NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+       /* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
+        * signal to avoid any glitches due to power up transients in both
+        * the analog and digital DAC circuit.
+        */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+               NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+       /* CICCLP off */
+       regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
+               NAU8825_DAC_CLIP_OFF, NAU8825_DAC_CLIP_OFF);
+
+       /* Class AB bias current to 2x, DAC Capacitor enable MSB/LSB */
+       regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_2,
+               NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+               NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB,
+               NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+               NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB);
+       /* Class G timer 64ms */
+       regmap_update_bits(regmap, NAU8825_REG_CLASSG_CTRL,
+               NAU8825_CLASSG_TIMER_MASK,
+               0x20 << NAU8825_CLASSG_TIMER_SFT);
+       /* DAC clock delay 2ns, VREF */
+       regmap_update_bits(regmap, NAU8825_REG_RDAC,
+               NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK,
+               (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) |
+               (0x3 << NAU8825_RDAC_VREF_SFT));
 }
 
 static const struct regmap_config nau8825_regmap_config = {
index dff8edb..8ceb5f3 100644 (file)
@@ -14,6 +14,7 @@
 
 #define NAU8825_REG_RESET              0x00
 #define NAU8825_REG_ENA_CTRL           0x01
+#define NAU8825_REG_IIC_ADDR_SET               0x02
 #define NAU8825_REG_CLK_DIVIDER                0x03
 #define NAU8825_REG_FLL1               0x04
 #define NAU8825_REG_FLL2               0x05
 
 /* HSD_CTRL (0xc) */
 #define NAU8825_HSD_AUTO_MODE  (1 << 6)
-/* 0 - short to GND, 1 - open */
+/* 0 - open, 1 - short to GND */
 #define NAU8825_SPKR_DWN1R     (1 << 1)
 #define NAU8825_SPKR_DWN1L     (1 << 0)
 
 /* DACR_CTRL (0x34) */
 #define NAU8825_DACR_CH_SEL_SFT        9
 
+/* CLASSG_CTRL (0x50) */
+#define NAU8825_CLASSG_TIMER_SFT       8
+#define NAU8825_CLASSG_TIMER_MASK      (0x3f << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_EN              (1 << 0)
+
 /* I2C_DEVICE_ID (0x58) */
 #define NAU8825_GPIO2JD1       (1 << 7)
 #define NAU8825_SOFTWARE_ID_MASK       0x3
 #define NAU8825_SOFTWARE_ID_NAU8825    0x0
 
 /* BIAS_ADJ (0x66) */
+#define NAU8825_BIAS_TESTDAC_EN        (0x3 << 8)
 #define NAU8825_BIAS_VMID      (1 << 6)
 #define NAU8825_BIAS_VMID_SEL_SFT      4
 #define NAU8825_BIAS_VMID_SEL_MASK     (3 << NAU8825_BIAS_VMID_SEL_SFT)
 #define NAU8825_ADC_VREFSEL_VMID_PLUS_1DB      (3 << 8)
 #define NAU8825_POWERUP_ADCL   (1 << 6)
 
+/* RDAC (0x73) */
+#define NAU8825_RDAC_CLK_DELAY_SFT     4
+#define NAU8825_RDAC_CLK_DELAY_MASK    (0x7 << NAU8825_RDAC_CLK_DELAY_SFT)
+#define NAU8825_RDAC_VREF_SFT  2
+#define NAU8825_RDAC_VREF_MASK (0x3 << NAU8825_RDAC_VREF_SFT)
+
 /* MIC_BIAS (0x74) */
 #define NAU8825_MICBIAS_JKSLV  (1 << 14)
 #define NAU8825_MICBIAS_JKR2   (1 << 12)
 /* BOOST (0x76) */
 #define NAU8825_PRECHARGE_DIS  (1 << 13)
 #define NAU8825_GLOBAL_BIAS_EN (1 << 12)
+#define NAU8825_HP_BOOST_DIS           (1 << 9)
 #define NAU8825_HP_BOOST_G_DIS (1 << 8)
 #define NAU8825_SHORT_SHUTDOWN_EN      (1 << 6)
 
index 9769676..f7e789e 100644 (file)
@@ -17,6 +17,27 @@ config SND_SOC_MT8173_MAX98090
          Select Y if you have such device.
          If unsure select "N".
 
+config SND_SOC_MT8173_RT5650
+       tristate "ASoC Audio driver for MT8173 with RT5650 codec"
+       depends on SND_SOC_MEDIATEK && I2C
+       select SND_SOC_RT5645
+       help
+         This adds ASoC driver for Mediatek MT8173 boards
+         with the RT5650 audio codec.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT8173_RT5650_RT5514
+       tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs"
+       depends on SND_SOC_MEDIATEK && I2C
+       select SND_SOC_RT5645
+       select SND_SOC_RT5514
+       help
+         This adds ASoC driver for Mediatek MT8173 boards
+         with the RT5650 and RT5514 codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
 config SND_SOC_MT8173_RT5650_RT5676
        tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
        depends on SND_SOC_MEDIATEK && I2C
@@ -27,4 +48,3 @@ config SND_SOC_MT8173_RT5650_RT5676
          with the RT5650 and RT5676 codecs.
          Select Y if you have such device.
          If unsure select "N".
-
index 75effbe..d486860 100644 (file)
@@ -2,4 +2,6 @@
 obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o
 # Machine support
 obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o
+obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o
 obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173-rt5650-rt5514.c
new file mode 100644 (file)
index 0000000..58e0836
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * mt8173-rt5650-rt5514.c  --  MT8173 machine driver with RT5650/5514 codecs
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5645.h"
+
+#define MCLK_FOR_CODECS                12288000
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_rt5514_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = {
+       {"Speaker", NULL, "SPOL"},
+       {"Speaker", NULL, "SPOR"},
+       {"Sub DMIC1L", NULL, "Int Mic"},
+       {"Sub DMIC1R", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Headset Mic", NULL, "micbias1"},
+       {"Headset Mic", NULL, "micbias2"},
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream,
+                                         struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int i, ret;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+               /* pll from mclk 12.288M */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
+                                         params_rate(params) * 512);
+               if (ret)
+                       return ret;
+
+               /* sysclk from pll */
+               ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+                                            params_rate(params) * 512,
+                                            SND_SOC_CLOCK_IN);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_ops mt8173_rt5650_rt5514_ops = {
+       .hw_params = mt8173_rt5650_rt5514_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_rt5514_jack;
+
+static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
+       int ret;
+
+       rt5645_sel_asrc_clk_src(codec,
+                               RT5645_DA_STEREO_FILTER |
+                               RT5645_AD_STEREO_FILTER,
+                               RT5645_CLK_SEL_I2S1_ASRC);
+
+       /* enable jack detection */
+       ret = snd_soc_card_jack_new(card, "Headset Jack",
+                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                   &mt8173_rt5650_rt5514_jack, NULL, 0);
+       if (ret) {
+               dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+               return ret;
+       }
+
+       return rt5645_set_jack_detect(codec,
+                                     &mt8173_rt5650_rt5514_jack,
+                                     &mt8173_rt5650_rt5514_jack,
+                                     &mt8173_rt5650_rt5514_jack);
+}
+
+static struct snd_soc_dai_link_component mt8173_rt5650_rt5514_codecs[] = {
+       {
+               .dai_name = "rt5645-aif1",
+       },
+       {
+               .dai_name = "rt5514-aif1",
+       },
+};
+
+enum {
+       DAI_LINK_PLAYBACK,
+       DAI_LINK_CAPTURE,
+       DAI_LINK_CODEC_I2S,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = {
+       /* Front End DAI links */
+       [DAI_LINK_PLAYBACK] = {
+               .name = "rt5650_rt5514 Playback",
+               .stream_name = "rt5650_rt5514 Playback",
+               .cpu_dai_name = "DL1",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+       },
+       [DAI_LINK_CAPTURE] = {
+               .name = "rt5650_rt5514 Capture",
+               .stream_name = "rt5650_rt5514 Capture",
+               .cpu_dai_name = "VUL",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+       },
+       /* Back End DAI links */
+       [DAI_LINK_CODEC_I2S] = {
+               .name = "Codec",
+               .cpu_dai_name = "I2S",
+               .no_pcm = 1,
+               .codecs = mt8173_rt5650_rt5514_codecs,
+               .num_codecs = 2,
+               .init = mt8173_rt5650_rt5514_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .ops = &mt8173_rt5650_rt5514_ops,
+               .ignore_pmdown_time = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+static struct snd_soc_codec_conf mt8173_rt5650_rt5514_codec_conf[] = {
+       {
+               .name_prefix = "Sub",
+       },
+};
+
+static struct snd_soc_card mt8173_rt5650_rt5514_card = {
+       .name = "mtk-rt5650-rt5514",
+       .owner = THIS_MODULE,
+       .dai_link = mt8173_rt5650_rt5514_dais,
+       .num_links = ARRAY_SIZE(mt8173_rt5650_rt5514_dais),
+       .codec_conf = mt8173_rt5650_rt5514_codec_conf,
+       .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5514_codec_conf),
+       .controls = mt8173_rt5650_rt5514_controls,
+       .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5514_controls),
+       .dapm_widgets = mt8173_rt5650_rt5514_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5514_widgets),
+       .dapm_routes = mt8173_rt5650_rt5514_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5514_routes),
+};
+
+static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &mt8173_rt5650_rt5514_card;
+       struct device_node *platform_node;
+       int i, ret;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_rt5650_rt5514_dais[i].platform_name)
+                       continue;
+               mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node;
+       }
+
+       mt8173_rt5650_rt5514_codecs[0].of_node =
+               of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+       if (!mt8173_rt5650_rt5514_codecs[0].of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       mt8173_rt5650_rt5514_codecs[1].of_node =
+               of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
+       if (!mt8173_rt5650_rt5514_codecs[1].of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       mt8173_rt5650_rt5514_codec_conf[0].of_node =
+               mt8173_rt5650_rt5514_codecs[1].of_node;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+                       __func__, ret);
+       return ret;
+}
+
+static const struct of_device_id mt8173_rt5650_rt5514_dt_match[] = {
+       { .compatible = "mediatek,mt8173-rt5650-rt5514", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5514_dt_match);
+
+static struct platform_driver mt8173_rt5650_rt5514_driver = {
+       .driver = {
+                  .name = "mtk-rt5650-rt5514",
+                  .of_match_table = mt8173_rt5650_rt5514_dt_match,
+#ifdef CONFIG_PM
+                  .pm = &snd_soc_pm_ops,
+#endif
+       },
+       .probe = mt8173_rt5650_rt5514_dev_probe,
+};
+
+module_platform_driver(mt8173_rt5650_rt5514_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 and RT5514 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650-rt5514");
+
index 50ba538..5c4c58c 100644 (file)
@@ -131,10 +131,17 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = {
        },
 };
 
+enum {
+       DAI_LINK_PLAYBACK,
+       DAI_LINK_CAPTURE,
+       DAI_LINK_CODEC_I2S,
+       DAI_LINK_INTERCODEC
+};
+
 /* Digital audio interface glue - connects codec <---> CPU */
 static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
        /* Front End DAI links */
-       {
+       [DAI_LINK_PLAYBACK] = {
                .name = "rt5650_rt5676 Playback",
                .stream_name = "rt5650_rt5676 Playback",
                .cpu_dai_name = "DL1",
@@ -144,7 +151,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .dynamic = 1,
                .dpcm_playback = 1,
        },
-       {
+       [DAI_LINK_CAPTURE] = {
                .name = "rt5650_rt5676 Capture",
                .stream_name = "rt5650_rt5676 Capture",
                .cpu_dai_name = "VUL",
@@ -156,7 +163,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
        },
 
        /* Back End DAI links */
-       {
+       [DAI_LINK_CODEC_I2S] = {
                .name = "Codec",
                .cpu_dai_name = "I2S",
                .no_pcm = 1,
@@ -170,7 +177,8 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .dpcm_playback = 1,
                .dpcm_capture = 1,
        },
-       { /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
+       /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
+       [DAI_LINK_INTERCODEC] = {
                .name = "rt5650_rt5676 intercodec",
                .stream_name = "rt5650_rt5676 intercodec",
                .cpu_dai_name = "snd-soc-dummy-dai",
@@ -240,7 +248,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
        mt8173_rt5650_rt5676_codec_conf[0].of_node =
                mt8173_rt5650_rt5676_codecs[1].of_node;
 
-       mt8173_rt5650_rt5676_dais[3].codec_of_node =
+       mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node =
                mt8173_rt5650_rt5676_codecs[1].of_node;
 
        card->dev = &pdev->dev;
diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173-rt5650.c
new file mode 100644 (file)
index 0000000..bb09bb1
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * mt8173-rt5650.c  --  MT8173 machine driver with RT5650 codecs
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Koro Chen <koro.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5645.h"
+
+#define MCLK_FOR_CODECS                12288000
+
+static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = {
+       {"Speaker", NULL, "SPOL"},
+       {"Speaker", NULL, "SPOR"},
+       {"DMIC L1", NULL, "Int Mic"},
+       {"DMIC R1", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Headset Mic", NULL, "micbias1"},
+       {"Headset Mic", NULL, "micbias2"},
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int i, ret;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+               /* pll from mclk 12.288M */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
+                                         params_rate(params) * 512);
+               if (ret)
+                       return ret;
+
+               /* sysclk from pll */
+               ret = snd_soc_dai_set_sysclk(codec_dai, 1,
+                                            params_rate(params) * 512,
+                                            SND_SOC_CLOCK_IN);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_ops mt8173_rt5650_ops = {
+       .hw_params = mt8173_rt5650_hw_params,
+};
+
+static struct snd_soc_jack mt8173_rt5650_jack;
+
+static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
+       int ret;
+
+       rt5645_sel_asrc_clk_src(codec,
+                               RT5645_DA_STEREO_FILTER |
+                               RT5645_AD_STEREO_FILTER,
+                               RT5645_CLK_SEL_I2S1_ASRC);
+       /* enable jack detection */
+       ret = snd_soc_card_jack_new(card, "Headset Jack",
+                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                   &mt8173_rt5650_jack, NULL, 0);
+       if (ret) {
+               dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
+               return ret;
+       }
+
+       return rt5645_set_jack_detect(codec,
+                                     &mt8173_rt5650_jack,
+                                     &mt8173_rt5650_jack,
+                                     &mt8173_rt5650_jack);
+}
+
+static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = {
+       {
+               .dai_name = "rt5645-aif1",
+       },
+};
+
+enum {
+       DAI_LINK_PLAYBACK,
+       DAI_LINK_CAPTURE,
+       DAI_LINK_CODEC_I2S,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
+       /* Front End DAI links */
+       [DAI_LINK_PLAYBACK] = {
+               .name = "rt5650 Playback",
+               .stream_name = "rt5650 Playback",
+               .cpu_dai_name = "DL1",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+       },
+       [DAI_LINK_CAPTURE] = {
+               .name = "rt5650 Capture",
+               .stream_name = "rt5650 Capture",
+               .cpu_dai_name = "VUL",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+       },
+       /* Back End DAI links */
+       [DAI_LINK_CODEC_I2S] = {
+               .name = "Codec",
+               .cpu_dai_name = "I2S",
+               .no_pcm = 1,
+               .codecs = mt8173_rt5650_codecs,
+               .num_codecs = 1,
+               .init = mt8173_rt5650_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .ops = &mt8173_rt5650_ops,
+               .ignore_pmdown_time = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+static struct snd_soc_card mt8173_rt5650_card = {
+       .name = "mtk-rt5650",
+       .owner = THIS_MODULE,
+       .dai_link = mt8173_rt5650_dais,
+       .num_links = ARRAY_SIZE(mt8173_rt5650_dais),
+       .controls = mt8173_rt5650_controls,
+       .num_controls = ARRAY_SIZE(mt8173_rt5650_controls),
+       .dapm_widgets = mt8173_rt5650_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_widgets),
+       .dapm_routes = mt8173_rt5650_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_routes),
+};
+
+static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &mt8173_rt5650_card;
+       struct device_node *platform_node;
+       int i, ret;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_rt5650_dais[i].platform_name)
+                       continue;
+               mt8173_rt5650_dais[i].platform_of_node = platform_node;
+       }
+
+       mt8173_rt5650_codecs[0].of_node =
+               of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
+       if (!mt8173_rt5650_codecs[0].of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'audio-codec' missing or invalid\n");
+               return -EINVAL;
+       }
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+                       __func__, ret);
+       return ret;
+}
+
+static const struct of_device_id mt8173_rt5650_dt_match[] = {
+       { .compatible = "mediatek,mt8173-rt5650", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mt8173_rt5650_dt_match);
+
+static struct platform_driver mt8173_rt5650_driver = {
+       .driver = {
+                  .name = "mtk-rt5650",
+                  .of_match_table = mt8173_rt5650_dt_match,
+#ifdef CONFIG_PM
+                  .pm = &snd_soc_pm_ops,
+#endif
+       },
+       .probe = mt8173_rt5650_dev_probe,
+};
+
+module_platform_driver(mt8173_rt5650_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8173 RT5650 SoC machine driver");
+MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-rt5650");
+
index 9b1af1a..f341f62 100644 (file)
@@ -87,6 +87,7 @@ struct mtk_afe_memif_data {
        int irq_en_shift;
        int irq_fs_shift;
        int irq_clr_shift;
+       int msb_shift;
 };
 
 struct mtk_afe_memif {
index 08af9f5..f1c58a2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include "mtk-afe-common.h"
 #define AFE_I2S_CON1           0x0034
 #define AFE_I2S_CON2           0x0038
 #define AFE_CONN_24BIT         0x006c
+#define AFE_MEMIF_MSB          0x00cc
 
 #define AFE_CONN1              0x0024
 #define AFE_CONN2              0x0028
+#define AFE_CONN3              0x002c
 #define AFE_CONN7              0x0460
 #define AFE_CONN8              0x0464
 #define AFE_HDMI_CONN0         0x0390
@@ -61,6 +64,7 @@
 #define AFE_HDMI_OUT_CUR       0x0378
 #define AFE_HDMI_OUT_END       0x037c
 
+#define AFE_ADDA_TOP_CON0      0x0120
 #define AFE_ADDA2_TOP_CON0     0x0600
 
 #define AFE_HDMI_OUT_CON0      0x0370
@@ -257,6 +261,7 @@ static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate)
                return -EINVAL;
 
        /* from external ADC */
+       regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
        regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1);
 
        /* set input */
@@ -281,20 +286,13 @@ static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable)
 
        regmap_read(afe->regmap, AFE_I2S_CON2, &val);
        if (!!(val & AFE_I2S_CON2_EN) == enable)
-               return; /* must skip soft reset */
-
-       /* I2S soft reset begin */
-       regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0x4);
+               return;
 
        /* input */
        regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable);
 
        /* output */
        regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
-
-       /* I2S soft reset end */
-       udelay(1);
-       regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0);
 }
 
 static int mtk_afe_dais_enable_clks(struct mtk_afe *afe,
@@ -363,6 +361,7 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream,
                return 0;
 
        mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+       mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL);
        regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
                           AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
        return 0;
@@ -382,6 +381,7 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream,
                           AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
                           AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
        mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+       mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL);
 }
 
 static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
@@ -395,6 +395,9 @@ static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
        mtk_afe_dais_set_clks(afe,
                              afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256,
                              NULL, 0);
+       mtk_afe_dais_set_clks(afe,
+                             afe->clocks[MTK_CLK_I2S2_M], runtime->rate * 256,
+                             NULL, 0);
        /* config I2S */
        ret = mtk_afe_set_i2s(afe, substream->runtime->rate);
        if (ret)
@@ -592,6 +595,7 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
        struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+       int msb_at_bit33 = 0;
        int ret;
 
        dev_dbg(afe->dev,
@@ -603,7 +607,8 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       memif->phys_buf_addr = substream->runtime->dma_addr;
+       msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
+       memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
        memif->buffer_size = substream->runtime->dma_bytes;
 
        /* start */
@@ -614,6 +619,11 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream,
                     memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
                     memif->phys_buf_addr + memif->buffer_size - 1);
 
+       /* set MSB to 33-bit */
+       regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
+                          1 << memif->data->msb_shift,
+                          msb_at_bit33 << memif->data->msb_shift);
+
        /* set channel */
        if (memif->data->mono_shift >= 0) {
                unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
@@ -894,15 +904,19 @@ static const struct snd_kcontrol_new mtk_afe_o04_mix[] = {
 };
 
 static const struct snd_kcontrol_new mtk_afe_o09_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0),
        SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0),
 };
 
 static const struct snd_kcontrol_new mtk_afe_o10_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0),
        SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = {
        /* inter-connections */
+       SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -925,12 +939,16 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = {
        {"I2S Playback", NULL, "O04"},
        {"VUL", NULL, "O09"},
        {"VUL", NULL, "O10"},
+       {"I03", NULL, "I2S Capture"},
+       {"I04", NULL, "I2S Capture"},
        {"I17", NULL, "I2S Capture"},
        {"I18", NULL, "I2S Capture"},
        { "O03", "I05 Switch", "I05" },
        { "O04", "I06 Switch", "I06" },
        { "O09", "I17 Switch", "I17" },
+       { "O09", "I03 Switch", "I03" },
        { "O10", "I18 Switch", "I18" },
+       { "O10", "I04 Switch", "I04" },
 };
 
 static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = {
@@ -978,6 +996,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 0,
                .irq_fs_shift = 4,
                .irq_clr_shift = 0,
+               .msb_shift = 0,
        }, {
                .name = "DL2",
                .id = MTK_AFE_MEMIF_DL2,
@@ -991,6 +1010,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 2,
                .irq_fs_shift = 16,
                .irq_clr_shift = 2,
+               .msb_shift = 1,
        }, {
                .name = "VUL",
                .id = MTK_AFE_MEMIF_VUL,
@@ -1004,6 +1024,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 1,
                .irq_fs_shift = 8,
                .irq_clr_shift = 1,
+               .msb_shift = 6,
        }, {
                .name = "DAI",
                .id = MTK_AFE_MEMIF_DAI,
@@ -1017,6 +1038,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 3,
                .irq_fs_shift = 20,
                .irq_clr_shift = 3,
+               .msb_shift = 5,
        }, {
                .name = "AWB",
                .id = MTK_AFE_MEMIF_AWB,
@@ -1030,6 +1052,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 14,
                .irq_fs_shift = 24,
                .irq_clr_shift = 6,
+               .msb_shift = 3,
        }, {
                .name = "MOD_DAI",
                .id = MTK_AFE_MEMIF_MOD_DAI,
@@ -1043,6 +1066,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 3,
                .irq_fs_shift = 20,
                .irq_clr_shift = 3,
+               .msb_shift = 4,
        }, {
                .name = "HDMI",
                .id = MTK_AFE_MEMIF_HDMI,
@@ -1056,6 +1080,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = {
                .irq_en_shift = 12,
                .irq_fs_shift = -1,
                .irq_clr_shift = 4,
+               .msb_shift = 8,
        },
 };
 
@@ -1189,6 +1214,10 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev)
        struct mtk_afe *afe;
        struct resource *res;
 
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
+       if (ret)
+               return ret;
+
        afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
        if (!afe)
                return -ENOMEM;
index a6c7b8d..1363100 100644 (file)
@@ -418,7 +418,7 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
        }
 
        stat = __raw_readl(saif->base + SAIF_STAT);
-       if (stat & BM_SAIF_STAT_BUSY) {
+       if (!saif->mclk_in_use && (stat & BM_SAIF_STAT_BUSY)) {
                dev_err(cpu_dai->dev, "error: busy\n");
                return -EBUSY;
        }
index f83cc2b..64425d3 100644 (file)
@@ -345,6 +345,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
                dai_drv = &omap4_hdmi_dai;
                break;
        case OMAPDSS_VER_OMAP5:
+       case OMAPDSS_VER_DRA7xx:
                dai_drv = &omap5_hdmi_dai;
                break;
        default: