sof_realtek_common.c (12457B)
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2020 Intel Corporation. All rights reserved. 4 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 "sof_realtek_common.h" 19 20/* 21 * Current only 2-amp configuration is supported for rt1011 22 */ 23static const struct snd_soc_dapm_route speaker_map_lr[] = { 24 /* speaker */ 25 { "Left Spk", NULL, "Left SPO" }, 26 { "Right Spk", NULL, "Right SPO" }, 27}; 28 29/* 30 * Make sure device's Unique ID follows this configuration: 31 * 32 * Two speakers: 33 * 0: left, 1: right 34 * Four speakers: 35 * 0: Woofer left, 1: Woofer right 36 * 2: Tweeter left, 3: Tweeter right 37 */ 38static struct snd_soc_codec_conf rt1011_codec_confs[] = { 39 { 40 .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), 41 .name_prefix = "Left", 42 }, 43 { 44 .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), 45 .name_prefix = "Right", 46 }, 47}; 48 49static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { 50 { 51 .name = RT1011_DEV0_NAME, 52 .dai_name = RT1011_CODEC_DAI, 53 }, 54 { 55 .name = RT1011_DEV1_NAME, 56 .dai_name = RT1011_CODEC_DAI, 57 }, 58}; 59 60static const struct { 61 unsigned int tx; 62 unsigned int rx; 63} rt1011_tdm_mask[] = { 64 {.tx = 0x4, .rx = 0x1}, 65 {.tx = 0x8, .rx = 0x2}, 66}; 67 68static int rt1011_hw_params(struct snd_pcm_substream *substream, 69 struct snd_pcm_hw_params *params) 70{ 71 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 72 struct snd_soc_dai *codec_dai; 73 int srate, i, ret = 0; 74 75 srate = params_rate(params); 76 77 for_each_rtd_codec_dais(rtd, i, codec_dai) { 78 /* 100 Fs to drive 24 bit data */ 79 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, 80 100 * srate, 256 * srate); 81 if (ret < 0) { 82 dev_err(codec_dai->dev, "fail to set pll, ret %d\n", 83 ret); 84 return ret; 85 } 86 87 ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1, 88 256 * srate, SND_SOC_CLOCK_IN); 89 if (ret < 0) { 90 dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", 91 ret); 92 return ret; 93 } 94 95 if (i >= ARRAY_SIZE(rt1011_tdm_mask)) { 96 dev_err(codec_dai->dev, "invalid codec index %d\n", 97 i); 98 return -ENODEV; 99 } 100 101 ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx, 102 rt1011_tdm_mask[i].rx, 4, 103 params_width(params)); 104 if (ret < 0) { 105 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", 106 ret); 107 return ret; 108 } 109 } 110 111 return 0; 112} 113 114static const struct snd_soc_ops rt1011_ops = { 115 .hw_params = rt1011_hw_params, 116}; 117 118static int rt1011_init(struct snd_soc_pcm_runtime *rtd) 119{ 120 struct snd_soc_card *card = rtd->card; 121 int ret; 122 123 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, 124 ARRAY_SIZE(speaker_map_lr)); 125 if (ret) 126 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 127 return ret; 128} 129 130void sof_rt1011_dai_link(struct snd_soc_dai_link *link) 131{ 132 link->codecs = rt1011_dai_link_components; 133 link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components); 134 link->init = rt1011_init; 135 link->ops = &rt1011_ops; 136} 137EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); 138 139void sof_rt1011_codec_conf(struct snd_soc_card *card) 140{ 141 card->codec_conf = rt1011_codec_confs; 142 card->num_configs = ARRAY_SIZE(rt1011_codec_confs); 143} 144EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); 145 146/* 147 * rt1015: i2c mode driver for ALC1015 and ALC1015Q 148 * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB 149 * 150 * For stereo output, there are always two amplifiers on the board. 151 * However, the ACPI implements only one device instance (UID=0) if they 152 * are sharing the same enable pin. The code will detect the number of 153 * device instance and use corresponding DAPM structures for 154 * initialization. 155 */ 156static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = { 157 /* speaker */ 158 { "Left Spk", NULL, "Speaker" }, 159 { "Right Spk", NULL, "Speaker" }, 160}; 161 162static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = { 163 /* speaker */ 164 { "Left Spk", NULL, "Left Speaker" }, 165 { "Right Spk", NULL, "Right Speaker" }, 166}; 167 168static struct snd_soc_codec_conf rt1015p_codec_confs[] = { 169 { 170 .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME), 171 .name_prefix = "Left", 172 }, 173 { 174 .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME), 175 .name_prefix = "Right", 176 }, 177}; 178 179static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = { 180 { 181 .name = RT1015P_DEV0_NAME, 182 .dai_name = RT1015P_CODEC_DAI, 183 }, 184 { 185 .name = RT1015P_DEV1_NAME, 186 .dai_name = RT1015P_CODEC_DAI, 187 }, 188}; 189 190static int rt1015p_get_num_codecs(void) 191{ 192 static int dev_num; 193 194 if (dev_num) 195 return dev_num; 196 197 if (!acpi_dev_present("RTL1015", "1", -1)) 198 dev_num = 1; 199 else 200 dev_num = 2; 201 202 return dev_num; 203} 204 205static int rt1015p_hw_params(struct snd_pcm_substream *substream, 206 struct snd_pcm_hw_params *params) 207{ 208 /* reserved for debugging purpose */ 209 210 return 0; 211} 212 213static const struct snd_soc_ops rt1015p_ops = { 214 .hw_params = rt1015p_hw_params, 215}; 216 217static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) 218{ 219 struct snd_soc_card *card = rtd->card; 220 int ret; 221 222 if (rt1015p_get_num_codecs() == 1) 223 ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes, 224 ARRAY_SIZE(rt1015p_1dev_dapm_routes)); 225 else 226 ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes, 227 ARRAY_SIZE(rt1015p_2dev_dapm_routes)); 228 if (ret) 229 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 230 return ret; 231} 232 233void sof_rt1015p_dai_link(struct snd_soc_dai_link *link) 234{ 235 link->codecs = rt1015p_dai_link_components; 236 link->num_codecs = rt1015p_get_num_codecs(); 237 link->init = rt1015p_init; 238 link->ops = &rt1015p_ops; 239} 240EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); 241 242void sof_rt1015p_codec_conf(struct snd_soc_card *card) 243{ 244 if (rt1015p_get_num_codecs() == 1) 245 return; 246 247 card->codec_conf = rt1015p_codec_confs; 248 card->num_configs = ARRAY_SIZE(rt1015p_codec_confs); 249} 250EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); 251 252/* 253 * RT1015 audio amplifier 254 */ 255 256static int rt1015_hw_params(struct snd_pcm_substream *substream, 257 struct snd_pcm_hw_params *params) 258{ 259 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 260 struct snd_soc_dai *codec_dai; 261 int i, fs = 64, ret; 262 263 for_each_rtd_codec_dais(rtd, i, codec_dai) { 264 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, 265 params_rate(params) * fs, 266 params_rate(params) * 256); 267 if (ret) 268 return ret; 269 270 ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, 271 params_rate(params) * 256, 272 SND_SOC_CLOCK_IN); 273 if (ret) 274 return ret; 275 } 276 277 return 0; 278} 279 280static int rt1015_hw_params_pll_and_tdm(struct snd_pcm_substream *substream, 281 struct snd_pcm_hw_params *params) 282{ 283 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 284 struct snd_soc_dai *codec_dai; 285 int i, fs = 100, ret; 286 287 for_each_rtd_codec_dais(rtd, i, codec_dai) { 288 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, 289 params_rate(params) * fs, 290 params_rate(params) * 256); 291 if (ret) 292 return ret; 293 294 ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, 295 params_rate(params) * 256, 296 SND_SOC_CLOCK_IN); 297 if (ret) 298 return ret; 299 } 300 /* rx slot 1 for RT1015_DEV0_NAME */ 301 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 302 0x0, 0x1, 4, 24); 303 if (ret) 304 return ret; 305 306 /* rx slot 2 for RT1015_DEV1_NAME */ 307 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 1), 308 0x0, 0x2, 4, 24); 309 if (ret) 310 return ret; 311 312 return 0; 313} 314 315static struct snd_soc_ops rt1015_ops = { 316 .hw_params = rt1015_hw_params, 317}; 318 319static struct snd_soc_codec_conf rt1015_amp_conf[] = { 320 { 321 .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME), 322 .name_prefix = "Left", 323 }, 324 { 325 .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME), 326 .name_prefix = "Right", 327 }, 328}; 329 330static struct snd_soc_dai_link_component rt1015_components[] = { 331 { 332 .name = RT1015_DEV0_NAME, 333 .dai_name = RT1015_CODEC_DAI, 334 }, 335 { 336 .name = RT1015_DEV1_NAME, 337 .dai_name = RT1015_CODEC_DAI, 338 }, 339}; 340 341static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) 342{ 343 return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, 344 ARRAY_SIZE(speaker_map_lr)); 345} 346 347void sof_rt1015_codec_conf(struct snd_soc_card *card) 348{ 349 card->codec_conf = rt1015_amp_conf; 350 card->num_configs = ARRAY_SIZE(rt1015_amp_conf); 351} 352EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); 353 354void sof_rt1015_dai_link(struct snd_soc_dai_link *link, unsigned int fs) 355{ 356 link->codecs = rt1015_components; 357 link->num_codecs = ARRAY_SIZE(rt1015_components); 358 link->init = speaker_codec_init_lr; 359 link->ops = &rt1015_ops; 360 361 if (fs == 100) 362 rt1015_ops.hw_params = rt1015_hw_params_pll_and_tdm; 363} 364EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); 365 366/* 367 * RT1308 audio amplifier 368 */ 369static const struct snd_kcontrol_new rt1308_kcontrols[] = { 370 SOC_DAPM_PIN_SWITCH("Speakers"), 371}; 372 373static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = { 374 SND_SOC_DAPM_SPK("Speakers", NULL), 375}; 376 377static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { 378 /* speaker */ 379 {"Speakers", NULL, "SPOL"}, 380 {"Speakers", NULL, "SPOR"}, 381}; 382 383static struct snd_soc_dai_link_component rt1308_components[] = { 384 { 385 .name = RT1308_DEV0_NAME, 386 .dai_name = RT1308_CODEC_DAI, 387 } 388}; 389 390static int rt1308_init(struct snd_soc_pcm_runtime *rtd) 391{ 392 struct snd_soc_card *card = rtd->card; 393 int ret; 394 395 ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets, 396 ARRAY_SIZE(rt1308_dapm_widgets)); 397 if (ret) { 398 dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret); 399 return ret; 400 } 401 402 ret = snd_soc_add_card_controls(card, rt1308_kcontrols, 403 ARRAY_SIZE(rt1308_kcontrols)); 404 if (ret) { 405 dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret); 406 return ret; 407 } 408 409 ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes, 410 ARRAY_SIZE(rt1308_dapm_routes)); 411 412 if (ret) 413 dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret); 414 415 return ret; 416} 417 418static int rt1308_hw_params(struct snd_pcm_substream *substream, 419 struct snd_pcm_hw_params *params) 420{ 421 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 422 struct snd_soc_card *card = rtd->card; 423 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 424 int clk_id, clk_freq, pll_out; 425 int ret; 426 427 clk_id = RT1308_PLL_S_MCLK; 428 /* get the tplg configured mclk. */ 429 clk_freq = sof_dai_get_mclk(rtd); 430 431 pll_out = params_rate(params) * 512; 432 433 /* Set rt1308 pll */ 434 ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); 435 if (ret < 0) { 436 dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret); 437 return ret; 438 } 439 440 /* Set rt1308 sysclk */ 441 ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, 442 SND_SOC_CLOCK_IN); 443 if (ret < 0) 444 dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret); 445 446 return ret; 447} 448 449static const struct snd_soc_ops rt1308_ops = { 450 .hw_params = rt1308_hw_params, 451}; 452 453void sof_rt1308_dai_link(struct snd_soc_dai_link *link) 454{ 455 link->codecs = rt1308_components; 456 link->num_codecs = ARRAY_SIZE(rt1308_components); 457 link->init = rt1308_init; 458 link->ops = &rt1308_ops; 459} 460EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); 461 462/* 463 * 2-amp Configuration for RT1019 464 */ 465 466static const struct snd_soc_dapm_route rt1019_dapm_routes[] = { 467 /* speaker */ 468 { "Left Spk", NULL, "Speaker" }, 469 { "Right Spk", NULL, "Speaker" }, 470}; 471 472static struct snd_soc_dai_link_component rt1019_components[] = { 473 { 474 .name = RT1019_DEV0_NAME, 475 .dai_name = RT1019_CODEC_DAI, 476 }, 477}; 478 479static int rt1019_init(struct snd_soc_pcm_runtime *rtd) 480{ 481 struct snd_soc_card *card = rtd->card; 482 int ret; 483 484 ret = snd_soc_dapm_add_routes(&card->dapm, rt1019_dapm_routes, 485 ARRAY_SIZE(rt1019_dapm_routes)); 486 if (ret) { 487 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 488 return ret; 489 } 490 return ret; 491} 492 493void sof_rt1019_dai_link(struct snd_soc_dai_link *link) 494{ 495 link->codecs = rt1019_components; 496 link->num_codecs = ARRAY_SIZE(rt1019_components); 497 link->init = rt1019_init; 498} 499EXPORT_SYMBOL_NS(sof_rt1019_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); 500 501MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); 502MODULE_LICENSE("GPL");