3208 lines
		
	
	
		
			101 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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");
 |