brintos

brintos / linux-shallow public Read only

0
0
Text · 9.4 KiB · 763067c Raw
328 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * mt8173-rt5650-rt5676.c  --  MT8173 machine driver with RT5650/5676 codecs4 *5 * Copyright (c) 2015 MediaTek Inc.6 * Author: Koro Chen <koro.chen@mediatek.com>7 */8 9#include <linux/module.h>10#include <sound/soc.h>11#include <sound/jack.h>12#include "../../codecs/rt5645.h"13#include "../../codecs/rt5677.h"14 15#define MCLK_FOR_CODECS		1228800016 17static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {18	SND_SOC_DAPM_SPK("Speaker", NULL),19	SND_SOC_DAPM_MIC("Int Mic", NULL),20	SND_SOC_DAPM_HP("Headphone", NULL),21	SND_SOC_DAPM_MIC("Headset Mic", NULL),22};23 24static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {25	{"Speaker", NULL, "SPOL"},26	{"Speaker", NULL, "SPOR"},27	{"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650  */28	{"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */29	{"Sub DMIC R1", NULL, "Int Mic"},30	{"Headphone", NULL, "HPOL"},31	{"Headphone", NULL, "HPOR"},32	{"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650  */33	{"IN1P", NULL, "Headset Mic"},34	{"IN1N", NULL, "Headset Mic"},35	{"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650  */36};37 38static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {39	SOC_DAPM_PIN_SWITCH("Speaker"),40	SOC_DAPM_PIN_SWITCH("Int Mic"),41	SOC_DAPM_PIN_SWITCH("Headphone"),42	SOC_DAPM_PIN_SWITCH("Headset Mic"),43};44 45static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {46	{47		.pin	= "Headphone",48		.mask	= SND_JACK_HEADPHONE,49	},50	{51		.pin	= "Headset Mic",52		.mask	= SND_JACK_MICROPHONE,53	},54};55 56static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,57					  struct snd_pcm_hw_params *params)58{59	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);60	struct snd_soc_dai *codec_dai;61	int i, ret;62 63	for_each_rtd_codec_dais(rtd, i, codec_dai) {64		/* pll from mclk 12.288M */65		ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,66					  params_rate(params) * 512);67		if (ret)68			return ret;69 70		/* sysclk from pll */71		ret = snd_soc_dai_set_sysclk(codec_dai, 1,72					     params_rate(params) * 512,73					     SND_SOC_CLOCK_IN);74		if (ret)75			return ret;76	}77	return 0;78}79 80static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = {81	.hw_params = mt8173_rt5650_rt5676_hw_params,82};83 84static struct snd_soc_jack mt8173_rt5650_rt5676_jack;85 86static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)87{88	struct snd_soc_card *card = runtime->card;89	struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;90	struct snd_soc_component *component_sub = snd_soc_rtd_to_codec(runtime, 1)->component;91	int ret;92 93	rt5645_sel_asrc_clk_src(component,94				RT5645_DA_STEREO_FILTER |95				RT5645_AD_STEREO_FILTER,96				RT5645_CLK_SEL_I2S1_ASRC);97	rt5677_sel_asrc_clk_src(component_sub,98				RT5677_DA_STEREO_FILTER |99				RT5677_AD_STEREO1_FILTER,100				RT5677_CLK_SEL_I2S1_ASRC);101	rt5677_sel_asrc_clk_src(component_sub,102				RT5677_AD_STEREO2_FILTER |103				RT5677_I2S2_SOURCE,104				RT5677_CLK_SEL_I2S2_ASRC);105 106	/* enable jack detection */107	ret = snd_soc_card_jack_new_pins(card, "Headset Jack",108					 SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |109					 SND_JACK_BTN_0 | SND_JACK_BTN_1 |110					 SND_JACK_BTN_2 | SND_JACK_BTN_3,111					 &mt8173_rt5650_rt5676_jack,112					 mt8173_rt5650_rt5676_jack_pins,113					 ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));114	if (ret) {115		dev_err(card->dev, "Can't new Headset Jack %d\n", ret);116		return ret;117	}118 119	return rt5645_set_jack_detect(component,120				      &mt8173_rt5650_rt5676_jack,121				      &mt8173_rt5650_rt5676_jack,122				      &mt8173_rt5650_rt5676_jack);123}124 125 126enum {127	DAI_LINK_PLAYBACK,128	DAI_LINK_CAPTURE,129	DAI_LINK_HDMI,130	DAI_LINK_CODEC_I2S,131	DAI_LINK_HDMI_I2S,132	DAI_LINK_INTERCODEC133};134 135SND_SOC_DAILINK_DEFS(playback,136	DAILINK_COMP_ARRAY(COMP_CPU("DL1")),137	DAILINK_COMP_ARRAY(COMP_DUMMY()),138	DAILINK_COMP_ARRAY(COMP_EMPTY()));139 140SND_SOC_DAILINK_DEFS(capture,141	DAILINK_COMP_ARRAY(COMP_CPU("VUL")),142	DAILINK_COMP_ARRAY(COMP_DUMMY()),143	DAILINK_COMP_ARRAY(COMP_EMPTY()));144 145SND_SOC_DAILINK_DEFS(hdmi_pcm,146	DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),147	DAILINK_COMP_ARRAY(COMP_DUMMY()),148	DAILINK_COMP_ARRAY(COMP_EMPTY()));149 150SND_SOC_DAILINK_DEFS(codec,151	DAILINK_COMP_ARRAY(COMP_CPU("I2S")),152	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),153			   COMP_CODEC(NULL, "rt5677-aif1")),154	DAILINK_COMP_ARRAY(COMP_EMPTY()));155 156SND_SOC_DAILINK_DEFS(hdmi_be,157	DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),158	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),159	DAILINK_COMP_ARRAY(COMP_EMPTY()));160 161SND_SOC_DAILINK_DEFS(intercodec,162	DAILINK_COMP_ARRAY(COMP_DUMMY()),163	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif2")),164	DAILINK_COMP_ARRAY(COMP_DUMMY()));165 166/* Digital audio interface glue - connects codec <---> CPU */167static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {168	/* Front End DAI links */169	[DAI_LINK_PLAYBACK] = {170		.name = "rt5650_rt5676 Playback",171		.stream_name = "rt5650_rt5676 Playback",172		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},173		.dynamic = 1,174		.dpcm_playback = 1,175		SND_SOC_DAILINK_REG(playback),176	},177	[DAI_LINK_CAPTURE] = {178		.name = "rt5650_rt5676 Capture",179		.stream_name = "rt5650_rt5676 Capture",180		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},181		.dynamic = 1,182		.dpcm_capture = 1,183		SND_SOC_DAILINK_REG(capture),184	},185	[DAI_LINK_HDMI] = {186		.name = "HDMI",187		.stream_name = "HDMI PCM",188		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},189		.dynamic = 1,190		.dpcm_playback = 1,191		SND_SOC_DAILINK_REG(hdmi_pcm),192	},193 194	/* Back End DAI links */195	[DAI_LINK_CODEC_I2S] = {196		.name = "Codec",197		.no_pcm = 1,198		.init = mt8173_rt5650_rt5676_init,199		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |200			   SND_SOC_DAIFMT_CBS_CFS,201		.ops = &mt8173_rt5650_rt5676_ops,202		.ignore_pmdown_time = 1,203		.dpcm_playback = 1,204		.dpcm_capture = 1,205		SND_SOC_DAILINK_REG(codec),206	},207	[DAI_LINK_HDMI_I2S] = {208		.name = "HDMI BE",209		.no_pcm = 1,210		.dpcm_playback = 1,211		SND_SOC_DAILINK_REG(hdmi_be),212	},213	/* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */214	[DAI_LINK_INTERCODEC] = {215		.name = "rt5650_rt5676 intercodec",216		.stream_name = "rt5650_rt5676 intercodec",217		.no_pcm = 1,218		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |219			   SND_SOC_DAIFMT_CBM_CFM,220		SND_SOC_DAILINK_REG(intercodec),221	},222};223 224static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {225	{226		.name_prefix = "Sub",227	},228};229 230static struct snd_soc_card mt8173_rt5650_rt5676_card = {231	.name = "mtk-rt5650-rt5676",232	.owner = THIS_MODULE,233	.dai_link = mt8173_rt5650_rt5676_dais,234	.num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),235	.codec_conf = mt8173_rt5650_rt5676_codec_conf,236	.num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),237	.controls = mt8173_rt5650_rt5676_controls,238	.num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),239	.dapm_widgets = mt8173_rt5650_rt5676_widgets,240	.num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),241	.dapm_routes = mt8173_rt5650_rt5676_routes,242	.num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),243};244 245static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)246{247	struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;248	struct device_node *platform_node;249	struct snd_soc_dai_link *dai_link;250	int i, ret;251 252	platform_node = of_parse_phandle(pdev->dev.of_node,253					 "mediatek,platform", 0);254	if (!platform_node) {255		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");256		return -EINVAL;257	}258 259	for_each_card_prelinks(card, i, dai_link) {260		if (dai_link->platforms->name)261			continue;262		dai_link->platforms->of_node = platform_node;263	}264 265	mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =266		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);267	if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {268		dev_err(&pdev->dev,269			"Property 'audio-codec' missing or invalid\n");270		ret = -EINVAL;271		goto put_node;272	}273	mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =274		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);275	if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {276		dev_err(&pdev->dev,277			"Property 'audio-codec' missing or invalid\n");278		ret = -EINVAL;279		goto put_node;280	}281	mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =282		mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;283 284	mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =285		mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;286 287	mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node =288		of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);289	if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {290		dev_err(&pdev->dev,291			"Property 'audio-codec' missing or invalid\n");292		ret = -EINVAL;293		goto put_node;294	}295 296	card->dev = &pdev->dev;297 298	ret = devm_snd_soc_register_card(&pdev->dev, card);299 300put_node:301	of_node_put(platform_node);302	return ret;303}304 305static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {306	{ .compatible = "mediatek,mt8173-rt5650-rt5676", },307	{ }308};309MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);310 311static struct platform_driver mt8173_rt5650_rt5676_driver = {312	.driver = {313		   .name = "mtk-rt5650-rt5676",314		   .of_match_table = mt8173_rt5650_rt5676_dt_match,315		   .pm = &snd_soc_pm_ops,316	},317	.probe = mt8173_rt5650_rt5676_dev_probe,318};319 320module_platform_driver(mt8173_rt5650_rt5676_driver);321 322/* Module information */323MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");324MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");325MODULE_LICENSE("GPL v2");326MODULE_ALIAS("platform:mtk-rt5650-rt5676");327 328