^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Machine driver for AMD ACP Audio engine using Realtek RT5645 codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2017 Advanced Micro Devices, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is modified from rt288 machine driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Permission is hereby granted, free of charge, to any person obtaining a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * copy of this software and associated documentation files (the "Software"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * to deal in the Software without restriction, including without limitation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * the rights to use, copy, modify, merge, publish, distribute, sublicense,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * and/or sell copies of the Software, and to permit persons to whom the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Software is furnished to do so, subject to the following conditions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * The above copyright notice and this permission notice shall be included in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * all copies or substantial portions of the Software.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * OTHER DEALINGS IN THE SOFTWARE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <sound/soc-dapm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <sound/jack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include "../codecs/rt5645.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define CZ_PLAT_CLK 24000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static struct snd_soc_jack cz_jack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) CZ_PLAT_CLK, params_rate(params) * 512);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) params_rate(params) * 512, SND_SOC_CLOCK_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int cz_init(struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct snd_soc_component *codec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) codec = asoc_rtd_to_codec(rtd, 0)->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) card = rtd->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = snd_soc_card_jack_new(card, "Headset Jack",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) SND_JACK_BTN_0 | SND_JACK_BTN_1 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) SND_JACK_BTN_2 | SND_JACK_BTN_3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) &cz_jack, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) dev_err(card->dev, "HP jack creation failed %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) rt5645_set_jack_detect(codec, &cz_jack, &cz_jack, &cz_jack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static struct snd_soc_ops cz_aif1_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .hw_params = cz_aif1_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) SND_SOC_DAILINK_DEF(designware1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) SND_SOC_DAILINK_DEF(designware2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) SND_SOC_DAILINK_DEF(codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) SND_SOC_DAILINK_DEF(platform,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static struct snd_soc_dai_link cz_dai_rt5650[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .name = "amd-rt5645-play",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .stream_name = "RT5645_AIF1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) | SND_SOC_DAIFMT_CBM_CFM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .init = cz_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .ops = &cz_aif1_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) SND_SOC_DAILINK_REG(designware1, codec, platform),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .name = "amd-rt5645-cap",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .stream_name = "RT5645_AIF1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) | SND_SOC_DAIFMT_CBM_CFM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .ops = &cz_aif1_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) SND_SOC_DAILINK_REG(designware2, codec, platform),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static const struct snd_soc_dapm_widget cz_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) SND_SOC_DAPM_HP("Headphones", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) SND_SOC_DAPM_SPK("Speakers", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) SND_SOC_DAPM_MIC("Headset Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) SND_SOC_DAPM_MIC("Int Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static const struct snd_soc_dapm_route cz_audio_route[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {"Headphones", NULL, "HPOL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {"Headphones", NULL, "HPOR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {"RECMIXL", NULL, "Headset Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {"RECMIXR", NULL, "Headset Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {"Speakers", NULL, "SPOL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {"Speakers", NULL, "SPOR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {"DMIC L2", NULL, "Int Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {"DMIC R2", NULL, "Int Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static const struct snd_kcontrol_new cz_mc_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) SOC_DAPM_PIN_SWITCH("Headphones"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) SOC_DAPM_PIN_SWITCH("Speakers"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) SOC_DAPM_PIN_SWITCH("Headset Mic"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) SOC_DAPM_PIN_SWITCH("Int Mic"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static struct snd_soc_card cz_card = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .name = "acprt5650",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .dai_link = cz_dai_rt5650,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .num_links = ARRAY_SIZE(cz_dai_rt5650),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .dapm_widgets = cz_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .num_dapm_widgets = ARRAY_SIZE(cz_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .dapm_routes = cz_audio_route,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .num_dapm_routes = ARRAY_SIZE(cz_audio_route),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .controls = cz_mc_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .num_controls = ARRAY_SIZE(cz_mc_controls),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static int cz_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) card = &cz_card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) cz_card.dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) platform_set_drvdata(pdev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) "devm_snd_soc_register_card(%s) failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) cz_card.name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #ifdef CONFIG_ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static const struct acpi_device_id cz_audio_acpi_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) { "AMDI1002", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static struct platform_driver cz_pcm_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .name = "cz-rt5645",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .pm = &snd_soc_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .probe = cz_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) module_platform_driver(cz_pcm_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) MODULE_AUTHOR("akshu.agrawal@amd.com");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) MODULE_DESCRIPTION("cz-rt5645 audio support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) MODULE_LICENSE("GPL v2");