| /* |
| * es8374.c -- ES8374 ALSA SoC Audio Codec |
| * |
| * Copyright (C) 2016 Everest Semiconductor Co., Ltd |
| * |
| * Authors: XianqingZheng(xqzheng@ambarella.com) |
| * |
| * |
| * Based on es8374.c by David Yang(yangxiaohua@everest-semi.com) |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #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 <mach/gpio.h> |
| #include <mach/pcu.h> |
| #include <linux/gpio.h> |
| #include <sound/jack.h> |
| #include <linux/irq.h> |
| |
| #include "es8374.h" |
| |
| /* |
| * The pre-declare for es8374 microphone type |
| */ |
| //#define es8374_digital_mic 0 |
| //#define es8374_analog_mic 1 |
| #define es8374_digital_mic 1 |
| #define es8374_analog_mic 0 |
| #define es8374_mic_type es8374_analog_mic |
| |
| /* |
| * The pre-declare for PLL output divider |
| */ |
| #define es8374_pll_out_div2 2 |
| #define es8374_pll_out_div4 4 |
| #define es8374_pll_out_div8 8 |
| #define es8374_pll_out_div es8374_pll_out_div8 |
| |
| /* |
| * The pre-declare for DVDD supply voltage |
| */ |
| #define es8374_dvdd_supply_1v8 0x18 |
| #define es8374_dvdd_supply_2v5 0x25 |
| #define es8374_dvdd_supply_3v3 0x33 |
| #define es8374_dvdd_supply es8374_dvdd_supply_3v3 |
| |
| /* |
| * es8374 register cache |
| */ |
| static const u8 es8374_reg_defaults[ES8374_MAX_REGISTER] = { |
| 0x03, 0x03, 0x00, 0x20, 0x00, 0x11, 0x01, 0x00, |
| 0x20, 0x80, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x40, 0x40, 0x9C, 0xBE, 0x00, 0xA0, |
| 0xFC, 0x00, 0x18, 0x00, 0x10, 0x10, 0x00, 0x08, |
| 0x08, 0xD4, 0x00, 0x00, 0x18, 0xC0, 0x1C, 0x00, |
| 0xB0, 0x32, 0x03, 0x00, 0x0D, 0x06, 0x1F, 0xF7, |
| 0xFD, 0xFF, 0x1F, 0xF7, 0xFD, 0xFF, 0x04, 0x01, |
| 0xC0, 0x00, 0x02, 0x17, 0xFD, 0xFF, 0x07, 0xFD, |
| 0xFF, 0x00, 0xFF, 0xBB, 0xFF, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| }; |
| #if 0 |
| static u8 es8374_equalizer_src[] = { |
| 0x0A, 0x9B, 0x32, 0x03, 0x5C, 0x5D, 0x4B, 0x24, 0x0A, 0x9B, |
| 0x32, 0x03, 0x4C, 0x1F, 0x43, 0x05, 0x6D, 0x27, 0x54, 0x06, |
| 0x4D, 0xE1, 0x32, 0x02, 0x3E, 0x55, 0x2A, 0x20, 0x4D, 0xE1, |
| 0x32, 0x02, 0x2E, 0x17, 0x22, 0x01, 0x9F, 0xE7, 0x43, 0x25, |
| 0x4B, 0xD9, 0x21, 0x01, 0xF9, 0xD4, 0x11, 0x21, 0x4B, 0xD9, |
| 0x21, 0x01, 0xE9, 0x96, 0x19, 0x00, 0x4C, 0xE7, 0x22, 0x23, |
| }; |
| #endif |
| |
| /* |
| * The declaration about i2s digital serial port structor |
| */ |
| struct sp_config { |
| u8 spc, mmcc, spfs; |
| u32 srate; |
| u8 lrcdiv; |
| u8 sclkdiv; |
| }; |
| |
| /* |
| * codec private data |
| */ |
| |
| struct es8374_private { |
| struct snd_soc_codec *codec; |
| u32 clk_id; |
| u32 mclk; |
| u32 sysclk; |
| /* platform dependant DVDD voltage configuration */ |
| u8 dvdd_pwr_vol; |
| u8 pll_div; |
| bool dmic_enable; |
| int irq_num; |
| }; |
| |
| //struct es8374_private *es8374_data; |
| |
| /* |
| * Define ADC and DAC Volume |
| */ |
| static const DECLARE_TLV_DB_SCALE(vdac_tlv, -9600, 50, 1); |
| static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -9600, 50, 1); |
| /* |
| * Define D2SE MIC BOOST GAIN |
| */ |
| static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 1500, 0); |
| /* |
| * Define LINE PGA GAIN |
| */ |
| static const DECLARE_TLV_DB_SCALE(linin_pga_tlv, -3, 300, 0); |
| /* |
| * Define dmic boost gain |
| */ |
| static const DECLARE_TLV_DB_SCALE(dmic_6db_scaleup_tlv, 0, 600, 0); |
| /* |
| * Definitiiion ALC noise gate type |
| */ |
| |
| static const char * const ng_type_txt[] = {"Constant PGA Gain", |
| "Mute ADC Output"}; |
| static const struct soc_enum ng_type = |
| SOC_ENUM_SINGLE(ES8374_ALC_NGTH_REG2B, 6, 2, ng_type_txt); |
| |
| |
| /* |
| * Definitiiion dac auto mute type |
| */ |
| |
| static const char * const dac_auto_mute_type_txt[] = { |
| "AUTO MUTE DISABLE", |
| "MONO OUTPUT MUTE", |
| "SPEAKER MUTE", |
| "MONO OUT & SPEAKER MUTE" |
| }; |
| static const struct soc_enum dac_auto_mute_type = |
| SOC_ENUM_SINGLE(ES8374_DAC_CONTROL_REG37, 4, 4, dac_auto_mute_type_txt); |
| /* |
| * Definitiiion dac dsm mute type |
| */ |
| |
| static const char * const dac_dsm_mute_type_txt[] = { |
| "DAC DSM UNMUTE", |
| "DAC DSM MUTE", |
| }; |
| static const struct soc_enum dac_dsm_mute_type = |
| SOC_ENUM_SINGLE(ES8374_DAC_CONTROL_REG37, 0, 2, dac_dsm_mute_type_txt); |
| |
| #ifdef _USE_7520V3_PHONE_TYPE_WTWD |
| static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, 0, 150, 0); |
| /* |
| * Define MONO output gain |
| */ |
| static const DECLARE_TLV_DB_RANGE(mono_out_gain_tlv, \ |
| 48,52,TLV_DB_SCALE_ITEM(-2150, 150, 0), \ |
| 56,59,TLV_DB_SCALE_ITEM(-1400, 150, 0), \ |
| 16,20,TLV_DB_SCALE_ITEM(-800, 150, 0), \ |
| 24,27,TLV_DB_SCALE_ITEM(-500, 150, 0), \ |
| ); |
| /* |
| * Define spk mix gain |
| */ |
| static const DECLARE_TLV_DB_RANGE(spk_mix_tlv, \ |
| 32,36,TLV_DB_SCALE_ITEM(-2150, 150, 0), \ |
| 40,43,TLV_DB_SCALE_ITEM(-1400, 150, 0), \ |
| 0,4,TLV_DB_SCALE_ITEM(-800, 150, 0), \ |
| 8,11,TLV_DB_SCALE_ITEM(-500, 150, 0), \ |
| ); |
| |
| |
| #else |
| /* |
| * Define MONO output gain |
| */ |
| static const DECLARE_TLV_DB_SCALE(mono_out_gain_tlv, 0, 150, 0); |
| #endif |
| |
| |
| /* |
| * es8374 Controls |
| */ |
| static const struct snd_kcontrol_new es8374_snd_controls[] = { |
| /* |
| * controls for capture path |
| */ |
| SOC_SINGLE_TLV("D2SE MIC BOOST GAIN", |
| ES8374_AIN_PWR_SRC_REG21, 2, 1, 0, mic_boost_tlv), |
| SOC_SINGLE_TLV("LIN PGA GAIN", |
| ES8374_AIN_PGA_REG22, 0, 15, 0, linin_pga_tlv), |
| SOC_SINGLE_TLV("DMIC 6DB SCALE UP GAIN", |
| ES8374_ADC_CONTROL_REG24, 7, 1, 0, dmic_6db_scaleup_tlv), |
| SOC_SINGLE("ADC Double FS Mode", ES8374_ADC_CONTROL_REG24, 6, 1, 0), |
| SOC_SINGLE("ADC Soft Ramp", ES8374_ADC_CONTROL_REG24, 4, 1, 0), |
| SOC_SINGLE("ADC MUTE", ES8374_ADC_CONTROL_REG24, 5, 1, 0), |
| SOC_SINGLE("ADC INVERTED", ES8374_ADC_CONTROL_REG24, 2, 1, 0), |
| SOC_SINGLE("ADC HPF COEFFICIENT", ES8374_ADC_HPF_REG2C, 0, 31, 0), |
| SOC_SINGLE_TLV("ADC Capture Volume", |
| ES8374_ADC_VOLUME_REG25, 0, 192, 1, adc_rec_tlv), |
| SOC_SINGLE("ALC Capture Target Volume", ES8374_ALC_LVL_HLD_REG28, 4, 15, 0), |
| SOC_SINGLE("ALC Capture Max PGA", ES8374_ALC_EN_MAX_GAIN_REG26, 0, 31, 0), |
| SOC_SINGLE("ALC Capture Min PGA", ES8374_ALC_MIN_GAIN_REG27, 0, 31, 0), |
| SOC_SINGLE("ALC Capture Hold Time", ES8374_ALC_LVL_HLD_REG28, 0, 15, 0), |
| SOC_SINGLE("ALC Capture Decay Time", ES8374_ALC_DCY_ATK_REG29, 4, 15, 0), |
| SOC_SINGLE("ALC Capture Attack Time", ES8374_ALC_DCY_ATK_REG29, 0, 15, 0), |
| SOC_SINGLE("ALC WIN SIZE", ES8374_ALC_WIN_SIZE_REG2A, 0, 31, 0), |
| |
| SOC_SINGLE("ALC Capture NG Threshold", ES8374_ALC_NGTH_REG2B, 0, 31, 0), |
| SOC_ENUM("ALC Capture NG Type", ng_type), |
| SOC_SINGLE("ALC Capture NG Switch", ES8374_ALC_NGTH_REG2B, 5, 1, 0), |
| |
| /* |
| * controls for playback path |
| */ |
| SOC_SINGLE("DAC Double FS Mode", ES8374_DAC_CONTROL_REG37, 7, 1, 0), |
| SOC_SINGLE("DAC Soft Ramp Rate", ES8374_DAC_CONTROL_REG36, 2, 7, 0), |
| SOC_SINGLE("DAC MUTE", ES8374_DAC_CONTROL_REG36, 5, 1, 0), |
| SOC_SINGLE("DAC OFFSET", ES8374_DAC_OFFSET_REG39, 0, 255, 0), |
| SOC_ENUM("DAC AUTO MUTE TYPE", dac_auto_mute_type), |
| SOC_ENUM("DAC DSM MUTE TYPE", dac_dsm_mute_type), |
| |
| SOC_SINGLE_TLV("DAC Playback Volume", |
| ES8374_DAC_VOLUME_REG38, 0, 192, 1, vdac_tlv), |
| #ifdef _USE_7520V3_PHONE_TYPE_WTWD |
| SOC_SINGLE_TLV("MONO OUT GAIN", |
| ES8374_MONO_GAIN_REG1B, 0, 59, 0, mono_out_gain_tlv), |
| SOC_SINGLE_TLV("SPEAKER MIXER GAIN", |
| ES8374_SPK_MIX_GAIN_REG1D, 0, 43, 0, spk_mix_tlv), |
| SOC_SINGLE_TLV("SPEAKER OUTPUT Volume", |
| ES8374_SPK_OUT_GAIN_REG1E, 0, 7, 0, spk_vol_tlv), |
| |
| #else |
| SOC_SINGLE_TLV("MONO OUT GAIN", |
| ES8374_MONO_GAIN_REG1B, 0, 15, 0, mono_out_gain_tlv), |
| SOC_SINGLE_TLV("SPEAKER MIXER GAIN", |
| ES8374_SPK_MIX_GAIN_REG1D, 0, 15, 0, mono_out_gain_tlv), |
| SOC_SINGLE_TLV("SPEAKER OUTPUT Volume", |
| ES8374_SPK_OUT_GAIN_REG1E, 0, 7, 0, mono_out_gain_tlv), |
| #endif |
| }; |
| |
| /* |
| * DAPM Controls |
| */ |
| /* |
| * alc on/off |
| */ |
| static const char * const es8374_alc_enable_txt[] = { |
| "ALC OFF", |
| "ALC ON", |
| }; |
| static const unsigned int es8374_alc_enable_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8374_alc_enable_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_ALC_EN_MAX_GAIN_REG26, 6, 1, |
| ARRAY_SIZE(es8374_alc_enable_txt), |
| es8374_alc_enable_txt, |
| es8374_alc_enable_values); |
| static const struct snd_kcontrol_new es8374_alc_enable_controls = |
| SOC_DAPM_ENUM("Route", es8374_alc_enable_enum); |
| /* |
| * adc line in select |
| */ |
| static const char * const es8374_adc_input_src_txt[] = { |
| "NO-IN", |
| "LIN1-RIN1", |
| "LIN2-RIN2", |
| "LIN1-LIN2", |
| }; |
| static const unsigned int es8374_adc_input_src_values[] = { |
| 0, 1, 2, 3}; |
| static const struct soc_enum es8374_adc_input_src_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_AIN_PWR_SRC_REG21, 4, 3, |
| ARRAY_SIZE(es8374_adc_input_src_txt), |
| es8374_adc_input_src_txt, |
| es8374_adc_input_src_values); |
| static const struct snd_kcontrol_new es8374_adc_input_src_controls = |
| SOC_DAPM_ENUM("Route", es8374_adc_input_src_enum); |
| |
| /* |
| * ANALOG IN MUX |
| */ |
| static const char * const es8374_analog_input_mux_txt[] = { |
| "LIN1", |
| "LIN2", |
| "DIFF OUT1", |
| "DIFF OUT2", |
| "PGA OUT1", |
| "PGA OUT2" |
| }; |
| static const unsigned int es8374_analog_input_mux_values[] = { |
| 0, 1, 2, 3, 4, 5}; |
| static const struct soc_enum es8374_analog_input_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_MONO_MIX_REG1A, 0, 7, |
| ARRAY_SIZE(es8374_analog_input_mux_txt), |
| es8374_analog_input_mux_txt, |
| es8374_analog_input_mux_values); |
| static const struct snd_kcontrol_new es8374_analog_input_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_analog_input_mux_enum); |
| /* |
| * MONO OUTPUT MIXER |
| */ |
| static const struct snd_kcontrol_new es8374_mono_out_mixer_controls[] = { |
| SOC_DAPM_SINGLE("LIN TO MONO OUT Switch", ES8374_MONO_MIX_REG1A, 6, 1, 0), |
| SOC_DAPM_SINGLE("DAC TO MONO OUT Switch", ES8374_MONO_MIX_REG1A, 7, 1, 0), |
| }; |
| /* |
| * SPEAKER OUTPUT MIXER |
| */ |
| static const struct snd_kcontrol_new es8374_speaker_mixer_controls[] = { |
| SOC_DAPM_SINGLE("LIN TO SPEAKER OUT Switch", ES8374_SPK_MIX_REG1C, 6, 1, 0), |
| SOC_DAPM_SINGLE("DAC TO SPEAKER OUT Switch", ES8374_SPK_MIX_REG1C, 7, 1, 0), |
| }; |
| /* |
| * digital microphone soure |
| */ |
| static const char * const es8374_dmic_mux_txt[] = { |
| "DMIC DISABLE1", |
| "DMIC DISABLE2", |
| "DMIC AT HIGH LEVEL", |
| "DMIC AT LOW LEVEL", |
| }; |
| static const unsigned int es8374_dmic_mux_values[] = { |
| 0, 1, 2, 3}; |
| static const struct soc_enum es8374_dmic_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_ADC_CONTROL_REG24, 0, 3, |
| ARRAY_SIZE(es8374_dmic_mux_txt), |
| es8374_dmic_mux_txt, |
| es8374_dmic_mux_values); |
| static const struct snd_kcontrol_new es8374_dmic_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_dmic_mux_enum); |
| /* |
| * ADC sdp soure |
| */ |
| static const char * const es8374_adc_sdp_mux_txt[] = { |
| "FROM ADC OUT", |
| "FROM EQUALIZER", |
| }; |
| static const unsigned int es8374_adc_sdp_mux_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8374_adc_sdp_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_EQ_SRC_REG2D, 7, 1, |
| ARRAY_SIZE(es8374_adc_sdp_mux_txt), |
| es8374_adc_sdp_mux_txt, |
| es8374_adc_sdp_mux_values); |
| static const struct snd_kcontrol_new es8374_adc_sdp_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_adc_sdp_mux_enum); |
| |
| /* |
| * DAC dsm soure |
| */ |
| static const char * const es8374_dac_dsm_mux_txt[] = { |
| "FROM SDP IN", |
| "FROM EQUALIZER", |
| }; |
| static const unsigned int es8374_dac_dsm_mux_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8374_dac_dsm_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_EQ_SRC_REG2D, 6, 1, |
| ARRAY_SIZE(es8374_dac_dsm_mux_txt), |
| es8374_dac_dsm_mux_txt, |
| es8374_dac_dsm_mux_values); |
| static const struct snd_kcontrol_new es8374_dac_dsm_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_dac_dsm_mux_enum); |
| /* |
| * equalizer data soure |
| */ |
| static const char * const es8374_equalizer_src_mux_txt[] = { |
| "FROM ADC OUT", |
| "FROM SDP IN", |
| }; |
| static const unsigned int es8374_equalizer_src_mux_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8374_equalizer_src_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_EQ_SRC_REG2D, 5, 1, |
| ARRAY_SIZE(es8374_equalizer_src_mux_txt), |
| es8374_equalizer_src_mux_txt, |
| es8374_equalizer_src_mux_values); |
| static const struct snd_kcontrol_new es8374_equalizer_src_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_equalizer_src_mux_enum); |
| /* |
| * DAC data soure |
| */ |
| static const char * const es8374_dac_data_mux_txt[] = { |
| "SELECT SDP LEFT DATA", |
| "SELECT SDP RIGHT DATA", |
| }; |
| static const unsigned int es8374_dac_data_mux_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8374_dac_data_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8374_DAC_CONTROL_REG36, 6, 1, |
| ARRAY_SIZE(es8374_dac_data_mux_txt), |
| es8374_dac_data_mux_txt, |
| es8374_dac_data_mux_values); |
| static const struct snd_kcontrol_new es8374_dac_data_mux_controls = |
| SOC_DAPM_ENUM("Route", es8374_dac_data_mux_enum); |
| |
| |
| static int es8374_adc_power_event(struct snd_soc_dapm_widget *w, |
| struct snd_kcontrol *kcontrol, int event) |
| { |
| |
| switch (event) { |
| case SND_SOC_DAPM_POST_PMU: |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x08, 0x08); |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x02, 0x02); |
| //snd_soc_write(w->codec, ES8374_AIN_PGA_REG22, 0x77); |
| snd_soc_update_bits(w->codec, ES8374_AIN_PWR_SRC_REG21, 0xc0, 0x00); |
| snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0xdc,0x40); |
| return 0; |
| case SND_SOC_DAPM_POST_PMD: |
| snd_soc_write(w->codec, ES8374_ADC_VOLUME_REG25, 0xc0); |
| snd_soc_write(w->codec, ES8374_ALC_LVL_HLD_REG28, 0x1C); |
| snd_soc_write(w->codec, ES8374_ALC_EN_MAX_GAIN_REG26, 0x00); |
| snd_soc_write(w->codec, ES8374_AIN_PGA_REG22, 0x00); |
| snd_soc_write(w->codec, ES8374_AIN_PWR_SRC_REG21, 0xD4); |
| //snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0x0c,0x0c); |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x0a, 0x00); |
| |
| return 0; |
| default: |
| dev_dbg(w->codec->dev, |
| "Alsa Unhandled dapm widget event %d from %s\n", |
| event, w->name); |
| return 0; |
| } |
| |
| return 0; |
| |
| } |
| |
| static int es8374_mono_out_power_event(struct snd_soc_dapm_widget *w, |
| struct snd_kcontrol *kcontrol, int event) |
| { |
| CPPS_FUNC(cpps_callbacks, zDrv_Audio_Printf)("Alsa mono out pevent wname=%s,stream=%s,event=%d ,REG1C=%x \n" ,w->name,w->sname,event,snd_soc_read(w->codec, ES8374_SPK_MIX_REG1C)); |
| |
| switch (event) { |
| case SND_SOC_DAPM_POST_PMU: |
| snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0xf2,0x40); |
| snd_soc_update_bits(w->codec, ES8374_MONO_MIX_REG1A, 0x38, 0x20); |
| //snd_soc_update_bits(w->codec, ES8374_DAC_CONTROL_REG36, 0x04, 0x04); |
| snd_soc_update_bits(w->codec, ES8374_DAC_CONTROL_REG37, 0x3f, 0x00); |
| return 0; |
| case SND_SOC_DAPM_POST_PMD: |
| //snd_soc_write(w->codec, ES8374_DAC_CONTROL_REG36, 0x20); |
| //snd_soc_write(w->codec, ES8374_DAC_CONTROL_REG37, 0x01); |
| snd_soc_write(w->codec, ES8374_MONO_MIX_REG1A, 0x08); |
| //snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0x22,0x22); |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x05, 0x05); |
| |
| return 0; |
| default: |
| dev_dbg(w->codec->dev, |
| "Alsa Unhandled dapm widget event %d from %s\n", |
| event, w->name); |
| return 0; |
| } |
| |
| return 0; |
| |
| } |
| |
| static int es8374_classD_out_power_event(struct snd_soc_dapm_widget *w, |
| struct snd_kcontrol *kcontrol, int event) |
| { |
| |
| |
| CPPS_FUNC(cpps_callbacks, zDrv_Audio_Printf)("Alsa class-d pevent wname=%s,stream=%s,event=%d,REG1C=%x \n" ,w->name,w->sname,event,snd_soc_read(w->codec, ES8374_SPK_MIX_REG1C)); |
| switch (event) { |
| case SND_SOC_DAPM_POST_PMU: |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x05, 0x05); |
| snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0xf2,0x40); |
| snd_soc_update_bits(w->codec, ES8374_SPK_MIX_REG1C, 0x10, 0x10); |
| snd_soc_update_bits(w->codec, ES8374_SPK_MIX_GAIN_REG1D, 0xf0, 0x00); |
| snd_soc_update_bits(w->codec, ES8374_SPK_OUT_GAIN_REG1E, 0xf8, 0xa0); |
| //snd_soc_update_bits(w->codec, ES8374_DAC_CONTROL_REG36, 0x04, 0x04); |
| snd_soc_update_bits(w->codec, ES8374_DAC_CONTROL_REG37, 0x3f, 0x00); |
| return 0; |
| case SND_SOC_DAPM_POST_PMD: |
| //snd_soc_write(w->codec, ES8374_DAC_CONTROL_REG36, 0x20); |
| //snd_soc_write(w->codec, ES8374_DAC_CONTROL_REG37, 0x01); |
| snd_soc_write(w->codec, ES8374_SPK_MIX_GAIN_REG1D, 0x10); |
| snd_soc_write(w->codec, ES8374_SPK_OUT_GAIN_REG1E, 0x40); |
| snd_soc_write(w->codec, ES8374_SPK_MIX_REG1C, 0x10); |
| //snd_soc_update_bits(w->codec, ES8374_ANA_PWR_CTL_REG15, 0x22,0x22); |
| //snd_soc_update_bits(w->codec, ES8374_CLK_MANAGEMENT_REG01, 0x05, 0x05); |
| return 0; |
| default: |
| dev_dbg(w->codec->dev, |
| "Alsa Unhandled dapm widget event %d from %s\n", |
| event, w->name); |
| return 0; |
| } |
| |
| return 0; |
| |
| } |
| |
| |
| static const struct snd_soc_dapm_widget es8374_dapm_widgets[] = { |
| /* Input Lines */ |
| SND_SOC_DAPM_INPUT("DMIC"), |
| SND_SOC_DAPM_INPUT("MIC1"), |
| SND_SOC_DAPM_INPUT("MIC2"), |
| SND_SOC_DAPM_INPUT("LIN1"), |
| SND_SOC_DAPM_INPUT("LIN2"), |
| |
| /* |
| * Capture path |
| */ |
| // SND_SOC_DAPM_MICBIAS("micbias", ES8374_ANA_REF_REG14, |
| // 4, 1), |
| SND_SOC_DAPM_SUPPLY("micbias", ES8374_ANA_REF_REG14, |
| 4, 1, NULL, 0), |
| /* Input MUX */ |
| SND_SOC_DAPM_MUX("DIFFERENTIAL MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_adc_input_src_controls), |
| |
| SND_SOC_DAPM_PGA("DIFFERENTIAL PGA", SND_SOC_NOPM, |
| 0, 0, NULL, 0), |
| |
| SND_SOC_DAPM_PGA("LINE PGA", SND_SOC_NOPM, |
| 0, 0, NULL, 0), |
| |
| /* ADCs */ |
| // SND_SOC_DAPM_ADC("MONO ADC", NULL, SND_SOC_NOPM, 0, 0), |
| SND_SOC_DAPM_ADC_E("MONO ADC", "Mono Capture", SND_SOC_NOPM, 0, 0, |
| es8374_adc_power_event, SND_SOC_DAPM_POST_PMU | |
| SND_SOC_DAPM_POST_PMD), |
| |
| /* Dmic MUX */ |
| SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_dmic_mux_controls), |
| |
| /* Dmic MUX */ |
| SND_SOC_DAPM_MUX("ALC MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_alc_enable_controls), |
| |
| |
| /* sdp MUX */ |
| SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_adc_sdp_mux_controls), |
| |
| /* Digital Interface */ |
| SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 1, |
| SND_SOC_NOPM, 0, 0), |
| |
| /* |
| * Render path |
| */ |
| SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, |
| SND_SOC_NOPM, 0, 0), |
| |
| /* DACs SDP DATA SRC MUX */ |
| SND_SOC_DAPM_MUX("DAC SDP SRC MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_dac_data_mux_controls), |
| |
| /* DACs DATA SRC MUX */ |
| SND_SOC_DAPM_MUX("DAC SRC MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_dac_dsm_mux_controls), |
| |
| SND_SOC_DAPM_DAC("MONO DAC", NULL, SND_SOC_NOPM, 0, 0), |
| |
| |
| /* hpmux for hp mixer */ |
| SND_SOC_DAPM_MUX("ANALOG INPUT MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_analog_input_mux_controls), |
| |
| /* Output mixer */ |
| SND_SOC_DAPM_MIXER_E("MONO MIXER", SND_SOC_NOPM, |
| 0, 0, &es8374_mono_out_mixer_controls[0], ARRAY_SIZE(es8374_mono_out_mixer_controls), |
| es8374_mono_out_power_event, SND_SOC_DAPM_POST_PMU | |
| SND_SOC_DAPM_POST_PMD), |
| |
| SND_SOC_DAPM_MIXER_E("SPEAKER MIXER", SND_SOC_NOPM, |
| 0, 0, &es8374_speaker_mixer_controls[0], ARRAY_SIZE(es8374_speaker_mixer_controls), |
| es8374_classD_out_power_event, SND_SOC_DAPM_POST_PMU | |
| SND_SOC_DAPM_POST_PMD), |
| |
| /* |
| * Equalizer path |
| */ |
| SND_SOC_DAPM_MUX("EQUALIZER MUX", SND_SOC_NOPM, 0, 0, |
| &es8374_equalizer_src_mux_controls), |
| |
| |
| /* Output Lines */ |
| SND_SOC_DAPM_OUTPUT("MOUT"), |
| SND_SOC_DAPM_OUTPUT("SPKOUT"), |
| |
| }; |
| |
| |
| static const struct snd_soc_dapm_route es8374_dapm_routes[] = { |
| /* |
| * record route map |
| */ |
| {"MIC1", NULL, "micbias"}, |
| {"MIC2", NULL, "micbias"}, |
| {"DMIC", NULL, "micbias"}, |
| |
| {"DIFFERENTIAL MUX", "LIN1-RIN1", "MIC1"}, |
| {"DIFFERENTIAL MUX", "LIN2-RIN2", "MIC2"}, |
| |
| // {"micbias", NULL, "DIFFERENTIAL MUX"}, |
| // {"DIFFERENTIAL PGA", NULL, "micbias"}, |
| |
| {"DIFFERENTIAL PGA", NULL, "DIFFERENTIAL MUX"}, |
| |
| {"LINE PGA", NULL, "DIFFERENTIAL PGA"}, |
| |
| {"MONO ADC", NULL, "LINE PGA"}, |
| |
| {"DMIC MUX", "DMIC DISABLE1", "MONO ADC"}, |
| {"DMIC MUX", "DMIC DISABLE2", "MONO ADC"}, |
| {"DMIC MUX", "DMIC AT HIGH LEVEL", "DMIC"}, |
| {"DMIC MUX", "DMIC AT LOW LEVEL", "DMIC"}, |
| |
| |
| {"ALC MUX", "ALC OFF", "DMIC MUX"}, |
| {"ALC MUX", "ALC ON", "DMIC MUX"}, |
| #if 0 |
| /* |
| * Equalizer path |
| */ |
| {"EQUALIZER MUX", "FROM ADC OUT", "ALC MUX"}, |
| {"EQUALIZER MUX", "FROM SDP IN", "I2S IN"}, |
| |
| {"SDP OUT MUX", "FROM ADC OUT", "ALC MUX"}, |
| {"SDP OUT MUX", "FROM EQUALIZER", "EQUALIZER MUX"}, |
| |
| {"I2S OUT", NULL, "SDP OUT MUX"}, |
| /* |
| * playback route map |
| */ |
| {"DAC SDP SRC MUX", "SELECT SDP LEFT DATA", "I2S IN"}, |
| {"DAC SDP SRC MUX", "SELECT SDP RIGHT DATA", "I2S IN"}, |
| |
| {"DAC SRC MUX", "FROM SDP IN", "DAC SDP SRC MUX"}, |
| {"DAC SRC MUX", "FROM EQUALIZER", "EQUALIZER MUX"}, |
| |
| {"MONO DAC", NULL, "DAC SRC MUX"}, |
| #endif |
| #if 1 |
| /* |
| * Equalizer path |
| */ |
| {"EQUALIZER MUX", "FROM ADC OUT", "ALC MUX"}, |
| {"EQUALIZER MUX", "FROM SDP IN", "I2S IN"}, |
| |
| {"SDP OUT MUX", "FROM ADC OUT", "ALC MUX"}, |
| {"SDP OUT MUX", "FROM EQUALIZER", "EQUALIZER MUX"}, |
| |
| {"I2S OUT", NULL, "SDP OUT MUX"}, |
| /* |
| * playback route map |
| */ |
| {"DAC SRC MUX", "FROM SDP IN", "I2S IN"}, |
| |
| // {"DAC SRC MUX", "FROM SDP IN", "DAC SDP SRC MUX"}, |
| {"DAC SRC MUX", "FROM EQUALIZER", "EQUALIZER MUX"}, |
| |
| {"DAC SDP SRC MUX", "SELECT SDP LEFT DATA", "DAC SRC MUX"}, |
| {"DAC SDP SRC MUX", "SELECT SDP RIGHT DATA", "DAC SRC MUX"}, |
| |
| {"MONO DAC", NULL, "DAC SDP SRC MUX"}, |
| |
| // {"MONO DAC", NULL, "DAC SRC MUX"}, |
| #endif |
| |
| |
| |
| |
| {"ANALOG INPUT MUX", "LIN1", "LIN1"}, |
| {"ANALOG INPUT MUX", "LIN2", "LIN2"}, |
| {"ANALOG INPUT MUX", "DIFF OUT1", "DIFFERENTIAL MUX"}, |
| {"ANALOG INPUT MUX", "DIFF OUT2", "DIFFERENTIAL PGA"}, |
| {"ANALOG INPUT MUX", "PGA OUT1", "LINE PGA"}, |
| {"ANALOG INPUT MUX", "PGA OUT2", "LINE PGA"}, |
| |
| |
| {"MONO MIXER", "LIN TO MONO OUT Switch", "ANALOG INPUT MUX"}, |
| {"MONO MIXER", "DAC TO MONO OUT Switch", "MONO DAC"}, |
| |
| {"SPEAKER MIXER", "LIN TO SPEAKER OUT Switch", "ANALOG INPUT MUX"}, |
| {"SPEAKER MIXER", "DAC TO SPEAKER OUT Switch", "MONO DAC"}, |
| |
| |
| {"MOUT", NULL, "MONO MIXER"}, |
| {"SPKOUT", NULL, "SPEAKER MIXER"}, |
| |
| }; |
| /* |
| * pll configuration structor |
| */ |
| struct _pll_coeff_div { |
| u32 freq_in; /* input frequency */ |
| u32 freq_out; /* output frequency */ |
| u8 mclkdiv2; /* mclk div2 */ |
| u8 plldiv; /* pll output divider */ |
| u8 pll_n; /* pll N */ |
| u8 pll_k1; /* pll K */ |
| u8 pll_k2; /* PLL K */ |
| u8 pll_k3; /* PLL K */ |
| }; |
| /* |
| * codec pll coefficients |
| * this table is used for the non-standard audio clock condition |
| */ |
| static const struct _pll_coeff_div pll_coeff_div[] = { |
| |
| {6000000 , 12288000, 0, 4, 0x08, 0x08, 0x13, 0xe1}, |
| {6000000 , 11289600, 0, 4, 0x07, 0x16, 0x25, 0x6d}, |
| |
| {8000000 , 12288000, 0, 4, 0x06, 0x06, 0x0e, 0xe9}, |
| {8000000 , 11289600, 0, 8, 0x0b, 0x0c, 0x2f, 0x0c}, |
| |
| {8192000 , 12288000, 0, 4, 0x06, 0x00, 0x00, 0x01}, |
| {8192000 , 11289600, 0, 8, 0x0b, 0x01, 0x0d, 0x42}, |
| |
| {12000000, 12288000, 0, 8, 0x08, 0x08, 0x13, 0xe1}, |
| {12000000, 11289600, 0, 8, 0x07, 0x16, 0x25, 0x6d}, |
| |
| {13000000, 12288000, 0, 8, 0x08, 0x17, 0xa3, 0x30}, |
| {13000000, 11289600, 0, 8, 0x06, 0x27, 0xdc, 0x2c}, |
| |
| {16000000, 12288000, 0, 8, 0x06, 0x06, 0x0e, 0xe9}, |
| {16000000, 11289600, 1, 8, 0x0b, 0x0c, 0x2f, 0x0c}, |
| |
| {16384000, 12288000, 0, 8, 0x06, 0x00, 0x00, 0x01}, |
| {16384000, 11289600, 1, 8, 0x0b, 0x01, 0x0d, 0x42}, |
| |
| {19200000, 12288000, 1, 8, 0x0a, 0x0a, 0x18, 0xd9}, |
| {19200000, 11289600, 1, 8, 0x09, 0x11, 0x2a, 0x3d}, |
| |
| {24000000, 12288000, 1, 8, 0x08, 0x08, 0x13, 0xe1}, |
| {24000000, 11289600, 1, 8, 0x07, 0x16, 0x25, 0x6d}, |
| |
| {25000000, 12288000, 1, 8, 0x07, 0x24, 0x5c, 0xe3}, |
| {25000000, 11289600, 1, 8, 0x07, 0x09, 0x7b, 0x00}, |
| |
| {26000000, 12288000, 1, 8, 0x07, 0x17, 0xa3, 0x30}, |
| {26000000, 11289600, 1, 8, 0x06, 0x27, 0xdc, 0x2c}, |
| |
| {27000000, 12288000, 1, 8, 0x07, 0x0b, 0xda, 0xcd}, |
| {27000000, 11289600, 1, 8, 0x06, 0x1d, 0x08, 0xdd}, |
| |
| {32000000, 12288000, 1, 8, 0x06, 0x06, 0x0e, 0xe9}, |
| {32000000, 11289600, 1, 8, 0x05, 0x1b, 0x20, 0x9e}, |
| }; |
| |
| static inline int get_pll_coeff(int freqin, int freqout) |
| { |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(pll_coeff_div); i++) { |
| if (pll_coeff_div[i].freq_in == freqin && \ |
| pll_coeff_div[i].freq_out == freqout) |
| return i; |
| } |
| |
| return -EINVAL; |
| } |
| /* |
| * a structor for standard clock divider configration |
| */ |
| struct _coeff_div { |
| u32 mclk; /* mclk frequency */ |
| u32 rate; /* sample rate */ |
| u8 mclkdiv2; /* mclkdiv2 */ |
| u8 adc_dac_div; /* internal adc&dac clock divider */ |
| u8 lrck_h; /* adc&dac lrck divider */ |
| u8 lrck_l; |
| u8 sclk_div; /* sclk divider */ |
| u8 doublespeed; |
| u8 osr; /* adc osr */ |
| }; |
| |
| |
| /* |
| * clock configuration |
| * this table is used for standard clock condition |
| */ |
| static const struct _coeff_div coeff_div[] = { |
| /* 8k */ |
| {1024000 , 8000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {2048000 , 8000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {3072000 , 8000, 0, 0x11, 0x01, 0x80, 0x0c, 1, 0x30}, |
| {4096000 , 8000, 1, 0x11, 0x00, 0x00, 0x08, 0, 0x20}, |
| {6144000 , 8000, 0, 0x33, 0x03, 0x00, 0x15, 0, 0x20}, |
| {8192000 , 8000, 1, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| {12288000, 8000, 0, 0x66, 0x06, 0x00, 0x1d, 0, 0x20}, |
| {16384000, 8000, 1, 0x44, 0x04, 0x00, 0x18, 0, 0x20}, |
| {24576000, 8000, 1, 0x66, 0x06, 0x00, 0x1d, 0, 0x20}, |
| |
| /* 11.025k */ |
| {11289600, 11025, 0, 0x44, 0x04, 0x00, 0x18, 0, 0x20}, |
| {22579200, 11025, 0, 0x44, 0x04, 0x00, 0x18, 0, 0x20}, |
| /* 12k */ |
| {3072000 , 12000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {6144000 , 12000, 0, 0x22, 0x01, 0x00, 0x08, 0, 0x20}, |
| {12288000, 12000, 0, 0x44, 0x04, 0x00, 0x18, 0, 0x20}, |
| {24576000, 12000, 1, 0x44, 0x04, 0x00, 0x18, 0, 0x20}, |
| |
| /* 16k */ |
| {2048000 , 16000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {3072000 , 16000, 0, 0x11, 0x00, 0xc0, 0x06, 1, 0x30}, |
| {4096000 , 16000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {6144000 , 16000, 0, 0x11, 0x01, 0x80, 0x0c, 0, 0x30}, |
| {8192000 , 16000, 0, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| {12288000, 16000, 0, 0x33, 0x03, 0x00, 0x15, 0, 0x20}, |
| {16384000, 16000, 1, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| {24576000, 16000, 1, 0x33, 0x03, 0x00, 0x15, 0, 0x20}, |
| |
| /* 22.05k */ |
| {11289600, 22050, 0, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| {22579200, 22050, 1, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| /* 24k */ |
| {3072000 , 24000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {6144000 , 24000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {12288000, 24000, 0, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| {24576000, 24000, 1, 0x22, 0x02, 0x00, 0x10, 0, 0x20}, |
| /* 32k */ |
| {4096000 , 32000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {6144000 , 32000, 0, 0x11, 0x00, 0xc0, 0x06, 1, 0x30}, |
| {8192000 , 32000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {16384000, 32000, 1, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {12288000, 32000, 0, 0x11, 0x01, 0x80, 0x0c, 0, 0x30}, |
| {24576000, 32000, 1, 0x11, 0x01, 0x80, 0x0c, 0, 0x30}, |
| /* 44.1k */ |
| {11289600, 44100, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {22579200, 44100, 1, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| /* 48k */ |
| {12288000, 48000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {24576000, 48000, 1, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {6144000 , 48000, 1, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| /* 64k */ |
| {8192000 , 64000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {16384000, 64000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| {12288000, 32000, 0, 0x11, 0x00, 0xc0, 0x06, 1, 0x30}, |
| {24576000, 32000, 0, 0x11, 0x01, 0x80, 0x0c, 0, 0x30}, |
| /* 88.2k */ |
| {11289600, 44100, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {22579200, 44100, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| /* 96k */ |
| {12288000, 48000, 0, 0x11, 0x00, 0x80, 0x04, 1, 0x20}, |
| {24576000, 48000, 0, 0x11, 0x01, 0x00, 0x08, 0, 0x20}, |
| |
| }; |
| static inline int get_coeff(int mclk, int rate) |
| { |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { |
| if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) |
| return i; |
| } |
| |
| return -EINVAL; |
| } |
| |
| /* |
| * if PLL not be used, use internal clk1 for mclk,otherwise, use internal clk2 for PLL source. |
| */ |
| static int es8374_set_dai_sysclk(struct snd_soc_dai *dai, |
| int clk_id, unsigned int freq, int dir) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| struct es8374_private *es8374 = snd_soc_codec_get_drvdata(codec); |
| |
| es8374->clk_id = clk_id; |
| es8374->sysclk = freq; |
| if (clk_id == ES8374_CLKID_MCLK) { |
| snd_soc_write(codec,ES8374_CLK_MANAGEMENT_REG01,0x7F); //IC clk on |
| snd_soc_write(codec,ES8374_CLK_DIV_REG05,0x11); //clk div set |
| snd_soc_write(codec,ES8374_PLL_CONTROL1_REG09,0x01); //pll set:reset on ,set start |
| snd_soc_write(codec,ES8374_PLL_K_REG0C,0x22); //pll set:k |
| snd_soc_write(codec,ES8374_PLL_K_REG0D,0x2E); //pll set:k |
| snd_soc_write(codec,ES8374_PLL_K_REG0E,0xC6); //pll set:k |
| es8374->mclk = freq; |
| } else { |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG01, 0xff, 0xff); |
| } |
| |
| return 0; |
| } |
| |
| static int es8374_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) |
| { |
| struct snd_soc_codec *codec = codec_dai->codec; |
| u8 iface = 0; |
| u8 adciface = 0; |
| u8 daciface = 0; |
| |
| iface = snd_soc_read(codec, ES8374_MS_BCKDIV_REG0F); |
| adciface = snd_soc_read(codec, ES8374_ADC_FMT_REG10); |
| daciface = snd_soc_read(codec, ES8374_DAC_FMT_REG11); |
| |
| /* set master/slave audio interface */ |
| switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| case SND_SOC_DAIFMT_CBM_CFM: /* MASTER MODE */ |
| iface |= 0x80; |
| break; |
| case SND_SOC_DAIFMT_CBS_CFS: /* SLAVE MODE */ |
| iface &= 0x7F; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| |
| /* interface format */ |
| switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| case SND_SOC_DAIFMT_I2S: |
| adciface &= 0xFC; |
| daciface &= 0xFC; |
| break; |
| case SND_SOC_DAIFMT_RIGHT_J: |
| return -EINVAL; |
| case SND_SOC_DAIFMT_LEFT_J: |
| adciface &= 0xFC; |
| daciface &= 0xFC; |
| adciface |= 0x01; |
| daciface |= 0x01; |
| break; |
| case SND_SOC_DAIFMT_DSP_A: |
| adciface &= 0xDC; |
| daciface &= 0xDC; |
| adciface |= 0x03; |
| daciface |= 0x03; |
| break; |
| case SND_SOC_DAIFMT_DSP_B: |
| adciface &= 0xDC; |
| daciface &= 0xDC; |
| adciface |= 0x23; |
| daciface |= 0x23; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| |
| /* clock inversion */ |
| if(((fmt & SND_SOC_DAIFMT_FORMAT_MASK)==SND_SOC_DAIFMT_I2S) || |
| ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LEFT_J)) { |
| |
| switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| case SND_SOC_DAIFMT_NB_NF: |
| |
| iface &= 0xDF; |
| adciface &= 0xDF; |
| daciface &= 0xDF; |
| break; |
| case SND_SOC_DAIFMT_IB_IF: |
| iface |= 0x20; |
| adciface |= 0x20; |
| daciface |= 0x20; |
| break; |
| case SND_SOC_DAIFMT_IB_NF: |
| iface |= 0x20; |
| adciface &= 0xDF; |
| daciface &= 0xDF; |
| break; |
| case SND_SOC_DAIFMT_NB_IF: |
| iface &= 0xDF; |
| adciface |= 0x20; |
| daciface |= 0x20; |
| break; |
| default: |
| return -EINVAL; |
| } |
| } |
| snd_soc_write(codec, ES8374_MS_BCKDIV_REG0F, iface); |
| snd_soc_write(codec, ES8374_ADC_FMT_REG10, adciface); |
| snd_soc_write(codec, ES8374_DAC_FMT_REG11, daciface); |
| return 0; |
| } |
| static int es8374_pcm_startup(struct snd_pcm_substream *substream, |
| struct snd_soc_dai *dai) |
| { |
| return 0; |
| } |
| |
| static void es8374_pcm_shutdown(struct snd_pcm_substream *substream, |
| struct snd_soc_dai *dai) |
| { |
| struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| struct snd_soc_codec *codec = rtd->codec; |
| u16 rst_val; |
| |
| rst_val = snd_soc_read(codec, ES8374_RESET_REG00); |
| if (!(rst_val & 0x80)) { |
| snd_soc_write(codec,0x00,0x3F); //IC Rst start |
| msleep(1); //DELAY_MS |
| snd_soc_write(codec,0x00,0x03); //IC Rst stop |
| snd_soc_write(codec,0x01,0xeF); //IC clk on |
| snd_soc_write(codec,0x05,0x33); //clk div set |
| snd_soc_write(codec,0x6F,0xA0); //pll set:mode enable |
| snd_soc_write(codec,0x72,0x41); //pll set:mode set |
| snd_soc_write(codec,0x09,0x01); //pll set:reset on ,set start |
| snd_soc_write(codec,0x0C,0x17); //pll set:k |
| snd_soc_write(codec,0x0D,0xa3); //pll set:k |
| snd_soc_write(codec,0x0E,0x30); //pll set:k |
| snd_soc_write(codec,0x0A,0x88); //pll set: |
| snd_soc_write(codec,0x0B,0x07); //pll set:n |
| snd_soc_write(codec,0x09,0x41); //pll set:reset off ,set stop |
| snd_soc_write(codec,0x24,0x08); //adc set |
| snd_soc_write(codec,0x36,0x20); //dac set xiu 180614 |
| snd_soc_write(codec,0x12,0x30); //timming set |
| snd_soc_write(codec,0x13,0x20); //timming set |
| snd_soc_write(codec,0x21,0x50); //adc set: SEL LIN1 CH+PGAGAIN=0DB |
| snd_soc_write(codec,0x22,0x00); //adc set: PGA GAIN=0DB |
| snd_soc_write(codec,0x21,0x10); //adc set: SEL LIN1 CH+PGAGAIN=0DB |
| snd_soc_write(codec,0x00,0x80); // IC START |
| msleep(50); //DELAY_MS |
| |
| snd_soc_write(codec,0x02,0x08); |
| snd_soc_write(codec,0x14,0x8a); // IC START |
| snd_soc_write(codec,0x15,0x40); // IC START |
| snd_soc_write(codec,0x1A,0xa0); // monoout set xiu 180614 |
| snd_soc_write(codec,0x1B,0x14); // monoout set xiu 180614 |
| snd_soc_write(codec,0x1C,0x10); // spk set xiu 180614 |
| snd_soc_write(codec,0x1D,0x10); // spk set |
| snd_soc_write(codec,0x1F,0x00); // spk set |
| snd_soc_write(codec,0x1E,0x40); // spk on |
| snd_soc_write(codec,0x28,0x1c); // alc set |
| snd_soc_write(codec,0x25,0xc0); // ADCVOLUME on |
| snd_soc_write(codec,0x38,0xc0); // DACVOLUMEL on |
| snd_soc_write(codec,0x37,0x00); // dac set xiu 180614 |
| snd_soc_write(codec,0x6D,0x15); //SEL:GPIO1=HPInserted in+SEL:GPIO2=Interrupt out |
| snd_soc_write(codec,0x2C,0x05); |
| snd_soc_write(codec,0x2D,0x05); |
| } |
| if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| rtd->codec_dai->runtime = NULL; |
| return; |
| } |
| |
| static int es8374_pcm_hw_params(struct snd_pcm_substream *substream, |
| struct snd_pcm_hw_params *params, |
| struct snd_soc_dai *dai) |
| { |
| struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| struct snd_soc_codec *codec = rtd->codec; |
| struct es8374_private *es8374 = snd_soc_codec_get_drvdata(codec); |
| u16 iface; |
| int coeff, rates; |
| int N; |
| // printk("Alsa %s level\n",__func__); |
| if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| rtd->codec_dai->runtime = substream->runtime; |
| |
| if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| iface = snd_soc_read(codec, ES8374_DAC_FMT_REG11) & 0xE3; |
| /* bit size */ |
| switch (params_format(params)) { |
| case SNDRV_PCM_FORMAT_S16_LE: |
| iface |= 0x0c; |
| break; |
| case SNDRV_PCM_FORMAT_S20_3LE: |
| iface |= 0x04; |
| break; |
| case SNDRV_PCM_FORMAT_S24_LE: |
| break; |
| case SNDRV_PCM_FORMAT_S32_LE: |
| iface |= 0x10; |
| break; |
| } |
| /* set iface & srate */ |
| snd_soc_write(codec, ES8374_DAC_FMT_REG11, iface); |
| } else { |
| iface = snd_soc_read(codec, ES8374_ADC_FMT_REG10) & 0xE3; |
| /* bit size */ |
| switch (params_format(params)) { |
| case SNDRV_PCM_FORMAT_S16_LE: |
| iface |= 0x0c; |
| break; |
| case SNDRV_PCM_FORMAT_S20_3LE: |
| iface |= 0x04; |
| break; |
| case SNDRV_PCM_FORMAT_S24_LE: |
| break; |
| case SNDRV_PCM_FORMAT_S32_LE: |
| iface |= 0x10; |
| break; |
| } |
| /* set iface */ |
| snd_soc_write(codec, ES8374_ADC_FMT_REG10, iface); |
| } |
| |
| if(es8374->dmic_enable){ |
| // printk("dmic is enabled\n"); |
| snd_soc_write(codec, ES8374_GPIO_INSERT_REG6D, 0x5F); //set gpio1 to DMIC CLK |
| } else { |
| // printk("dmic is not enabled\n"); |
| // snd_soc_write(codec, ES8374_GPIO_INSERT_REG6D, 0x1F); //set gpio1 to GM SHORT |
| snd_soc_write(codec, ES8374_GPIO_INSERT_REG6D, 0x15); //set gpio1 to GM SHORT |
| } |
| |
| /* |
| * do PLL configuration if PLL used |
| */ |
| if(es8374->clk_id == ES8374_CLKID_PLLO) { // if pll used |
| /* |
| * get the target PLL output clock according to the LRCK rates |
| */ |
| switch(params_rate(params)) { |
| case 8000: |
| case 16000: |
| case 24000: |
| case 48000: |
| rates = 12288000; |
| break; |
| case 11025: |
| case 22050: |
| case 44100: |
| rates = 11289600; |
| break; |
| default: |
| rates = 12288000; |
| break; |
| |
| } |
| coeff = get_pll_coeff(es8374->sysclk, rates); |
| if(coeff < 0 ) { |
| dev_err(codec->dev, |
| "Unable to configure pll, freq input = %dHz, freq output = %dHz\n", |
| es8374->sysclk, rates); |
| return coeff; |
| } |
| |
| snd_soc_update_bits(codec, ES8374_DAC_CONTROL_REG36, 0x20, 0x20); // mute dac firstly |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0x40, 0x00); // reset pll |
| mdelay(1); /// |
| if(pll_coeff_div[coeff].mclkdiv2 == 0) // set mclk div2 |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG01, 0x80, 0x00); // mclkdiv2 = 0 |
| else |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG01, 0x80, 0x80); // mclkdiv2 = 1 |
| |
| switch(pll_coeff_div[coeff].plldiv) { // set pll div |
| case 0x00: // not used pll |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0x03, 0x00); |
| break; |
| case 0x02: // internal mclk = pll out /2 |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0x03, 0x03); |
| break; |
| case 0x04: // internal mclk = pll out / 4 |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0x03, 0x02); |
| break; |
| case 0x08: // internal mclk = pll out /8 |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0x03, 0x01); |
| break; |
| default: |
| dev_err(codec->dev, |
| "invalid pll divider coff\n"); |
| break; |
| } |
| switch (es8374->dvdd_pwr_vol) { |
| case es8374_dvdd_supply_1v8: |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL2_REG0A, 0x0c, 0x00); /* dvdd=1.8v */ |
| break; |
| case es8374_dvdd_supply_2v5: |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL2_REG0A, 0x0c, 0x04); /* dvdd=2.5v */ |
| break; |
| case es8374_dvdd_supply_3v3: |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL2_REG0A, 0x0c, 0x08); /* dvdd=3.3v */ |
| break; |
| default: |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL2_REG0A, 0x0c, 0x00); /* dvdd=1.8v */ |
| break; |
| } |
| |
| N = snd_soc_read(codec, ES8374_PLL_N_REG0B) & 0xf0; |
| N |= pll_coeff_div[coeff].pll_n & 0x0f; |
| snd_soc_write(codec, ES8374_PLL_N_REG0B, N); |
| |
| snd_soc_write(codec, ES8374_PLL_K_REG0C, pll_coeff_div[coeff].pll_k1 & 0x3f); |
| snd_soc_write(codec, ES8374_PLL_K_REG0D, pll_coeff_div[coeff].pll_k2 & 0xff); |
| snd_soc_write(codec, ES8374_PLL_K_REG0E, pll_coeff_div[coeff].pll_k3 & 0xff); |
| |
| snd_soc_update_bits(codec, ES8374_PLL_CONTROL1_REG09, 0xc0, 0x40); // start pll |
| |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG02, 0x08, 0x08); // start pll |
| |
| es8374->mclk = pll_coeff_div[coeff].freq_out; //reset the mclk frequency |
| } |
| |
| /* |
| * to get correct clock configuration according to MCLK and LRCK frequecny. |
| */ |
| coeff = get_coeff(es8374->mclk, params_rate(params)); |
| if (coeff < 0) { |
| dev_err(codec->dev, |
| "Unable to configure sample rate %dHz with %dHz MCLK\n", |
| params_rate(params), es8374->mclk); |
| return coeff; |
| } |
| if(es8374->clk_id == ES8374_CLKID_MCLK) { // if pll used |
| |
| if(coeff_div[coeff].mclkdiv2 == 0) // set mclk div2 |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG01, 0x80, 0x00); // mclkdiv2 = 0 |
| else |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG01, 0x80, 0x80); // mclkdiv2 = 1 |
| } |
| snd_soc_write(codec, ES8374_CLK_DIV_REG05, coeff_div[coeff].adc_dac_div); // set adc div & dac div |
| snd_soc_write(codec, ES8374_LRCK_DIV_REG06, coeff_div[coeff].lrck_h & 0x0f); //set lrck div |
| snd_soc_write(codec, ES8374_LRCK_DIV_REG07, coeff_div[coeff].lrck_l); |
| snd_soc_update_bits(codec, ES8374_MS_BCKDIV_REG0F, 0x1f, coeff_div[coeff].sclk_div); // set sclk divider |
| if(coeff_div[coeff].doublespeed == 1) //set double speed bits |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG02, 0x30, 0x30); |
| else |
| snd_soc_update_bits(codec, ES8374_CLK_MANAGEMENT_REG02, 0x30, 0x00); |
| |
| snd_soc_update_bits(codec, ES8374_ADC_OSR_REG03, 0x3f, coeff_div[coeff].osr & 0x3f); |
| |
| // snd_soc_update_bits(codec, ES8374_DAC_CONTROL_REG36, 0x20, 0x00); // un-mute dac firstly |
| return 0; |
| } |
| |
| static int es8374_set_bias_level(struct snd_soc_codec *codec, |
| enum snd_soc_bias_level level) |
| { |
| dev_dbg(codec->dev, "es8374_set_bias_level.= 0x%x.......\n", codec->dapm.bias_level); |
| dev_dbg(codec->dev, "level = %d\n", level); |
| // printk("Alsa %s level=%d\n",__func__, level); |
| switch (level) { |
| case SND_SOC_BIAS_ON: |
| break; |
| |
| case SND_SOC_BIAS_PREPARE: |
| if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) |
| snd_soc_update_bits(codec, ES8374_ANA_REF_REG14, 0xf, 0xa); |
| break; |
| |
| case SND_SOC_BIAS_STANDBY: |
| snd_soc_write(codec, ES8374_AIN_PWR_SRC_REG21, 0xD4); |
| snd_soc_write(codec, ES8374_ANA_PWR_CTL_REG15, 0xBF); |
| snd_soc_write(codec, ES8374_ANA_REF_REG14, 0x96); |
| snd_soc_write(codec, ES8374_PLL_CONTROL1_REG09, 0x80); |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0xff); |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0x03); |
| break; |
| |
| case SND_SOC_BIAS_OFF: |
| |
| snd_soc_write(codec, ES8374_ALC_LVL_HLD_REG28, 0x1c); |
| snd_soc_update_bits(codec, ES8374_AIN_PWR_SRC_REG21, 0xc0, 0x00); |
| snd_soc_write(codec, ES8374_ANA_PWR_CTL_REG15, 0xbf); |
| snd_soc_write(codec, ES8374_ANA_REF_REG14, 0x14); |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0x03); |
| break; |
| } |
| |
| codec->dapm.bias_level = level; |
| |
| return 0; |
| } |
| |
| static int es8374_set_tristate(struct snd_soc_dai *dai, int tristate) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| dev_dbg(codec->dev, "es8374_set_tristate........\n"); |
| if(tristate) { |
| snd_soc_update_bits(codec, ES8374_MS_BCKDIV_REG0F, |
| 0x40, 0x40); |
| } else { |
| snd_soc_update_bits(codec, ES8374_MS_BCKDIV_REG0F, |
| 0x40, 0x00); |
| } |
| |
| return 0; |
| } |
| |
| static DEFINE_RAW_SPINLOCK(codec_pa_lock); |
| static int es8374_mute(struct snd_soc_dai *dai, int mute) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| // printk("Alsa %s level mute=%d\n",__func__,mute); |
| unsigned long flags; |
| struct snd_pcm_runtime *runtime = dai->runtime; |
| dev_dbg(codec->dev, "%s %d\n", __func__, mute); |
| if (mute) { |
| snd_soc_update_bits(codec, ES8374_DAC_CONTROL_REG36, 0x20, 0x20); |
| mdelay(4); |
| #ifdef CONFIG_ARCH_ZX297520V3_WATCH |
| gpio_set_value(ZX29_GPIO_125, GPIO_LOW); |
| mdelay(1); |
| #endif |
| } else { |
| if (dai->playback_active) { |
| #ifdef CONFIG_ARCH_ZX297520V3_WATCH |
| gpio_set_value(ZX29_GPIO_125, GPIO_LOW); |
| mdelay(1); |
| raw_spin_lock_irqsave(&codec_pa_lock, flags); |
| gpio_set_value(ZX29_GPIO_125, GPIO_HIGH); |
| udelay(2); |
| gpio_set_value(ZX29_GPIO_125, GPIO_LOW); |
| udelay(2); |
| gpio_set_value(ZX29_GPIO_125, GPIO_HIGH); |
| udelay(2); |
| gpio_set_value(ZX29_GPIO_125, GPIO_LOW); |
| udelay(2); |
| gpio_set_value(ZX29_GPIO_125, GPIO_HIGH); |
| raw_spin_unlock_irqrestore(&codec_pa_lock, flags); |
| #endif |
| if (runtime && (runtime->status->state != SNDRV_PCM_STATE_XRUN)) |
| snd_soc_update_bits(codec, ES8374_DAC_CONTROL_REG36, 0x20, 0x00); |
| } |
| } |
| return 0; |
| } |
| |
| |
| #define es8374_RATES SNDRV_PCM_RATE_8000_96000 |
| |
| #define es8374_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| SNDRV_PCM_FMTBIT_S24_LE) |
| |
| static struct snd_soc_dai_ops es8374_ops = { |
| .startup = es8374_pcm_startup, |
| .shutdown = es8374_pcm_shutdown, |
| .hw_params = es8374_pcm_hw_params, |
| .set_fmt = es8374_set_dai_fmt, |
| .set_sysclk = es8374_set_dai_sysclk, |
| .digital_mute = es8374_mute, |
| }; |
| |
| static struct snd_soc_dai_driver es8374_dai[] = { |
| { |
| .name = "ES8374 HiFi", |
| .playback = { |
| .stream_name = "Playback", |
| .channels_min = 1, |
| .channels_max = 2, |
| .rates = es8374_RATES, |
| .formats = es8374_FORMATS, |
| }, |
| .capture = { |
| .stream_name = "Capture", |
| .channels_min = 1, |
| .channels_max = 2, |
| .rates = es8374_RATES, |
| .formats = es8374_FORMATS, |
| }, |
| .ops = &es8374_ops, |
| .symmetric_rates = 1, |
| }, |
| }; |
| |
| static int es8374_suspend(struct snd_soc_codec *codec) |
| { |
| #if 0 |
| // snd_soc_write(codec, ES8374_DAC_VOLUME_REG38, 0xc0); |
| // snd_soc_write(codec, ES8374_ADC_VOLUME_REG25, 0xc0); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG36, 0x20); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG37, 0x21); |
| snd_soc_write(codec, ES8374_MONO_MIX_REG1A, 0x08); |
| snd_soc_write(codec, ES8374_SPK_MIX_REG1C, 0x10); |
| snd_soc_write(codec, ES8374_SPK_MIX_GAIN_REG1D, 0x10); |
| snd_soc_write(codec, ES8374_SPK_OUT_GAIN_REG1E, 0x40); |
| snd_soc_update_bits(codec, ES8374_AIN_PWR_SRC_REG21, 0xc0, 0x00); |
| snd_soc_write(codec, ES8374_ANA_PWR_CTL_REG15, 0xbf); |
| snd_soc_write(codec, ES8374_ANA_REF_REG14, 0x14); |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0x03); |
| #endif |
| return 0; |
| } |
| |
| static int es8374_resume(struct snd_soc_codec *codec) |
| { |
| #if 0 |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0x7f); |
| snd_soc_write(codec, ES8374_ANA_REF_REG14, 0x8a); |
| snd_soc_write(codec, ES8374_ANA_PWR_CTL_REG15, 0x40); |
| snd_soc_update_bits(codec, ES8374_AIN_PWR_SRC_REG21, 0xc0, 0xc0); |
| snd_soc_write(codec, ES8374_MONO_MIX_REG1A, 0xa0); |
| snd_soc_write(codec, ES8374_SPK_MIX_REG1C, 0x90); |
| snd_soc_write(codec, ES8374_SPK_MIX_GAIN_REG1D, 0x02); |
| snd_soc_write(codec, ES8374_SPK_OUT_GAIN_REG1E, 0xa0); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG36, 0x00); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG37, 0x00); |
| // snd_soc_write(codec, ES8374_DAC_VOLUME_REG38, 0x00); |
| // snd_soc_write(codec, ES8374_ADC_VOLUME_REG25, 0x00); |
| #endif |
| return 0; |
| } |
| |
| static int es8374_probe(struct snd_soc_codec *codec) |
| { |
| int ret = 0; |
| // struct es8374_private *es8374 = es8374_data; |
| struct es8374_private *es8374 = snd_soc_codec_get_drvdata(codec); |
| |
| es8374->codec = codec; |
| |
| ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); |
| if (ret < 0) |
| return ret; |
| |
| codec->cache_bypass = 1; |
| |
| snd_soc_write(codec,0x00,0x3F); //IC Rst start |
| msleep(1); //DELAY_MS |
| snd_soc_write(codec,0x00,0x03); //IC Rst stop |
| snd_soc_write(codec,0x01,0xFF); //IC clk on |
| snd_soc_write(codec,0x05,0x33); //clk div set |
| snd_soc_write(codec,0x6F,0xA0); //pll set:mode enable |
| snd_soc_write(codec,0x72,0x41); //pll set:mode set |
| snd_soc_write(codec,0x09,0x01); //pll set:reset on ,set start |
| snd_soc_write(codec,0x0C,0x17); //pll set:k |
| snd_soc_write(codec,0x0D,0xa3); //pll set:k |
| snd_soc_write(codec,0x0E,0x30); //pll set:k |
| snd_soc_write(codec,0x0A,0x88); //pll set: |
| snd_soc_write(codec,0x0B,0x07); //pll set:n |
| snd_soc_write(codec,0x09,0x41); //pll set:reset off ,set stop |
| snd_soc_write(codec,0x24,0x08); //adc set |
| snd_soc_write(codec,0x36,0x20); //dac set xiu 180614 |
| snd_soc_write(codec,0x12,0x30); //timming set |
| snd_soc_write(codec,0x13,0x20); //timming set |
| snd_soc_write(codec,0x21,0x50); //adc set: SEL LIN1 CH+PGAGAIN=0DB |
| snd_soc_write(codec,0x22,0x00); //adc set: PGA GAIN=0DB |
| snd_soc_write(codec,0x21,0x10); //adc set: SEL LIN1 CH+PGAGAIN=0DB |
| snd_soc_write(codec,0x00,0x80); // IC START |
| msleep(50); //DELAY_MS |
| |
| snd_soc_write(codec,0x02,0x08); |
| snd_soc_write(codec,0x14,0x8A); // IC START |
| snd_soc_write(codec,0x15,0x40); // IC START |
| snd_soc_write(codec,0x1A,0x08); // monoout set xiu 180614 |
| snd_soc_write(codec,0x1B,0x13); // monoout set xiu 180614 |
| snd_soc_write(codec,0x1C,0x10); // spk set xiu 180614 |
| snd_soc_write(codec,0x1D,0x10); // spk set |
| snd_soc_write(codec,0x1F,0x00); // spk set |
| snd_soc_write(codec,0x1E,0x40); // spk on |
| snd_soc_write(codec,0x28,0x1c); // alc set |
| snd_soc_write(codec,0x25,0xc0); // ADCVOLUME on |
| snd_soc_write(codec,0x38,0x00); // DACVOLUMEL on |
| snd_soc_write(codec,0x37,0x01); // dac set xiu 180614 |
| // snd_soc_write(codec,0x6D,0x60); //SEL:GPIO1=DMIC CLK OUT+SEL:GPIO2=PLL CLK OUT |
| |
| snd_soc_write(codec,0x6D,0x15); //SEL:GPIO1=HPInserted in+SEL:GPIO2=Interrupt out |
| snd_soc_write(codec,0x2C,0x05); |
| snd_soc_write(codec,0x2D,0x05); |
| // snd_soc_write(codec,0x6D,0x17); //SEL:GPIO1=HPInserted in+SEL:GPIO2=Interrupt out |
| // snd_soc_write(codec,0x2C,0x6f); |
| return ret; |
| } |
| |
| static int es8374_remove(struct snd_soc_codec *codec) |
| { |
| es8374_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| return 0; |
| } |
| |
| static struct snd_soc_codec_driver soc_codec_dev_es8374 = { |
| .probe = es8374_probe, |
| .remove = es8374_remove, |
| .suspend = es8374_suspend, |
| .resume = es8374_resume, |
| .set_bias_level = es8374_set_bias_level, |
| |
| .reg_cache_size = ARRAY_SIZE(es8374_reg_defaults), |
| .reg_word_size = sizeof(u8), |
| .reg_cache_default = es8374_reg_defaults, |
| |
| .controls = es8374_snd_controls, |
| .num_controls = ARRAY_SIZE(es8374_snd_controls), |
| .dapm_widgets = es8374_dapm_widgets, |
| .num_dapm_widgets = ARRAY_SIZE(es8374_dapm_widgets), |
| .dapm_routes = es8374_dapm_routes, |
| .num_dapm_routes = ARRAY_SIZE(es8374_dapm_routes), |
| }; |
| #ifdef CONFIG_OF |
| static struct of_device_id es8374_if_dt_ids[] = { |
| { .compatible = "ambarella,es8374", }, |
| { } |
| }; |
| #endif |
| |
| static void es8374_i2c_shutdown(struct i2c_client *i2c) |
| { |
| struct snd_soc_codec *codec; |
| struct es8374_private *es8374; |
| |
| es8374 = i2c_get_clientdata(i2c); |
| codec = es8374->codec; |
| |
| snd_soc_write(codec, ES8374_DAC_VOLUME_REG38, 0xc0); |
| snd_soc_write(codec, ES8374_ADC_VOLUME_REG25, 0xc0); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG36, 0x20); |
| snd_soc_write(codec, ES8374_DAC_CONTROL_REG37, 0x21); |
| snd_soc_write(codec, ES8374_MONO_MIX_REG1A, 0x08); |
| snd_soc_write(codec, ES8374_SPK_MIX_REG1C, 0x10); |
| snd_soc_write(codec, ES8374_SPK_MIX_GAIN_REG1D, 0x10); |
| snd_soc_write(codec, ES8374_SPK_OUT_GAIN_REG1E, 0x40); |
| snd_soc_update_bits(codec, ES8374_AIN_PWR_SRC_REG21, 0xc0, 0x00); |
| snd_soc_write(codec, ES8374_ANA_PWR_CTL_REG15, 0xbf); |
| snd_soc_write(codec, ES8374_ANA_REF_REG14, 0x14); |
| snd_soc_write(codec, ES8374_CLK_MANAGEMENT_REG01, 0x03); |
| |
| return; |
| } |
| |
| static int es8374_i2c_probe(struct i2c_client *i2c_client, |
| const struct i2c_device_id *id) |
| { |
| struct es8374_private *es8374; |
| |
| int ret = -1; |
| |
| es8374 = kzalloc(sizeof(*es8374), GFP_KERNEL); |
| if (es8374 == NULL) |
| return -ENOMEM; |
| |
| es8374->dmic_enable = es8374_mic_type; /* select the mic type */ |
| es8374->pll_div = es8374_pll_out_div; /* select the pll out divider */ |
| es8374->dvdd_pwr_vol = es8374_dvdd_supply; /* confirm the dvdd voltage for PLL */ |
| es8374->clk_id = ES8374_CLKID; /* confirm PLL used or not */ |
| |
| i2c_set_clientdata(i2c_client, es8374); |
| |
| // es8374_data = es8374; |
| |
| ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8374, |
| &es8374_dai[0], ARRAY_SIZE(es8374_dai)); |
| if (ret < 0) { |
| return ret; |
| } |
| #ifdef CONFIG_ARCH_ZX297520V3_WATCH |
| ret = gpio_request_one(ZX29_GPIO_125, GPIOF_OUT_INIT_LOW, "codec_pa"); |
| if (ret < 0) { |
| printk(KERN_ERR "Alsa es8374: codec_pa in use\n"); |
| return ret; |
| } |
| #endif |
| return ret; |
| } |
| |
| static int es8374_i2c_remove(struct i2c_client *client) |
| { |
| snd_soc_unregister_codec(&client->dev); |
| kfree(i2c_get_clientdata(client)); |
| return 0; |
| } |
| |
| static const struct i2c_device_id es8374_i2c_id[] = { |
| {"es8374", 0 }, |
| {"10ES8374:00", 0}, |
| {"10ES8374", 0}, |
| { } |
| }; |
| MODULE_DEVICE_TABLE(i2c, es8374_i2c_id); |
| |
| static struct i2c_driver es8374_i2c_driver = { |
| .driver = { |
| .name = "es8374", |
| .owner = THIS_MODULE, |
| #ifdef CONFIG_OF |
| .of_match_table = of_match_ptr(es8374_if_dt_ids), |
| #endif |
| }, |
| .shutdown = es8374_i2c_shutdown, |
| .probe = es8374_i2c_probe, |
| .remove = es8374_i2c_remove, |
| .id_table = es8374_i2c_id, |
| }; |
| |
| static int __init es8374_init(void) |
| { |
| return i2c_add_driver(&es8374_i2c_driver); |
| } |
| |
| static void __exit es8374_exit(void) |
| { |
| return i2c_del_driver(&es8374_i2c_driver); |
| } |
| |
| module_init(es8374_init); |
| module_exit(es8374_exit); |
| |
| MODULE_DESCRIPTION("ASoC es8374 driver"); |
| MODULE_AUTHOR("XianqingZheng <xqzheng@ambarella.com>"); |
| MODULE_LICENSE("GPL"); |
| |