Path: blob/master/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* mt8173-rt5650-rt5676.c -- MT8173 machine driver with RT5650/5676 codecs3*4* Copyright (c) 2015 MediaTek Inc.5* Author: Koro Chen <[email protected]>6*/78#include <linux/module.h>9#include <sound/soc.h>10#include <sound/jack.h>11#include "../../codecs/rt5645.h"12#include "../../codecs/rt5677.h"1314#define MCLK_FOR_CODECS 122880001516static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {17SND_SOC_DAPM_SPK("Speaker", NULL),18SND_SOC_DAPM_MIC("Int Mic", NULL),19SND_SOC_DAPM_HP("Headphone", NULL),20SND_SOC_DAPM_MIC("Headset Mic", NULL),21};2223static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {24{"Speaker", NULL, "SPOL"},25{"Speaker", NULL, "SPOR"},26{"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */27{"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */28{"Sub DMIC R1", NULL, "Int Mic"},29{"Headphone", NULL, "HPOL"},30{"Headphone", NULL, "HPOR"},31{"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */32{"IN1P", NULL, "Headset Mic"},33{"IN1N", NULL, "Headset Mic"},34{"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */35};3637static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {38SOC_DAPM_PIN_SWITCH("Speaker"),39SOC_DAPM_PIN_SWITCH("Int Mic"),40SOC_DAPM_PIN_SWITCH("Headphone"),41SOC_DAPM_PIN_SWITCH("Headset Mic"),42};4344static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {45{46.pin = "Headphone",47.mask = SND_JACK_HEADPHONE,48},49{50.pin = "Headset Mic",51.mask = SND_JACK_MICROPHONE,52},53};5455static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,56struct snd_pcm_hw_params *params)57{58struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);59struct snd_soc_dai *codec_dai;60int i, ret;6162for_each_rtd_codec_dais(rtd, i, codec_dai) {63/* pll from mclk 12.288M */64ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,65params_rate(params) * 512);66if (ret)67return ret;6869/* sysclk from pll */70ret = snd_soc_dai_set_sysclk(codec_dai, 1,71params_rate(params) * 512,72SND_SOC_CLOCK_IN);73if (ret)74return ret;75}76return 0;77}7879static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = {80.hw_params = mt8173_rt5650_rt5676_hw_params,81};8283static struct snd_soc_jack mt8173_rt5650_rt5676_jack;8485static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)86{87struct snd_soc_card *card = runtime->card;88struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;89struct snd_soc_component *component_sub = snd_soc_rtd_to_codec(runtime, 1)->component;90int ret;9192rt5645_sel_asrc_clk_src(component,93RT5645_DA_STEREO_FILTER |94RT5645_AD_STEREO_FILTER,95RT5645_CLK_SEL_I2S1_ASRC);96rt5677_sel_asrc_clk_src(component_sub,97RT5677_DA_STEREO_FILTER |98RT5677_AD_STEREO1_FILTER,99RT5677_CLK_SEL_I2S1_ASRC);100rt5677_sel_asrc_clk_src(component_sub,101RT5677_AD_STEREO2_FILTER |102RT5677_I2S2_SOURCE,103RT5677_CLK_SEL_I2S2_ASRC);104105/* enable jack detection */106ret = snd_soc_card_jack_new_pins(card, "Headset Jack",107SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |108SND_JACK_BTN_0 | SND_JACK_BTN_1 |109SND_JACK_BTN_2 | SND_JACK_BTN_3,110&mt8173_rt5650_rt5676_jack,111mt8173_rt5650_rt5676_jack_pins,112ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));113if (ret) {114dev_err(card->dev, "Can't new Headset Jack %d\n", ret);115return ret;116}117118return rt5645_set_jack_detect(component,119&mt8173_rt5650_rt5676_jack,120&mt8173_rt5650_rt5676_jack,121&mt8173_rt5650_rt5676_jack);122}123124125enum {126DAI_LINK_PLAYBACK,127DAI_LINK_CAPTURE,128DAI_LINK_HDMI,129DAI_LINK_CODEC_I2S,130DAI_LINK_HDMI_I2S,131DAI_LINK_INTERCODEC132};133134SND_SOC_DAILINK_DEFS(playback,135DAILINK_COMP_ARRAY(COMP_CPU("DL1")),136DAILINK_COMP_ARRAY(COMP_DUMMY()),137DAILINK_COMP_ARRAY(COMP_EMPTY()));138139SND_SOC_DAILINK_DEFS(capture,140DAILINK_COMP_ARRAY(COMP_CPU("VUL")),141DAILINK_COMP_ARRAY(COMP_DUMMY()),142DAILINK_COMP_ARRAY(COMP_EMPTY()));143144SND_SOC_DAILINK_DEFS(hdmi_pcm,145DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),146DAILINK_COMP_ARRAY(COMP_DUMMY()),147DAILINK_COMP_ARRAY(COMP_EMPTY()));148149SND_SOC_DAILINK_DEFS(codec,150DAILINK_COMP_ARRAY(COMP_CPU("I2S")),151DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),152COMP_CODEC(NULL, "rt5677-aif1")),153DAILINK_COMP_ARRAY(COMP_EMPTY()));154155SND_SOC_DAILINK_DEFS(hdmi_be,156DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),157DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),158DAILINK_COMP_ARRAY(COMP_EMPTY()));159160SND_SOC_DAILINK_DEFS(intercodec,161DAILINK_COMP_ARRAY(COMP_DUMMY()),162DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif2")),163DAILINK_COMP_ARRAY(COMP_DUMMY()));164165/* Digital audio interface glue - connects codec <---> CPU */166static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {167/* Front End DAI links */168[DAI_LINK_PLAYBACK] = {169.name = "rt5650_rt5676 Playback",170.stream_name = "rt5650_rt5676 Playback",171.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},172.dynamic = 1,173.playback_only = 1,174SND_SOC_DAILINK_REG(playback),175},176[DAI_LINK_CAPTURE] = {177.name = "rt5650_rt5676 Capture",178.stream_name = "rt5650_rt5676 Capture",179.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},180.dynamic = 1,181.capture_only = 1,182SND_SOC_DAILINK_REG(capture),183},184[DAI_LINK_HDMI] = {185.name = "HDMI",186.stream_name = "HDMI PCM",187.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},188.dynamic = 1,189.playback_only = 1,190SND_SOC_DAILINK_REG(hdmi_pcm),191},192193/* Back End DAI links */194[DAI_LINK_CODEC_I2S] = {195.name = "Codec",196.no_pcm = 1,197.init = mt8173_rt5650_rt5676_init,198.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |199SND_SOC_DAIFMT_CBC_CFC,200.ops = &mt8173_rt5650_rt5676_ops,201.ignore_pmdown_time = 1,202SND_SOC_DAILINK_REG(codec),203},204[DAI_LINK_HDMI_I2S] = {205.name = "HDMI BE",206.no_pcm = 1,207.playback_only = 1,208SND_SOC_DAILINK_REG(hdmi_be),209},210/* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */211[DAI_LINK_INTERCODEC] = {212.name = "rt5650_rt5676 intercodec",213.stream_name = "rt5650_rt5676 intercodec",214.no_pcm = 1,215.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |216SND_SOC_DAIFMT_CBP_CFP,217SND_SOC_DAILINK_REG(intercodec),218},219};220221static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {222{223.name_prefix = "Sub",224},225};226227static struct snd_soc_card mt8173_rt5650_rt5676_card = {228.name = "mtk-rt5650-rt5676",229.owner = THIS_MODULE,230.dai_link = mt8173_rt5650_rt5676_dais,231.num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),232.codec_conf = mt8173_rt5650_rt5676_codec_conf,233.num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),234.controls = mt8173_rt5650_rt5676_controls,235.num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),236.dapm_widgets = mt8173_rt5650_rt5676_widgets,237.num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),238.dapm_routes = mt8173_rt5650_rt5676_routes,239.num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),240};241242static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)243{244struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;245struct device_node *platform_node;246struct snd_soc_dai_link *dai_link;247int i, ret;248249platform_node = of_parse_phandle(pdev->dev.of_node,250"mediatek,platform", 0);251if (!platform_node) {252dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");253return -EINVAL;254}255256for_each_card_prelinks(card, i, dai_link) {257if (dai_link->platforms->name)258continue;259dai_link->platforms->of_node = platform_node;260}261262mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =263of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);264if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {265dev_err(&pdev->dev,266"Property 'audio-codec' missing or invalid\n");267ret = -EINVAL;268goto put_node;269}270mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =271of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);272if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {273dev_err(&pdev->dev,274"Property 'audio-codec' missing or invalid\n");275ret = -EINVAL;276goto put_node;277}278mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =279mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;280281mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =282mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;283284mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node =285of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);286if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {287dev_err(&pdev->dev,288"Property 'audio-codec' missing or invalid\n");289ret = -EINVAL;290goto put_node;291}292293card->dev = &pdev->dev;294295ret = devm_snd_soc_register_card(&pdev->dev, card);296297put_node:298of_node_put(platform_node);299return ret;300}301302static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {303{ .compatible = "mediatek,mt8173-rt5650-rt5676", },304{ }305};306MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);307308static struct platform_driver mt8173_rt5650_rt5676_driver = {309.driver = {310.name = "mtk-rt5650-rt5676",311.of_match_table = mt8173_rt5650_rt5676_dt_match,312.pm = &snd_soc_pm_ops,313},314.probe = mt8173_rt5650_rt5676_dev_probe,315};316317module_platform_driver(mt8173_rt5650_rt5676_driver);318319/* Module information */320MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");321MODULE_AUTHOR("Koro Chen <[email protected]>");322MODULE_LICENSE("GPL v2");323MODULE_ALIAS("platform:mtk-rt5650-rt5676");324325326327