root/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
// SPDX-License-Identifier: GPL-2.0
//
// mt8192-mt6359-rt1015-rt5682.c  --
//      MT8192-MT6359-RT1015-RT6358 ALSA SoC machine driver
//
// Copyright (c) 2020 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
//

#include <linux/input.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/rt5682.h>
#include <sound/soc.h>

#include "../../codecs/mt6359.h"
#include "../../codecs/rt1015.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-soc-card.h"
#include "../common/mtk-soundcard-driver.h"
#include "mt8192-afe-common.h"
#include "mt8192-afe-clk.h"
#include "mt8192-afe-gpio.h"

#define DRIVER_NAME "mt8192_mt6359"

#define RT1015_CODEC_DAI        "rt1015-aif"
#define RT1015_DEV0_NAME        "rt1015.1-0028"
#define RT1015_DEV1_NAME        "rt1015.1-0029"

#define RT1015_RT5682_CARD_NAME "mt8192_mt6359_rt1015_rt5682"
#define RT1015P_RT5682_CARD_NAME "mt8192_mt6359_rt1015p_rt5682"
#define RT1015P_RT5682S_CARD_NAME "mt8192_mt6359_rt1015p_rt5682s"

#define RT1015_RT5682_OF_NAME "mediatek,mt8192_mt6359_rt1015_rt5682"
#define RT1015P_RT5682_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682"
#define RT1015P_RT5682S_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682s"

enum mt8192_jacks {
        MT8192_JACK_HEADSET,
        MT8192_JACK_HDMI,
        MT8192_JACK_MAX,
};

/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin mt8192_jack_pins[] = {
        {
                .pin = "Headphone Jack",
                .mask = SND_JACK_HEADPHONE,
        },
        {
                .pin = "Headset Mic",
                .mask = SND_JACK_MICROPHONE,
        },
};

static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
                                       struct snd_pcm_hw_params *params)
{
        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai;
        unsigned int rate = params_rate(params);
        unsigned int mclk_fs_ratio = 128;
        unsigned int mclk_fs = rate * mclk_fs_ratio;
        int ret, i;

        for_each_rtd_codec_dais(rtd, i, codec_dai) {
                ret = snd_soc_dai_set_pll(codec_dai, 0,
                                          RT1015_PLL_S_BCLK,
                                          params_rate(params) * 64,
                                          params_rate(params) * 256);
                if (ret) {
                        dev_err(card->dev, "failed to set pll\n");
                        return ret;
                }

                ret = snd_soc_dai_set_sysclk(codec_dai,
                                             RT1015_SCLK_S_PLL,
                                             params_rate(params) * 256,
                                             SND_SOC_CLOCK_IN);
                if (ret) {
                        dev_err(card->dev, "failed to set sysclk\n");
                        return ret;
                }
        }

        return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
}

static int mt8192_rt5682x_i2s_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params)
{
        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
        unsigned int rate = params_rate(params);
        unsigned int mclk_fs_ratio = 128;
        unsigned int mclk_fs = rate * mclk_fs_ratio;
        int bitwidth;
        int ret;

        bitwidth = snd_pcm_format_width(params_format(params));
        if (bitwidth < 0) {
                dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
                return bitwidth;
        }

        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
        if (ret) {
                dev_err(card->dev, "failed to set tdm slot\n");
                return ret;
        }

        ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1,
                                  RT5682_PLL1_S_BCLK1,
                                  params_rate(params) * 64,
                                  params_rate(params) * 512);
        if (ret) {
                dev_err(card->dev, "failed to set pll\n");
                return ret;
        }

        ret = snd_soc_dai_set_sysclk(codec_dai,
                                     RT5682_SCLK_S_PLL1,
                                     params_rate(params) * 512,
                                     SND_SOC_CLOCK_IN);
        if (ret) {
                dev_err(card->dev, "failed to set sysclk\n");
                return ret;
        }

        return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
}

static const struct snd_soc_ops mt8192_rt1015_i2s_ops = {
        .hw_params = mt8192_rt1015_i2s_hw_params,
};

static const struct snd_soc_ops mt8192_rt5682x_i2s_ops = {
        .hw_params = mt8192_rt5682x_i2s_hw_params,
};

static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
{
        struct snd_soc_component *cmpnt_afe =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
        struct snd_soc_component *cmpnt_codec =
                snd_soc_rtd_to_codec(rtd, 0)->component;
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
        struct mt8192_afe_private *afe_priv = afe->platform_priv;
        int phase;
        unsigned int monitor;
        int test_done_1, test_done_2, test_done_3;
        int cycle_1, cycle_2, cycle_3;
        int prev_cycle_1, prev_cycle_2, prev_cycle_3;
        int chosen_phase_1, chosen_phase_2, chosen_phase_3;
        int counter;
        int mtkaif_calib_ok;

        pm_runtime_get_sync(afe->dev);
        mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1);
        mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0);
        mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 1);
        mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 0);

        mt6359_mtkaif_calibration_enable(cmpnt_codec);

        /* set clock protocol 2 */
        regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);
        regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x39);

        /* set test type to synchronizer pulse */
        regmap_update_bits(afe_priv->topckgen,
                           CKSYS_AUD_TOP_CFG, 0xffff, 0x4);

        mtkaif_calib_ok = true;
        afe_priv->mtkaif_calibration_num_phase = 42;    /* mt6359: 0 ~ 42 */
        afe_priv->mtkaif_chosen_phase[0] = -1;
        afe_priv->mtkaif_chosen_phase[1] = -1;
        afe_priv->mtkaif_chosen_phase[2] = -1;

        for (phase = 0;
             phase <= afe_priv->mtkaif_calibration_num_phase &&
             mtkaif_calib_ok;
             phase++) {
                mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
                                                    phase, phase, phase);

                regmap_update_bits(afe_priv->topckgen,
                                   CKSYS_AUD_TOP_CFG, 0x1, 0x1);

                test_done_1 = 0;
                test_done_2 = 0;
                test_done_3 = 0;
                cycle_1 = -1;
                cycle_2 = -1;
                cycle_3 = -1;
                counter = 0;
                while (test_done_1 == 0 ||
                       test_done_2 == 0 ||
                       test_done_3 == 0) {
                        regmap_read(afe_priv->topckgen,
                                    CKSYS_AUD_TOP_MON, &monitor);

                        test_done_1 = (monitor >> 28) & 0x1;
                        test_done_2 = (monitor >> 29) & 0x1;
                        test_done_3 = (monitor >> 30) & 0x1;
                        if (test_done_1 == 1)
                                cycle_1 = monitor & 0xf;

                        if (test_done_2 == 1)
                                cycle_2 = (monitor >> 4) & 0xf;

                        if (test_done_3 == 1)
                                cycle_3 = (monitor >> 8) & 0xf;

                        /* handle if never test done */
                        if (++counter > 10000) {
                                dev_err(afe->dev, "%s(), test fail, cycle_1 %d, cycle_2 %d, cycle_3 %d, monitor 0x%x\n",
                                        __func__,
                                        cycle_1, cycle_2, cycle_3, monitor);
                                mtkaif_calib_ok = false;
                                break;
                        }
                }

                if (phase == 0) {
                        prev_cycle_1 = cycle_1;
                        prev_cycle_2 = cycle_2;
                        prev_cycle_3 = cycle_3;
                }

                if (cycle_1 != prev_cycle_1 &&
                    afe_priv->mtkaif_chosen_phase[0] < 0) {
                        afe_priv->mtkaif_chosen_phase[0] = phase - 1;
                        afe_priv->mtkaif_phase_cycle[0] = prev_cycle_1;
                }

                if (cycle_2 != prev_cycle_2 &&
                    afe_priv->mtkaif_chosen_phase[1] < 0) {
                        afe_priv->mtkaif_chosen_phase[1] = phase - 1;
                        afe_priv->mtkaif_phase_cycle[1] = prev_cycle_2;
                }

                if (cycle_3 != prev_cycle_3 &&
                    afe_priv->mtkaif_chosen_phase[2] < 0) {
                        afe_priv->mtkaif_chosen_phase[2] = phase - 1;
                        afe_priv->mtkaif_phase_cycle[2] = prev_cycle_3;
                }

                regmap_update_bits(afe_priv->topckgen,
                                   CKSYS_AUD_TOP_CFG, 0x1, 0x0);

                if (afe_priv->mtkaif_chosen_phase[0] >= 0 &&
                    afe_priv->mtkaif_chosen_phase[1] >= 0 &&
                    afe_priv->mtkaif_chosen_phase[2] >= 0)
                        break;
        }

        if (afe_priv->mtkaif_chosen_phase[0] < 0)
                chosen_phase_1 = 0;
        else
                chosen_phase_1 = afe_priv->mtkaif_chosen_phase[0];

        if (afe_priv->mtkaif_chosen_phase[1] < 0)
                chosen_phase_2 = 0;
        else
                chosen_phase_2 = afe_priv->mtkaif_chosen_phase[1];

        if (afe_priv->mtkaif_chosen_phase[2] < 0)
                chosen_phase_3 = 0;
        else
                chosen_phase_3 = afe_priv->mtkaif_chosen_phase[2];

        mt6359_set_mtkaif_calibration_phase(cmpnt_codec,
                                            chosen_phase_1,
                                            chosen_phase_2,
                                            chosen_phase_3);

        /* disable rx fifo */
        regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38);

        mt6359_mtkaif_calibration_disable(cmpnt_codec);

        mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1);
        mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0);
        mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 1);
        mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 0);
        pm_runtime_put(afe->dev);

        dev_dbg(afe->dev, "%s(), mtkaif_chosen_phase[0/1/2]:%d/%d/%d\n",
                __func__,
                afe_priv->mtkaif_chosen_phase[0],
                afe_priv->mtkaif_chosen_phase[1],
                afe_priv->mtkaif_chosen_phase[2]);

        return 0;
}

static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd)
{
        struct snd_soc_component *cmpnt_afe =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
        struct snd_soc_component *cmpnt_codec =
                snd_soc_rtd_to_codec(rtd, 0)->component;
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
        struct mt8192_afe_private *afe_priv = afe->platform_priv;

        /* set mtkaif protocol */
        mt6359_set_mtkaif_protocol(cmpnt_codec,
                                   MT6359_MTKAIF_PROTOCOL_2_CLK_P2);
        afe_priv->mtkaif_protocol = MTKAIF_PROTOCOL_2_CLK_P2;

        /* mtkaif calibration */
        mt8192_mt6359_mtkaif_calibration(rtd);

        return 0;
}

static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
        struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8192_JACK_HEADSET];
        struct snd_soc_component *cmpnt_afe =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
        struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
        struct snd_soc_component *cmpnt_codec =
                snd_soc_rtd_to_codec(rtd, 0)->component;
        int ret;

        ret = mt8192_dai_i2s_set_share(afe, "I2S8", "I2S9");
        if (ret) {
                dev_err(rtd->dev, "Failed to set up shared clocks\n");
                return ret;
        }

        ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
                                    SND_JACK_HEADSET | SND_JACK_BTN_0 |
                                    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
                                    SND_JACK_BTN_3,
                                    jack, mt8192_jack_pins,
                                    ARRAY_SIZE(mt8192_jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
        }

        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);

        return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
};

static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
        struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8192_JACK_HDMI];
        struct snd_soc_component *cmpnt_codec =
                snd_soc_rtd_to_codec(rtd, 0)->component;
        int ret;

        ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack);
        if (ret) {
                dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
                return ret;
        }

        return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}

static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                      struct snd_pcm_hw_params *params)
{
        /* fix BE i2s format to S24_LE, clean param mask first */
        snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
                             0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);

        params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);

        return 0;
}

/* FE */
SND_SOC_DAILINK_DEFS(playback1,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback12,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback2,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback3,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback4,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback5,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback6,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback7,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback8,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback9,
                     DAILINK_COMP_ARRAY(COMP_CPU("DL9")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture1,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture2,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture3,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture4,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture5,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture6,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture7,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture8,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL8")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture_mono1,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture_mono2,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_2")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(capture_mono3,
                     DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_3")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(playback_hdmi,
                     DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

/* BE */
SND_SOC_DAILINK_DEFS(primary_codec,
                     DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
                     DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
                                                   "mt6359-snd-codec-aif1"),
                                        COMP_CODEC("dmic-codec",
                                                   "dmic-hifi")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(primary_codec_ch34,
                     DAILINK_COMP_ARRAY(COMP_CPU("ADDA_CH34")),
                     DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
                                                   "mt6359-snd-codec-aif2")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(ap_dmic,
                     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
                     DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s0,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s1,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s2,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s3,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s5,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S5")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s6,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S6")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s7,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S7")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s8,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S8")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(i2s9,
                     DAILINK_COMP_ARRAY(COMP_CPU("I2S9")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(connsys_i2s,
                     DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(pcm1,
                     DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(pcm2,
                     DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")),
                     DAILINK_COMP_ARRAY(COMP_DUMMY()),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

SND_SOC_DAILINK_DEFS(tdm,
                     DAILINK_COMP_ARRAY(COMP_CPU("TDM")),
                     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
                     DAILINK_COMP_ARRAY(COMP_EMPTY()));

static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
        /* Front End DAI links */
        {
                .name = "Playback_1",
                .stream_name = "Playback_1",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback1),
        },
        {
                .name = "Playback_12",
                .stream_name = "Playback_12",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback12),
        },
        {
                .name = "Playback_2",
                .stream_name = "Playback_2",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback2),
        },
        {
                .name = "Playback_3",
                .stream_name = "Playback_3",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                .ops = &mtk_soundcard_common_playback_ops,
                SND_SOC_DAILINK_REG(playback3),
        },
        {
                .name = "Playback_4",
                .stream_name = "Playback_4",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback4),
        },
        {
                .name = "Playback_5",
                .stream_name = "Playback_5",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback5),
        },
        {
                .name = "Playback_6",
                .stream_name = "Playback_6",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback6),
        },
        {
                .name = "Playback_7",
                .stream_name = "Playback_7",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback7),
        },
        {
                .name = "Playback_8",
                .stream_name = "Playback_8",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback8),
        },
        {
                .name = "Playback_9",
                .stream_name = "Playback_9",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback9),
        },
        {
                .name = "Capture_1",
                .stream_name = "Capture_1",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                .ops = &mtk_soundcard_common_capture_ops,
                SND_SOC_DAILINK_REG(capture1),
        },
        {
                .name = "Capture_2",
                .stream_name = "Capture_2",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                .ops = &mtk_soundcard_common_playback_ops,
                SND_SOC_DAILINK_REG(capture2),
        },
        {
                .name = "Capture_3",
                .stream_name = "Capture_3",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture3),
        },
        {
                .name = "Capture_4",
                .stream_name = "Capture_4",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture4),
        },
        {
                .name = "Capture_5",
                .stream_name = "Capture_5",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture5),
        },
        {
                .name = "Capture_6",
                .stream_name = "Capture_6",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture6),
        },
        {
                .name = "Capture_7",
                .stream_name = "Capture_7",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture7),
        },
        {
                .name = "Capture_8",
                .stream_name = "Capture_8",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture8),
        },
        {
                .name = "Capture_Mono_1",
                .stream_name = "Capture_Mono_1",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture_mono1),
        },
        {
                .name = "Capture_Mono_2",
                .stream_name = "Capture_Mono_2",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture_mono2),
        },
        {
                .name = "Capture_Mono_3",
                .stream_name = "Capture_Mono_3",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .capture_only = 1,
                SND_SOC_DAILINK_REG(capture_mono3),
        },
        {
                .name = "playback_hdmi",
                .stream_name = "Playback_HDMI",
                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
                            SND_SOC_DPCM_TRIGGER_PRE},
                .dynamic = 1,
                .playback_only = 1,
                SND_SOC_DAILINK_REG(playback_hdmi),
        },
        /* Back End DAI links */
        {
                .name = "Primary Codec",
                .no_pcm = 1,
                .ignore_suspend = 1,
                .init = mt8192_mt6359_init,
                SND_SOC_DAILINK_REG(primary_codec),
        },
        {
                .name = "Primary Codec CH34",
                .no_pcm = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(primary_codec_ch34),
        },
        {
                .name = "AP_DMIC",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(ap_dmic),
        },
        {
                .name = "AP_DMIC_CH34",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(ap_dmic_ch34),
        },
        {
                .name = "I2S0",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s0),
        },
        {
                .name = "I2S1",
                .no_pcm = 1,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s1),
        },
        {
                .name = "I2S2",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s2),
        },
        {
                .name = "I2S3",
                .no_pcm = 1,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s3),
        },
        {
                .name = "I2S5",
                .no_pcm = 1,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s5),
        },
        {
                .name = "I2S6",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s6),
        },
        {
                .name = "I2S7",
                .no_pcm = 1,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s7),
        },
        {
                .name = "I2S8",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                .init = mt8192_rt5682_init,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s8),
                .ops = &mt8192_rt5682x_i2s_ops,
        },
        {
                .name = "I2S9",
                .no_pcm = 1,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                SND_SOC_DAILINK_REG(i2s9),
                .ops = &mt8192_rt5682x_i2s_ops,
        },
        {
                .name = "CONNSYS_I2S",
                .no_pcm = 1,
                .capture_only = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(connsys_i2s),
        },
        {
                .name = "PCM 1",
                .no_pcm = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(pcm1),
        },
        {
                .name = "PCM 2",
                .no_pcm = 1,
                .ignore_suspend = 1,
                SND_SOC_DAILINK_REG(pcm2),
        },
        {
                .name = "TDM",
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_DSP_A |
                           SND_SOC_DAIFMT_IB_NF |
                           SND_SOC_DAIFMT_CBP_CFP,
                .playback_only = 1,
                .ignore_suspend = 1,
                .be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
                .ignore = 1,
                .init = mt8192_mt6359_hdmi_init,
                SND_SOC_DAILINK_REG(tdm),
        },
};

static const struct snd_soc_dapm_widget
mt8192_mt6359_rt1015_rt5682_widgets[] = {
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_OUTPUT("TDM Out"),
};

static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = {
        /* speaker */
        { "Left Spk", NULL, "Left SPO" },
        { "Right Spk", NULL, "Right SPO" },
        /* headset */
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
        { "IN1P", NULL, "Headset Mic" },
        /* TDM */
        { "TDM Out", NULL, "TDM" },
};

static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = {
        SOC_DAPM_PIN_SWITCH("Left Spk"),
        SOC_DAPM_PIN_SWITCH("Right Spk"),
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
};

static struct snd_soc_codec_conf rt1015_amp_conf[] = {
        {
                .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),
                .name_prefix = "Left",
        },
        {
                .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),
                .name_prefix = "Right",
        },
};

static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = {
        .name = RT1015_RT5682_CARD_NAME,
        .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = mt8192_mt6359_dai_links,
        .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
        .controls = mt8192_mt6359_rt1015_rt5682_controls,
        .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_controls),
        .dapm_widgets = mt8192_mt6359_rt1015_rt5682_widgets,
        .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_widgets),
        .dapm_routes = mt8192_mt6359_rt1015_rt5682_routes,
        .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_routes),
        .codec_conf = rt1015_amp_conf,
        .num_configs = ARRAY_SIZE(rt1015_amp_conf),
};

static const struct snd_soc_dapm_widget mt8192_mt6359_rt1015p_rt5682x_widgets[] = {
        SND_SOC_DAPM_SPK("Speakers", NULL),
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
};

static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682x_routes[] = {
        /* speaker */
        { "Speakers", NULL, "Speaker" },
        /* headset */
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
        { "IN1P", NULL, "Headset Mic" },
};

static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682x_controls[] = {
        SOC_DAPM_PIN_SWITCH("Speakers"),
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
};

static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = {
        .driver_name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .dai_link = mt8192_mt6359_dai_links,
        .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links),
        .controls = mt8192_mt6359_rt1015p_rt5682x_controls,
        .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_controls),
        .dapm_widgets = mt8192_mt6359_rt1015p_rt5682x_widgets,
        .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_widgets),
        .dapm_routes = mt8192_mt6359_rt1015p_rt5682x_routes,
        .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes),
};

static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
                                          struct snd_soc_dai_link *link,
                                          struct device_node *node,
                                          char *link_name)
{
        int ret;

        if (node && strcmp(link->name, link_name) == 0) {
                ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link);
                if (ret < 0) {
                        dev_err_probe(card->dev, ret, "get dai link codecs fail\n");
                        return ret;
                }
        }

        return 0;
}

static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data)
{
        struct mtk_platform_card_data *card_data = soc_card_data->card_data;
        struct snd_soc_card *card = card_data->card;
        struct device *dev = card->dev;
        struct device_node *hdmi_codec, *headset_codec, *speaker_codec;
        struct snd_soc_dai_link *dai_link;
        int i, ret = 0;

        hdmi_codec = of_parse_phandle(dev->of_node, "mediatek,hdmi-codec", 0);
        if (!hdmi_codec)
                dev_dbg(dev, "The machine has no hdmi-codec\n");

        speaker_codec = of_get_child_by_name(dev->of_node, "speaker-codecs");
        if (!speaker_codec) {
                ret = -EINVAL;
                dev_err_probe(dev, ret, "Property 'speaker-codecs' missing or invalid\n");
                goto err_speaker_codec;
        }

        headset_codec = of_get_child_by_name(dev->of_node, "headset-codec");
        if (!headset_codec) {
                ret = -EINVAL;
                dev_err_probe(dev, ret, "Property 'headset-codec' missing or invalid\n");
                goto err_headset_codec;
        }

        for_each_card_prelinks(card, i, dai_link) {
                ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3");
                if (ret) {
                        dev_err_probe(dev, ret, "%s set speaker_codec fail\n",
                                      dai_link->name);
                        break;
                }

                ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8");
                if (ret) {
                        dev_err_probe(dev, ret, "%s set headset_codec fail\n",
                                      dai_link->name);
                        break;
                }

                ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9");
                if (ret) {
                        dev_err_probe(dev, ret, "%s set headset_codec fail\n",
                                      dai_link->name);
                        break;
                }

                if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
                        dai_link->codecs->of_node = hdmi_codec;
                        dai_link->ignore = 0;
                }

                if (dai_link->num_codecs &&
                    strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0)
                        dai_link->ops = &mt8192_rt1015_i2s_ops;
        }

        of_node_put(headset_codec);
err_headset_codec:
        of_node_put(speaker_codec);
err_speaker_codec:
        of_node_put(hdmi_codec);
        return ret;
}

static int mt8192_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
{
        struct mtk_platform_card_data *card_data = soc_card_data->card_data;
        struct snd_soc_card *card = card_data->card;
        int ret;

        if (legacy) {
                ret = mt8192_mt6359_legacy_probe(soc_card_data);
                if (ret)
                        return ret;
        } else {
                struct snd_soc_dai_link *dai_link;
                int i;

                for_each_card_prelinks(card, i, dai_link)
                        if (dai_link->num_codecs &&
                            strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0)
                                dai_link->ops = &mt8192_rt1015_i2s_ops;
        }

        ret = mt8192_afe_gpio_init(card->dev);
        if (ret)
                return dev_err_probe(card->dev, ret, "%s init gpio error\n", __func__);

        return 0;
}

static const unsigned int mt8192_pcm_playback_channels[] = { 1, 2 };
static const unsigned int mt8192_pcm_playback_rates[] = { 48000 };

static const unsigned int mt8192_pcm_capture_channels[] = { 1, 2, 4 };
static const unsigned int mt8192_pcm_capture_rates[] = {
        8000, 16000, 32000, 48000, 96000, 192000
};

static const struct mtk_pcm_constraints_data mt8192_pcm_constraints[MTK_CONSTRAINT_CAPTURE + 1] = {
        [MTK_CONSTRAINT_PLAYBACK] = {
                .channels =  &(const struct snd_pcm_hw_constraint_list) {
                        .list = mt8192_pcm_playback_channels,
                        .count = ARRAY_SIZE(mt8192_pcm_playback_channels)
                },
                .rates =  &(const struct snd_pcm_hw_constraint_list) {
                        .list = mt8192_pcm_playback_rates,
                        .count = ARRAY_SIZE(mt8192_pcm_playback_rates)
                }
        },
        [MTK_CONSTRAINT_CAPTURE] = {
                .channels =  &(const struct snd_pcm_hw_constraint_list) {
                        .list = mt8192_pcm_capture_channels,
                        .count = ARRAY_SIZE(mt8192_pcm_capture_channels)
                },
                .rates =  &(const struct snd_pcm_hw_constraint_list) {
                        .list = mt8192_pcm_capture_rates,
                        .count = ARRAY_SIZE(mt8192_pcm_capture_rates)
                }
        }
};

static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015_rt5682_pdata = {
        .card_name = RT1015_RT5682_CARD_NAME,
        .card_data = &(struct mtk_platform_card_data) {
                .card = &mt8192_mt6359_rt1015_rt5682_card,
                .num_jacks = MT8192_JACK_MAX,
                .pcm_constraints = mt8192_pcm_constraints,
                .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
        },
        .soc_probe = mt8192_mt6359_soc_card_probe
};

static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015p_rt5682_pdata = {
        .card_name = RT1015P_RT5682_CARD_NAME,
        .card_data = &(struct mtk_platform_card_data) {
                .card = &mt8192_mt6359_rt1015p_rt5682x_card,
                .num_jacks = MT8192_JACK_MAX,
                .pcm_constraints = mt8192_pcm_constraints,
                .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
        },
        .soc_probe = mt8192_mt6359_soc_card_probe
};

static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015p_rt5682s_pdata = {
        .card_name = RT1015P_RT5682S_CARD_NAME,
        .card_data = &(struct mtk_platform_card_data) {
                .card = &mt8192_mt6359_rt1015p_rt5682x_card,
                .num_jacks = MT8192_JACK_MAX,
                .pcm_constraints = mt8192_pcm_constraints,
                .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
        },
        .soc_probe = mt8192_mt6359_soc_card_probe
};

#ifdef CONFIG_OF
static const struct of_device_id mt8192_mt6359_dt_match[] = {
        {
                .compatible = RT1015_RT5682_OF_NAME,
                .data = &mt8192_mt6359_rt1015_rt5682_pdata,
        },
        {
                .compatible = RT1015P_RT5682_OF_NAME,
                .data = &mt8192_mt6359_rt1015p_rt5682_pdata,
        },
        {
                .compatible = RT1015P_RT5682S_OF_NAME,
                .data = &mt8192_mt6359_rt1015p_rt5682s_pdata,
        },
        {}
};
MODULE_DEVICE_TABLE(of, mt8192_mt6359_dt_match);
#endif

static const struct dev_pm_ops mt8192_mt6359_pm_ops = {
        .poweroff = snd_soc_poweroff,
        .restore = snd_soc_resume,
};

static struct platform_driver mt8192_mt6359_driver = {
        .driver = {
                .name = DRIVER_NAME,
#ifdef CONFIG_OF
                .of_match_table = mt8192_mt6359_dt_match,
#endif
                .pm = &mt8192_mt6359_pm_ops,
        },
        .probe = mtk_soundcard_common_probe,
};

module_platform_driver(mt8192_mt6359_driver);

/* Module information */
MODULE_DESCRIPTION("MT8192-MT6359 ALSA SoC machine driver");
MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("mt8192_mt6359 soc card");