344 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * MediaTek MT8365 Sound Card driver4 *5 * Copyright (c) 2024 MediaTek Inc.6 * Authors: Nicolas Belin <nbelin@baylibre.com>7 */8 9#include <linux/module.h>10#include <linux/of_gpio.h>11#include <sound/soc.h>12#include <sound/pcm_params.h>13#include "mt8365-afe-common.h"14#include <linux/pinctrl/consumer.h>15#include "../common/mtk-soc-card.h"16#include "../common/mtk-soundcard-driver.h"17 18enum pinctrl_pin_state {19 PIN_STATE_DEFAULT,20 PIN_STATE_DMIC,21 PIN_STATE_MISO_OFF,22 PIN_STATE_MISO_ON,23 PIN_STATE_MOSI_OFF,24 PIN_STATE_MOSI_ON,25 PIN_STATE_MAX26};27 28static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = {29 "default",30 "dmic",31 "miso_off",32 "miso_on",33 "mosi_off",34 "mosi_on",35};36 37struct mt8365_mt6357_priv {38 struct pinctrl *pinctrl;39 struct pinctrl_state *pin_states[PIN_STATE_MAX];40};41 42enum {43 /* FE */44 DAI_LINK_DL1_PLAYBACK = 0,45 DAI_LINK_DL2_PLAYBACK,46 DAI_LINK_AWB_CAPTURE,47 DAI_LINK_VUL_CAPTURE,48 /* BE */49 DAI_LINK_2ND_I2S_INTF,50 DAI_LINK_DMIC,51 DAI_LINK_INT_ADDA,52 DAI_LINK_NUM53};54 55static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = {56 SND_SOC_DAPM_OUTPUT("HDMI Out"),57};58 59static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {60 {"HDMI Out", NULL, "2ND I2S Playback"},61 {"DMIC In", NULL, "MICBIAS0"},62};63 64static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)65{66 struct snd_soc_pcm_runtime *rtd = substream->private_data;67 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);68 int ret = 0;69 70 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {71 if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON]))72 return ret;73 74 ret = pinctrl_select_state(priv->pinctrl,75 priv->pin_states[PIN_STATE_MOSI_ON]);76 if (ret)77 dev_err(rtd->card->dev, "%s failed to select state %d\n",78 __func__, ret);79 }80 81 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {82 if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON]))83 return ret;84 85 ret = pinctrl_select_state(priv->pinctrl,86 priv->pin_states[PIN_STATE_MISO_ON]);87 if (ret)88 dev_err(rtd->card->dev, "%s failed to select state %d\n",89 __func__, ret);90 }91 92 return 0;93}94 95static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)96{97 struct snd_soc_pcm_runtime *rtd = substream->private_data;98 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);99 int ret = 0;100 101 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {102 if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF]))103 return;104 105 ret = pinctrl_select_state(priv->pinctrl,106 priv->pin_states[PIN_STATE_MOSI_OFF]);107 if (ret)108 dev_err(rtd->card->dev, "%s failed to select state %d\n",109 __func__, ret);110 }111 112 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {113 if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF]))114 return;115 116 ret = pinctrl_select_state(priv->pinctrl,117 priv->pin_states[PIN_STATE_MISO_OFF]);118 if (ret)119 dev_err(rtd->card->dev, "%s failed to select state %d\n",120 __func__, ret);121 }122}123 124static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = {125 .startup = mt8365_mt6357_int_adda_startup,126 .shutdown = mt8365_mt6357_int_adda_shutdown,127};128 129SND_SOC_DAILINK_DEFS(playback1,130 DAILINK_COMP_ARRAY(COMP_CPU("DL1")),131 DAILINK_COMP_ARRAY(COMP_DUMMY()),132 DAILINK_COMP_ARRAY(COMP_EMPTY()));133SND_SOC_DAILINK_DEFS(playback2,134 DAILINK_COMP_ARRAY(COMP_CPU("DL2")),135 DAILINK_COMP_ARRAY(COMP_DUMMY()),136 DAILINK_COMP_ARRAY(COMP_EMPTY()));137SND_SOC_DAILINK_DEFS(awb_capture,138 DAILINK_COMP_ARRAY(COMP_CPU("AWB")),139 DAILINK_COMP_ARRAY(COMP_DUMMY()),140 DAILINK_COMP_ARRAY(COMP_EMPTY()));141SND_SOC_DAILINK_DEFS(vul,142 DAILINK_COMP_ARRAY(COMP_CPU("VUL")),143 DAILINK_COMP_ARRAY(COMP_DUMMY()),144 DAILINK_COMP_ARRAY(COMP_EMPTY()));145 146SND_SOC_DAILINK_DEFS(i2s3,147 DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")),148 DAILINK_COMP_ARRAY(COMP_DUMMY()),149 DAILINK_COMP_ARRAY(COMP_EMPTY()));150SND_SOC_DAILINK_DEFS(dmic,151 DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),152 DAILINK_COMP_ARRAY(COMP_DUMMY()),153 DAILINK_COMP_ARRAY(COMP_EMPTY()));154SND_SOC_DAILINK_DEFS(primary_codec,155 DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")),156 DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")),157 DAILINK_COMP_ARRAY(COMP_EMPTY()));158 159/* Digital audio interface glue - connects codec <---> CPU */160static struct snd_soc_dai_link mt8365_mt6357_dais[] = {161 /* Front End DAI links */162 [DAI_LINK_DL1_PLAYBACK] = {163 .name = "DL1_FE",164 .stream_name = "MultiMedia1_PLayback",165 .id = DAI_LINK_DL1_PLAYBACK,166 .trigger = {167 SND_SOC_DPCM_TRIGGER_POST,168 SND_SOC_DPCM_TRIGGER_POST169 },170 .dynamic = 1,171 .dpcm_playback = 1,172 .dpcm_merged_rate = 1,173 SND_SOC_DAILINK_REG(playback1),174 },175 [DAI_LINK_DL2_PLAYBACK] = {176 .name = "DL2_FE",177 .stream_name = "MultiMedia2_PLayback",178 .id = DAI_LINK_DL2_PLAYBACK,179 .trigger = {180 SND_SOC_DPCM_TRIGGER_POST,181 SND_SOC_DPCM_TRIGGER_POST182 },183 .dynamic = 1,184 .dpcm_playback = 1,185 .dpcm_merged_rate = 1,186 SND_SOC_DAILINK_REG(playback2),187 },188 [DAI_LINK_AWB_CAPTURE] = {189 .name = "AWB_FE",190 .stream_name = "DL1_AWB_Record",191 .id = DAI_LINK_AWB_CAPTURE,192 .trigger = {193 SND_SOC_DPCM_TRIGGER_POST,194 SND_SOC_DPCM_TRIGGER_POST195 },196 .dynamic = 1,197 .dpcm_capture = 1,198 .dpcm_merged_rate = 1,199 SND_SOC_DAILINK_REG(awb_capture),200 },201 [DAI_LINK_VUL_CAPTURE] = {202 .name = "VUL_FE",203 .stream_name = "MultiMedia1_Capture",204 .id = DAI_LINK_VUL_CAPTURE,205 .trigger = {206 SND_SOC_DPCM_TRIGGER_POST,207 SND_SOC_DPCM_TRIGGER_POST208 },209 .dynamic = 1,210 .dpcm_capture = 1,211 .dpcm_merged_rate = 1,212 SND_SOC_DAILINK_REG(vul),213 },214 /* Back End DAI links */215 [DAI_LINK_2ND_I2S_INTF] = {216 .name = "I2S_OUT_BE",217 .no_pcm = 1,218 .id = DAI_LINK_2ND_I2S_INTF,219 .dai_fmt = SND_SOC_DAIFMT_I2S |220 SND_SOC_DAIFMT_NB_NF |221 SND_SOC_DAIFMT_CBS_CFS,222 .dpcm_playback = 1,223 .dpcm_capture = 1,224 SND_SOC_DAILINK_REG(i2s3),225 },226 [DAI_LINK_DMIC] = {227 .name = "DMIC_BE",228 .no_pcm = 1,229 .id = DAI_LINK_DMIC,230 .dpcm_capture = 1,231 SND_SOC_DAILINK_REG(dmic),232 },233 [DAI_LINK_INT_ADDA] = {234 .name = "MTK_Codec",235 .no_pcm = 1,236 .id = DAI_LINK_INT_ADDA,237 .dpcm_playback = 1,238 .dpcm_capture = 1,239 .ops = &mt8365_mt6357_int_adda_ops,240 SND_SOC_DAILINK_REG(primary_codec),241 },242};243 244static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)245{246 struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);247 int ret, i;248 249 priv->pinctrl = devm_pinctrl_get(card->dev);250 if (IS_ERR(priv->pinctrl)) {251 ret = PTR_ERR(priv->pinctrl);252 return dev_err_probe(card->dev, ret,253 "Failed to get pinctrl\n");254 }255 256 for (i = PIN_STATE_DEFAULT ; i < PIN_STATE_MAX ; i++) {257 priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,258 mt8365_mt6357_pin_str[i]);259 if (IS_ERR(priv->pin_states[i])) {260 dev_info(card->dev, "No pin state for %s\n",261 mt8365_mt6357_pin_str[i]);262 } else {263 ret = pinctrl_select_state(priv->pinctrl,264 priv->pin_states[i]);265 if (ret) {266 dev_err_probe(card->dev, ret,267 "Failed to select pin state %s\n",268 mt8365_mt6357_pin_str[i]);269 return ret;270 }271 }272 }273 return 0;274}275 276static struct snd_soc_card mt8365_mt6357_soc_card = {277 .name = "mt8365-evk",278 .owner = THIS_MODULE,279 .dai_link = mt8365_mt6357_dais,280 .num_links = ARRAY_SIZE(mt8365_mt6357_dais),281 .dapm_widgets = mt8365_mt6357_widgets,282 .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets),283 .dapm_routes = mt8365_mt6357_routes,284 .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes),285};286 287static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)288{289 struct mtk_platform_card_data *card_data = soc_card_data->card_data;290 struct snd_soc_card *card = card_data->card;291 struct device *dev = card->dev;292 struct mt8365_mt6357_priv *mach_priv;293 int ret;294 295 card->dev = dev;296 ret = parse_dai_link_info(card);297 if (ret)298 goto err;299 300 mach_priv = devm_kzalloc(dev, sizeof(*mach_priv),301 GFP_KERNEL);302 if (!mach_priv)303 return -ENOMEM;304 soc_card_data->mach_priv = mach_priv;305 snd_soc_card_set_drvdata(card, soc_card_data);306 mt8365_mt6357_gpio_probe(card);307 return 0;308 309err:310 clean_card_reference(card);311 return ret;312}313 314static const struct mtk_soundcard_pdata mt8365_mt6357_card = {315 .card_name = "mt8365-mt6357",316 .card_data = &(struct mtk_platform_card_data) {317 .card = &mt8365_mt6357_soc_card,318 },319 .soc_probe = mt8365_mt6357_dev_probe320};321 322static const struct of_device_id mt8365_mt6357_dt_match[] = {323 { .compatible = "mediatek,mt8365-mt6357", .data = &mt8365_mt6357_card },324 { /* sentinel */ }325};326MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match);327 328static struct platform_driver mt8365_mt6357_driver = {329 .driver = {330 .name = "mt8365_mt6357",331 .of_match_table = mt8365_mt6357_dt_match,332 .pm = &snd_soc_pm_ops,333 },334 .probe = mtk_soundcard_common_probe,335};336 337module_platform_driver(mt8365_mt6357_driver);338 339/* Module information */340MODULE_DESCRIPTION("MT8365 EVK SoC machine driver");341MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>");342MODULE_LICENSE("GPL");343MODULE_ALIAS("platform: mt8365_mt6357");344