162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// rk817 ALSA SoC Audio driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/device.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/mfd/rk808.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_gpio.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/regmap.h>
1662306a36Sopenharmony_ci#include <sound/core.h>
1762306a36Sopenharmony_ci#include <sound/pcm_params.h>
1862306a36Sopenharmony_ci#include <sound/soc.h>
1962306a36Sopenharmony_ci#include <sound/tlv.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct rk817_codec_priv {
2262306a36Sopenharmony_ci	struct snd_soc_component *component;
2362306a36Sopenharmony_ci	struct rk808 *rk808;
2462306a36Sopenharmony_ci	struct clk *mclk;
2562306a36Sopenharmony_ci	unsigned int stereo_sysclk;
2662306a36Sopenharmony_ci	bool mic_in_differential;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/*
3062306a36Sopenharmony_ci * This sets the codec up with the values defined in the default implementation including the APLL
3162306a36Sopenharmony_ci * from the Rockchip vendor kernel. I do not know if these values are universal despite differing
3262306a36Sopenharmony_ci * from the default values defined above and taken from the datasheet, or implementation specific.
3362306a36Sopenharmony_ci * I don't have another implementation to compare from the Rockchip sources. Hard-coding for now.
3462306a36Sopenharmony_ci * Additionally, I do not know according to the documentation the units accepted for the clock
3562306a36Sopenharmony_ci * values, so for the moment those are left unvalidated.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int rk817_init(struct snd_soc_component *component)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_DDAC_POPD_DACST, 0x02);
4362306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_DDAC_SR_LMT0, 0x02);
4462306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_DADC_SR_ACL0, 0x02);
4562306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_DTOP_VUCTIME, 0xf4);
4662306a36Sopenharmony_ci	if (rk817->mic_in_differential) {
4762306a36Sopenharmony_ci		snd_soc_component_update_bits(component, RK817_CODEC_AMIC_CFG0, MIC_DIFF_MASK,
4862306a36Sopenharmony_ci			MIC_DIFF_EN);
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int rk817_set_component_pll(struct snd_soc_component *component,
5562306a36Sopenharmony_ci		int pll_id, int source, unsigned int freq_in,
5662306a36Sopenharmony_ci		unsigned int freq_out)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	/* Set resistor value and charge pump current for PLL. */
5962306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_APLL_CFG1, 0x58);
6062306a36Sopenharmony_ci	/* Set the PLL feedback clock divide value (values not documented). */
6162306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_APLL_CFG2, 0x2d);
6262306a36Sopenharmony_ci	/* Set the PLL pre-divide value (values not documented). */
6362306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_APLL_CFG3, 0x0c);
6462306a36Sopenharmony_ci	/* Set the PLL VCO output clock divide and PLL divided ratio of PLL High Clk (values not
6562306a36Sopenharmony_ci	 * documented).
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0xa5);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/*
7362306a36Sopenharmony_ci * DDAC/DADC L/R volume setting
7462306a36Sopenharmony_ci * 0db~-95db, 0.375db/step, for example:
7562306a36Sopenharmony_ci * 0x00: 0dB
7662306a36Sopenharmony_ci * 0xff: -95dB
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX(rk817_vol_tlv, -9500, 0);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/*
8262306a36Sopenharmony_ci * PGA GAIN L/R volume setting
8362306a36Sopenharmony_ci * 27db~-18db, 3db/step, for example:
8462306a36Sopenharmony_ci * 0x0: -18dB
8562306a36Sopenharmony_ci * 0xf: 27dB
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX(rk817_gain_tlv, -1800, 2700);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic const struct snd_kcontrol_new rk817_volume_controls[] = {
9162306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume", RK817_CODEC_DDAC_VOLL,
9262306a36Sopenharmony_ci		RK817_CODEC_DDAC_VOLR, 0, 0x00, 0xff, 1, rk817_vol_tlv),
9362306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume", RK817_CODEC_DADC_VOLL,
9462306a36Sopenharmony_ci		RK817_CODEC_DADC_VOLR, 0, 0x00, 0xff, 1, rk817_vol_tlv),
9562306a36Sopenharmony_ci	SOC_DOUBLE_TLV("Mic Capture Gain", RK817_CODEC_DMIC_PGA_GAIN, 4, 0, 0xf, 0,
9662306a36Sopenharmony_ci		rk817_gain_tlv),
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* Since the speaker output and L headphone pin are internally the same, make audio path mutually
10062306a36Sopenharmony_ci * exclusive with a mux.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const char *dac_mux_text[] = {
10462306a36Sopenharmony_ci	"HP",
10562306a36Sopenharmony_ci	"SPK",
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_VIRT_DECL(dac_enum, dac_mux_text);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_mux =
11162306a36Sopenharmony_ci	SOC_DAPM_ENUM("Playback Mux", dac_enum);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget rk817_dapm_widgets[] = {
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* capture/playback common */
11662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("LDO Regulator", RK817_CODEC_AREF_RTCFG1, 6, 0, NULL, 0),
11762306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("IBIAS Block", RK817_CODEC_AREF_RTCFG1, 2, 1, NULL, 0),
11862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("VAvg Buffer", RK817_CODEC_AREF_RTCFG1, 1, 1, NULL, 0),
11962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("PLL Power", RK817_CODEC_APLL_CFG5, 0, 1, NULL, 0),
12062306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S TX1 Transfer Start", RK817_CODEC_DI2S_RXCMD_TSD, 5, 0, NULL, 0),
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* capture path common */
12362306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("ADC Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 7, 0, NULL, 0),
12462306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S TX Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 6, 0, NULL, 0),
12562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("ADC Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 5, 0, NULL, 0),
12662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S TX Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 4, 0, NULL, 0),
12762306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("MIC Power On", RK817_CODEC_AMIC_CFG0, 6, 1, NULL, 0),
12862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S TX3 Transfer Start", RK817_CODEC_DI2S_TXCR3_TXCMD, 7, 0, NULL, 0),
12962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S TX3 Right Justified", RK817_CODEC_DI2S_TXCR3_TXCMD, 3, 0, NULL, 0),
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* capture path L */
13262306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC L", "Capture", RK817_CODEC_AADC_CFG0, 7, 1),
13362306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("PGA L Power On", RK817_CODEC_AMIC_CFG0, 5, 1, NULL, 0),
13462306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Mic Boost L1", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0),
13562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Mic Boost L2", RK817_CODEC_AMIC_CFG0, 2, 0, NULL, 0),
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* capture path R */
13862306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC R", "Capture", RK817_CODEC_AADC_CFG0, 6, 1),
13962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("PGA R Power On", RK817_CODEC_AMIC_CFG0, 4, 1, NULL, 0),
14062306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Mic Boost R1", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0),
14162306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Mic Boost R2", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0),
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* playback path common */
14462306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 3, 0, NULL, 0),
14562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S RX Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 2, 0, NULL, 0),
14662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 1, 0, NULL, 0),
14762306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S RX Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 0, 0, NULL, 0),
14862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC Bias", RK817_CODEC_ADAC_CFG1, 3, 1, NULL, 0),
14962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("DAC Mute Off", RK817_CODEC_DDAC_MUTE_MIXCTL, 0, 1, NULL, 0),
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* playback path speaker */
15262306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D Mode", RK817_CODEC_DDAC_MUTE_MIXCTL, 4, 0, NULL, 0),
15362306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("High Pass Filter", RK817_CODEC_DDAC_MUTE_MIXCTL, 7, 0, NULL, 0),
15462306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("SPK DAC", "Playback", RK817_CODEC_ADAC_CFG1, 2, 1),
15562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Enable Class D", RK817_CODEC_ACLASSD_CFG1, 7, 0, NULL, 0),
15662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Disable Class D Mute Ramp", RK817_CODEC_ACLASSD_CFG1, 6, 1, NULL, 0),
15762306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D Mute Rate 1", RK817_CODEC_ACLASSD_CFG1, 3, 0, NULL, 0),
15862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D Mute Rate 2", RK817_CODEC_ACLASSD_CFG1, 2, 1, NULL, 0),
15962306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D OCPP 2", RK817_CODEC_ACLASSD_CFG2, 5, 0, NULL, 0),
16062306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D OCPP 3", RK817_CODEC_ACLASSD_CFG2, 4, 0, NULL, 0),
16162306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D OCPN 2", RK817_CODEC_ACLASSD_CFG2, 1, 0, NULL, 0),
16262306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Class D OCPN 3", RK817_CODEC_ACLASSD_CFG2, 0, 0, NULL, 0),
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* playback path headphones */
16562306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", RK817_CODEC_AHP_CP, 4, 0, NULL, 0),
16662306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Headphone CP Discharge LDO", RK817_CODEC_AHP_CP, 3, 1, NULL, 0),
16762306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Headphone OStage", RK817_CODEC_AHP_CFG0, 6, 1, NULL, 0),
16862306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Headphone Pre Amp", RK817_CODEC_AHP_CFG0, 5, 1, NULL, 0),
16962306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC L", "Playback", RK817_CODEC_ADAC_CFG1, 1, 1),
17062306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC R", "Playback", RK817_CODEC_ADAC_CFG1, 0, 1),
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Mux for input/output path selection */
17362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Playback Mux", SND_SOC_NOPM, 1, 0, &dac_mux),
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Pins for Simple Card Bindings */
17662306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MICL"),
17762306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MICR"),
17862306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HPOL"),
17962306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HPOR"),
18062306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("SPKO"),
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rk817_dapm_routes[] = {
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* capture path */
18662306a36Sopenharmony_ci	/* left mic */
18762306a36Sopenharmony_ci	{"ADC L", NULL, "LDO Regulator"},
18862306a36Sopenharmony_ci	{"ADC L", NULL, "IBIAS Block"},
18962306a36Sopenharmony_ci	{"ADC L", NULL, "VAvg Buffer"},
19062306a36Sopenharmony_ci	{"ADC L", NULL, "PLL Power"},
19162306a36Sopenharmony_ci	{"ADC L", NULL, "ADC Clock"},
19262306a36Sopenharmony_ci	{"ADC L", NULL, "I2S TX Clock"},
19362306a36Sopenharmony_ci	{"ADC L", NULL, "ADC Channel Enable"},
19462306a36Sopenharmony_ci	{"ADC L", NULL, "I2S TX Channel Enable"},
19562306a36Sopenharmony_ci	{"ADC L", NULL, "I2S TX1 Transfer Start"},
19662306a36Sopenharmony_ci	{"MICL", NULL, "MIC Power On"},
19762306a36Sopenharmony_ci	{"MICL", NULL, "PGA L Power On"},
19862306a36Sopenharmony_ci	{"MICL", NULL, "Mic Boost L1"},
19962306a36Sopenharmony_ci	{"MICL", NULL, "Mic Boost L2"},
20062306a36Sopenharmony_ci	{"MICL", NULL, "I2S TX3 Transfer Start"},
20162306a36Sopenharmony_ci	{"MICL", NULL, "I2S TX3 Right Justified"},
20262306a36Sopenharmony_ci	{"ADC L", NULL, "MICL"},
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* right mic */
20562306a36Sopenharmony_ci	{"ADC R", NULL, "LDO Regulator"},
20662306a36Sopenharmony_ci	{"ADC R", NULL, "IBIAS Block"},
20762306a36Sopenharmony_ci	{"ADC R", NULL, "VAvg Buffer"},
20862306a36Sopenharmony_ci	{"ADC R", NULL, "PLL Power"},
20962306a36Sopenharmony_ci	{"ADC R", NULL, "ADC Clock"},
21062306a36Sopenharmony_ci	{"ADC R", NULL, "I2S TX Clock"},
21162306a36Sopenharmony_ci	{"ADC R", NULL, "ADC Channel Enable"},
21262306a36Sopenharmony_ci	{"ADC R", NULL, "I2S TX Channel Enable"},
21362306a36Sopenharmony_ci	{"ADC R", NULL, "I2S TX1 Transfer Start"},
21462306a36Sopenharmony_ci	{"MICR", NULL, "MIC Power On"},
21562306a36Sopenharmony_ci	{"MICR", NULL, "PGA R Power On"},
21662306a36Sopenharmony_ci	{"MICR", NULL, "Mic Boost R1"},
21762306a36Sopenharmony_ci	{"MICR", NULL, "Mic Boost R2"},
21862306a36Sopenharmony_ci	{"MICR", NULL, "I2S TX3 Transfer Start"},
21962306a36Sopenharmony_ci	{"MICR", NULL, "I2S TX3 Right Justified"},
22062306a36Sopenharmony_ci	{"ADC R", NULL, "MICR"},
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* playback path */
22362306a36Sopenharmony_ci	/* speaker path */
22462306a36Sopenharmony_ci	{"SPK DAC", NULL, "LDO Regulator"},
22562306a36Sopenharmony_ci	{"SPK DAC", NULL, "IBIAS Block"},
22662306a36Sopenharmony_ci	{"SPK DAC", NULL, "VAvg Buffer"},
22762306a36Sopenharmony_ci	{"SPK DAC", NULL, "PLL Power"},
22862306a36Sopenharmony_ci	{"SPK DAC", NULL, "I2S TX1 Transfer Start"},
22962306a36Sopenharmony_ci	{"SPK DAC", NULL, "DAC Clock"},
23062306a36Sopenharmony_ci	{"SPK DAC", NULL, "I2S RX Clock"},
23162306a36Sopenharmony_ci	{"SPK DAC", NULL, "DAC Channel Enable"},
23262306a36Sopenharmony_ci	{"SPK DAC", NULL, "I2S RX Channel Enable"},
23362306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D Mode"},
23462306a36Sopenharmony_ci	{"SPK DAC", NULL, "DAC Bias"},
23562306a36Sopenharmony_ci	{"SPK DAC", NULL, "DAC Mute Off"},
23662306a36Sopenharmony_ci	{"SPK DAC", NULL, "Enable Class D"},
23762306a36Sopenharmony_ci	{"SPK DAC", NULL, "Disable Class D Mute Ramp"},
23862306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D Mute Rate 1"},
23962306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D Mute Rate 2"},
24062306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D OCPP 2"},
24162306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D OCPP 3"},
24262306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D OCPN 2"},
24362306a36Sopenharmony_ci	{"SPK DAC", NULL, "Class D OCPN 3"},
24462306a36Sopenharmony_ci	{"SPK DAC", NULL, "High Pass Filter"},
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* headphone path L */
24762306a36Sopenharmony_ci	{"DAC L", NULL, "LDO Regulator"},
24862306a36Sopenharmony_ci	{"DAC L", NULL, "IBIAS Block"},
24962306a36Sopenharmony_ci	{"DAC L", NULL, "VAvg Buffer"},
25062306a36Sopenharmony_ci	{"DAC L", NULL, "PLL Power"},
25162306a36Sopenharmony_ci	{"DAC L", NULL, "I2S TX1 Transfer Start"},
25262306a36Sopenharmony_ci	{"DAC L", NULL, "DAC Clock"},
25362306a36Sopenharmony_ci	{"DAC L", NULL, "I2S RX Clock"},
25462306a36Sopenharmony_ci	{"DAC L", NULL, "DAC Channel Enable"},
25562306a36Sopenharmony_ci	{"DAC L", NULL, "I2S RX Channel Enable"},
25662306a36Sopenharmony_ci	{"DAC L", NULL, "DAC Bias"},
25762306a36Sopenharmony_ci	{"DAC L", NULL, "DAC Mute Off"},
25862306a36Sopenharmony_ci	{"DAC L", NULL, "Headphone Charge Pump"},
25962306a36Sopenharmony_ci	{"DAC L", NULL, "Headphone CP Discharge LDO"},
26062306a36Sopenharmony_ci	{"DAC L", NULL, "Headphone OStage"},
26162306a36Sopenharmony_ci	{"DAC L", NULL, "Headphone Pre Amp"},
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* headphone path R */
26462306a36Sopenharmony_ci	{"DAC R", NULL, "LDO Regulator"},
26562306a36Sopenharmony_ci	{"DAC R", NULL, "IBIAS Block"},
26662306a36Sopenharmony_ci	{"DAC R", NULL, "VAvg Buffer"},
26762306a36Sopenharmony_ci	{"DAC R", NULL, "PLL Power"},
26862306a36Sopenharmony_ci	{"DAC R", NULL, "I2S TX1 Transfer Start"},
26962306a36Sopenharmony_ci	{"DAC R", NULL, "DAC Clock"},
27062306a36Sopenharmony_ci	{"DAC R", NULL, "I2S RX Clock"},
27162306a36Sopenharmony_ci	{"DAC R", NULL, "DAC Channel Enable"},
27262306a36Sopenharmony_ci	{"DAC R", NULL, "I2S RX Channel Enable"},
27362306a36Sopenharmony_ci	{"DAC R", NULL, "DAC Bias"},
27462306a36Sopenharmony_ci	{"DAC R", NULL, "DAC Mute Off"},
27562306a36Sopenharmony_ci	{"DAC R", NULL, "Headphone Charge Pump"},
27662306a36Sopenharmony_ci	{"DAC R", NULL, "Headphone CP Discharge LDO"},
27762306a36Sopenharmony_ci	{"DAC R", NULL, "Headphone OStage"},
27862306a36Sopenharmony_ci	{"DAC R", NULL, "Headphone Pre Amp"},
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* mux path for output selection */
28162306a36Sopenharmony_ci	{"Playback Mux", "HP", "DAC L"},
28262306a36Sopenharmony_ci	{"Playback Mux", "HP", "DAC R"},
28362306a36Sopenharmony_ci	{"Playback Mux", "SPK", "SPK DAC"},
28462306a36Sopenharmony_ci	{"SPKO", NULL, "Playback Mux"},
28562306a36Sopenharmony_ci	{"HPOL", NULL, "Playback Mux"},
28662306a36Sopenharmony_ci	{"HPOR", NULL, "Playback Mux"},
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int rk817_set_dai_sysclk(struct snd_soc_dai *codec_dai,
29062306a36Sopenharmony_ci				int clk_id, unsigned int freq, int dir)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
29362306a36Sopenharmony_ci	struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	rk817->stereo_sysclk = freq;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int rk817_set_dai_fmt(struct snd_soc_dai *codec_dai,
30162306a36Sopenharmony_ci			     unsigned int fmt)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
30462306a36Sopenharmony_ci	unsigned int i2s_mst = 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
30762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
30862306a36Sopenharmony_ci		i2s_mst |= RK817_I2S_MODE_SLV;
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
31162306a36Sopenharmony_ci		i2s_mst |= RK817_I2S_MODE_MST;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	default:
31462306a36Sopenharmony_ci		dev_err(component->dev, "%s : set master mask failed!\n", __func__);
31562306a36Sopenharmony_ci		return -EINVAL;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	snd_soc_component_update_bits(component, RK817_CODEC_DI2S_CKM,
31962306a36Sopenharmony_ci				      RK817_I2S_MODE_MASK, i2s_mst);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int rk817_hw_params(struct snd_pcm_substream *substream,
32562306a36Sopenharmony_ci			   struct snd_pcm_hw_params *params,
32662306a36Sopenharmony_ci			    struct snd_soc_dai *dai)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	switch (params_format(params)) {
33162306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
33262306a36Sopenharmony_ci		snd_soc_component_write(component, RK817_CODEC_DI2S_RXCR2,
33362306a36Sopenharmony_ci					VDW_RX_16BITS);
33462306a36Sopenharmony_ci		snd_soc_component_write(component, RK817_CODEC_DI2S_TXCR2,
33562306a36Sopenharmony_ci					VDW_TX_16BITS);
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
33862306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
33962306a36Sopenharmony_ci		snd_soc_component_write(component, RK817_CODEC_DI2S_RXCR2,
34062306a36Sopenharmony_ci					VDW_RX_24BITS);
34162306a36Sopenharmony_ci		snd_soc_component_write(component, RK817_CODEC_DI2S_TXCR2,
34262306a36Sopenharmony_ci					VDW_TX_24BITS);
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	default:
34562306a36Sopenharmony_ci		return -EINVAL;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (mute)
35662306a36Sopenharmony_ci		snd_soc_component_update_bits(component,
35762306a36Sopenharmony_ci					      RK817_CODEC_DDAC_MUTE_MIXCTL,
35862306a36Sopenharmony_ci					      DACMT_MASK, DACMT_ENABLE);
35962306a36Sopenharmony_ci	else
36062306a36Sopenharmony_ci		snd_soc_component_update_bits(component,
36162306a36Sopenharmony_ci					      RK817_CODEC_DDAC_MUTE_MIXCTL,
36262306a36Sopenharmony_ci					      DACMT_MASK, DACMT_DISABLE);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci#define RK817_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
36862306a36Sopenharmony_ci			      SNDRV_PCM_RATE_16000 |	\
36962306a36Sopenharmony_ci			      SNDRV_PCM_RATE_32000 |	\
37062306a36Sopenharmony_ci			      SNDRV_PCM_RATE_44100 |	\
37162306a36Sopenharmony_ci			      SNDRV_PCM_RATE_48000 |	\
37262306a36Sopenharmony_ci			      SNDRV_PCM_RATE_96000)
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci#define RK817_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
37562306a36Sopenharmony_ci			      SNDRV_PCM_RATE_16000 |	\
37662306a36Sopenharmony_ci			      SNDRV_PCM_RATE_32000 |	\
37762306a36Sopenharmony_ci			      SNDRV_PCM_RATE_44100 |	\
37862306a36Sopenharmony_ci			      SNDRV_PCM_RATE_48000 |	\
37962306a36Sopenharmony_ci			      SNDRV_PCM_RATE_96000)
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci#define RK817_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
38262306a36Sopenharmony_ci			SNDRV_PCM_FMTBIT_S20_3LE |\
38362306a36Sopenharmony_ci			SNDRV_PCM_FMTBIT_S24_LE |\
38462306a36Sopenharmony_ci			SNDRV_PCM_FMTBIT_S32_LE)
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rk817_dai_ops = {
38762306a36Sopenharmony_ci	.hw_params	= rk817_hw_params,
38862306a36Sopenharmony_ci	.set_fmt	= rk817_set_dai_fmt,
38962306a36Sopenharmony_ci	.set_sysclk	= rk817_set_dai_sysclk,
39062306a36Sopenharmony_ci	.mute_stream	= rk817_digital_mute,
39162306a36Sopenharmony_ci	.no_capture_mute	= 1,
39262306a36Sopenharmony_ci};
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic struct snd_soc_dai_driver rk817_dai[] = {
39562306a36Sopenharmony_ci	{
39662306a36Sopenharmony_ci		.name = "rk817-hifi",
39762306a36Sopenharmony_ci		.playback = {
39862306a36Sopenharmony_ci			.stream_name = "Playback",
39962306a36Sopenharmony_ci			.channels_min = 2,
40062306a36Sopenharmony_ci			.channels_max = 8,
40162306a36Sopenharmony_ci			.rates = RK817_PLAYBACK_RATES,
40262306a36Sopenharmony_ci			.formats = RK817_FORMATS,
40362306a36Sopenharmony_ci		},
40462306a36Sopenharmony_ci		.capture = {
40562306a36Sopenharmony_ci			.stream_name = "Capture",
40662306a36Sopenharmony_ci			.channels_min = 1,
40762306a36Sopenharmony_ci			.channels_max = 2,
40862306a36Sopenharmony_ci			.rates = RK817_CAPTURE_RATES,
40962306a36Sopenharmony_ci			.formats = RK817_FORMATS,
41062306a36Sopenharmony_ci		},
41162306a36Sopenharmony_ci		.ops = &rk817_dai_ops,
41262306a36Sopenharmony_ci	},
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int rk817_probe(struct snd_soc_component *component)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component);
41862306a36Sopenharmony_ci	struct rk808 *rk808 = dev_get_drvdata(component->dev->parent);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	snd_soc_component_init_regmap(component, rk808->regmap);
42162306a36Sopenharmony_ci	rk817->component = component;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	snd_soc_component_write(component, RK817_CODEC_DTOP_LPT_SRST, 0x40);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	rk817_init(component);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* setting initial pll values so that we can continue to leverage simple-audio-card.
42862306a36Sopenharmony_ci	 * The values aren't important since no parameters are used.
42962306a36Sopenharmony_ci	 */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	snd_soc_component_set_pll(component, 0, 0, 0, 0);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic void rk817_remove(struct snd_soc_component *component)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	snd_soc_component_exit_regmap(component);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_rk817 = {
44262306a36Sopenharmony_ci	.probe = rk817_probe,
44362306a36Sopenharmony_ci	.remove = rk817_remove,
44462306a36Sopenharmony_ci	.idle_bias_on = 1,
44562306a36Sopenharmony_ci	.use_pmdown_time = 1,
44662306a36Sopenharmony_ci	.endianness = 1,
44762306a36Sopenharmony_ci	.controls = rk817_volume_controls,
44862306a36Sopenharmony_ci	.num_controls = ARRAY_SIZE(rk817_volume_controls),
44962306a36Sopenharmony_ci	.dapm_routes = rk817_dapm_routes,
45062306a36Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(rk817_dapm_routes),
45162306a36Sopenharmony_ci	.dapm_widgets = rk817_dapm_widgets,
45262306a36Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(rk817_dapm_widgets),
45362306a36Sopenharmony_ci	.set_pll = rk817_set_component_pll,
45462306a36Sopenharmony_ci};
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void rk817_codec_parse_dt_property(struct device *dev,
45762306a36Sopenharmony_ci					 struct rk817_codec_priv *rk817)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct device_node *node;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	node = of_get_child_by_name(dev->parent->of_node, "codec");
46262306a36Sopenharmony_ci	if (!node) {
46362306a36Sopenharmony_ci		dev_dbg(dev, "%s() Can not get child: codec\n",
46462306a36Sopenharmony_ci			__func__);
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	rk817->mic_in_differential =
46862306a36Sopenharmony_ci			of_property_read_bool(node, "rockchip,mic-in-differential");
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	of_node_put(node);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int rk817_platform_probe(struct platform_device *pdev)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
47662306a36Sopenharmony_ci	struct rk817_codec_priv *rk817_codec_data;
47762306a36Sopenharmony_ci	int ret;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	rk817_codec_data = devm_kzalloc(&pdev->dev,
48062306a36Sopenharmony_ci					sizeof(struct rk817_codec_priv),
48162306a36Sopenharmony_ci					GFP_KERNEL);
48262306a36Sopenharmony_ci	if (!rk817_codec_data)
48362306a36Sopenharmony_ci		return -ENOMEM;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	platform_set_drvdata(pdev, rk817_codec_data);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	rk817_codec_data->rk808 = rk808;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	rk817_codec_parse_dt_property(&pdev->dev, rk817_codec_data);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	rk817_codec_data->mclk = devm_clk_get(pdev->dev.parent, "mclk");
49262306a36Sopenharmony_ci	if (IS_ERR(rk817_codec_data->mclk)) {
49362306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "Unable to get mclk\n");
49462306a36Sopenharmony_ci		ret = -ENXIO;
49562306a36Sopenharmony_ci		goto err_;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	ret = clk_prepare_enable(rk817_codec_data->mclk);
49962306a36Sopenharmony_ci	if (ret < 0) {
50062306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s() clock prepare error %d\n",
50162306a36Sopenharmony_ci			__func__, ret);
50262306a36Sopenharmony_ci		goto err_;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk817,
50662306a36Sopenharmony_ci					      rk817_dai, ARRAY_SIZE(rk817_dai));
50762306a36Sopenharmony_ci	if (ret < 0) {
50862306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s() register codec error %d\n",
50962306a36Sopenharmony_ci			__func__, ret);
51062306a36Sopenharmony_ci		goto err_clk;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return 0;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cierr_clk:
51662306a36Sopenharmony_ci	clk_disable_unprepare(rk817_codec_data->mclk);
51762306a36Sopenharmony_cierr_:
51862306a36Sopenharmony_ci	return ret;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic void rk817_platform_remove(struct platform_device *pdev)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct rk817_codec_priv *rk817 = platform_get_drvdata(pdev);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	clk_disable_unprepare(rk817->mclk);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic struct platform_driver rk817_codec_driver = {
52962306a36Sopenharmony_ci	.driver = {
53062306a36Sopenharmony_ci		   .name = "rk817-codec",
53162306a36Sopenharmony_ci		   },
53262306a36Sopenharmony_ci	.probe = rk817_platform_probe,
53362306a36Sopenharmony_ci	.remove_new = rk817_platform_remove,
53462306a36Sopenharmony_ci};
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cimodule_platform_driver(rk817_codec_driver);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC RK817 codec driver");
53962306a36Sopenharmony_ciMODULE_AUTHOR("binyuan <kevan.lan@rock-chips.com>");
54062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
54162306a36Sopenharmony_ciMODULE_ALIAS("platform:rk817-codec");
542