18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/gpio.h> 128c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/input.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/jack.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 218c2ecf20Sopenharmony_ci#include <sound/soc.h> 228c2ecf20Sopenharmony_ci#include "rockchip_i2s.h" 238c2ecf20Sopenharmony_ci#include "../codecs/da7219.h" 248c2ecf20Sopenharmony_ci#include "../codecs/da7219-aad.h" 258c2ecf20Sopenharmony_ci#include "../codecs/rt5514.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define DRV_NAME "rk3399-gru-sound" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define SOUND_FS 256 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned int dmic_wakeup_delay; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct snd_soc_jack rockchip_sound_jack; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Headset jack detection DAPM pins */ 368c2ecf20Sopenharmony_cistatic struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { 378c2ecf20Sopenharmony_ci { 388c2ecf20Sopenharmony_ci .pin = "Headphones", 398c2ecf20Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 408c2ecf20Sopenharmony_ci }, 418c2ecf20Sopenharmony_ci { 428c2ecf20Sopenharmony_ci .pin = "Headset Mic", 438c2ecf20Sopenharmony_ci .mask = SND_JACK_MICROPHONE, 448c2ecf20Sopenharmony_ci }, 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { 498c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphones", NULL), 508c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Speakers", NULL), 518c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 528c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Int Mic", NULL), 538c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("HDMI", NULL), 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rockchip_controls[] = { 578c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphones"), 588c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Speakers"), 598c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 608c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Int Mic"), 618c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("HDMI"), 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream, 658c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 688c2ecf20Sopenharmony_ci unsigned int mclk; 698c2ecf20Sopenharmony_ci int ret; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci mclk = params_rate(params) * SOUND_FS; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0); 748c2ecf20Sopenharmony_ci if (ret) { 758c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", 768c2ecf20Sopenharmony_ci __func__, mclk, ret); 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream, 848c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 878c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 888c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 898c2ecf20Sopenharmony_ci unsigned int mclk; 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci mclk = params_rate(params) * SOUND_FS; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 958c2ecf20Sopenharmony_ci SND_SOC_CLOCK_OUT); 968c2ecf20Sopenharmony_ci if (ret < 0) { 978c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK, 1028c2ecf20Sopenharmony_ci mclk, SND_SOC_CLOCK_IN); 1038c2ecf20Sopenharmony_ci if (ret) { 1048c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", 1058c2ecf20Sopenharmony_ci __func__, params_rate(params) * 512, ret); 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Wait for DMIC stable */ 1108c2ecf20Sopenharmony_ci msleep(dmic_wakeup_delay); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream, 1168c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1198c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 1208c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 1218c2ecf20Sopenharmony_ci int mclk, ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* in bypass mode, the mclk has to be one of the frequencies below */ 1248c2ecf20Sopenharmony_ci switch (params_rate(params)) { 1258c2ecf20Sopenharmony_ci case 8000: 1268c2ecf20Sopenharmony_ci case 16000: 1278c2ecf20Sopenharmony_ci case 24000: 1288c2ecf20Sopenharmony_ci case 32000: 1298c2ecf20Sopenharmony_ci case 48000: 1308c2ecf20Sopenharmony_ci case 64000: 1318c2ecf20Sopenharmony_ci case 96000: 1328c2ecf20Sopenharmony_ci mclk = 12288000; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case 11025: 1358c2ecf20Sopenharmony_ci case 22050: 1368c2ecf20Sopenharmony_ci case 44100: 1378c2ecf20Sopenharmony_ci case 88200: 1388c2ecf20Sopenharmony_ci mclk = 11289600; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci default: 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 1458c2ecf20Sopenharmony_ci SND_SOC_CLOCK_OUT); 1468c2ecf20Sopenharmony_ci if (ret < 0) { 1478c2ecf20Sopenharmony_ci dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret); 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 1528c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 1538c2ecf20Sopenharmony_ci if (ret < 0) { 1548c2ecf20Sopenharmony_ci dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret); 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); 1598c2ecf20Sopenharmony_ci if (ret < 0) { 1608c2ecf20Sopenharmony_ci dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret); 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 1708c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* We need default MCLK and PLL settings for the accessory detection */ 1748c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000, 1758c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 1768c2ecf20Sopenharmony_ci if (ret < 0) { 1778c2ecf20Sopenharmony_ci dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret); 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); 1828c2ecf20Sopenharmony_ci if (ret < 0) { 1838c2ecf20Sopenharmony_ci dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret); 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* Enable Headset and 4 Buttons Jack detection */ 1888c2ecf20Sopenharmony_ci ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 1898c2ecf20Sopenharmony_ci SND_JACK_HEADSET | SND_JACK_LINEOUT | 1908c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 1918c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3, 1928c2ecf20Sopenharmony_ci &rockchip_sound_jack, 1938c2ecf20Sopenharmony_ci rockchip_sound_jack_pins, 1948c2ecf20Sopenharmony_ci ARRAY_SIZE(rockchip_sound_jack_pins)); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (ret) { 1978c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret); 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci snd_jack_set_key( 2028c2ecf20Sopenharmony_ci rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 2038c2ecf20Sopenharmony_ci snd_jack_set_key( 2048c2ecf20Sopenharmony_ci rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 2058c2ecf20Sopenharmony_ci snd_jack_set_key( 2068c2ecf20Sopenharmony_ci rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 2078c2ecf20Sopenharmony_ci snd_jack_set_key( 2088c2ecf20Sopenharmony_ci rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci da7219_aad_jack_det(component, &rockchip_sound_jack); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream, 2168c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2198c2ecf20Sopenharmony_ci unsigned int mclk; 2208c2ecf20Sopenharmony_ci int ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mclk = params_rate(params) * SOUND_FS; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0); 2258c2ecf20Sopenharmony_ci if (ret) { 2268c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", 2278c2ecf20Sopenharmony_ci __func__, mclk, ret); 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Wait for DMIC stable */ 2328c2ecf20Sopenharmony_ci msleep(dmic_wakeup_delay); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int rockchip_sound_startup(struct snd_pcm_substream *substream) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; 2428c2ecf20Sopenharmony_ci return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 2438c2ecf20Sopenharmony_ci 8000, 96000); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_max98357a_ops = { 2478c2ecf20Sopenharmony_ci .startup = rockchip_sound_startup, 2488c2ecf20Sopenharmony_ci .hw_params = rockchip_sound_max98357a_hw_params, 2498c2ecf20Sopenharmony_ci}; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_rt5514_ops = { 2528c2ecf20Sopenharmony_ci .startup = rockchip_sound_startup, 2538c2ecf20Sopenharmony_ci .hw_params = rockchip_sound_rt5514_hw_params, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_da7219_ops = { 2578c2ecf20Sopenharmony_ci .startup = rockchip_sound_startup, 2588c2ecf20Sopenharmony_ci .hw_params = rockchip_sound_da7219_hw_params, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_dmic_ops = { 2628c2ecf20Sopenharmony_ci .startup = rockchip_sound_startup, 2638c2ecf20Sopenharmony_ci .hw_params = rockchip_sound_dmic_hw_params, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic struct snd_soc_card rockchip_sound_card = { 2678c2ecf20Sopenharmony_ci .name = "rk3399-gru-sound", 2688c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2698c2ecf20Sopenharmony_ci .dapm_widgets = rockchip_dapm_widgets, 2708c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets), 2718c2ecf20Sopenharmony_ci .controls = rockchip_controls, 2728c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(rockchip_controls), 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cienum { 2768c2ecf20Sopenharmony_ci DAILINK_CDNDP, 2778c2ecf20Sopenharmony_ci DAILINK_DA7219, 2788c2ecf20Sopenharmony_ci DAILINK_DMIC, 2798c2ecf20Sopenharmony_ci DAILINK_MAX98357A, 2808c2ecf20Sopenharmony_ci DAILINK_RT5514, 2818c2ecf20Sopenharmony_ci DAILINK_RT5514_DSP, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(cdndp, 2858c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 2868c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")), 2878c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(da7219, 2908c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 2918c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")), 2928c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dmic, 2958c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 2968c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")), 2978c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(max98357a, 3008c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 3018c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), 3028c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(rt5514, 3058c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 3068c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")), 3078c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(rt5514_dsp, 3108c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 3118c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_DUMMY()), 3128c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_link rockchip_dais[] = { 3158c2ecf20Sopenharmony_ci [DAILINK_CDNDP] = { 3168c2ecf20Sopenharmony_ci .name = "DP", 3178c2ecf20Sopenharmony_ci .stream_name = "DP PCM", 3188c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 3198c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 3208c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(cdndp), 3218c2ecf20Sopenharmony_ci }, 3228c2ecf20Sopenharmony_ci [DAILINK_DA7219] = { 3238c2ecf20Sopenharmony_ci .name = "DA7219", 3248c2ecf20Sopenharmony_ci .stream_name = "DA7219 PCM", 3258c2ecf20Sopenharmony_ci .init = rockchip_sound_da7219_init, 3268c2ecf20Sopenharmony_ci .ops = &rockchip_sound_da7219_ops, 3278c2ecf20Sopenharmony_ci /* set da7219 as slave */ 3288c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 3298c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 3308c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(da7219), 3318c2ecf20Sopenharmony_ci }, 3328c2ecf20Sopenharmony_ci [DAILINK_DMIC] = { 3338c2ecf20Sopenharmony_ci .name = "DMIC", 3348c2ecf20Sopenharmony_ci .stream_name = "DMIC PCM", 3358c2ecf20Sopenharmony_ci .ops = &rockchip_sound_dmic_ops, 3368c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 3378c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 3388c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dmic), 3398c2ecf20Sopenharmony_ci }, 3408c2ecf20Sopenharmony_ci [DAILINK_MAX98357A] = { 3418c2ecf20Sopenharmony_ci .name = "MAX98357A", 3428c2ecf20Sopenharmony_ci .stream_name = "MAX98357A PCM", 3438c2ecf20Sopenharmony_ci .ops = &rockchip_sound_max98357a_ops, 3448c2ecf20Sopenharmony_ci /* set max98357a as slave */ 3458c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 3468c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 3478c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(max98357a), 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci [DAILINK_RT5514] = { 3508c2ecf20Sopenharmony_ci .name = "RT5514", 3518c2ecf20Sopenharmony_ci .stream_name = "RT5514 PCM", 3528c2ecf20Sopenharmony_ci .ops = &rockchip_sound_rt5514_ops, 3538c2ecf20Sopenharmony_ci /* set rt5514 as slave */ 3548c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 3558c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 3568c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(rt5514), 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci /* RT5514 DSP for voice wakeup via spi bus */ 3598c2ecf20Sopenharmony_ci [DAILINK_RT5514_DSP] = { 3608c2ecf20Sopenharmony_ci .name = "RT5514 DSP", 3618c2ecf20Sopenharmony_ci .stream_name = "Wake on Voice", 3628c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(rt5514_dsp), 3638c2ecf20Sopenharmony_ci }, 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = { 3678c2ecf20Sopenharmony_ci /* Output */ 3688c2ecf20Sopenharmony_ci {"HDMI", NULL, "TX"}, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = { 3728c2ecf20Sopenharmony_ci /* Output */ 3738c2ecf20Sopenharmony_ci {"Headphones", NULL, "HPL"}, 3748c2ecf20Sopenharmony_ci {"Headphones", NULL, "HPR"}, 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Input */ 3778c2ecf20Sopenharmony_ci {"MIC", NULL, "Headset Mic"}, 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = { 3818c2ecf20Sopenharmony_ci /* Input */ 3828c2ecf20Sopenharmony_ci {"DMic", NULL, "Int Mic"}, 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = { 3868c2ecf20Sopenharmony_ci /* Output */ 3878c2ecf20Sopenharmony_ci {"Speakers", NULL, "Speaker"}, 3888c2ecf20Sopenharmony_ci}; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = { 3918c2ecf20Sopenharmony_ci /* Input */ 3928c2ecf20Sopenharmony_ci {"DMIC1L", NULL, "Int Mic"}, 3938c2ecf20Sopenharmony_ci {"DMIC1R", NULL, "Int Mic"}, 3948c2ecf20Sopenharmony_ci}; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistruct rockchip_sound_route { 3978c2ecf20Sopenharmony_ci const struct snd_soc_dapm_route *routes; 3988c2ecf20Sopenharmony_ci int num_routes; 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic const struct rockchip_sound_route rockchip_routes[] = { 4028c2ecf20Sopenharmony_ci [DAILINK_CDNDP] = { 4038c2ecf20Sopenharmony_ci .routes = rockchip_sound_cdndp_routes, 4048c2ecf20Sopenharmony_ci .num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes), 4058c2ecf20Sopenharmony_ci }, 4068c2ecf20Sopenharmony_ci [DAILINK_DA7219] = { 4078c2ecf20Sopenharmony_ci .routes = rockchip_sound_da7219_routes, 4088c2ecf20Sopenharmony_ci .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes), 4098c2ecf20Sopenharmony_ci }, 4108c2ecf20Sopenharmony_ci [DAILINK_DMIC] = { 4118c2ecf20Sopenharmony_ci .routes = rockchip_sound_dmic_routes, 4128c2ecf20Sopenharmony_ci .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes), 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci [DAILINK_MAX98357A] = { 4158c2ecf20Sopenharmony_ci .routes = rockchip_sound_max98357a_routes, 4168c2ecf20Sopenharmony_ci .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes), 4178c2ecf20Sopenharmony_ci }, 4188c2ecf20Sopenharmony_ci [DAILINK_RT5514] = { 4198c2ecf20Sopenharmony_ci .routes = rockchip_sound_rt5514_routes, 4208c2ecf20Sopenharmony_ci .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes), 4218c2ecf20Sopenharmony_ci }, 4228c2ecf20Sopenharmony_ci [DAILINK_RT5514_DSP] = {}, 4238c2ecf20Sopenharmony_ci}; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistruct dailink_match_data { 4268c2ecf20Sopenharmony_ci const char *compatible; 4278c2ecf20Sopenharmony_ci struct bus_type *bus_type; 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic const struct dailink_match_data dailink_match[] = { 4318c2ecf20Sopenharmony_ci [DAILINK_CDNDP] = { 4328c2ecf20Sopenharmony_ci .compatible = "rockchip,rk3399-cdn-dp", 4338c2ecf20Sopenharmony_ci }, 4348c2ecf20Sopenharmony_ci [DAILINK_DA7219] = { 4358c2ecf20Sopenharmony_ci .compatible = "dlg,da7219", 4368c2ecf20Sopenharmony_ci }, 4378c2ecf20Sopenharmony_ci [DAILINK_DMIC] = { 4388c2ecf20Sopenharmony_ci .compatible = "dmic-codec", 4398c2ecf20Sopenharmony_ci }, 4408c2ecf20Sopenharmony_ci [DAILINK_MAX98357A] = { 4418c2ecf20Sopenharmony_ci .compatible = "maxim,max98357a", 4428c2ecf20Sopenharmony_ci }, 4438c2ecf20Sopenharmony_ci [DAILINK_RT5514] = { 4448c2ecf20Sopenharmony_ci .compatible = "realtek,rt5514", 4458c2ecf20Sopenharmony_ci .bus_type = &i2c_bus_type, 4468c2ecf20Sopenharmony_ci }, 4478c2ecf20Sopenharmony_ci [DAILINK_RT5514_DSP] = { 4488c2ecf20Sopenharmony_ci .compatible = "realtek,rt5514", 4498c2ecf20Sopenharmony_ci .bus_type = &spi_bus_type, 4508c2ecf20Sopenharmony_ci }, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int rockchip_sound_codec_node_match(struct device_node *np_codec) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct device *dev; 4568c2ecf20Sopenharmony_ci int i; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dailink_match); i++) { 4598c2ecf20Sopenharmony_ci if (!of_device_is_compatible(np_codec, 4608c2ecf20Sopenharmony_ci dailink_match[i].compatible)) 4618c2ecf20Sopenharmony_ci continue; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (dailink_match[i].bus_type) { 4648c2ecf20Sopenharmony_ci dev = bus_find_device_by_of_node(dailink_match[i].bus_type, 4658c2ecf20Sopenharmony_ci np_codec); 4668c2ecf20Sopenharmony_ci if (!dev) 4678c2ecf20Sopenharmony_ci continue; 4688c2ecf20Sopenharmony_ci put_device(dev); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return i; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci return -1; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int rockchip_sound_of_parse_dais(struct device *dev, 4778c2ecf20Sopenharmony_ci struct snd_soc_card *card) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct device_node *np_cpu, *np_cpu0, *np_cpu1; 4808c2ecf20Sopenharmony_ci struct device_node *np_codec; 4818c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai; 4828c2ecf20Sopenharmony_ci struct snd_soc_dapm_route *routes; 4838c2ecf20Sopenharmony_ci int i, index; 4848c2ecf20Sopenharmony_ci int num_routes; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais), 4878c2ecf20Sopenharmony_ci GFP_KERNEL); 4888c2ecf20Sopenharmony_ci if (!card->dai_link) 4898c2ecf20Sopenharmony_ci return -ENOMEM; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci num_routes = 0; 4928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++) 4938c2ecf20Sopenharmony_ci num_routes += rockchip_routes[i].num_routes; 4948c2ecf20Sopenharmony_ci routes = devm_kcalloc(dev, num_routes, sizeof(*routes), 4958c2ecf20Sopenharmony_ci GFP_KERNEL); 4968c2ecf20Sopenharmony_ci if (!routes) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci card->dapm_routes = routes; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0); 5018c2ecf20Sopenharmony_ci np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci card->num_dapm_routes = 0; 5048c2ecf20Sopenharmony_ci card->num_links = 0; 5058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) { 5068c2ecf20Sopenharmony_ci np_codec = of_parse_phandle(dev->of_node, 5078c2ecf20Sopenharmony_ci "rockchip,codec", i); 5088c2ecf20Sopenharmony_ci if (!np_codec) 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (!of_device_is_available(np_codec)) 5128c2ecf20Sopenharmony_ci continue; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci index = rockchip_sound_codec_node_match(np_codec); 5158c2ecf20Sopenharmony_ci if (index < 0) 5168c2ecf20Sopenharmony_ci continue; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci switch (index) { 5198c2ecf20Sopenharmony_ci case DAILINK_CDNDP: 5208c2ecf20Sopenharmony_ci np_cpu = np_cpu1; 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case DAILINK_RT5514_DSP: 5238c2ecf20Sopenharmony_ci np_cpu = np_codec; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci default: 5268c2ecf20Sopenharmony_ci np_cpu = np_cpu0; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (!np_cpu) { 5318c2ecf20Sopenharmony_ci dev_err(dev, "Missing 'rockchip,cpu' for %s\n", 5328c2ecf20Sopenharmony_ci rockchip_dais[index].name); 5338c2ecf20Sopenharmony_ci return -EINVAL; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci dai = &card->dai_link[card->num_links++]; 5378c2ecf20Sopenharmony_ci *dai = rockchip_dais[index]; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!dai->codecs->name) 5408c2ecf20Sopenharmony_ci dai->codecs->of_node = np_codec; 5418c2ecf20Sopenharmony_ci dai->platforms->of_node = np_cpu; 5428c2ecf20Sopenharmony_ci dai->cpus->of_node = np_cpu; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (card->num_dapm_routes + rockchip_routes[index].num_routes > 5458c2ecf20Sopenharmony_ci num_routes) { 5468c2ecf20Sopenharmony_ci dev_err(dev, "Too many routes\n"); 5478c2ecf20Sopenharmony_ci return -EINVAL; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci memcpy(routes + card->num_dapm_routes, 5518c2ecf20Sopenharmony_ci rockchip_routes[index].routes, 5528c2ecf20Sopenharmony_ci rockchip_routes[index].num_routes * sizeof(*routes)); 5538c2ecf20Sopenharmony_ci card->num_dapm_routes += rockchip_routes[index].num_routes; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int rockchip_sound_probe(struct platform_device *pdev) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct snd_soc_card *card = &rockchip_sound_card; 5628c2ecf20Sopenharmony_ci int ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = rockchip_sound_of_parse_dais(&pdev->dev, card); 5658c2ecf20Sopenharmony_ci if (ret < 0) { 5668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret); 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* Set DMIC wakeup delay */ 5718c2ecf20Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms", 5728c2ecf20Sopenharmony_ci &dmic_wakeup_delay); 5738c2ecf20Sopenharmony_ci if (ret) { 5748c2ecf20Sopenharmony_ci dmic_wakeup_delay = 0; 5758c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 5768c2ecf20Sopenharmony_ci "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n"); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 5808c2ecf20Sopenharmony_ci return devm_snd_soc_register_card(&pdev->dev, card); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_sound_of_match[] = { 5848c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3399-gru-sound", }, 5858c2ecf20Sopenharmony_ci {}, 5868c2ecf20Sopenharmony_ci}; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic struct platform_driver rockchip_sound_driver = { 5898c2ecf20Sopenharmony_ci .probe = rockchip_sound_probe, 5908c2ecf20Sopenharmony_ci .driver = { 5918c2ecf20Sopenharmony_ci .name = DRV_NAME, 5928c2ecf20Sopenharmony_ci .of_match_table = rockchip_sound_of_match, 5938c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5948c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 5958c2ecf20Sopenharmony_ci#endif 5968c2ecf20Sopenharmony_ci }, 5978c2ecf20Sopenharmony_ci}; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cimodule_platform_driver(rockchip_sound_driver); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>"); 6028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rockchip ASoC Machine Driver"); 6038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6048c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 6058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_sound_of_match); 606