0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/gpio.h>
0011 #include <linux/of_gpio.h>
0012 #include <sound/soc.h>
0013 #include <sound/jack.h>
0014 #include "../../codecs/rt5645.h"
0015 #include "../../codecs/rt5677.h"
0016
0017 #define MCLK_FOR_CODECS 12288000
0018
0019 static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {
0020 SND_SOC_DAPM_SPK("Speaker", NULL),
0021 SND_SOC_DAPM_MIC("Int Mic", NULL),
0022 SND_SOC_DAPM_HP("Headphone", NULL),
0023 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0024 };
0025
0026 static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {
0027 {"Speaker", NULL, "SPOL"},
0028 {"Speaker", NULL, "SPOR"},
0029 {"Speaker", NULL, "Sub AIF2TX"},
0030 {"Sub DMIC L1", NULL, "Int Mic"},
0031 {"Sub DMIC R1", NULL, "Int Mic"},
0032 {"Headphone", NULL, "HPOL"},
0033 {"Headphone", NULL, "HPOR"},
0034 {"Headphone", NULL, "Sub AIF2TX"},
0035 {"IN1P", NULL, "Headset Mic"},
0036 {"IN1N", NULL, "Headset Mic"},
0037 {"Sub AIF2RX", NULL, "Headset Mic"},
0038 };
0039
0040 static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
0041 SOC_DAPM_PIN_SWITCH("Speaker"),
0042 SOC_DAPM_PIN_SWITCH("Int Mic"),
0043 SOC_DAPM_PIN_SWITCH("Headphone"),
0044 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0045 };
0046
0047 static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
0048 struct snd_pcm_hw_params *params)
0049 {
0050 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0051 struct snd_soc_dai *codec_dai;
0052 int i, ret;
0053
0054 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0055
0056 ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
0057 params_rate(params) * 512);
0058 if (ret)
0059 return ret;
0060
0061
0062 ret = snd_soc_dai_set_sysclk(codec_dai, 1,
0063 params_rate(params) * 512,
0064 SND_SOC_CLOCK_IN);
0065 if (ret)
0066 return ret;
0067 }
0068 return 0;
0069 }
0070
0071 static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = {
0072 .hw_params = mt8173_rt5650_rt5676_hw_params,
0073 };
0074
0075 static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
0076
0077 static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
0078 {
0079 struct snd_soc_card *card = runtime->card;
0080 struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
0081 struct snd_soc_component *component_sub = asoc_rtd_to_codec(runtime, 1)->component;
0082 int ret;
0083
0084 rt5645_sel_asrc_clk_src(component,
0085 RT5645_DA_STEREO_FILTER |
0086 RT5645_AD_STEREO_FILTER,
0087 RT5645_CLK_SEL_I2S1_ASRC);
0088 rt5677_sel_asrc_clk_src(component_sub,
0089 RT5677_DA_STEREO_FILTER |
0090 RT5677_AD_STEREO1_FILTER,
0091 RT5677_CLK_SEL_I2S1_ASRC);
0092 rt5677_sel_asrc_clk_src(component_sub,
0093 RT5677_AD_STEREO2_FILTER |
0094 RT5677_I2S2_SOURCE,
0095 RT5677_CLK_SEL_I2S2_ASRC);
0096
0097
0098 ret = snd_soc_card_jack_new(card, "Headset Jack",
0099 SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
0100 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
0101 SND_JACK_BTN_2 | SND_JACK_BTN_3,
0102 &mt8173_rt5650_rt5676_jack);
0103 if (ret) {
0104 dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
0105 return ret;
0106 }
0107
0108 return rt5645_set_jack_detect(component,
0109 &mt8173_rt5650_rt5676_jack,
0110 &mt8173_rt5650_rt5676_jack,
0111 &mt8173_rt5650_rt5676_jack);
0112 }
0113
0114
0115 enum {
0116 DAI_LINK_PLAYBACK,
0117 DAI_LINK_CAPTURE,
0118 DAI_LINK_HDMI,
0119 DAI_LINK_CODEC_I2S,
0120 DAI_LINK_HDMI_I2S,
0121 DAI_LINK_INTERCODEC
0122 };
0123
0124 SND_SOC_DAILINK_DEFS(playback,
0125 DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
0126 DAILINK_COMP_ARRAY(COMP_DUMMY()),
0127 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0128
0129 SND_SOC_DAILINK_DEFS(capture,
0130 DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
0131 DAILINK_COMP_ARRAY(COMP_DUMMY()),
0132 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0133
0134 SND_SOC_DAILINK_DEFS(hdmi_pcm,
0135 DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
0136 DAILINK_COMP_ARRAY(COMP_DUMMY()),
0137 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0138
0139 SND_SOC_DAILINK_DEFS(codec,
0140 DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
0141 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),
0142 COMP_CODEC(NULL, "rt5677-aif1")),
0143 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0144
0145 SND_SOC_DAILINK_DEFS(hdmi_be,
0146 DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),
0147 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
0148 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0149
0150 SND_SOC_DAILINK_DEFS(intercodec,
0151 DAILINK_COMP_ARRAY(COMP_DUMMY()),
0152 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif2")),
0153 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0154
0155
0156 static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
0157
0158 [DAI_LINK_PLAYBACK] = {
0159 .name = "rt5650_rt5676 Playback",
0160 .stream_name = "rt5650_rt5676 Playback",
0161 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
0162 .dynamic = 1,
0163 .dpcm_playback = 1,
0164 SND_SOC_DAILINK_REG(playback),
0165 },
0166 [DAI_LINK_CAPTURE] = {
0167 .name = "rt5650_rt5676 Capture",
0168 .stream_name = "rt5650_rt5676 Capture",
0169 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
0170 .dynamic = 1,
0171 .dpcm_capture = 1,
0172 SND_SOC_DAILINK_REG(capture),
0173 },
0174 [DAI_LINK_HDMI] = {
0175 .name = "HDMI",
0176 .stream_name = "HDMI PCM",
0177 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
0178 .dynamic = 1,
0179 .dpcm_playback = 1,
0180 SND_SOC_DAILINK_REG(hdmi_pcm),
0181 },
0182
0183
0184 [DAI_LINK_CODEC_I2S] = {
0185 .name = "Codec",
0186 .no_pcm = 1,
0187 .init = mt8173_rt5650_rt5676_init,
0188 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0189 SND_SOC_DAIFMT_CBS_CFS,
0190 .ops = &mt8173_rt5650_rt5676_ops,
0191 .ignore_pmdown_time = 1,
0192 .dpcm_playback = 1,
0193 .dpcm_capture = 1,
0194 SND_SOC_DAILINK_REG(codec),
0195 },
0196 [DAI_LINK_HDMI_I2S] = {
0197 .name = "HDMI BE",
0198 .no_pcm = 1,
0199 .dpcm_playback = 1,
0200 SND_SOC_DAILINK_REG(hdmi_be),
0201 },
0202
0203 [DAI_LINK_INTERCODEC] = {
0204 .name = "rt5650_rt5676 intercodec",
0205 .stream_name = "rt5650_rt5676 intercodec",
0206 .no_pcm = 1,
0207 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0208 SND_SOC_DAIFMT_CBM_CFM,
0209 SND_SOC_DAILINK_REG(intercodec),
0210 },
0211 };
0212
0213 static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {
0214 {
0215 .name_prefix = "Sub",
0216 },
0217 };
0218
0219 static struct snd_soc_card mt8173_rt5650_rt5676_card = {
0220 .name = "mtk-rt5650-rt5676",
0221 .owner = THIS_MODULE,
0222 .dai_link = mt8173_rt5650_rt5676_dais,
0223 .num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),
0224 .codec_conf = mt8173_rt5650_rt5676_codec_conf,
0225 .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),
0226 .controls = mt8173_rt5650_rt5676_controls,
0227 .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),
0228 .dapm_widgets = mt8173_rt5650_rt5676_widgets,
0229 .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),
0230 .dapm_routes = mt8173_rt5650_rt5676_routes,
0231 .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),
0232 };
0233
0234 static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
0235 {
0236 struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
0237 struct device_node *platform_node;
0238 struct snd_soc_dai_link *dai_link;
0239 int i, ret;
0240
0241 platform_node = of_parse_phandle(pdev->dev.of_node,
0242 "mediatek,platform", 0);
0243 if (!platform_node) {
0244 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
0245 return -EINVAL;
0246 }
0247
0248 for_each_card_prelinks(card, i, dai_link) {
0249 if (dai_link->platforms->name)
0250 continue;
0251 dai_link->platforms->of_node = platform_node;
0252 }
0253
0254 mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =
0255 of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
0256 if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
0257 dev_err(&pdev->dev,
0258 "Property 'audio-codec' missing or invalid\n");
0259 ret = -EINVAL;
0260 goto put_node;
0261 }
0262 mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
0263 of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
0264 if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
0265 dev_err(&pdev->dev,
0266 "Property 'audio-codec' missing or invalid\n");
0267 ret = -EINVAL;
0268 goto put_node;
0269 }
0270 mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
0271 mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
0272
0273 mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =
0274 mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
0275
0276 mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node =
0277 of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);
0278 if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
0279 dev_err(&pdev->dev,
0280 "Property 'audio-codec' missing or invalid\n");
0281 ret = -EINVAL;
0282 goto put_node;
0283 }
0284
0285 card->dev = &pdev->dev;
0286
0287 ret = devm_snd_soc_register_card(&pdev->dev, card);
0288
0289 put_node:
0290 of_node_put(platform_node);
0291 return ret;
0292 }
0293
0294 static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
0295 { .compatible = "mediatek,mt8173-rt5650-rt5676", },
0296 { }
0297 };
0298 MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);
0299
0300 static struct platform_driver mt8173_rt5650_rt5676_driver = {
0301 .driver = {
0302 .name = "mtk-rt5650-rt5676",
0303 .of_match_table = mt8173_rt5650_rt5676_dt_match,
0304 .pm = &snd_soc_pm_ops,
0305 },
0306 .probe = mt8173_rt5650_rt5676_dev_probe,
0307 };
0308
0309 module_platform_driver(mt8173_rt5650_rt5676_driver);
0310
0311
0312 MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");
0313 MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
0314 MODULE_LICENSE("GPL v2");
0315 MODULE_ALIAS("platform:mtk-rt5650-rt5676");
0316