// SPDX-License-Identifier: GPL-2.0
/*
* rt715.c -- rt715 ALSA SoC audio driver
*
* Copyright(c) 2019 Realtek Semiconductor Corp.
*
* ALC715 ASoC Codec Driver based Intel Dummy SdW codec driver
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include <linux/soundwire/sdw.h>
#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/hda_verbs.h>
#include "rt715.h"
static int rt715_index_write(struct regmap *regmap, unsigned int reg,
unsigned int value)
{
int ret;
unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg;
ret = regmap_write(regmap, addr, value);
if (ret < 0) {
pr_err("Failed to set private value: %08x <= %04x %d\n", ret,
addr, value);
}
return ret;
}
static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
unsigned int addr_l, unsigned int val_h,
unsigned int *r_val, unsigned int *l_val)
{
int ret;
/* R Channel */
*r_val = (val_h << 8);
ret = regmap_read(rt715->regmap, addr_l, r_val);
if (ret < 0)
pr_err("Failed to get R channel gain.\n");
/* L Channel */
val_h |= 0x20;
*l_val = (val_h << 8);
ret = regmap_read(rt715->regmap, addr_h, l_val);
if (ret < 0)
pr_err("Failed to get L channel gain.\n");
}
/* For Verb-Set Amplifier Gain (Verb ID = 3h) */
static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
unsigned int addr_h, addr_l, val_h, val_ll, val_lr;
unsigned int read_ll, read_rl;
int i;
/* Can't use update bit function, so read the original value first */
addr_h = mc->reg;
addr_l = mc->rreg;
if (mc->shift == RT715_DIR_OUT_SFT) /* output */
val_h = 0x80;
else /* input */
val_h = 0x0;
rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
/* L Channel */
if (mc->invert) {
/* for mute */
val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7;
/* keep gain */
read_ll = read_ll & 0x7f;
val_ll |= read_ll;
} else {
/* for gain */
val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
if (val_ll > mc->max)
val_ll = mc->max;
/* keep mute status */
read_ll = read_ll & 0x80;
val_ll |= read_ll;
}
/* R Channel */
if (mc->invert) {
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
/* for mute */
val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7;
/* keep gain */
read_rl = read_rl & 0x7f;
val_lr |= read_rl;
} else {
/* for gain */
val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
if (val_lr > mc->max)
val_lr = mc->max;
/* keep mute status */
read_rl = read_rl & 0x80;
val_lr |= read_rl;
}
for (i = 0; i < 3; i++) { /* retry 3 times at most */
if (val_ll == val_lr) {
/* Set both L/R channels at the same time */
val_h = (1 << mc->shift) | (3 << 4);
regmap_write(rt715->regmap, addr_h,
(val_h << 8 | val_ll));
regmap_write(rt715->regmap, addr_l,
(val_h << 8 | val_ll));
} else {
/* Lch*/
val_h = (1 << mc->shift) | (1 << 5);
regmap_write(rt715->regmap, addr_h,
(val_h << 8 |