2025-05-10 21:49:39 +08:00

1163 lines
32 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// rk630_codec.c -- rk630 ALSA Soc Audio driver
//
// Copyright (c) 2022 Rockchip Electronics Co. Ltd.
// Author: Xinhuang Li <buluess.li@rock-chips.com>
// Author: Yanchao Hu <yanchao.hu@rock-chips.com>
//
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mfd/rk630.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/rockchip/grf.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "rk630_codec.h"
struct rk630_codec_priv {
struct regmap *regmap;
struct regmap *grf;
struct regmap *cru;
struct device *dev;
unsigned int irq;
struct snd_soc_component *component;
unsigned int stereo_sysclk;
unsigned int rate;
bool mic_in_differential;
struct gpio_desc *spk_ctl_gpio;
struct clk *pclk;
struct clk *mclk;
};
static int rk630_init(struct snd_soc_component *component)
{
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
snd_soc_component_write(component, RK630_RESET, 0x00);
mdelay(10);
snd_soc_component_write(component, RK630_RESET, 0x43);
mdelay(10);
snd_soc_component_update_bits(component, RK630_BSTL_ALCL_CTL,
RK630_BSTL_MODE_EN, RK630_BSTL_MODE_SINGLE);
dev_dbg(component->dev, "%s mic_in_differential = %d\n",
__func__, rk630->mic_in_differential);
if (rk630->mic_in_differential) {
snd_soc_component_update_bits(component, RK630_BSTL_ALCL_CTL,
RK630_BSTL_MODE_EN, RK630_BSTL_MODE_DIFF);
snd_soc_component_update_bits(component, RK630_ALC_MUNIN_CTL,
RK630_ALCR_MUTE_SHT, RK630_ALCR_DIS);
}
return 0;
}
static const struct reg_default rk630_reg_defaults[] = {
{ RK630_RESET, 0x0003 },
{ RK630_ADC_INT_CTL1, 0x0050 },
{ RK630_ADC_INT_CTL2, 0x000e },
{ RK630_DAC_INT_CTL1, 0x0050 },
{ RK630_DAC_INT_CTL2, 0x000e },
{ RK630_DAC_INT_CTL3, 0x22 },
{ RK630_ADC_MIC_CTL, 0x0000 },
{ RK630_BST_CTL, 0x000 },
{ RK630_ALC_MUNIN_CTL, 0x0044 },
{ RK630_BSTL_ALCL_CTL, 0x000c },
{ RK630_ALCR_GAIN_CTL, 0x000C },
{ RK630_ADC_ENABLE, 0x0000 },
{ RK630_DAC_CTL, 0x0000 },
{ RK630_DAC_ENABLE, 0x0000 },
{ RK630_HPMIX_CTL, 0x0000 },
{ RK630_HPMIX_S_SELECT, 0x0000 },
{ RK630_HPOUT_CTL, 0x0000 },
{ RK630_HPOUTL_GAIN, 0x0000 },
{ RK630_HPOUTR_GAIN, 0x0000 },
{ RK630_SELECT_CURRENT, 0x003e },
{ RK630_PGAL_AGC_CTL1, 0x0000 },
{ RK630_PGAL_AGC_CTL2, 0x0046 },
{ RK630_PGAL_AGC_CTL3, 0x0041 },
{ RK630_PGAL_AGC_CTL4, 0x000c },
{ RK630_PGAL_ASR_CTL, 0x0000 },
{ RK630_PGAL_AGC_MAX_H, 0x0026 },
{ RK630_PGAL_AGC_MAX_L, 0x0040 },
{ RK630_PGAL_AGC_MIN_H, 0x0036 },
{ RK630_PGAL_AGC_MIN_L, 0x0020 },
{ RK630_PGAL_AGC_CTL5, 0x0038 },
{ RK630_PGAR_AGC_CTL1, 0x0000 },
{ RK630_PGAR_AGC_CTL2, 0x0046 },
{ RK630_PGAR_AGC_CTL3, 0x0041 },
{ RK630_PGAR_AGC_CTL4, 0x000c },
{ RK630_PGAR_ASR_CTL, 0x0000 },
{ RK630_PGAR_AGC_MAX_H, 0x0026 },
{ RK630_PGAR_AGC_MAX_L, 0x0040 },
{ RK630_PGAR_AGC_MIN_H, 0x0036 },
{ RK630_PGAR_AGC_MIN_L, 0x0020 },
{ RK630_PGAR_AGC_CTL5, 0x0038 },
};
static bool rk630_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RK630_RESET:
case RK630_ADC_INT_CTL2:
return true;
default:
return false;
}
}
static bool rk630_codec_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RK630_RESET:
case RK630_ADC_INT_CTL1:
case RK630_ADC_INT_CTL2:
case RK630_DAC_INT_CTL1:
case RK630_DAC_INT_CTL2:
case RK630_DAC_INT_CTL3:
case RK630_ADC_MIC_CTL:
case RK630_BST_CTL:
case RK630_ALC_MUNIN_CTL:
case RK630_BSTL_ALCL_CTL:
case RK630_ALCR_GAIN_CTL:
case RK630_ADC_ENABLE:
case RK630_DAC_CTL:
case RK630_DAC_ENABLE:
case RK630_HPMIX_CTL:
case RK630_HPMIX_S_SELECT:
case RK630_HPOUT_CTL:
case RK630_HPOUTL_GAIN:
case RK630_HPOUTR_GAIN:
case RK630_SELECT_CURRENT:
case RK630_PGAL_AGC_CTL1:
case RK630_PGAL_AGC_CTL2:
case RK630_PGAL_AGC_CTL3:
case RK630_PGAL_AGC_CTL4:
case RK630_PGAL_ASR_CTL:
case RK630_PGAL_AGC_MAX_H:
case RK630_PGAL_AGC_MAX_L:
case RK630_PGAL_AGC_MIN_H:
case RK630_PGAL_AGC_MIN_L:
case RK630_PGAL_AGC_CTL5:
case RK630_PGAR_AGC_CTL1:
case RK630_PGAR_AGC_CTL2:
case RK630_PGAR_AGC_CTL3:
case RK630_PGAR_AGC_CTL4:
case RK630_PGAR_ASR_CTL:
case RK630_PGAR_AGC_MAX_H:
case RK630_PGAR_AGC_MAX_L:
case RK630_PGAR_AGC_MIN_H:
case RK630_PGAR_AGC_MIN_L:
case RK630_PGAR_AGC_CTL5:
case RK630_ALC_CTL:
return true;
default:
return false;
}
}
static int rk630_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
dev_dbg(component->dev, "%s level=%d\n", __func__, level);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
snd_soc_component_write(component, RK630_DAC_INT_CTL3, 0x32);
snd_soc_component_update_bits(component, RK630_ADC_MIC_CTL,
RK630_ADC_CURRENT_ENABLE,
RK630_ADC_CURRENT_ENABLE);
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_CURRENT_EN,
RK630_CURRENT_EN);
/* set power */
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCL_REF_VOL_EN |
RK630_ADCR_REF_VOL_EN,
RK630_ADCL_REF_VOL_EN |
RK630_ADCR_REF_VOL_EN);
snd_soc_component_update_bits(component, RK630_ADC_MIC_CTL,
RK630_ADCL_ZERO_DET_EN |
RK630_ADCR_ZERO_DET_EN,
RK630_ADCL_ZERO_DET_EN |
RK630_ADCR_ZERO_DET_EN);
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_REF_VOL_DACL_EN |
RK630_REF_VOL_DACR_EN,
RK630_REF_VOL_DACL_EN |
RK630_REF_VOL_DACR_EN);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_REF_VOL_EN |
RK630_DACR_REF_VOL_EN,
RK630_DACL_REF_VOL_EN |
RK630_DACR_REF_VOL_EN);
}
break;
case SND_SOC_BIAS_OFF:
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_REF_VOL_EN |
RK630_DACR_REF_VOL_EN,
0);
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_REF_VOL_DACL_EN |
RK630_REF_VOL_DACR_EN,
0);
snd_soc_component_update_bits(component, RK630_ADC_MIC_CTL,
RK630_ADCL_ZERO_DET_EN |
RK630_ADCR_ZERO_DET_EN,
0);
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCL_REF_VOL_EN |
RK630_ADCR_REF_VOL_EN,
0);
snd_soc_component_update_bits(component, RK630_ADC_MIC_CTL,
RK630_ADC_CURRENT_ENABLE,
0);
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_CURRENT_EN,
0);
snd_soc_component_write(component, RK630_DAC_INT_CTL3, 0x22);
break;
}
return 0;
}
static const DECLARE_TLV_DB_SCALE(bst_vol_tlv, 0, 2000, 0);
static const DECLARE_TLV_DB_MINMAX(pga_vol_tlv, -1800, 2850);
static const DECLARE_TLV_DB_MINMAX(out_vol_tlv, -3900, 600);
static const struct snd_kcontrol_new rk630_snd_controls[] = {
SOC_SINGLE_TLV("BSTL Capture Volume", RK630_BST_CTL,
RK630_BSTL_GAIN_SHT, 1, 0, bst_vol_tlv),
SOC_SINGLE_TLV("BSTR Capture Volume", RK630_BST_CTL,
RK630_BSTR_GAIN_SHT, 1, 0, bst_vol_tlv),
SOC_DOUBLE_R_RANGE_TLV("PGA AGC Volume", RK630_PGAL_AGC_CTL4,
RK630_PGAR_AGC_CTL4, 0, 0x00, 0x1f, 0, pga_vol_tlv),
SOC_DOUBLE_R_RANGE_TLV("Playback Volume", RK630_HPOUTL_GAIN,
RK630_HPOUTR_GAIN, 0, 0x00, 0x1f, 0, out_vol_tlv),
SOC_SINGLE("ALCL Switch", RK630_ALC_MUNIN_CTL,
RK630_ALCL_MUTE_SHT, 1, 0),
SOC_SINGLE("ALCR Switch", RK630_ALC_MUNIN_CTL,
RK630_ALCR_MUTE_SHT, 1, 0),
};
static int rk630_dacl_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_WORK, 0);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_EN | RK630_DACL_CLK_EN,
RK630_DACL_EN | RK630_DACL_CLK_EN);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_WORK, RK630_DACL_WORK);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_EN
| RK630_DACL_CLK_EN, 0);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACL_WORK, 0);
break;
default:
return 0;
}
return 0;
}
static int rk630_dacr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACR_WORK, 0);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACR_EN
| RK630_DACR_CLK_EN,
RK630_DACR_EN
| RK630_DACR_CLK_EN);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACR_WORK,
RK630_DACR_WORK);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACR_EN
| RK630_DACR_CLK_EN, 0);
snd_soc_component_update_bits(component, RK630_DAC_ENABLE,
RK630_DACR_WORK, 0);
break;
default:
return 0;
}
return 0;
}
static int rk630_adcl_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCL_CLK_EN
| RK630_ADCL_AMP_EN,
RK630_ADCL_CLK_EN
| RK630_ADCL_AMP_EN);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCL_CLK_EN
| RK630_ADCL_AMP_EN, 0);
break;
default:
return 0;
}
return 0;
}
static int rk630_adcr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCR_CLK_EN
| RK630_ADCR_AMP_EN,
RK630_ADCR_CLK_EN
| RK630_ADCR_AMP_EN);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, RK630_ADC_ENABLE,
RK630_ADCR_CLK_EN
| RK630_ADCR_AMP_EN, 0);
break;
default:
return 0;
}
return 0;
}
/* HPmix */
static const struct snd_kcontrol_new rk630_hpmixl[] = {
SOC_DAPM_SINGLE("ALCR Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXL_SEL_ALCR_SFT, 1, 0),
SOC_DAPM_SINGLE("ALCL Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXL_SEL_ALCL_SFT, 1, 0),
SOC_DAPM_SINGLE("DACL Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXL_SEL_DACL_SFT, 1, 0),
};
static const struct snd_kcontrol_new rk630_hpmixr[] = {
SOC_DAPM_SINGLE("ALCR Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXR_SEL_ALCR_SFT, 1, 0),
SOC_DAPM_SINGLE("ALCL Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXR_SEL_ALCL_SFT, 1, 0),
SOC_DAPM_SINGLE("DACR Switch", RK630_HPMIX_S_SELECT,
RK630_HPMIXR_SEL_DACR_SFT, 1, 0),
};
static int rk630_hpmixl_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_ZO_DET_VOUTL_EN,
RK630_ZO_DET_VOUTL_EN);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_ZO_DET_VOUTL_EN,
RK630_ZO_DET_VOUTL_DIS);
break;
default:
return 0;
}
return 0;
}
static int rk630_hpmixr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_ZO_DET_VOUTR_EN,
RK630_ZO_DET_VOUTR_EN);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_component_update_bits(component, RK630_DAC_CTL,
RK630_ZO_DET_VOUTR_EN,
RK630_ZO_DET_VOUTR_DIS);
break;
default:
return 0;
}
return 0;
}
/* HP MUX */
static const char *const hpl_sel[] = {"HPMIXL", "DACL"};
static const struct soc_enum hpl_sel_enum =
SOC_ENUM_SINGLE(RK630_HPMIX_S_SELECT, RK630_HPMIXL_BYPASS_SFT,
ARRAY_SIZE(hpl_sel), hpl_sel);
static const struct snd_kcontrol_new hpl_sel_mux =
SOC_DAPM_ENUM("HPL select Mux", hpl_sel_enum);
static const char *const hpr_sel[] = {"HPMIXR", "DACR"};
static const struct soc_enum hpr_sel_enum =
SOC_ENUM_SINGLE(RK630_HPMIX_S_SELECT, RK630_HPMIXR_BYPASS_SFT,
ARRAY_SIZE(hpr_sel), hpr_sel);
static const struct snd_kcontrol_new hpr_sel_mux =
SOC_DAPM_ENUM("HPR select Mux", hpr_sel_enum);
/* IN_L MUX */
static const char *const lnl_sel[] = {"NO", "BSTL", "LINEL", "NOUSE"};
static const struct soc_enum lnl_sel_enum =
SOC_ENUM_SINGLE(RK630_ALC_MUNIN_CTL, RK630_MUXINL_F_SHT,
ARRAY_SIZE(lnl_sel), lnl_sel);
static const struct snd_kcontrol_new lnl_sel_mux =
SOC_DAPM_ENUM("MUXIN_L select", lnl_sel_enum);
/* IN_R MUX */
static const char *const lnr_sel[] = {"NO", "BSTR", "LINER", "NOUSE"};
static const struct soc_enum lnr_sel_enum =
SOC_ENUM_SINGLE(RK630_ALC_MUNIN_CTL, RK630_MUXINR_F_SHT,
ARRAY_SIZE(lnr_sel), lnr_sel);
static const struct snd_kcontrol_new lnr_sel_mux =
SOC_DAPM_ENUM("MUXIN_R select", lnr_sel_enum);
static const struct snd_soc_dapm_widget rk630_dapm_widgets[] = {
/* microphone bias */
SND_SOC_DAPM_SUPPLY("Mic Bias", RK630_ADC_MIC_CTL, RK630_MICBIAS_VOL_ENABLE, 0, NULL, 0),
/* ADCs */
SND_SOC_DAPM_ADC_E("ADCL", NULL, SND_SOC_NOPM,
0, 0, rk630_adcl_event,
SND_SOC_DAPM_POST_PMD
| SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_ADC_E("ADCR", NULL, SND_SOC_NOPM,
0, 0, rk630_adcr_event,
SND_SOC_DAPM_POST_PMD
| SND_SOC_DAPM_POST_PMU),
/* PGA */
SND_SOC_DAPM_PGA("BSTL", RK630_BST_CTL, RK630_BSTL_PWRD_SFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("BSTR", RK630_BST_CTL, RK630_BSTR_PWRD_SFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("BSTL Mute", RK630_BST_CTL, RK630_BSTL_MUTE_SHT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("BSTR Mute", RK630_BST_CTL, RK630_BSTR_MUTE_SHT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ALCL", RK630_ALC_MUNIN_CTL, RK630_ALCL_PWR_SHT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ALCR", RK630_ALC_MUNIN_CTL, RK630_ALCR_PWR_SHT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ALCL Mute", RK630_ALC_MUNIN_CTL, RK630_ALCL_MUTE_SHT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ALCR Mute", RK630_ALC_MUNIN_CTL, RK630_ALCR_MUTE_SHT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ALCL Ctl", RK630_ALC_CTL, 5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ALCR Ctl", RK630_ALC_CTL, 4, 0, NULL, 0),
/* DACs */
SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM,
0, 0, rk630_dacl_event,
SND_SOC_DAPM_POST_PMD
| SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM,
0, 0, rk630_dacr_event,
SND_SOC_DAPM_POST_PMD
| SND_SOC_DAPM_POST_PMU),
/* PGA */
SND_SOC_DAPM_PGA("HPL", RK630_HPOUT_CTL,
RK630_HPOUTL_PWR_SHT, 0, NULL, 0),
SND_SOC_DAPM_PGA("HPR", RK630_HPOUT_CTL,
RK630_HPOUTR_PWR_SHT, 0, NULL, 0),
/* MIXER */
SND_SOC_DAPM_MIXER_E("HPMIXL", RK630_HPMIX_CTL,
RK630_HPMIXL_SFT, 0,
rk630_hpmixl,
ARRAY_SIZE(rk630_hpmixl),
rk630_hpmixl_event,
SND_SOC_DAPM_PRE_PMD
| SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MIXER_E("HPMIXR", RK630_HPMIX_CTL,
RK630_HPMIXR_SFT, 0,
rk630_hpmixr,
ARRAY_SIZE(rk630_hpmixr),
rk630_hpmixr_event,
SND_SOC_DAPM_PRE_PMD
| SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("HPR Init", RK630_HPOUT_CTL, 3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("HPL Init", RK630_HPOUT_CTL, 6, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DACR Mute Off", RK630_HPOUT_CTL, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DACL Mute Off", RK630_HPOUT_CTL, 5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("HPR Vref", RK630_HPOUT_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("HPL Vref", RK630_HPOUT_CTL, 1, 0, NULL, 0),
/* MUX */
SND_SOC_DAPM_MUX("IN_R Mux", SND_SOC_NOPM, 0, 0, &lnr_sel_mux),
SND_SOC_DAPM_MUX("IN_L Mux", SND_SOC_NOPM, 0, 0, &lnl_sel_mux),
SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_sel_mux),
SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_sel_mux),
/* Audio Interface */
SND_SOC_DAPM_AIF_OUT("I2S DAC", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("I2S ADC", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
/* Input */
SND_SOC_DAPM_INPUT("LINEL"),
SND_SOC_DAPM_INPUT("LINER"),
SND_SOC_DAPM_INPUT("MICP"),
SND_SOC_DAPM_INPUT("MICN"),
/* Output */
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
};
static const struct snd_soc_dapm_route rk630_dapm_routes[] = {
/* Input */
{"BSTR", NULL, "MICP"},
{"BSTL", NULL, "MICP"},
{"BSTL", NULL, "MICN"},
{"IN_R Mux", "LINER", "LINER"},
{"IN_R Mux", "BSTR", "BSTR"},
{"IN_L Mux", "LINEL", "LINEL"},
{"IN_L Mux", "BSTL", "BSTL"},
{"ALCL", NULL, "IN_L Mux"},
{"ALCR", NULL, "IN_R Mux"},
{"ADCR", NULL, "ALCR"},
{"ADCL", NULL, "ALCL"},
{"I2S ADC", NULL, "BSTR Mute"},
{"I2S ADC", NULL, "BSTL Mute"},
{"I2S ADC", NULL, "ALCR Mute"},
{"I2S ADC", NULL, "ALCL Mute"},
{"I2S ADC", NULL, "ALCR Ctl"},
{"I2S ADC", NULL, "ALCL Ctl"},
{"I2S ADC", NULL, "Mic Bias"},
{"I2S ADC", NULL, "ADCR"},
{"I2S ADC", NULL, "ADCL"},
/* Output */
{"DACR", NULL, "I2S DAC"},
{"DACL", NULL, "I2S DAC"},
{"HPMIXR", "ALCR Switch", "ALCR"},
{"HPMIXR", "ALCL Switch", "ALCL"},
{"HPMIXR", "DACR Switch", "DACR"},
{"HPMIXL", "ALCR Switch", "ALCR"},
{"HPMIXL", "ALCL Switch", "ALCL"},
{"HPMIXL", "DACL Switch", "DACL"},
{"HPR", NULL, "HPR Vref"},
{"HPL", NULL, "HPL Vref"},
{"DACR", NULL, "DACR Mute Off"},
{"DACL", NULL, "DACL Mute Off"},
{"HPR Mux", "DACR", "DACR"},
{"HPR Mux", "HPMIXR", "HPMIXR"},
{"HPL Mux", "DACL", "DACL"},
{"HPL Mux", "HPMIXL", "HPMIXL"},
{"HPR", NULL, "HPR Mux"},
{"HPL", NULL, "HPL Mux"},
{"HPR", NULL, "HPR Init"},
{"HPL", NULL, "HPL Init"},
{"HPOUTR", NULL, "HPR"},
{"HPOUTL", NULL, "HPL"},
};
static int rk630_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
if (!rk630) {
dev_warn(component->dev, "%s : rk630 is NULL\n", __func__);
return -EINVAL;
}
rk630->stereo_sysclk = freq;
return 0;
}
static int rk630_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
adc_aif2 |= RK630_I2S_MODE_SLV;
/*set tx_lrck->lrck,rx_lrck->lrck*/
regmap_write(rk630->grf,
PLUMAGE_GRF_SOC_CON0,
((CON_TX_LRCK_EN_MASK | CON_RX_LRCK_EN_MASK) <<
PLUMAGE_GRF_MASK_SHIFT) |
(CON_TX_LRCK_EN | CON_RX_LRCK_EN));
/*sclk oe:1,lrck oe:1*/
regmap_write(rk630->grf,
PLUMAGE_GRF_SOC_CON0,
((CON_SCLK_OE_MASK | CON_I2S_LRCK_OE_MASK) <<
PLUMAGE_GRF_MASK_SHIFT) |
(CON_SCLK_OE_SLAVE | CON_I2S_LRCK_OE_SLAVE));
break;
case SND_SOC_DAIFMT_CBM_CFM:
adc_aif2 |= RK630_I2S_MODE_MST;
/*set tx_lrck->lrck*/
regmap_write(rk630->grf,
PLUMAGE_GRF_SOC_CON0,
((CON_TX_LRCK_EN_MASK | CON_RX_LRCK_EN_MASK) <<
PLUMAGE_GRF_MASK_SHIFT) |
(CON_TX_LRCK_EN | CON_RX_LRCK_DIS));
/*sclk oe:0,lrck oe:0*/
regmap_write(rk630->grf,
PLUMAGE_GRF_SOC_CON0,
((CON_SCLK_OE_MASK | CON_I2S_LRCK_OE_MASK) <<
PLUMAGE_GRF_MASK_SHIFT) |
(CON_SCLK_OE_MASTER | CON_I2S_LRCK_OE_MASTER));
break;
default:
dev_warn(component->dev, "%s : set master mask failed!\n", __func__);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
adc_aif1 |= RK630_ADC_DF_PCM;
dac_aif1 |= RK630_DAC_DF_PCM;
break;
case SND_SOC_DAIFMT_DSP_B:
break;
case SND_SOC_DAIFMT_I2S:
adc_aif1 |= RK630_ADC_DF_I2S;
dac_aif1 |= RK630_DAC_DF_I2S;
break;
case SND_SOC_DAIFMT_RIGHT_J:
adc_aif1 |= RK630_ADC_DF_RJ;
dac_aif1 |= RK630_DAC_DF_RJ;
break;
case SND_SOC_DAIFMT_LEFT_J:
adc_aif1 |= RK630_ADC_DF_LJ;
dac_aif1 |= RK630_DAC_DF_LJ;
break;
default:
dev_warn(component->dev, "%s : set format failed!\n", __func__);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
adc_aif1 |= RK630_ALRCK_POL_DIS;
adc_aif2 |= RK630_ABCLK_POL_DIS;
dac_aif1 |= RK630_DLRCK_POL_DIS;
dac_aif2 |= RK630_DBCLK_POL_DIS;
break;
case SND_SOC_DAIFMT_IB_IF:
adc_aif1 |= RK630_ALRCK_POL_EN;
adc_aif2 |= RK630_ABCLK_POL_EN;
dac_aif1 |= RK630_DLRCK_POL_EN;
dac_aif2 |= RK630_DBCLK_POL_EN;
break;
case SND_SOC_DAIFMT_IB_NF:
adc_aif1 |= RK630_ALRCK_POL_DIS;
adc_aif2 |= RK630_ABCLK_POL_EN;
dac_aif1 |= RK630_DLRCK_POL_DIS;
dac_aif2 |= RK630_DBCLK_POL_EN;
break;
case SND_SOC_DAIFMT_NB_IF:
adc_aif1 |= RK630_ALRCK_POL_EN;
adc_aif2 |= RK630_ABCLK_POL_DIS;
dac_aif1 |= RK630_DLRCK_POL_EN;
dac_aif2 |= RK630_DBCLK_POL_DIS;
break;
default:
dev_warn(component->dev, "%s : set dai format failed!\n", __func__);
return -EINVAL;
}
snd_soc_component_update_bits(component, RK630_ADC_INT_CTL1,
RK630_ALRCK_POL_MASK |
RK630_ADC_DF_MASK, adc_aif1);
snd_soc_component_update_bits(component, RK630_ADC_INT_CTL2,
RK630_ABCLK_POL_MASK |
RK630_I2S_MODE_MASK, adc_aif2);
snd_soc_component_update_bits(component, RK630_DAC_INT_CTL1,
RK630_DLRCK_POL_MASK |
RK630_DAC_DF_MASK, dac_aif1);
snd_soc_component_update_bits(component, RK630_DAC_INT_CTL2,
RK630_DBCLK_POL_MASK, dac_aif2);
return 0;
}
static int rk630_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component = rtd->codec_dai->component;
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
unsigned int rate = params_rate(params);
unsigned int div, approximate_sample;
unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
if (!rk630) {
dev_warn(component->dev, "%s : rk630 is NULL\n", __func__);
return -EINVAL;
}
/* bclk = codec_clk / 4 */
/* lrck = bclk / (wl * 2) */
div = (((rk630->stereo_sysclk / 4) / rate) / 2);
if ((rk630->stereo_sysclk % (4 * rate * 2) > 0) ||
(div != 16 && div != 20 && div != 24 && div != 32)) {
dev_warn(component->dev, "%s : need PLL\n", __func__);
return -EINVAL;
}
switch (div) {
case 16:
adc_aif2 |= RK630_ADC_WL_16;
dac_aif2 |= RK630_DAC_WL_16;
break;
case 20:
adc_aif2 |= RK630_ADC_WL_20;
dac_aif2 |= RK630_DAC_WL_20;
break;
case 24:
adc_aif2 |= RK630_ADC_WL_24;
dac_aif2 |= RK630_DAC_WL_24;
break;
case 32:
adc_aif2 |= RK630_ADC_WL_32;
dac_aif2 |= RK630_DAC_WL_32;
break;
default:
return -EINVAL;
}
dev_dbg(component->dev, "%s : MCLK = %dHz, sample rate = %dHz, div = %d\n",
__func__, rk630->stereo_sysclk, rate, div);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
adc_aif1 |= RK630_ADC_VWL_16;
dac_aif1 |= RK630_DAC_VWL_16;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
adc_aif1 |= RK630_ADC_VWL_20;
dac_aif1 |= RK630_DAC_VWL_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
adc_aif1 |= RK630_ADC_VWL_24;
dac_aif1 |= RK630_DAC_VWL_24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
adc_aif1 |= RK630_ADC_VWL_32;
dac_aif1 |= RK630_DAC_VWL_32;
break;
default:
return -EINVAL;
}
switch (params_channels(params)) {
case RK630_MONO:
adc_aif1 |= RK630_ADC_TYPE_MONO;
break;
case RK630_STEREO:
adc_aif1 |= RK630_ADC_TYPE_STEREO;
break;
default:
return -EINVAL;
}
adc_aif1 |= RK630_ADC_SWAP_DIS;
adc_aif2 |= RK630_ADC_RST_DIS;
dac_aif1 |= RK630_DAC_SWAP_DIS;
dac_aif2 |= RK630_DAC_RST_DIS;
rk630->rate = rate;
switch (rk630->rate) {
case 96000:
approximate_sample = RK630_PGA_ASR_96KHz;
break;
case 48000:
approximate_sample = RK630_PGA_ASR_48KHz;
break;
case 44100:
approximate_sample = RK630_PGA_ASR_441KHz;
break;
case 32000:
approximate_sample = RK630_PGA_ASR_32KHz;
break;
case 24000:
approximate_sample = RK630_PGA_ASR_24KHz;
break;
case 16000:
approximate_sample = RK630_PGA_ASR_16KHz;
break;
case 12000:
approximate_sample = RK630_PGA_ASR_12KHz;
break;
case 8000:
approximate_sample = RK630_PGA_ASR_8KHz;
break;
default:
return -EINVAL;
}
snd_soc_component_update_bits(component, RK630_PGAL_ASR_CTL,
RK630_PGA_ASR_MASK, approximate_sample);
snd_soc_component_update_bits(component, RK630_PGAR_ASR_CTL,
RK630_PGA_ASR_MASK, approximate_sample);
snd_soc_component_update_bits(component, RK630_ADC_INT_CTL1,
RK630_ADC_VWL_MASK |
RK630_ADC_SWAP_MASK |
RK630_ADC_TYPE_MASK,
adc_aif1);
snd_soc_component_update_bits(component, RK630_ADC_INT_CTL2,
RK630_ADC_WL_MASK |
RK630_ADC_RST_MASK,
adc_aif2);
snd_soc_component_update_bits(component, RK630_DAC_INT_CTL1,
RK630_DAC_VWL_MASK |
RK630_DAC_SWAP_MASK,
dac_aif1);
snd_soc_component_update_bits(component, RK630_DAC_INT_CTL2,
RK630_DAC_WL_MASK |
RK630_DAC_RST_MASK,
dac_aif2);
return 0;
}
static int rk630_codec_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
if (mute) {
if (rk630 && rk630->spk_ctl_gpio)
gpiod_set_value(rk630->spk_ctl_gpio, 0);
} else {
if (rk630 && rk630->spk_ctl_gpio)
gpiod_set_value(rk630->spk_ctl_gpio, 1);
}
return 0;
}
#define RK630_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_192000)
#define RK630_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000)
#define RK630_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops rk630_dai_ops = {
.hw_params = rk630_codec_hw_params,
.set_fmt = rk630_codec_set_dai_fmt,
.set_sysclk = rk630_codec_set_dai_sysclk,
.digital_mute = rk630_codec_digital_mute,
};
static struct snd_soc_dai_driver rk630_dai[] = {
{
.name = "rk630-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
.rates = RK630_PLAYBACK_RATES,
.formats = RK630_FORMATS,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
.rates = RK630_CAPTURE_RATES,
.formats = RK630_FORMATS,
},
.ops = &rk630_dai_ops,
},
};
static int rk630_codec_probe(struct snd_soc_component *component)
{
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
unsigned int val;
int ret;
snd_soc_component_init_regmap(component, rk630->regmap);
rk630->component = component;
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
regmap_write(rk630->cru, CRU_GATE_CON0, GRU_ACODECPHY_EN);
snd_soc_component_read(component, RK630_RESET, &val);
if (val != 0x03) {
dev_err(component->dev, "%s : codec register 0: %x is not a 0x00000003\n",
__func__, val);
ret = -ENODEV;
goto err__;
}
rk630_init(component);
return 0;
err__:
dev_err(component->dev, "%s err ret=%d\n", __func__, ret);
return ret;
}
/* power down chip */
static void rk630_codec_remove(struct snd_soc_component *component)
{
struct rk630_codec_priv *rk630 = snd_soc_component_get_drvdata(component);
if (!rk630) {
dev_err(component->dev, "%s : rk630 is NULL\n", __func__);
return;
}
if (rk630->spk_ctl_gpio)
gpiod_set_value(rk630->spk_ctl_gpio, 0);
snd_soc_component_write(component, RK630_RESET, 0xfc);
snd_soc_component_write(component, RK630_RESET, 0x3);
}
static const struct snd_soc_component_driver soc_codec_dev_rk630 = {
.probe = rk630_codec_probe,
.remove = rk630_codec_remove,
.set_bias_level = rk630_set_bias_level,
.controls = rk630_snd_controls,
.num_controls = ARRAY_SIZE(rk630_snd_controls),
.dapm_routes = rk630_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rk630_dapm_routes),
.dapm_widgets = rk630_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rk630_dapm_widgets),
};
const struct regmap_config rk630_codec_regmap_config = {
.name = "rk630-codec",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = RK630_MAX_REG,
.cache_type = REGCACHE_NONE,
.writeable_reg = rk630_codec_register,
.readable_reg = rk630_codec_register,
.volatile_reg = rk630_volatile_register,
.reg_defaults = rk630_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(rk630_reg_defaults),
.reg_format_endian = REGMAP_ENDIAN_NATIVE,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
};
static int rk630_codec_platform_probe(struct platform_device *pdev)
{
struct device_node *rk630_np = pdev->dev.of_node;
struct rk630 *rk630 = dev_get_drvdata(pdev->dev.parent);
struct rk630_codec_priv *rk630_codec;
int ret;
rk630_codec = devm_kzalloc(&pdev->dev, sizeof(*rk630_codec), GFP_KERNEL);
if (!rk630_codec)
return -ENOMEM;
rk630_codec->dev = &pdev->dev;
platform_set_drvdata(pdev, rk630_codec);
rk630_codec->grf = rk630->grf;
if (IS_ERR(rk630_codec->grf)) {
dev_err(&pdev->dev, "needs rk630 grf\n");
ret = PTR_ERR(rk630_codec->grf);
goto err__;
}
rk630_codec->cru = rk630->cru;
if (IS_ERR(rk630_codec->cru)) {
dev_err(&pdev->dev, "needs rk630 cru\n");
ret = PTR_ERR(rk630_codec->cru);
goto err__;
}
rk630_codec->regmap = rk630->codec;
if (IS_ERR(rk630_codec->regmap)) {
dev_err(&pdev->dev, "needs rk630 codec\n");
ret = PTR_ERR(rk630_codec->regmap);
goto err__;
}
rk630_codec->spk_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "spk-ctl",
GPIOD_OUT_LOW);
if (!IS_ERR_OR_NULL(rk630_codec->spk_ctl_gpio))
dev_dbg(&pdev->dev, "spk-ctl-gpio %d\n", desc_to_gpio(rk630_codec->spk_ctl_gpio));
rk630_codec->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(rk630_codec->mclk)) {
dev_err(&pdev->dev, "Unable to get mclk\n");
ret = -ENXIO;
goto err__;
}
ret = clk_prepare_enable(rk630_codec->mclk);
if (ret < 0) {
dev_err(&pdev->dev, "%s() clock prepare error %d\n",
__func__, ret);
goto err__;
}
rk630_codec->mic_in_differential =
of_property_read_bool(rk630_np, "mic-in-differential");
return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk630,
rk630_dai, ARRAY_SIZE(rk630_dai));
err__:
platform_set_drvdata(pdev, NULL);
return ret;
}
static int rk630_codec_platform_remove(struct platform_device *pdev)
{
struct rk630_codec_priv *rk630_codec = platform_get_drvdata(pdev);
clk_disable_unprepare(rk630_codec->mclk);
return 0;
}
static void rk630_codec_platform_shutdown(struct platform_device *pdev)
{
struct rk630_codec_priv *rk630 = dev_get_drvdata(&pdev->dev);
if (!rk630 || !rk630->component)
return;
if (rk630->spk_ctl_gpio)
gpiod_set_value(rk630->spk_ctl_gpio, 0);
snd_soc_component_write(rk630->component, RK630_RESET, 0xfc);
snd_soc_component_write(rk630->component, RK630_RESET, 0x03);
}
static const struct of_device_id rk630_codec_of_match[] = {
{ .compatible = "rockchip,rk630-codec" },
{},
};
static struct platform_driver rk630_codec_driver = {
.driver = {
.name = "rk630-codec",
.of_match_table = of_match_ptr(rk630_codec_of_match),
},
.probe = rk630_codec_platform_probe,
.remove = rk630_codec_platform_remove,
.shutdown = rk630_codec_platform_shutdown,
};
module_platform_driver(rk630_codec_driver);
MODULE_DESCRIPTION("ASoC RK630 CODEC driver");
MODULE_AUTHOR("Xinhuang Li <buluess.li@rock-chips.com>");
MODULE_LICENSE("GPL");