211 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * mt8173-max98090.c -- MT8173 MAX98090 ALSA SoC machine driver4 *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/max98090.h"13 14static struct snd_soc_jack mt8173_max98090_jack;15 16static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = {17 {18 .pin = "Headphone",19 .mask = SND_JACK_HEADPHONE,20 },21 {22 .pin = "Headset Mic",23 .mask = SND_JACK_MICROPHONE,24 },25};26 27static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = {28 SND_SOC_DAPM_SPK("Speaker", NULL),29 SND_SOC_DAPM_MIC("Int Mic", NULL),30 SND_SOC_DAPM_HP("Headphone", NULL),31 SND_SOC_DAPM_MIC("Headset Mic", NULL),32};33 34static const struct snd_soc_dapm_route mt8173_max98090_routes[] = {35 {"Speaker", NULL, "SPKL"},36 {"Speaker", NULL, "SPKR"},37 {"DMICL", NULL, "Int Mic"},38 {"Headphone", NULL, "HPL"},39 {"Headphone", NULL, "HPR"},40 {"Headset Mic", NULL, "MICBIAS"},41 {"IN34", NULL, "Headset Mic"},42};43 44static const struct snd_kcontrol_new mt8173_max98090_controls[] = {45 SOC_DAPM_PIN_SWITCH("Speaker"),46 SOC_DAPM_PIN_SWITCH("Int Mic"),47 SOC_DAPM_PIN_SWITCH("Headphone"),48 SOC_DAPM_PIN_SWITCH("Headset Mic"),49};50 51static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,52 struct snd_pcm_hw_params *params)53{54 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);55 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);56 57 return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,58 SND_SOC_CLOCK_IN);59}60 61static const struct snd_soc_ops mt8173_max98090_ops = {62 .hw_params = mt8173_max98090_hw_params,63};64 65static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)66{67 int ret;68 struct snd_soc_card *card = runtime->card;69 struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;70 71 /* enable jack detection */72 ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET,73 &mt8173_max98090_jack,74 mt8173_max98090_jack_pins,75 ARRAY_SIZE(mt8173_max98090_jack_pins));76 if (ret) {77 dev_err(card->dev, "Can't create a new Jack %d\n", ret);78 return ret;79 }80 81 return max98090_mic_detect(component, &mt8173_max98090_jack);82}83 84SND_SOC_DAILINK_DEFS(playback,85 DAILINK_COMP_ARRAY(COMP_CPU("DL1")),86 DAILINK_COMP_ARRAY(COMP_DUMMY()),87 DAILINK_COMP_ARRAY(COMP_EMPTY()));88 89SND_SOC_DAILINK_DEFS(capture,90 DAILINK_COMP_ARRAY(COMP_CPU("VUL")),91 DAILINK_COMP_ARRAY(COMP_DUMMY()),92 DAILINK_COMP_ARRAY(COMP_EMPTY()));93 94SND_SOC_DAILINK_DEFS(hifi,95 DAILINK_COMP_ARRAY(COMP_CPU("I2S")),96 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),97 DAILINK_COMP_ARRAY(COMP_EMPTY()));98 99/* Digital audio interface glue - connects codec <---> CPU */100static struct snd_soc_dai_link mt8173_max98090_dais[] = {101 /* Front End DAI links */102 {103 .name = "MAX98090 Playback",104 .stream_name = "MAX98090 Playback",105 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},106 .dynamic = 1,107 .dpcm_playback = 1,108 SND_SOC_DAILINK_REG(playback),109 },110 {111 .name = "MAX98090 Capture",112 .stream_name = "MAX98090 Capture",113 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},114 .dynamic = 1,115 .dpcm_capture = 1,116 SND_SOC_DAILINK_REG(capture),117 },118 /* Back End DAI links */119 {120 .name = "Codec",121 .no_pcm = 1,122 .init = mt8173_max98090_init,123 .ops = &mt8173_max98090_ops,124 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |125 SND_SOC_DAIFMT_CBS_CFS,126 .dpcm_playback = 1,127 .dpcm_capture = 1,128 SND_SOC_DAILINK_REG(hifi),129 },130};131 132static struct snd_soc_card mt8173_max98090_card = {133 .name = "mt8173-max98090",134 .owner = THIS_MODULE,135 .dai_link = mt8173_max98090_dais,136 .num_links = ARRAY_SIZE(mt8173_max98090_dais),137 .controls = mt8173_max98090_controls,138 .num_controls = ARRAY_SIZE(mt8173_max98090_controls),139 .dapm_widgets = mt8173_max98090_widgets,140 .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets),141 .dapm_routes = mt8173_max98090_routes,142 .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes),143};144 145static int mt8173_max98090_dev_probe(struct platform_device *pdev)146{147 struct snd_soc_card *card = &mt8173_max98090_card;148 struct device_node *codec_node, *platform_node;149 struct snd_soc_dai_link *dai_link;150 int ret, i;151 152 platform_node = of_parse_phandle(pdev->dev.of_node,153 "mediatek,platform", 0);154 if (!platform_node) {155 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");156 return -EINVAL;157 }158 for_each_card_prelinks(card, i, dai_link) {159 if (dai_link->platforms->name)160 continue;161 dai_link->platforms->of_node = platform_node;162 }163 164 codec_node = of_parse_phandle(pdev->dev.of_node,165 "mediatek,audio-codec", 0);166 if (!codec_node) {167 dev_err(&pdev->dev,168 "Property 'audio-codec' missing or invalid\n");169 ret = -EINVAL;170 goto put_platform_node;171 }172 for_each_card_prelinks(card, i, dai_link) {173 if (dai_link->codecs->name)174 continue;175 dai_link->codecs->of_node = codec_node;176 }177 card->dev = &pdev->dev;178 179 ret = devm_snd_soc_register_card(&pdev->dev, card);180 181 of_node_put(codec_node);182 183put_platform_node:184 of_node_put(platform_node);185 return ret;186}187 188static const struct of_device_id mt8173_max98090_dt_match[] = {189 { .compatible = "mediatek,mt8173-max98090", },190 { }191};192MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);193 194static struct platform_driver mt8173_max98090_driver = {195 .driver = {196 .name = "mt8173-max98090",197 .of_match_table = mt8173_max98090_dt_match,198 .pm = &snd_soc_pm_ops,199 },200 .probe = mt8173_max98090_dev_probe,201};202 203module_platform_driver(mt8173_max98090_driver);204 205/* Module information */206MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver");207MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");208MODULE_LICENSE("GPL v2");209MODULE_ALIAS("platform:mt8173-max98090");210 211