| /* |
| * es8312.c -- ES8312/ES8312 ALSA SoC Audio Codec |
| * |
| * Copyright (C) 2018 Everest Semiconductor Co., Ltd |
| * |
| * Authors: David Yang(yangxiaohua@everest-semi.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 "es8312.h" |
| //#include <linux/soc/zte/pm/drv_idle.h> |
| #include "linux/soc/zte/pm/drv_idle.h" |
| #include "linux/wakelock.h" |
| |
| /* |
| * es8312 register cache |
| */ |
| static struct reg_default es8312_reg_defaults[] = { |
| { 0x00, 0x1f }, |
| { 0x01, 0x00 }, |
| { 0x02, 0x00 }, |
| { 0x03, 0x10 }, |
| { 0x04, 0x10 }, |
| { 0x05, 0x00 }, |
| { 0x06, 0x03 }, |
| { 0x07, 0x00 }, |
| { 0x08, 0xff }, |
| { 0x09, 0x00 }, |
| { 0x0a, 0x00 }, |
| { 0x0b, 0x00 }, |
| { 0x0c, 0x20 }, |
| { 0x0d, 0xfc }, |
| { 0x0e, 0x6a }, |
| { 0x0f, 0x00 }, |
| |
| { 0x10, 0x13 }, |
| { 0x11, 0x7c }, |
| { 0x12, 0x02 }, |
| { 0x13, 0x40 }, |
| { 0x14, 0x10 }, |
| { 0x15, 0x00 }, |
| { 0x16, 0x04 }, |
| { 0x17, 0x00 }, |
| { 0x18, 0x00 }, |
| { 0x19, 0x00 }, |
| { 0x1a, 0x00 }, |
| { 0x1b, 0x0c }, |
| { 0x1c, 0x4c }, |
| { 0x1d, 0x00 }, |
| { 0x1e, 0x00 }, |
| { 0x1f, 0x00 }, |
| |
| { 0x20, 0x00 }, |
| { 0x21, 0x00 }, |
| { 0x22, 0x00 }, |
| { 0x23, 0x00 }, |
| { 0x24, 0x00 }, |
| { 0x25, 0x00 }, |
| { 0x26, 0x00 }, |
| { 0x27, 0x00 }, |
| { 0x28, 0x00 }, |
| { 0x29, 0x00 }, |
| { 0x2a, 0x00 }, |
| { 0x2b, 0x00 }, |
| { 0x2c, 0x00 }, |
| { 0x2d, 0x00 }, |
| { 0x2e, 0x00 }, |
| { 0x2f, 0x00 }, |
| |
| { 0x30, 0x00 }, |
| { 0x31, 0x00 }, |
| { 0x32, 0x00 }, |
| { 0x33, 0x00 }, |
| { 0x34, 0x00 }, |
| { 0x35, 0x00 }, |
| { 0x36, 0x00 }, |
| { 0x37, 0x08 }, |
| { 0x38, 0x00 }, |
| { 0x39, 0x00 }, |
| { 0x3a, 0x00 }, |
| { 0x3b, 0x00 }, |
| { 0x3c, 0x00 }, |
| { 0x3d, 0x00 }, |
| { 0x3e, 0x00 }, |
| { 0x3f, 0x00 }, |
| |
| { 0x40, 0x00 }, |
| { 0x41, 0x00 }, |
| { 0x42, 0x00 }, |
| { 0x43, 0x00 }, |
| { 0x44, 0x00 }, |
| { 0x45, 0x00 }, |
| |
| }; |
| struct sp_config { |
| u8 spc, mmcc, spfs; |
| u32 srate; |
| u8 lrcdiv; |
| u8 sclkdiv; |
| }; |
| |
| /* codec private data */ |
| struct es8312_private { |
| struct snd_soc_codec *codec; |
| struct regmap *regmap; |
| u32 mclk; |
| bool sclkinv; |
| bool mclkinv; |
| bool dmic_enable; |
| struct mutex codec_mutex; |
| struct wake_lock pm_lock; |
| volatile int codec_active_count; |
| }; |
| |
| struct es8312_private *es8312_data; |
| struct snd_soc_codec *es8312_codec; |
| |
| static bool es8312_volatile_register(struct device *dev, |
| unsigned int reg) |
| { |
| if ((reg <= 0xff)) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| static bool es8312_readable_register(struct device *dev, |
| unsigned int reg) |
| { |
| if ((reg <= 0xff)) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| static bool es8312_writable_register(struct device *dev, |
| unsigned int reg) |
| { |
| if ((reg <= 0xff)) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| static const DECLARE_TLV_DB_SCALE(vdac_tlv, |
| -9550, 50, true); |
| static const DECLARE_TLV_DB_SCALE(vadc_tlv, |
| -9550, 50, true); |
| static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, |
| 0, 300, true); |
| static const DECLARE_TLV_DB_SCALE(fm_pga_tlv, |
| 0, 600, true); |
| static const DECLARE_TLV_DB_SCALE(mono_pga_tlv, |
| 0, 600, true); |
| static const DECLARE_TLV_DB_SCALE(adc_scale_tlv, |
| 0, 600, false); |
| static const DECLARE_TLV_DB_SCALE(alc_winsize_tlv, |
| 0, 25, false); |
| static const DECLARE_TLV_DB_SCALE(alc_maxlevel_tlv, |
| -3600, 200, false); |
| static const DECLARE_TLV_DB_SCALE(alc_minlevel_tlv, |
| -3600, 200, false); |
| static const DECLARE_TLV_DB_SCALE(alc_noisegate_tlv, |
| -9600, 600, false); |
| static const DECLARE_TLV_DB_SCALE(alc_noisegate_winsize_tlv, |
| 4200, 4200, false); |
| static const DECLARE_TLV_DB_SCALE(alc_automute_gain_tlv, |
| 4200, 4200, false); |
| static const DECLARE_TLV_DB_SCALE(adc_ramprate_tlv, |
| 0, 25, false); |
| |
| static const char * const dmic_type_txt[] = { |
| "dmic at high level", |
| "dmic at low level" |
| }; |
| static const struct soc_enum dmic_type = |
| SOC_ENUM_SINGLE(ES8312_ADC_REG15, 0, 1, dmic_type_txt); |
| |
| static const char * const automute_type_txt[] = { |
| "automute disabled", |
| "automute enable" |
| }; |
| static const struct soc_enum alc_automute_type = |
| SOC_ENUM_SINGLE(ES8312_ADC_REG18, 6, 1, automute_type_txt); |
| |
| static const char * const dacdsm_mute_type_txt[] = { |
| "mute to 8", |
| "mute to 7/9" |
| }; |
| static const struct soc_enum dacdsm_mute_type = |
| SOC_ENUM_SINGLE(ES8312_DAC_REG31, 7, 1, dacdsm_mute_type_txt); |
| |
| static const char * const aec_type_txt[] = { |
| "adc left, adc right", |
| "adc left, null right", |
| "null left, adc right", |
| "null left, null right", |
| "dac left, adc right", |
| "adc left, dac right", |
| "dac left, dac right", |
| "N/A" |
| }; |
| static const struct soc_enum aec_type = |
| SOC_ENUM_SINGLE(ES8312_GPIO_REG44, 4, 7, aec_type_txt); |
| |
| static const char * const adc2dac_sel_txt[] = { |
| "disable", |
| "adc data to dac", |
| }; |
| static const struct soc_enum adc2dac_sel = |
| SOC_ENUM_SINGLE(ES8312_GPIO_REG44, 7, 1, adc2dac_sel_txt); |
| |
| static const char * const mclk_sel_txt[] = { |
| "from mclk pin", |
| "from bclk", |
| }; |
| static const struct soc_enum mclk_src = |
| SOC_ENUM_SINGLE(ES8312_CLK_MANAGER_REG01, 7, 1, mclk_sel_txt); |
| |
| /* |
| * es8312 Controls |
| */ |
| static const struct snd_kcontrol_new es8312_snd_controls[] = { |
| SOC_SINGLE_TLV("MIC PGA GAIN", ES8312_SYSTEM_REG14, |
| 0, 10, 0, mic_pga_tlv), |
| SOC_SINGLE_TLV("FM GAIN", ES8312_SYSTEM_REG13, |
| 6, 2, 0, fm_pga_tlv), |
| SOC_SINGLE("FM Switch", ES8312_SYSTEM_REG13, 5, 1, 0), |
| SOC_SINGLE_TLV("ADC SCALE", ES8312_ADC_REG16, |
| 0, 7, 0, adc_scale_tlv), |
| SOC_ENUM("DMIC TYPE", dmic_type), |
| SOC_SINGLE_TLV("ADC RAMP RATE", ES8312_ADC_REG15, |
| 4, 15, 0, adc_ramprate_tlv), |
| SOC_SINGLE("ADC SDP MUTE", ES8312_SDPOUT_REG0A, 6, 1, 0), |
| SOC_SINGLE("ADC INVERTED", ES8312_ADC_REG16, 4, 1, 0), |
| SOC_SINGLE("ADC SYNC", ES8312_ADC_REG16, 5, 1, 1), |
| SOC_SINGLE("ADC RAM CLR", ES8312_ADC_REG16, 3, 1, 0), |
| SOC_SINGLE_TLV("ADC VOLUME", ES8312_ADC_REG17, |
| 0, 255, 0, vadc_tlv), |
| SOC_SINGLE("ALC ENABLE", ES8312_ADC_REG18, 7, 1, 0), |
| SOC_ENUM("ALC AUTOMUTE TYPE", alc_automute_type), |
| SOC_SINGLE_TLV("ALC WIN SIZE", ES8312_ADC_REG18, |
| 0, 15, 0, alc_winsize_tlv), |
| SOC_SINGLE_TLV("ALC MAX LEVEL", ES8312_ADC_REG19, |
| 4, 15, 0, alc_maxlevel_tlv), |
| SOC_SINGLE_TLV("ALC MIN LEVEL", ES8312_ADC_REG19, |
| 0, 15, 0, alc_minlevel_tlv), |
| SOC_SINGLE_TLV("ALC AUTOMUTE WINSIZE", ES8312_ADC_REG1A, |
| 4, 15, 0, alc_noisegate_winsize_tlv), |
| SOC_SINGLE_TLV("ALC AUTOMUTE GATE THRESHOLD", ES8312_ADC_REG1A, |
| 0, 15, 0, alc_noisegate_tlv), |
| SOC_SINGLE_TLV("ALC AUTOMUTE VOLUME", ES8312_ADC_REG1B, |
| 5, 7, 0, alc_automute_gain_tlv), |
| SOC_SINGLE("ADC FS MODE", ES8312_CLK_MANAGER_REG03, 6, 1, 0), |
| SOC_SINGLE("ADC OSR", ES8312_CLK_MANAGER_REG03, 0, 63, 0), |
| SOC_SINGLE("DAC SDP MUTE", ES8312_SDPIN_REG09, 6, 1, 0), |
| SOC_SINGLE("DAC DEM MUTE", ES8312_DAC_REG31, 5, 1, 0), |
| SOC_SINGLE("DAC INVERT", ES8312_DAC_REG31, 4, 1, 0), |
| SOC_SINGLE("DAC RAM CLR", ES8312_DAC_REG31, 3, 1, 0), |
| SOC_ENUM("DAC DSM MUTE", dacdsm_mute_type), |
| SOC_SINGLE("DAC OFFSET", ES8312_DAC_REG33, 0, 255, 0), |
| SOC_SINGLE_TLV("DAC VOLUME", ES8312_DAC_REG32, |
| 0, 255, 0, vdac_tlv), |
| SOC_SINGLE("DRC ENABLE", ES8312_DAC_REG34, 7, 1, 0), |
| SOC_SINGLE_TLV("DRC WIN SIZE", ES8312_DAC_REG34, |
| 0, 15, 0, alc_winsize_tlv), |
| SOC_SINGLE_TLV("DRC MAX LEVEL", ES8312_DAC_REG35, |
| 4, 15, 0, alc_maxlevel_tlv), |
| SOC_SINGLE_TLV("DRC MIN LEVEL", ES8312_DAC_REG35, |
| 0, 15, 0, alc_minlevel_tlv), |
| SOC_SINGLE_TLV("DAC RAMP RATE", ES8312_DAC_REG37, |
| 4, 15, 0, adc_ramprate_tlv), |
| SOC_SINGLE("DAC OSR", ES8312_CLK_MANAGER_REG04, 0, 127, 0), |
| SOC_ENUM("AEC MODE", aec_type), |
| SOC_ENUM("ADC DATA TO DAC TEST MODE", adc2dac_sel), |
| SOC_SINGLE("MCLK INVERT", ES8312_CLK_MANAGER_REG01, 6, 1, 0), |
| SOC_SINGLE("BCLK INVERT", ES8312_CLK_MANAGER_REG06, 5, 1, 0), |
| // SOC_ENUM("MCLK SOURCE", mclk_src), |
| }; |
| |
| /* |
| * adc line in selection |
| */ |
| static const char * const es8312_adc_input_src_txt[] = { |
| "NO-IN", |
| "MIC1P-MIC1N", |
| "MIC2P-MIC2N", |
| "MIC1-MIC2", |
| }; |
| static const unsigned int es8312_adc_input_src_values[] = { |
| 0, 1, 2, 3}; |
| static const struct soc_enum es8312_adc_input_src_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_SYSTEM_REG14, 4, 3, |
| ARRAY_SIZE(es8312_adc_input_src_txt), |
| es8312_adc_input_src_txt, |
| es8312_adc_input_src_values); |
| static const struct snd_kcontrol_new es8312_adc_input_src_controls = |
| SOC_DAPM_ENUM("Route", es8312_adc_input_src_enum); |
| |
| /* |
| * DAPM Controls |
| */ |
| static const char * const es8312_dmic_mux_txt[] = { |
| "DMIC DISABLE", |
| "DMIC ENABLE" |
| }; |
| static const unsigned int es8312_dmic_mux_values[] = { |
| 0, 1 |
| }; |
| static const struct soc_enum es8312_dmic_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_SYSTEM_REG14, 6, 1, |
| ARRAY_SIZE(es8312_dmic_mux_txt), |
| es8312_dmic_mux_txt, |
| es8312_dmic_mux_values); |
| static const struct snd_kcontrol_new es8312_dmic_mux_controls = |
| SOC_DAPM_ENUM("DMIC ROUTE", es8312_dmic_mux_enum); |
| |
| static const char * const es8312_adc_sdp_mux_txt[] = { |
| "FROM EQUALIZER", |
| "FROM ADC OUT", |
| }; |
| static const unsigned int es8312_adc_sdp_mux_values[] = { |
| 0, 1 |
| }; |
| static const struct soc_enum es8312_adc_sdp_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_ADC_REG1C, 6, 1, |
| ARRAY_SIZE(es8312_adc_sdp_mux_txt), |
| es8312_adc_sdp_mux_txt, |
| es8312_adc_sdp_mux_values); |
| static const struct snd_kcontrol_new es8312_adc_sdp_mux_controls = |
| SOC_DAPM_ENUM("ADC SDP ROUTE", es8312_adc_sdp_mux_enum); |
| |
| /* |
| * alc on/off |
| */ |
| static const char * const es8312_alc_enable_txt[] = { |
| "ALC OFF", |
| "ALC ON", |
| }; |
| static const unsigned int es8312_alc_enable_values[] = { |
| 0, 1}; |
| static const struct soc_enum es8312_alc_enable_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_ADC_REG18, 7, 1, |
| ARRAY_SIZE(es8312_alc_enable_txt), |
| es8312_alc_enable_txt, |
| es8312_alc_enable_values); |
| static const struct snd_kcontrol_new es8312_alc_enable_controls = |
| SOC_DAPM_ENUM("Route", es8312_alc_enable_enum); |
| |
| /* |
| * DAC data soure |
| */ |
| static const char * const es8312_dac_data_mux_txt[] = { |
| "SELECT SDP LEFT DATA", |
| "SELECT SDP RIGHT DATA", |
| }; |
| static const unsigned int es8312_dac_data_mux_values[] = { |
| 0, 1 |
| }; |
| static const struct soc_enum es8312_dac_data_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_SDPIN_REG09, 7, 1, |
| ARRAY_SIZE(es8312_dac_data_mux_txt), |
| es8312_dac_data_mux_txt, |
| es8312_dac_data_mux_values); |
| static const struct snd_kcontrol_new es8312_dac_data_mux_controls = |
| SOC_DAPM_ENUM("DAC SDP ROUTE", es8312_dac_data_mux_enum); |
| |
| |
| /* |
| * DRC |
| */ |
| static const char * const es8312_drc_mux_txt[] = { |
| "DRC DISABLE", |
| "DRC ENABLE", |
| }; |
| static const unsigned int es8312_drc_mux_values[] = { |
| 0, 1 |
| }; |
| static const struct soc_enum es8312_drc_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_DAC_REG34, 7, 1, |
| ARRAY_SIZE(es8312_drc_mux_txt), |
| es8312_drc_mux_txt, |
| es8312_drc_mux_values); |
| static const struct snd_kcontrol_new es8312_drc_mux_controls = |
| SOC_DAPM_ENUM("DRC MUX ROUTE", es8312_drc_mux_enum); |
| |
| /* |
| * Dac eq |
| */ |
| static const char * const es8312_dac_eq_mux_txt[] = { |
| "DAC EQ ENABLE", |
| "DAC EQ BYPASS", |
| }; |
| static const unsigned int es8312_dac_eq_mux_values[] = { |
| 0,1 |
| }; |
| static const struct soc_enum es8312_dac_eq_mux_enum = |
| SOC_VALUE_ENUM_SINGLE(ES8312_DAC_REG37, 3, 1, |
| ARRAY_SIZE(es8312_dac_eq_mux_txt), |
| es8312_dac_eq_mux_txt, |
| es8312_dac_eq_mux_values); |
| static const struct snd_kcontrol_new es8312_dac_eq_mux_controls = |
| SOC_DAPM_ENUM("DAC EQ MUX ROUTE", es8312_dac_eq_mux_enum); |
| |
| |
| |
| static const struct snd_soc_dapm_widget es8312_dapm_widgets[] = { |
| /* Input*/ |
| SND_SOC_DAPM_INPUT("DMIC"), |
| SND_SOC_DAPM_INPUT("AMIC"), |
| |
| /* Input MUX */ |
| SND_SOC_DAPM_MUX("DIFFERENTIAL MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_adc_input_src_controls), |
| |
| SND_SOC_DAPM_PGA("INPUT PGA", SND_SOC_NOPM, |
| 0, 0, NULL, 0), |
| /* ADCs */ |
| SND_SOC_DAPM_ADC("MONO ADC", NULL, SND_SOC_NOPM, 0, 0), |
| /* Dmic MUX */ |
| SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_dmic_mux_controls), |
| /* Dmic MUX */ |
| SND_SOC_DAPM_MUX("ALC MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_alc_enable_controls), |
| |
| /* sdp MUX */ |
| SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_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, |
| &es8312_dac_data_mux_controls), |
| |
| SND_SOC_DAPM_MUX("DRC MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_drc_mux_controls), |
| SND_SOC_DAPM_MUX("DAC EQ MUX", SND_SOC_NOPM, 0, 0, |
| &es8312_dac_eq_mux_controls), |
| |
| SND_SOC_DAPM_DAC("MONO DAC", NULL, SND_SOC_NOPM, 0, 0), |
| |
| /* Output Lines */ |
| SND_SOC_DAPM_OUTPUT("DIFFERENTIAL OUT"), |
| |
| }; |
| |
| |
| static const struct snd_soc_dapm_route es8312_dapm_routes[] = { |
| /* record route map */ |
| |
| {"DIFFERENTIAL MUX", "MIC1P-MIC1N", "AMIC"}, |
| {"DIFFERENTIAL MUX", "MIC2P-MIC2N", "AMIC"}, |
| {"DIFFERENTIAL MUX", "MIC1-MIC2", "AMIC"}, |
| |
| {"INPUT PGA", NULL, "DIFFERENTIAL MUX"}, |
| {"MONO ADC", NULL, "INPUT PGA"}, |
| {"DMIC MUX", "DMIC DISABLE", "MONO ADC"}, |
| {"DMIC MUX", "DMIC ENABLE", "DMIC"}, |
| |
| /* Alc Mux */ |
| {"ALC MUX", "ALC OFF", "DMIC MUX"}, |
| {"ALC MUX", "ALC ON", "DMIC MUX"}, |
| |
| /* |
| * Equalizer path |
| */ |
| {"SDP OUT MUX", "FROM EQUALIZER", "ALC MUX"}, |
| {"SDP OUT MUX", "FROM ADC OUT", "ALC 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"}, |
| |
| {"DRC MUX", "DRC DISABLE", "DAC SDP SRC MUX"}, |
| {"DRC MUX", "DRC ENABLE", "DAC SDP SRC MUX"}, |
| |
| {"DAC EQ MUX", "DAC EQ BYPASS", "DRC MUX"}, |
| {"DAC EQ MUX", "DAC EQ ENABLE", "DRC MUX"}, |
| |
| {"MONO DAC", NULL, "DAC EQ MUX"}, |
| {"DIFFERENTIAL OUT", NULL, "MONO DAC"}, |
| }; |
| |
| struct _coeff_div { |
| u32 mclk; /* mclk frequency */ |
| u32 rate; /* sample rate */ |
| u8 prediv; /* the pre divider with range from 1 to 8 */ |
| u8 premulti; /* the pre multiplier with x1, x2, x4 and x8 selection */ |
| u8 adcdiv; /* adcclk divider */ |
| u8 dacdiv; /* dacclk divider */ |
| u8 fsmode; /* double speed or single speed, =0, ss, =1, ds */ |
| u8 lrck_h; /* adclrck divider and daclrck divider */ |
| u8 lrck_l; |
| u8 bclkdiv; /* sclk divider */ |
| u8 adcosr; /* adc osr */ |
| u8 dacosr; /* dac osr */ |
| }; |
| |
| |
| /* codec hifi mclk clock divider coefficients */ |
| static const struct _coeff_div coeff_div[] = { |
| //mclk rate prediv mult adcdiv dacdiv fsmode lrch lrcl bckdiv osr |
| /* 8k */ |
| //{26000000, 8000 , 0x05, 0x08, 0x0d, 0x0d, 0x00, 0x01, 0xff, 0x04, 0x19, 0x19}, |
| {26000000, 8000 , 0x06, 0x01, 0x02, 0x02, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| //{26000000, 8000 , 0x05, 0x08, 0x0d, 0x0d, 0x00, 0x01, 0x8f, 0x04, 0x14, 0x14}, |
| {24576000, 8000 , 0x06, 0x01, 0x02, 0x02, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 8000 , 0x06, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 8000 , 0x03, 0x02, 0x03, 0x03, 0x00, 0x01, 0xff, 0x18, 0x10, 0x10}, |
| {16384000, 8000 , 0x08, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {8192000 , 8000 , 0x04, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 8000 , 0x03, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {4096000 , 8000 , 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {2048000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 8000 , 0x03, 0x04, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| {1024000 , 8000 , 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 11.025k */ |
| {26000000, 11025, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 11025, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {5644800 , 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2822400 , 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1411200 , 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 12k */ |
| {26000000, 12000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x19, 0x19}, |
| {24576000, 12000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 16k */ |
| {26000000, 16000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 16000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, |
| {16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {8192000 , 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {4096000 , 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2048000 , 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1024000 , 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 22.05k */ |
| {26000000, 22050, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 22050, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {5644800 , 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2822400 , 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1411200 , 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 24k */ |
| {26000000, 24000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 24000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 32k */ |
| {26000000, 32000, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 32000, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, |
| {16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {8192000 , 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {4096000 , 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2048000 , 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, |
| {1024000 , 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 44.1k */ |
| {26000000, 44100, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 44100, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {5644800 , 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2822400 , 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1411200 , 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 48k */ |
| {26000000, 48000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 48000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| |
| /* 64k */ |
| {26000000, 64000, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 64000, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, |
| {16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {8192000 , 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, |
| {4096000 , 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, |
| {2048000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18}, |
| {1024000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, |
| |
| /* 88.2k */ |
| {26000000, 88200, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 88200, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {5644800 , 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {2822400 , 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1411200 , 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, |
| |
| /* 96k */ |
| {26000000, 96000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {24576000, 96000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {6144000 , 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {3072000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, |
| {1536000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, |
| }; |
| 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 es8312_set_dai_sysclk(struct snd_soc_dai *dai, |
| int clk_id, unsigned int freq, int dir) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| printk("Enter into %s() freq =%d\n", __func__, freq); |
| |
| if (clk_id == ES8312_CLKID_BCLK) |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x80, 0x80); |
| else if (clk_id == ES8312_CLKID_MCLK) |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x80, 0x00); |
| |
| es8312->mclk = freq; |
| #if 0 |
| switch (freq) { |
| case 11289600: |
| case 22579200: |
| es8312->mclk = freq; |
| return 0; |
| |
| case 12288000: |
| case 16384000: |
| case 18432000: |
| case 24576000: |
| case 26000000: |
| es8312->mclk = freq; |
| return 0; |
| } |
| #endif |
| return 0; |
| } |
| |
| static int es8312_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; |
| printk("Enter into %s()\n", __func__); |
| iface = snd_soc_read(codec, ES8312_RESET_REG00); |
| adciface = snd_soc_read(codec, ES8312_SDPOUT_REG0A); |
| daciface = snd_soc_read(codec, ES8312_SDPIN_REG09); |
| |
| /* set master/slave audio interface */ |
| switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| case SND_SOC_DAIFMT_CBM_CFM: /* MASTER MODE */ |
| printk("ES8312 in Master mode\n"); |
| iface |= 0x40; |
| break; |
| case SND_SOC_DAIFMT_CBS_CFS: /* SLAVE MODE */ |
| printk("ES8312 in Slave mode\n"); |
| iface &= 0xBF; |
| break; |
| default: |
| return -EINVAL; |
| } |
| snd_soc_write(codec, ES8312_RESET_REG00, iface); |
| |
| |
| /* interface format */ |
| switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| case SND_SOC_DAIFMT_I2S: |
| printk("ES8312 in I2S Format\n"); |
| adciface &= 0xFC; |
| daciface &= 0xFC; |
| break; |
| case SND_SOC_DAIFMT_RIGHT_J: |
| return -EINVAL; |
| case SND_SOC_DAIFMT_LEFT_J: |
| printk("ES8312 in LJ Format\n"); |
| adciface &= 0xFC; |
| daciface &= 0xFC; |
| adciface |= 0x01; |
| daciface |= 0x01; |
| break; |
| case SND_SOC_DAIFMT_DSP_A: |
| printk("ES8312 in DSP-A Format\n"); |
| adciface &= 0xDC; |
| daciface &= 0xDC; |
| adciface |= 0x03; |
| daciface |= 0x03; |
| break; |
| case SND_SOC_DAIFMT_DSP_B: |
| printk("ES8312 in DSP-B Format\n"); |
| adciface &= 0xDC; |
| daciface &= 0xDC; |
| adciface |= 0x23; |
| daciface |= 0x23; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| iface = snd_soc_read(codec, ES8312_CLK_MANAGER_REG06); |
| /* 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, ES8312_CLK_MANAGER_REG06, iface); |
| snd_soc_write(codec, ES8312_SDPOUT_REG0A, adciface); |
| snd_soc_write(codec, ES8312_SDPIN_REG09, daciface); |
| return 0; |
| } |
| |
| static int es8312_pcm_startup(struct snd_pcm_substream *substream, |
| struct snd_soc_dai *dai) |
| { |
| return 0; |
| } |
| |
| static int es8312_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; |
| struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| printk("Enter into %s()\n", __func__); |
| snd_soc_write(codec, ES8312_DAC_REG32, 0x00); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF); |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02); |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x00); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x08); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x00); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x1F); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00); |
| snd_soc_write(codec, ES8312_GP_REG45, 0x01); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFC); |
| return 0; |
| } |
| |
| static int es8312_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 es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| u16 iface; |
| int coeff; |
| u8 regv, datmp; |
| printk("Enter into %s()\n", __func__); |
| |
| coeff = get_coeff(es8312->mclk, params_rate(params)); |
| if (coeff < 0) { |
| printk("Unable to configure sample rate %dHz with %dHz MCLK\n", |
| params_rate(params), es8312->mclk); |
| return coeff; |
| } |
| |
| /* |
| * set clock parammeters |
| */ |
| if(coeff >= 0) { |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x83); |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG02) & 0x07; |
| regv |= (coeff_div[coeff].prediv - 1) << 5; |
| datmp = 0; |
| switch(coeff_div[coeff].premulti) |
| { |
| case 1: |
| datmp = 0; |
| break; |
| case 2: |
| datmp = 1; |
| break; |
| case 4: |
| datmp = 2; |
| break; |
| case 8: |
| datmp = 3; |
| break; |
| defalut: |
| break; |
| } |
| regv |= (datmp) << 3; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG05) & 0x00; |
| regv |= (coeff_div[coeff].adcdiv-1) << 4; |
| regv |= (coeff_div[coeff].dacdiv-1) << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG03) & 0x80; |
| regv |= coeff_div[coeff].fsmode << 6; |
| regv |= coeff_div[coeff].adcosr << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG04) & 0x80; |
| regv |= coeff_div[coeff].dacosr << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG07) & 0xf0; |
| regv |= coeff_div[coeff].lrck_h << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG07, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG08) & 0x00; |
| regv |= coeff_div[coeff].lrck_l << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG08, regv); |
| |
| regv = snd_soc_read(codec, ES8312_CLK_MANAGER_REG06) & 0xE0; |
| regv |= coeff_div[coeff].bclkdiv << 0; |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG06, regv); |
| |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x80); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F); |
| } |
| |
| if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| iface = snd_soc_read(codec, ES8312_SDPIN_REG09) & 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, ES8312_SDPIN_REG09, iface); |
| } else { |
| iface = snd_soc_read(codec, ES8312_SDPOUT_REG0A) & 0xE3; |
| /* bit size */ |
| |
| /* set iface */ |
| snd_soc_write(codec, ES8312_SDPOUT_REG0A, iface); |
| } |
| 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; |
| } |
| switch(params_rate(params)) |
| { |
| case 8000: |
| case 11025: |
| break; |
| case 16000: |
| case 24000: |
| case 48000: |
| case 22050: |
| case 44100: |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| extern void zx29_i2s_close_clk(void); |
| #ifdef CONFIG_PM |
| static void es8312_set_cpu_active(struct es8312_private *es8312) |
| { |
| mutex_lock(&es8312->codec_mutex); |
| if(es8312->codec_active_count == 0) |
| { |
| zx_cpuidle_set_busy(IDLE_FLAG_CODEC); |
| wake_lock(&es8312->pm_lock); |
| es8312->codec_active_count++; |
| } |
| mutex_unlock(&es8312->codec_mutex); |
| } |
| |
| static void es8312_set_cpu_idle(struct es8312_private *es8312) |
| { |
| mutex_lock(&es8312->codec_mutex); |
| if(es8312->codec_active_count != 0) |
| { |
| es8312->codec_active_count--; |
| zx_cpuidle_set_free(IDLE_FLAG_CODEC); |
| wake_unlock(&es8312->pm_lock); |
| } |
| mutex_unlock(&es8312->codec_mutex); |
| } |
| |
| #endif |
| static int es8312_set_bias_level(struct snd_soc_codec *codec, |
| enum snd_soc_bias_level level) |
| { |
| int regv; |
| struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| printk("Enter into %s(), level = %d\n", __func__, level); |
| switch (level) { |
| case SND_SOC_BIAS_ON: |
| snd_soc_write(codec, ES8312_GP_REG45, 0x00); |
| snd_soc_write(codec, ES8312_ADC_REG16, 0x24); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F); |
| snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x80); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01); |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, 0x3F, 0x3F); |
| if(es8312->mclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x00); |
| } |
| if(es8312->sclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x20); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x00); |
| } |
| regv = snd_soc_read(codec, ES8312_SYSTEM_REG14) & 0xCF; |
| regv |= 0x1A; |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, regv); |
| if(es8312->dmic_enable == true) { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x00); |
| } |
| snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x40); |
| snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A); |
| snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x48); |
| snd_soc_write(codec, ES8312_GPIO_REG44, 0x08); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0xBF); |
| snd_soc_write(codec, ES8312_DAC_REG32, 0xBF); |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0xc0); |
| #ifdef CONFIG_PM |
| es8312_set_cpu_active(es8312); |
| #endif |
| break; |
| case SND_SOC_BIAS_PREPARE: |
| break; |
| case SND_SOC_BIAS_STANDBY: |
| snd_soc_write(codec, ES8312_DAC_REG32, 0x00); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF); |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02); |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x00); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x08); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x00); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x1F); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00); |
| snd_soc_write(codec, ES8312_GP_REG45, 0x01); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFC); |
| zx29_i2s_close_clk(); |
| #ifdef CONFIG_PM |
| es8312_set_cpu_idle(es8312); |
| #endif |
| break; |
| case SND_SOC_BIAS_OFF: |
| break; |
| } |
| codec->dapm.bias_level = level; |
| return 0; |
| } |
| |
| static int es8312_set_tristate(struct snd_soc_dai *dai, int tristate) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| printk("Enter into %s(), tristate = %d\n", __func__, tristate); |
| if(tristate) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG07, |
| 0x30, 0x30); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG07, |
| 0x30, 0x00); |
| } |
| return 0; |
| } |
| |
| static DEFINE_RAW_SPINLOCK(codec_pa_lock); |
| static int es8312_mute(struct snd_soc_dai *dai, int mute) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| unsigned long flags; |
| |
| printk("Enter into %s(), mute = %d\n", __func__, mute); |
| if (mute) { |
| // snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02); |
| mdelay(4); |
| gpio_set_value(ZX29_GPIO_125, GPIO_LOW); |
| mdelay(1); |
| snd_soc_update_bits(codec, ES8312_DAC_REG31, 0x68, 0x68); |
| // snd_soc_write(codec, ES8312_DAC_REG32, 0x00); |
| // snd_soc_write(codec, ES8312_DAC_REG37, 0x08); |
| } else if (dai->playback_active) { |
| 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); |
| snd_soc_update_bits(codec, ES8312_DAC_REG31, 0x68, 0x00); |
| // snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00); |
| } |
| return 0; |
| } |
| |
| #define es8312_RATES SNDRV_PCM_RATE_8000_96000 |
| |
| #define es8312_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| SNDRV_PCM_FMTBIT_S24_LE) |
| |
| static struct snd_soc_dai_ops es8312_ops = { |
| .startup = es8312_pcm_startup, |
| .hw_params = es8312_pcm_hw_params, |
| .set_fmt = es8312_set_dai_fmt, |
| .set_sysclk = es8312_set_dai_sysclk, |
| .digital_mute = es8312_mute, |
| .set_tristate = es8312_set_tristate, |
| }; |
| |
| static struct snd_soc_dai_driver es8312_dai[] = { |
| { |
| .name = "ES8312 HiFi", |
| .playback = { |
| .stream_name = "Playback", |
| .channels_min = 1, |
| .channels_max = 2, |
| .rates = es8312_RATES, |
| .formats = es8312_FORMATS, |
| }, |
| .capture = { |
| .stream_name = "Capture", |
| .channels_min = 1, |
| .channels_max = 2, |
| .rates = es8312_RATES, |
| .formats = es8312_FORMATS, |
| }, |
| .ops = &es8312_ops, |
| .symmetric_rates = 1, |
| }, |
| }; |
| |
| static int es8312_suspend(struct snd_soc_codec *codec) |
| { |
| printk("Enter into %s()\n", __func__); |
| snd_soc_write(codec, ES8312_DAC_REG32, 0x00); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0xFF); |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x02); |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0xFA); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x00); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x08); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x00); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x1F); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x00); |
| snd_soc_write(codec, ES8312_GP_REG45, 0x01); |
| return 0; |
| } |
| |
| static int es8312_resume(struct snd_soc_codec *codec) |
| { |
| struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| printk("Enter into %s()\n", __func__); |
| snd_soc_write(codec, ES8312_GP_REG45, 0x00); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, 0x00); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, 0x10); |
| snd_soc_write(codec, ES8312_ADC_REG16, 0x24); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, 0x10); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F); |
| snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x80); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F); |
| if(es8312->mclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x00); |
| } |
| if(es8312->sclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x20); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x00); |
| } |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x1A); |
| if(es8312->dmic_enable == true) { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x00); |
| } |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10); |
| snd_soc_write(codec, ES8312_SDPIN_REG09, 0x00); |
| snd_soc_write(codec, ES8312_SDPOUT_REG0A, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x40); |
| snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A); |
| snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x48); |
| snd_soc_write(codec, ES8312_GPIO_REG44, 0x08); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0xBF); |
| snd_soc_write(codec, ES8312_DAC_REG32, 0xBF); |
| |
| return 0; |
| } |
| |
| static int es8312_probe(struct snd_soc_codec *codec) |
| { |
| int ret = 0; |
| struct es8312_private *es8312 = snd_soc_codec_get_drvdata(codec); |
| printk("Enter into %s()\n", __func__); |
| ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); |
| if (ret < 0) |
| return ret; |
| es8312_codec = codec; |
| es8312->codec = codec; |
| codec->cache_bypass = 1; |
| |
| snd_soc_update_bits(codec, ES8312_RESET_REG00, |
| 0x10, 0x10); |
| snd_soc_update_bits(codec, ES8312_RESET_REG00, |
| 0x10, 0x00); |
| snd_soc_write(codec, ES8312_GP_REG45, 0x00); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x30); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG02, 0x00); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG03, 0x10); |
| snd_soc_write(codec, ES8312_ADC_REG16, 0x24); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG04, 0x10); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG05, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0B, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0C, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG10, 0x1F); |
| snd_soc_write(codec, ES8312_SYSTEM_REG11, 0x7F); |
| snd_soc_write(codec, ES8312_RESET_REG00, 0x80); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0D, 0x01); |
| snd_soc_write(codec, ES8312_CLK_MANAGER_REG01, 0x3F); |
| if(es8312->mclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG01, |
| 0x40, 0x00); |
| } |
| if(es8312->sclkinv == true) { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x20); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_CLK_MANAGER_REG06, |
| 0x20, 0x00); |
| } |
| snd_soc_write(codec, ES8312_SYSTEM_REG14, 0x1A); |
| if(es8312->dmic_enable == true) { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x40); |
| } |
| else { |
| snd_soc_update_bits(codec, ES8312_SYSTEM_REG14, |
| 0x40, 0x00); |
| } |
| snd_soc_write(codec, ES8312_SYSTEM_REG12, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG13, 0x10); |
| snd_soc_write(codec, ES8312_SDPIN_REG09, 0x00); |
| snd_soc_write(codec, ES8312_SDPOUT_REG0A, 0x00); |
| snd_soc_write(codec, ES8312_SYSTEM_REG0E, 0x02); |
| snd_soc_write(codec, ES8312_ADC_REG15, 0x40); |
| snd_soc_write(codec, ES8312_ADC_REG1B, 0x0A); |
| snd_soc_write(codec, ES8312_ADC_REG1C, 0x6A); |
| snd_soc_write(codec, ES8312_DAC_REG37, 0x48); |
| snd_soc_write(codec, ES8312_GPIO_REG44, 0x08); |
| snd_soc_write(codec, ES8312_ADC_REG17, 0xBF); |
| snd_soc_write(codec, ES8312_DAC_REG32, 0xBF); |
| |
| msleep(100); |
| es8312_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| return ret; |
| } |
| |
| static int es8312_remove(struct snd_soc_codec *codec) |
| { |
| es8312_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| return 0; |
| } |
| |
| static struct snd_soc_codec_driver soc_codec_dev_es8312 = { |
| .probe = es8312_probe, |
| .remove = es8312_remove, |
| .suspend = es8312_suspend, |
| .resume = es8312_resume, |
| .set_bias_level = es8312_set_bias_level, |
| |
| .reg_cache_size = ARRAY_SIZE(es8312_reg_defaults), |
| .reg_word_size = sizeof(u8), |
| .reg_cache_default = es8312_reg_defaults, |
| .controls = es8312_snd_controls, |
| .num_controls = ARRAY_SIZE(es8312_snd_controls), |
| .dapm_widgets = es8312_dapm_widgets, |
| .num_dapm_widgets = ARRAY_SIZE(es8312_dapm_widgets), |
| .dapm_routes = es8312_dapm_routes, |
| .num_dapm_routes = ARRAY_SIZE(es8312_dapm_routes), |
| }; |
| |
| static struct regmap_config es8312_regmap = { |
| .reg_bits = 8, |
| .val_bits = 8, |
| |
| .max_register = ES8312_MAX_REGISTER, |
| .reg_defaults = es8312_reg_defaults, |
| .num_reg_defaults = ARRAY_SIZE(es8312_reg_defaults), |
| .volatile_reg = es8312_volatile_register, |
| .writeable_reg = es8312_writable_register, |
| .readable_reg = es8312_readable_register, |
| .cache_type = REGCACHE_RBTREE, |
| }; |
| |
| #ifdef CONFIG_OF |
| static struct of_device_id es8312_if_dt_ids[] = { |
| { .compatible = "ambarella,es8312", }, |
| { } |
| }; |
| #endif |
| |
| #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| static void es8312_i2c_shutdown(struct i2c_client *i2c) |
| { |
| struct snd_soc_codec *codec; |
| struct es8312_private *es8312; |
| es8312 = i2c_get_clientdata(i2c); |
| if(es8312 == NULL){ |
| printk("%s(): NULL pointer es8312\n", __FUNCTION__); |
| return; |
| } |
| codec = es8312->codec; |
| return; |
| } |
| static u32 cur_reg=0; |
| |
| static ssize_t es8312_show(struct device *dev, |
| struct device_attribute *attr, char *_buf) |
| { |
| int ret; |
| ret = sprintf(_buf, "%s(): get 0x%04x=0x%04x\n", |
| __FUNCTION__, cur_reg, |
| snd_soc_read(es8312_codec, cur_reg)); |
| return ret; |
| } |
| |
| static u32 strtol(const char *nptr, int base) |
| { |
| u32 ret; |
| if(!nptr || (base!=16 && base!=10 && base!=8)) |
| { |
| printk("%s(): NULL pointer input\n", __FUNCTION__); |
| return -1; |
| } |
| for(ret=0; *nptr; nptr++) |
| { |
| if((base==16 && *nptr>='A' && *nptr<='F') || |
| (base==16 && *nptr>='a' && *nptr<='f') || |
| (base>=10 && *nptr>='0' && *nptr<='9') || |
| (base>=8 && *nptr>='0' && *nptr<='7') ) |
| { |
| ret *= base; |
| if(base==16 && *nptr>='A' && *nptr<='F') |
| ret += *nptr-'A'+10; |
| else if(base==16 && *nptr>='a' && *nptr<='f') |
| ret += *nptr-'a'+10; |
| else if(base>=10 && *nptr>='0' && *nptr<='9') |
| ret += *nptr-'0'; |
| else if(base>=8 && *nptr>='0' && *nptr<='7') |
| ret += *nptr-'0'; |
| } |
| else |
| return ret; |
| } |
| return ret; |
| } |
| |
| static ssize_t es8312_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int val=0, flag=0; |
| u8 i=0, reg, num, value_w, value_r; |
| |
| val = simple_strtol(buf, NULL, 16); |
| flag = (val >> 16) & 0xFF; |
| |
| if (flag) { |
| reg = (val >> 8) & 0xFF; |
| value_w = val & 0xFF; |
| printk("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n", |
| reg, value_w, flag); |
| while(flag--) { |
| snd_soc_write(es8312_codec, reg, value_w); |
| printk("Write 0x%02x to REG:0x%02x\n", |
| value_w, |
| reg); |
| reg++; |
| } |
| } |
| else { |
| reg = (val >> 8) & 0xFF; |
| num = val & 0xff; |
| printk("\nRead: start REG:0x%02x,count:0x%02x\n", |
| reg, num); |
| do { |
| value_r = 0; |
| value_r = snd_soc_read(es8312_codec, reg); |
| printk("REG[0x%02x]: 0x%02x; \n", |
| reg, value_r); |
| reg++; |
| i++; |
| } while (i<num); |
| } |
| |
| return count; |
| } |
| |
| static struct device *es8312_dev = NULL; |
| static struct class *es8312_class = NULL; |
| static DEVICE_ATTR(es8312, 0664, es8312_show, es8312_store); |
| |
| static struct attribute *es8312_debug_attrs[] = { |
| &dev_attr_es8312.attr, |
| NULL, |
| }; |
| |
| static struct attribute_group es8312_debug_attr_group = { |
| .name = "es8312_debug", |
| .attrs = es8312_debug_attrs, |
| }; |
| |
| static int es8312_i2c_probe(struct i2c_client *i2c_client, |
| const struct i2c_device_id *id) |
| { |
| struct es8312_private *es8312; |
| int ret = -1; |
| printk("Enter into %s\n", __func__); |
| es8312 = devm_kzalloc(&i2c_client->dev, |
| sizeof(*es8312), GFP_KERNEL); |
| if (es8312 == NULL) |
| return -ENOMEM; |
| |
| printk("Enter into %s---1\n", __func__); |
| es8312->dmic_enable = false; // dmic interface disabled |
| /* the edge of lrck is always at the falling edge of mclk */ |
| es8312->mclkinv = false; |
| /* the edge of lrck is always at the falling edge of sclk */ |
| es8312->sclkinv = false; |
| |
| printk("Enter into %s----2\n", __func__); |
| dev_set_drvdata(&i2c_client->dev, es8312); |
| es8312_data = es8312; |
| printk("Enter into %s---3\n", __func__); |
| ret = snd_soc_register_codec(&i2c_client->dev, |
| &soc_codec_dev_es8312, |
| &es8312_dai[0], |
| ARRAY_SIZE(es8312_dai)); |
| if (ret < 0) { |
| kfree(es8312); |
| return ret; |
| } |
| |
| printk("Enter into %s-----4\n", __func__); |
| ret = sysfs_create_group(&i2c_client->dev.kobj, |
| &es8312_debug_attr_group); |
| if (ret) { |
| pr_err("failed to create attr group\n"); |
| } |
| 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; |
| } |
| #ifdef CONFIG_PM |
| es8312->codec_active_count = 0; |
| mutex_init(&es8312->codec_mutex); |
| wake_lock_init(&es8312->pm_lock,WAKE_LOCK_SUSPEND,"es8312-code"); |
| #endif |
| printk("Exit %s\n", __func__); |
| return ret; |
| } |
| |
| static int es8312_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 es8312_i2c_id[] = { |
| {"es8312", 0 }, |
| { } |
| }; |
| MODULE_DEVICE_TABLE(i2c, es8312_i2c_id); |
| |
| static struct i2c_driver es8312_i2c_driver = { |
| .driver = { |
| .name = "es8312", |
| .owner = THIS_MODULE, |
| #ifdef CONFIG_OF |
| .of_match_table = of_match_ptr(es8312_if_dt_ids), |
| #endif |
| }, |
| .shutdown = es8312_i2c_shutdown, |
| .probe = es8312_i2c_probe, |
| .remove = es8312_i2c_remove, |
| .id_table = es8312_i2c_id, |
| }; |
| #endif |
| static int __init es8312_init(void) |
| { |
| return i2c_add_driver(&es8312_i2c_driver); |
| } |
| |
| static void __exit es8312_exit(void) |
| { |
| return i2c_del_driver(&es8312_i2c_driver); |
| } |
| |
| module_init(es8312_init); |
| module_exit(es8312_exit); |
| |
| MODULE_DESCRIPTION("ASoC es8312 driver"); |
| MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); |
| MODULE_LICENSE("GPL"); |
| |