From 23c49bc23ca34afdd22b5c5180adf0a01385a8a5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=99=88=E9=87=91=E6=B3=89?= Date: Thu, 18 Apr 2013 10:42:32 +0800 Subject: [PATCH] add rk616 codec driver --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rk616_codec.c | 1766 ++++++++++++++++++++++++++++++++ sound/soc/codecs/rk616_codec.h | 737 +++++++++++++ sound/soc/rk29/Kconfig | 9 + sound/soc/rk29/Makefile | 2 + sound/soc/rk29/rk_rk616.c | 286 ++++++ 7 files changed, 2807 insertions(+) create mode 100755 sound/soc/codecs/rk616_codec.c create mode 100755 sound/soc/codecs/rk616_codec.h create mode 100755 sound/soc/rk29/rk_rk616.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6619b8fb5554..3889aff2bd7f 100755 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -87,6 +87,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5639 if I2C select SND_SOC_RT5616 if I2C select SND_SOC_RK610 if I2C + select SND_SOC_RK616 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C select SND_SOC_WM8915 if I2C @@ -437,6 +438,10 @@ config SND_SOC_RK610 tristate depends on MFD_RK610 +config SND_SOC_RK616 + tristate + depends on MFD_RK616 + # Amp config SND_SOC_LM4857 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a03da1769aa4..62292a90224e 100755 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -93,6 +93,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-rk1000-objs := rk1000_codec.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-rk610-objs := rk610_codec.o +snd-soc-rk616-objs := rk616_codec.o snd-soc-rt5640-objs := rt5640.o rt5640-dsp.o rt5640_ioctl.o rt56xx_ioctl.o snd-soc-rt3261-objs := rt3261.o rt3261-dsp.o rt3261_ioctl.o rt_codec_ioctl.o snd-soc-rt3224-objs := rt3261.o rt3261_ioctl.o rt_codec_ioctl.o @@ -204,6 +205,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_RK1000) += snd-soc-rk1000.o obj-$(CONFIG_SND_SOC_RK610) += snd-soc-rk610.o +obj-$(CONFIG_SND_SOC_RK616) += snd-soc-rk616.o obj-$(CONFIG_SND_SOC_RK2928) += snd-soc-rk2928.o # Amp diff --git a/sound/soc/codecs/rk616_codec.c b/sound/soc/codecs/rk616_codec.c new file mode 100755 index 000000000000..99f49f9a3e76 --- /dev/null +++ b/sound/soc/codecs/rk616_codec.c @@ -0,0 +1,1766 @@ +/* + * rk616.c -- RK616 CODEC ALSA SoC audio driver + * + * Copyright 2013 Rockship + * Author: chenjq + */ + +#define DEBUG //for log + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk616_codec.h" +#include + + +#define RK616_FOR_MID + +#define RK616_REG_RW /* for debug */ +#define RK616_PROC +#ifdef RK616_PROC +#include +#include +#include +#endif + +#ifdef CONFIG_RK_HEADSET_DET +#include "../../../drivers/headset_observe/rk_headset.h" +#endif + +struct rk616_codec_priv { + struct snd_soc_codec *codec; + + unsigned int stereo_sysclk; + unsigned int rate; +#ifdef RK616_FOR_MID + int playback_active; + int capture_active; +#endif + int spk_ctr_status; + int spk_ctr_pin; + int spk_ctr_on; + int spk_ctr_off; +}; + +static struct rk616_codec_priv *rk616_priv = NULL; + +static const unsigned int rk616_reg_defaults[RK616_PGAR_AGC_CTL5 + 1] = { + [RK616_RESET] = 0x0003, + [RK616_ADC_INT_CTL1] = 0x0050, + [RK616_ADC_INT_CTL2] = 0x000e, + [RK616_DAC_INT_CTL1] = 0x0050, + [RK616_DAC_INT_CTL2] = 0x001c, + [RK616_PGA_AGC_CTL] = 0x000c, + [RK616_PWR_ADD1] = 0x007c, + [RK616_BST_CTL] = 0x0099, + [RK616_DIFFIN_CTL] = 0x0024, + [RK616_MIXINL_CTL] = 0x001f, + [RK616_MIXINL_VOL1] = 0x0024, + [RK616_MIXINL_VOL2] = 0x0004, + [RK616_MIXINR_CTL] = 0x003f, + [RK616_MIXINR_VOL1] = 0x0024, + [RK616_MIXINR_VOL2] = 0x0024, + [RK616_PGAL_CTL] = 0x00cc, + [RK616_PGAR_CTL] = 0x00cc, + [RK616_PWR_ADD2] = 0x00ff, + [RK616_DAC_CTL] = 0x003f, + [RK616_LINEMIX_CTL] = 0x001f, + [RK616_MUXHP_HPMIX_CTL] = 0x003c, + [RK616_HPMIX_CTL] = 0x00ff, + [RK616_HPMIX_VOL1] = 0x0000, + [RK616_HPMIX_VOL2] = 0x0000, + [RK616_LINEOUT1_CTL] = 0x0060, + [RK616_LINEOUT2_CTL] = 0x0060, + [RK616_SPKL_CTL] = 0x00e0, + [RK616_SPKR_CTL] = 0x00e0, + [RK616_HPL_CTL] = 0x00e0, + [RK616_HPR_CTL] = 0x00e0, + [RK616_MICBIAS_CTL] = 0x00ff, + [RK616_MICKEY_DET_CTL] = 0x0028, + [RK616_PWR_ADD3] = 0x000f, + [RK616_ADC_CTL] = 0x0036, + [RK616_PGAL_AGC_CTL1] = 0x001f, + [RK616_PGAL_AGC_CTL2] = 0x0025, + [RK616_PGAL_AGC_CTL3] = 0x0041, + [RK616_PGAL_AGC_CTL4] = 0x002c, + [RK616_PGAL_ASR_CTL] = 0x0000, + [RK616_PGAL_AGC_MAX_H] = 0x0026, + [RK616_PGAL_AGC_MAX_L] = 0x0040, + [RK616_PGAL_AGC_MIN_H] = 0x0036, + [RK616_PGAL_AGC_MIN_L] = 0x0020, + [RK616_PGAL_AGC_CTL5] = 0x0038, + [RK616_PGAR_AGC_CTL1] = 0x001f, + [RK616_PGAR_AGC_CTL2] = 0x0025, + [RK616_PGAR_AGC_CTL3] = 0x0041, + [RK616_PGAR_AGC_CTL4] = 0x002c, + [RK616_PGAR_ASR_CTL] = 0x0000, + [RK616_PGAR_AGC_MAX_H] = 0x0026, + [RK616_PGAR_AGC_MAX_L] = 0x0040, + [RK616_PGAR_AGC_MIN_H] = 0x0036, + [RK616_PGAR_AGC_MIN_L] = 0x0020, + [RK616_PGAR_AGC_CTL5] = 0x0038, +}; + +static struct rk616_reg_val_typ rk616_mfd_reg_defaults[] = { + {CRU_CODEC_DIV, 0x00000000}, + {CRU_IO_CON0, (I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) | + ((I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16)}, + {CRU_IO_CON1, (I2S1_SI_EN | I2S0_SI_EN) | ((I2S1_SI_EN | I2S0_SI_EN) << 16)}, +}; + +static struct rk616_reg_val_typ rk616_mfd_reg_cache[] = { + {CRU_CODEC_DIV, 0x00000000}, + {CRU_IO_CON0, (I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) | + ((I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16)}, + {CRU_IO_CON1, (I2S1_SI_EN | I2S0_SI_EN) | ((I2S1_SI_EN | I2S0_SI_EN) << 16)}, +}; + +#define RK616_MFD_REG_LEN ARRAY_SIZE(rk616_mfd_reg_cache) + +static int rk616_mfd_register(unsigned int reg) +{ + int i; + + for (i = 0; i < RK616_MFD_REG_LEN; i++) { + if (rk616_mfd_reg_cache[i].reg == reg) + return 1; + } + + return 0; +} + +//writeable mask bit 16~31 +static int rk616_mfd_mask_register(unsigned int reg) +{ + switch (reg) { + case CRU_IO_CON0: + case CRU_IO_CON1: + return 1; + default: + return 0; + } +} + +static int rk616_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +{ + switch (reg) { + case RK616_RESET: + case RK616_MICKEY_DET_CTL: + return 1; + default: + return 0; + } +} + +static int rk616_codec_register(struct snd_soc_codec *codec, unsigned int reg) +{ + switch (reg) { + case RK616_RESET: + case RK616_ADC_INT_CTL1 : + case RK616_ADC_INT_CTL2 : + case RK616_DAC_INT_CTL1: + case RK616_DAC_INT_CTL2: + case RK616_PGA_AGC_CTL: + case RK616_PWR_ADD1: + case RK616_BST_CTL: + case RK616_DIFFIN_CTL: + case RK616_MIXINL_CTL: + case RK616_MIXINL_VOL1: + case RK616_MIXINL_VOL2: + case RK616_MIXINR_CTL: + case RK616_MIXINR_VOL1: + case RK616_MIXINR_VOL2: + case RK616_PGAL_CTL: + case RK616_PGAR_CTL : + case RK616_PWR_ADD2: + case RK616_DAC_CTL: + case RK616_LINEMIX_CTL: + case RK616_MUXHP_HPMIX_CTL: + case RK616_HPMIX_CTL: + case RK616_HPMIX_VOL1: + case RK616_HPMIX_VOL2: + case RK616_LINEOUT1_CTL: + case RK616_LINEOUT2_CTL: + case RK616_SPKL_CTL: + case RK616_SPKR_CTL: + case RK616_HPL_CTL: + case RK616_HPR_CTL: + case RK616_MICBIAS_CTL: + case RK616_MICKEY_DET_CTL: + case RK616_PWR_ADD3: + case RK616_ADC_CTL: + case RK616_PGAL_AGC_CTL1: + case RK616_PGAL_AGC_CTL2: + case RK616_PGAL_AGC_CTL3: + case RK616_PGAL_AGC_CTL4: + case RK616_PGAL_ASR_CTL: + case RK616_PGAL_AGC_MAX_H: + case RK616_PGAL_AGC_MAX_L: + case RK616_PGAL_AGC_MIN_H: + case RK616_PGAL_AGC_MIN_L: + case RK616_PGAL_AGC_CTL5: + case RK616_PGAR_AGC_CTL1: + case RK616_PGAR_AGC_CTL2: + case RK616_PGAR_AGC_CTL3: + case RK616_PGAR_AGC_CTL4: + case RK616_PGAR_ASR_CTL: + case RK616_PGAR_AGC_MAX_H: + case RK616_PGAR_AGC_MAX_L: + case RK616_PGAR_AGC_MIN_H: + case RK616_PGAR_AGC_MIN_L: + case RK616_PGAR_AGC_CTL5: + return 1; + default: + return 0; + } +} + +static inline unsigned int rk616_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + unsigned int *cache = codec->reg_cache; + int i; + + if (rk616_codec_register(codec, reg)) + return cache[reg]; + + if (rk616_mfd_register(reg)) { + for (i = 0; i < RK616_MFD_REG_LEN; i++) { + if (rk616_mfd_reg_cache[i].reg == reg) + return rk616_mfd_reg_cache[i].value; + } + } + + return -EINVAL; +} + +static inline void rk616_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + unsigned int *cache = codec->reg_cache; + int i; + + if (rk616_codec_register(codec, reg)) { + cache[reg] = value; + return; + } + + if (rk616_mfd_register(reg)) { + for (i = 0; i < RK616_MFD_REG_LEN; i++) { + if (rk616_mfd_reg_cache[i].reg == reg) { + rk616_mfd_reg_cache[i].value = value; + return; + } + } + } +} + +static unsigned int rk616_codec_read(struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int value; + struct mfd_rk616 *rk616 = snd_soc_codec_get_drvdata(codec); + + if (!rk616) + return -EINVAL; + + if (rk616_volatile_register(codec, reg) == 0) { + value = rk616_read_reg_cache(codec, reg); + } else { + if (rk616->read_dev(rk616, reg, &value) < 0) { + dev_err(codec->dev, "%s reg = 0x%x failed\n", __func__, reg); + return -EIO; + } + } + + dev_dbg(codec->dev, "%s reg = %x, val= %x\n", __func__, reg, value); + return value; +} + +static int rk616_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +{ + struct mfd_rk616 *rk616 = snd_soc_codec_get_drvdata(codec); + + if (!rk616) + return -EINVAL; + + if (rk616_mfd_mask_register(reg)) + value = ((0xffff0000 & rk616_read_reg_cache(codec, reg)) | (value & 0x0000ffff)); + + if (rk616->write_dev(rk616, reg, &value) < 0) { + dev_err(codec->dev, "%s reg = 0x%x failed\n", __func__, reg); + return -EIO; + } + + rk616_write_reg_cache(codec, reg, value); + + dev_dbg(codec->dev, "%s reg=0x%x, val=0x%x\n", __func__, reg, value); + return 0; +} + +static int rk616_hw_write(const struct i2c_client *client, const char *buf, int count) +{ + struct snd_soc_codec *codec = rk616_priv->codec; + unsigned int reg, value; + int ret = -1; + + if (!rk616_priv & !rk616_priv->codec) + return -EINVAL; + + if (count == 3) { + reg = (unsigned int)buf[0]; + value = (buf[1] & 0xff00) | (0x00ff & buf[2]); + ret = rk616_codec_write(codec, reg, value); + } else { + dev_err(codec->dev, "%s i2c len error\n", __func__); + } + + return (ret == 0) ? count : ret; +} + +static int rk616_reset(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_write(codec, RK616_RESET, 0); + if (ret >= 0) { + memcpy(codec->reg_cache, rk616_reg_defaults, + sizeof(rk616_reg_defaults)); + memcpy(rk616_mfd_reg_cache, rk616_mfd_reg_defaults, + sizeof(rk616_mfd_reg_defaults)); + } + + return ret; +} + +#ifdef RK616_FOR_MID +static struct rk616_reg_val_typ init_list[] = { + +}; + +#define RK616_INIT_REG_LEN ARRAY_SIZE(init_list) + +static int rk616_reg_init(struct snd_soc_codec *codec) +{ + int i; + + for (i = 0; i < RK616_INIT_REG_LEN; i++) + snd_soc_write(codec, init_list[i].reg, init_list[i].value); + + return 0; +} +#endif + +int rk616_headset_mic_detect(bool headset_status) +{ + struct snd_soc_codec *codec = rk616_priv->codec; + + dev_dbg(codec->dev, "%s::%d\n", __FUNCTION__, __LINE__); + + if (!rk616_priv & !rk616_priv->codec) + return -EINVAL; + + if (headset_status) { + + } else {// headset is out, disable MIC2 Bias + dev_dbg(codec->dev, "headset is out,disable Mic2 Bias\n"); + } + return 0; +} +EXPORT_SYMBOL(rk616_headset_mic_detect); + +void codec_set_spk(bool on) +{ + struct snd_soc_codec *codec = rk616_priv->codec; + + dev_dbg(codec->dev, "%s:: %s\n", __func__, on?"enable spk":"disable spk"); + + if (!rk616_priv & !rk616_priv->codec) + return; + + if (on) { +#ifdef RK616_FOR_MID + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_MUTE, 0); + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_MUTE, 0); + snd_soc_update_bits(codec, RK616_HPL_CTL, + RK616_MUTE, 0); + snd_soc_update_bits(codec, RK616_HPR_CTL, + RK616_MUTE, 0); +#else + snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); +#endif + } else { +#ifdef RK616_FOR_MID + snd_soc_update_bits(codec, RK616_SPKL_CTL, + RK616_MUTE, RK616_MUTE); + snd_soc_update_bits(codec, RK616_SPKR_CTL, + RK616_MUTE, RK616_MUTE); + snd_soc_update_bits(codec, RK616_HPL_CTL, + RK616_MUTE, RK616_MUTE); + snd_soc_update_bits(codec, RK616_HPR_CTL, + RK616_MUTE, RK616_MUTE); +#else + snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk"); +#endif + } + snd_soc_dapm_sync(&codec->dapm); +} +EXPORT_SYMBOL_GPL(codec_set_spk); + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -3900, 150, 0); +static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1800, 150, 0); +static const DECLARE_TLV_DB_SCALE(bst_vol_tlv, 0, 2000, 0); +static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -1200, 300, 0); +static const DECLARE_TLV_DB_SCALE(pga_agc_max_vol_tlv, -1350, 600, 0); +static const DECLARE_TLV_DB_SCALE(pga_agc_min_vol_tlv, -1800, 600, 0); + +static const char *rk616_input_mode[] = {"Differential", "Single-Ended"}; + +static const char *rk616_micbias_ratio[] = {"1.0 Vref", "1.1 Vref", + "1.2 Vref", "1.3 Vref", "1.4 Vref", "1.5 Vref", "1.6 Vref", "1.7 Vref",}; + +static const char *rk616_dis_en_sel[] = {"Disable", "Enable"}; + +static const char *rk616_mickey_range[] = {"100uA", "300uA", + "500uA", "700uA", "900uA", "1100uA", "1300uA", "1500uA"}; + +static const char *rk616_pga_gain_control[] = {"Normal", "AGC"}; + +static const char *rk616_pga_agc_way[] = {"Normal", "Jack"}; + +static const char *rk616_pga_agc_hold_time[] = {"0ms", "2ms", + "4ms", "8ms", "16ms", "32ms", "64ms", "128ms", "256ms", "512ms", "1s"}; + +static const char *rk616_pga_agc_ramp_up_time[] = {"500us", "1ms", "2ms", + "4ms", "8ms", "16ms", "32ms", "64ms", "128ms", "256ms", "512ms"}; + +static const char *rk616_pga_agc_ramp_down_time[] = {"Normal:125us Jack:32us", + "Normal:250us Jack:64us", "Normal:500us Jack:125us", "Normal:1ms Jack:250us", + "Normal:2ms Jack:500us", "Normal:4ms Jack:1ms", "Normal:8ms Jack:2ms", + "Normal:16ms Jack:4ms", "Normal:32ms Jack:8ms", "Normal:64ms Jack:16ms", + "Normal:128ms Jack:32ms"}; + +static const char *rk616_pga_agc_mode[] = {"Normal", "Limiter"}; + +static const char *rk616_pga_agc_recovery_mode[] = {"Right Now", "After AGC to Limiter"}; + +static const char *rk616_pga_agc_noise_gate_threhold[] = {"-39dB", "-45dB", "-51dB", + "-57dB", "-63dB", "-69dB", "-75dB", "-81dB"}; + +static const char *rk616_pga_agc_update_gain[] = {"Right Now", "After 1st Zero Cross"}; + +static const char *rk616_pga_agc_approximate_sample_rate[] = {"48KHz", "32KHz", + "24KHz", "16KHz", "12KHz", "8KHz"}; + +static const struct soc_enum rk616_bst_enum[] = { +SOC_ENUM_SINGLE(RK616_BST_CTL, RK616_BSTL_MODE_SFT, 2, rk616_input_mode), +SOC_ENUM_SINGLE(RK616_BST_CTL, RK616_BSTR_MODE_SFT, 2, rk616_input_mode), +}; + +static const struct soc_enum rk616_diffin_enum = + SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_DIFFIN_MODE_SFT, 2, rk616_input_mode); + +static const struct soc_enum rk616_micbias_enum[] = { +SOC_ENUM_SINGLE(RK616_MICBIAS_CTL, RK616_MICBIAS1_V_SFT, 8, rk616_micbias_ratio), +SOC_ENUM_SINGLE(RK616_MICBIAS_CTL, RK616_MICBIAS2_V_SFT, 8, rk616_micbias_ratio), +}; + +static const struct soc_enum rk616_mickey_enum[] = { +SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK1_DET_SFT, 2, rk616_dis_en_sel), +SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK2_DET_SFT, 2, rk616_dis_en_sel), +SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK1_DET_I_SFT, 8, rk616_mickey_range), +SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK2_DET_I_SFT, 8, rk616_mickey_range), +}; + +static const struct soc_enum rk616_agcl_enum[] = { +SOC_ENUM_SINGLE(RK616_PGA_AGC_CTL, RK616_PGAL_AGC_EN_SFT, 2, rk616_pga_gain_control),/*0*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL1, RK616_PGA_AGC_WAY_SFT, 2, rk616_pga_agc_way),/*1*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL1, RK616_PGA_AGC_HOLD_T_SFT, 11, rk616_pga_agc_hold_time),/*2*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL2, RK616_PGA_AGC_GRU_T_SFT, 11, rk616_pga_agc_ramp_up_time),/*3*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL2, RK616_PGA_AGC_GRD_T_SFT, 11, rk616_pga_agc_ramp_down_time),/*4*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_MODE_SFT, 2, rk616_pga_agc_mode),/*5*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_ZO_SFT, 2, rk616_dis_en_sel),/*6*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_REC_MODE_SFT, 2, rk616_pga_agc_recovery_mode),/*7*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_FAST_D_SFT, 2, rk616_dis_en_sel),/*8*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_NG_SFT, 2, rk616_dis_en_sel),/*9*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_NG_THR_SFT, 8, rk616_pga_agc_noise_gate_threhold),/*10*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL4, RK616_PGA_AGC_ZO_MODE_SFT, 2, rk616_pga_agc_update_gain),/*11*/ +SOC_ENUM_SINGLE(RK616_PGAL_ASR_CTL, RK616_PGA_SLOW_CLK_SFT, 2, rk616_dis_en_sel),/*12*/ +SOC_ENUM_SINGLE(RK616_PGAL_ASR_CTL, RK616_PGA_ASR_SFT, 6, rk616_pga_agc_approximate_sample_rate),/*13*/ +SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL5, RK616_PGA_AGC_SFT, 2, rk616_dis_en_sel),/*14*/ +}; + +static const struct soc_enum rk616_agcr_enum[] = { +SOC_ENUM_SINGLE(RK616_PGA_AGC_CTL, RK616_PGAR_AGC_EN_SFT, 2, rk616_pga_gain_control),/*0*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL1, RK616_PGA_AGC_WAY_SFT, 2, rk616_pga_agc_way),/*1*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL1, RK616_PGA_AGC_HOLD_T_SFT, 11, rk616_pga_agc_hold_time),/*2*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL2, RK616_PGA_AGC_GRU_T_SFT, 11, rk616_pga_agc_ramp_up_time),/*3*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL2, RK616_PGA_AGC_GRD_T_SFT, 11, rk616_pga_agc_ramp_down_time),/*4*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_MODE_SFT, 2, rk616_pga_agc_mode),/*5*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_ZO_SFT, 2, rk616_dis_en_sel),/*6*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_REC_MODE_SFT, 2, rk616_pga_agc_recovery_mode),/*7*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_FAST_D_SFT, 2, rk616_dis_en_sel),/*8*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_NG_SFT, 2, rk616_dis_en_sel),/*9*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_NG_THR_SFT, 8, rk616_pga_agc_noise_gate_threhold),/*10*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL4, RK616_PGA_AGC_ZO_MODE_SFT, 2, rk616_pga_agc_update_gain),/*11*/ +SOC_ENUM_SINGLE(RK616_PGAR_ASR_CTL, RK616_PGA_SLOW_CLK_SFT, 2, rk616_dis_en_sel),/*12*/ +SOC_ENUM_SINGLE(RK616_PGAR_ASR_CTL, RK616_PGA_ASR_SFT, 6, rk616_pga_agc_approximate_sample_rate),/*13*/ +SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL5, RK616_PGA_AGC_SFT, 2, rk616_dis_en_sel),/*14*/ +}; + +#ifdef RK616_REG_RW +#define REGVAL_MAX 0xffff +static unsigned int regctl_addr = 0x08; + +static int rk616_regctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = REGVAL_MAX; + return 0; +} + +static int rk616_regctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = regctl_addr; + ucontrol->value.integer.value[1] = snd_soc_read(codec, regctl_addr); + return 0; +} + +static int rk616_regctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = ucontrol->value.integer.value[0]; + unsigned int value = ucontrol->value.integer.value[0]; + + if (rk616_codec_register(codec, reg) || + rk616_mfd_register(reg)) { + regctl_addr = reg; + if (value <= REGVAL_MAX) + snd_soc_write(codec, regctl_addr, value); + } + + return 0; +} +#endif + +static const struct snd_kcontrol_new rk616_snd_controls[] = { + + SOC_SINGLE("I2S0 schmitt input Switch", CRU_IO_CON1, + 3, 1, 0), + SOC_SINGLE("I2S1 schmitt input Switch", CRU_IO_CON1, + 4, 1, 0), + SOC_SINGLE("I2S0 output Switch", CRU_IO_CON0, + 12, 1, 0), + SOC_SINGLE("I2S1 output Switch", CRU_IO_CON0, + 13, 1, 0), + + SOC_DOUBLE_R_TLV("SPKOUT Playback Volume", RK616_SPKL_CTL, + RK616_SPKR_CTL, RK616_VOL_SFT, 31, 0, out_vol_tlv), + SOC_DOUBLE_R("SPKOUT Playback Switch", RK616_SPKL_CTL, + RK616_SPKR_CTL, RK616_MUTE_SFT, 1, 1), + + SOC_DOUBLE_R_TLV("HPOUT Playback Volume", RK616_HPL_CTL, + RK616_HPR_CTL, RK616_VOL_SFT, 31, 0, out_vol_tlv), + SOC_DOUBLE_R("HPOUT Playback Switch", RK616_HPL_CTL, + RK616_HPR_CTL, RK616_MUTE_SFT, 1, 1), + + SOC_SINGLE_TLV("LINEOUT1 Playback Volume", RK616_LINEOUT1_CTL, + RK616_LINEOUT_VOL_SFT, 31, 0, out_vol_tlv), + SOC_SINGLE("LINEOUT1 Playback Switch", RK616_LINEOUT1_CTL, + RK616_LINEOUT_MUTE_SFT, 1, 1), + SOC_SINGLE_TLV("LINEOUT2 Playback Volume", RK616_LINEOUT2_CTL, + RK616_LINEOUT_VOL_SFT, 31, 0, out_vol_tlv), + SOC_SINGLE("LINEOUT2 Playback Switch", RK616_LINEOUT2_CTL, + RK616_LINEOUT_MUTE_SFT, 1, 1), + + SOC_SINGLE_TLV("PGAL Capture Volume", RK616_PGAL_CTL, + RK616_PGA_VOL_SFT, 31, 0, pga_vol_tlv),//0x0a bit 5 is 0 + SOC_SINGLE("PGAL Capture Switch", RK616_PGAL_CTL, + RK616_PGA_MUTE_SFT, 1, 1), + SOC_SINGLE_TLV("PGAR Capture Volume", RK616_PGAR_CTL, + RK616_PGA_VOL_SFT, 31, 0, pga_vol_tlv),//0x0a bit 4 is 0 + SOC_SINGLE("PGAR Capture Switch", RK616_PGAR_CTL, + RK616_PGA_MUTE_SFT, 1, 1), + + SOC_SINGLE_TLV("DIFFIN Capture Volume", RK616_DIFFIN_CTL, + RK616_DIFFIN_GAIN_SFT, 1, 0, bst_vol_tlv), + SOC_SINGLE("DIFFIN Capture Switch", RK616_DIFFIN_CTL, + RK616_DIFFIN_MUTE_SFT, 1, 1), + + SOC_SINGLE_TLV("BST_L Capture Volume", RK616_BST_CTL, + RK616_BSTL_GAIN_SFT, 1, 0, bst_vol_tlv), + SOC_SINGLE("BST_L Capture Switch", RK616_BST_CTL, + RK616_BSTL_MUTE_SFT, 1, 1), + SOC_SINGLE_TLV("BST_R Capture Volume", RK616_BST_CTL, + RK616_BSTR_GAIN_SFT, 1, 0, bst_vol_tlv), + SOC_SINGLE("BST_R Capture Switch", RK616_BST_CTL, + RK616_BSTR_MUTE_SFT, 1, 1), + + SOC_ENUM("BST_L Mode", rk616_bst_enum[0]), + SOC_ENUM("BST_R Mode", rk616_bst_enum[1]), + SOC_ENUM("DIFFIN Mode", rk616_diffin_enum), + + + SOC_SINGLE_TLV("MUXMIC to MIXINL Volume", RK616_MIXINL_VOL1, + RK616_MIL_F_MUX_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("IN1P to MIXINL Volume", RK616_MIXINL_VOL1, + RK616_MIL_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("IN3L to MIXINL Volume", RK616_MIXINL_VOL2, + RK616_MIL_F_IN3L_VOL_SFT, 7, 0, mix_vol_tlv), + + SOC_SINGLE_TLV("MIXINR MUX to MIXINR Volume", RK616_MIXINR_VOL1, + RK616_MIR_F_MIRM_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("IN3R to MIXINR Volume", RK616_MIXINR_VOL1, + RK616_MIR_F_IN3R_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("MIC2N to MIXINR Volume", RK616_MIXINR_VOL2, + RK616_MIR_F_MIC2N_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("IN1P to MIXINR Volume", RK616_MIXINR_VOL2, + RK616_MIR_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv), + + SOC_SINGLE("MIXINL Switch", RK616_MIXINL_CTL, + RK616_MIL_MUTE_SFT, 1, 1), + SOC_SINGLE("MIXINR Switch", RK616_MIXINR_CTL, + RK616_MIR_MUTE_SFT, 1, 1), + + SOC_SINGLE_TLV("IN1P to HPMIXL Volume", RK616_HPMIX_VOL1, + RK616_HML_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("HPMIX MUX to HPMIXL Volume", RK616_HPMIX_VOL2, + RK616_HML_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv), + SOC_SINGLE_TLV("HPMIX MUX to MIXINR Volume", RK616_HPMIX_VOL2, + RK616_HMR_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv), + + SOC_ENUM("Micbias1 Voltage", rk616_micbias_enum[0]), + SOC_ENUM("Micbias2 Voltage ", rk616_micbias_enum[1]), + + SOC_ENUM("MIC1 Key Detection Enable", rk616_mickey_enum[0]), + SOC_ENUM("MIC2 Key Detection Enable", rk616_mickey_enum[1]), + SOC_ENUM("MIC1 Key Range", rk616_mickey_enum[2]), + SOC_ENUM("MIC2 Key Range", rk616_mickey_enum[3]), + + + SOC_ENUM("PGAL Gain Control", rk616_agcl_enum[0]), + SOC_ENUM("PGAL AGC Way", rk616_agcl_enum[1]), + SOC_ENUM("PGAL AGC Hold Time", rk616_agcl_enum[2]), + SOC_ENUM("PGAL AGC Ramp Up Time", rk616_agcl_enum[3]), + SOC_ENUM("PGAL AGC Ramp Down Time", rk616_agcl_enum[4]), + SOC_ENUM("PGAL AGC Mode", rk616_agcl_enum[5]), + SOC_ENUM("PGAL AGC Gain Update Zero Enable", rk616_agcl_enum[6]), + SOC_ENUM("PGAL AGC Gain Recovery LPGA VOL", rk616_agcl_enum[7]), + SOC_ENUM("PGAL AGC Fast Decrement Enable", rk616_agcl_enum[8]), + SOC_ENUM("PGAL AGC Noise Gate Enable", rk616_agcl_enum[9]), + SOC_ENUM("PGAL AGC Noise Gate Threhold", rk616_agcl_enum[10]), + SOC_ENUM("PGAL AGC Upate Gain", rk616_agcl_enum[11]), + SOC_ENUM("PGAL AGC Slow Clock Enable", rk616_agcl_enum[12]), + SOC_ENUM("PGAL AGC Approximate Sample Rate", rk616_agcl_enum[13]), + SOC_ENUM("PGAL AGC Enable", rk616_agcl_enum[14]), + + SOC_SINGLE_TLV("PGAL AGC Volume", RK616_PGAL_AGC_CTL4, + RK616_PGA_AGC_VOL_SFT, 31, 0, pga_vol_tlv),//AGC disable and 0x0a bit 5 is 1 + + SOC_SINGLE("PGAL AGC Max Level High 8 Bits", RK616_PGAL_AGC_MAX_H, + 0, 255, 0), + SOC_SINGLE("PGAL AGC Max Level Low 8 Bits", RK616_PGAL_AGC_MAX_L, + 0, 255, 0), + SOC_SINGLE("PGAL AGC Min Level High 8 Bits", RK616_PGAL_AGC_MIN_H, + 0, 255, 0), + SOC_SINGLE("PGAL AGC Min Level Low 8 Bits", RK616_PGAL_AGC_MIN_L, + 0, 255, 0), + + SOC_SINGLE_TLV("PGAL AGC Max Gain", RK616_PGAL_AGC_CTL5, + RK616_PGA_AGC_MAX_G_SFT, 7, 0, pga_agc_max_vol_tlv),//AGC enable and 0x0a bit 5 is 1 + SOC_SINGLE_TLV("PGAL AGC Min Gain", RK616_PGAL_AGC_CTL5, + RK616_PGA_AGC_MIN_G_SFT, 7, 0, pga_agc_min_vol_tlv),//AGC enable and 0x0a bit 5 is 1 + + SOC_ENUM("PGAR Gain Control", rk616_agcr_enum[0]), + SOC_ENUM("PGAR AGC Way", rk616_agcr_enum[1]), + SOC_ENUM("PGAR AGC Hold Time", rk616_agcr_enum[2]), + SOC_ENUM("PGAR AGC Ramp Up Time", rk616_agcr_enum[3]), + SOC_ENUM("PGAR AGC Ramp Down Time", rk616_agcr_enum[4]), + SOC_ENUM("PGAR AGC Mode", rk616_agcr_enum[5]), + SOC_ENUM("PGAR AGC Gain Update Zero Enable", rk616_agcr_enum[6]), + SOC_ENUM("PGAR AGC Gain Recovery LPGA VOL", rk616_agcr_enum[7]), + SOC_ENUM("PGAR AGC Fast Decrement Enable", rk616_agcr_enum[8]), + SOC_ENUM("PGAR AGC Noise Gate Enable", rk616_agcr_enum[9]), + SOC_ENUM("PGAR AGC Noise Gate Threhold", rk616_agcr_enum[10]), + SOC_ENUM("PGAR AGC Upate Gain", rk616_agcr_enum[11]), + SOC_ENUM("PGAR AGC Slow Clock Enable", rk616_agcr_enum[12]), + SOC_ENUM("PGAR AGC Approximate Sample Rate", rk616_agcr_enum[13]), + SOC_ENUM("PGAR AGC Enable", rk616_agcr_enum[14]), + + SOC_SINGLE_TLV("PGAR AGC Volume", RK616_PGAR_AGC_CTL4, + RK616_PGA_AGC_VOL_SFT, 31, 0, pga_vol_tlv),//AGC disable and 0x0a bit 4 is 1 + + SOC_SINGLE("PGAR AGC Max Level High 8 Bits", RK616_PGAR_AGC_MAX_H, + 0, 255, 0), + SOC_SINGLE("PGAR AGC Max Level Low 8 Bits", RK616_PGAR_AGC_MAX_L, + 0, 255, 0), + SOC_SINGLE("PGAR AGC Min Level High 8 Bits", RK616_PGAR_AGC_MIN_H, + 0, 255, 0), + SOC_SINGLE("PGAR AGC Min Level Low 8 Bits", RK616_PGAR_AGC_MIN_L, + 0, 255, 0), + + SOC_SINGLE_TLV("PGAR AGC Max Gain", RK616_PGAR_AGC_CTL5, + RK616_PGA_AGC_MAX_G_SFT, 7, 0, pga_agc_max_vol_tlv),//AGC enable and 0x06 bit 4 is 1 + SOC_SINGLE_TLV("PGAR AGC Min Gain", RK616_PGAR_AGC_CTL5, + RK616_PGA_AGC_MIN_G_SFT, 7, 0, pga_agc_min_vol_tlv),//AGC enable and 0x06 bit 4 is 1 + +#ifdef RK616_REG_RW + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Register Control", + .info = rk616_regctl_info, + .get = rk616_regctl_get, + .put = rk616_regctl_put, + }, +#endif +}; + +static int rk616_dacl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RK616_DAC_CTL, + RK616_DACL_PWRD | RK616_DACL_CLK_PWRD, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RK616_DAC_CTL, + RK616_DACL_PWRD | RK616_DACL_CLK_PWRD, + RK616_DACL_PWRD | RK616_DACL_CLK_PWRD); + break; + + default: + return 0; + } + + return 0; +} + +static int rk616_dacr_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RK616_DAC_CTL, + RK616_DACR_PWRD | RK616_DACR_CLK_PWRD, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RK616_DAC_CTL, + RK616_DACR_PWRD | RK616_DACR_CLK_PWRD, + RK616_DACR_PWRD | RK616_DACR_CLK_PWRD); + break; + + default: + return 0; + } + + return 0; +} + +static int rk616_adcl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RK616_ADC_CTL, + RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RK616_ADC_CTL, + RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD, + RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD); + break; + + default: + return 0; + } + + return 0; +} + +static int rk616_adcr_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RK616_ADC_CTL, + RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RK616_ADC_CTL, + RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD, + RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD); + break; + + default: + return 0; + } + + return 0; +} + +/* Mixin */ +static const struct snd_kcontrol_new rk616_mixinl[] = { + SOC_DAPM_SINGLE("IN3L Switch", RK616_MIXINL_CTL, + RK616_MIL_F_IN3L_SFT, 1, 1), + SOC_DAPM_SINGLE("IN1P Switch", RK616_MIXINL_CTL, + RK616_MIL_F_IN1P_SFT, 1, 1), + SOC_DAPM_SINGLE("MUXMIC Switch", RK616_MIXINL_CTL, + RK616_MIL_F_MUX_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rk616_mixinr[] = { + SOC_DAPM_SINGLE("MIC2N Switch", RK616_MIXINR_CTL, + RK616_MIR_F_MIC2N_SFT, 1, 1), + SOC_DAPM_SINGLE("IN1P Switch", RK616_MIXINL_CTL, + RK616_MIR_F_IN1P_SFT, 1, 1), + SOC_DAPM_SINGLE("IN3R Switch", RK616_MIXINL_CTL, + RK616_MIR_F_IN3R_SFT, 1, 1), + SOC_DAPM_SINGLE("MIXINR Mux Switch", RK616_MIXINL_CTL, + RK616_MIR_F_MIRM_SFT, 1, 1), +}; + +/* Linemix */ +static const struct snd_kcontrol_new rk616_linemix[] = { + SOC_DAPM_SINGLE("PGAR Switch", RK616_LINEMIX_CTL, + RK616_LM_F_PGAR_SFT, 1, 1), + SOC_DAPM_SINGLE("PGAL Switch", RK616_LINEMIX_CTL, + RK616_LM_F_PGAL_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RK616_LINEMIX_CTL, + RK616_LM_F_DACR_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RK616_LINEMIX_CTL, + RK616_LM_F_DACL_SFT, 1, 1), +}; + +/* HPmix */ +static const struct snd_kcontrol_new rk616_hpmixl[] = { + SOC_DAPM_SINGLE("HPMix Mux Switch", RK616_HPMIX_CTL, + RK616_HML_F_HMM_SFT, 1, 1), + SOC_DAPM_SINGLE("IN1P Switch", RK616_HPMIX_CTL, + RK616_HML_F_IN1P_SFT, 1, 1), + SOC_DAPM_SINGLE("PGAL Switch", RK616_HPMIX_CTL, + RK616_HML_F_PGAL_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RK616_HPMIX_CTL, + RK616_HML_F_DACL_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rk616_hpmixr[] = { + SOC_DAPM_SINGLE("HPMix Mux Switch", RK616_HPMIX_CTL, + RK616_HMR_F_HMM_SFT, 1, 1), + SOC_DAPM_SINGLE("PGAR Switch", RK616_HPMIX_CTL, + RK616_HMR_F_PGAR_SFT, 1, 1), + SOC_DAPM_SINGLE("PGAL Switch", RK616_HPMIX_CTL, + RK616_HMR_F_PGAL_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RK616_HPMIX_CTL, + RK616_HMR_F_DACR_SFT, 1, 1), +}; + +/* HP MUX */ +static const char *hpl_sel[] = {"HPMIXL", "DACL"}; + +static const struct soc_enum hpl_sel_enum = + SOC_ENUM_SINGLE(RK616_MUXHP_HPMIX_CTL, RK616_MHL_F_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 *hpr_sel[] = {"HPMIXR", "DACR"}; + +static const struct soc_enum hpr_sel_enum = + SOC_ENUM_SINGLE(RK616_MUXHP_HPMIX_CTL, RK616_MHR_F_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); + +/* MIC MUX */ +static const char *mic_sel[] = {"BSTL", "BSTR"}; + +static const struct soc_enum mic_sel_enum = + SOC_ENUM_SINGLE(RK616_MIXINL_CTL, RK616_MM_F_SFT, + ARRAY_SIZE(mic_sel), mic_sel); + +static const struct snd_kcontrol_new mic_sel_mux = + SOC_DAPM_ENUM("Mic select Mux", mic_sel_enum); + +/* MIXINR MUX */ +static const char *mixinr_sel[] = {"DIFFIN", "IN1N"}; + +static const struct soc_enum mixinr_sel_enum = + SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_MIRM_F_SFT, + ARRAY_SIZE(mixinr_sel), mixinr_sel); + +static const struct snd_kcontrol_new mixinr_sel_mux = + SOC_DAPM_ENUM("Mixinr select Mux", mixinr_sel_enum); + +/* HPMIX MUX */ +static const char *hpmix_sel[] = {"DIFFIN", "IN1N"}; + +static const struct soc_enum hpmix_sel_enum = + SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_HMM_F_SFT, + ARRAY_SIZE(hpmix_sel), hpmix_sel); + +static const struct snd_kcontrol_new hpmix_sel_mux = + SOC_DAPM_ENUM("HPMix select Mux", hpmix_sel_enum); + + +static const struct snd_soc_dapm_widget rk616_dapm_widgets[] = { + /* supply */ + SND_SOC_DAPM_SUPPLY("I2S0 Interface", CRU_IO_CON0, + 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S1 Interface", CRU_IO_CON0, + 4, 1, NULL, 0), + + /* microphone bias */ + SND_SOC_DAPM_MICBIAS("Mic1 Bias", RK616_MICBIAS_CTL, + RK616_MICBIAS1_PWRD_SFT, 1), + SND_SOC_DAPM_MICBIAS("Mic2 Bias", RK616_MICBIAS_CTL, + RK616_MICBIAS2_PWRD_SFT, 1), + + /* DACs */ + SND_SOC_DAPM_SUPPLY("DAC", RK616_PWR_ADD2, + RK616_DAC_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_ADC_E("DAC L", NULL, SND_SOC_NOPM, + 0, 0, rk616_dacl_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("DAC R", NULL, SND_SOC_NOPM, + 0, 0, rk616_dacr_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + /* ADCs */ + SND_SOC_DAPM_SUPPLY("ADC", RK616_PWR_ADD1, + RK616_ADC_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_ADC_E("ADC L", NULL, SND_SOC_NOPM, + 0, 0, rk616_adcl_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("ADC R", NULL, SND_SOC_NOPM, + 0, 0, rk616_adcr_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + /* PGA */ + SND_SOC_DAPM_PGA("BSTL", RK616_BST_CTL, + RK616_BSTL_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("BSTR", RK616_BST_CTL, + RK616_BSTR_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("DIFFIN", RK616_DIFFIN_CTL, + RK616_DIFFIN_PWRD, 1, NULL, 0), + SND_SOC_DAPM_PGA("PGAL", RK616_PGAL_CTL, + RK616_PGA_PWRD, 1, NULL, 0), + SND_SOC_DAPM_PGA("PGAR", RK616_PGAR_CTL, + RK616_PGA_PWRD, 1, NULL, 0), + SND_SOC_DAPM_PGA("SPKL", RK616_SPKL_CTL, + RK616_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("SPKR", RK616_SPKR_CTL, + RK616_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("HPL", RK616_HPL_CTL, + RK616_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("HPR", RK616_HPR_CTL, + RK616_PWRD_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("LINE1", RK616_LINEOUT1_CTL, + RK616_LINEOUT_PWRD, 1, NULL, 0), + SND_SOC_DAPM_PGA("LINE2", RK616_LINEOUT2_CTL, + RK616_LINEOUT_PWRD, 1, NULL, 0), + + /* MIXER */ + SND_SOC_DAPM_MIXER("MIXINL", RK616_MIXINL_CTL, + RK616_MIL_PWRD_SFT, 1, rk616_mixinl, + ARRAY_SIZE(rk616_mixinl)), + SND_SOC_DAPM_MIXER("MIXINR", RK616_MIXINR_CTL, + RK616_MIR_PWRD_SFT, 1, rk616_mixinr, + ARRAY_SIZE(rk616_mixinr)), + SND_SOC_DAPM_MIXER("LINEMIX", RK616_LINEMIX_CTL, + RK616_LM_PWRD_SFT, 1, rk616_linemix, + ARRAY_SIZE(rk616_linemix)), + SND_SOC_DAPM_MIXER("HPMIXL", RK616_MUXHP_HPMIX_CTL, + RK616_HML_PWRD_SFT, 1, rk616_hpmixl, + ARRAY_SIZE(rk616_hpmixl)), + SND_SOC_DAPM_MIXER("HPMIXR", RK616_MUXHP_HPMIX_CTL, + RK616_HMR_PWRD_SFT, 1, rk616_hpmixr, + ARRAY_SIZE(rk616_hpmixr)), + + /* 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), + SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0, + &mic_sel_mux), + SND_SOC_DAPM_MUX("MIXINR Mux", SND_SOC_NOPM, 0, 0, + &mixinr_sel_mux), + SND_SOC_DAPM_MUX("HPMix Mux", SND_SOC_NOPM, 0, 0, + &hpmix_sel_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("I2S0 DAC", "HIFI Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S0 ADC", "HIFI Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S1 DAC", "VOICE Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S1 ADC", "VOICE Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Input */ + SND_SOC_DAPM_INPUT("IN3L"), + SND_SOC_DAPM_INPUT("IN3R"), + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("MIC2P"), + SND_SOC_DAPM_INPUT("MIC2N"), + SND_SOC_DAPM_INPUT("MIC1P"), + SND_SOC_DAPM_INPUT("MIC1N"), + + /* Output */ + SND_SOC_DAPM_OUTPUT("SPKOUTL"), + SND_SOC_DAPM_OUTPUT("SPKOUTR"), + SND_SOC_DAPM_OUTPUT("HPOUTL"), + SND_SOC_DAPM_OUTPUT("HPOUTR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), +}; + +static const struct snd_soc_dapm_route rk616_dapm_routes[] = { + {"I2S0 DAC", NULL, "I2S0 Interface"}, + {"I2S0 ADC", NULL, "I2S0 Interface"}, + {"I2S1 DAC", NULL, "I2S1Interface"}, + {"I2S1 ADC", NULL, "I2S1Interface"}, + + /* Input */ + {"DIFFIN", NULL, "IN1P"}, + {"DIFFIN", NULL, "IN1N"}, + + {"BSTR", NULL, "MIC2P"}, + {"BSTR", NULL, "MIC2N"}, + + {"BSTL", NULL, "MIC1P"}, + {"BSTL", NULL, "MIC1N"}, + + {"HPMix Mux", "DIFFIN", "DIFFIN"}, + {"HPMix Mux", "IN1N", "IN1N"}, + + {"MIXINR Mux", "DIFFIN", "DIFFIN"}, + {"MIXINR Mux", "IN1N", "IN1N"}, + + {"Mic Mux", "BSTR", "BSTR"}, + {"Mic Mux", "BSTL", "BSTL"}, + + {"MIXINR", "MIC2N Switch", "MIC2N"}, + {"MIXINR", "IN1P Switch", "IN1P"}, + {"MIXINR", "IN3R Switch", "IN3R"}, + {"MIXINR", "MIXINR Mux Switch", "MIXINR Mux"}, + + {"MIXINL", "IN3L Switch", "IN3L"}, + {"MIXINL", "IN1P Switch", "IN1P"}, + {"MIXINL", "MUXMIC Switch", "Mic Mux"}, + + {"PGAR", NULL, "MIXINR"}, + {"PGAL", NULL, "MIXINL"}, + + {"ADCR", NULL, "PGAR"}, + {"ADCL", NULL, "PGAL"}, + + {"ADC", NULL, "ADCR"}, + {"ADC", NULL, "ADCL"}, + + {"I2S0 ADC", NULL, "ADC"}, + {"I2S1 ADC", NULL, "ADC"}, + + /* Output */ + {"DAC", NULL, "I2S0 DAC"}, + {"DAC", NULL, "I2S1 DAC"}, + + {"DACR", NULL, "DAC"}, + {"DACL", NULL, "DAC"}, + + {"LINEMIX", "PGAR Switch", "PGAR"}, + {"LINEMIX", "PGAL Switch", "PGAL"}, + {"LINEMIX", "DACR Switch", "DACR"}, + {"LINEMIX", "DACL Mux Switch", "DACL"}, + + {"HPMIXR", "HPMix Mux Switch", "HPMix Mux"}, + {"HPMIXR", "PGAR Switch", "PGAR"}, + {"HPMIXR", "PGAL Switch", "PGAL"}, + {"HPMIXR", "DACR Switch", "DACR"}, + + {"HPMIXL", "HPMix Mux Switch", "HPMix Mux"}, + {"HPMIXL", "IN1P Switch", "PGAR"}, + {"HPMIXL", "PGAL Switch", "PGAL"}, + {"HPMIXL", "DACL Switch", "DACL"}, + + {"HPR Mux", "DACR", "DACR"}, + {"HPR Mux", "HPMIXR", "HPMIXR"}, + + {"HPL Mux", "DACL", "DACL"}, + {"HPL Mux", "HPMIXL", "HPMIXR"}, + + {"LINE1", NULL, "LINEMIX"}, + {"LINE2", NULL, "LINEMIX"}, + + {"SPKR", NULL, "HPR Mux"}, + {"SPKL", NULL, "HPL Mux"}, + + {"HPR", NULL, "HPR Mux"}, + {"HPL", NULL, "HPL Mux"}, + + {"LINEOUT1", NULL, "LINE1"}, + {"LINEOUT2", NULL, "LINE2"}, + + {"SPKOUTR", NULL, "SPKR"}, + {"SPKOUTL", NULL, "SPKL"}, + + {"HPOUTR", NULL, "HPR"}, + {"HPOUTL", NULL, "HPL"}, + +}; + +static int rk616_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, RK616_MICBIAS_CTL, + RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD, 0); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + /* set power */ + snd_soc_update_bits(codec, RK616_PWR_ADD1, + RK616_DIFFIN_MIR_PGAR_RLPWRD | RK616_MIC1_MIC2_MIL_PGAL_RLPWRD | + RK616_ADCL_RLPWRD | RK616_ADCR_RLPWRD, + RK616_DIFFIN_MIR_PGAR_RLPWRD | RK616_MIC1_MIC2_MIL_PGAL_RLPWRD | + RK616_ADCL_RLPWRD | RK616_ADCR_RLPWRD); + + snd_soc_update_bits(codec, RK616_PWR_ADD2, + RK616_HPL_HPR_PWRD | RK616_DACL_SPKL_RLPWRD | + RK616_DACR_SPKR_RLPWRD | RK616_LM_LO_RLPWRD | + RK616_HM_RLPWRD, + RK616_DACL_SPKL_RLPWRD | RK616_DACR_SPKR_RLPWRD | + RK616_LM_LO_RLPWRD | RK616_HM_RLPWRD); + + snd_soc_update_bits(codec, RK616_PWR_ADD3, + RK616_ADCL_ZO_PWRD | RK616_ADCR_ZO_PWRD | + RK616_DACL_ZO_PWRD | RK616_DACR_ZO_PWRD , + RK616_ADCL_ZO_PWRD | RK616_ADCR_ZO_PWRD | + RK616_DACL_ZO_PWRD | RK616_DACR_ZO_PWRD ); + + snd_soc_write(codec, RK616_MICBIAS_CTL, + RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD | + RK616_MICBIAS1_V_1_7 | RK616_MICBIAS2_V_1_7); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, RK616_PWR_ADD1, 0xffff); + snd_soc_write(codec, RK616_PWR_ADD2, 0xffff); + snd_soc_write(codec, RK616_PWR_ADD3, 0xffff); + snd_soc_update_bits(codec, RK616_MICBIAS_CTL, + RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD, + RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD); + break; + } + + codec->dapm.bias_level = level; + + return 0; +} + +static int rk616_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct rk616_codec_priv *rk616 = rk616_priv; + + if (!rk616) + return -EINVAL; + + rk616->stereo_sysclk = freq; + + return 0; +} + +static int rk616_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + 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 |= RK616_I2S_MODE_SLV; + break; + case SND_SOC_DAIFMT_CBM_CFM: + adc_aif2 |= RK616_I2S_MODE_MST; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + adc_aif1 |= RK616_ADC_DF_PCM; + dac_aif1 |= RK616_DAC_DF_PCM; + break; + case SND_SOC_DAIFMT_DSP_B: + break; + case SND_SOC_DAIFMT_I2S: + adc_aif1 |= RK616_ADC_DF_I2S; + dac_aif1 |= RK616_DAC_DF_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + adc_aif1 |= RK616_ADC_DF_RJ; + dac_aif1 |= RK616_DAC_DF_RJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + adc_aif1 |= RK616_ADC_DF_LJ; + dac_aif1 |= RK616_DAC_DF_LJ; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + adc_aif1 |= RK616_ALRCK_POL_DIS; + adc_aif2 |= RK616_ABCLK_POL_DIS; + dac_aif1 |= RK616_DLRCK_POL_DIS; + dac_aif2 |= RK616_DBCLK_POL_DIS; + break; + case SND_SOC_DAIFMT_IB_IF: + adc_aif1 |= RK616_ALRCK_POL_EN; + adc_aif2 |= RK616_ABCLK_POL_EN; + dac_aif1 |= RK616_DLRCK_POL_EN; + dac_aif2 |= RK616_DBCLK_POL_EN; + break; + case SND_SOC_DAIFMT_IB_NF: + adc_aif1 |= RK616_ALRCK_POL_DIS; + adc_aif2 |= RK616_ABCLK_POL_EN; + dac_aif1 |= RK616_DLRCK_POL_DIS; + dac_aif2 |= RK616_DBCLK_POL_EN; + break; + case SND_SOC_DAIFMT_NB_IF: + adc_aif1 |= RK616_ALRCK_POL_EN; + adc_aif2 |= RK616_ABCLK_POL_DIS; + dac_aif1 |= RK616_DLRCK_POL_EN; + dac_aif2 |= RK616_DBCLK_POL_DIS; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RK616_ADC_INT_CTL1, + RK616_ALRCK_POL_MASK | RK616_ADC_DF_MASK, adc_aif1); + snd_soc_update_bits(codec, RK616_ADC_INT_CTL2, + RK616_ABCLK_POL_MASK | RK616_I2S_MODE_MASK, adc_aif2); + snd_soc_update_bits(codec, RK616_DAC_INT_CTL1, + RK616_DLRCK_POL_MASK | RK616_DAC_DF_MASK, dac_aif1); + snd_soc_update_bits(codec, RK616_DAC_INT_CTL2, + RK616_DBCLK_POL_MASK, dac_aif2); + + return 0; +} + +static int rk616_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_codec *codec =rtd->codec; + struct rk616_codec_priv *rk616 = rk616_priv; + unsigned int rate = params_rate(params); + unsigned int div; + unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; + u32 mfd_aif1 = 0, mfd_aif2 = 0; + + if (!rk616) + return -EINVAL; + + if (rk616->stereo_sysclk % rate > 0) { + dev_err(codec->dev, "need PLL"); + return -EINVAL; + } + + div = (rk616->stereo_sysclk / rate) - 1; + + dev_dbg(codec->dev, "MCLK = %dHz, sample rate = %dHz, div = %d\n", + rk616->stereo_sysclk, rate, div); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adc_aif1 |= RK616_ADC_VWL_16; + adc_aif2 |= RK616_ADC_WL_16; + dac_aif1 |= RK616_DAC_VWL_16; + dac_aif2 |= RK616_DAC_WL_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adc_aif1 |= RK616_ADC_VWL_20; + adc_aif2 |= RK616_ADC_WL_20; + dac_aif1 |= RK616_DAC_VWL_20; + dac_aif2 |= RK616_DAC_WL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + adc_aif1 |= RK616_ADC_VWL_24; + adc_aif2 |= RK616_ADC_WL_24; + dac_aif1 |= RK616_DAC_VWL_24; + dac_aif2 |= RK616_DAC_WL_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + adc_aif1 |= RK616_ADC_VWL_32; + adc_aif2 |= RK616_ADC_WL_32; + dac_aif1 |= RK616_DAC_VWL_32; + dac_aif2 |= RK616_DAC_WL_32; + break; + default: + return -EINVAL; + } + + switch (params_channels(params)) { + case RK616_MONO: + adc_aif1 |= RK616_I2S_TYPE_MONO; + break; + case RK616_STEREO: + adc_aif1 |= RK616_I2S_TYPE_STEREO; + break; + default: + return -EINVAL; + } + + adc_aif1 |= RK616_ADC_SWAP_DIS; + adc_aif2 |= RK616_ADC_RST_DIS; + dac_aif1 |= RK616_DAC_SWAP_DIS; + dac_aif2 |= RK616_DAC_RST_DIS; + + rk616->rate = rate; + + snd_soc_write(codec, CRU_CODEC_DIV, div);//(lrclk = mclk / div + 1) + + snd_soc_update_bits(codec, RK616_ADC_INT_CTL1, + RK616_ADC_VWL_MASK | RK616_ADC_SWAP_MASK | + RK616_I2S_TYPE_MASK, adc_aif1); + snd_soc_update_bits(codec, RK616_ADC_INT_CTL2, + RK616_ADC_WL_MASK | RK616_ADC_RST_MASK, adc_aif2); + snd_soc_update_bits(codec, RK616_DAC_INT_CTL1, + RK616_DAC_VWL_MASK | RK616_DAC_SWAP_MASK, dac_aif1); + snd_soc_update_bits(codec, RK616_DAC_INT_CTL2, + RK616_DAC_WL_MASK | RK616_DAC_RST_MASK, dac_aif2); + + switch (dai->id) { + case RK616_HIFI: + mfd_aif1 |= (I2S0_OUT_EN | I2S1_PD_DISABLE) | + ((I2S1_OUT_EN | I2S0_OUT_EN | + I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16); + mfd_aif2 |= I2S0_SI_EN | ((I2S1_SI_EN | I2S0_SI_EN) << 16); + break; + case RK616_VOICE: + mfd_aif1 |= (I2S1_OUT_EN | I2S0_PD_DISABLE) | + ((I2S1_OUT_EN | I2S0_OUT_EN | + I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16); + mfd_aif2 |= I2S1_SI_EN | ((I2S1_SI_EN | I2S0_SI_EN) << 16); + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, CRU_IO_CON0, mfd_aif1); + snd_soc_write(codec, CRU_IO_CON1, mfd_aif2); + + return 0; +} + +#ifdef RK616_FOR_MID +static int rk616_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rk616_codec_priv *rk616 = rk616_priv; + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + bool is_codec_running = rk616->playback_active > 0 || rk616->capture_active > 0; + + if (!rk616) + return -EINVAL; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (playback) + rk616->playback_active++; + else + rk616->capture_active++; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (playback) + rk616->playback_active--; + else + rk616->capture_active--; + break; + + default: + return 0; + break; + } + + if (rk616->playback_active > 0 || rk616->capture_active > 0){ + if (is_codec_running == false) { + rk616_reg_init(codec); + } + } else { + if (is_codec_running == true) { + rk616_reset(codec); + } + } + + return 0; +} +#endif + +#define RK616_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) + +#define RK616_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 RK616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops rk616_dai_ops = { + .hw_params = rk616_hw_params, + .set_fmt = rk616_set_dai_fmt, + .set_sysclk = rk616_set_dai_sysclk, +#ifdef RK616_FOR_MID + .trigger = rk616_trigger, +#endif +}; + +static struct snd_soc_dai_driver rk616_dai[] = { + { + .name = "rk616-hifi", + .id = RK616_HIFI, + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 2, + .channels_max = 2, + .rates = RK616_PLAYBACK_RATES, + .formats = RK616_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 2, + .channels_max = 2, + .rates = RK616_CAPTURE_RATES, + .formats = RK616_FORMATS, + }, + .ops = &rk616_dai_ops, + }, + { + .name = "rk616-voice", + .id = RK616_VOICE, + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RK616_PLAYBACK_RATES, + .formats = RK616_FORMATS, + }, + .capture = { + .stream_name = "Voice Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RK616_CAPTURE_RATES, + .formats = RK616_FORMATS, + }, + .ops = &rk616_dai_ops, + }, + +}; + +static int rk616_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + rk616_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int rk616_resume(struct snd_soc_codec *codec) +{ + rk616_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +#ifdef RK616_PROC +static int rk616_proc_init(void); +#endif + +static int rk616_probe(struct snd_soc_codec *codec) +{ + struct rk616_codec_priv *rk616; + int ret; + unsigned int val; + + rk616 = kzalloc(sizeof(struct rk616_codec_priv), GFP_KERNEL); + if (rk616 == NULL) + return -ENOMEM; + + rk616->codec = codec; + +#ifdef RK616_FOR_MID + rk616->playback_active = 0; + rk616->capture_active = 0; +#endif + + rk616_priv = rk616; + + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err__; + } + + codec->hw_read = rk616_codec_read; + codec->hw_write = (hw_write_t)rk616_hw_write; + codec->read = rk616_codec_read; + codec->write = rk616_codec_write; + + val = snd_soc_read(codec, RK616_RESET); + if (val != rk616_reg_defaults[RK616_RESET]) { + dev_err(codec->dev, + "Device register 0: %x is not a 0x0003\n", val); + ret = -ENODEV; + goto err__; + } + + rk616_reset(codec); + + rk616_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +#ifdef RK616_PROC + rk616_proc_init(); +#endif + + snd_soc_add_controls(codec, rk616_snd_controls, + ARRAY_SIZE(rk616_snd_controls)); + +err__: + kfree(rk616); + + return ret; +} + +/* power down chip */ +static int rk616_remove(struct snd_soc_codec *codec) +{ + rk616_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_rk616 = { + .probe = rk616_probe, + .remove = rk616_remove, + .suspend = rk616_suspend, + .resume = rk616_resume, + .set_bias_level = rk616_set_bias_level, + .reg_cache_size = ARRAY_SIZE(rk616_reg_defaults), + .reg_word_size = sizeof(unsigned int), + .reg_cache_default = rk616_reg_defaults, + .volatile_register = rk616_volatile_register, + //.seq_notifier = wm8903_seq_notifier, + .dapm_widgets = rk616_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk616_dapm_widgets), + .dapm_routes = rk616_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rk616_dapm_routes), +}; + +static __devinit int rk616_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_rk616, rk616_dai, ARRAY_SIZE(rk616_dai)); +} + +static __devexit int rk616_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver rk616_codec_driver = { + .driver = { + .name = "rk616-codec", + .owner = THIS_MODULE, + }, + .probe = rk616_platform_probe, + .remove = __devexit_p(rk616_platform_remove), +}; + + +static __init int rk616_modinit(void) +{ + return platform_driver_register(&rk616_codec_driver); +} +module_init(rk616_modinit); + +static __exit void rk616_exit(void) +{ + platform_driver_unregister(&rk616_codec_driver); +} +module_exit(rk616_exit); + +#ifdef RK616_PROC +static ssize_t rk616_proc_write(struct file *file, const char __user *buffer, + unsigned long len, void *data) +{ + struct snd_soc_codec *codec = rk616_priv->codec; + char *cookie_pot, *p, debug_write_read = 0; + int reg, value; + + if (!rk616_priv & !rk616_priv->codec) + return -EINVAL; + + cookie_pot = (char *)vmalloc( len ); + if (!cookie_pot) { + return -ENOMEM; + } else { + if (copy_from_user( cookie_pot, buffer, len )) + return -EFAULT; + } + + switch(cookie_pot[0]) { + case 'd': + case 'D': + debug_write_read ++; + debug_write_read %= 2; + if (debug_write_read != 0) + printk("Debug read and write reg on\n"); + else + printk("Debug read and write reg off\n"); + break; + case 'r': + case 'R': + printk("Read reg debug\n"); + if (cookie_pot[1] ==':') { + debug_write_read = 1; + strsep(&cookie_pot,":"); + while ((p = strsep(&cookie_pot, ","))) { + reg = simple_strtol(p, NULL, 16); + value = snd_soc_read(codec, reg); + printk("rk616_read:0x%04x = 0x%04x\n", reg, value); + } + debug_write_read = 0; + printk("\n"); + } else { + printk("Error Read reg debug.\n"); + printk("For example: echo r:22,23,24,25>rk616_ts\n"); + } + break; + case 'w': + case 'W': + printk("Write reg debug\n"); + if (cookie_pot[1] ==':') { + debug_write_read = 1; + strsep(&cookie_pot, ":"); + while ((p = strsep(&cookie_pot, "="))) { + reg = simple_strtol(p, NULL, 16); + p=strsep(&cookie_pot, ","); + value = simple_strtol(p, NULL, 16); + snd_soc_write(codec, reg, value); + printk("rk616_write:0x%04x = 0x%04x\n", reg, value); + } + debug_write_read = 0; + printk("\n"); + } else { + printk("Error Write reg debug.\n"); + printk("For example: w:22=0,23=0,24=0,25=0>rk616_ts\n"); + } + break; + case 'a': + printk("Dump reg \n"); + + for (reg = 0; reg < 0x6e; reg += 2) { + value = snd_soc_read(codec, reg); + printk("rk616_read : 0x%04x = 0x%04x\n", reg, value); + } + break; + default: + printk("Help for rk616_ts .\n-->The Cmd list: \n"); + printk("-->'d&&D' Open or Off the debug\n"); + printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>rk616_ts\n"); + printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>rk616_ts\n"); + break; + } + + return len; +} + +static const struct file_operations rk616_proc_fops = { + .owner = THIS_MODULE, +}; + +static int rk616_proc_init(void) +{ + struct proc_dir_entry *rk616_proc_entry; + + rk616_proc_entry = create_proc_entry("driver/rk616_ts", 0777, NULL); + + if(rk616_proc_entry != NULL) { + rk616_proc_entry->write_proc = rk616_proc_write; + return 0; + } else { + printk("create proc error !\n"); + return -1; + } +} +#endif + +MODULE_DESCRIPTION("ASoC RK616 driver"); +MODULE_AUTHOR("chenjq "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rk616_codec.h b/sound/soc/codecs/rk616_codec.h new file mode 100755 index 000000000000..704caea26bea --- /dev/null +++ b/sound/soc/codecs/rk616_codec.h @@ -0,0 +1,737 @@ +/* + * rk616.h -- RK616 CODEC ALSA SoC audio driver + * + * Copyright 2013 Rockship + * Author: chenjq + * + */ + +#ifndef __RK616_CODEC_H__ +#define __RK616_CODEC_H__ + +#define RK616_CODEC_BASE 0x0800 + +#define RK616_RESET (RK616_CODEC_BASE + 0x00) +#define RK616_ADC_INT_CTL1 (RK616_CODEC_BASE + 0x08) +#define RK616_ADC_INT_CTL2 (RK616_CODEC_BASE + 0x0c) +#define RK616_DAC_INT_CTL1 (RK616_CODEC_BASE + 0x10) +#define RK616_DAC_INT_CTL2 (RK616_CODEC_BASE + 0x14) +#define RK616_PGA_AGC_CTL (RK616_CODEC_BASE + 0x28) +#define RK616_PWR_ADD1 (RK616_CODEC_BASE + 0x3c) +#define RK616_BST_CTL (RK616_CODEC_BASE + 0x40) +#define RK616_DIFFIN_CTL (RK616_CODEC_BASE + 0x44) +#define RK616_MIXINL_CTL (RK616_CODEC_BASE + 0x48) +#define RK616_MIXINL_VOL1 (RK616_CODEC_BASE + 0x4c) +#define RK616_MIXINL_VOL2 (RK616_CODEC_BASE + 0x50) +#define RK616_MIXINR_CTL (RK616_CODEC_BASE + 0x54) +#define RK616_MIXINR_VOL1 (RK616_CODEC_BASE + 0x58) +#define RK616_MIXINR_VOL2 (RK616_CODEC_BASE + 0x5c) +#define RK616_PGAL_CTL (RK616_CODEC_BASE + 0x60) +#define RK616_PGAR_CTL (RK616_CODEC_BASE + 0x64) +#define RK616_PWR_ADD2 (RK616_CODEC_BASE + 0x68) +#define RK616_DAC_CTL (RK616_CODEC_BASE + 0x6c) +#define RK616_LINEMIX_CTL (RK616_CODEC_BASE + 0x70) +#define RK616_MUXHP_HPMIX_CTL (RK616_CODEC_BASE + 0x74) +#define RK616_HPMIX_CTL (RK616_CODEC_BASE + 0x78) +#define RK616_HPMIX_VOL1 (RK616_CODEC_BASE + 0x7c) +#define RK616_HPMIX_VOL2 (RK616_CODEC_BASE + 0x80) +#define RK616_LINEOUT1_CTL (RK616_CODEC_BASE + 0x84) +#define RK616_LINEOUT2_CTL (RK616_CODEC_BASE + 0x88) +#define RK616_SPKL_CTL (RK616_CODEC_BASE + 0x8c) +#define RK616_SPKR_CTL (RK616_CODEC_BASE + 0x90) +#define RK616_HPL_CTL (RK616_CODEC_BASE + 0x94) +#define RK616_HPR_CTL (RK616_CODEC_BASE + 0x98) +#define RK616_MICBIAS_CTL (RK616_CODEC_BASE + 0x9c) +#define RK616_MICKEY_DET_CTL (RK616_CODEC_BASE + 0xa0) +#define RK616_PWR_ADD3 (RK616_CODEC_BASE + 0xa4) +#define RK616_ADC_CTL (RK616_CODEC_BASE + 0xa8) +#define RK616_PGAL_AGC_CTL1 (RK616_CODEC_BASE + 0xc0) +#define RK616_PGAL_AGC_CTL2 (RK616_CODEC_BASE + 0xc4) +#define RK616_PGAL_AGC_CTL3 (RK616_CODEC_BASE + 0xc8) +#define RK616_PGAL_AGC_CTL4 (RK616_CODEC_BASE + 0xcc) +#define RK616_PGAL_ASR_CTL (RK616_CODEC_BASE + 0xd0) +#define RK616_PGAL_AGC_MAX_H (RK616_CODEC_BASE + 0xd4) +#define RK616_PGAL_AGC_MAX_L (RK616_CODEC_BASE + 0xd8) +#define RK616_PGAL_AGC_MIN_H (RK616_CODEC_BASE + 0xdc) +#define RK616_PGAL_AGC_MIN_L (RK616_CODEC_BASE + 0xe0) +#define RK616_PGAL_AGC_CTL5 (RK616_CODEC_BASE + 0xe4) +#define RK616_PGAR_AGC_CTL1 (RK616_CODEC_BASE + 0x100) +#define RK616_PGAR_AGC_CTL2 (RK616_CODEC_BASE + 0x104) +#define RK616_PGAR_AGC_CTL3 (RK616_CODEC_BASE + 0x108) +#define RK616_PGAR_AGC_CTL4 (RK616_CODEC_BASE + 0x10c) +#define RK616_PGAR_ASR_CTL (RK616_CODEC_BASE + 0x110) +#define RK616_PGAR_AGC_MAX_H (RK616_CODEC_BASE + 0x114) +#define RK616_PGAR_AGC_MAX_L (RK616_CODEC_BASE + 0x118) +#define RK616_PGAR_AGC_MIN_H (RK616_CODEC_BASE + 0x11c) +#define RK616_PGAR_AGC_MIN_L (RK616_CODEC_BASE + 0x120) +#define RK616_PGAR_AGC_CTL5 (RK616_CODEC_BASE + 0x124) + +/* global definition (0x8c 0x90 0x94 0x98) */ +#define RK616_PWRD (0x1 << 7) +#define RK616_PWRD_SFT 7 + +#define RK616_INIT_MASK (0x1 << 6)//? INIT +#define RK616_INIT_SFT 6 +#define RK616_INIT_RN (0x1 << 6) +#define RK616_INIT_AFT (0x0 << 6) + +#define RK616_MUTE (0x1 << 5) +#define RK616_MUTE_SFT 5 + +#define RK616_VOL_MASK 0x1f +#define RK616_VOL_SFT 0 + +/* ADC Interface Control 1 (0x08) */ +#define RK616_ALRCK_POL_MASK (0x1 << 7) +#define RK616_ALRCK_POL_SFT 7 +#define RK616_ALRCK_POL_EN (0x1 << 7) +#define RK616_ALRCK_POL_DIS (0x0 << 7) + +#define RK616_ADC_VWL_MASK (0x3 << 5) +#define RK616_ADC_VWL_SFT 5 +#define RK616_ADC_VWL_32 (0x3 << 5) +#define RK616_ADC_VWL_24 (0x2 << 5) +#define RK616_ADC_VWL_20 (0x1 << 5) +#define RK616_ADC_VWL_16 (0x0 << 5) + +#define RK616_ADC_DF_MASK (0x3 << 3) +#define RK616_ADC_DF_SFT 3 +#define RK616_ADC_DF_PCM (0x3 << 3) +#define RK616_ADC_DF_I2S (0x2 << 3) +#define RK616_ADC_DF_LJ (0x1 << 3) +#define RK616_ADC_DF_RJ (0x0 << 3) + +#define RK616_ADC_SWAP_MASK (0x1 << 1) +#define RK616_ADC_SWAP_SFT 1 +#define RK616_ADC_SWAP_EN (0x1 << 1) +#define RK616_ADC_SWAP_DIS (0x0 << 1) + +#define RK616_I2S_TYPE_MASK 0x1 +#define RK616_I2S_TYPE_SFT 0 +#define RK616_I2S_TYPE_STEREO 0x1 +#define RK616_I2S_TYPE_MONO 0x0 + +/* ADC Interface Control 2 (0x0c) */ +#define RK616_I2S_MODE_MASK (0x1 << 4) +#define RK616_I2S_MODE_SFT 4 +#define RK616_I2S_MODE_MST (0x1 << 4) +#define RK616_I2S_MODE_SLV (0x0 << 4) + +#define RK616_ADC_WL_MASK (0x3 << 2) +#define RK616_ADC_WL_SFT 2 +#define RK616_ADC_WL_32 (0x3 << 2) +#define RK616_ADC_WL_24 (0x2 << 2) +#define RK616_ADC_WL_20 (0x1 << 2) +#define RK616_ADC_WL_16 (0x0 << 2) + +#define RK616_ADC_RST_MASK (0x1 << 1) +#define RK616_ADC_RST_SFT 1 +#define RK616_ADC_RST_EN (0x1 << 1) +#define RK616_ADC_RST_DIS (0x0 << 1) + +#define RK616_ABCLK_POL_MASK 0x1 +#define RK616_ABCLK_POL_SFT 0 +#define RK616_ABCLK_POL_EN 0x1 +#define RK616_ABCLK_POL_DIS 0x0 + +/* DAC Interface Control 1 (0x10) */ +#define RK616_DLRCK_POL_MASK (0x1 << 7) +#define RK616_DLRCK_POL_SFT 7 +#define RK616_DLRCK_POL_EN (0x1 << 7) +#define RK616_DLRCK_POL_DIS (0x0 << 7) + +#define RK616_DAC_VWL_MASK (0x3 << 5) +#define RK616_DAC_VWL_SFT 5 +#define RK616_DAC_VWL_32 (0x3 << 5) +#define RK616_DAC_VWL_24 (0x2 << 5) +#define RK616_DAC_VWL_20 (0x1 << 5) +#define RK616_DAC_VWL_16 (0x0 << 5) + +#define RK616_DAC_DF_MASK (0x3 << 3) +#define RK616_DAC_DF_SFT 3 +#define RK616_DAC_DF_PCM (0x3 << 3) +#define RK616_DAC_DF_I2S (0x2 << 3) +#define RK616_DAC_DF_LJ (0x1 << 3) +#define RK616_DAC_DF_RJ (0x0 << 3) + +#define RK616_DAC_SWAP_MASK (0x1 << 2) +#define RK616_DAC_SWAP_SFT 2 +#define RK616_DAC_SWAP_EN (0x1 << 2) +#define RK616_DAC_SWAP_DIS (0x0 << 2) + +/* DAC Interface Control 2 (0x14) */ +#define RK616_DAC_WL_MASK (0x3 << 2) +#define RK616_DAC_WL_SFT 2 +#define RK616_DAC_WL_32 (0x3 << 2) +#define RK616_DAC_WL_24 (0x2 << 2) +#define RK616_DAC_WL_20 (0x1 << 2) +#define RK616_DAC_WL_16 (0x0 << 2) + +#define RK616_DAC_RST_MASK (0x1 << 1) +#define RK616_DAC_RST_SFT 1 +#define RK616_DAC_RST_EN (0x1 << 1) +#define RK616_DAC_RST_DIS (0x0 << 1) + +#define RK616_DBCLK_POL_MASK 0x1 +#define RK616_DBCLK_POL_SFT 0 +#define RK616_DBCLK_POL_EN 0x1 +#define RK616_DBCLK_POL_DIS 0x0 + +/* PGA AGC Enable (0x28) */ +#define RK616_PGAL_AGC_EN_MASK (0x1 << 5) +#define RK616_PGAL_AGC_EN_SFT 5 +#define RK616_PGAL_AGC_EN (0x1 << 5) +#define RK616_PGAL_AGC_DIS (0x0 << 5) + +#define RK616_PGAR_AGC_EN_MASK (0x1 << 4) +#define RK616_PGAR_AGC_EN_SFT 4 +#define RK616_PGAR_AGC_EN (0x1 << 4) +#define RK616_PGAR_AGC_DIS (0x0 << 4) + +/* Power Management Addition 1 (0x3c) */ +#define RK616_ADC_PWRD (0x1 << 6) +#define RK616_ADC_PWRD_SFT 6 + +#define RK616_DIFFIN_MIR_PGAR_RLPWRD (0x1 << 5) +#define RK616_DIFFIN_MIR_PGAR_RLPWRD_SFT 5 + +#define RK616_MIC1_MIC2_MIL_PGAL_RLPWRD (0x1 << 4) +#define RK616_MIC1_MIC2_MIL_PGAL_RLPWRD_SFT 4 + +#define RK616_ADCL_RLPWRD (0x1 << 3) +#define RK616_ADCL_RLPWRD_SFT 3 + +#define RK616_ADCR_RLPWRD (0x1 << 2) +#define RK616_ADCR_RLPWRD_SFT 2 + +/* BST Control (0x40) */ +#define RK616_BSTL_PWRD (0x1 << 7) +#define RK616_BSTL_PWRD_SFT 7 + +#define RK616_BSTL_MODE_MASK (0x1 << 6) +#define RK616_BSTL_MODE_SFT 6 +#define RK616_BSTL_MODE_SE (0x1 << 6) +#define RK616_BSTL_MODE_DIFF (0x0 << 6) + +#define RK616_BSTL_GAIN_MASK (0x1 << 5) +#define RK616_BSTL_GAIN_SFT 5 +#define RK616_BSTL_GAIN_20DB (0x1 << 5) +#define RK616_BSTL_GAIN_0DB (0x0 << 5) + +#define RK616_BSTL_MUTE (0x1 << 4) +#define RK616_BSTL_MUTE_SFT 4 + +#define RK616_BSTR_PWRD (0x1 << 3) +#define RK616_BSTR_PWRD_SFT 3 + +#define RK616_BSTR_MODE_MASK (0x1 << 2) +#define RK616_BSTR_MODE_SFT 2 +#define RK616_BSTR_MODE_SE (0x1 << 2) +#define RK616_BSTR_MODE_DIFF (0x0 << 2) + +#define RK616_BSTR_GAIN_MASK (0x1 << 1) +#define RK616_BSTR_GAIN_SFT 1 +#define RK616_BSTR_GAIN_20DB (0x1 << 1) +#define RK616_BSTR_GAIN_0DB (0x0 << 1) + +#define RK616_BSTR_MUTE 0x1 +#define RK616_BSTR_MUTE_SFT 0 + +/* DIFFIN Control (0x44) */ +#define RK616_DIFFIN_PWRD (0x1 << 5) +#define RK616_DIFFIN_PWRD_SFT 5 + +#define RK616_DIFFIN_MODE_MASK (0x1 << 4) +#define RK616_DIFFIN_MODE_SFT 4 +#define RK616_DIFFIN_MODE_SE (0x1 << 4) +#define RK616_DIFFIN_MODE_DIFF (0x0 << 4) + +#define RK616_DIFFIN_GAIN_MASK (0x1 << 3) +#define RK616_DIFFIN_GAIN_SFT 3 +#define RK616_DIFFIN_GAIN_20DB (0x1 << 3) +#define RK616_DIFFIN_GAIN_0DB (0x0 << 3) + +#define RK616_DIFFIN_MUTE (0x1 << 2) +#define RK616_DIFFIN_MUTE_SFT 2 + +#define RK616_MIRM_F_MASK (0x1 << 1) +#define RK616_MIRM_F_SFT 1 +#define RK616_MIRM_F_IN1N (0x1 << 1) +#define RK616_MIRM_F_DIFFIN (0x0 << 1) + +#define RK616_HMM_F_MASK 0x1 +#define RK616_HMM_F_SFT 0 +#define RK616_HMM_F_IN1N 0x1 +#define RK616_HMM_F_DIFFIN 0x0 + + +/* BSTR MUXMIC MIXINL Control (0x48) */ +#define RK616_SE_BSTR_F_MASK (0x1 << 6) +#define RK616_SE_BSTR_F_SFT 6 +#define RK616_SE_BSTR_F_MIN2P (0x1 << 6) +#define RK616_SE_BSTR_F_MIN2N (0x0 << 6) + +#define RK616_MM_F_MASK (0x1 << 5) +#define RK616_MM_F_SFT 5 +#define RK616_MM_F_BSTR (0x1 << 5) +#define RK616_MM_F_BSTL (0x0 << 5) + +#define RK616_MIL_PWRD (0x1 << 4) +#define RK616_MIL_PWRD_SFT 4 + +#define RK616_MIL_MUTE (0x1 << 3) +#define RK616_MIL_MUTE_SFT 3 + +#define RK616_MIL_F_IN3L (0x1 << 2) +#define RK616_MIL_F_IN3L_SFT 2 + +#define RK616_MIL_F_IN1P (0x1 << 1) +#define RK616_MIL_F_IN1P_SFT 1 + +#define RK616_MIL_F_MUX (0x1 << 0) +#define RK616_MIL_F_MUX_SFT 0 + +/* MIXINL volume 1 (0x4c) */ +#define RK616_MIL_F_MUX_VOL_MASK (0x7 << 3) +#define RK616_MIL_F_MUX_VOL_SFT 3 + +#define RK616_MIL_F_IN1P_VOL_MASK 0x7 +#define RK616_MIL_F_IN1P_VOL_SFT 0 + +/* MIXINL volume 2 (0x50) */ +#define RK616_MIL_F_IN3L_VOL_MASK 0x7 +#define RK616_MIL_F_IN3L_VOL_SFT 0 + +/* MIXINR Control (0x54) */ +#define RK616_MIR_PWRD (0x1 << 5) +#define RK616_MIR_PWRD_SFT 5 + +#define RK616_MIR_MUTE (0x1 << 4) +#define RK616_MIR_MUTE_SFT 4 + +#define RK616_MIR_F_MIC2N (0x1 << 3) +#define RK616_MIR_F_MIC2N_SFT 3 + +#define RK616_MIR_F_IN1P (0x1 << 2) +#define RK616_MIR_F_IN1P_SFT 2 + +#define RK616_MIR_F_IN3R (0x1 << 1) +#define RK616_MIR_F_IN3R_SFT 1 + +#define RK616_MIR_F_MIRM 0x1 +#define RK616_MIR_F_MIRM_SFT 0 + +/* MIXINR volume 1 (0x58) */ +#define RK616_MIR_F_MIRM_VOL_MASK (0x7 << 3) +#define RK616_MIR_F_MIRM_VOL_SFT 3 + +#define RK616_MIR_F_IN3R_VOL_MASK 0x7 +#define RK616_MIR_F_IN3R_VOL_SFT 0 + +/* MIXINR volume 2 (0x5c) */ +#define RK616_MIR_F_MIC2N_VOL_MASK (0x7 << 3) +#define RK616_MIR_F_MIC2N_VOL_SFT 3 + +#define RK616_MIR_F_IN1P_VOL_MASK 0x7 +#define RK616_MIR_F_IN1P_VOL_SFT 0 + +/* PGA Control (0x60 0x64) */ +#define RK616_PGA_PWRD (0x1 << 7) +#define RK616_PGA_PWRD_SFT 7 + +#define RK616_PGA_MUTE (0x1 << 6) +#define RK616_PGA_MUTE_SFT 6 + +#define RK616_PGA_VOL_MASK (0x1f << 0) +#define RK616_PGA_VOL_SFT 0 + + +/* Power Management Addition 2 (0x68) */ +#define RK616_HPL_HPR_PWRD (0x1 << 7) +#define RK616_HPL_HPR_PWRD_SFT 7 + +#define RK616_DAC_PWRD (0x1 << 6)//? Interface or not +#define RK616_DAC_PWRD_SFT 6 + +#define RK616_DACL_RLPWRD (0x1 << 5) +#define RK616_DACL_RLPWRD_SFT 5 + +#define RK616_DACL_SPKL_RLPWRD (0x1 << 4) +#define RK616_DACL_SPKL_RLPWRD_SFT 4 + +#define RK616_DACR_RLPWRD (0x1 << 3) +#define RK616_DACR_RLPWRD_SFT 3 + +#define RK616_DACR_SPKR_RLPWRD (0x1 << 2)//? BIT 3 BIT 6 BIT 2 +#define RK616_DACR_SPKR_RLPWRD_SFT 2 + +#define RK616_LM_LO_RLPWRD (0x1 << 1) +#define RK616_LM_LO_RLPWRD_SFT 1 + +#define RK616_HM_RLPWRD 0x1 +#define RK616_HM_RLPWRD_SFT 0 + +/* DAC Control (0x6c) */ +#define RK616_DACL_INIT_MASK (0x1 << 5)//? INIT? +#define RK616_DACL_INIT_SFT 5 +#define RK616_DACL_INIT_RN (0x1 << 5) +#define RK616_DACL_INIT_AFT (0x0 << 5) + +#define RK616_DACR_INIT_MASK (0x1 << 4)//? INIT? +#define RK616_DACR_INIT_SFT 4 +#define RK616_DACR_INIT_RN (0x1 << 4) +#define RK616_DACR_INIT_AFT (0x0 << 4) + +#define RK616_DACL_PWRD (0x1 << 3) +#define RK616_DACL_PWRD_SFT 3 + +#define RK616_DACR_PWRD (0x1 << 2) +#define RK616_DACR_PWRD_SFT 2 + +#define RK616_DACR_CLK_PWRD (0x1 << 1) +#define RK616_DACR_CLK_PWRD_SFT 1 + +#define RK616_DACL_CLK_PWRD 0x1 +#define RK616_DACL_CLK_PWRD_SFT 0 + +/* Linemix Control (0x70) */ +#define RK616_LM_PWRD (0x1 << 4) +#define RK616_LM_PWRD_SFT 4 + +#define RK616_LM_F_PGAR (0x1 << 3) +#define RK616_LM_F_PGAR_SFT 3 + +#define RK616_LM_F_PGAL (0x1 << 2) +#define RK616_LM_F_PGAL_SFT 2 + +#define RK616_LM_F_DACR (0x1 << 1) +#define RK616_LM_F_DACR_SFT 1 + +#define RK616_LM_F_DACL 0x1 +#define RK616_LM_F_DACL_SFT 0 + +/* MUXHP HPMIX Control (0x74) */ +#define RK616_HML_PWRD (0x1 << 5) +#define RK616_HML_PWRD_SFT 5 + +#define RK616_HML_INIT_MASK (0x1 << 4)//? INIT? +#define RK616_HML_INIT_SFT 4 +#define RK616_HML_INIT_RN (0x1 << 4) +#define RK616_HML_INIT_AFT (0x0 << 4) + +#define RK616_HMR_PWRD (0x1 << 3) +#define RK616_HMR_PWRD_SFT 3 + +#define RK616_HMR_INIT_MASK (0x1 << 2)//? INIT? +#define RK616_HMR_INIT_SFT 2 +#define RK616_HMR_INIT_RN (0x1 << 2) +#define RK616_HMR_INIT_AFT (0x0 << 2) + +#define RK616_MHL_F_MASK (0x1 << 1) +#define RK616_MHL_F_SFT 1 +#define RK616_MHL_F_DACL (0x1 << 1) +#define RK616_MHL_F_HPMIXL (0x0 << 1) + +#define RK616_MHR_F_MASK 0x1 +#define RK616_MHR_F_SFT 0 +#define RK616_MHR_F_DACR 0x1 +#define RK616_MHR_F_HPMIXR 0x0 + +/* HPMIX Control (0x78) */ +#define RK616_HML_F_HMM (0x1 << 7) +#define RK616_HML_F_HMM_SFT 7 + +#define RK616_HML_F_IN1P (0x1 << 6) +#define RK616_HML_F_IN1P_SFT 6 + +#define RK616_HML_F_PGAL (0x1 << 5) +#define RK616_HML_F_PGAL_SFT 5 + +#define RK616_HML_F_DACL (0x1 << 4) +#define RK616_HML_F_DACL_SFT 4 + +#define RK616_HMR_F_HMM (0x1 << 3) +#define RK616_HMR_F_HMM_SFT 3 + +#define RK616_HMR_F_PGAR (0x1 << 2) +#define RK616_HMR_F_PGAR_SFT 2 + +#define RK616_HMR_F_PGAL (0x1 << 1) +#define RK616_HMR_F_PGAL_SFT 1 + +#define RK616_HMR_F_DACR 0x1 +#define RK616_HMR_F_DACR_SFT 0 + +/* HPMIX Volume Control 1 (0x7c) */ +#define RK616_HML_F_IN1P_VOL_MASK 0x7 +#define RK616_HML_F_IN1P_VOL_SFT 0 + +/* HPMIX Volume Control 2 (0x80) */ +#define RK616_HML_F_HMM_VOL_MASK (0x7 << 3) +#define RK616_HML_F_HMM_VOL_SFT 3 + +#define RK616_HMR_F_HMM_VOL_MASK 0x7 +#define RK616_HMR_F_HMM_VOL_SFT 0 + +/* Lineout1 Control (0x84 0x88) */ +#define RK616_LINEOUT_PWRD (0x1 << 6) +#define RK616_LINEOUT_PWRD_SFT 6 + +#define RK616_LINEOUT_MUTE (0x1 << 5) +#define RK616_LINEOUT_MUTE_SFT 5 + +#define RK616_LINEOUT_VOL_MASK 0x1f +#define RK616_LINEOUT_VOL_SFT 0 + +/* Micbias Control 1 (0x9c) */ +#define RK616_MICBIAS1_PWRD (0x1 << 7) +#define RK616_MICBIAS1_PWRD_SFT 7 + +#define RK616_MICBIAS2_PWRD (0x1 << 6) +#define RK616_MICBIAS2_PWRD_SFT 6 + +#define RK616_MICBIAS1_V_MASK (0x7 << 3) +#define RK616_MICBIAS1_V_SFT 3 +#define RK616_MICBIAS1_V_1_7 (0x7 << 3) +#define RK616_MICBIAS1_V_1_6 (0x6 << 3) +#define RK616_MICBIAS1_V_1_5 (0x5 << 3) +#define RK616_MICBIAS1_V_1_4 (0x4 << 3) +#define RK616_MICBIAS1_V_1_3 (0x3 << 3) +#define RK616_MICBIAS1_V_1_2 (0x2 << 3) +#define RK616_MICBIAS1_V_1_1 (0x1 << 3) +#define RK616_MICBIAS1_V_1_0 (0x0 << 3) + +#define RK616_MICBIAS2_V_MASK 0x7 +#define RK616_MICBIAS2_V_SFT 0 +#define RK616_MICBIAS2_V_1_7 0x7 +#define RK616_MICBIAS2_V_1_6 0x6 +#define RK616_MICBIAS2_V_1_5 0x5 +#define RK616_MICBIAS2_V_1_4 0x4 +#define RK616_MICBIAS2_V_1_3 0x3 +#define RK616_MICBIAS2_V_1_2 0x2 +#define RK616_MICBIAS2_V_1_1 0x1 +#define RK616_MICBIAS2_V_1_0 0x0 + +/* MIC Key Detection Control (0xa0) */ +#define RK616_MK1_DET_MASK (0x1 << 7) +#define RK616_MK1_DET_SFT 7 +#define RK616_MK1_EN (0x1 << 7) +#define RK616_MK1_DIS (0x0 << 7) + +#define RK616_MK2_DET_MASK (0x1 << 6) +#define RK616_MK2_DET_SFT 6 +#define RK616_MK2_EN (0x1 << 6) +#define RK616_MK2_DIS (0x0 << 6) + +#define RK616_MK1_DET_I_MASK (0x7 << 3) +#define RK616_MK1_DET_I_SFT 3 +#define RK616_MK1_DET_I_1500 (0x7 << 3) +#define RK616_MK1_DET_I_1300 (0x6 << 3) +#define RK616_MK1_DET_I_1100 (0x5 << 3) +#define RK616_MK1_DET_I_900 (0x4 << 3) +#define RK616_MK1_DET_I_700 (0x3 << 3) +#define RK616_MK1_DET_I_500 (0x2 << 3) +#define RK616_MK1_DET_I_300 (0x1 << 3) +#define RK616_MK1_DET_I_100 (0x0 << 3) + +#define RK616_MK2_DET_I_MASK 0x7 +#define RK616_MK2_DET_I_SFT 0 +#define RK616_MK2_DET_I_1500 0x7 +#define RK616_MK2_DET_I_1300 0x6 +#define RK616_MK2_DET_I_1100 0x5 +#define RK616_MK2_DET_I_900 0x4 +#define RK616_MK2_DET_I_700 0x3 +#define RK616_MK2_DET_I_500 0x2 +#define RK616_MK2_DET_I_300 0x1 +#define RK616_MK2_DET_I_100 0x0 + +/* Power Management Addition 3 (0xa4) */ +#define RK616_ADCL_ZO_PWRD (0x1 << 3) +#define RK616_ADCL_ZO_PWRD_SFT 3 + +#define RK616_ADCR_ZO_PWRD (0x1 << 2) +#define RK616_ADCR_ZO_PWRD_SFT 2 + +#define RK616_DACL_ZO_PWRD (0x1 << 1) +#define RK616_DACL_ZO_PWRD_SFT 1 + +#define RK616_DACR_ZO_PWRD 0x1 +#define RK616_DACR_ZO_PWRD_SFT 0 + +/* ADC control (0xa8) */ +#define RK616_ADCL_CLK_PWRD (0x1 << 5)//?set to 1 +#define RK616_ADCL_CLK_PWRD_SFT 5 + +#define RK616_ADCL_PWRD (0x1 << 4) +#define RK616_ADCL_PWRD_SFT 4 + +#define RK616_ADCL_RST_MASK (0x1 << 3)//? 0x0c same +#define RK616_ADCL_RST_SFT 3 +#define RK616_ADCL_RST_EN (0x1 << 3)//? 1 clear 0 work means +#define RK616_ADCL_RST_DIS (0x0 << 3) + +#define RK616_ADCR_CLK_PWRD (0x1 << 2) +#define RK616_ADCR_CLK_PWRD_SFT 2 + +#define RK616_ADCR_PWRD (0x1 << 1) +#define RK616_ADCR_PWRD_SFT 1 + +#define RK616_ADCR_RST_MASK 0x1//? 0x0c same +#define RK616_ADCR_RST_SFT 0 +#define RK616_ADCR_RST_EN 0x1//? 1 clear 0 work means +#define RK616_ADCR_RST_DIS 0x0 + +/* PGA AGC control 1 (0xc0 0x110) */ +#define RK616_PGA_AGC_WAY_MASK (0x1 << 4) +#define RK616_PGA_AGC_WAY_SFT 4 +#define RK616_PGA_AGC_WAY_JACK (0x1 << 4) +#define RK616_PGA_AGC_WAY_NOR (0x0 << 4) + +#define RK616_PGA_AGC_HOLD_T_MASK 0xf +#define RK616_PGA_AGC_HOLD_T_SFT 0 +#define RK616_PGA_AGC_HOLD_T_1024 0xa +#define RK616_PGA_AGC_HOLD_T_512 0x9 +#define RK616_PGA_AGC_HOLD_T_256 0x8 +#define RK616_PGA_AGC_HOLD_T_128 0x7 +#define RK616_PGA_AGC_HOLD_T_64 0x6 +#define RK616_PGA_AGC_HOLD_T_32 0x5 +#define RK616_PGA_AGC_HOLD_T_16 0x4 +#define RK616_PGA_AGC_HOLD_T_8 0x3 +#define RK616_PGA_AGC_HOLD_T_4 0x2 +#define RK616_PGA_AGC_HOLD_T_2 0x1 +#define RK616_PGA_AGC_HOLD_T_0 0x0 + +/* PGA AGC control 2 (0xc4 0x104) */ +#define RK616_PGA_AGC_GRU_T_MASK (0xf << 4) +#define RK616_PGA_AGC_GRU_T_SFT 4 +#define RK616_PGA_AGC_GRU_T_512 (0xa << 4) +#define RK616_PGA_AGC_GRU_T_256 (0x9 << 4) +#define RK616_PGA_AGC_GRU_T_128 (0x8 << 4) +#define RK616_PGA_AGC_GRU_T_64 (0x7 << 4) +#define RK616_PGA_AGC_GRU_T_32 (0x6 << 4) +#define RK616_PGA_AGC_GRU_T_16 (0x5 << 4) +#define RK616_PGA_AGC_GRU_T_8 (0x4 << 4) +#define RK616_PGA_AGC_GRU_T_4 (0x3 << 4) +#define RK616_PGA_AGC_GRU_T_2 (0x2 << 4) +#define RK616_PGA_AGC_GRU_T_1 (0x1 << 4) +#define RK616_PGA_AGC_GRU_T_0_5 (0x0 << 4) + +#define RK616_PGA_AGC_GRD_T_MASK 0xf +#define RK616_PGA_AGC_GRD_T_SFT 0 +#define RK616_PGA_AGC_GRD_T_128_32 0xa +#define RK616_PGA_AGC_GRD_T_64_16 0x9 +#define RK616_PGA_AGC_GRD_T_32_8 0x8 +#define RK616_PGA_AGC_GRD_T_16_4 0x7 +#define RK616_PGA_AGC_GRD_T_8_2 0x6 +#define RK616_PGA_AGC_GRD_T_4_1 0x5 +#define RK616_PGA_AGC_GRD_T_2_0_512 0x4 +#define RK616_PGA_AGC_GRD_T_1_0_256 0x3 +#define RK616_PGA_AGC_GRD_T_0_500_128 0x2 +#define RK616_PGA_AGC_GRD_T_0_250_64 0x1 +#define RK616_PGA_AGC_GRD_T_0_125_32 0x0 + +/* PGA AGC control 3 (0xc8 0x108) */ +#define RK616_PGA_AGC_MODE_MASK (0x1 << 7) +#define RK616_PGA_AGC_MODE_SFT 7 +#define RK616_PGA_AGC_MODE_LIMIT (0x1 << 7) +#define RK616_PGA_AGC_MODE_NOR (0x0 << 7) + +#define RK616_PGA_AGC_ZO_MASK (0x1 << 6) +#define RK616_PGA_AGC_ZO_SFT 6 +#define RK616_PGA_AGC_ZO_EN (0x1 << 6) +#define RK616_PGA_AGC_ZO_DIS (0x0 << 6) + +#define RK616_PGA_AGC_REC_MODE_MASK (0x1 << 5) +#define RK616_PGA_AGC_REC_MODE_SFT 5 +#define RK616_PGA_AGC_REC_MODE_AC (0x1 << 5) +#define RK616_PGA_AGC_REC_MODE_RN (0x0 << 5) + +#define RK616_PGA_AGC_FAST_D_MASK (0x1 << 4) +#define RK616_PGA_AGC_FAST_D_SFT 4 +#define RK616_PGA_AGC_FAST_D_EN (0x1 << 4) +#define RK616_PGA_AGC_FAST_D_DIS (0x0 << 4) + +#define RK616_PGA_AGC_NG_MASK (0x1 << 3) +#define RK616_PGA_AGC_NG_SFT 3 +#define RK616_PGA_AGC_NG_EN (0x1 << 3) +#define RK616_PGA_AGC_NG_DIS (0x0 << 3) + +#define RK616_PGA_AGC_NG_THR_MASK 0x7 +#define RK616_PGA_AGC_NG_THR_SFT 0 +#define RK616_PGA_AGC_NG_THR_N81DB 0x7 +#define RK616_PGA_AGC_NG_THR_N75DB 0x6 +#define RK616_PGA_AGC_NG_THR_N69DB 0x5 +#define RK616_PGA_AGC_NG_THR_N63DB 0x4 +#define RK616_PGA_AGC_NG_THR_N57DB 0x3 +#define RK616_PGA_AGC_NG_THR_N51DB 0x2 +#define RK616_PGA_AGC_NG_THR_N45DB 0x1 +#define RK616_PGA_AGC_NG_THR_N39DB 0x0 + +/* PGA AGC Control 4 (0xcc 0x10c) */ +#define RK616_PGA_AGC_ZO_MODE_MASK (0x1 << 5) +#define RK616_PGA_AGC_ZO_MODE_SFT 5 +#define RK616_PGA_AGC_ZO_MODE_UWRC (0x1 << 5) +#define RK616_PGA_AGC_ZO_MODE_UARC (0x0 << 5) + +#define RK616_PGA_AGC_VOL_MASK 0x1f +#define RK616_PGA_AGC_VOL_SFT 0 + +/* PGA ASR Control (0xd0 0x110) */ +#define RK616_PGA_SLOW_CLK_MASK (0x1 << 3) +#define RK616_PGA_SLOW_CLK_SFT 3 +#define RK616_PGA_SLOW_CLK_EN (0x1 << 3) +#define RK616_PGA_SLOW_CLK_DIS (0x0 << 3) + +#define RK616_PGA_ASR_MASK 0x7 +#define RK616_PGA_ASR_SFT 0 +#define RK616_PGA_ASR_8KHz 0x5 +#define RK616_PGA_ASR_12KHz 0x4 +#define RK616_PGA_ASR_16KHz 0x3 +#define RK616_PGA_ASR_24KHz 0x2 +#define RK616_PGA_ASR_32KHz 0x1 +#define RK616_PGA_ASR_48KHz 0x0 + +/* PGA AGC Control 5 (0xe4 0x124) */ +#define RK616_PGA_AGC_MASK (0x1 << 6) +#define RK616_PGA_AGC_SFT 6 +#define RK616_PGA_AGC_EN (0x1 << 6) +#define RK616_PGA_AGC_DIS (0x0 << 6) + +#define RK616_PGA_AGC_MAX_G_MASK (0x7 << 3) +#define RK616_PGA_AGC_MAX_G_SFT 3 +#define RK616_PGA_AGC_MAX_G_28_5DB (0x7 << 3) +#define RK616_PGA_AGC_MAX_G_22_5DB (0x6 << 3) +#define RK616_PGA_AGC_MAX_G_16_5DB (0x5 << 3) +#define RK616_PGA_AGC_MAX_G_10_5DB (0x4 << 3) +#define RK616_PGA_AGC_MAX_G_4_5DB (0x3 << 3) +#define RK616_PGA_AGC_MAX_G_N1_5DB (0x2 << 3) +#define RK616_PGA_AGC_MAX_G_N7_5DB (0x1 << 3) +#define RK616_PGA_AGC_MAX_G_N13_5DB (0x0 << 3) + +#define RK616_PGA_AGC_MIN_G_MASK 0x7 +#define RK616_PGA_AGC_MIN_G_SFT 0 +#define RK616_PGA_AGC_MIN_G_24DB 0x7 +#define RK616_PGA_AGC_MIN_G_18DB 0x6 +#define RK616_PGA_AGC_MIN_G_12DB 0x5 +#define RK616_PGA_AGC_MIN_G_6DB 0x4 +#define RK616_PGA_AGC_MIN_G_0DB 0x3 +#define RK616_PGA_AGC_MIN_G_N6DB 0x2 +#define RK616_PGA_AGC_MIN_G_N12DB 0x1 +#define RK616_PGA_AGC_MIN_G_N18DB 0x0 + +enum { + RK616_HIFI, + RK616_VOICE, +}; + +enum { + RK616_MONO = 1, + RK616_STEREO, +}; + +struct rk616_reg_val_typ { + unsigned int reg; + unsigned int value; +}; + +#endif //__RK616_CODEC_H__ diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index de090e13bda4..d44586c90cc3 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -251,6 +251,15 @@ config SND_RK29_SOC_RK610 Say Y if you want to add support for SoC audio on rockchip with the RK610(JETTA). +config SND_RK29_SOC_RK616 + tristate "SoC I2S Audio support for rockchip - RK616" + depends on SND_RK29_SOC + select SND_RK29_SOC_I2S + select SND_SOC_RK616 + help + Say Y if you want to add support for SoC audio on rockchip + with the RK616(JETTA). + config SND_RK_SOC_RK2928 tristate "SoC I2S Audio support for rockchip - RK2928" depends on SND_RK29_SOC && ARCH_RK2928 diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile index aa29e347a3c0..cfd5e3bbc1a2 100755 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -29,6 +29,7 @@ snd-soc-rk1000-objs := rk29_rk1000codec.o snd-soc-wm8994-objs := rk29_wm8994.o snd-soc-hdmi-objs := rk29_hdmi.o snd-soc-rk610-objs := rk29_jetta_codec.o +snd-soc-rk616-objs := rk_rk616.o snd-soc-aic3262-objs := rk29_aic3262.o snd-soc-rk2928-objs := rk2928-card.o snd-soc-es8323-objs := rk29_es8323.o @@ -51,5 +52,6 @@ obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o +obj-$(CONFIG_SND_RK29_SOC_RK616) += snd-soc-rk616.o obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o diff --git a/sound/soc/rk29/rk_rk616.c b/sound/soc/rk29/rk_rk616.c new file mode 100755 index 000000000000..49ae8e14deca --- /dev/null +++ b/sound/soc/rk29/rk_rk616.c @@ -0,0 +1,286 @@ +/* + * rk_rk616.c -- SoC audio for rockchip + * + * Driver for rockchip rk616 audio + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/rk616_codec.h" +#include "rk29_pcm.h" +#include "rk29_i2s.h" + +#if 1 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Headset Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), +}; + +static const struct snd_soc_dapm_route rk_audio_map[]={ + + /* Mic Jack --> MIC_IN*/ + {"Mic1 Bias", NULL, "Mic Jack"}, + {"MIC1", NULL, "Mic1 Bias"}, + + // HP MIC + {"Mic1 Bias", NULL, "Headset Jack"}, + {"MIC3", NULL, "Mic1 Bias"}, + + {"Ext Spk", NULL, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + + {"Headphone Jack", NULL, "HPOL"}, + {"Headphone Jack", NULL, "HPOR"}, +} ; + +static const struct snd_kcontrol_new rk_controls[] = { + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Headset Jack"), + SOC_DAPM_PIN_SWITCH("Ext Spk"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), +}; + +static int rk616_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + snd_soc_add_controls(codec, rk_controls, + ARRAY_SIZE(rk_controls)); + + /* Add specific widgets */ + snd_soc_dapm_new_controls(dapm, rk_dapm_widgets, + ARRAY_SIZE(rk_dapm_widgets)); + /* Set up specific audio path audio_mapnects */ + snd_soc_dapm_add_routes(dapm, rk_audio_map, ARRAY_SIZE(rk_audio_map)); + + snd_soc_dapm_enable_pin(dapm, "Mic Jack"); + snd_soc_dapm_enable_pin(dapm, "Headset Jack"); + snd_soc_dapm_enable_pin(dapm, "Ext Spk"); + snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static int rk_hifi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + /* set codec DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); + #endif + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + if (ret < 0) + return ret; + + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + pll_out = 11289600; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + return -EINVAL; + break; + } + + DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + + /*Set the system clk for codec*/ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) { + DBG("rk_hifi_hw_params:failed to set the sysclk for codec side\n"); + return ret; + } + + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); + + DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params)); + + return 0; +} + +static int rk_voice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS); + + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + pll_out = 11289600; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + return -EINVAL; + break; + } + + //snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000); + + /*Set the system clk for codec*/ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); + + if (ret < 0) { + printk("rk_voice_hw_params:failed to set the sysclk for codec side\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + + return 0; +} + +static struct snd_soc_ops rk616_hifi_ops = { + .hw_params = rk_hifi_hw_params, +}; + +static struct snd_soc_ops rk616_voice_ops = { + .hw_params = rk_voice_hw_params, +}; + +static struct snd_soc_dai_link rk_dai[] = { + { + .name = "RK616 I2S1", + .stream_name = "RK616 PCM", + .codec_name = "rk616 codec.0-0050", + .platform_name = "rockchip-audio", + .cpu_dai_name = "rk29_i2s.0", + .codec_dai_name = "rk616-hifi", + .init = rk616_init, + .ops = &rk616_hifi_ops, + }, + { + .name = "RK616 I2S2", + .stream_name = "RK616 PCM", + .codec_name = "rtk616.0-001f", + .platform_name = "rockchip-audio", + .cpu_dai_name = "rk29_i2s.0", + .codec_dai_name = "rk616-voice", + .ops = &rk616_voice_ops, + }, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "RK_RK616", + .dai_link = rk_dai, + .num_links = 2, +}; + +static struct platform_device *rk_snd_device; + +static int __init audio_card_init(void) +{ + int ret =0; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + rk_snd_device = platform_device_alloc("soc-audio", -1); + if (!rk_snd_device) { + printk("platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(rk_snd_device, &snd_soc_card_rk); + ret = platform_device_add(rk_snd_device); + if (ret) { + printk("platform device add failed\n"); + + platform_device_put(rk_snd_device); + return ret; + } + + return ret; +} + +static void __exit audio_card_exit(void) +{ + platform_device_unregister(rk_snd_device); +} + +module_init(audio_card_init); +module_exit(audio_card_exit); +/* Module information */ +MODULE_AUTHOR("rockchip"); +MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface"); +MODULE_LICENSE("GPL"); -- 2.34.1