688 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2020 Intel Corporation4 5#include <linux/device.h>6#include <linux/kernel.h>7#include <sound/pcm.h>8#include <sound/pcm_params.h>9#include <sound/soc.h>10#include <sound/soc-acpi.h>11#include <sound/soc-dai.h>12#include <sound/soc-dapm.h>13#include <sound/sof.h>14#include <uapi/sound/asound.h>15#include "../../codecs/rt1011.h"16#include "../../codecs/rt1015.h"17#include "../../codecs/rt1308.h"18#include "../common/soc-intel-quirks.h"19#include "sof_realtek_common.h"20 21/*22 * Common structures and functions23 */24static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = {25 SOC_DAPM_PIN_SWITCH("Left Spk"),26 SOC_DAPM_PIN_SWITCH("Right Spk"),27 28};29 30static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = {31 SND_SOC_DAPM_SPK("Left Spk", NULL),32 SND_SOC_DAPM_SPK("Right Spk", NULL),33};34 35static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = {36 SOC_DAPM_PIN_SWITCH("WL Ext Spk"),37 SOC_DAPM_PIN_SWITCH("WR Ext Spk"),38 SOC_DAPM_PIN_SWITCH("TL Ext Spk"),39 SOC_DAPM_PIN_SWITCH("TR Ext Spk"),40};41 42static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = {43 SND_SOC_DAPM_SPK("WL Ext Spk", NULL),44 SND_SOC_DAPM_SPK("WR Ext Spk", NULL),45 SND_SOC_DAPM_SPK("TL Ext Spk", NULL),46 SND_SOC_DAPM_SPK("TR Ext Spk", NULL),47};48 49/* helper function to get the number of specific codec */50static unsigned int get_num_codecs(const char *hid)51{52 struct acpi_device *adev;53 unsigned int dev_num = 0;54 55 for_each_acpi_dev_match(adev, hid, NULL, -1)56 dev_num++;57 58 return dev_num;59}60 61/*62 * Realtek ALC101163 */64static const struct snd_soc_dapm_route speaker_map_lr[] = {65 /* speaker */66 { "Left Spk", NULL, "Left SPO" },67 { "Right Spk", NULL, "Right SPO" },68};69 70static const struct snd_soc_dapm_route rt1011_4spk_routes[] = {71 {"WL Ext Spk", NULL, "WL SPO" },72 {"WR Ext Spk", NULL, "WR SPO" },73 {"TL Ext Spk", NULL, "TL SPO" },74 {"TR Ext Spk", NULL, "TR SPO" },75};76 77static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = {78 {79 .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),80 .name_prefix = "Left",81 },82 {83 .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),84 .name_prefix = "Right",85 },86};87 88static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = {89 {90 .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),91 .name_prefix = "WL",92 },93 {94 .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),95 .name_prefix = "WR",96 },97 {98 .dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME),99 .name_prefix = "TL",100 },101 {102 .dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME),103 .name_prefix = "TR",104 },105};106 107static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {108 {109 .name = RT1011_DEV0_NAME,110 .dai_name = RT1011_CODEC_DAI,111 },112 {113 .name = RT1011_DEV1_NAME,114 .dai_name = RT1011_CODEC_DAI,115 },116 {117 .name = RT1011_DEV2_NAME,118 .dai_name = RT1011_CODEC_DAI,119 },120 {121 .name = RT1011_DEV3_NAME,122 .dai_name = RT1011_CODEC_DAI,123 },124};125 126static const struct {127 unsigned int tx;128 unsigned int rx;129} rt1011_tdm_mask[] = {130 {.tx = 0x4, .rx = 0x1},131 {.tx = 0x8, .rx = 0x2},132 {.tx = 0x1, .rx = 0x1},133 {.tx = 0x2, .rx = 0x2},134};135 136static int rt1011_hw_params(struct snd_pcm_substream *substream,137 struct snd_pcm_hw_params *params)138{139 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);140 struct snd_soc_dai *codec_dai;141 int srate, i, ret = 0;142 143 srate = params_rate(params);144 145 for_each_rtd_codec_dais(rtd, i, codec_dai) {146 /* 100 Fs to drive 24 bit data */147 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,148 100 * srate, 256 * srate);149 if (ret < 0) {150 dev_err(codec_dai->dev, "fail to set pll, ret %d\n",151 ret);152 return ret;153 }154 155 ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,156 256 * srate, SND_SOC_CLOCK_IN);157 if (ret < 0) {158 dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",159 ret);160 return ret;161 }162 163 if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {164 dev_err(codec_dai->dev, "invalid codec index %d\n",165 i);166 return -ENODEV;167 }168 169 ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,170 rt1011_tdm_mask[i].rx, 4,171 params_width(params));172 if (ret < 0) {173 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",174 ret);175 return ret;176 }177 }178 179 return 0;180}181 182static const struct snd_soc_ops rt1011_ops = {183 .hw_params = rt1011_hw_params,184};185 186static int rt1011_init(struct snd_soc_pcm_runtime *rtd)187{188 struct snd_soc_card *card = rtd->card;189 unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);190 int ret;191 192 switch (num_codecs) {193 case 2:194 if (!soc_intel_is_cml()) {195 ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,196 ARRAY_SIZE(realtek_2spk_widgets));197 if (ret) {198 dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",199 ret);200 return ret;201 }202 203 ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,204 ARRAY_SIZE(realtek_2spk_kcontrols));205 if (ret) {206 dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n",207 ret);208 return ret;209 }210 211 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr,212 ARRAY_SIZE(speaker_map_lr));213 if (ret) {214 dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",215 ret);216 return ret;217 }218 219 break;220 }221 222 /*223 * register speaker widgets "WL Ext Spk" and "WR Ext Spk" to224 * keep backward compatible with cml devices225 */226 fallthrough;227 case 4:228 ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets,229 num_codecs);230 if (ret) {231 dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",232 ret);233 return ret;234 }235 236 ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols,237 num_codecs);238 if (ret) {239 dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n",240 ret);241 return ret;242 }243 244 ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes,245 num_codecs);246 if (ret) {247 dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",248 ret);249 return ret;250 }251 break;252 default:253 dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs);254 return -EINVAL;255 }256 257 return ret;258}259 260void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link)261{262 unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);263 264 link->codecs = rt1011_dai_link_components;265 266 switch (num_codecs) {267 case 2:268 case 4:269 link->num_codecs = num_codecs;270 break;271 default:272 dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);273 break;274 }275 276 link->init = rt1011_init;277 link->ops = &rt1011_ops;278}279EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);280 281void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card)282{283 unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);284 285 switch (num_codecs) {286 case 2:287 if (soc_intel_is_cml()) {288 /*289 * use name prefix 'WL' and 'WR' for speaker widgets to290 * keep backward compatible with cml devices291 */292 card->codec_conf = rt1011_4spk_codec_confs;293 } else {294 card->codec_conf = rt1011_2spk_codec_confs;295 }296 297 card->num_configs = num_codecs;298 break;299 case 4:300 card->codec_conf = rt1011_4spk_codec_confs;301 card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs);302 break;303 default:304 dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);305 break;306 }307 308}309EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);310 311/*312 * rt1015: i2c mode driver for ALC1015 and ALC1015Q313 * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB314 *315 * For stereo output, there are always two amplifiers on the board.316 * However, the ACPI implements only one device instance (UID=0) if they317 * are sharing the same enable pin. This is the case of rt1015p.318 */319static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {320 /* speaker */321 { "Left Spk", NULL, "Speaker" },322 { "Right Spk", NULL, "Speaker" },323};324 325static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {326 {327 .name = RT1015P_DEV0_NAME,328 .dai_name = RT1015P_CODEC_DAI,329 },330};331 332static int rt1015p_hw_params(struct snd_pcm_substream *substream,333 struct snd_pcm_hw_params *params)334{335 /* reserved for debugging purpose */336 337 return 0;338}339 340static const struct snd_soc_ops rt1015p_ops = {341 .hw_params = rt1015p_hw_params,342};343 344static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)345{346 struct snd_soc_card *card = rtd->card;347 int ret;348 349 ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,350 ARRAY_SIZE(realtek_2spk_widgets));351 if (ret) {352 dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret);353 return ret;354 }355 356 ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,357 ARRAY_SIZE(realtek_2spk_kcontrols));358 if (ret) {359 dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret);360 return ret;361 }362 363 ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes,364 ARRAY_SIZE(rt1015p_dapm_routes));365 if (ret)366 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);367 return ret;368}369 370void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)371{372 link->codecs = rt1015p_dai_link_components;373 link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components);374 link->init = rt1015p_init;375 link->ops = &rt1015p_ops;376}377EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);378 379void sof_rt1015p_codec_conf(struct snd_soc_card *card)380{381}382EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);383 384/*385 * RT1015 audio amplifier386 */387 388static const struct {389 unsigned int tx;390 unsigned int rx;391} rt1015_tdm_mask[] = {392 {.tx = 0x0, .rx = 0x1},393 {.tx = 0x0, .rx = 0x2},394};395 396static int rt1015_hw_params(struct snd_pcm_substream *substream,397 struct snd_pcm_hw_params *params)398{399 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);400 struct snd_soc_dai_link *dai_link = rtd->dai_link;401 struct snd_soc_dai *codec_dai;402 int i, clk_freq;403 int ret = 0;404 405 clk_freq = sof_dai_get_bclk(rtd);406 407 if (clk_freq <= 0) {408 dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq);409 return -EINVAL;410 }411 412 for_each_rtd_codec_dais(rtd, i, codec_dai) {413 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,414 clk_freq,415 params_rate(params) * 256);416 if (ret) {417 dev_err(codec_dai->dev, "fail to set pll, ret %d\n",418 ret);419 return ret;420 }421 422 ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,423 params_rate(params) * 256,424 SND_SOC_CLOCK_IN);425 if (ret) {426 dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",427 ret);428 return ret;429 }430 431 switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {432 case SND_SOC_DAIFMT_DSP_A:433 case SND_SOC_DAIFMT_DSP_B:434 /* 4-slot TDM */435 ret = snd_soc_dai_set_tdm_slot(codec_dai,436 rt1015_tdm_mask[i].tx,437 rt1015_tdm_mask[i].rx,438 4,439 params_width(params));440 if (ret < 0) {441 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",442 ret);443 return ret;444 }445 break;446 default:447 dev_dbg(codec_dai->dev, "codec is in I2S mode\n");448 break;449 }450 }451 452 return ret;453}454 455static const struct snd_soc_ops rt1015_ops = {456 .hw_params = rt1015_hw_params,457};458 459static struct snd_soc_codec_conf rt1015_amp_conf[] = {460 {461 .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),462 .name_prefix = "Left",463 },464 {465 .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),466 .name_prefix = "Right",467 },468};469 470static struct snd_soc_dai_link_component rt1015_components[] = {471 {472 .name = RT1015_DEV0_NAME,473 .dai_name = RT1015_CODEC_DAI,474 },475 {476 .name = RT1015_DEV1_NAME,477 .dai_name = RT1015_CODEC_DAI,478 },479};480 481static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd)482{483 struct snd_soc_card *card = rtd->card;484 unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID);485 int ret;486 487 switch (num_codecs) {488 case 2:489 ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,490 ARRAY_SIZE(realtek_2spk_widgets));491 if (ret) {492 dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n",493 ret);494 return ret;495 }496 497 ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,498 ARRAY_SIZE(realtek_2spk_kcontrols));499 if (ret) {500 dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n",501 ret);502 return ret;503 }504 505 ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr,506 ARRAY_SIZE(speaker_map_lr));507 if (ret) {508 dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n",509 ret);510 return ret;511 }512 break;513 default:514 dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs);515 return -EINVAL;516 }517 518 return ret;519}520 521void sof_rt1015_codec_conf(struct snd_soc_card *card)522{523 card->codec_conf = rt1015_amp_conf;524 card->num_configs = ARRAY_SIZE(rt1015_amp_conf);525}526EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);527 528void sof_rt1015_dai_link(struct snd_soc_dai_link *link)529{530 link->codecs = rt1015_components;531 link->num_codecs = ARRAY_SIZE(rt1015_components);532 link->init = speaker_codec_init_lr;533 link->ops = &rt1015_ops;534}535EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);536 537/*538 * RT1308 audio amplifier539 */540static const struct snd_kcontrol_new rt1308_kcontrols[] = {541 SOC_DAPM_PIN_SWITCH("Speakers"),542};543 544static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = {545 SND_SOC_DAPM_SPK("Speakers", NULL),546};547 548static const struct snd_soc_dapm_route rt1308_dapm_routes[] = {549 /* speaker */550 {"Speakers", NULL, "SPOL"},551 {"Speakers", NULL, "SPOR"},552};553 554static struct snd_soc_dai_link_component rt1308_components[] = {555 {556 .name = RT1308_DEV0_NAME,557 .dai_name = RT1308_CODEC_DAI,558 }559};560 561static int rt1308_init(struct snd_soc_pcm_runtime *rtd)562{563 struct snd_soc_card *card = rtd->card;564 int ret;565 566 ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets,567 ARRAY_SIZE(rt1308_dapm_widgets));568 if (ret) {569 dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);570 return ret;571 }572 573 ret = snd_soc_add_card_controls(card, rt1308_kcontrols,574 ARRAY_SIZE(rt1308_kcontrols));575 if (ret) {576 dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret);577 return ret;578 }579 580 ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes,581 ARRAY_SIZE(rt1308_dapm_routes));582 583 if (ret)584 dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret);585 586 return ret;587}588 589static int rt1308_hw_params(struct snd_pcm_substream *substream,590 struct snd_pcm_hw_params *params)591{592 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);593 struct snd_soc_card *card = rtd->card;594 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);595 int clk_id, clk_freq, pll_out;596 int ret;597 598 clk_id = RT1308_PLL_S_MCLK;599 /* get the tplg configured mclk. */600 clk_freq = sof_dai_get_mclk(rtd);601 602 pll_out = params_rate(params) * 512;603 604 /* Set rt1308 pll */605 ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);606 if (ret < 0) {607 dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret);608 return ret;609 }610 611 /* Set rt1308 sysclk */612 ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,613 SND_SOC_CLOCK_IN);614 if (ret < 0)615 dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret);616 617 return ret;618}619 620static const struct snd_soc_ops rt1308_ops = {621 .hw_params = rt1308_hw_params,622};623 624void sof_rt1308_dai_link(struct snd_soc_dai_link *link)625{626 link->codecs = rt1308_components;627 link->num_codecs = ARRAY_SIZE(rt1308_components);628 link->init = rt1308_init;629 link->ops = &rt1308_ops;630}631EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);632 633/*634 * 2-amp Configuration for RT1019635 */636 637static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {638 /* speaker */639 { "Left Spk", NULL, "Speaker" },640 { "Right Spk", NULL, "Speaker" },641};642 643static struct snd_soc_dai_link_component rt1019p_components[] = {644 {645 .name = RT1019P_DEV0_NAME,646 .dai_name = RT1019P_CODEC_DAI,647 },648};649 650static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)651{652 struct snd_soc_card *card = rtd->card;653 int ret;654 655 ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,656 ARRAY_SIZE(realtek_2spk_widgets));657 if (ret) {658 dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret);659 return ret;660 }661 662 ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,663 ARRAY_SIZE(realtek_2spk_kcontrols));664 if (ret) {665 dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret);666 return ret;667 }668 669 ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,670 ARRAY_SIZE(rt1019p_dapm_routes));671 if (ret) {672 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);673 return ret;674 }675 return ret;676}677 678void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)679{680 link->codecs = rt1019p_components;681 link->num_codecs = ARRAY_SIZE(rt1019p_components);682 link->init = rt1019p_init;683}684EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);685 686MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");687MODULE_LICENSE("GPL");688