162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * rt715.c -- rt715 ALSA SoC audio driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright(c) 2019 Realtek Semiconductor Corp.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * ALC715 ASoC Codec Driver based Intel Dummy SdW codec driver
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1762306a36Sopenharmony_ci#include <linux/pm.h>
1862306a36Sopenharmony_ci#include <linux/soundwire/sdw.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/of_device.h>
2562306a36Sopenharmony_ci#include <sound/core.h>
2662306a36Sopenharmony_ci#include <sound/pcm.h>
2762306a36Sopenharmony_ci#include <sound/pcm_params.h>
2862306a36Sopenharmony_ci#include <sound/sdw.h>
2962306a36Sopenharmony_ci#include <sound/soc.h>
3062306a36Sopenharmony_ci#include <sound/soc-dapm.h>
3162306a36Sopenharmony_ci#include <sound/initval.h>
3262306a36Sopenharmony_ci#include <sound/tlv.h>
3362306a36Sopenharmony_ci#include <sound/hda_verbs.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "rt715.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int rt715_index_write(struct regmap *regmap, unsigned int reg,
3862306a36Sopenharmony_ci		unsigned int value)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	int ret;
4162306a36Sopenharmony_ci	unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	ret = regmap_write(regmap, addr, value);
4462306a36Sopenharmony_ci	if (ret < 0) {
4562306a36Sopenharmony_ci		pr_err("Failed to set private value: %08x <= %04x %d\n", ret,
4662306a36Sopenharmony_ci			addr, value);
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return ret;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int rt715_index_write_nid(struct regmap *regmap,
5362306a36Sopenharmony_ci		unsigned int nid, unsigned int reg, unsigned int value)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int ret;
5662306a36Sopenharmony_ci	unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	ret = regmap_write(regmap, addr, value);
5962306a36Sopenharmony_ci	if (ret < 0)
6062306a36Sopenharmony_ci		pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
6162306a36Sopenharmony_ci			addr, value, ret);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return ret;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int rt715_index_read_nid(struct regmap *regmap,
6762306a36Sopenharmony_ci		unsigned int nid, unsigned int reg, unsigned int *value)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int ret;
7062306a36Sopenharmony_ci	unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	*value = 0;
7362306a36Sopenharmony_ci	ret = regmap_read(regmap, addr, value);
7462306a36Sopenharmony_ci	if (ret < 0)
7562306a36Sopenharmony_ci		pr_err("Failed to get private value: %06x => %04x ret=%d\n",
7662306a36Sopenharmony_ci			addr, *value, ret);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return ret;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int rt715_index_update_bits(struct regmap *regmap, unsigned int nid,
8262306a36Sopenharmony_ci			unsigned int reg, unsigned int mask, unsigned int val)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	unsigned int tmp, orig;
8562306a36Sopenharmony_ci	int ret;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	ret = rt715_index_read_nid(regmap, nid, reg, &orig);
8862306a36Sopenharmony_ci	if (ret < 0)
8962306a36Sopenharmony_ci		return ret;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	tmp = orig & ~mask;
9262306a36Sopenharmony_ci	tmp |= val & mask;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return rt715_index_write_nid(regmap, nid, reg, tmp);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void rt715_reset(struct regmap *regmap)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	regmap_write(regmap, RT715_FUNC_RESET, 0);
10062306a36Sopenharmony_ci	rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS,
10162306a36Sopenharmony_ci		RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG,
10262306a36Sopenharmony_ci		RT715_CLEAR_HIDDEN_REG);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
10762306a36Sopenharmony_ci				unsigned int addr_l, unsigned int val_h,
10862306a36Sopenharmony_ci				unsigned int *r_val, unsigned int *l_val)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	int ret;
11162306a36Sopenharmony_ci	/* R Channel */
11262306a36Sopenharmony_ci	*r_val = val_h << 8;
11362306a36Sopenharmony_ci	ret = regmap_read(rt715->regmap, addr_l, r_val);
11462306a36Sopenharmony_ci	if (ret < 0)
11562306a36Sopenharmony_ci		pr_err("Failed to get R channel gain.\n");
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* L Channel */
11862306a36Sopenharmony_ci	val_h |= 0x20;
11962306a36Sopenharmony_ci	*l_val = val_h << 8;
12062306a36Sopenharmony_ci	ret = regmap_read(rt715->regmap, addr_h, l_val);
12162306a36Sopenharmony_ci	if (ret < 0)
12262306a36Sopenharmony_ci		pr_err("Failed to get L channel gain.\n");
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* For Verb-Set Amplifier Gain (Verb ID = 3h) */
12662306a36Sopenharmony_cistatic int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
12762306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
13062306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
13162306a36Sopenharmony_ci		snd_soc_component_get_dapm(component);
13262306a36Sopenharmony_ci	struct soc_mixer_control *mc =
13362306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
13462306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
13562306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h, val_ll, val_lr;
13662306a36Sopenharmony_ci	unsigned int read_ll, read_rl, i;
13762306a36Sopenharmony_ci	unsigned int k_vol_changed = 0;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
14062306a36Sopenharmony_ci		if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_vol_ori[i]) {
14162306a36Sopenharmony_ci			k_vol_changed = 1;
14262306a36Sopenharmony_ci			break;
14362306a36Sopenharmony_ci		}
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* Can't use update bit function, so read the original value first */
14762306a36Sopenharmony_ci	addr_h = mc->reg;
14862306a36Sopenharmony_ci	addr_l = mc->rreg;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (mc->shift == RT715_DIR_OUT_SFT) /* output */
15162306a36Sopenharmony_ci		val_h = 0x80;
15262306a36Sopenharmony_ci	else /* input */
15362306a36Sopenharmony_ci		val_h = 0x0;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
15862306a36Sopenharmony_ci		regmap_write(rt715->regmap,
15962306a36Sopenharmony_ci				RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* L Channel */
16262306a36Sopenharmony_ci	rt715->kctl_2ch_vol_ori[0] = ucontrol->value.integer.value[0];
16362306a36Sopenharmony_ci	/* for gain */
16462306a36Sopenharmony_ci	val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
16562306a36Sopenharmony_ci	if (val_ll > mc->max)
16662306a36Sopenharmony_ci		val_ll = mc->max;
16762306a36Sopenharmony_ci	/* keep mute status */
16862306a36Sopenharmony_ci	val_ll |= read_ll & 0x80;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* R Channel */
17162306a36Sopenharmony_ci	rt715->kctl_2ch_vol_ori[1] = ucontrol->value.integer.value[1];
17262306a36Sopenharmony_ci	/* for gain */
17362306a36Sopenharmony_ci	val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
17462306a36Sopenharmony_ci	if (val_lr > mc->max)
17562306a36Sopenharmony_ci		val_lr = mc->max;
17662306a36Sopenharmony_ci	/* keep mute status */
17762306a36Sopenharmony_ci	val_lr |= read_rl & 0x80;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	for (i = 0; i < 3; i++) { /* retry 3 times at most */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		if (val_ll == val_lr) {
18262306a36Sopenharmony_ci			/* Set both L/R channels at the same time */
18362306a36Sopenharmony_ci			val_h = (1 << mc->shift) | (3 << 4);
18462306a36Sopenharmony_ci			regmap_write(rt715->regmap, addr_h,
18562306a36Sopenharmony_ci				(val_h << 8) | val_ll);
18662306a36Sopenharmony_ci			regmap_write(rt715->regmap, addr_l,
18762306a36Sopenharmony_ci				(val_h << 8) | val_ll);
18862306a36Sopenharmony_ci		} else {
18962306a36Sopenharmony_ci			/* Lch*/
19062306a36Sopenharmony_ci			val_h = (1 << mc->shift) | (1 << 5);
19162306a36Sopenharmony_ci			regmap_write(rt715->regmap, addr_h,
19262306a36Sopenharmony_ci				(val_h << 8) | val_ll);
19362306a36Sopenharmony_ci			/* Rch */
19462306a36Sopenharmony_ci			val_h = (1 << mc->shift) | (1 << 4);
19562306a36Sopenharmony_ci			regmap_write(rt715->regmap, addr_l,
19662306a36Sopenharmony_ci				(val_h << 8) | val_lr);
19762306a36Sopenharmony_ci		}
19862306a36Sopenharmony_ci		/* check result */
19962306a36Sopenharmony_ci		if (mc->shift == RT715_DIR_OUT_SFT) /* output */
20062306a36Sopenharmony_ci			val_h = 0x80;
20162306a36Sopenharmony_ci		else /* input */
20262306a36Sopenharmony_ci			val_h = 0x0;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		rt715_get_gain(rt715, addr_h, addr_l, val_h,
20562306a36Sopenharmony_ci				&read_rl, &read_ll);
20662306a36Sopenharmony_ci		if (read_rl == val_lr && read_ll == val_ll)
20762306a36Sopenharmony_ci			break;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* D0:power on state, D3: power saving mode */
21162306a36Sopenharmony_ci	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
21262306a36Sopenharmony_ci		regmap_write(rt715->regmap,
21362306a36Sopenharmony_ci				RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
21462306a36Sopenharmony_ci	return k_vol_changed;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol,
21862306a36Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
22162306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
22262306a36Sopenharmony_ci	struct soc_mixer_control *mc =
22362306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
22462306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h;
22562306a36Sopenharmony_ci	unsigned int read_ll, read_rl;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	addr_h = mc->reg;
22862306a36Sopenharmony_ci	addr_l = mc->rreg;
22962306a36Sopenharmony_ci	if (mc->shift == RT715_DIR_OUT_SFT) /* output */
23062306a36Sopenharmony_ci		val_h = 0x80;
23162306a36Sopenharmony_ci	else /* input */
23262306a36Sopenharmony_ci		val_h = 0x0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (mc->invert) {
23762306a36Sopenharmony_ci		/* for mute status */
23862306a36Sopenharmony_ci		read_ll = !(read_ll & 0x80);
23962306a36Sopenharmony_ci		read_rl = !(read_rl & 0x80);
24062306a36Sopenharmony_ci	} else {
24162306a36Sopenharmony_ci		/* for gain */
24262306a36Sopenharmony_ci		read_ll = read_ll & 0x7f;
24362306a36Sopenharmony_ci		read_rl = read_rl & 0x7f;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = read_ll;
24662306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = read_rl;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
25262306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
25562306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
25662306a36Sopenharmony_ci		snd_soc_component_get_dapm(component);
25762306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
25862306a36Sopenharmony_ci	static const unsigned int capture_reg_H[] = {
25962306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
26062306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
26162306a36Sopenharmony_ci	static const unsigned int capture_reg_L[] = {
26262306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
26362306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
26462306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
26562306a36Sopenharmony_ci	unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0;
26662306a36Sopenharmony_ci	unsigned int read_ll, read_rl, i, j, loop_cnt = 4;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
26962306a36Sopenharmony_ci		if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_switch_ori[i])
27062306a36Sopenharmony_ci			k_changed = 1;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	for (j = 0; j < loop_cnt; j++) {
27462306a36Sopenharmony_ci		/* Can't use update bit function, so read the original value first */
27562306a36Sopenharmony_ci		addr_h = capture_reg_H[j];
27662306a36Sopenharmony_ci		addr_l = capture_reg_L[j];
27762306a36Sopenharmony_ci		rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
28062306a36Sopenharmony_ci			regmap_write(rt715->regmap,
28162306a36Sopenharmony_ci					RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* L Channel */
28462306a36Sopenharmony_ci		/* for mute */
28562306a36Sopenharmony_ci		rt715->kctl_8ch_switch_ori[j * 2] =
28662306a36Sopenharmony_ci			ucontrol->value.integer.value[j * 2];
28762306a36Sopenharmony_ci		val_ll = (!ucontrol->value.integer.value[j * 2]) << 7;
28862306a36Sopenharmony_ci		/* keep gain */
28962306a36Sopenharmony_ci		val_ll |= read_ll & 0x7f;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		/* R Channel */
29262306a36Sopenharmony_ci		/* for mute */
29362306a36Sopenharmony_ci		rt715->kctl_8ch_switch_ori[j * 2 + 1] =
29462306a36Sopenharmony_ci			ucontrol->value.integer.value[j * 2 + 1];
29562306a36Sopenharmony_ci		val_lr = (!ucontrol->value.integer.value[j * 2 + 1]) << 7;
29662306a36Sopenharmony_ci		/* keep gain */
29762306a36Sopenharmony_ci		val_lr |= read_rl & 0x7f;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		for (i = 0; i < 3; i++) { /* retry 3 times at most */
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			if (val_ll == val_lr) {
30262306a36Sopenharmony_ci				/* Set both L/R channels at the same time */
30362306a36Sopenharmony_ci				val_h = (1 << k_shift) | (3 << 4);
30462306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_h,
30562306a36Sopenharmony_ci					(val_h << 8) | val_ll);
30662306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_l,
30762306a36Sopenharmony_ci					(val_h << 8) | val_ll);
30862306a36Sopenharmony_ci			} else {
30962306a36Sopenharmony_ci				/* Lch*/
31062306a36Sopenharmony_ci				val_h = (1 << k_shift) | (1 << 5);
31162306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_h,
31262306a36Sopenharmony_ci					(val_h << 8) | val_ll);
31362306a36Sopenharmony_ci				/* Rch */
31462306a36Sopenharmony_ci				val_h = (1 << k_shift) | (1 << 4);
31562306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_l,
31662306a36Sopenharmony_ci					(val_h << 8) | val_lr);
31762306a36Sopenharmony_ci			}
31862306a36Sopenharmony_ci			val_h = 0x0;
31962306a36Sopenharmony_ci			rt715_get_gain(rt715, addr_h, addr_l, val_h,
32062306a36Sopenharmony_ci					&read_rl, &read_ll);
32162306a36Sopenharmony_ci			if (read_rl == val_lr && read_ll == val_ll)
32262306a36Sopenharmony_ci				break;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* D0:power on state, D3: power saving mode */
32762306a36Sopenharmony_ci	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
32862306a36Sopenharmony_ci		regmap_write(rt715->regmap,
32962306a36Sopenharmony_ci				RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
33062306a36Sopenharmony_ci	return k_changed;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol,
33462306a36Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
33762306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
33862306a36Sopenharmony_ci	static const unsigned int capture_reg_H[] = {
33962306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
34062306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
34162306a36Sopenharmony_ci	static const unsigned int capture_reg_L[] = {
34262306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
34362306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
34462306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
34562306a36Sopenharmony_ci	unsigned int read_ll, read_rl;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
34862306a36Sopenharmony_ci		addr_h = capture_reg_H[i];
34962306a36Sopenharmony_ci		addr_l = capture_reg_L[i];
35062306a36Sopenharmony_ci		rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		ucontrol->value.integer.value[i * 2] = !(read_ll & 0x80);
35362306a36Sopenharmony_ci		ucontrol->value.integer.value[i * 2 + 1] = !(read_rl & 0x80);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
36062306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
36362306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
36462306a36Sopenharmony_ci		snd_soc_component_get_dapm(component);
36562306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
36662306a36Sopenharmony_ci	static const unsigned int capture_reg_H[] = {
36762306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
36862306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
36962306a36Sopenharmony_ci	static const unsigned int capture_reg_L[] = {
37062306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
37162306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L};
37262306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr;
37362306a36Sopenharmony_ci	unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0;
37462306a36Sopenharmony_ci	unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
37762306a36Sopenharmony_ci		if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_vol_ori[i])
37862306a36Sopenharmony_ci			k_changed = 1;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	for (j = 0; j < loop_cnt; j++) {
38262306a36Sopenharmony_ci		addr_h = capture_reg_H[j];
38362306a36Sopenharmony_ci		addr_l = capture_reg_L[j];
38462306a36Sopenharmony_ci		rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
38762306a36Sopenharmony_ci			regmap_write(rt715->regmap,
38862306a36Sopenharmony_ci					RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		/* L Channel */
39162306a36Sopenharmony_ci		/* for gain */
39262306a36Sopenharmony_ci		rt715->kctl_8ch_vol_ori[j * 2] = ucontrol->value.integer.value[j * 2];
39362306a36Sopenharmony_ci		val_ll = ((ucontrol->value.integer.value[j * 2]) & 0x7f);
39462306a36Sopenharmony_ci		if (val_ll > k_max)
39562306a36Sopenharmony_ci			val_ll = k_max;
39662306a36Sopenharmony_ci		/* keep mute status */
39762306a36Sopenharmony_ci		val_ll |= read_ll & 0x80;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci		/* R Channel */
40062306a36Sopenharmony_ci		/* for gain */
40162306a36Sopenharmony_ci		rt715->kctl_8ch_vol_ori[j * 2 + 1] =
40262306a36Sopenharmony_ci			ucontrol->value.integer.value[j * 2 + 1];
40362306a36Sopenharmony_ci		val_lr = ((ucontrol->value.integer.value[j * 2 + 1]) & 0x7f);
40462306a36Sopenharmony_ci		if (val_lr > k_max)
40562306a36Sopenharmony_ci			val_lr = k_max;
40662306a36Sopenharmony_ci		/* keep mute status */
40762306a36Sopenharmony_ci		val_lr |= read_rl & 0x80;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		for (i = 0; i < 3; i++) { /* retry 3 times at most */
41062306a36Sopenharmony_ci			if (val_ll == val_lr) {
41162306a36Sopenharmony_ci				/* Set both L/R channels at the same time */
41262306a36Sopenharmony_ci				val_h = (1 << k_shift) | (3 << 4);
41362306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_h,
41462306a36Sopenharmony_ci					(val_h << 8) | val_ll);
41562306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_l,
41662306a36Sopenharmony_ci					(val_h << 8) | val_ll);
41762306a36Sopenharmony_ci			} else {
41862306a36Sopenharmony_ci				/* Lch*/
41962306a36Sopenharmony_ci				val_h = (1 << k_shift) | (1 << 5);
42062306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_h,
42162306a36Sopenharmony_ci					(val_h << 8) | val_ll);
42262306a36Sopenharmony_ci				/* Rch */
42362306a36Sopenharmony_ci				val_h = (1 << k_shift) | (1 << 4);
42462306a36Sopenharmony_ci				regmap_write(rt715->regmap, addr_l,
42562306a36Sopenharmony_ci					(val_h << 8) | val_lr);
42662306a36Sopenharmony_ci			}
42762306a36Sopenharmony_ci			val_h = 0x0;
42862306a36Sopenharmony_ci			rt715_get_gain(rt715, addr_h, addr_l, val_h,
42962306a36Sopenharmony_ci					&read_rl, &read_ll);
43062306a36Sopenharmony_ci			if (read_rl == val_lr && read_ll == val_ll)
43162306a36Sopenharmony_ci				break;
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* D0:power on state, D3: power saving mode */
43662306a36Sopenharmony_ci	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
43762306a36Sopenharmony_ci		regmap_write(rt715->regmap,
43862306a36Sopenharmony_ci				RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
43962306a36Sopenharmony_ci	return k_changed;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol,
44362306a36Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
44662306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
44762306a36Sopenharmony_ci	static const unsigned int capture_reg_H[] = {
44862306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
44962306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H };
45062306a36Sopenharmony_ci	static const unsigned int capture_reg_L[] = {
45162306a36Sopenharmony_ci		RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L,
45262306a36Sopenharmony_ci		RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L };
45362306a36Sopenharmony_ci	unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4;
45462306a36Sopenharmony_ci	unsigned int read_ll, read_rl;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
45762306a36Sopenharmony_ci		addr_h = capture_reg_H[i];
45862306a36Sopenharmony_ci		addr_l = capture_reg_L[i];
45962306a36Sopenharmony_ci		rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		ucontrol->value.integer.value[i * 2] = read_ll & 0x7f;
46262306a36Sopenharmony_ci		ucontrol->value.integer.value[i * 2 + 1] = read_rl & 0x7f;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	return 0;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
46962306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int rt715_switch_info(struct snd_kcontrol *kcontrol,
47262306a36Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
47562306a36Sopenharmony_ci	uinfo->count = 8;
47662306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
47762306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
47862306a36Sopenharmony_ci	return 0;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int rt715_vol_info(struct snd_kcontrol *kcontrol,
48262306a36Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
48562306a36Sopenharmony_ci	uinfo->count = 8;
48662306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
48762306a36Sopenharmony_ci	uinfo->value.integer.max = 0x3f;
48862306a36Sopenharmony_ci	return 0;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
49262306a36Sopenharmony_ci	 xhandler_get, xhandler_put) \
49362306a36Sopenharmony_ci{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
49462306a36Sopenharmony_ci	.info = snd_soc_info_volsw, \
49562306a36Sopenharmony_ci	.get = xhandler_get, .put = xhandler_put, \
49662306a36Sopenharmony_ci	.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
49762306a36Sopenharmony_ci					    xmax, xinvert) }
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci#define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \
50062306a36Sopenharmony_ci{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
50162306a36Sopenharmony_ci	.info = rt715_switch_info, \
50262306a36Sopenharmony_ci	.get = xhandler_get, .put = xhandler_put, \
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci#define RT715_MAIN_VOL_EXT_TLV(xname, xhandler_get, xhandler_put, tlv_array) \
50662306a36Sopenharmony_ci{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
50762306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
50862306a36Sopenharmony_ci		 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
50962306a36Sopenharmony_ci	.tlv.p = (tlv_array), \
51062306a36Sopenharmony_ci	.info = rt715_vol_info, \
51162306a36Sopenharmony_ci	.get = xhandler_get, .put = xhandler_put, \
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt715_snd_controls[] = {
51562306a36Sopenharmony_ci	/* Capture switch */
51662306a36Sopenharmony_ci	RT715_MAIN_SWITCH_EXT("Capture Switch",
51762306a36Sopenharmony_ci			rt715_set_main_switch_get, rt715_set_main_switch_put),
51862306a36Sopenharmony_ci	/* Volume Control */
51962306a36Sopenharmony_ci	RT715_MAIN_VOL_EXT_TLV("Capture Volume",
52062306a36Sopenharmony_ci			rt715_set_main_vol_get, rt715_set_main_vol_put, in_vol_tlv),
52162306a36Sopenharmony_ci	/* MIC Boost Control */
52262306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost", RT715_SET_GAIN_DMIC1_H,
52362306a36Sopenharmony_ci			RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0,
52462306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
52562306a36Sopenharmony_ci			mic_vol_tlv),
52662306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("DMIC2 Boost", RT715_SET_GAIN_DMIC2_H,
52762306a36Sopenharmony_ci			RT715_SET_GAIN_DMIC2_L, RT715_DIR_IN_SFT, 3, 0,
52862306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
52962306a36Sopenharmony_ci			mic_vol_tlv),
53062306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("DMIC3 Boost", RT715_SET_GAIN_DMIC3_H,
53162306a36Sopenharmony_ci			RT715_SET_GAIN_DMIC3_L, RT715_DIR_IN_SFT, 3, 0,
53262306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
53362306a36Sopenharmony_ci			mic_vol_tlv),
53462306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("DMIC4 Boost", RT715_SET_GAIN_DMIC4_H,
53562306a36Sopenharmony_ci			RT715_SET_GAIN_DMIC4_L, RT715_DIR_IN_SFT, 3, 0,
53662306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
53762306a36Sopenharmony_ci			mic_vol_tlv),
53862306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("MIC1 Boost", RT715_SET_GAIN_MIC1_H,
53962306a36Sopenharmony_ci			RT715_SET_GAIN_MIC1_L, RT715_DIR_IN_SFT, 3, 0,
54062306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
54162306a36Sopenharmony_ci			mic_vol_tlv),
54262306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("MIC2 Boost", RT715_SET_GAIN_MIC2_H,
54362306a36Sopenharmony_ci			RT715_SET_GAIN_MIC2_L, RT715_DIR_IN_SFT, 3, 0,
54462306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
54562306a36Sopenharmony_ci			mic_vol_tlv),
54662306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("LINE1 Boost", RT715_SET_GAIN_LINE1_H,
54762306a36Sopenharmony_ci			RT715_SET_GAIN_LINE1_L, RT715_DIR_IN_SFT, 3, 0,
54862306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
54962306a36Sopenharmony_ci			mic_vol_tlv),
55062306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("LINE2 Boost", RT715_SET_GAIN_LINE2_H,
55162306a36Sopenharmony_ci			RT715_SET_GAIN_LINE2_L, RT715_DIR_IN_SFT, 3, 0,
55262306a36Sopenharmony_ci			rt715_set_amp_gain_get, rt715_set_amp_gain_put,
55362306a36Sopenharmony_ci			mic_vol_tlv),
55462306a36Sopenharmony_ci};
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic int rt715_mux_get(struct snd_kcontrol *kcontrol,
55762306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct snd_soc_component *component =
56062306a36Sopenharmony_ci		snd_soc_dapm_kcontrol_component(kcontrol);
56162306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
56262306a36Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
56362306a36Sopenharmony_ci	unsigned int reg, val;
56462306a36Sopenharmony_ci	int ret;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/* nid = e->reg, vid = 0xf01 */
56762306a36Sopenharmony_ci	reg = RT715_VERB_SET_CONNECT_SEL | e->reg;
56862306a36Sopenharmony_ci	ret = regmap_read(rt715->regmap, reg, &val);
56962306a36Sopenharmony_ci	if (ret < 0) {
57062306a36Sopenharmony_ci		dev_err(component->dev, "%s: sdw read failed: %d\n",
57162306a36Sopenharmony_ci			__func__, ret);
57262306a36Sopenharmony_ci		return ret;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/*
57662306a36Sopenharmony_ci	 * The first two indices of ADC Mux 24/25 are routed to the same
57762306a36Sopenharmony_ci	 * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2.
57862306a36Sopenharmony_ci	 * To have a unique set of inputs, we skip the index1 of the muxes.
57962306a36Sopenharmony_ci	 */
58062306a36Sopenharmony_ci	if ((e->reg == RT715_MUX_IN3 || e->reg == RT715_MUX_IN4) && (val > 0))
58162306a36Sopenharmony_ci		val -= 1;
58262306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = val;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return 0;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic int rt715_mux_put(struct snd_kcontrol *kcontrol,
58862306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct snd_soc_component *component =
59162306a36Sopenharmony_ci		snd_soc_dapm_kcontrol_component(kcontrol);
59262306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
59362306a36Sopenharmony_ci				snd_soc_dapm_kcontrol_dapm(kcontrol);
59462306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
59562306a36Sopenharmony_ci	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
59662306a36Sopenharmony_ci	unsigned int *item = ucontrol->value.enumerated.item;
59762306a36Sopenharmony_ci	unsigned int val, val2 = 0, change, reg;
59862306a36Sopenharmony_ci	int ret;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (item[0] >= e->items)
60162306a36Sopenharmony_ci		return -EINVAL;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* Verb ID = 0x701h, nid = e->reg */
60462306a36Sopenharmony_ci	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	reg = RT715_VERB_SET_CONNECT_SEL | e->reg;
60762306a36Sopenharmony_ci	ret = regmap_read(rt715->regmap, reg, &val2);
60862306a36Sopenharmony_ci	if (ret < 0) {
60962306a36Sopenharmony_ci		dev_err(component->dev, "%s: sdw read failed: %d\n",
61062306a36Sopenharmony_ci			__func__, ret);
61162306a36Sopenharmony_ci		return ret;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (val == val2)
61562306a36Sopenharmony_ci		change = 0;
61662306a36Sopenharmony_ci	else
61762306a36Sopenharmony_ci		change = 1;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (change) {
62062306a36Sopenharmony_ci		reg = RT715_VERB_SET_CONNECT_SEL | e->reg;
62162306a36Sopenharmony_ci		regmap_write(rt715->regmap, reg, val);
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	snd_soc_dapm_mux_update_power(dapm, kcontrol,
62562306a36Sopenharmony_ci						item[0], e, NULL);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return change;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic const char * const adc_22_23_mux_text[] = {
63162306a36Sopenharmony_ci	"MIC1",
63262306a36Sopenharmony_ci	"MIC2",
63362306a36Sopenharmony_ci	"LINE1",
63462306a36Sopenharmony_ci	"LINE2",
63562306a36Sopenharmony_ci	"DMIC1",
63662306a36Sopenharmony_ci	"DMIC2",
63762306a36Sopenharmony_ci	"DMIC3",
63862306a36Sopenharmony_ci	"DMIC4",
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/*
64262306a36Sopenharmony_ci * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and
64362306a36Sopenharmony_ci * 1 will be connected to the same dmic source, therefore we skip index 1 to
64462306a36Sopenharmony_ci * avoid misunderstanding on usage of dapm routing.
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_cistatic const unsigned int rt715_adc_24_25_values[] = {
64762306a36Sopenharmony_ci	0,
64862306a36Sopenharmony_ci	2,
64962306a36Sopenharmony_ci	3,
65062306a36Sopenharmony_ci	4,
65162306a36Sopenharmony_ci	5,
65262306a36Sopenharmony_ci};
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic const char * const adc_24_mux_text[] = {
65562306a36Sopenharmony_ci	"MIC2",
65662306a36Sopenharmony_ci	"DMIC1",
65762306a36Sopenharmony_ci	"DMIC2",
65862306a36Sopenharmony_ci	"DMIC3",
65962306a36Sopenharmony_ci	"DMIC4",
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic const char * const adc_25_mux_text[] = {
66362306a36Sopenharmony_ci	"MIC1",
66462306a36Sopenharmony_ci	"DMIC1",
66562306a36Sopenharmony_ci	"DMIC2",
66662306a36Sopenharmony_ci	"DMIC3",
66762306a36Sopenharmony_ci	"DMIC4",
66862306a36Sopenharmony_ci};
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(
67162306a36Sopenharmony_ci	rt715_adc22_enum, RT715_MUX_IN1, 0, adc_22_23_mux_text);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(
67462306a36Sopenharmony_ci	rt715_adc23_enum, RT715_MUX_IN2, 0, adc_22_23_mux_text);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum,
67762306a36Sopenharmony_ci	RT715_MUX_IN3, 0, 0xf,
67862306a36Sopenharmony_ci	adc_24_mux_text, rt715_adc_24_25_values);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum,
68162306a36Sopenharmony_ci	RT715_MUX_IN4, 0, 0xf,
68262306a36Sopenharmony_ci	adc_25_mux_text, rt715_adc_24_25_values);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt715_adc22_mux =
68562306a36Sopenharmony_ci	SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum,
68662306a36Sopenharmony_ci			rt715_mux_get, rt715_mux_put);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt715_adc23_mux =
68962306a36Sopenharmony_ci	SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum,
69062306a36Sopenharmony_ci			rt715_mux_get, rt715_mux_put);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt715_adc24_mux =
69362306a36Sopenharmony_ci	SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum,
69462306a36Sopenharmony_ci			rt715_mux_get, rt715_mux_put);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt715_adc25_mux =
69762306a36Sopenharmony_ci	SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum,
69862306a36Sopenharmony_ci			rt715_mux_get, rt715_mux_put);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget rt715_dapm_widgets[] = {
70162306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("DMIC1"),
70262306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("DMIC2"),
70362306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("DMIC3"),
70462306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("DMIC4"),
70562306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC1"),
70662306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC2"),
70762306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("LINE1"),
70862306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("LINE2"),
70962306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC 07", NULL, RT715_SET_STREAMID_MIC_ADC, 4, 0),
71062306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC 08", NULL, RT715_SET_STREAMID_LINE_ADC, 4, 0),
71162306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC 09", NULL, RT715_SET_STREAMID_MIX_ADC, 4, 0),
71262306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC 27", NULL, RT715_SET_STREAMID_MIX_ADC2, 4, 0),
71362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
71462306a36Sopenharmony_ci		&rt715_adc22_mux),
71562306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
71662306a36Sopenharmony_ci		&rt715_adc23_mux),
71762306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0,
71862306a36Sopenharmony_ci		&rt715_adc24_mux),
71962306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0,
72062306a36Sopenharmony_ci		&rt715_adc25_mux),
72162306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
72262306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0),
72362306a36Sopenharmony_ci};
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rt715_audio_map[] = {
72662306a36Sopenharmony_ci	{"DP6TX", NULL, "ADC 09"},
72762306a36Sopenharmony_ci	{"DP6TX", NULL, "ADC 08"},
72862306a36Sopenharmony_ci	{"DP4TX", NULL, "ADC 07"},
72962306a36Sopenharmony_ci	{"DP4TX", NULL, "ADC 27"},
73062306a36Sopenharmony_ci	{"ADC 09", NULL, "ADC 22 Mux"},
73162306a36Sopenharmony_ci	{"ADC 08", NULL, "ADC 23 Mux"},
73262306a36Sopenharmony_ci	{"ADC 07", NULL, "ADC 24 Mux"},
73362306a36Sopenharmony_ci	{"ADC 27", NULL, "ADC 25 Mux"},
73462306a36Sopenharmony_ci	{"ADC 22 Mux", "MIC1", "MIC1"},
73562306a36Sopenharmony_ci	{"ADC 22 Mux", "MIC2", "MIC2"},
73662306a36Sopenharmony_ci	{"ADC 22 Mux", "LINE1", "LINE1"},
73762306a36Sopenharmony_ci	{"ADC 22 Mux", "LINE2", "LINE2"},
73862306a36Sopenharmony_ci	{"ADC 22 Mux", "DMIC1", "DMIC1"},
73962306a36Sopenharmony_ci	{"ADC 22 Mux", "DMIC2", "DMIC2"},
74062306a36Sopenharmony_ci	{"ADC 22 Mux", "DMIC3", "DMIC3"},
74162306a36Sopenharmony_ci	{"ADC 22 Mux", "DMIC4", "DMIC4"},
74262306a36Sopenharmony_ci	{"ADC 23 Mux", "MIC1", "MIC1"},
74362306a36Sopenharmony_ci	{"ADC 23 Mux", "MIC2", "MIC2"},
74462306a36Sopenharmony_ci	{"ADC 23 Mux", "LINE1", "LINE1"},
74562306a36Sopenharmony_ci	{"ADC 23 Mux", "LINE2", "LINE2"},
74662306a36Sopenharmony_ci	{"ADC 23 Mux", "DMIC1", "DMIC1"},
74762306a36Sopenharmony_ci	{"ADC 23 Mux", "DMIC2", "DMIC2"},
74862306a36Sopenharmony_ci	{"ADC 23 Mux", "DMIC3", "DMIC3"},
74962306a36Sopenharmony_ci	{"ADC 23 Mux", "DMIC4", "DMIC4"},
75062306a36Sopenharmony_ci	{"ADC 24 Mux", "MIC2", "MIC2"},
75162306a36Sopenharmony_ci	{"ADC 24 Mux", "DMIC1", "DMIC1"},
75262306a36Sopenharmony_ci	{"ADC 24 Mux", "DMIC2", "DMIC2"},
75362306a36Sopenharmony_ci	{"ADC 24 Mux", "DMIC3", "DMIC3"},
75462306a36Sopenharmony_ci	{"ADC 24 Mux", "DMIC4", "DMIC4"},
75562306a36Sopenharmony_ci	{"ADC 25 Mux", "MIC1", "MIC1"},
75662306a36Sopenharmony_ci	{"ADC 25 Mux", "DMIC1", "DMIC1"},
75762306a36Sopenharmony_ci	{"ADC 25 Mux", "DMIC2", "DMIC2"},
75862306a36Sopenharmony_ci	{"ADC 25 Mux", "DMIC3", "DMIC3"},
75962306a36Sopenharmony_ci	{"ADC 25 Mux", "DMIC4", "DMIC4"},
76062306a36Sopenharmony_ci};
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic int rt715_set_bias_level(struct snd_soc_component *component,
76362306a36Sopenharmony_ci				enum snd_soc_bias_level level)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm =
76662306a36Sopenharmony_ci		snd_soc_component_get_dapm(component);
76762306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	switch (level) {
77062306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
77162306a36Sopenharmony_ci		if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
77262306a36Sopenharmony_ci			regmap_write(rt715->regmap,
77362306a36Sopenharmony_ci						RT715_SET_AUDIO_POWER_STATE,
77462306a36Sopenharmony_ci						AC_PWRST_D0);
77562306a36Sopenharmony_ci			msleep(RT715_POWER_UP_DELAY_MS);
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci		break;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
78062306a36Sopenharmony_ci		regmap_write(rt715->regmap,
78162306a36Sopenharmony_ci					RT715_SET_AUDIO_POWER_STATE,
78262306a36Sopenharmony_ci					AC_PWRST_D3);
78362306a36Sopenharmony_ci		break;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	default:
78662306a36Sopenharmony_ci		break;
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci	dapm->bias_level = level;
78962306a36Sopenharmony_ci	return 0;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic int rt715_probe(struct snd_soc_component *component)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
79562306a36Sopenharmony_ci	int ret;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (!rt715->first_hw_init)
79862306a36Sopenharmony_ci		return 0;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	ret = pm_runtime_resume(component->dev);
80162306a36Sopenharmony_ci	if (ret < 0 && ret != -EACCES)
80262306a36Sopenharmony_ci		return ret;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return 0;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_rt715 = {
80862306a36Sopenharmony_ci	.probe = rt715_probe,
80962306a36Sopenharmony_ci	.set_bias_level = rt715_set_bias_level,
81062306a36Sopenharmony_ci	.controls = rt715_snd_controls,
81162306a36Sopenharmony_ci	.num_controls = ARRAY_SIZE(rt715_snd_controls),
81262306a36Sopenharmony_ci	.dapm_widgets = rt715_dapm_widgets,
81362306a36Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets),
81462306a36Sopenharmony_ci	.dapm_routes = rt715_audio_map,
81562306a36Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(rt715_audio_map),
81662306a36Sopenharmony_ci	.endianness = 1,
81762306a36Sopenharmony_ci};
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
82062306a36Sopenharmony_ci				int direction)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	return 0;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic void rt715_shutdown(struct snd_pcm_substream *substream,
82962306a36Sopenharmony_ci				struct snd_soc_dai *dai)
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	snd_soc_dai_set_dma_data(dai, substream, NULL);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
83662306a36Sopenharmony_ci				struct snd_pcm_hw_params *params,
83762306a36Sopenharmony_ci				struct snd_soc_dai *dai)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
84062306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
84162306a36Sopenharmony_ci	struct sdw_stream_config stream_config = {0};
84262306a36Sopenharmony_ci	struct sdw_port_config port_config = {0};
84362306a36Sopenharmony_ci	struct sdw_stream_runtime *sdw_stream;
84462306a36Sopenharmony_ci	int retval;
84562306a36Sopenharmony_ci	unsigned int val = 0;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (!sdw_stream)
85062306a36Sopenharmony_ci		return -EINVAL;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (!rt715->slave)
85362306a36Sopenharmony_ci		return -EINVAL;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	switch (dai->id) {
85862306a36Sopenharmony_ci	case RT715_AIF1:
85962306a36Sopenharmony_ci		port_config.num = 6;
86062306a36Sopenharmony_ci		rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa500);
86162306a36Sopenharmony_ci		break;
86262306a36Sopenharmony_ci	case RT715_AIF2:
86362306a36Sopenharmony_ci		port_config.num = 4;
86462306a36Sopenharmony_ci		rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa000);
86562306a36Sopenharmony_ci		break;
86662306a36Sopenharmony_ci	default:
86762306a36Sopenharmony_ci		dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
86862306a36Sopenharmony_ci		return -EINVAL;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	retval = sdw_stream_add_slave(rt715->slave, &stream_config,
87262306a36Sopenharmony_ci					&port_config, 1, sdw_stream);
87362306a36Sopenharmony_ci	if (retval) {
87462306a36Sopenharmony_ci		dev_err(dai->dev, "Unable to configure port\n");
87562306a36Sopenharmony_ci		return retval;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	switch (params_rate(params)) {
87962306a36Sopenharmony_ci	/* bit 14 0:48K 1:44.1K */
88062306a36Sopenharmony_ci	/* bit 15 Stream Type 0:PCM 1:Non-PCM, should always be PCM */
88162306a36Sopenharmony_ci	case 44100:
88262306a36Sopenharmony_ci		val |= 0x40 << 8;
88362306a36Sopenharmony_ci		break;
88462306a36Sopenharmony_ci	case 48000:
88562306a36Sopenharmony_ci		val |= 0x0 << 8;
88662306a36Sopenharmony_ci		break;
88762306a36Sopenharmony_ci	default:
88862306a36Sopenharmony_ci		dev_err(component->dev, "Unsupported sample rate %d\n",
88962306a36Sopenharmony_ci			params_rate(params));
89062306a36Sopenharmony_ci		return -EINVAL;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (params_channels(params) <= 16) {
89462306a36Sopenharmony_ci		/* bit 3:0 Number of Channel */
89562306a36Sopenharmony_ci		val |= (params_channels(params) - 1);
89662306a36Sopenharmony_ci	} else {
89762306a36Sopenharmony_ci		dev_err(component->dev, "Unsupported channels %d\n",
89862306a36Sopenharmony_ci			params_channels(params));
89962306a36Sopenharmony_ci		return -EINVAL;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	switch (params_width(params)) {
90362306a36Sopenharmony_ci	/* bit 6:4 Bits per Sample */
90462306a36Sopenharmony_ci	case 8:
90562306a36Sopenharmony_ci		break;
90662306a36Sopenharmony_ci	case 16:
90762306a36Sopenharmony_ci		val |= (0x1 << 4);
90862306a36Sopenharmony_ci		break;
90962306a36Sopenharmony_ci	case 20:
91062306a36Sopenharmony_ci		val |= (0x2 << 4);
91162306a36Sopenharmony_ci		break;
91262306a36Sopenharmony_ci	case 24:
91362306a36Sopenharmony_ci		val |= (0x3 << 4);
91462306a36Sopenharmony_ci		break;
91562306a36Sopenharmony_ci	case 32:
91662306a36Sopenharmony_ci		val |= (0x4 << 4);
91762306a36Sopenharmony_ci		break;
91862306a36Sopenharmony_ci	default:
91962306a36Sopenharmony_ci		return -EINVAL;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_MIC_ADC_FORMAT_H, val);
92362306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_MIC_LINE_FORMAT_H, val);
92462306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_MIX_ADC_FORMAT_H, val);
92562306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_MIX_ADC2_FORMAT_H, val);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	return retval;
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic int rt715_pcm_hw_free(struct snd_pcm_substream *substream,
93162306a36Sopenharmony_ci				struct snd_soc_dai *dai)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
93462306a36Sopenharmony_ci	struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
93562306a36Sopenharmony_ci	struct sdw_stream_runtime *sdw_stream =
93662306a36Sopenharmony_ci		snd_soc_dai_get_dma_data(dai, substream);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (!rt715->slave)
93962306a36Sopenharmony_ci		return -EINVAL;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	sdw_stream_remove_slave(rt715->slave, sdw_stream);
94262306a36Sopenharmony_ci	return 0;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
94662306a36Sopenharmony_ci#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
94762306a36Sopenharmony_ci			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rt715_ops = {
95062306a36Sopenharmony_ci	.hw_params	= rt715_pcm_hw_params,
95162306a36Sopenharmony_ci	.hw_free	= rt715_pcm_hw_free,
95262306a36Sopenharmony_ci	.set_stream	= rt715_set_sdw_stream,
95362306a36Sopenharmony_ci	.shutdown	= rt715_shutdown,
95462306a36Sopenharmony_ci};
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic struct snd_soc_dai_driver rt715_dai[] = {
95762306a36Sopenharmony_ci	{
95862306a36Sopenharmony_ci		.name = "rt715-aif1",
95962306a36Sopenharmony_ci		.id = RT715_AIF1,
96062306a36Sopenharmony_ci		.capture = {
96162306a36Sopenharmony_ci			.stream_name = "DP6 Capture",
96262306a36Sopenharmony_ci			.channels_min = 1,
96362306a36Sopenharmony_ci			.channels_max = 2,
96462306a36Sopenharmony_ci			.rates = RT715_STEREO_RATES,
96562306a36Sopenharmony_ci			.formats = RT715_FORMATS,
96662306a36Sopenharmony_ci		},
96762306a36Sopenharmony_ci		.ops = &rt715_ops,
96862306a36Sopenharmony_ci	},
96962306a36Sopenharmony_ci	{
97062306a36Sopenharmony_ci		.name = "rt715-aif2",
97162306a36Sopenharmony_ci		.id = RT715_AIF2,
97262306a36Sopenharmony_ci		.capture = {
97362306a36Sopenharmony_ci			.stream_name = "DP4 Capture",
97462306a36Sopenharmony_ci			.channels_min = 1,
97562306a36Sopenharmony_ci			.channels_max = 2,
97662306a36Sopenharmony_ci			.rates = RT715_STEREO_RATES,
97762306a36Sopenharmony_ci			.formats = RT715_FORMATS,
97862306a36Sopenharmony_ci		},
97962306a36Sopenharmony_ci		.ops = &rt715_ops,
98062306a36Sopenharmony_ci	},
98162306a36Sopenharmony_ci};
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci/* Bus clock frequency */
98462306a36Sopenharmony_ci#define RT715_CLK_FREQ_9600000HZ 9600000
98562306a36Sopenharmony_ci#define RT715_CLK_FREQ_12000000HZ 12000000
98662306a36Sopenharmony_ci#define RT715_CLK_FREQ_6000000HZ 6000000
98762306a36Sopenharmony_ci#define RT715_CLK_FREQ_4800000HZ 4800000
98862306a36Sopenharmony_ci#define RT715_CLK_FREQ_2400000HZ 2400000
98962306a36Sopenharmony_ci#define RT715_CLK_FREQ_12288000HZ 12288000
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ciint rt715_clock_config(struct device *dev)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct rt715_priv *rt715 = dev_get_drvdata(dev);
99462306a36Sopenharmony_ci	unsigned int clk_freq, value;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	clk_freq = (rt715->params.curr_dr_freq >> 1);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	switch (clk_freq) {
99962306a36Sopenharmony_ci	case RT715_CLK_FREQ_12000000HZ:
100062306a36Sopenharmony_ci		value = 0x0;
100162306a36Sopenharmony_ci		break;
100262306a36Sopenharmony_ci	case RT715_CLK_FREQ_6000000HZ:
100362306a36Sopenharmony_ci		value = 0x1;
100462306a36Sopenharmony_ci		break;
100562306a36Sopenharmony_ci	case RT715_CLK_FREQ_9600000HZ:
100662306a36Sopenharmony_ci		value = 0x2;
100762306a36Sopenharmony_ci		break;
100862306a36Sopenharmony_ci	case RT715_CLK_FREQ_4800000HZ:
100962306a36Sopenharmony_ci		value = 0x3;
101062306a36Sopenharmony_ci		break;
101162306a36Sopenharmony_ci	case RT715_CLK_FREQ_2400000HZ:
101262306a36Sopenharmony_ci		value = 0x4;
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci	case RT715_CLK_FREQ_12288000HZ:
101562306a36Sopenharmony_ci		value = 0x5;
101662306a36Sopenharmony_ci		break;
101762306a36Sopenharmony_ci	default:
101862306a36Sopenharmony_ci		return -EINVAL;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	regmap_write(rt715->regmap, 0xe0, value);
102262306a36Sopenharmony_ci	regmap_write(rt715->regmap, 0xf0, value);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return 0;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ciint rt715_init(struct device *dev, struct regmap *sdw_regmap,
102862306a36Sopenharmony_ci	struct regmap *regmap, struct sdw_slave *slave)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct rt715_priv *rt715;
103162306a36Sopenharmony_ci	int ret;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL);
103462306a36Sopenharmony_ci	if (!rt715)
103562306a36Sopenharmony_ci		return -ENOMEM;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	dev_set_drvdata(dev, rt715);
103862306a36Sopenharmony_ci	rt715->slave = slave;
103962306a36Sopenharmony_ci	rt715->regmap = regmap;
104062306a36Sopenharmony_ci	rt715->sdw_regmap = sdw_regmap;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	regcache_cache_only(rt715->regmap, true);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/*
104562306a36Sopenharmony_ci	 * Mark hw_init to false
104662306a36Sopenharmony_ci	 * HW init will be performed when device reports present
104762306a36Sopenharmony_ci	 */
104862306a36Sopenharmony_ci	rt715->hw_init = false;
104962306a36Sopenharmony_ci	rt715->first_hw_init = false;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(dev,
105262306a36Sopenharmony_ci						&soc_codec_dev_rt715,
105362306a36Sopenharmony_ci						rt715_dai,
105462306a36Sopenharmony_ci						ARRAY_SIZE(rt715_dai));
105562306a36Sopenharmony_ci	if (ret < 0)
105662306a36Sopenharmony_ci		return ret;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* set autosuspend parameters */
105962306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, 3000);
106062306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* make sure the device does not suspend immediately */
106362306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	pm_runtime_enable(dev);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* important note: the device is NOT tagged as 'active' and will remain
106862306a36Sopenharmony_ci	 * 'suspended' until the hardware is enumerated/initialized. This is required
106962306a36Sopenharmony_ci	 * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
107062306a36Sopenharmony_ci	 * fail with -EACCESS because of race conditions between card creation and enumeration
107162306a36Sopenharmony_ci	 */
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	return 0;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ciint rt715_io_init(struct device *dev, struct sdw_slave *slave)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct rt715_priv *rt715 = dev_get_drvdata(dev);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (rt715->hw_init)
108162306a36Sopenharmony_ci		return 0;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	regcache_cache_only(rt715->regmap, false);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/*
108662306a36Sopenharmony_ci	 *  PM runtime status is marked as 'active' only when a Slave reports as Attached
108762306a36Sopenharmony_ci	 */
108862306a36Sopenharmony_ci	if (!rt715->first_hw_init)
108962306a36Sopenharmony_ci		/* update count of parent 'active' children */
109062306a36Sopenharmony_ci		pm_runtime_set_active(&slave->dev);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	pm_runtime_get_noresume(&slave->dev);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	rt715_reset(rt715->regmap);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/* Mute nid=08h/09h */
109762306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080);
109862306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080);
109962306a36Sopenharmony_ci	/* Mute nid=07h/27h */
110062306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_GAIN_MIC_ADC_H, 0xb080);
110162306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC2_H, 0xb080);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	/* Set Pin Widget */
110462306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_PIN_DMIC1, 0x20);
110562306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_PIN_DMIC2, 0x20);
110662306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_PIN_DMIC3, 0x20);
110762306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_PIN_DMIC4, 0x20);
110862306a36Sopenharmony_ci	/* Set Converter Stream */
110962306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_STREAMID_LINE_ADC, 0x10);
111062306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_STREAMID_MIX_ADC, 0x10);
111162306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_STREAMID_MIC_ADC, 0x10);
111262306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_STREAMID_MIX_ADC2, 0x10);
111362306a36Sopenharmony_ci	/* Set Configuration Default */
111462306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT1, 0xd0);
111562306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT2, 0x11);
111662306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT3, 0xa1);
111762306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT4, 0x81);
111862306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT1, 0xd1);
111962306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT2, 0x11);
112062306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT3, 0xa1);
112162306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT4, 0x81);
112262306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT1, 0xd0);
112362306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT2, 0x11);
112462306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT3, 0xa1);
112562306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT4, 0x81);
112662306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT1, 0xd1);
112762306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT2, 0x11);
112862306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT3, 0xa1);
112962306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT4, 0x81);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Finish Initial Settings, set power to D3 */
113262306a36Sopenharmony_ci	regmap_write(rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (rt715->first_hw_init)
113562306a36Sopenharmony_ci		regcache_mark_dirty(rt715->regmap);
113662306a36Sopenharmony_ci	else
113762306a36Sopenharmony_ci		rt715->first_hw_init = true;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* Mark Slave initialization complete */
114062306a36Sopenharmony_ci	rt715->hw_init = true;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&slave->dev);
114362306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&slave->dev);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return 0;
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC rt715 driver");
114962306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC rt715 driver SDW");
115062306a36Sopenharmony_ciMODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
115162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1152