3208 lines
101 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// es8396.c -- ES8396 ALSA SoC Audio Codec
//
// Copyright (C) 2014 Everest Semiconductor Co., Ltd
//
// Authors: David Yang(yangxiaohua@everest-semi.com)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/stddef.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include "es8396.h"
static int es8396_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level);
/*
* ES8396 register cache
*/
static struct reg_default es8396_reg_defaults[] = {
{0x00, 0x00},
{0x01, 0x00},
{0x02, 0x80},
{0x03, 0x00},
{0x04, 0x00},
{0x05, 0x00},
{0x06, 0x00},
{0x07, 0x00},
{0x08, 0x50},
{0x09, 0x04},
{0x0a, 0x00},
{0x0b, 0x20},
{0x0c, 0x20},
{0x0d, 0x00},
{0x0e, 0x00},
{0x0f, 0x00},
{0x10, 0x00},
{0x11, 0x00},
{0x12, 0x00},
{0x13, 0x00},
{0x14, 0x00},
{0x15, 0x00},
{0x16, 0x00},
{0x17, 0x00},
{0x18, 0x00},
{0x19, 0x00},
{0x1a, 0x00},
{0x1b, 0x00},
{0x1c, 0x00},
{0x1d, 0x00},
{0x1e, 0x00},
{0x1f, 0x00},
{0x20, 0x00},
{0x21, 0x00},
{0x22, 0x00},
{0x23, 0x00},
{0x24, 0x00},
{0x25, 0x00},
{0x26, 0x11},
{0x27, 0x00},
{0x28, 0x00},
{0x29, 0x04},
{0x2a, 0x00},
{0x2b, 0x33},
{0x2c, 0x00},
{0x2d, 0x04},
{0x2e, 0x00},
{0x2f, 0x11},
{0x30, 0x00},
{0x31, 0x04},
{0x32, 0x00},
{0x33, 0x11},
{0x34, 0x00},
{0x35, 0x04},
{0x36, 0x00},
{0x37, 0x11},
{0x38, 0x00},
{0x39, 0x04},
{0x3a, 0x44},
{0x3b, 0x00},
{0x3c, 0x20},
{0x3d, 0x00},
{0x3e, 0x00},
{0x3f, 0x00},
{0x40, 0x08},
{0x41, 0x88},
{0x42, 0x20},
{0x43, 0x82},
{0x44, 0x03},
{0x45, 0xa0},
{0x46, 0x00},
{0x47, 0x00},
{0x48, 0x01},
{0x49, 0x01},
{0x4a, 0x80},
{0x4b, 0x80},
{0x4c, 0x80},
{0x4d, 0x80},
{0x4e, 0x84},
{0x4f, 0x84},
{0x50, 0x84},
{0x51, 0x84},
{0x52, 0xc0},
{0x53, 0x80},
{0x54, 0x00},
{0x55, 0x00},
{0x56, 0xc0},
{0x57, 0xc0},
{0x58, 0x0b},
{0x59, 0x32},
{0x5a, 0x00},
{0x5b, 0x1f},
{0x5c, 0xc0},
{0x5d, 0x00},
{0x5e, 0xfc},
{0x5f, 0x02},
{0x60, 0x00},
{0x61, 0x00},
{0x62, 0x00},
{0x63, 0x00},
{0x64, 0x00},
{0x65, 0x00},
{0x66, 0x80},
{0x67, 0x00},
{0x68, 0x00},
{0x69, 0x00},
{0x6a, 0xc0},
{0x6b, 0xc0},
{0x6c, 0x00},
{0x6d, 0x00},
{0x6e, 0xc8},
{0x6f, 0x00},
{0x70, 0xd3},
{0x71, 0x90},
{0x72, 0x00},
{0x73, 0x00},
{0x74, 0x88},
{0x75, 0xc1},
{0x76, 0x00},
{0x77, 0x00},
{0x7a, 0x00},
{0x7b, 0x00},
};
static u8 es8396_equalizer_lpf_bt_incall[] = {
0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
0x6D, 0x27, 0x64, 0x09, 0x4C, 0xA3, 0x53, 0x07, 0x6D, 0x27, 0x64, 0x09,
0x8D, 0xE5, 0x23, 0x00, 0x2A, 0xA3, 0x4A, 0x22,
};
struct sp_config {
u8 spc, mmcc, spfs;
u32 srate;
u8 lrcdiv;
u8 sclkdiv;
};
/* codec private data */
struct es8396_private {
struct snd_soc_component *component;
struct sp_config config[3];
struct regmap *regmap;
u8 sysclk[3];
u32 mclk[3];
struct clk *mclk_clock;
/* platform dependent DVDD voltage configuration */
u8 dvdd_pwr_vol;
/* platform dependent CLASS D Mono mode configuration */
bool spkmono;
/* platform dependent earpiece mode configuration */
bool earpiece;
/* platform dependent monon/p differential mode configuration */
bool monoin_differential;
/* platform dependent lout/rout differential mode configuration */
bool lno_differential;
/* platform dependent analog ldo level configuration */
u8 ana_ldo_lvl;
/* platform dependent speaker ldo level configuration */
u8 spk_ldo_lvl;
/* platform dependent mic bias voltage configuration */
u8 mic_bias_lvl;
u8 dmic_amic;
bool jackdet_enable;
u8 gpio_int_pol;
int shutdwn_delay;
int pon_delay;
struct gpio_desc *spk_ctl_gpio;
struct gpio_desc *lineout_ctl_gpio;
bool calibrate;
u8 output_device_selected;
u8 aif1_select;
u8 aif2_select;
/*
* Add a delay work-quenue, to debug DC calibration
*/
struct mutex adc_depop_mlock;
struct delayed_work adc_depop_work;
/* for playback pop noise */
struct mutex pcm_depop_mlock;
struct delayed_work pcm_pop_work;
/* for playback pop noise */
struct mutex pcm_shutdown_depop_mlock;
struct delayed_work pcm_shutdown_depop_work;
/* for voice pop noise */
struct mutex voice_depop_mlock;
struct delayed_work voice_pop_work;
/* for voice pop noise */
struct mutex voice_shutdown_depop_mlock;
struct delayed_work voice_shutdown_depop_work;
/* for hp calibration */
struct mutex init_cali_mlock;
struct delayed_work init_cali_work;
int pcm_pop_work_retry;
};
static bool es8396_valid_micbias(u8 micbias)
{
switch (micbias) {
case MICBIAS_3V:
case MICBIAS_2_8V:
case MICBIAS_2_5V:
case MICBIAS_2_3V:
case MICBIAS_2V:
case MICBIAS_1_5V:
return true;
default:
break;
}
return false;
}
static bool es8396_valid_analdo(u8 ldolvl)
{
switch (ldolvl) {
case ANA_LDO_3V:
case ANA_LDO_2_9V:
case ANA_LDO_2_8V:
case ANA_LDO_2_7V:
case ANA_LDO_2_4V:
case ANA_LDO_2_3V:
case ANA_LDO_2_2V:
case ANA_LDO_2_1V:
return true;
default:
break;
}
return false;
}
static bool es8396_valid_spkldo(u8 ldolvl)
{
switch (ldolvl) {
case SPK_LDO_3_3V:
case SPK_LDO_3_2V:
case SPK_LDO_3V:
case SPK_LDO_2_9V:
case SPK_LDO_2_8V:
case SPK_LDO_2_6V:
case SPK_LDO_2_5V:
case SPK_LDO_2_4V:
return true;
default:
break;
}
return false;
}
static void pcm_shutdown_depop_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
pcm_shutdown_depop_work.work);
struct snd_soc_component *component = es8396->component;
mutex_lock(&es8396->pcm_shutdown_depop_mlock);
snd_soc_component_update_bits(component, ES8396_SDP1_IN_FMT_REG1F,
0x40, 0x40);
es8396->aif1_select &= 0xfe;
mutex_unlock(&es8396->pcm_shutdown_depop_mlock);
}
static void voice_shutdown_depop_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
voice_shutdown_depop_work.work);
struct snd_soc_component *component = es8396->component;
mutex_lock(&es8396->voice_shutdown_depop_mlock);
snd_soc_component_update_bits(component, ES8396_SDP2_IN_FMT_REG22,
0x7F, 0x53);
es8396->aif2_select &= 0xfe;
if (es8396->aif1_select != 0) {
snd_soc_component_write(component, 0x1A, 0x00);
snd_soc_component_write(component, 0x67, 0x00);
snd_soc_component_write(component, 0x69, 0x00);
snd_soc_component_write(component, 0x66, 0x00);
}
mutex_unlock(&es8396->voice_shutdown_depop_mlock);
}
static void init_cali_work_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
init_cali_work.work);
struct snd_soc_component *component = es8396->component;
mutex_lock(&es8396->init_cali_mlock);
pr_debug("init_cali_work_events\n");
if (es8396->pcm_pop_work_retry > 0) {
es8396->pcm_pop_work_retry--;
pr_debug("Enter into %s %d\n", __func__, __LINE__);
snd_soc_component_write(component, ES8396_DAC_OFFSET_CALI_REG6F, 0x83);
if (es8396->pcm_pop_work_retry) {
schedule_delayed_work(&es8396->init_cali_work,
msecs_to_jiffies(100));
}
}
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x3C);
/* use line out */
msleep(100);
snd_soc_component_write(component, 0x4E, 0x80);
snd_soc_component_write(component, 0x4F, 0x81);
snd_soc_component_write(component, 0x4A, 0x60);
snd_soc_component_write(component, 0x4B, 0x60);
mutex_unlock(&es8396->init_cali_mlock);
}
static void voice_pop_work_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
voice_pop_work.work);
struct snd_soc_component *component = es8396->component;
int i;
mutex_lock(&es8396->voice_depop_mlock);
pr_debug("voice_pop_work_events\n");
/*
* set the clock source to pll out
* set divider for voice playback
* set Equalizer
* set DAC source from equalizer
*/
snd_soc_component_update_bits(component, ES8396_SDP2_IN_FMT_REG22,
0x3F, 0x13);
snd_soc_component_update_bits(component, ES8396_SDP2_OUT_FMT_REG23,
0x7F, 0x33);
/* use line out */
snd_soc_component_write(component, 0x4E, 0x80);
snd_soc_component_write(component, 0x4F, 0x81);
snd_soc_component_write(component, 0x4A, 0x60);
snd_soc_component_write(component, 0x4B, 0x60);
snd_soc_component_write(component, 0x1A, 0x40); /* Enable HPOUT */
/* unmute dac */
snd_soc_component_write(component, 0x66, 0x00);
for (i = 0; i < 120; i = i + 2) {
snd_soc_component_write(component, 0x6A, 120 - i);
snd_soc_component_write(component, 0x6B, 120 - i);
usleep_range(100, 200);
}
mutex_unlock(&es8396->voice_depop_mlock);
}
static void pcm_pop_work_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
pcm_pop_work.work);
struct snd_soc_component *component = es8396->component;
int i;
mutex_lock(&es8396->pcm_depop_mlock);
pr_debug("pcm_pop_work_events\n");
snd_soc_component_write(component, ES8396_SYS_VMID_REF_REG71, 0xFC);
/* use line out */
snd_soc_component_write(component, 0x4E, 0x80);
snd_soc_component_write(component, 0x4F, 0x81);
snd_soc_component_write(component, 0x4A, 0x60);
snd_soc_component_write(component, 0x4B, 0x60);
snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0x03, 0x00);
snd_soc_component_update_bits(component, ES8396_SDP1_IN_FMT_REG1F, 0x40, 0x00);
for (i = 0; i < 120; i = i + 2) {
snd_soc_component_write(component, 0x6A, 120 - i);
snd_soc_component_write(component, 0x6B, 120 - i);
usleep_range(100, 200);
}
mutex_unlock(&es8396->pcm_depop_mlock);
}
/*********************************************************************
* to power on/off class d with min pop noise
*********************************************************************/
static int classd_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
unsigned int regv1, regv2, lvl;
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_PRE_PMU: /* prepare power up */
/* power up class d */
pr_debug("SND_SOC_DAPM_PRE_PMU = 0x%x\n", event);
/* read the clock configure */
regv1 = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
regv1 &= 0xcf;
/* enable class d clock */
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, regv1);
/* dac csm startup, dac digital still on */
snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0xFE, 0x00);
/* dac analog power on */
snd_soc_component_update_bits(component, ES8396_DAC_REF_PWR_CTRL_REG6E,
0xff, 0x34);
regv2 = snd_soc_component_read(component, ES8396_SPK_CTRL_1_REG3C);
/* set speaker ldo level */
if (es8396_valid_spkldo(es8396->spk_ldo_lvl) == false) {
pr_err("speaker LDO Level error.\n");
return -EINVAL;
} else {
regv1 = regv2 & 0xD8;
lvl = es8396->spk_ldo_lvl;
lvl &= 0x07;
regv1 |= lvl;
regv1 |= 0x10;
}
if (es8396->spkmono == 1) { /* speaker in mono mode */
regv1 = regv1 | 0x40;
} else {
regv1 = regv1 & 0xbf;
}
snd_soc_component_write(component, ES8396_SPK_CTRL_1_REG3C, regv1);
snd_soc_component_write(component, ES8396_SPK_CTRL_2_REG3D, 0x10);
regv1 = snd_soc_component_read(component, ES8396_SPK_MIXER_REG26);
/* clear pdnspkl_biasgen, clear pdnspkr_biasgen */
regv1 &= 0xee;
snd_soc_component_write(component, ES8396_SPK_MIXER_REG26, regv1);
snd_soc_component_write(component, ES8396_SPK_MIXER_VOL_REG28, 0x33);
snd_soc_component_write(component, ES8396_SPK_CTRL_SRC_REG3A, 0xA9);
/* L&R DAC Vol=-6db */
snd_soc_component_write(component, ES8396_DAC_LDAC_VOL_REG6A, 0x00);
snd_soc_component_write(component, ES8396_DAC_RDAC_VOL_REG6B, 0x00);
regv1 = snd_soc_component_read(component, ES8396_HP_MIXER_BOOST_REG2B);
regv1 &= 0xcc;
snd_soc_component_write(component, ES8396_HP_MIXER_BOOST_REG2B, regv1);
regv1 = snd_soc_component_read(component, ES8396_CPHP_CTRL_3_REG44);
regv1 &= 0xcc;
snd_soc_component_write(component, ES8396_CPHP_CTRL_3_REG44, regv1);
regv1 = snd_soc_component_read(component, ES8396_CPHP_CTRL_1_REG42);
regv1 &= 0xdf;
snd_soc_component_write(component, ES8396_CPHP_CTRL_1_REG42, regv1);
regv1 = snd_soc_component_read(component, ES8396_CPHP_CTRL_2_REG43);
regv1 &= 0x7f;
snd_soc_component_write(component, ES8396_CPHP_CTRL_2_REG43, regv1);
es8396->output_device_selected = 0;
break;
case SND_SOC_DAPM_POST_PMU: /* after power up */
pr_debug("SND_SOC_DAPM_POST_PMU = 0x%x\n", event);
schedule_delayed_work(&es8396->pcm_pop_work,
msecs_to_jiffies(50));
break;
case SND_SOC_DAPM_PRE_PMD: /* prepare power down */
pr_debug("SND_SOC_DAPM_PRE_PMD = 0x%x\n", event);
/* read the clock configure */
regv1 = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
regv1 |= 0x10;
/* stop class d clock */
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, regv1);
/* dac csm startup, dac digital still on */
/* snd_soc_component_update_bits(w->component, ES8396_DAC_CSM_REG66,
0x01, 0x01); */
regv1 = snd_soc_component_read(component, ES8396_SPK_EN_VOL_REG3B);
regv1 &= 0x77;
/* clear enspk_l,enspk_r */
snd_soc_component_write(component, ES8396_SPK_EN_VOL_REG3B, regv1);
regv1 = snd_soc_component_read(component, ES8396_SPK_CTRL_SRC_REG3A);
regv1 |= 0x44; /* set pdnspkl_biasgen, set pdnspkr_biasgen */
snd_soc_component_write(component, ES8396_SPK_CTRL_SRC_REG3A, regv1);
regv1 = snd_soc_component_read(component, ES8396_SPK_MIXER_REG26);
/* clear pdnspkl_biasgen, clear pdnspkr_biasgen */
regv1 |= 0x11;
snd_soc_component_write(component, ES8396_SPK_MIXER_REG26, regv1);
snd_soc_component_update_bits(component, ES8396_SPK_CTRL_1_REG3C, 0x20,
0x20);
break;
case SND_SOC_DAPM_POST_PMD: /* after power down */
pr_debug("SND_SOC_DAPM_POST_PMD = 0x%x\n", event);
break;
default:
break;
}
return 0;
}
static int micbias_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);
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
unsigned int regv;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (es8396_valid_micbias(es8396->mic_bias_lvl) == false) {
pr_err("MIC BIAS Level error.\n");
return -EINVAL;
} else {
regv = es8396->mic_bias_lvl;
regv &= 0x07;
regv = (regv << 4) | 0x08;
/* enable micbias1 */
snd_soc_component_write(component, ES8396_SYS_MICBIAS_CTRL_REG74,
regv);
}
regv = snd_soc_component_read(component, ES8396_ALRCK_GPIO_SEL_REG15);
if (es8396->dmic_amic == MIC_DMIC) {
regv &= 0xf0; /* enable DMIC CLK */
regv |= 0x0A;
} else {
regv &= 0xf0; /* disable DMIC CLK */
}
snd_soc_component_write(component, ES8396_ALRCK_GPIO_SEL_REG15, regv);
break;
case SND_SOC_DAPM_POST_PMD:
regv = snd_soc_component_read(component, ES8396_ALRCK_GPIO_SEL_REG15);
regv &= 0xf0; /* disable DMIC CLK */
snd_soc_component_write(component, ES8396_ALRCK_GPIO_SEL_REG15, regv);
break;
default:
break;
}
return 0;
}
static void adc_depop_work_events(struct work_struct *work)
{
struct es8396_private *es8396 = container_of(work, struct es8396_private,
adc_depop_work.work);
struct snd_soc_component *component = es8396->component;
pr_debug("adc_depop_work_events\n");
mutex_lock(&es8396->adc_depop_mlock);
snd_soc_component_update_bits(component, ES8396_SDP1_OUT_FMT_REG20, 0x40, 0x00);
mutex_unlock(&es8396->adc_depop_mlock);
}
static int adc_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
unsigned int regv;
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
pr_debug("Enter into %s %d\n", __func__, __LINE__);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
pr_debug("Enter into SND_SOC_DAPM_PRE_PMU %s %d\n", __func__,
__LINE__);
snd_soc_component_update_bits(component, ES8396_SDP1_OUT_FMT_REG20, 0x40,
0x40);
/* set adc alc */
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
/* Enable MIC BOOST */
snd_soc_component_write(component, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
/* axMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_AX_MIXER_BOOST_REG2F);
regv |= 0x88;
snd_soc_component_write(component, ES8396_AX_MIXER_BOOST_REG2F, regv);
/* axmixer vol = +12db */
snd_soc_component_write(component, ES8396_AX_MIXER_VOL_REG30, 0xaa);
/* axmixer high driver capacility */
snd_soc_component_write(component, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
/* MNMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_MN_MIXER_BOOST_REG37);
regv |= 0x88;
snd_soc_component_write(component, ES8396_MN_MIXER_BOOST_REG37, regv);
/* mnmixer vol = +12db */
snd_soc_component_write(component, ES8396_MN_MIXER_VOL_REG38, 0x44);
/* mnmixer high driver capacility */
snd_soc_component_write(component, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
msleep(200);
/* ADC STM and Digital Startup, ADC DS Mode */
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x00);
/* force adc stm to normal */
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x40);
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x0);
/* ADC Volume =0db */
snd_soc_component_write(component, ES8396_ADC_LADC_VOL_REG56, 0x0);
snd_soc_component_write(component, ES8396_ADC_RADC_VOL_REG57, 0x0);
snd_soc_component_write(component, ES8396_ADC_CLK_DIV_REG09, 0x04);
schedule_delayed_work(&es8396->adc_depop_work,
msecs_to_jiffies(150));
break;
case SND_SOC_DAPM_PRE_PMD:
pr_debug("Enter into SND_SOC_DAPM_PRE_PMD %s %d\n", __func__,
__LINE__);
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x20);
snd_soc_component_write(component, ES8396_ADC_CLK_DIV_REG09, 0x04);
break;
default:
break;
}
return 0;
}
/*********************************************************************
* to power on/off headphone with min pop noise
********************************************************************/
static int hpamp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
unsigned int regv;
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
pr_debug("Enter into %s %d\n", __func__, __LINE__);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
pr_debug("Enter into %s %d, event = SND_SOC_DAPM_PRE_PMU\n",
__func__, __LINE__);
es8396->output_device_selected = 1;
break;
case SND_SOC_DAPM_POST_PMU:
pr_debug("Enter into %s %d, event = SND_SOC_DAPM_POST_PMU\n",
__func__, __LINE__);
schedule_delayed_work(&es8396->pcm_pop_work,
msecs_to_jiffies(50));
break;
case SND_SOC_DAPM_PRE_PMD:
pr_debug("Enter into %s %d, event = SND_SOC_DAPM_PRE_PMD\n",
__func__, __LINE__);
/* dac analog power down */
snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0x42, 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
pr_debug("Enter into %s %d, event = SND_SOC_DAPM_POST_PMD\n",
__func__, __LINE__);
/* dac analog power down */
snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0x40, 0x40);
/* dac analog power down */
snd_soc_component_update_bits(component, ES8396_DAC_REF_PWR_CTRL_REG6E,
0xC0, 0xC0);
/* read the clock configure */
regv = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
regv |= 0x20;
/* stop charge pump clock */
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, regv);
regv = snd_soc_component_read(component, ES8396_HP_MIXER_BOOST_REG2B);
regv |= 0x11;
snd_soc_component_write(component, ES8396_HP_MIXER_BOOST_REG2B, regv);
break;
default:
break;
}
return 0;
}
/*
* ES8396 Controls
*/
static const DECLARE_TLV_DB_RANGE(mixvol_tlv,
0, 4, TLV_DB_SCALE_ITEM(-1200, 150, 0),
8, 11, TLV_DB_SCALE_ITEM(-600, 150, 0));
static const DECLARE_TLV_DB_RANGE(boost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
1, 3, TLV_DB_SCALE_ITEM(2000, 0, 0));
/* -34.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(vol_tlv, -600, 150, 0);
/* -34.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, 0, 150, 0);
/* -46.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(hp_tlv, -4800, 1200, 0);
/* -16.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -9600, 50, 0);
static const DECLARE_TLV_DB_SCALE(lineout_tlv, -1200, 1200, 0);
/* 0db min scale, 6 db steps, no mute */
static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
/* 0db min scalem 0.75db steps, no mute */
static const DECLARE_TLV_DB_SCALE(vdac_tlv, -9600, 50, 0);
static const char *const alc_func_txt[] = { "Off", "LOn", "ROn", "StereoOn" };
static const struct soc_enum alc_func =
SOC_ENUM_SINGLE(ES8396_ADC_ALC_CTRL_1_REG58, 6, 4, alc_func_txt);
/*
*define the line in,mic in, phone in ,and aif1-2 in volume/switch
*/
static const struct snd_kcontrol_new es8396_snd_controls[] = {
SOC_DOUBLE_R_TLV("DAC Playback Volume",
ES8396_DAC_LDAC_VOL_REG6A, ES8396_DAC_RDAC_VOL_REG6B,
0, 127, 1, vdac_tlv),
SOC_DOUBLE_TLV("MNIN MIXER Volume",
ES8396_MN_MIXER_VOL_REG38, 4, 0, 3, 1, mixvol_tlv),
SOC_DOUBLE_TLV("LIN MIXER Volume",
ES8396_LN_MIXER_VOL_REG34, 4, 0, 4, 0, mixvol_tlv),
SOC_DOUBLE_TLV("AXIN MIXER Volume",
ES8396_AX_MIXER_VOL_REG30, 4, 0, 4, 0, mixvol_tlv),
SOC_DOUBLE_TLV("Mic Boost Volume",
ES8396_ADC_MICBOOST_REG60, 4, 0, 3, 0, boost_tlv),
SOC_DOUBLE_R_TLV("ADC Capture Volume",
ES8396_ADC_LADC_VOL_REG56, ES8396_ADC_RADC_VOL_REG57,
0, 127, 1, adc_rec_tlv),
SOC_SINGLE_TLV("Speakerl Playback Volume",
ES8396_SPK_EN_VOL_REG3B, 4, 7, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Speakerr Playback Volume",
ES8396_SPK_EN_VOL_REG3B, 0, 7, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Headphonel Playback Volume",
ES8396_CPHP_ICAL_VOL_REG41, 4, 3, 1, hp_tlv),
SOC_SINGLE_TLV("Headphoner Playback Volume",
ES8396_CPHP_ICAL_VOL_REG41, 0, 3, 1, hp_tlv),
/*
* lineout playback volume
*/
SOC_SINGLE_TLV("Lineoutp Playback Volume",
ES8396_LNOUT_LO1_GAIN_CTRL_REG4E, 5, 1, 1, lineout_tlv),
SOC_SINGLE_TLV("Lineoutn Playback Volume",
ES8396_LNOUT_RO1_GAIN_CTRL_REG4F, 5, 1, 1, lineout_tlv),
/*
* monoout playback volume
*/
SOC_SINGLE_TLV("Monooutp Playback Volume",
ES8396_MONOHP_P_BOOST_MUTE_REG48, 3, 1, 1, lineout_tlv),
SOC_SINGLE_TLV("Monooutn Playback Volume",
ES8396_MONOHP_N_BOOST_MUTE_REG49, 3, 1, 1, lineout_tlv),
SOC_ENUM("ALC Capture Function", alc_func),
};
/*
* DAPM Controls
*/
static const struct snd_kcontrol_new es8396_dac_controls =
SOC_DAPM_SINGLE("Switch", ES8396_DAC_CSM_REG66, 3, 1, 1);
static const struct snd_kcontrol_new hp_amp_ctl =
SOC_DAPM_SINGLE("Switch", ES8396_CP_CLK_DIV_REG0B, 1, 1, 1);
static const struct snd_kcontrol_new es8396_hpl_mixer_controls[] = {
SOC_DAPM_SINGLE("LNMUX2HPMIX_L Switch", ES8396_HP_MIXER_REG2A, 6, 1, 0),
SOC_DAPM_SINGLE("AXMUX2HPMIX_L Switch", ES8396_HP_MIXER_REG2A, 5, 1, 0),
SOC_DAPM_SINGLE("DACL2HPMIX Switch", ES8396_HP_MIXER_REF_LP_REG2D,
5, 1, 0),
};
static const struct snd_kcontrol_new es8396_hpr_mixer_controls[] = {
SOC_DAPM_SINGLE("LNMUX2HPMIX_R Switch", ES8396_HP_MIXER_REG2A, 2, 1, 0),
SOC_DAPM_SINGLE("AXMUX2HPMIX_R Switch", ES8396_HP_MIXER_REG2A, 1, 1, 0),
SOC_DAPM_SINGLE("DACR2HPMIX Switch", ES8396_HP_MIXER_REF_LP_REG2D,
4, 1, 0),
};
/*
* Only used mono out p mixer for differential output
*/
static const struct snd_kcontrol_new es8396_mono_p_mixer_controls[] = {
SOC_DAPM_SINGLE("LHPMIX2MNMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 7,
1, 0),
SOC_DAPM_SINGLE("RHPMIX2MNOMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 6,
1, 0),
SOC_DAPM_SINGLE("RMNMIX2MNOMIXP Switch", ES8396_MONOHP_P_MIXER_REG47, 5,
1, 0),
SOC_DAPM_SINGLE("RAXMIX2MNOMIXP Switch",
ES8396_MONOHP_P_MIXER_REG47, 4, 1, 0),
SOC_DAPM_SINGLE("LLNMIX2MNOMIXP Switch",
ES8396_MONOHP_P_MIXER_REG47, 3, 1, 0),
};
static const struct snd_kcontrol_new es8396_mono_n_mixer_controls[] = {
SOC_DAPM_SINGLE("LMNMIX2MNMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 7,
1, 0),
SOC_DAPM_SINGLE("RHPMIX2MNOMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 6,
1, 0),
SOC_DAPM_SINGLE("MOPINV2MNOMIXN Switch", ES8396_MONOHP_N_MIXER_REG46, 5,
1, 0),
SOC_DAPM_SINGLE("LLNMIX2MNOMIXN Switch",
ES8396_MONOHP_N_MIXER_REG46, 4, 1, 0),
SOC_DAPM_SINGLE("LAXMIX2MNOMIXN Switch",
ES8396_MONOHP_N_MIXER_REG46, 3, 1, 0),
};
/*
* define the stereo class d speaker mixer
*/
static const struct snd_kcontrol_new es8396_speaker_lmixer_controls[] = {
SOC_DAPM_SINGLE("LLNMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 6, 1,
0),
SOC_DAPM_SINGLE("LAXMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 5, 1,
0),
SOC_DAPM_SINGLE("LDAC2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 7, 1, 0),
};
static const struct snd_kcontrol_new es8396_speaker_rmixer_controls[] = {
SOC_DAPM_SINGLE("RLNMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 2, 1,
0),
SOC_DAPM_SINGLE("RAXMUX2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 1, 1,
0),
SOC_DAPM_SINGLE("RDAC2SPKMIX Switch", ES8396_SPK_MIXER_REG26, 3, 1, 0),
};
/*
* Only used line out1 p mixer for differential output
*/
static const struct snd_kcontrol_new es8396_lout1_mixer_controls[] = {
SOC_DAPM_SINGLE("LDAC2LO1MIXP Switch", SND_SOC_NOPM,
5, 1, 0),
SOC_DAPM_SINGLE("LAXMIX2LO1MIXP Switch",
ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 4, 1, 0),
SOC_DAPM_SINGLE("LLNMIX2LO1MIXP Switch",
ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 3, 1, 0),
SOC_DAPM_SINGLE("LMNMIX2LO1MIXP Switch",
ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 2, 1, 0),
SOC_DAPM_SINGLE("RO1INV2LO1MIXP Switch",
ES8396_LNOUT_LO1EN_LO1MIX_REG4A, 1, 1, 0),
};
static const struct snd_kcontrol_new es8396_rout1_mixer_controls[] = {
SOC_DAPM_SINGLE("RDAC2RO1MIXN Switch", SND_SOC_NOPM,
5, 1, 0),
SOC_DAPM_SINGLE("RAXMIX2RO1MIXN Switch",
ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 4, 1, 0),
SOC_DAPM_SINGLE("RLNMIX2RO1MIXN Switch",
ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 3, 1, 0),
SOC_DAPM_SINGLE("RMNMIX2RO1MIXN Switch",
ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 2, 1, 0),
SOC_DAPM_SINGLE("LO1INV2RO1MIXN Switch",
ES8396_LNOUT_RO1EN_RO1MIX_REG4B, 1, 1, 0),
};
/*
*left LNMIX mixer
*/
static const struct snd_kcontrol_new es8396_lnmix_l_mixer_controls[] = {
SOC_DAPM_SINGLE("AINL2LLNMIX Switch", ES8396_LN_MIXER_REG32, 7, 1, 0),
SOC_DAPM_SINGLE("LLNMUX2LLNMIX Switch", ES8396_LN_MIXER_REG32, 6, 1, 0),
SOC_DAPM_SINGLE("MIC1P2LLNMIX Switch", ES8396_LN_MIXER_REG32, 5, 1, 0),
SOC_DAPM_SINGLE("PMICDSE2LLNMIX Switch", ES8396_LN_MIXER_REG32, 4, 1, 0),
};
/*
*right LNMIX mixer
*/
static const struct snd_kcontrol_new es8396_lnmix_r_mixer_controls[] = {
SOC_DAPM_SINGLE("AINR2RLNMIX Switch", ES8396_LN_MIXER_REG32, 3, 1, 0),
SOC_DAPM_SINGLE("RLNMUX2RLNMIX Switch", ES8396_LN_MIXER_REG32, 2, 1, 0),
SOC_DAPM_SINGLE("MIC1N2LLNMIX Switch", ES8396_LN_MIXER_REG32, 1, 1, 0),
SOC_DAPM_SINGLE("NMICDSE2RLNMIX Switch", ES8396_LN_MIXER_REG32, 0, 1, 0),
};
/*
*left AXMIX mixer
*/
static const struct snd_kcontrol_new es8396_axmix_l_mixer_controls[] = {
SOC_DAPM_SINGLE("LAXMUX2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 7, 1, 0),
SOC_DAPM_SINGLE("MONOP2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 6, 1, 0),
SOC_DAPM_SINGLE("MIC2P2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 5, 1, 0),
SOC_DAPM_SINGLE("PMICDSE2LAXMIX Switch", ES8396_AX_MIXER_REG2E, 4, 1, 0),
};
/*
*right AXMIX mixer
*/
static const struct snd_kcontrol_new es8396_axmix_r_mixer_controls[] = {
SOC_DAPM_SINGLE("RAXMUX2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 3, 1, 0),
SOC_DAPM_SINGLE("MONON2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 2, 1, 0),
SOC_DAPM_SINGLE("MIC2N2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 1, 1, 0),
SOC_DAPM_SINGLE("NMICDSE2RAXMIX Switch", ES8396_AX_MIXER_REG2E, 0, 1, 0),
};
/*
*left MNMIX mixer
*/
static const struct snd_kcontrol_new es8396_mnmix_l_mixer_controls[] = {
SOC_DAPM_SINGLE("LDAC2LMNMIX Switch", ES8396_MN_MIXER_REG36, 7, 1, 0),
SOC_DAPM_SINGLE("MONOP2LMNMIX Switch", ES8396_MN_MIXER_REG36, 6, 1, 0),
SOC_DAPM_SINGLE("AINL2LMNMIX Switch", ES8396_MN_MIXER_REG36, 5, 1, 0),
};
/*
*right MNMIX mixer
*/
static const struct snd_kcontrol_new es8396_mnmix_r_mixer_controls[] = {
SOC_DAPM_SINGLE("RDAC2RMNMIX Switch", ES8396_MN_MIXER_REG36, 3, 1, 0),
SOC_DAPM_SINGLE("MONON2RMNMIX Switch", ES8396_MN_MIXER_REG36, 2, 1, 0),
SOC_DAPM_SINGLE("AINR2RMNMIX Switch", ES8396_MN_MIXER_REG36, 1, 1, 0),
};
/*
* Left Record Mixer
*/
static const struct snd_kcontrol_new es8396_capture_l_mixer_controls[] = {
SOC_DAPM_SINGLE("RLNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 7, 1, 0),
SOC_DAPM_SINGLE("RAXMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 6, 1, 0),
SOC_DAPM_SINGLE("RMNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 5, 1, 0),
SOC_DAPM_SINGLE("LMNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 4, 1, 0),
SOC_DAPM_SINGLE("LLNMIX2LPGA Switch", ES8396_ADC_LPGA_MIXER_REG62, 3, 1, 0),
};
/*
* Right Record Mixer
*/
static const struct snd_kcontrol_new es8396_capture_r_mixer_controls[] = {
SOC_DAPM_SINGLE("RLNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 7, 1, 0),
SOC_DAPM_SINGLE("RAXMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 6, 1, 0),
SOC_DAPM_SINGLE("RMNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 5, 1, 0),
SOC_DAPM_SINGLE("LMNMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 4, 1, 0),
SOC_DAPM_SINGLE("LAXMIX2RPGA Switch", ES8396_ADC_RPGA_MIXER_REG63, 3, 1, 0),
};
static const struct snd_kcontrol_new es8396_adc_controls =
SOC_DAPM_SINGLE("Switch", ES8396_ADC_CSM_REG53, 6, 1, 1);
/*
* MIC INPUT MUX
*/
static const struct snd_kcontrol_new es8396_micin_mux_controls =
SOC_DAPM_SINGLE("Switch", ES8396_SYS_MIC_IBIAS_EN_REG75, 1, 1, 0);
/*
* left LN MUX
*/
static const char *const es8396_left_lnmux_txt[] = {
"NO IN",
"RPGAP",
"LPGAP",
"MONOP",
"AINL"
};
static const unsigned int es8396_left_lnmux_values[] = {
0, 1, 2, 4, 8
};
static const struct soc_enum es8396_left_lnmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_ADC_LN_MUX_REG64, 0, 15,
ARRAY_SIZE(es8396_left_lnmux_txt),
es8396_left_lnmux_txt,
es8396_left_lnmux_values);
static const struct snd_kcontrol_new es8396_left_lnmux_controls =
SOC_DAPM_ENUM("Route", es8396_left_lnmux_enum);
/*
* Right LN MUX
*/
static const char *const es8396_right_lnmux_txt[] = {
"NO IN",
"RPGAP",
"LPGAP",
"MONON",
"AINR"
};
static const struct soc_enum es8396_right_lnmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_ADC_LN_MUX_REG64, 4, 15,
ARRAY_SIZE(es8396_right_lnmux_txt),
es8396_right_lnmux_txt,
es8396_left_lnmux_values);
static const struct snd_kcontrol_new es8396_right_lnmux_controls =
SOC_DAPM_ENUM("Route", es8396_right_lnmux_enum);
/*
* left AX MUX
*/
static const struct soc_enum es8396_left_axmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_ADC_AX_MUX_REG65, 0, 15,
ARRAY_SIZE(es8396_left_lnmux_txt),
es8396_left_lnmux_txt,
es8396_left_lnmux_values);
static const struct snd_kcontrol_new es8396_left_axmux_controls =
SOC_DAPM_ENUM("Route", es8396_left_axmux_enum);
/*
* Right AX MUX
*/
static const struct soc_enum es8396_right_axmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_ADC_AX_MUX_REG65, 4, 15,
ARRAY_SIZE(es8396_right_lnmux_txt),
es8396_right_lnmux_txt,
es8396_left_lnmux_values);
static const struct snd_kcontrol_new es8396_right_axmux_controls =
SOC_DAPM_ENUM("Route", es8396_right_axmux_enum);
/*
* Left SPKOUT MUX
*/
static const char *const es8396_left_spkout_mux_txt[] = {
"NO Out",
"SPKR Route",
"SPKL Route"
};
static const unsigned int es8396_left_spkout_mux_values[] = {
0, 1, 2
};
static const struct soc_enum es8396_left_spkout_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_SPK_CTRL_SRC_REG3A, 4, 3,
ARRAY_SIZE(es8396_left_spkout_mux_txt),
es8396_left_spkout_mux_txt,
es8396_left_spkout_mux_values);
static const struct snd_kcontrol_new es8396_left_spkout_mux_controls =
SOC_DAPM_ENUM("Route", es8396_left_spkout_mux_enum);
/*
* Right SPKOUT MUX
*/
static const struct soc_enum es8396_right_spkout_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_SPK_CTRL_SRC_REG3A, 0, 3,
ARRAY_SIZE(es8396_left_spkout_mux_txt),
es8396_left_spkout_mux_txt,
es8396_left_spkout_mux_values);
static const struct snd_kcontrol_new es8396_right_spkout_mux_controls =
SOC_DAPM_ENUM("Route", es8396_right_spkout_mux_enum);
/*
* SPKLDO POWER SWITCH
*/
static const struct snd_kcontrol_new es8396_spkldo_pwrswitch_controls =
SOC_DAPM_SINGLE("Switch", ES8396_DAMP_CLK_DIV_REG0C, 1, 1, 1);
/*
* Dmic MUX
*/
static const char *const es8396_dmic_mux_txt[] = {
/* 0 can be used for stereo amic */
"dmic disable,use adc",
"ldata use ladc,rdata use ldmic at low clk",
"ldata use ladc,rdata use rdmic at low clk",
"ldata use ladc,rdata use rdmic at high clk",
"ldata use ldmic at high clk,rdata use radc",
"ldata use ldmic at high clk,rdata use ldmic at low clk",
/* can be used for stereo dmic */
"ldata use ldmic at high clk,rdata use rdmic at low clk",
"ldata use ldmic at high clk,rdata use rdmic at high clk",
"ldata use rdmic at high clk,rdata use radc",
/* can be used for stereo dmic */
"ldata use rdmic at high clk,rdata use ldmic at low clk",
"ldata use rdmic at high clk,rdata use rdmic at low clk",
"ldata use rdmic at high clk,rdata use rdmic at high clk",
"ldata use ldmic at low clk,rdata use radc",
"ldata use ldmic at low clk,rdata use ldmic at low clk",
"ldata use ldmic at low clk,rdata use rdmic at low clk",
/* can be used for stereo dmic */
"ldata use ldmic at low clk,rdata use rdmic at high clk",
};
static const unsigned int es8396_dmic_mux_values[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
static const struct soc_enum es8396_dmic_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_ADC_DMIC_RAMPRATE_REG54, 4, 15,
ARRAY_SIZE(es8396_dmic_mux_txt),
es8396_dmic_mux_txt,
es8396_dmic_mux_values);
static const struct snd_kcontrol_new es8396_dmic_mux_controls =
SOC_DAPM_ENUM("Route", es8396_dmic_mux_enum);
/*
* Digital mixer1 left
*/
static const char *const es8396_left_digital_mixer_txt[] = {
"left SDP1 in",
"left SDP2 in",
"left SDP3 in",
"left ADC out",
"right SDP1 in",
"right SDP2 in",
"right SDP3 in",
"right ADC out"
};
static const unsigned int es8396_left_digital_mixer_values[] = {
0, 1, 2, 3, 4, 5, 6, 7
};
static const struct soc_enum es8396_left_digital_mixer_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_1_REG18, 4, 15,
ARRAY_SIZE(es8396_left_digital_mixer_txt),
es8396_left_digital_mixer_txt,
es8396_left_digital_mixer_values);
static const struct snd_kcontrol_new es8396_left_digital_mixer_controls =
SOC_DAPM_ENUM("Route", es8396_left_digital_mixer_enum);
/*
* Digital mixer1 right
*/
static const char *const es8396_right_digital_mixer_txt[] = {
"right SDP1 in",
"right SDP2 in",
"right SDP3 in",
"right ADC out",
"left SDP1 in",
"left SDP2 in",
"left SDP3 in",
"left ADC out"
};
static const struct soc_enum es8396_right_digital_mixer_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_1_REG18, 0, 15,
ARRAY_SIZE(es8396_right_digital_mixer_txt),
es8396_right_digital_mixer_txt,
es8396_left_digital_mixer_values);
static const struct snd_kcontrol_new es8396_right_digital_mixer_controls =
SOC_DAPM_ENUM("Route", es8396_right_digital_mixer_enum);
/*
* Digital mixer2 left
*/
static const struct soc_enum es8396_left_digital2_mixer_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_2_REG19, 4, 15,
ARRAY_SIZE(es8396_left_digital_mixer_txt),
es8396_left_digital_mixer_txt,
es8396_left_digital_mixer_values);
static const struct snd_kcontrol_new es8396_left_digital2_mixer_controls =
SOC_DAPM_ENUM("Route", es8396_left_digital2_mixer_enum);
/*
* Digital mixer2 right
*/
static const struct soc_enum es8396_right_digital2_mixer_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DMIX_SRC_2_REG19, 0, 15,
ARRAY_SIZE(es8396_right_digital_mixer_txt),
es8396_right_digital_mixer_txt,
es8396_left_digital_mixer_values);
static const struct snd_kcontrol_new es8396_right_digital2_mixer_controls =
SOC_DAPM_ENUM("Route", es8396_right_digital2_mixer_enum);
/*
* equalizer clk mux
*/
static const char *const es8396_eq_clk_mux_txt[] = {
"from dac mclk",
"from adc mclk",
"from clk1",
"from clk2"
};
static const unsigned int es8396_eq_clk_mux_values[] = {
0, 1, 2, 3
};
static const struct soc_enum es8396_eq_clk_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_EQ_CLK_OSR_SEL_REG1C, 4, 3,
ARRAY_SIZE(es8396_eq_clk_mux_txt),
es8396_eq_clk_mux_txt,
es8396_eq_clk_mux_values);
static const struct snd_kcontrol_new es8396_eq_clk_mux_controls =
SOC_DAPM_ENUM("Route", es8396_eq_clk_mux_enum);
/*
* equalizer osr mux
*/
static const char *const es8396_eq_osr_mux_txt[] = {
"1FS OSR",
"2FS OSR",
"3FS OSR",
"4FS OSR",
"5FS OSR",
"6FS OSR"
};
static const unsigned int es8396_eq_osr_mux_values[] = {
0, 1, 2, 3, 4, 5
};
static const struct soc_enum es8396_eq_osr_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_EQ_CLK_OSR_SEL_REG1C, 0, 7,
ARRAY_SIZE(es8396_eq_osr_mux_txt),
es8396_eq_osr_mux_txt,
es8396_eq_osr_mux_values);
static const struct snd_kcontrol_new es8396_eq_osr_mux_controls =
SOC_DAPM_ENUM("Route", es8396_eq_osr_mux_enum);
/*
* DAC source mux
*/
static const char *const es8396_dac_src_mux_txt[] = {
"SDP1 in",
"SDP2 in",
"SDP3 in",
"ADC out",
"EQ stereo",
"EQ left",
"EQ right",
};
static const unsigned int es8396_dac_src_mux_values[] = {
0, 1, 2, 3, 4, 5, 6
};
static const struct soc_enum es8396_dac_src_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DAC_SRC_SDP1O_SRC_REG1A, 4, 7,
ARRAY_SIZE(es8396_dac_src_mux_txt),
es8396_dac_src_mux_txt,
es8396_dac_src_mux_values);
static const struct snd_kcontrol_new es8396_dac_src_mux_controls =
SOC_DAPM_ENUM("Route", es8396_dac_src_mux_enum);
/*
* I2S1 out mux
*/
static const char *const es8396_i2s1_out_mux_txt[] = {
"ADC out",
"SDP1 in",
"SDP2 in",
"SDP3 in",
"EQ stereo",
"EQ left",
"EQ right",
};
static const unsigned int es8396_i2s1_out_mux_values[] = {
0, 1, 2, 3, 4, 5, 6
};
static const struct soc_enum es8396_i2s1_out_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_DAC_SRC_SDP1O_SRC_REG1A, 0, 7,
ARRAY_SIZE(es8396_i2s1_out_mux_txt),
es8396_i2s1_out_mux_txt,
es8396_i2s1_out_mux_values);
static const struct snd_kcontrol_new es8396_i2s1_out_mux_controls =
SOC_DAPM_ENUM("Route", es8396_i2s1_out_mux_enum);
/*
* I2S2 out mux
*/
static const struct soc_enum es8396_i2s2_out_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_SDP2O_SDP3O_SRC_REG1B, 4, 7,
ARRAY_SIZE(es8396_i2s1_out_mux_txt),
es8396_i2s1_out_mux_txt,
es8396_i2s1_out_mux_values);
static const struct snd_kcontrol_new es8396_i2s2_out_mux_controls =
SOC_DAPM_ENUM("Route", es8396_i2s2_out_mux_enum);
/*
* I2S3 out mux
*/
static const struct soc_enum es8396_i2s3_out_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8396_SDP2O_SDP3O_SRC_REG1B, 0, 7,
ARRAY_SIZE(es8396_i2s1_out_mux_txt),
es8396_i2s1_out_mux_txt,
es8396_i2s1_out_mux_values);
static const struct snd_kcontrol_new es8396_i2s3_out_mux_controls =
SOC_DAPM_ENUM("Route", es8396_i2s3_out_mux_enum);
static const struct snd_soc_dapm_widget es8396_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("DMIC"),
SND_SOC_DAPM_INPUT("LINP"),
SND_SOC_DAPM_INPUT("RINN"),
SND_SOC_DAPM_INPUT("MONOINP"),
SND_SOC_DAPM_INPUT("MONOINN"),
SND_SOC_DAPM_INPUT("AINL"),
SND_SOC_DAPM_INPUT("AINR"),
SND_SOC_DAPM_INPUT("MIC"),
SND_SOC_DAPM_SUPPLY("MIC Bias", SND_SOC_NOPM, 0, 0,
micbias_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/*
* AIF OUT AND MUX
*/
SND_SOC_DAPM_AIF_OUT("VOICESDPOL", "SDP1 Capture", 0,
ES8396_SDP1_OUT_FMT_REG20, 6, 1),
SND_SOC_DAPM_AIF_OUT("VOICESDPOR", "SDP1 Capture", 0,
ES8396_SDP1_OUT_FMT_REG20, 6, 1),
SND_SOC_DAPM_MUX("VOICESDPO Mux", SND_SOC_NOPM, 0, 0, &es8396_i2s1_out_mux_controls),
SND_SOC_DAPM_AIF_OUT("MASTERSDPOL", "SDP2 Capture", 0,
ES8396_SDP2_OUT_FMT_REG23, 6, 1),
SND_SOC_DAPM_AIF_OUT("MASTERSDPOR", "SDP2 Capture", 0,
ES8396_SDP2_OUT_FMT_REG23, 6, 1),
SND_SOC_DAPM_MUX("MASTERSDPO Mux", SND_SOC_NOPM, 0, 0,
&es8396_i2s2_out_mux_controls),
SND_SOC_DAPM_AIF_OUT("AUXSDPOL", "SDP3 Capture", 0,
ES8396_SDP3_OUT_FMT_REG25, 6, 1),
SND_SOC_DAPM_AIF_OUT("AUXSDPOR", "SDP3 Capture", 0,
ES8396_SDP3_OUT_FMT_REG25, 6, 1),
SND_SOC_DAPM_MUX("AUXSDPO Mux", SND_SOC_NOPM, 0, 0,
&es8396_i2s3_out_mux_controls),
SND_SOC_DAPM_MIXER("VOICEOUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("MASTEROUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("AUXOUT AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
/* capature */
/*
*left and right mixer
*/
SND_SOC_DAPM_MIXER_NAMED_CTL("PGA Left Mix", SND_SOC_NOPM, 0, 0,
&es8396_capture_l_mixer_controls[0],
ARRAY_SIZE
(es8396_capture_l_mixer_controls)),
SND_SOC_DAPM_MIXER_NAMED_CTL("PGA Right Mix", SND_SOC_NOPM, 0, 0,
&es8396_capture_r_mixer_controls[0],
ARRAY_SIZE
(es8396_capture_r_mixer_controls)),
SND_SOC_DAPM_PGA("LPGA P", ES8396_ADC_ANALOG_CTRL_REG5E, 4, 1, NULL, 0),
SND_SOC_DAPM_PGA("RPGA P", ES8396_ADC_ANALOG_CTRL_REG5E, 5, 1, NULL, 0),
SND_SOC_DAPM_ADC("ADC Left", NULL, ES8396_ADC_ANALOG_CTRL_REG5E, 2, 1),
SND_SOC_DAPM_ADC("ADC Right", NULL, ES8396_ADC_ANALOG_CTRL_REG5E, 3, 1),
SND_SOC_DAPM_SWITCH_E("ADC_1", SND_SOC_NOPM, 0, 0,
&es8396_adc_controls, adc_event,
SND_SOC_DAPM_PRE_PMD),
/*
* Analog MIC Muxes
*/
SND_SOC_DAPM_SWITCH("AMIC Mux", ES8396_SYS_MIC_IBIAS_EN_REG75, 0, 1,
&es8396_micin_mux_controls),
SND_SOC_DAPM_PGA("MIC BOOST", SND_SOC_NOPM, 0, 0, NULL, 0),
/* LN,AX Muxes */
/*
* LN MUX
*/
SND_SOC_DAPM_MUX("LLN Mux", SND_SOC_NOPM, 0, 0,
&es8396_left_lnmux_controls),
SND_SOC_DAPM_MUX("RLN Mux", SND_SOC_NOPM, 0, 0,
&es8396_right_lnmux_controls),
/*
* AX MUX
*/
SND_SOC_DAPM_MUX("LAX Mux", SND_SOC_NOPM, 0, 0,
&es8396_left_axmux_controls),
SND_SOC_DAPM_MUX("RAX Mux", SND_SOC_NOPM, 0, 0,
&es8396_right_axmux_controls),
/*
* AIF IN
*/
SND_SOC_DAPM_AIF_IN("VOICESDPIL", "SDP1 Playback", 0,
ES8396_SDP1_IN_FMT_REG1F, 6, 1),
SND_SOC_DAPM_AIF_IN("VOICESDPIR", "SDP1 Playback", 0,
ES8396_SDP1_IN_FMT_REG1F, 6, 1),
SND_SOC_DAPM_AIF_IN("MASTERSDPIL", "SDP2 Playback", 0,
SND_SOC_NOPM, 6, 1),
SND_SOC_DAPM_AIF_IN("MASTERSDPIR", "SDP2 Playback", 0,
SND_SOC_NOPM, 6, 1),
SND_SOC_DAPM_AIF_IN("AUXSDPIL", "SDP3 Playback", 0,
ES8396_SDP3_IN_FMT_REG24, 6, 1),
SND_SOC_DAPM_AIF_IN("AUXSDPIR", "SDP3 Playback", 0,
ES8396_SDP3_IN_FMT_REG24, 6, 1),
SND_SOC_DAPM_MIXER("VOICEIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("MASTERIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("AUXIN AIF Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
/*
* Digital mixer1,2
*/
SND_SOC_DAPM_MUX("LDMIX1 Mux", SND_SOC_NOPM, 0, 0,
&es8396_left_digital_mixer_controls),
SND_SOC_DAPM_MUX("RDMIX1 Mux", SND_SOC_NOPM, 0, 0,
&es8396_right_digital_mixer_controls),
SND_SOC_DAPM_MUX("LDMIX2 Mux", SND_SOC_NOPM, 0, 0,
&es8396_left_digital2_mixer_controls),
SND_SOC_DAPM_MUX("RDMIX2 Mux", SND_SOC_NOPM, 0, 0,
&es8396_right_digital2_mixer_controls),
SND_SOC_DAPM_MIXER("Digital Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("Digital Right Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("Equalizer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("DACSRC Mux", SND_SOC_NOPM, 0, 0,
&es8396_dac_src_mux_controls),
/*
* DAC
*/
SND_SOC_DAPM_SWITCH("DAC_1", SND_SOC_NOPM, 0, 0,
&es8396_dac_controls),
SND_SOC_DAPM_DAC("Left DAC", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("Right DAC", NULL, SND_SOC_NOPM, 0, 0),
/*
* mixerMono
*/
SND_SOC_DAPM_MIXER("LMONIN Mix", ES8396_MN_MIXER_BOOST_REG37, 4, 1,
&es8396_mnmix_l_mixer_controls[0],
ARRAY_SIZE(es8396_mnmix_l_mixer_controls)),
SND_SOC_DAPM_PGA("LMONINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RMONIN Mix", ES8396_MN_MIXER_BOOST_REG37, 0, 1,
&es8396_mnmix_r_mixer_controls[0],
ARRAY_SIZE(es8396_mnmix_r_mixer_controls)),
SND_SOC_DAPM_PGA("RMONINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
/*
* mixerLN
*/
SND_SOC_DAPM_MIXER("LLNIN Mix", ES8396_LN_MIXER_BOOST_REG33, 4, 1,
&es8396_lnmix_l_mixer_controls[0],
ARRAY_SIZE(es8396_lnmix_l_mixer_controls)),
SND_SOC_DAPM_PGA("LLNINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RLNIN Mix", ES8396_LN_MIXER_BOOST_REG33, 0, 1,
&es8396_lnmix_r_mixer_controls[0],
ARRAY_SIZE(es8396_lnmix_r_mixer_controls)),
SND_SOC_DAPM_PGA("RLNINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
/*
* mixerAX
*/
SND_SOC_DAPM_MIXER("LAXIN Mix", ES8396_AX_MIXER_BOOST_REG2F, 4, 1,
&es8396_axmix_l_mixer_controls[0],
ARRAY_SIZE(es8396_axmix_l_mixer_controls)),
SND_SOC_DAPM_PGA("LAXINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RAXIN Mix", ES8396_AX_MIXER_BOOST_REG2F, 0, 1,
&es8396_axmix_r_mixer_controls[0],
ARRAY_SIZE(es8396_axmix_r_mixer_controls)),
SND_SOC_DAPM_PGA("RAXINMIX PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
/*
* mixerLNOUT
*/
SND_SOC_DAPM_MIXER("LOUT1 Mix", SND_SOC_NOPM, 0, 0,
&es8396_lout1_mixer_controls[0],
ARRAY_SIZE(es8396_lout1_mixer_controls)),
SND_SOC_DAPM_PGA("LNOUTMIX1 PGA", SND_SOC_NOPM, 6, 0,
NULL, 0),
SND_SOC_DAPM_MIXER("ROUT1 Mix", SND_SOC_NOPM, 0, 0,
&es8396_rout1_mixer_controls[0],
ARRAY_SIZE(es8396_rout1_mixer_controls)),
SND_SOC_DAPM_PGA("RNOUTMIX1 PGA", SND_SOC_NOPM, 6, 0,
NULL, 0),
/*
* mixerMNOUT
*/
SND_SOC_DAPM_MIXER("MNOUTP Mix", SND_SOC_NOPM, 0, 0,
&es8396_mono_p_mixer_controls[0],
ARRAY_SIZE(es8396_mono_p_mixer_controls)),
SND_SOC_DAPM_PGA("MNOUTP PGA", ES8396_MONOHP_P_BOOST_MUTE_REG48, 7, 0,
NULL, 0),
SND_SOC_DAPM_MIXER("MNOUTN Mix", SND_SOC_NOPM, 0, 0,
&es8396_mono_n_mixer_controls[0],
ARRAY_SIZE(es8396_mono_n_mixer_controls)),
SND_SOC_DAPM_PGA("MNOUTN PGA", ES8396_MONOHP_N_BOOST_MUTE_REG49, 7, 0,
NULL, 0),
/*
* mixerHP
*/
/*
* SND_SOC_DAPM_MIXER("HPL Mix", ES8396_HP_MIXER_BOOST_REG2B, 4, 1,
*/
SND_SOC_DAPM_MIXER("HPL Mix", SND_SOC_NOPM, 6, 0,
&es8396_hpl_mixer_controls[0],
ARRAY_SIZE(es8396_hpl_mixer_controls)),
/*
* SND_SOC_DAPM_MIXER("HPR Mix", ES8396_HP_MIXER_BOOST_REG2B, 0, 1,
*/
SND_SOC_DAPM_MIXER("HPR Mix", SND_SOC_NOPM, 2, 0,
&es8396_hpr_mixer_controls[0],
ARRAY_SIZE(es8396_hpr_mixer_controls)),
SND_SOC_DAPM_SWITCH_E("HP Amp", SND_SOC_NOPM, 0, 0,
&hp_amp_ctl, hpamp_event,
SND_SOC_DAPM_PRE_PMU),
/*
* mixerSPK
*/
SND_SOC_DAPM_MIXER("SPKL Mix", SND_SOC_NOPM, 0, 0,
&es8396_speaker_lmixer_controls[0],
ARRAY_SIZE(es8396_speaker_lmixer_controls)),
SND_SOC_DAPM_MIXER("SPKR Mix", SND_SOC_NOPM, 0, 0,
&es8396_speaker_rmixer_controls[0],
ARRAY_SIZE(es8396_speaker_rmixer_controls)),
SND_SOC_DAPM_SWITCH_E("SPK Amp", SND_SOC_NOPM, 0, 0,
&es8396_spkldo_pwrswitch_controls, classd_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUTPUT("MONOOUTP"),
SND_SOC_DAPM_OUTPUT("MONOOUTN"),
SND_SOC_DAPM_OUTPUT("HPL"),
SND_SOC_DAPM_OUTPUT("HPR"),
SND_SOC_DAPM_OUTPUT("SPKOUTL"),
SND_SOC_DAPM_OUTPUT("SPKOUTR"),
SND_SOC_DAPM_OUTPUT("LOUTP"),
SND_SOC_DAPM_OUTPUT("ROUTN"),
};
static const struct snd_soc_dapm_route es8396_dapm_routes[] = {
/* lln mux */
{"LLN Mux", "RPGAP", "RPGA P"},
{"LLN Mux", "LPGAP", "LPGA P"},
{"LLN Mux", "MONOP", "MONOINP"},
{"LLN Mux", "AINL", "AINL"},
/* rln mux */
{"RLN Mux", "RPGAP", "RPGA P"},
{"RLN Mux", "LPGAP", "LPGA P"},
{"RLN Mux", "MONON", "MONOINN"},
{"RLN Mux", "AINR", "AINR"},
/* lax mux */
{"LAX Mux", "RPGAP", "RPGA P"},
{"LAX Mux", "LPGAP", "LPGA P"},
{"LAX Mux", "MONOP", "MONOINP"},
{"LAX Mux", "AINL", "AINL"},
/* rax mux */
{"RAX Mux", "RPGAP", "RPGA P"},
{"RAX Mux", "LPGAP", "LPGA P"},
{"RAX Mux", "MONON", "MONOINN"},
{"RAX Mux", "AINR", "AINR"},
/* Left, right PGA */
{"LPGA P", NULL, "PGA Left Mix"},
{"RPGA P", NULL, "PGA Right Mix"},
{"PGA Left Mix", "RLNMIX2LPGA Switch", "RLNINMIX PGA"},
{"PGA Left Mix", "RAXMIX2LPGA Switch", "RAXINMIX PGA"},
{"PGA Left Mix", "RMNMIX2LPGA Switch", "RMONINMIX PGA"},
{"PGA Left Mix", "LMNMIX2LPGA Switch", "LMONINMIX PGA"},
{"PGA Left Mix", "LLNMIX2LPGA Switch", "LLNINMIX PGA"},
{"PGA Right Mix", "RLNMIX2RPGA Switch", "RLNINMIX PGA"},
{"PGA Right Mix", "RAXMIX2RPGA Switch", "RAXINMIX PGA"},
{"PGA Right Mix", "RMNMIX2RPGA Switch", "RMONINMIX PGA"},
{"PGA Right Mix", "LMNMIX2RPGA Switch", "LMONINMIX PGA"},
{"PGA Right Mix", "LAXMIX2RPGA Switch", "LAXINMIX PGA"},
/* lnmix */
{"RLNINMIX PGA", NULL, "RLNIN Mix"},
{"LLNINMIX PGA", NULL, "LLNIN Mix"},
{"LLNIN Mix", "AINL2LLNMIX Switch", "AINL"},
{"LLNIN Mix", "LLNMUX2LLNMIX Switch", "LLN Mux"},
{"LLNIN Mix", "MIC1P2LLNMIX Switch", "MIC"},
{"LLNIN Mix", "PMICDSE2LLNMIX Switch", "MIC BOOST"},
{"RLNIN Mix", "AINR2RLNMIX Switch", "AINR"},
{"RLNIN Mix", "RLNMUX2RLNMIX Switch", "RLN Mux"},
{"RLNIN Mix", "MIC1N2LLNMIX Switch", "MIC"},
{"RLNIN Mix", "NMICDSE2RLNMIX Switch", "MIC BOOST"},
/* AXmix */
{"RAXINMIX PGA", NULL, "RAXIN Mix"},
{"LAXINMIX PGA", NULL, "LAXIN Mix"},
{"LAXIN Mix", "LAXMUX2LAXMIX Switch", "LAX Mux"},
{"LAXIN Mix", "MONOP2LAXMIX Switch", "MONOINP"},
{"LAXIN Mix", "MIC2P2LAXMIX Switch", "MIC"},
{"LAXIN Mix", "PMICDSE2LAXMIX Switch", "MIC BOOST"},
{"RAXIN Mix", "RAXMUX2RAXMIX Switch", "RAX Mux"},
{"RAXIN Mix", "MONON2RAXMIX Switch", "MONOINN"},
{"RAXIN Mix", "MIC2N2RAXMIX Switch", "MIC"},
{"RAXIN Mix", "NMICDSE2RAXMIX Switch", "MIC BOOST"},
/* MNmix */
{"RMONINMIX PGA", NULL, "RMONIN Mix"},
{"LMONINMIX PGA", NULL, "LMONIN Mix"},
{"LMONIN Mix", "LDAC2LMNMIX Switch", "Left DAC"},
{"LMONIN Mix", "MONOP2LMNMIX Switch", "MONOINP"},
{"LMONIN Mix", "AINL2LMNMIX Switch", "AINL"},
{"RMONIN Mix", "RDAC2RMNMIX Switch", "Right DAC"},
{"RMONIN Mix", "MONON2RMNMIX Switch", "MONOINN"},
{"RMONIN Mix", "AINR2RMNMIX Switch", "AINR"},
/* Analog mic mux */
{"MIC BOOST", NULL, "AMIC Mux"},
{"AMIC Mux", "Switch", "MIC"},
{"MIC", NULL, "MIC Bias"},
/* capature */
{"ADC Left", NULL, "LPGA P"},
{"ADC Right", NULL, "RPGA P"},
{"ADC_1", "Switch", "ADC Left"},
{"ADC_1", "Switch", "ADC Right"},
/* digital mixer */
{"Equalizer", NULL, "Digital Left Mixer"},
{"Equalizer", NULL, "Digital Right Mixer"},
{"Digital Left Mixer", NULL, "LDMIX1 Mux"},
{"Digital Left Mixer", NULL, "LDMIX2 Mux"},
{"Digital Right Mixer", NULL, "RDMIX1 Mux"},
{"Digital Right Mixer", NULL, "RDMIX2 Mux"},
{"LDMIX1 Mux", "left SDP1 in", "VOICESDPIL"},
{"LDMIX1 Mux", "left SDP2 in", "MASTERSDPIL"},
{"LDMIX1 Mux", "left SDP3 in", "AUXSDPIL"},
{"LDMIX1 Mux", "left ADC out", "ADC_1"},
{"LDMIX1 Mux", "right SDP1 in", "VOICESDPIR"},
{"LDMIX1 Mux", "right SDP2 in", "MASTERSDPIR"},
{"LDMIX1 Mux", "right SDP3 in", "AUXSDPIR"},
{"LDMIX1 Mux", "right ADC out", "ADC_1"},
{"RDMIX1 Mux", "left SDP1 in", "VOICESDPIL"},
{"RDMIX1 Mux", "left SDP2 in", "MASTERSDPIL"},
{"RDMIX1 Mux", "left SDP3 in", "AUXSDPIL"},
{"RDMIX1 Mux", "left ADC out", "ADC_1"},
{"RDMIX1 Mux", "right SDP1 in", "VOICESDPIR"},
{"RDMIX1 Mux", "right SDP2 in", "MASTERSDPIR"},
{"RDMIX1 Mux", "right SDP3 in", "AUXSDPIR"},
{"RDMIX1 Mux", "right ADC out", "ADC_1"},
{"LDMIX2 Mux", "left SDP1 in", "VOICESDPIL"},
{"LDMIX2 Mux", "left SDP2 in", "MASTERSDPIL"},
{"LDMIX2 Mux", "left SDP3 in", "AUXSDPIL"},
{"LDMIX2 Mux", "left ADC out", "ADC_1"},
{"LDMIX2 Mux", "right SDP1 in", "VOICESDPIR"},
{"LDMIX2 Mux", "right SDP2 in", "MASTERSDPIR"},
{"LDMIX2 Mux", "right SDP3 in", "AUXSDPIR"},
{"LDMIX2 Mux", "right ADC out", "ADC_1"},
{"RDMIX2 Mux", "left SDP1 in", "VOICESDPIL"},
{"RDMIX2 Mux", "left SDP2 in", "MASTERSDPIL"},
{"RDMIX2 Mux", "left SDP3 in", "AUXSDPIL"},
{"RDMIX2 Mux", "left ADC out", "ADC_1"},
{"RDMIX2 Mux", "right SDP1 in", "VOICESDPIR"},
{"RDMIX2 Mux", "right SDP2 in", "MASTERSDPIR"},
{"RDMIX2 Mux", "right SDP3 in", "AUXSDPIR"},
{"RDMIX2 Mux", "right ADC out", "ADC_1"},
/* VOICE/SDP1 AIF IN mixer */
{"VOICEIN AIF Mixer", NULL, "VOICESDPIL"},
{"VOICEIN AIF Mixer", NULL, "VOICESDPIR"},
/* master/SDP2 AIF IN mixer */
{"MASTERIN AIF Mixer", NULL, "MASTERSDPIL"},
{"MASTERIN AIF Mixer", NULL, "MASTERSDPIR"},
/* aux/SDP3 AIF IN mixer */
{"AUXIN AIF Mixer", NULL, "AUXSDPIL"},
{"AUXIN AIF Mixer", NULL, "AUXSDPIR"},
/* VOICE/SDP1 AIF OUT */
{"VOICESDPOL", NULL, "VOICESDPO Mux"},
{"VOICESDPOR", NULL, "VOICESDPO Mux"},
{"VOICESDPO Mux", "ADC out", "ADC_1"},
{"VOICESDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
{"VOICESDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
{"VOICESDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
{"VOICESDPO Mux", "EQ stereo", "Equalizer"},
{"VOICESDPO Mux", "EQ left", "Digital Left Mixer"},
{"VOICESDPO Mux", "EQ right", "Digital Right Mixer"},
/* master/SDP2 AIF OUT */
{"MASTERSDPOL", NULL, "MASTERSDPO Mux"},
{"MASTERSDPOR", NULL, "MASTERSDPO Mux"},
{"MASTERSDPO Mux", "ADC out", "ADC_1"},
{"MASTERSDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
{"MASTERSDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
{"MASTERSDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
{"MASTERSDPO Mux", "EQ stereo", "Equalizer"},
{"MASTERSDPO Mux", "EQ left", "Digital Left Mixer"},
{"MASTERSDPO Mux", "EQ right", "Digital Right Mixer"},
/* AUX/SDP3 AIF OUT */
{"AUXSDPOL", NULL, "AUXSDPO Mux"},
{"AUXSDPOR", NULL, "AUXSDPO Mux"},
{"AUXSDPO Mux", "ADC out", "ADC_1"},
{"AUXSDPO Mux", "SDP1 in", "VOICEIN AIF Mixer"},
{"AUXSDPO Mux", "SDP2 in", "MASTERIN AIF Mixer"},
{"AUXSDPO Mux", "SDP3 in", "AUXIN AIF Mixer"},
{"AUXSDPO Mux", "EQ stereo", "Equalizer"},
{"AUXSDPO Mux", "EQ left", "Digital Left Mixer"},
{"AUXSDPO Mux", "EQ right", "Digital Right Mixer"},
/* DAC */
{"Left DAC", NULL, "DAC_1"},
{"Right DAC", NULL, "DAC_1"},
{"DAC_1", "Switch", "DACSRC Mux"},
{"DACSRC Mux", "SDP1 in", "VOICEIN AIF Mixer"},
{"DACSRC Mux", "SDP2 in", "MASTERIN AIF Mixer"},
{"DACSRC Mux", "SDP3 in", "AUXIN AIF Mixer"},
{"DACSRC Mux", "ADC out", "ADC_1"},
{"DACSRC Mux", "EQ stereo", "Equalizer"},
{"DACSRC Mux", "EQ left", "Digital Left Mixer"},
{"DACSRC Mux", "EQ right", "Digital Right Mixer"},
/* SPEAKER Paths */
{"SPKOUTL", NULL, "SPK Amp"},
{"SPKOUTR", NULL, "SPK Amp"},
{"SPK Amp", "Switch", "SPKL Mix"},
{"SPK Amp", "Switch", "SPKR Mix"},
/*
* {"SPK Amp", "Switch", "SPKL Mux"},
* {"SPK Amp", "Switch", "SPKR Mux"},
*
* {"SPKL Mux", "SPKR Route", "SPKR Mix"},
* {"SPKL Mux", "SPKL Route", "SPKL Mix"},
*
* {"SPKR Mux", "SPKR Route", "SPKR Mix"},
* {"SPKR Mux", "SPKL Route", "SPKL Mix"},
*/
{"SPKL Mix", "LLNMUX2SPKMIX Switch", "LLN Mux"},
{"SPKL Mix", "LAXMUX2SPKMIX Switch", "LAX Mux"},
{"SPKL Mix", "LDAC2SPKMIX Switch", "Left DAC"},
{"SPKR Mix", "RLNMUX2SPKMIX Switch", "RLN Mux"},
{"SPKR Mix", "RAXMUX2SPKMIX Switch", "RAX Mux"},
{"SPKR Mix", "RDAC2SPKMIX Switch", "Right DAC"},
/* HEADPHONE Paths */
{"HPL", NULL, "HP Amp"},
{"HPR", NULL, "HP Amp"},
{"HP Amp", "Switch", "HPL Mix"},
{"HP Amp", "Switch", "HPR Mix"},
{"HPL Mix", "LNMUX2HPMIX_L Switch", "LLN Mux"},
{"HPL Mix", "AXMUX2HPMIX_L Switch", "LAX Mux"},
{"HPL Mix", "DACL2HPMIX Switch", "Left DAC"},
{"HPR Mix", "LNMUX2HPMIX_R Switch", "RLN Mux"},
{"HPR Mix", "AXMUX2HPMIX_R Switch", "RAX Mux"},
{"HPR Mix", "DACR2HPMIX Switch", "Right DAC"},
/* EARPIECE Paths */
{"MONOOUTP", NULL, "MNOUTP PGA"},
{"MONOOUTN", NULL, "MNOUTN PGA"},
{"MNOUTP PGA", NULL, "MNOUTP Mix"},
{"MNOUTN PGA", NULL, "MNOUTN Mix"},
{"MNOUTP Mix", "LHPMIX2MNMIXP Switch", "HPL Mix"},
{"MNOUTP Mix", "RHPMIX2MNOMIXP Switch", "HPR Mix"},
{"MNOUTP Mix", "RMNMIX2MNOMIXP Switch", "RMONINMIX PGA"},
{"MNOUTP Mix", "RAXMIX2MNOMIXP Switch", "RAXINMIX PGA"},
{"MNOUTP Mix", "LLNMIX2MNOMIXP Switch", "LLNINMIX PGA"},
{"MNOUTN Mix", "LMNMIX2MNMIXN Switch", "LMONINMIX PGA"},
{"MNOUTN Mix", "RHPMIX2MNOMIXN Switch", "HPR Mix"},
{"MNOUTN Mix", "MOPINV2MNOMIXN Switch", "MNOUTP Mix"},
{"MNOUTN Mix", "LLNMIX2MNOMIXN Switch", "LLNINMIX PGA"},
{"MNOUTN Mix", "LAXMIX2MNOMIXN Switch", "LAXINMIX PGA"},
/* LNOUT Paths */
{"LOUTP", NULL, "LNOUTMIX1 PGA"},
{"ROUTN", NULL, "RNOUTMIX1 PGA"},
{"LNOUTMIX1 PGA", NULL, "LOUT1 Mix"},
{"RNOUTMIX1 PGA", NULL, "ROUT1 Mix"},
{"LOUT1 Mix", "LDAC2LO1MIXP Switch", "Left DAC"},
{"LOUT1 Mix", "LAXMIX2LO1MIXP Switch", "LAXINMIX PGA"},
{"LOUT1 Mix", "LLNMIX2LO1MIXP Switch", "LLNINMIX PGA"},
{"LOUT1 Mix", "LMNMIX2LO1MIXP Switch", "LMONINMIX PGA"},
{"LOUT1 Mix", "RO1INV2LO1MIXP Switch", "ROUT1 Mix"},
{"ROUT1 Mix", "RDAC2RO1MIXN Switch", "Right DAC"},
{"ROUT1 Mix", "RAXMIX2RO1MIXN Switch", "RAXINMIX PGA"},
{"ROUT1 Mix", "RLNMIX2RO1MIXN Switch", "RLNINMIX PGA"},
{"ROUT1 Mix", "RMNMIX2RO1MIXN Switch", "RMONINMIX PGA"},
{"ROUT1 Mix", "LO1INV2RO1MIXN Switch", "LOUT1 Mix"},
};
struct _pll_div {
u32 pll_in;
u32 pll_out;
u8 mclkdiv;
u8 plldiv;
u8 n;
u8 k1;
u8 k2;
u8 k3;
};
static const struct _pll_div codec_pll_div[] = {
{7500000, 11289600, 1, 8, 12, 0x01, 0xc6, 0xee},
{7500000, 12288000, 1, 8, 13, 0x04, 0x82, 0x90},
{7600000, 11289600, 1, 8, 11, 0x25, 0x2e, 0x93},
{7600000, 12288000, 1, 8, 12, 0x27, 0x53, 0x49},
{8192000, 11289600, 1, 8, 11, 0x01, 0x0d, 0x41},
{8192000, 12288000, 1, 8, 12, 0x00, 0x00, 0x01},
{8380000, 11289600, 1, 8, 10, 0x20, 0xb7, 0x8d},
{8380000, 12288000, 1, 8, 11, 0x1e, 0xbe, 0xb7},
{9000000, 11289600, 1, 8, 10, 0x01, 0x7b, 0x1c},
{9000000, 12288000, 1, 8, 10, 0x26, 0xd1, 0x4a},
{9600000, 11289600, 1, 8, 9, 0x11, 0x2a, 0x3c},
{9600000, 12288000, 1, 8, 10, 0x0a, 0x18, 0xd8},
{9800000, 11289600, 1, 8, 9, 0x09, 0x16, 0x5c},
{9800000, 12288000, 1, 8, 10, 0x01, 0x4e, 0x18},
{10000000, 11289600, 1, 8, 9, 0x01, 0x55, 0x33},
{10000000, 12288000, 1, 8, 9, 0x22, 0xef, 0x8f},
{11059200, 11289600, 1, 8, 8, 0x07, 0x03, 0x07},
{11059200, 12288000, 1, 8, 8, 0x25, 0x65, 0x7f},
{11289600, 11289600, 1, 8, 8, 0x00, 0x00, 0x01},
{11289600, 12288000, 1, 8, 8, 0x1d, 0xc3, 0xb8},
{11500000, 11289600, 1, 8, 7, 0x23, 0xe9, 0xcd},
{11500000, 12288000, 1, 8, 8, 0x17, 0x0f, 0xee},
{12000000, 11289600, 1, 8, 7, 0x16, 0x25, 0x6c},
{12000000, 12288000, 1, 8, 8, 0x08, 0x13, 0xe0},
{12288000, 11289600, 1, 8, 7, 0x0e, 0xb9, 0x90},
{12288000, 12288000, 1, 8, 8, 0x00, 0x00, 0x01},
{12500000, 11289600, 1, 8, 7, 0x09, 0x7a, 0xff},
{12500000, 12288000, 1, 8, 7, 0x24, 0x5c, 0xe2},
{12800000, 11289600, 1, 8, 7, 0x02, 0x5b, 0x21},
{12800000, 12288000, 1, 8, 7, 0x1c, 0x9b, 0xb9},
{13000000, 11289600, 1, 8, 6, 0x27, 0xdc, 0x2b},
{13000000, 12288000, 1, 8, 7, 0x17, 0xa3, 0x2f},
{13500000, 11289600, 1, 8, 6, 0x1d, 0x08, 0xdc},
{13500000, 12288000, 1, 8, 7, 0x0b, 0xda, 0xcc},
{13560000, 11289600, 1, 8, 6, 0x1b, 0xca, 0x0a},
{13560000, 12288000, 1, 8, 7, 0x0a, 0x7f, 0xc7},
{14000000, 11289600, 1, 8, 6, 0x12, 0xfb, 0x81},
{14000000, 12288000, 1, 8, 7, 0x00, 0xe9, 0xdd},
{15000000, 11289600, 1, 8, 6, 0x00, 0xe3, 0x77},
{15000000, 12288000, 1, 8, 6, 0x17, 0x4a, 0x5f},
{15360000, 11289600, 1, 8, 5, 0x25, 0x05, 0xc2},
{15360000, 12288000, 1, 8, 6, 0x10, 0xd4, 0x12},
{16000000, 11289600, 1, 8, 5, 0x1b, 0x20, 0x9d},
{16000000, 12288000, 1, 8, 6, 0x06, 0x0e, 0xe8},
{16384000, 11289600, 1, 8, 5, 0x15, 0x8f, 0xb8},
{16384000, 12288000, 1, 8, 6, 0x00, 0x00, 0x01},
{16800000, 11289600, 1, 8, 5, 0x0f, 0xd1, 0x96},
{16800000, 12288000, 1, 8, 5, 0x23, 0xd2, 0x0a},
{18432000, 11289600, 2, 8, 9, 0x21, 0xa8, 0x25},
{18432000, 12288000, 2, 8, 10, 0x1c, 0x0c, 0x1f},
{19200000, 11289600, 2, 8, 9, 0x11, 0x2a, 0x3c},
{19200000, 12288000, 2, 8, 10, 0x0a, 0x18, 0xd8},
{19800000, 11289600, 2, 8, 9, 0x05, 0x2b, 0xc0},
{19800000, 12288000, 2, 8, 9, 0x27, 0x1d, 0x01},
{20000000, 11289600, 2, 8, 9, 0x01, 0x55, 0x33},
{20000000, 12288000, 2, 8, 9, 0x22, 0xef, 0x8f},
{22118400, 11289600, 2, 8, 8, 0x07, 0x03, 0x07},
{22118400, 12288000, 2, 8, 8, 0x25, 0x65, 0x7f},
{22579200, 11289600, 2, 8, 8, 0x00, 0x00, 0x01},
{22579200, 12288000, 2, 8, 8, 0x1d, 0xc3, 0xb8},
{24000000, 11289600, 2, 8, 7, 0x16, 0x25, 0x6c},
{24000000, 12288000, 2, 8, 8, 0x08, 0x13, 0xe0},
{24576000, 11289600, 2, 8, 7, 0x0e, 0xb9, 0x90},
{24576000, 12288000, 2, 8, 8, 0x00, 0x00, 0x01},
{25000000, 11289600, 2, 8, 7, 0x09, 0x7a, 0xff},
{25000000, 12288000, 2, 8, 7, 0x24, 0x5c, 0xe2},
{26000000, 11289600, 2, 8, 6, 0x27, 0xdc, 0x2b},
{26000000, 12288000, 2, 8, 7, 0x17, 0xa3, 0x2f},
{27000000, 11289600, 2, 8, 6, 0x1d, 0x08, 0xdc},
{27000000, 12288000, 2, 8, 7, 0x0b, 0xda, 0xcc},
{30000000, 11289600, 2, 8, 6, 0x00, 0xe3, 0x77},
{30000000, 12288000, 2, 8, 6, 0x17, 0x4a, 0x5f},
};
static int es8396_set_pll(struct snd_soc_dai *dai, int pll_id,
int source, unsigned int freq_in,
unsigned int freq_out)
{
int i;
struct snd_soc_component *component = dai->component;
struct es8396_private *priv = snd_soc_component_get_drvdata(component);
u16 reg;
u8 N, K1, K2, K3, mclk_div, pll_div, tmp;
switch (pll_id) {
case ES8396_PLL:
break;
default:
return -EINVAL;
}
/* Disable PLL, power down and hold in reset state */
snd_soc_component_write(component, ES8396_PLL_CTRL_1_REG02, 0x81);
if (!freq_in || !freq_out)
return 0;
switch (source) {
case ES8396_PLL_NO_SRC_0:
/* Allow no source specification when stopping */
if (freq_out)
return -EINVAL;
reg = snd_soc_component_read(component, ES8396_CLK_SRC_SEL_REG01);
reg &= 0xF0;
if (source == 0)
reg |= 0x01; /* clksrc2= 0, clksrc1 = 1 */
else
reg |= 0x09; /* clksrc2= 1, clksrc1 = 1 */
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, reg);
reg = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
reg |= 0x0F;
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, reg);
pr_debug("ES8396 PLL No Clock source\n");
break;
case ES8396_PLL_SRC_FRM_MCLK:
reg = snd_soc_component_read(component, ES8396_CLK_SRC_SEL_REG01);
reg &= 0xF3;
reg |= 0x04; /* clksrc2= mclk */
/* use clk2 for pll clk source */
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, reg);
reg = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
reg |= 0x0F;
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, reg);
pr_debug("ES8396 PLL Clock Source from MCLK pin\n");
break;
case ES8396_PLL_SRC_FRM_BCLK:
reg = snd_soc_component_read(component, ES8396_CLK_SRC_SEL_REG01);
reg &= 0xF3;
reg |= 0x0c; /* clksrc2= bclk, */
/* use clk2 for pll clk source */
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, reg);
reg = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
reg |= 0x0F;
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, reg);
pr_debug("ES8396 PLL Clock Source from BCLK signal\n");
break;
default:
return -EINVAL;
}
/* get N & K */
tmp = 0;
if (source == ES8396_PLL_SRC_FRM_MCLK ||
source == ES8396_PLL_SRC_FRM_BCLK) {
for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
if (codec_pll_div[i].pll_in == freq_in &&
codec_pll_div[i].pll_out == freq_out) {
/* PLL source from MCLK */
mclk_div = codec_pll_div[i].mclkdiv;
pll_div = codec_pll_div[i].plldiv;
N = codec_pll_div[i].n;
K3 = codec_pll_div[i].k1;
K2 = codec_pll_div[i].k2;
K1 = codec_pll_div[i].k3;
tmp = 1;
break;
}
}
if (tmp == 1) {
pr_debug("MCLK DIV=%d PLL DIV=%d PLL CLOCK SOURCE=%dHz\n",
mclk_div, pll_div, freq_in);
pr_debug("N=%d, K3=%d, K2=%d, K1=%d\n", N, K3, K2, K1);
/* set N & K */
snd_soc_component_write(component, ES8396_PLL_N_REG04, N);
snd_soc_component_write(component, ES8396_PLL_K2_REG05, K3);
snd_soc_component_write(component, ES8396_PLL_K1_REG06, K2);
snd_soc_component_write(component, ES8396_PLL_K0_REG07, K1);
if (mclk_div == 1)
/* mclk div2 = 0 */
snd_soc_component_update_bits(component,
ES8396_CLK_SRC_SEL_REG01,
0x10, 0x00);
else
/* mclk div2 = 1 */
snd_soc_component_update_bits(component,
ES8396_CLK_SRC_SEL_REG01,
0x10, 0x10);
/* pll div 8 */
snd_soc_component_update_bits(component, ES8396_PLL_CTRL_1_REG02,
0x3, 0x01);
/* configure the pll power voltage */
switch (priv->dvdd_pwr_vol) {
case 0x18:
/* dvdd=1.8v */
snd_soc_component_update_bits(component,
ES8396_PLL_CTRL_2_REG03,
0x0c, 0x00);
break;
case 0x25:
/* dvdd=2.5v */
snd_soc_component_update_bits(component,
ES8396_PLL_CTRL_2_REG03,
0x0c, 0x04);
break;
case 0x33:
/* dvdd=3.3v */
snd_soc_component_update_bits(component,
ES8396_PLL_CTRL_2_REG03,
0x0c, 0x08);
break;
default:
/* dvdd=1.8v */
snd_soc_component_update_bits(component,
ES8396_PLL_CTRL_2_REG03,
0x0c, 0x00);
break;
}
/* enable PLL analog power up */
snd_soc_component_update_bits(component, ES8396_PLL_CTRL_1_REG02,
0x80, 0x00);
/* pll digital on */
snd_soc_component_update_bits(component, ES8396_PLL_CTRL_1_REG02,
0x40, 0x40);
priv->mclk[dai->id - 1] = freq_out;
snd_soc_component_write(component, ES8396_PLL_N_REG04, 0x08);
snd_soc_component_write(component, ES8396_PLL_K2_REG05, 0X1D);
snd_soc_component_write(component, ES8396_PLL_K1_REG06, 0XC3);
snd_soc_component_write(component, ES8396_PLL_K0_REG07, 0XB8);
} else {
pr_debug("Can not find the correct clock frequency!!!!!\n");
}
}
return 0;
}
/*
* if PLL not be used, use internal clk1 for mclk,
* otherwise, use internal clk2 for PLL source.
*/
static int es8396_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = dai->component;
struct es8396_private *priv = snd_soc_component_get_drvdata(component);
u8 reg;
switch (dai->id) {
case ES8396_SDP1:
case ES8396_SDP2:
case ES8396_SDP3:
break;
default:
return -EINVAL;
}
switch (clk_id) {
/* the clock source form MCLK pin, don't use PLL */
case ES8396_CLKID_MCLK:
reg = snd_soc_component_read(component, ES8396_CLK_SRC_SEL_REG01);
reg &= 0xFC;
reg |= 0x00; /* clksrc1= mclk */
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, reg);
/* always use clk1 */
reg = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
reg &= 0xf0;
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, reg);
priv->sysclk[dai->id] = clk_id;
priv->mclk[dai->id] = freq;
if (freq > 19600000) {
/* mclk div2 */
snd_soc_component_update_bits(component, ES8396_CLK_SRC_SEL_REG01,
0x10, 0x10);
}
switch (dai->id) {
case ES8396_SDP1:
/* bclkdiv m1 use clk1 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M1_REG0E,
0x20, 0x00);
/* lrckdiv m3 use clk1 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M3_REG10,
0x20, 0x00);
break;
case ES8396_SDP2:
case ES8396_SDP3:
/* bclkdiv m1 use clk1 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M2_REG0F,
0x20, 0x00);
/* lrckdiv m4 use clk1 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M4_REG11,
0x20, 0x00);
break;
default:
break;
}
pr_debug("ES8396 using MCLK as SYSCLK at %uHz\n", freq);
break;
/* the clock source form internal BCLK signal, don't use PLL */
case ES8396_CLKID_BCLK:
reg = snd_soc_component_read(component, ES8396_CLK_SRC_SEL_REG01);
reg &= 0xFC;
reg |= 0x03; /* clksrc1= bclk */
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, reg);
/* always use clk1 */
reg = snd_soc_component_read(component, ES8396_CLK_CTRL_REG08);
reg &= 0xf0;
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, reg);
priv->sysclk[dai->id] = clk_id;
priv->mclk[dai->id] = freq;
if (freq > 19600000) {
/* mclk div2 */
snd_soc_component_update_bits(component, ES8396_CLK_SRC_SEL_REG01,
0x10, 0x10);
}
switch (dai->id) {
case ES8396_SDP1:
/* bclkdiv m1 use clk1 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M1_REG0E,
0x20, 0x00);
/* lrckdiv m3 use clk1 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M3_REG10,
0x20, 0x00);
break;
case ES8396_SDP2:
case ES8396_SDP3:
/* bclkdiv m1 use clk1 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M2_REG0F,
0x20, 0x00);
/* lrckdiv m4 use clk1 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M4_REG11,
0x20, 0x00);
break;
default:
break;
}
pr_debug("ES8396 using BCLK as SYSCLK at %uHz\n", freq);
break;
case ES8396_CLKID_PLLO:
priv->sysclk[dai->id] = ES8396_CLKID_PLLO;
switch (dai->id) {
case ES8396_SDP1:
/* bclkdiv m1 use clk1 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M1_REG0E,
0x20, 0x00);
/* lrckdiv m3 use clk1 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M3_REG10,
0x20, 0x00);
break;
case ES8396_SDP2:
/* bclkdiv m1 use clk2 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M1_REG0E,
0x20, 0x20);
/* lrckdiv m3 use clk2 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M3_REG10,
0x20, 0x20);
break;
case ES8396_SDP3:
/* bclkdiv m1 use clk2 */
snd_soc_component_update_bits(component, ES8396_BCLK_DIV_M2_REG0F,
0x20, 0x20);
/* lrckdiv m4 use clk2 */
snd_soc_component_update_bits(component, ES8396_LRCK_DIV_M4_REG11,
0x20, 0x20);
break;
default:
break;
}
pr_debug("ES8396 using PLL Output as SYSCLK\n");
break;
default:
pr_err("ES8396 System clock error\n");
return -EINVAL;
}
return 0;
}
struct es8396_mclk_div {
u32 mclk;
u32 srate;
u8 lrcdiv;
u8 bclkdiv;
};
static struct es8396_mclk_div es8396_mclk_coeffs[] = {
/* MCLK, Sample Rate, lrckdiv, bclkdiv */
{5644800, 11025, 0x04, 0x08},
{5644800, 22050, 0x02, 0x04},
{5644800, 44100, 0x00, 0x02},
{6000000, 8000, 0x17, 0x0f},
{6000000, 11025, 0x16, 0x08},
{6000000, 12000, 0x15, 0x0a},
{6000000, 16000, 0x14, 0x05},
{6000000, 22050, 0x13, 0x04},
{6000000, 24000, 0x12, 0x05},
{6000000, 44100, 0x11, 0x02},
{6000000, 48000, 0x10, 0x01},
{6144000, 8000, 0x06, 0x0c},
{6144000, 12000, 0x04, 0x08},
{6144000, 16000, 0x03, 0x06},
{6144000, 24000, 0x02, 0x04},
{6144000, 32000, 0x01, 0x03},
{6144000, 48000, 0x00, 0x02},
{8192000, 8000, 0x07, 0x10},
{8192000, 16000, 0x04, 0x08},
{8192000, 32000, 0x02, 0x04},
{11289600, 11025, 0x07, 0x10},
{11289600, 22050, 0x04, 0x08},
{11289600, 44100, 0x02, 0x04},
{12000000, 8000, 0x1b, 0x17},
{12000000, 11025, 0x19, 0x11},
{12000000, 12000, 0x18, 0x13},
{12000000, 16000, 0x17, 0x0f},
{12000000, 22050, 0x16, 0x08},
{12000000, 24000, 0x15, 0x0a},
{12000000, 32000, 0x14, 0x05},
{12000000, 44100, 0x13, 0x04},
{12000000, 48000, 0x12, 0x05},
{12288000, 8000, 0x0a, 0x15},
{12288000, 12000, 0x07, 0x10},
{12288000, 16000, 0x06, 0x0c},
{12288000, 24000, 0x04, 0x08},
{12288000, 32000, 0x03, 0x06},
{12288000, 48000, 0x02, 0x04},
};
static int es8396_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
struct es8396_private *priv = snd_soc_component_get_drvdata(component);
u8 id = codec_dai->id;
unsigned int inv, format;
u8 spc, mmcc;
switch (id) {
case ES8396_SDP1:
spc = snd_soc_component_read(component, ES8396_SDP1_IN_FMT_REG1F) & 0x3f;
mmcc = snd_soc_component_read(component, ES8396_SDP_1_MS_REG12);
break;
case ES8396_SDP2:
spc = snd_soc_component_read(component, ES8396_SDP2_IN_FMT_REG22) & 0x3f;
mmcc = snd_soc_component_read(component, ES8396_SDP_2_MS_REG13);
break;
case ES8396_SDP3:
spc = snd_soc_component_read(component, ES8396_SDP3_IN_FMT_REG24) & 0x3f;
mmcc = snd_soc_component_read(component, ES8396_SDP_3_MS_REG14);
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
mmcc &= ~MS_MASTER;
mmcc |= 0x24;
if (id == ES8396_SDP1) {
mmcc &= 0xe4; /* select bclkm1,lrckm3 */
} else {
mmcc &= 0xe4; /* select bclkm2,lrckm4 */
mmcc |= 0x09;
}
break;
case SND_SOC_DAIFMT_CBS_CFS:
mmcc &= ~MS_MASTER;
break;
default:
return -EINVAL;
}
format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
switch (format) {
case SND_SOC_DAIFMT_I2S:
spc &= 0xC7;
/* lrck polarity normal, TO CHECK THE L&R Inverted for i-net */
spc |= 0x00;
break;
case SND_SOC_DAIFMT_LEFT_J:
spc &= 0xC7;
spc |= 0x18; /* lrck polarity normal */
break;
case SND_SOC_DAIFMT_RIGHT_J:
if (id == ES8396_SDP1) {
spc &= 0xC7;
spc |= 0x28; /* lrck polarity normal */
} else {
pr_err("ES8396 SDP2&SDP3 don't Support Right Justified\n");
return -EINVAL;
}
break;
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
spc &= 0xC7;
if (format == SND_SOC_DAIFMT_DSP_A)
spc |= 0x30;
else
spc |= 0x38;
break;
default:
return -EINVAL;
}
snd_soc_component_write(component, ES8396_SDP1_IN_FMT_REG1F, 00);
pr_debug("es8396_set_dai_fmt-->\n");
priv->config[id].spc = spc;
priv->config[id].mmcc = mmcc;
return 0;
}
static int es8396_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct es8396_private *priv = snd_soc_component_get_drvdata(component);
int id = dai->id;
int mclk_coeff = 0;
int srate = params_rate(params);
u8 bdiv, lrdiv;
pr_debug("DAI[%d]: MCLK= %u, srate= %u, lrckdiv= %x, bclkdiv= %x\n",
id, priv->mclk[0], srate,
es8396_mclk_coeffs[mclk_coeff].lrcdiv,
es8396_mclk_coeffs[mclk_coeff].bclkdiv);
switch (id) {
case ES8396_SDP1:
bdiv = snd_soc_component_read(component, ES8396_BCLK_DIV_M2_REG0F);
bdiv &= 0xe0;
bdiv |= es8396_mclk_coeffs[mclk_coeff].bclkdiv;
lrdiv = snd_soc_component_read(component, ES8396_LRCK_DIV_M4_REG11);
lrdiv &= 0xe0;
lrdiv |= 0x22; /* es8396_mclk_coeffs[mclk_coeff].lrcdiv; */
snd_soc_component_write(component, ES8396_BCLK_DIV_M2_REG0F, bdiv);
snd_soc_component_write(component, ES8396_LRCK_DIV_M4_REG11, lrdiv);
priv->config[id].srate = srate;
priv->config[id].lrcdiv = lrdiv;
priv->config[id].sclkdiv = bdiv;
break;
case ES8396_SDP2:
case ES8396_SDP3:
bdiv = snd_soc_component_read(component, ES8396_BCLK_DIV_M1_REG0E);
bdiv &= 0xe0;
bdiv |= es8396_mclk_coeffs[mclk_coeff].bclkdiv;
lrdiv = snd_soc_component_read(component, ES8396_LRCK_DIV_M3_REG10);
lrdiv &= 0xe0;
lrdiv |= es8396_mclk_coeffs[mclk_coeff].lrcdiv;
snd_soc_component_write(component, ES8396_BCLK_DIV_M1_REG0E, bdiv);
snd_soc_component_write(component, ES8396_LRCK_DIV_M3_REG10, lrdiv);
priv->config[id].srate = srate;
priv->config[id].lrcdiv = lrdiv;
priv->config[id].sclkdiv = bdiv;
break;
default:
return -EINVAL;
}
return 0;
}
static int es8396_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
u8 value;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_ON:
/*
* dac csm startup, dac digital still on
* snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0xFF, 0x00);
* dac analog power on
* snd_soc_component_update_bits(component, ES8396_DAC_REF_PWR_CTRL_REG6E,
* 0xff, 0x00);
*/
snd_soc_component_write(component, 0x4E, 0x80);
snd_soc_component_write(component, 0x4F, 0x81);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (es8396->aif1_select == 0 && es8396->aif2_select == 0) {
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
snd_soc_component_write(component, ES8396_SYS_VMID_REF_REG71,
0xFF);
if (es8396_valid_analdo(es8396->ana_ldo_lvl)) {
value = es8396->ana_ldo_lvl;
value &= 0x07;
snd_soc_component_write(component, 0x70, value);
}
}
}
/*
* dac csm startup, dac digital still stop
* snd_soc_component_update_bits(component, ES8396_DAC_CSM_REG66, 0xFF, 0x04);
* adc csm startup, adc digital still stop
* snd_soc_component_update_bits(component, ES8396_ADC_CSM_REG53, 0xFF, 0x00);
*/
break;
case SND_SOC_BIAS_OFF:
break;
}
return 0;
}
static int es8396_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_component *component = dai->component;
int id = dai->id;
pr_debug("es8396_set_tristate\n");
pr_debug("ES8396 SDP NUM = %d\n", id);
switch (id) {
case ES8396_SDP1:
return snd_soc_component_update_bits(component, ES8396_SDP1_DGAIN_TDM_REG21,
0x0a, 0x0a);
case ES8396_SDP2:
case ES8396_SDP3:
pr_err("SDP NUM = %d, Can not support tristate\n", id);
return -EINVAL;
default:
return -EINVAL;
}
}
static int es8396_pcm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
struct snd_soc_component *component = dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
int ret;
int regv;
int i;
pr_debug(">>>>>>>>es8396_pcm_startup\n");
ret = snd_soc_component_read(component, ES8396_ADC_CSM_REG53);
pr_debug("ES8396_ADC_CSM_REG53===0x%x\n", ret);
/*
* set the clock source to MCLK pin
* set divider for music playback
* set DAC source from SDP1 in
*/
if ((es8396->aif2_select & 0x01) == 0) {
pr_debug(">>>>>>>>es8396_pcm_startup, only power on sdp1 for music\n");
/* if don't have voice requirement */
snd_soc_component_write(component, 0x1A, 0x00);
snd_soc_component_write(component, 0x8, 0x10);
snd_soc_component_write(component, 0xd, 0x00);
snd_soc_component_write(component, 0x9, 0x04);
snd_soc_component_write(component, 0x69, 0x00);
snd_soc_component_write(component, 0x67, 0x00);
} else {
pr_debug(">>>>>>>>es8396_pcm_startup, already power on sdp2 for voice\n");
snd_soc_component_write(component, 0x18, 0x00); /* set eq source */
snd_soc_component_write(component, 0x19, 0x51); /* set eq source */
/* if have voice requirement */
snd_soc_component_write(component, 0x1A, 0x40);
snd_soc_component_write(component, 0x8, 0x10);
snd_soc_component_write(component, 0xd, 0x00);
snd_soc_component_write(component, 0x9, 0x04);
snd_soc_component_write(component, 0x67, 0x0c);
snd_soc_component_write(component, 0x69, 0x04);
}
if (playback) {
pr_debug(">>>>>>>>>>>es8396_pcm_startup playback\n");
es8396->aif1_select |= 0x01;
snd_soc_component_write(component, 0x66, 0x01);
for (i = 0; i < 120; i = i + 2) {
snd_soc_component_write(component, 0x6A, i + 1);
snd_soc_component_write(component, 0x6B, i + 1);
usleep_range(100, 200);
}
if (es8396->calibrate == 0) {
pr_debug("Enter into %s %d\n", __func__, __LINE__);
es8396->calibrate = true;
}
schedule_delayed_work(&es8396->pcm_pop_work,
msecs_to_jiffies(10));
} else {
pr_debug(">>>>>>>>>>>es8396_pcm_startup capture\n");
snd_soc_component_update_bits(component, ES8396_SDP1_OUT_FMT_REG20, 0x40,
0x40);
/* set adc alc */
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
/* Enable MIC BOOST */
snd_soc_component_write(component, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
/* axMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_AX_MIXER_BOOST_REG2F);
regv |= 0x88;
snd_soc_component_write(component, ES8396_AX_MIXER_BOOST_REG2F, regv);
/* axmixer vol = +12db */
snd_soc_component_write(component, ES8396_AX_MIXER_VOL_REG30, 0xaa);
/* axmixer high driver capacility */
snd_soc_component_write(component, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
snd_soc_component_write(component, 0x33, 0);
/* MNMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_MN_MIXER_BOOST_REG37);
regv |= 0x88;
snd_soc_component_write(component, ES8396_MN_MIXER_BOOST_REG37, regv);
/* mnmixer vol = +12db */
snd_soc_component_write(component, ES8396_MN_MIXER_VOL_REG38, 0x44);
/* mnmixer high driver capacility */
snd_soc_component_write(component, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
/* ADC STM and Digital Startup, ADC DS Mode */
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x00);
/* force adc stm to normal */
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x40);
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x0);
/* ADC Volume =0db */
snd_soc_component_write(component, ES8396_ADC_LADC_VOL_REG56, 0x0);
snd_soc_component_write(component, ES8396_ADC_RADC_VOL_REG57, 0x0);
snd_soc_component_write(component, ES8396_ADC_CLK_DIV_REG09, 0x04);
es8396->aif1_select |= 0x02;
schedule_delayed_work(&es8396->adc_depop_work,
msecs_to_jiffies(150));
}
return 0;
}
static void es8396_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
struct snd_soc_component *component = dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
pr_debug(">>>>>>>>es8396_pcm_shutdown\n");
/*
* mute SDP1 in and mute SDP1 out
*/
if (playback) {
pr_debug(">>>>>>>>es8396_pcm_shutdown, playback\n");
schedule_delayed_work(&es8396->pcm_shutdown_depop_work,
msecs_to_jiffies(20));
} else {
pr_debug(">>>>>>>>es8396_pcm_shutdown, capture\n");
snd_soc_component_update_bits(component, ES8396_SDP1_OUT_FMT_REG20, 0x40,
0x40);
es8396->aif1_select &= 0xfd;
}
}
static int es8396_voice_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int index;
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
struct snd_soc_component *component = dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
int regv;
int i;
pr_debug("****************es8396_voice_startup\n");
if (playback) {
pr_debug("****************es8396_voice_startup, playback\n");
es8396->aif2_select |= 0x01;
snd_soc_component_write(component, 0x4e, 0x84);
snd_soc_component_write(component, 0x4f, 0x85);
for (i = 0; i < 120; i = i + 2) {
snd_soc_component_write(component, 0x6A, i + 1);
snd_soc_component_write(component, 0x6B, i + 1);
usleep_range(100, 200);
}
/* mute dac */
snd_soc_component_write(component, 0x66, 0x01);
/* DSP-B, 1st SCLK after LRCK edge, I2S2 SDPIN */
snd_soc_component_update_bits(component, ES8396_SDP2_IN_FMT_REG22,
0x7F, 0x13);
snd_soc_component_write(component, 0x18, 0x51); /* set eq source */
snd_soc_component_write(component, 0x19, 0x51); /* set eq source */
snd_soc_component_write(component, 0x8, 0x10);
snd_soc_component_write(component, 0xd, 0x00);
snd_soc_component_write(component, 0x9, 0x04);
if ((es8396->aif1_select & 0x01) == 0) {
/* if only voice */
snd_soc_component_write(component, 0x67, 0x0c);
snd_soc_component_write(component, 0x69, 0x04);
} else {
snd_soc_component_write(component, 0x67, 0x0c);
snd_soc_component_write(component, 0x69, 0x04);
}
/* clk2 used as EQ clk, OSR = 6xFs for 8k resampling to 48k */
snd_soc_component_write(component, ES8396_EQ_CLK_OSR_SEL_REG1C, 0x35);
snd_soc_component_write(component, ES8396_SHARED_ADDR_REG1D, 0x00);
for (index = 0; index < 59; index++) {
snd_soc_component_write(component, ES8396_SHARED_DATA_REG1E,
es8396_equalizer_lpf_bt_incall[index]);
}
snd_soc_component_write(component, ES8396_SHARED_ADDR_REG1D, 0xbb);
snd_soc_component_write(component, ES8396_SHARED_DATA_REG1E,
es8396_equalizer_lpf_bt_incall[59]);
schedule_delayed_work(&es8396->voice_pop_work,
msecs_to_jiffies(50));
} else {
pr_debug("****************es8396_voice_startup, capture\n");
es8396->aif2_select |= 0x02;
/* set adc alc */
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_1_REG58, 0xC6);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_2_REG59, 0x12);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_4_REG5B, 0x04);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_5_REG5C, 0xC8);
snd_soc_component_write(component, ES8396_ADC_ALC_CTRL_6_REG5D, 0x11);
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x0);
snd_soc_component_write(component, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x02);
/* axMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_AX_MIXER_BOOST_REG2F);
regv |= 0x88;
snd_soc_component_write(component, ES8396_AX_MIXER_BOOST_REG2F, regv);
/* axmixer vol = +12db */
snd_soc_component_write(component, ES8396_AX_MIXER_VOL_REG30, 0xaa);
/* axmixer high driver capacility */
snd_soc_component_write(component, ES8396_AX_MIXER_REF_LP_REG31, 0x02);
snd_soc_component_write(component, 0x33, 0);
/* MNMixer Gain boost */
regv = snd_soc_component_read(component, ES8396_MN_MIXER_BOOST_REG37);
regv |= 0x88;
snd_soc_component_write(component, ES8396_MN_MIXER_BOOST_REG37, regv);
/* mnmixer vol = +12db */
snd_soc_component_write(component, ES8396_MN_MIXER_VOL_REG38, 0x44);
/* mnmixer high driver capacility */
snd_soc_component_write(component, ES8396_MN_MIXER_REF_LP_REG39, 0x02);
/* ADC STM and Digital Startup, ADC DS Mode */
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x00);
/* force adc stm to normal */
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x40);
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x0);
/* ADC Volume =0db */
snd_soc_component_write(component, ES8396_ADC_LADC_VOL_REG56, 0x0);
snd_soc_component_write(component, ES8396_ADC_RADC_VOL_REG57, 0x0);
/* clk2 used as EQ clk, OSR = 6xFs for 8k resampling to 48k */
snd_soc_component_update_bits(component, ES8396_SDP2_OUT_FMT_REG23,
0x7F, 0x33);
}
return 0;
}
static void es8396_voice_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
pr_debug("****************es8396_voice_shutdown\n");
/* DSP-B, 1st SCLK after LRCK edge, I2S2 SDPIN */
if (playback) {
snd_soc_component_write(component, 0x66, 0x01);
pr_debug("****************es8396_voice_shutdown, playback\n");
schedule_delayed_work(&es8396->voice_shutdown_depop_work,
msecs_to_jiffies(10));
} else {
pr_debug("****************es8396_voice_shutdown, captuer\n");
/* //DSP-B, 1st SCLK after LRCK edge, I2S2 SDPO */
snd_soc_component_update_bits(component, ES8396_SDP2_OUT_FMT_REG23,
0x7F, 0x73);
es8396->aif2_select &= 0xfd;
}
}
/*
* Only mute SDP IN(for dac)
*/
static int es8396_aif1_mute(struct snd_soc_dai *codec_dai, int mute, int stream)
{
struct snd_soc_component *component = codec_dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
pr_debug("es8396_aif1_mute id = %d, mute = %d", codec_dai->id, mute);
if (mute) {
if (es8396->spk_ctl_gpio && es8396->aif2_select == 0)
gpiod_set_value(es8396->spk_ctl_gpio, 0);
if (es8396->lineout_ctl_gpio && es8396->aif2_select == 0)
gpiod_set_value(es8396->lineout_ctl_gpio, 0);
msleep(100);
} else {
if (es8396->spk_ctl_gpio)
gpiod_set_value(es8396->spk_ctl_gpio, 1);
if (es8396->lineout_ctl_gpio)
gpiod_set_value(es8396->lineout_ctl_gpio, 1);
}
return 0;
}
static int es8396_aif2_mute(struct snd_soc_dai *codec_dai, int mute, int stream)
{
struct snd_soc_component *component = codec_dai->component;
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
pr_debug("es8396_aif2_mute id = %d, mute = %d", codec_dai->id, mute);
if (mute) {
if (es8396->spk_ctl_gpio && es8396->aif1_select == 0)
gpiod_set_value(es8396->spk_ctl_gpio, 0);
if (es8396->lineout_ctl_gpio && es8396->aif1_select == 0)
gpiod_set_value(es8396->lineout_ctl_gpio, 0);
msleep(100);
} else {
if (es8396->spk_ctl_gpio)
gpiod_set_value(es8396->spk_ctl_gpio, 1);
if (es8396->lineout_ctl_gpio)
gpiod_set_value(es8396->lineout_ctl_gpio, 1);
}
return 0;
}
/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
#define ES8396_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
#define ES8396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
static const struct snd_soc_dai_ops es8396_aif1_dai_ops = {
.startup = es8396_pcm_startup,
.shutdown = es8396_pcm_shutdown,
.set_sysclk = es8396_set_dai_sysclk,
.set_fmt = es8396_set_dai_fmt,
.hw_params = es8396_pcm_hw_params,
.mute_stream = es8396_aif1_mute,
.set_pll = es8396_set_pll,
.set_tristate = es8396_set_tristate,
.no_capture_mute = 1,
};
static const struct snd_soc_dai_ops es8396_aif2_dai_ops = {
.startup = es8396_voice_startup,
.shutdown = es8396_voice_shutdown,
.set_sysclk = es8396_set_dai_sysclk,
.set_fmt = es8396_set_dai_fmt,
.hw_params = es8396_pcm_hw_params,
.mute_stream = es8396_aif2_mute,
.set_pll = es8396_set_pll,
.no_capture_mute = 1,
};
static struct snd_soc_dai_driver es8396_dai[] = {
{
.name = "es8396-aif1",
.playback = {
.stream_name = "SDP1 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = ES8396_RATES,
.formats = ES8396_FORMATS,
},
.capture = {
.stream_name = "SDP1 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = ES8396_RATES,
.formats = ES8396_FORMATS,
},
.ops = &es8396_aif1_dai_ops,
},
};
static int es8396_suspend(struct device *dev)
{
struct es8396_private *es8396 = dev_get_drvdata(dev);
struct snd_soc_component *component = es8396->component;
snd_soc_component_write(component, 0x4e, 0x84);
snd_soc_component_write(component, 0x4f, 0x85);
snd_soc_component_write(component, 0x66, 0x01);
snd_soc_component_write(component, 0x6e, 0x00);
return 0;
}
static int es8396_resume(struct device *dev)
{
struct es8396_private *es8396 = dev_get_drvdata(dev);
struct snd_soc_component *component = es8396->component;
usleep_range(20000, 21000);
snd_soc_component_write(component, 0x6e, 0x00);
snd_soc_component_write(component, 0x66, 0x00);
snd_soc_component_write(component, 0x4e, 0x80);
snd_soc_component_write(component, 0x4f, 0x81);
return 0;
}
static int es8396_probe(struct snd_soc_component *component)
{
struct es8396_private *es8396 = snd_soc_component_get_drvdata(component);
int ret = 0, regv;
u8 value;
es8396->component = component;
es8396->mclk_clock = devm_clk_get(component->dev, "mclk");
if (PTR_ERR(es8396->mclk_clock) == -EPROBE_DEFER)
return -EPROBE_DEFER;
ret = clk_prepare_enable(es8396->mclk_clock);
if (ret)
return ret;
regv = snd_soc_component_read(component, ES8396_PLL_K2_REG05);
if (regv == 0x00) {
/*
* setup system analog control
*/
snd_soc_component_write(component, ES8396_DLL_CTRL_REG0D, 0x20);
snd_soc_component_write(component, ES8396_CLK_SRC_SEL_REG01, 0x04);
snd_soc_component_write(component, ES8396_PLL_CTRL_1_REG02, 0xc1);
snd_soc_component_write(component, ES8396_PLL_CTRL_2_REG03, 0x00);
snd_soc_component_write(component, ES8396_PLL_N_REG04, 0x08);
snd_soc_component_write(component, ES8396_PLL_K2_REG05, 0X1d);
snd_soc_component_write(component, ES8396_PLL_K1_REG06, 0Xc3);
snd_soc_component_write(component, ES8396_PLL_K0_REG07, 0Xb8);
snd_soc_component_write(component, ES8396_PLL_CTRL_1_REG02, 0x41);
/* adc,dac,cphp,class d clk enable,from clk2 */
snd_soc_component_write(component, ES8396_CLK_CTRL_REG08, 0x00);
/* adc clk ratio=1 */
snd_soc_component_write(component, ES8396_ADC_CLK_DIV_REG09, 0x04);
/* dac clk ratio=1 */
snd_soc_component_write(component, ES8396_DAC_CLK_DIV_REG0A, 0x01);
snd_soc_component_write(component, ES8396_BCLK_DIV_M2_REG0F, 0x24);
snd_soc_component_write(component, ES8396_LRCK_DIV_M4_REG11, 0x22);
msleep(50);
snd_soc_component_write(component, ES8396_SYS_VMID_REF_REG71, 0xFC);
snd_soc_component_write(component, 0x72, 0xFF);
snd_soc_component_write(component, 0x73, 0xFF);
if (es8396_valid_analdo(es8396->ana_ldo_lvl) == false) {
pr_err("Analog LDO Level error.\n");
return -EINVAL;
}
value = es8396->ana_ldo_lvl;
value &= 0x07;
snd_soc_component_write(component, ES8396_SYS_CHIP_ANA_CTL_REG70, value);
/* mic enable, mic d2se enable */
snd_soc_component_write(component, ES8396_SYS_MIC_IBIAS_EN_REG75, 0x01);
msleep(50);
snd_soc_component_write(component, ES8396_TEST_MODE_REG76, 0xA0);
snd_soc_component_write(component, ES8396_NGTH_REG7A, 0x20);
msleep(50);
/* power up adc and dac analog */
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x00);
snd_soc_component_write(component, ES8396_DAC_REF_PWR_CTRL_REG6E, 0x00);
/* set L,R DAC volume */
snd_soc_component_write(component, ES8396_DAC_LDAC_VOL_REG6A, 0x01);
snd_soc_component_write(component, ES8396_DAC_RDAC_VOL_REG6B, 0x01);
/* setup charge current for calibrate */
snd_soc_component_write(component, ES8396_ADC_LADC_VOL_REG56, 0x84);
snd_soc_component_write(component, ES8396_ADC_RADC_VOL_REG57, 0xdc);
snd_soc_component_write(component, ES8396_DAC_OFFSET_CALI_REG6F, 0x06);
snd_soc_component_write(component, ES8396_DAC_RAMP_RATE_REG67, 0x00);
/* enable adc and dac stm for calibrate */
snd_soc_component_write(component, ES8396_DAC_CSM_REG66, 0x00);
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x00);
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x40);
snd_soc_component_write(component, ES8396_ADC_FORCE_REG77, 0x00);
snd_soc_component_write(component, ES8396_DLL_CTRL_REG0D, 0x00);
msleep(100);
snd_soc_component_write(component, ES8396_DAC_CSM_REG66, 0x00);
snd_soc_component_write(component, ES8396_ADC_ANALOG_CTRL_REG5E, 0x00);
snd_soc_component_write(component, 0x5f, 0xf2);
snd_soc_component_write(component, 0x1f, 0x00);
snd_soc_component_write(component, 0x20, 0x40);
/* FM */
msleep(100);
snd_soc_component_write(component, 0x65, 0x88);
snd_soc_component_write(component, 0x2E, 0x88);
snd_soc_component_write(component, 0x2F, 0x00);
snd_soc_component_write(component, 0x30, 0xBB);
if (es8396_valid_micbias(es8396->mic_bias_lvl) == false) {
pr_err("MIC BIAS Level error.\n");
return -EINVAL;
}
value = es8396->mic_bias_lvl;
value &= 0x07;
value = (value << 4) | 0x08;
/* enable micbias1 */
snd_soc_component_write(component, ES8396_SYS_MICBIAS_CTRL_REG74, value);
snd_soc_component_write(component, ES8396_ADC_CSM_REG53, 0x20);
snd_soc_component_write(component, ES8396_ADC_PGA_GAIN_REG61, 0x33);
snd_soc_component_write(component, ES8396_ADC_MICBOOST_REG60, 0x22);
if (es8396->dmic_amic == MIC_AMIC)
/*use analog mic */
snd_soc_component_write(component, ES8396_ADC_DMIC_RAMPRATE_REG54,
0x00);
else
/*use digital mic */
snd_soc_component_write(component, ES8396_ADC_DMIC_RAMPRATE_REG54,
0xf0);
/*Enable HPF, LDATA= LADC, RDATA = LADC */
snd_soc_component_write(component, ES8396_ADC_HPF_COMP_DASEL_REG55, 0x31);
/*
* setup hp detection
*/
/* gpio 2 for irq, AINL as irq src, gpio1 for dmic clk */
snd_soc_component_write(component, ES8396_ALRCK_GPIO_SEL_REG15, 0xfa);
snd_soc_component_write(component, ES8396_DAC_JACK_DET_COMP_REG69, 0x00);
if (es8396->jackdet_enable == 1) {
/* jack detection from AINL pin, AINL=0, HP Insert */
snd_soc_component_write(component, ES8396_DAC_JACK_DET_COMP_REG69,
0x04);
if (es8396->gpio_int_pol == 0)
/* if HP insert, GPIO2=Low */
snd_soc_component_write(component, ES8396_GPIO_IRQ_REG16,
0x80);
else
/* if HP insert, GPIO2=High */
snd_soc_component_write(component, ES8396_GPIO_IRQ_REG16,
0xc0);
} else {
snd_soc_component_write(component, ES8396_GPIO_IRQ_REG16, 0x00);
}
/*
* setup mono in in differential mode or stereo mode
*/
/* monoin in differential mode */
if (es8396->monoin_differential == 1)
snd_soc_component_update_bits(component, ES8396_MN_MIXER_REF_LP_REG39,
0x08, 0x08);
else
snd_soc_component_update_bits(component, ES8396_MN_MIXER_REF_LP_REG39,
0x08, 0x00);
snd_soc_component_write(component, ES8396_DAC_JACK_DET_COMP_REG69, 0x00);
snd_soc_component_write(component, ES8396_BCLK_DIV_M1_REG0E, 0x24);
snd_soc_component_write(component, ES8396_LRCK_DIV_M3_REG10, 0x22);
snd_soc_component_write(component, ES8396_SDP_2_MS_REG13, 0x00);
//codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
}
INIT_DELAYED_WORK(&es8396->adc_depop_work, adc_depop_work_events);
mutex_init(&es8396->adc_depop_mlock);
INIT_DELAYED_WORK(&es8396->pcm_pop_work, pcm_pop_work_events);
mutex_init(&es8396->pcm_depop_mlock);
INIT_DELAYED_WORK(&es8396->voice_pop_work, voice_pop_work_events);
mutex_init(&es8396->voice_depop_mlock);
INIT_DELAYED_WORK(&es8396->init_cali_work, init_cali_work_events);
mutex_init(&es8396->init_cali_mlock);
INIT_DELAYED_WORK(&es8396->pcm_shutdown_depop_work,
pcm_shutdown_depop_events);
mutex_init(&es8396->pcm_shutdown_depop_mlock);
INIT_DELAYED_WORK(&es8396->voice_shutdown_depop_work,
voice_shutdown_depop_events);
mutex_init(&es8396->voice_shutdown_depop_mlock);
snd_soc_component_write(component, 0x6f, 0x83);
snd_soc_component_write(component, ES8396_SYS_VMID_REF_REG71, 0xFC);
msleep(100);
snd_soc_component_write(component, 0x4E, 0x84);
snd_soc_component_write(component, 0x4F, 0x85);
snd_soc_component_write(component, 0x4A, 0x60);
snd_soc_component_write(component, 0x4B, 0x60);
/*
* TODO: pop noise occur when HS calibration during probe
* increase the delay of a period of time if necessary
* msleep(50);
*/
return ret;
}
static void es8396_remove(struct snd_soc_component *component)
{
snd_soc_component_write(component, 0X4E, 0x84);
snd_soc_component_write(component, 0X4F, 0x85);
snd_soc_component_write(component, 0X4A, 0x80);
snd_soc_component_write(component, 0X4B, 0x80);
snd_soc_component_write(component, 0x70, 0xd4);
}
const struct regmap_config es8396_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ES8396_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = es8396_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(es8396_reg_defaults),
};
static const struct snd_soc_component_driver soc_codec_dev_es8396 = {
.probe = es8396_probe,
.remove = es8396_remove,
.set_bias_level = es8396_set_bias_level,
.dapm_widgets = es8396_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(es8396_dapm_widgets),
.dapm_routes = es8396_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(es8396_dapm_routes),
.controls = es8396_snd_controls,
.num_controls = ARRAY_SIZE(es8396_snd_controls),
};
static int init_es8396_prv(struct es8396_private *es8396)
{
if (!es8396)
return -EINVAL;
es8396->dvdd_pwr_vol = 0x18;
es8396->spkmono = false;
es8396->earpiece = true;
es8396->monoin_differential = true;
es8396->lno_differential = 0;
es8396->ana_ldo_lvl = ANA_LDO_2_1V;
es8396->spk_ldo_lvl = SPK_LDO_3V;
es8396->mic_bias_lvl = MICBIAS_3V;
es8396->jackdet_enable = true;
es8396->gpio_int_pol = 0;
es8396->dmic_amic = MIC_AMIC;
es8396->calibrate = false;
es8396->pcm_pop_work_retry = 1;
es8396->output_device_selected = 0;
es8396->aif1_select = 0;
es8396->aif2_select = 0;
return 0;
}
static int es8396_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct es8396_private *es8396;
int ret;
es8396 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8396_private),
GFP_KERNEL);
if (!es8396)
return -ENOMEM;
ret = init_es8396_prv(es8396);
if (ret < 0)
return -EINVAL;
es8396->regmap = devm_regmap_init_i2c(i2c_client, &es8396_regmap_config);
if (IS_ERR(es8396->regmap))
return PTR_ERR(es8396->regmap);
/* initialize codec */
i2c_set_clientdata(i2c_client, es8396);
/* external speaker amp controller */
es8396->spk_ctl_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"spk-con-gpio",
GPIOD_OUT_LOW);
if (IS_ERR(es8396->spk_ctl_gpio))
return PTR_ERR(es8396->spk_ctl_gpio);
/* lineout output controller*/
es8396->lineout_ctl_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"lineout-con-gpio",
GPIOD_OUT_LOW);
if (IS_ERR(es8396->lineout_ctl_gpio))
return PTR_ERR(es8396->lineout_ctl_gpio);
return devm_snd_soc_register_component(&i2c_client->dev,
&soc_codec_dev_es8396, es8396_dai,
ARRAY_SIZE(es8396_dai));
}
static void es8396_i2c_shutdown(struct i2c_client *client)
{
struct es8396_private *es8396 = i2c_get_clientdata(client);
struct snd_soc_component *component = es8396->component;
if (es8396->spk_ctl_gpio)
gpiod_set_value(es8396->spk_ctl_gpio, 0);
usleep_range(20000, 21000);
snd_soc_component_write(component, 0X4E, 0x84);
snd_soc_component_write(component, 0X4F, 0x85);
snd_soc_component_write(component, 0X4a, 0x80);
snd_soc_component_write(component, 0X4b, 0x80);
snd_soc_component_write(component, 0x70, 0xd4);
msleep(300);
}
static const struct i2c_device_id es8396_id[] = {
{"es8396", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, es8396_id);
static const struct dev_pm_ops es8396_pm_ops = {
.suspend = es8396_suspend,
.resume = es8396_resume,
};
static struct i2c_driver es8396_i2c_driver = {
.driver = {
.name = "es8396",
.pm = &es8396_pm_ops,
},
.id_table = es8396_id,
.probe = es8396_i2c_probe,
.shutdown = es8396_i2c_shutdown,
};
module_i2c_driver(es8396_i2c_driver);
MODULE_DESCRIPTION("ASoC ES8396 driver");
MODULE_AUTHOR("DavidYang, Everest Semiconductor Co., Ltd, <yangxiaohua@everest-semi.com>");
MODULE_LICENSE("GPL");