162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/gpio.h>
1262306a36Sopenharmony_ci#include <linux/of_gpio.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci#include <linux/input.h>
1762306a36Sopenharmony_ci#include <sound/core.h>
1862306a36Sopenharmony_ci#include <sound/jack.h>
1962306a36Sopenharmony_ci#include <sound/pcm.h>
2062306a36Sopenharmony_ci#include <sound/pcm_params.h>
2162306a36Sopenharmony_ci#include <sound/soc.h>
2262306a36Sopenharmony_ci#include "rockchip_i2s.h"
2362306a36Sopenharmony_ci#include "../codecs/da7219.h"
2462306a36Sopenharmony_ci#include "../codecs/rt5514.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define DRV_NAME "rk3399-gru-sound"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define SOUND_FS	256
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic unsigned int dmic_wakeup_delay;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic struct snd_soc_jack rockchip_sound_jack;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Headset jack detection DAPM pins */
3562306a36Sopenharmony_cistatic struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
3662306a36Sopenharmony_ci	{
3762306a36Sopenharmony_ci		.pin = "Headphones",
3862306a36Sopenharmony_ci		.mask = SND_JACK_HEADPHONE,
3962306a36Sopenharmony_ci	},
4062306a36Sopenharmony_ci	{
4162306a36Sopenharmony_ci		.pin = "Headset Mic",
4262306a36Sopenharmony_ci		.mask = SND_JACK_MICROPHONE,
4362306a36Sopenharmony_ci	},
4462306a36Sopenharmony_ci	{
4562306a36Sopenharmony_ci		.pin = "Line Out",
4662306a36Sopenharmony_ci		.mask = SND_JACK_LINEOUT,
4762306a36Sopenharmony_ci	},
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
5162306a36Sopenharmony_ci	SND_SOC_DAPM_HP("Headphones", NULL),
5262306a36Sopenharmony_ci	SND_SOC_DAPM_SPK("Speakers", NULL),
5362306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("Headset Mic", NULL),
5462306a36Sopenharmony_ci	SND_SOC_DAPM_LINE("Line Out", NULL),
5562306a36Sopenharmony_ci	SND_SOC_DAPM_MIC("Int Mic", NULL),
5662306a36Sopenharmony_ci	SND_SOC_DAPM_LINE("HDMI", NULL),
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const struct snd_kcontrol_new rockchip_controls[] = {
6062306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Headphones"),
6162306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Speakers"),
6262306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Headset Mic"),
6362306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Line Out"),
6462306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Int Mic"),
6562306a36Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("HDMI"),
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
6962306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
7262306a36Sopenharmony_ci	unsigned int mclk;
7362306a36Sopenharmony_ci	int ret;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	mclk = params_rate(params) * SOUND_FS;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
7862306a36Sopenharmony_ci	if (ret) {
7962306a36Sopenharmony_ci		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
8062306a36Sopenharmony_ci				__func__, mclk, ret);
8162306a36Sopenharmony_ci		return ret;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
8862306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
9162306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
9262306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
9362306a36Sopenharmony_ci	unsigned int mclk;
9462306a36Sopenharmony_ci	int ret;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	mclk = params_rate(params) * SOUND_FS;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
9962306a36Sopenharmony_ci				     SND_SOC_CLOCK_OUT);
10062306a36Sopenharmony_ci	if (ret < 0) {
10162306a36Sopenharmony_ci		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
10262306a36Sopenharmony_ci		return ret;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
10662306a36Sopenharmony_ci				     mclk, SND_SOC_CLOCK_IN);
10762306a36Sopenharmony_ci	if (ret) {
10862306a36Sopenharmony_ci		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
10962306a36Sopenharmony_ci				__func__, params_rate(params) * 512, ret);
11062306a36Sopenharmony_ci		return ret;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Wait for DMIC stable */
11462306a36Sopenharmony_ci	msleep(dmic_wakeup_delay);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
12062306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
12362306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
12462306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
12562306a36Sopenharmony_ci	int mclk, ret;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* in bypass mode, the mclk has to be one of the frequencies below */
12862306a36Sopenharmony_ci	switch (params_rate(params)) {
12962306a36Sopenharmony_ci	case 8000:
13062306a36Sopenharmony_ci	case 16000:
13162306a36Sopenharmony_ci	case 24000:
13262306a36Sopenharmony_ci	case 32000:
13362306a36Sopenharmony_ci	case 48000:
13462306a36Sopenharmony_ci	case 64000:
13562306a36Sopenharmony_ci	case 96000:
13662306a36Sopenharmony_ci		mclk = 12288000;
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci	case 11025:
13962306a36Sopenharmony_ci	case 22050:
14062306a36Sopenharmony_ci	case 44100:
14162306a36Sopenharmony_ci	case 88200:
14262306a36Sopenharmony_ci		mclk = 11289600;
14362306a36Sopenharmony_ci		break;
14462306a36Sopenharmony_ci	default:
14562306a36Sopenharmony_ci		return -EINVAL;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
14962306a36Sopenharmony_ci				     SND_SOC_CLOCK_OUT);
15062306a36Sopenharmony_ci	if (ret < 0) {
15162306a36Sopenharmony_ci		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
15262306a36Sopenharmony_ci		return ret;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
15662306a36Sopenharmony_ci				     SND_SOC_CLOCK_IN);
15762306a36Sopenharmony_ci	if (ret < 0) {
15862306a36Sopenharmony_ci		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
15962306a36Sopenharmony_ci		return ret;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
16362306a36Sopenharmony_ci	if (ret < 0) {
16462306a36Sopenharmony_ci		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
16562306a36Sopenharmony_ci		return ret;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return 0;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic struct snd_soc_jack cdn_dp_card_jack;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
17662306a36Sopenharmony_ci	struct snd_soc_card *card = rtd->card;
17762306a36Sopenharmony_ci	int ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Enable jack detection. */
18062306a36Sopenharmony_ci	ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT,
18162306a36Sopenharmony_ci				    &cdn_dp_card_jack);
18262306a36Sopenharmony_ci	if (ret) {
18362306a36Sopenharmony_ci		dev_err(card->dev, "Can't create DP Jack %d\n", ret);
18462306a36Sopenharmony_ci		return ret;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return snd_soc_component_set_jack(component, &cdn_dp_card_jack, NULL);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
19362306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
19462306a36Sopenharmony_ci	int ret;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* We need default MCLK and PLL settings for the accessory detection */
19762306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,
19862306a36Sopenharmony_ci				     SND_SOC_CLOCK_IN);
19962306a36Sopenharmony_ci	if (ret < 0) {
20062306a36Sopenharmony_ci		dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);
20162306a36Sopenharmony_ci		return ret;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
20562306a36Sopenharmony_ci	if (ret < 0) {
20662306a36Sopenharmony_ci		dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);
20762306a36Sopenharmony_ci		return ret;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Enable Headset and 4 Buttons Jack detection */
21162306a36Sopenharmony_ci	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
21262306a36Sopenharmony_ci					 SND_JACK_HEADSET | SND_JACK_LINEOUT |
21362306a36Sopenharmony_ci					 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
21462306a36Sopenharmony_ci					 SND_JACK_BTN_2 | SND_JACK_BTN_3,
21562306a36Sopenharmony_ci					 &rockchip_sound_jack,
21662306a36Sopenharmony_ci					 rockchip_sound_jack_pins,
21762306a36Sopenharmony_ci					 ARRAY_SIZE(rockchip_sound_jack_pins));
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (ret) {
22062306a36Sopenharmony_ci		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
22162306a36Sopenharmony_ci		return ret;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	snd_jack_set_key(
22562306a36Sopenharmony_ci		rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
22662306a36Sopenharmony_ci	snd_jack_set_key(
22762306a36Sopenharmony_ci		rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
22862306a36Sopenharmony_ci	snd_jack_set_key(
22962306a36Sopenharmony_ci		rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
23062306a36Sopenharmony_ci	snd_jack_set_key(
23162306a36Sopenharmony_ci		rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	snd_soc_component_set_jack(component, &rockchip_sound_jack, NULL);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
23962306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
24262306a36Sopenharmony_ci	unsigned int mclk;
24362306a36Sopenharmony_ci	int ret;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	mclk = params_rate(params) * SOUND_FS;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
24862306a36Sopenharmony_ci	if (ret) {
24962306a36Sopenharmony_ci		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
25062306a36Sopenharmony_ci				__func__, mclk, ret);
25162306a36Sopenharmony_ci		return ret;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* Wait for DMIC stable */
25562306a36Sopenharmony_ci	msleep(dmic_wakeup_delay);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int rockchip_sound_startup(struct snd_pcm_substream *substream)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
26562306a36Sopenharmony_ci	return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
26662306a36Sopenharmony_ci			8000, 96000);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_max98357a_ops = {
27062306a36Sopenharmony_ci	.startup = rockchip_sound_startup,
27162306a36Sopenharmony_ci	.hw_params = rockchip_sound_max98357a_hw_params,
27262306a36Sopenharmony_ci};
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_rt5514_ops = {
27562306a36Sopenharmony_ci	.startup = rockchip_sound_startup,
27662306a36Sopenharmony_ci	.hw_params = rockchip_sound_rt5514_hw_params,
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_da7219_ops = {
28062306a36Sopenharmony_ci	.startup = rockchip_sound_startup,
28162306a36Sopenharmony_ci	.hw_params = rockchip_sound_da7219_hw_params,
28262306a36Sopenharmony_ci};
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic const struct snd_soc_ops rockchip_sound_dmic_ops = {
28562306a36Sopenharmony_ci	.startup = rockchip_sound_startup,
28662306a36Sopenharmony_ci	.hw_params = rockchip_sound_dmic_hw_params,
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic struct snd_soc_card rockchip_sound_card = {
29062306a36Sopenharmony_ci	.name = "rk3399-gru-sound",
29162306a36Sopenharmony_ci	.owner = THIS_MODULE,
29262306a36Sopenharmony_ci	.dapm_widgets = rockchip_dapm_widgets,
29362306a36Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
29462306a36Sopenharmony_ci	.controls = rockchip_controls,
29562306a36Sopenharmony_ci	.num_controls = ARRAY_SIZE(rockchip_controls),
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cienum {
29962306a36Sopenharmony_ci	DAILINK_CDNDP,
30062306a36Sopenharmony_ci	DAILINK_DA7219,
30162306a36Sopenharmony_ci	DAILINK_DMIC,
30262306a36Sopenharmony_ci	DAILINK_MAX98357A,
30362306a36Sopenharmony_ci	DAILINK_RT5514,
30462306a36Sopenharmony_ci	DAILINK_RT5514_DSP,
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(cdndp,
30862306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
30962306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")),
31062306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(da7219,
31362306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
31462306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")),
31562306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(dmic,
31862306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
31962306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")),
32062306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(max98357a,
32362306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
32462306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
32562306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(rt5514,
32862306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
32962306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")),
33062306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(rt5514_dsp,
33362306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()),
33462306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_DUMMY()),
33562306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_EMPTY()));
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic const struct snd_soc_dai_link rockchip_dais[] = {
33862306a36Sopenharmony_ci	[DAILINK_CDNDP] = {
33962306a36Sopenharmony_ci		.name = "DP",
34062306a36Sopenharmony_ci		.stream_name = "DP PCM",
34162306a36Sopenharmony_ci		.init = rockchip_sound_cdndp_init,
34262306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
34362306a36Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS,
34462306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(cdndp),
34562306a36Sopenharmony_ci	},
34662306a36Sopenharmony_ci	[DAILINK_DA7219] = {
34762306a36Sopenharmony_ci		.name = "DA7219",
34862306a36Sopenharmony_ci		.stream_name = "DA7219 PCM",
34962306a36Sopenharmony_ci		.init = rockchip_sound_da7219_init,
35062306a36Sopenharmony_ci		.ops = &rockchip_sound_da7219_ops,
35162306a36Sopenharmony_ci		/* set da7219 as slave */
35262306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
35362306a36Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS,
35462306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(da7219),
35562306a36Sopenharmony_ci	},
35662306a36Sopenharmony_ci	[DAILINK_DMIC] = {
35762306a36Sopenharmony_ci		.name = "DMIC",
35862306a36Sopenharmony_ci		.stream_name = "DMIC PCM",
35962306a36Sopenharmony_ci		.ops = &rockchip_sound_dmic_ops,
36062306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
36162306a36Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS,
36262306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(dmic),
36362306a36Sopenharmony_ci	},
36462306a36Sopenharmony_ci	[DAILINK_MAX98357A] = {
36562306a36Sopenharmony_ci		.name = "MAX98357A",
36662306a36Sopenharmony_ci		.stream_name = "MAX98357A PCM",
36762306a36Sopenharmony_ci		.ops = &rockchip_sound_max98357a_ops,
36862306a36Sopenharmony_ci		/* set max98357a as slave */
36962306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
37062306a36Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS,
37162306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(max98357a),
37262306a36Sopenharmony_ci	},
37362306a36Sopenharmony_ci	[DAILINK_RT5514] = {
37462306a36Sopenharmony_ci		.name = "RT5514",
37562306a36Sopenharmony_ci		.stream_name = "RT5514 PCM",
37662306a36Sopenharmony_ci		.ops = &rockchip_sound_rt5514_ops,
37762306a36Sopenharmony_ci		/* set rt5514 as slave */
37862306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
37962306a36Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS,
38062306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(rt5514),
38162306a36Sopenharmony_ci	},
38262306a36Sopenharmony_ci	/* RT5514 DSP for voice wakeup via spi bus */
38362306a36Sopenharmony_ci	[DAILINK_RT5514_DSP] = {
38462306a36Sopenharmony_ci		.name = "RT5514 DSP",
38562306a36Sopenharmony_ci		.stream_name = "Wake on Voice",
38662306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(rt5514_dsp),
38762306a36Sopenharmony_ci	},
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
39162306a36Sopenharmony_ci	/* Output */
39262306a36Sopenharmony_ci	{"HDMI", NULL, "TX"},
39362306a36Sopenharmony_ci};
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
39662306a36Sopenharmony_ci	/* Output */
39762306a36Sopenharmony_ci	{"Headphones", NULL, "HPL"},
39862306a36Sopenharmony_ci	{"Headphones", NULL, "HPR"},
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Input */
40162306a36Sopenharmony_ci	{"MIC", NULL, "Headset Mic"},
40262306a36Sopenharmony_ci};
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
40562306a36Sopenharmony_ci	/* Input */
40662306a36Sopenharmony_ci	{"DMic", NULL, "Int Mic"},
40762306a36Sopenharmony_ci};
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
41062306a36Sopenharmony_ci	/* Output */
41162306a36Sopenharmony_ci	{"Speakers", NULL, "Speaker"},
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
41562306a36Sopenharmony_ci	/* Input */
41662306a36Sopenharmony_ci	{"DMIC1L", NULL, "Int Mic"},
41762306a36Sopenharmony_ci	{"DMIC1R", NULL, "Int Mic"},
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistruct rockchip_sound_route {
42162306a36Sopenharmony_ci	const struct snd_soc_dapm_route *routes;
42262306a36Sopenharmony_ci	int num_routes;
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic const struct rockchip_sound_route rockchip_routes[] = {
42662306a36Sopenharmony_ci	[DAILINK_CDNDP] = {
42762306a36Sopenharmony_ci		.routes = rockchip_sound_cdndp_routes,
42862306a36Sopenharmony_ci		.num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),
42962306a36Sopenharmony_ci	},
43062306a36Sopenharmony_ci	[DAILINK_DA7219] = {
43162306a36Sopenharmony_ci		.routes = rockchip_sound_da7219_routes,
43262306a36Sopenharmony_ci		.num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci	[DAILINK_DMIC] = {
43562306a36Sopenharmony_ci		.routes = rockchip_sound_dmic_routes,
43662306a36Sopenharmony_ci		.num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),
43762306a36Sopenharmony_ci	},
43862306a36Sopenharmony_ci	[DAILINK_MAX98357A] = {
43962306a36Sopenharmony_ci		.routes = rockchip_sound_max98357a_routes,
44062306a36Sopenharmony_ci		.num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),
44162306a36Sopenharmony_ci	},
44262306a36Sopenharmony_ci	[DAILINK_RT5514] = {
44362306a36Sopenharmony_ci		.routes = rockchip_sound_rt5514_routes,
44462306a36Sopenharmony_ci		.num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),
44562306a36Sopenharmony_ci	},
44662306a36Sopenharmony_ci	[DAILINK_RT5514_DSP] = {},
44762306a36Sopenharmony_ci};
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistruct dailink_match_data {
45062306a36Sopenharmony_ci	const char *compatible;
45162306a36Sopenharmony_ci	struct bus_type *bus_type;
45262306a36Sopenharmony_ci};
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic const struct dailink_match_data dailink_match[] = {
45562306a36Sopenharmony_ci	[DAILINK_CDNDP] = {
45662306a36Sopenharmony_ci		.compatible = "rockchip,rk3399-cdn-dp",
45762306a36Sopenharmony_ci	},
45862306a36Sopenharmony_ci	[DAILINK_DA7219] = {
45962306a36Sopenharmony_ci		.compatible = "dlg,da7219",
46062306a36Sopenharmony_ci	},
46162306a36Sopenharmony_ci	[DAILINK_DMIC] = {
46262306a36Sopenharmony_ci		.compatible = "dmic-codec",
46362306a36Sopenharmony_ci	},
46462306a36Sopenharmony_ci	[DAILINK_MAX98357A] = {
46562306a36Sopenharmony_ci		.compatible = "maxim,max98357a",
46662306a36Sopenharmony_ci	},
46762306a36Sopenharmony_ci	[DAILINK_RT5514] = {
46862306a36Sopenharmony_ci		.compatible = "realtek,rt5514",
46962306a36Sopenharmony_ci		.bus_type = &i2c_bus_type,
47062306a36Sopenharmony_ci	},
47162306a36Sopenharmony_ci	[DAILINK_RT5514_DSP] = {
47262306a36Sopenharmony_ci		.compatible = "realtek,rt5514",
47362306a36Sopenharmony_ci		.bus_type = &spi_bus_type,
47462306a36Sopenharmony_ci	},
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int rockchip_sound_codec_node_match(struct device_node *np_codec)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct device *dev;
48062306a36Sopenharmony_ci	int i;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {
48362306a36Sopenharmony_ci		if (!of_device_is_compatible(np_codec,
48462306a36Sopenharmony_ci					     dailink_match[i].compatible))
48562306a36Sopenharmony_ci			continue;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (dailink_match[i].bus_type) {
48862306a36Sopenharmony_ci			dev = bus_find_device_by_of_node(dailink_match[i].bus_type,
48962306a36Sopenharmony_ci							 np_codec);
49062306a36Sopenharmony_ci			if (!dev)
49162306a36Sopenharmony_ci				continue;
49262306a36Sopenharmony_ci			put_device(dev);
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		return i;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci	return -1;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int rockchip_sound_of_parse_dais(struct device *dev,
50162306a36Sopenharmony_ci					struct snd_soc_card *card)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct device_node *np_cpu, *np_cpu0, *np_cpu1;
50462306a36Sopenharmony_ci	struct device_node *np_codec;
50562306a36Sopenharmony_ci	struct snd_soc_dai_link *dai;
50662306a36Sopenharmony_ci	struct snd_soc_dapm_route *routes;
50762306a36Sopenharmony_ci	int i, index;
50862306a36Sopenharmony_ci	int num_routes;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
51162306a36Sopenharmony_ci				      GFP_KERNEL);
51262306a36Sopenharmony_ci	if (!card->dai_link)
51362306a36Sopenharmony_ci		return -ENOMEM;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	num_routes = 0;
51662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
51762306a36Sopenharmony_ci		num_routes += rockchip_routes[i].num_routes;
51862306a36Sopenharmony_ci	routes = devm_kcalloc(dev, num_routes, sizeof(*routes),
51962306a36Sopenharmony_ci			      GFP_KERNEL);
52062306a36Sopenharmony_ci	if (!routes)
52162306a36Sopenharmony_ci		return -ENOMEM;
52262306a36Sopenharmony_ci	card->dapm_routes = routes;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
52562306a36Sopenharmony_ci	np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	card->num_dapm_routes = 0;
52862306a36Sopenharmony_ci	card->num_links = 0;
52962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
53062306a36Sopenharmony_ci		np_codec = of_parse_phandle(dev->of_node,
53162306a36Sopenharmony_ci					    "rockchip,codec", i);
53262306a36Sopenharmony_ci		if (!np_codec)
53362306a36Sopenharmony_ci			break;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		if (!of_device_is_available(np_codec))
53662306a36Sopenharmony_ci			continue;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		index = rockchip_sound_codec_node_match(np_codec);
53962306a36Sopenharmony_ci		if (index < 0)
54062306a36Sopenharmony_ci			continue;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		switch (index) {
54362306a36Sopenharmony_ci		case DAILINK_CDNDP:
54462306a36Sopenharmony_ci			np_cpu = np_cpu1;
54562306a36Sopenharmony_ci			break;
54662306a36Sopenharmony_ci		case DAILINK_RT5514_DSP:
54762306a36Sopenharmony_ci			np_cpu = np_codec;
54862306a36Sopenharmony_ci			break;
54962306a36Sopenharmony_ci		default:
55062306a36Sopenharmony_ci			np_cpu = np_cpu0;
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		if (!np_cpu) {
55562306a36Sopenharmony_ci			dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
55662306a36Sopenharmony_ci				rockchip_dais[index].name);
55762306a36Sopenharmony_ci			return -EINVAL;
55862306a36Sopenharmony_ci		}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		dai = &card->dai_link[card->num_links++];
56162306a36Sopenharmony_ci		*dai = rockchip_dais[index];
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		if (!dai->codecs->name)
56462306a36Sopenharmony_ci			dai->codecs->of_node = np_codec;
56562306a36Sopenharmony_ci		dai->platforms->of_node = np_cpu;
56662306a36Sopenharmony_ci		dai->cpus->of_node = np_cpu;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		if (card->num_dapm_routes + rockchip_routes[index].num_routes >
56962306a36Sopenharmony_ci		    num_routes) {
57062306a36Sopenharmony_ci			dev_err(dev, "Too many routes\n");
57162306a36Sopenharmony_ci			return -EINVAL;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		memcpy(routes + card->num_dapm_routes,
57562306a36Sopenharmony_ci		       rockchip_routes[index].routes,
57662306a36Sopenharmony_ci		       rockchip_routes[index].num_routes * sizeof(*routes));
57762306a36Sopenharmony_ci		card->num_dapm_routes += rockchip_routes[index].num_routes;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic int rockchip_sound_probe(struct platform_device *pdev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct snd_soc_card *card = &rockchip_sound_card;
58662306a36Sopenharmony_ci	int ret;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
58962306a36Sopenharmony_ci	if (ret < 0) {
59062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
59162306a36Sopenharmony_ci		return ret;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* Set DMIC wakeup delay */
59562306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
59662306a36Sopenharmony_ci					&dmic_wakeup_delay);
59762306a36Sopenharmony_ci	if (ret) {
59862306a36Sopenharmony_ci		dmic_wakeup_delay = 0;
59962306a36Sopenharmony_ci		dev_dbg(&pdev->dev,
60062306a36Sopenharmony_ci			"no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	card->dev = &pdev->dev;
60462306a36Sopenharmony_ci	return devm_snd_soc_register_card(&pdev->dev, card);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic const struct of_device_id rockchip_sound_of_match[] = {
60862306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3399-gru-sound", },
60962306a36Sopenharmony_ci	{},
61062306a36Sopenharmony_ci};
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic struct platform_driver rockchip_sound_driver = {
61362306a36Sopenharmony_ci	.probe = rockchip_sound_probe,
61462306a36Sopenharmony_ci	.driver = {
61562306a36Sopenharmony_ci		.name = DRV_NAME,
61662306a36Sopenharmony_ci		.of_match_table = rockchip_sound_of_match,
61762306a36Sopenharmony_ci#ifdef CONFIG_PM
61862306a36Sopenharmony_ci		.pm = &snd_soc_pm_ops,
61962306a36Sopenharmony_ci#endif
62062306a36Sopenharmony_ci	},
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cimodule_platform_driver(rockchip_sound_driver);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciMODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
62662306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
62762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
62862306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME);
62962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
630