628 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA72194 *5 * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved.6 */7 8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/slab.h>11#include <linux/delay.h>12#include <linux/spi/spi.h>13#include <linux/i2c.h>14#include <linux/input.h>15#include <sound/core.h>16#include <sound/jack.h>17#include <sound/pcm.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20#include "rockchip_i2s.h"21#include "../codecs/da7219.h"22#include "../codecs/rt5514.h"23 24#define DRV_NAME "rk3399-gru-sound"25 26#define SOUND_FS 25627 28static unsigned int dmic_wakeup_delay;29 30static struct snd_soc_jack rockchip_sound_jack;31 32/* Headset jack detection DAPM pins */33static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {34 {35 .pin = "Headphones",36 .mask = SND_JACK_HEADPHONE,37 },38 {39 .pin = "Headset Mic",40 .mask = SND_JACK_MICROPHONE,41 },42 {43 .pin = "Line Out",44 .mask = SND_JACK_LINEOUT,45 },46};47 48static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {49 SND_SOC_DAPM_HP("Headphones", NULL),50 SND_SOC_DAPM_SPK("Speakers", NULL),51 SND_SOC_DAPM_MIC("Headset Mic", NULL),52 SND_SOC_DAPM_LINE("Line Out", NULL),53 SND_SOC_DAPM_MIC("Int Mic", NULL),54 SND_SOC_DAPM_LINE("HDMI", NULL),55};56 57static const struct snd_kcontrol_new rockchip_controls[] = {58 SOC_DAPM_PIN_SWITCH("Headphones"),59 SOC_DAPM_PIN_SWITCH("Speakers"),60 SOC_DAPM_PIN_SWITCH("Headset Mic"),61 SOC_DAPM_PIN_SWITCH("Line Out"),62 SOC_DAPM_PIN_SWITCH("Int Mic"),63 SOC_DAPM_PIN_SWITCH("HDMI"),64};65 66static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,67 struct snd_pcm_hw_params *params)68{69 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);70 unsigned int mclk;71 int ret;72 73 mclk = params_rate(params) * SOUND_FS;74 75 ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);76 if (ret) {77 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",78 __func__, mclk, ret);79 return ret;80 }81 82 return 0;83}84 85static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,86 struct snd_pcm_hw_params *params)87{88 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);89 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);90 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);91 unsigned int mclk;92 int ret;93 94 mclk = params_rate(params) * SOUND_FS;95 96 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,97 SND_SOC_CLOCK_OUT);98 if (ret < 0) {99 dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);100 return ret;101 }102 103 ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,104 mclk, SND_SOC_CLOCK_IN);105 if (ret) {106 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",107 __func__, params_rate(params) * 512, ret);108 return ret;109 }110 111 /* Wait for DMIC stable */112 msleep(dmic_wakeup_delay);113 114 return 0;115}116 117static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,118 struct snd_pcm_hw_params *params)119{120 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);121 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);122 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);123 int mclk, ret;124 125 /* in bypass mode, the mclk has to be one of the frequencies below */126 switch (params_rate(params)) {127 case 8000:128 case 16000:129 case 24000:130 case 32000:131 case 48000:132 case 64000:133 case 96000:134 mclk = 12288000;135 break;136 case 11025:137 case 22050:138 case 44100:139 case 88200:140 mclk = 11289600;141 break;142 default:143 return -EINVAL;144 }145 146 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,147 SND_SOC_CLOCK_OUT);148 if (ret < 0) {149 dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);150 return ret;151 }152 153 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,154 SND_SOC_CLOCK_IN);155 if (ret < 0) {156 dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);157 return ret;158 }159 160 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);161 if (ret < 0) {162 dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);163 return ret;164 }165 166 return 0;167}168 169static struct snd_soc_jack cdn_dp_card_jack;170 171static int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)172{173 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;174 struct snd_soc_card *card = rtd->card;175 int ret;176 177 /* Enable jack detection. */178 ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT,179 &cdn_dp_card_jack);180 if (ret) {181 dev_err(card->dev, "Can't create DP Jack %d\n", ret);182 return ret;183 }184 185 return snd_soc_component_set_jack(component, &cdn_dp_card_jack, NULL);186}187 188static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)189{190 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;191 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);192 int ret;193 194 /* We need default MCLK and PLL settings for the accessory detection */195 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,196 SND_SOC_CLOCK_IN);197 if (ret < 0) {198 dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);199 return ret;200 }201 202 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);203 if (ret < 0) {204 dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);205 return ret;206 }207 208 /* Enable Headset and 4 Buttons Jack detection */209 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",210 SND_JACK_HEADSET | SND_JACK_LINEOUT |211 SND_JACK_BTN_0 | SND_JACK_BTN_1 |212 SND_JACK_BTN_2 | SND_JACK_BTN_3,213 &rockchip_sound_jack,214 rockchip_sound_jack_pins,215 ARRAY_SIZE(rockchip_sound_jack_pins));216 217 if (ret) {218 dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);219 return ret;220 }221 222 snd_jack_set_key(223 rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);224 snd_jack_set_key(225 rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);226 snd_jack_set_key(227 rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);228 snd_jack_set_key(229 rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);230 231 snd_soc_component_set_jack(component, &rockchip_sound_jack, NULL);232 233 return 0;234}235 236static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,237 struct snd_pcm_hw_params *params)238{239 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);240 unsigned int mclk;241 int ret;242 243 mclk = params_rate(params) * SOUND_FS;244 245 ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);246 if (ret) {247 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",248 __func__, mclk, ret);249 return ret;250 }251 252 /* Wait for DMIC stable */253 msleep(dmic_wakeup_delay);254 255 return 0;256}257 258static int rockchip_sound_startup(struct snd_pcm_substream *substream)259{260 struct snd_pcm_runtime *runtime = substream->runtime;261 262 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;263 return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,264 8000, 96000);265}266 267static const struct snd_soc_ops rockchip_sound_max98357a_ops = {268 .startup = rockchip_sound_startup,269 .hw_params = rockchip_sound_max98357a_hw_params,270};271 272static const struct snd_soc_ops rockchip_sound_rt5514_ops = {273 .startup = rockchip_sound_startup,274 .hw_params = rockchip_sound_rt5514_hw_params,275};276 277static const struct snd_soc_ops rockchip_sound_da7219_ops = {278 .startup = rockchip_sound_startup,279 .hw_params = rockchip_sound_da7219_hw_params,280};281 282static const struct snd_soc_ops rockchip_sound_dmic_ops = {283 .startup = rockchip_sound_startup,284 .hw_params = rockchip_sound_dmic_hw_params,285};286 287static struct snd_soc_card rockchip_sound_card = {288 .name = "rk3399-gru-sound",289 .owner = THIS_MODULE,290 .dapm_widgets = rockchip_dapm_widgets,291 .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),292 .controls = rockchip_controls,293 .num_controls = ARRAY_SIZE(rockchip_controls),294};295 296enum {297 DAILINK_CDNDP,298 DAILINK_DA7219,299 DAILINK_DMIC,300 DAILINK_MAX98357A,301 DAILINK_RT5514,302 DAILINK_RT5514_DSP,303};304 305SND_SOC_DAILINK_DEFS(cdndp,306 DAILINK_COMP_ARRAY(COMP_EMPTY()),307 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")),308 DAILINK_COMP_ARRAY(COMP_EMPTY()));309 310SND_SOC_DAILINK_DEFS(da7219,311 DAILINK_COMP_ARRAY(COMP_EMPTY()),312 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")),313 DAILINK_COMP_ARRAY(COMP_EMPTY()));314 315SND_SOC_DAILINK_DEFS(dmic,316 DAILINK_COMP_ARRAY(COMP_EMPTY()),317 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")),318 DAILINK_COMP_ARRAY(COMP_EMPTY()));319 320SND_SOC_DAILINK_DEFS(max98357a,321 DAILINK_COMP_ARRAY(COMP_EMPTY()),322 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),323 DAILINK_COMP_ARRAY(COMP_EMPTY()));324 325SND_SOC_DAILINK_DEFS(rt5514,326 DAILINK_COMP_ARRAY(COMP_EMPTY()),327 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")),328 DAILINK_COMP_ARRAY(COMP_EMPTY()));329 330SND_SOC_DAILINK_DEFS(rt5514_dsp,331 DAILINK_COMP_ARRAY(COMP_EMPTY()),332 DAILINK_COMP_ARRAY(COMP_DUMMY()),333 DAILINK_COMP_ARRAY(COMP_EMPTY()));334 335static const struct snd_soc_dai_link rockchip_dais[] = {336 [DAILINK_CDNDP] = {337 .name = "DP",338 .stream_name = "DP PCM",339 .init = rockchip_sound_cdndp_init,340 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |341 SND_SOC_DAIFMT_CBS_CFS,342 SND_SOC_DAILINK_REG(cdndp),343 },344 [DAILINK_DA7219] = {345 .name = "DA7219",346 .stream_name = "DA7219 PCM",347 .init = rockchip_sound_da7219_init,348 .ops = &rockchip_sound_da7219_ops,349 /* set da7219 as slave */350 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |351 SND_SOC_DAIFMT_CBS_CFS,352 SND_SOC_DAILINK_REG(da7219),353 },354 [DAILINK_DMIC] = {355 .name = "DMIC",356 .stream_name = "DMIC PCM",357 .ops = &rockchip_sound_dmic_ops,358 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |359 SND_SOC_DAIFMT_CBS_CFS,360 SND_SOC_DAILINK_REG(dmic),361 },362 [DAILINK_MAX98357A] = {363 .name = "MAX98357A",364 .stream_name = "MAX98357A PCM",365 .ops = &rockchip_sound_max98357a_ops,366 /* set max98357a as slave */367 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |368 SND_SOC_DAIFMT_CBS_CFS,369 SND_SOC_DAILINK_REG(max98357a),370 },371 [DAILINK_RT5514] = {372 .name = "RT5514",373 .stream_name = "RT5514 PCM",374 .ops = &rockchip_sound_rt5514_ops,375 /* set rt5514 as slave */376 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |377 SND_SOC_DAIFMT_CBS_CFS,378 SND_SOC_DAILINK_REG(rt5514),379 },380 /* RT5514 DSP for voice wakeup via spi bus */381 [DAILINK_RT5514_DSP] = {382 .name = "RT5514 DSP",383 .stream_name = "Wake on Voice",384 SND_SOC_DAILINK_REG(rt5514_dsp),385 },386};387 388static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {389 /* Output */390 {"HDMI", NULL, "TX"},391};392 393static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {394 /* Output */395 {"Headphones", NULL, "HPL"},396 {"Headphones", NULL, "HPR"},397 398 /* Input */399 {"MIC", NULL, "Headset Mic"},400};401 402static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {403 /* Input */404 {"DMic", NULL, "Int Mic"},405};406 407static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {408 /* Output */409 {"Speakers", NULL, "Speaker"},410};411 412static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {413 /* Input */414 {"DMIC1L", NULL, "Int Mic"},415 {"DMIC1R", NULL, "Int Mic"},416};417 418struct rockchip_sound_route {419 const struct snd_soc_dapm_route *routes;420 int num_routes;421};422 423static const struct rockchip_sound_route rockchip_routes[] = {424 [DAILINK_CDNDP] = {425 .routes = rockchip_sound_cdndp_routes,426 .num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),427 },428 [DAILINK_DA7219] = {429 .routes = rockchip_sound_da7219_routes,430 .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),431 },432 [DAILINK_DMIC] = {433 .routes = rockchip_sound_dmic_routes,434 .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),435 },436 [DAILINK_MAX98357A] = {437 .routes = rockchip_sound_max98357a_routes,438 .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),439 },440 [DAILINK_RT5514] = {441 .routes = rockchip_sound_rt5514_routes,442 .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),443 },444 [DAILINK_RT5514_DSP] = {},445};446 447struct dailink_match_data {448 const char *compatible;449 const struct bus_type *bus_type;450};451 452static const struct dailink_match_data dailink_match[] = {453 [DAILINK_CDNDP] = {454 .compatible = "rockchip,rk3399-cdn-dp",455 },456 [DAILINK_DA7219] = {457 .compatible = "dlg,da7219",458 },459 [DAILINK_DMIC] = {460 .compatible = "dmic-codec",461 },462 [DAILINK_MAX98357A] = {463 .compatible = "maxim,max98357a",464 },465 [DAILINK_RT5514] = {466 .compatible = "realtek,rt5514",467 .bus_type = &i2c_bus_type,468 },469 [DAILINK_RT5514_DSP] = {470 .compatible = "realtek,rt5514",471 .bus_type = &spi_bus_type,472 },473};474 475static int rockchip_sound_codec_node_match(struct device_node *np_codec)476{477 struct device *dev;478 int i;479 480 for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {481 if (!of_device_is_compatible(np_codec,482 dailink_match[i].compatible))483 continue;484 485 if (dailink_match[i].bus_type) {486 dev = bus_find_device_by_of_node(dailink_match[i].bus_type,487 np_codec);488 if (!dev)489 continue;490 put_device(dev);491 }492 493 return i;494 }495 return -1;496}497 498static int rockchip_sound_of_parse_dais(struct device *dev,499 struct snd_soc_card *card)500{501 struct device_node *np_cpu, *np_cpu0, *np_cpu1;502 struct device_node *np_codec;503 struct snd_soc_dai_link *dai;504 struct snd_soc_dapm_route *routes;505 int i, index;506 int num_routes;507 508 card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),509 GFP_KERNEL);510 if (!card->dai_link)511 return -ENOMEM;512 513 num_routes = 0;514 for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)515 num_routes += rockchip_routes[i].num_routes;516 routes = devm_kcalloc(dev, num_routes, sizeof(*routes),517 GFP_KERNEL);518 if (!routes)519 return -ENOMEM;520 card->dapm_routes = routes;521 522 np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);523 np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);524 525 card->num_dapm_routes = 0;526 card->num_links = 0;527 for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {528 np_codec = of_parse_phandle(dev->of_node,529 "rockchip,codec", i);530 if (!np_codec)531 break;532 533 if (!of_device_is_available(np_codec))534 continue;535 536 index = rockchip_sound_codec_node_match(np_codec);537 if (index < 0)538 continue;539 540 switch (index) {541 case DAILINK_CDNDP:542 np_cpu = np_cpu1;543 break;544 case DAILINK_RT5514_DSP:545 np_cpu = np_codec;546 break;547 default:548 np_cpu = np_cpu0;549 break;550 }551 552 if (!np_cpu) {553 dev_err(dev, "Missing 'rockchip,cpu' for %s\n",554 rockchip_dais[index].name);555 return -EINVAL;556 }557 558 dai = &card->dai_link[card->num_links++];559 *dai = rockchip_dais[index];560 561 if (!dai->codecs->name)562 dai->codecs->of_node = np_codec;563 dai->platforms->of_node = np_cpu;564 dai->cpus->of_node = np_cpu;565 566 if (card->num_dapm_routes + rockchip_routes[index].num_routes >567 num_routes) {568 dev_err(dev, "Too many routes\n");569 return -EINVAL;570 }571 572 memcpy(routes + card->num_dapm_routes,573 rockchip_routes[index].routes,574 rockchip_routes[index].num_routes * sizeof(*routes));575 card->num_dapm_routes += rockchip_routes[index].num_routes;576 }577 578 return 0;579}580 581static int rockchip_sound_probe(struct platform_device *pdev)582{583 struct snd_soc_card *card = &rockchip_sound_card;584 int ret;585 586 ret = rockchip_sound_of_parse_dais(&pdev->dev, card);587 if (ret < 0) {588 dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);589 return ret;590 }591 592 /* Set DMIC wakeup delay */593 ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",594 &dmic_wakeup_delay);595 if (ret) {596 dmic_wakeup_delay = 0;597 dev_dbg(&pdev->dev,598 "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");599 }600 601 card->dev = &pdev->dev;602 return devm_snd_soc_register_card(&pdev->dev, card);603}604 605static const struct of_device_id rockchip_sound_of_match[] = {606 { .compatible = "rockchip,rk3399-gru-sound", },607 {},608};609 610static struct platform_driver rockchip_sound_driver = {611 .probe = rockchip_sound_probe,612 .driver = {613 .name = DRV_NAME,614 .of_match_table = rockchip_sound_of_match,615#ifdef CONFIG_PM616 .pm = &snd_soc_pm_ops,617#endif618 },619};620 621module_platform_driver(rockchip_sound_driver);622 623MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");624MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");625MODULE_LICENSE("GPL v2");626MODULE_ALIAS("platform:" DRV_NAME);627MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);628