// SPDX-License-Identifier: GPL-2.0-only /* add2010.c -- add2010 ALSA SoC Audio driver * * Copyright 1998 Elite Semiconductor Memory Technology * * Author: ESMT Audio/Power Product BU Team */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "add2010.h" // after enable,you can use "tinymix" or "amixer" cmd to change eq mode. //#define ADD2010_CHANGE_EQ_MODE_EN static int add2010_codec_probe(struct snd_soc_component *component); #ifdef ADD2010_CHANGE_EQ_MODE_EN // eq file, add Parameter file in "codec\add2010_eq", and then include the header file. #include "add2010_eq/add2010_eq_mode_1.h" #include "add2010_eq/add2010_eq_mode_2.h" // the value range of eq mode, modify them according to your request. #define ADD2010_EQ_MODE_MIN 1 #define ADD2010_EQ_MODE_MAX 2 #endif /* Define how often to check (and clear) the fault status register (in ms) */ #define ADD2010_FAULT_CHECK_INTERVAL 500 // you can read out the register and ram data, and check them. //#define ADD2010_REG_RAM_CHECK enum add2010_type { ADD2010, }; static const char * const add2010_supply_names[] = { "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ "pvdd", /* Class-D amp and analog power supply (connected). */ }; #define ADD2010_NUM_SUPPLIES ARRAY_SIZE(add2010_supply_names) static int m_reg_tab[ADD2010_REGISTER_COUNT][2] = { {0x00, 0x00},//##State_Control_1 {0x01, 0x91},//##State_Control_2 {0x02, 0x00},//##State_Control_3 {0x03, 0x1c},//##Master_volume_control {0x04, 0x18},//##Channel_1_volume_control {0x05, 0x18},//##Channel_2_volume_control {0x06, 0x18},//##Channel_3_volume_control {0x07, 0x18},//##Channel_4_volume_control {0x08, 0x18},//##Channel_5_volume_control {0x09, 0x18},//##Channel_6_volume_control {0x0a, 0x10},//##Bass_Tone_Boost_and_Cut {0x0b, 0x10},//##Treble_Tone_Boost_and_Cut {0x0c, 0x90},//##State_Control_4 {0x0d, 0x00},//##Channel_1_configuration_registers {0x0e, 0x00},//##Channel_2_configuration_registers {0x0f, 0x00},//##Channel_3_configuration_registers {0x10, 0x00},//##Channel_4_configuration_registers {0x11, 0x00},//##Channel_5_configuration_registers {0x12, 0x00},//##Channel_6_configuration_registers {0x13, 0x00},//##Channel_7_configuration_registers {0x14, 0x00},//##Channel_8_configuration_registers {0x15, 0x6a},//##DRC1_limiter_attack/release_rate {0x16, 0x6a},//##DRC2_limiter_attack/release_rate {0x17, 0x6a},//##DRC3_limiter_attack/release_rate {0x18, 0x6a},//##DRC4_limiter_attack/release_rate {0x19, 0x10},//##State_Control_6 {0x1a, 0x70},//##State_Control_7 {0x1b, 0x00},//##State_Control_8 {0x1c, 0x00},//##State_Control_9 {0x1d, 0x00},//##Coefficient_RAM_Base_Address {0x1e, 0x00},//##Top_8-bits_of_coefficients_A1 {0x1f, 0x00},//##Middle_8-bits_of_coefficients_A1 {0x20, 0x00},//##Bottom_8-bits_of_coefficients_A1 {0x21, 0x00},//##Top_8-bits_of_coefficients_A2 {0x22, 0x00},//##Middle_8-bits_of_coefficients_A2 {0x23, 0x00},//##Bottom_8-bits_of_coefficients_A2 {0x24, 0x00},//##Top_8-bits_of_coefficients_B1 {0x25, 0x00},//##Middle_8-bits_of_coefficients_B1 {0x26, 0x00},//##Bottom_8-bits_of_coefficients_B1 {0x27, 0x00},//##Top_8-bits_of_coefficients_B2 {0x28, 0x00},//##Middle_8-bits_of_coefficients_B2 {0x29, 0x00},//##Bottom_8-bits_of_coefficients_B2 {0x2a, 0x40},//##Top_8-bits_of_coefficients_A0 {0x2b, 0x00},//##Middle_8-bits_of_coefficients_A0 {0x2c, 0x00},//##Bottom_8-bits_of_coefficients_A0 {0x2d, 0x00},//##Coefficient_RAM_R/W_control {0x2e, 0x00},//##Protection_Enable/Disable {0x2f, 0x00},//##Memory_BIST_status {0x30, 0x00},//##Memory_Test_Tor_Sensing_Time {0x31, 0x00},//##Scan_key {0x32, 0x00},//##Test_Mode_Control_Reg {0x33, 0x00},//####Test_Mode_2_Control_Reg {0x34, 0x00},//##Volume_Fine_tune {0x35, 0x00},//##Volume_Fine_tune {0x36, 0x40},//##HP_Control {0x37, 0xc8},//##Device_ID_register {0x38, 0x00},//##RAM1_test_register_address {0x39, 0x00},//##Top_8-bits_of_RAM1_Data {0x3a, 0x00},//##Middle_8-bits_of_RAM1_Data {0x3b, 0x00},//##Bottom_8-bits_of_RAM1_Data {0x3c, 0x00},//##RAM1_test_r/w_control {0x3d, 0x00},//##RAM3_test_register_address {0x3e, 0x00},//##Top_8-bits_of_RAM3_Data {0x3f, 0x00},//##Middle_8-bits_of_RAM3_Data {0x40, 0x00},//##Bottom_8-bits_of_RAM3_Data {0x41, 0x00},//##RAM3_test_r/w_control {0x42, 0x00},//##Level_Meter_Clear {0x43, 0x00},//##Power_Meter_Clear {0x44, 0x00},//##TOP_of_C1_Level_Meter {0x45, 0x31},//##Middle_of_C1_Level_Meter {0x46, 0xf6},//##Bottom_of_C1_Level_Meter {0x47, 0x00},//##TOP_of_C2_Level_Meter {0x48, 0x32},//##Middle_of_C2_Level_Meter {0x49, 0x46},//##Bottom_of_C2_Level_Meter {0x4a, 0x00},//##TOP_of_C3_Level_Meter {0x4b, 0x00},//##Middle_of_C3_Level_Meter {0x4c, 0x00},//##Bottom_of_C3_Level_Meter {0x4d, 0x00},//##TOP_of_C4_Level_Meter {0x4e, 0x00},//##Middle_of_C4_Level_Meter {0x4f, 0x00},//##Bottom_of_C4_Level_Meter {0x50, 0x00},//##TOP_of_C5_Level_Meter {0x51, 0x00},//##Middle_of_C5_Level_Meter {0x52, 0x00},//##Bottom_of_C5_Level_Meter {0x53, 0x00},//##TOP_of_C6_Level_Meter {0x54, 0x00},//##Middle_of_C6_Level_Meter {0x55, 0x00},//##Bottom_of_C6_Level_Meter {0x56, 0x00},//##TOP_of_C7_Level_Meter {0x57, 0x00},//##Middle_of_C7_Level_Meter {0x58, 0x00},//##Bottom_of_C7_Level_Meter {0x59, 0x00},//##TOP_of_C8_Level_Meter {0x5a, 0x00},//##Middle_of_C8_Level_Meter {0x5b, 0x00},//##Bottom_of_C8_Level_Meter {0x5c, 0x05},//##I2S_Data_Output_Selection_Register {0x5d, 0x00},//##Check_Status {0x5e, 0x00},//##Top_8_bits_of_DRC_CHK_set_value {0x5f, 0x00},//##Middle_8_bits_of_DRC_CHK_set_value {0x60, 0x00},//##Bottom_8_bits_of_DRC_CHK_set_value {0x61, 0x00},//##Top_8_bits_of_BEQ_CHK_set_value {0x62, 0x00},//##Middle_8_bits_of_BEQ_CHK_set_value {0x63, 0x00},//##Bottom_8_bits_of_BEQ_CHK_set_value {0x64, 0x00},//##Top_8_bits_of_DRC_CHK_result {0x65, 0x00},//##Middle_8_bits_of_DRC_CHK_result {0x66, 0x00},//##Bottom_8_bits_of_DRC_CHK_result {0x67, 0x00},//##Top_8_bits_of_BEQ_CHK_result {0x68, 0x00},//##Middle_8_bits_of_BEQ_CHK_result {0x69, 0x00},//##Bottom_8_bits_of_BEQ_CHK_result {0x6a, 0x00},//##Reserve {0x6b, 0x00},//##Reserve {0x6c, 0x00},//##Reserve {0x6d, 0x00},//##Reserve {0x6e, 0x00},//##Reserve {0x6f, 0x00},//##Reserve {0x70, 0x78},//##Dither_Signal_Setting {0x71, 0x00},//##Reserve {0x72, 0x00},//##Reserve {0x73, 0x00},//##Reserve {0x74, 0x00},//##Mono_Key_High_Byte {0x75, 0x00},//##Mono_Key_Low_Byte {0x76, 0x00},//##Reserve {0x77, 0x07},//##Hi-res_Item {0x78, 0xfc},//##Test_Mode_register {0x79, 0x58},//##VOS_Control_and_IDAC_VN_LPF_Setting {0x7a, 0x00},//##Reserve {0x7b, 0x55},//##MBIST_User_Program_Top_Byte_Even {0x7c, 0x55},//##MBIST_User_Program_Middle_Byte_Even {0x7d, 0x55},//##MBIST_User_Program_Bottom_Byte_Even {0x7e, 0x55},//##MBIST_User_Program_Top_Byte_Odd {0x7f, 0x55},//##MBIST_User_Program_Middle_Byte_Odd {0x80, 0x55},//##MBIST_User_Program_Bottom_Byte_Odd {0x81, 0x00},//##GPIO0_Control {0x82, 0x00},//##GPIO1_Control {0x83, 0x00},//##GPIO2_Control {0x84, 0xc4},//##ERROR_Register_Read_only {0x85, 0xc4},//##ERROR_Latch_Register_Read_only {0x86, 0x00},//##ERROR_Clear_Register {0x87, 0xff},//##HP_Master_Volume {0x88, 0x18},//##HP_Channel_1_Volume {0x89, 0x18},//##HP_Channel_2_Volume {0x8a, 0x18},//##HP_Channel_3_Volume {0x8b, 0x18},//##HP_Channel_4_Volume {0x8c, 0x18},//##HP_Channel_5_Volume {0x8d, 0x18},//##HP_Channel_6_Volume {0x8e, 0x00},//##HP_Volume_Fine_Tune_1 {0x8f, 0x00},//##HP_Volume_Fine_Tune_2 {0x90, 0x6a},//##SMB_Left_DRC_A/R_rate {0x91, 0x6a},//##SMB_Right_DRC_A/R_rate {0x92, 0x00},//##RAM2_Test_egister_Address {0x93, 0x00},//##Top_8-bits_of_RAM2_Data {0x94, 0x00},//##Middle_8-bits_of_RAM2_Data {0x95, 0x00},//##Bottom_8-bits_of_RAM2_Data {0x96, 0x00},//##RAM2_test_r/w_control {0x97, 0x00},//##RAM4_Test_egister_Address {0x98, 0x00},//##Top_8-bits_of_RAM4_Data {0x99, 0x00},//##Middle_8-bits_of_RAM4_Data {0x9a, 0x00},//##Bottom_8-bits_of_RAM4_Data {0x9b, 0x00},//##RAM4_test_r/w_control }; static int m_ram1_tab[][4] = { {0x00, 0x00, 0x00, 0x00},//##Channel_1_EQ1_A1 {0x01, 0x00, 0x00, 0x00},//##Channel_1_EQ1_A2 {0x02, 0x00, 0x00, 0x00},//##Channel_1_EQ1_B1 {0x03, 0x00, 0x00, 0x00},//##Channel_1_EQ1_B2 {0x04, 0x20, 0x00, 0x00},//##Channel_1_EQ1_A0 {0x05, 0x00, 0x00, 0x00},//##Channel_1_EQ2_A1 {0x06, 0x00, 0x00, 0x00},//##Channel_1_EQ2_A2 {0x07, 0x00, 0x00, 0x00},//##Channel_1_EQ2_B1 {0x08, 0x00, 0x00, 0x00},//##Channel_1_EQ2_B2 {0x09, 0x20, 0x00, 0x00},//##Channel_1_EQ2_A0 {0x0a, 0x00, 0x00, 0x00},//##Channel_1_EQ3_A1 {0x0b, 0x00, 0x00, 0x00},//##Channel_1_EQ3_A2 {0x0c, 0x00, 0x00, 0x00},//##Channel_1_EQ3_B1 {0x0d, 0x00, 0x00, 0x00},//##Channel_1_EQ3_B2 {0x0e, 0x20, 0x00, 0x00},//##Channel_1_EQ3_A0 {0x0f, 0x00, 0x00, 0x00},//##Channel_1_EQ4_A1 {0x10, 0x00, 0x00, 0x00},//##Channel_1_EQ4_A2 {0x11, 0x00, 0x00, 0x00},//##Channel_1_EQ4_B1 {0x12, 0x00, 0x00, 0x00},//##Channel_1_EQ4_B2 {0x13, 0x20, 0x00, 0x00},//##Channel_1_EQ4_A0 {0x14, 0x00, 0x00, 0x00},//##Channel_1_EQ5_A1 {0x15, 0x00, 0x00, 0x00},//##Channel_1_EQ5_A2 {0x16, 0x00, 0x00, 0x00},//##Channel_1_EQ5_B1 {0x17, 0x00, 0x00, 0x00},//##Channel_1_EQ5_B2 {0x18, 0x20, 0x00, 0x00},//##Channel_1_EQ5_A0 {0x19, 0x00, 0x00, 0x00},//##Channel_1_EQ6_A1 {0x1a, 0x00, 0x00, 0x00},//##Channel_1_EQ6_A2 {0x1b, 0x00, 0x00, 0x00},//##Channel_1_EQ6_B1 {0x1c, 0x00, 0x00, 0x00},//##Channel_1_EQ6_B2 {0x1d, 0x20, 0x00, 0x00},//##Channel_1_EQ6_A0 {0x1e, 0x00, 0x00, 0x00},//##Channel_1_EQ7_A1 {0x1f, 0x00, 0x00, 0x00},//##Channel_1_EQ7_A2 {0x20, 0x00, 0x00, 0x00},//##Channel_1_EQ7_B1 {0x21, 0x00, 0x00, 0x00},//##Channel_1_EQ7_B2 {0x22, 0x20, 0x00, 0x00},//##Channel_1_EQ7_A0 {0x23, 0x00, 0x00, 0x00},//##Channel_1_EQ8_A1 {0x24, 0x00, 0x00, 0x00},//##Channel_1_EQ8_A2 {0x25, 0x00, 0x00, 0x00},//##Channel_1_EQ8_B1 {0x26, 0x00, 0x00, 0x00},//##Channel_1_EQ8_B2 {0x27, 0x20, 0x00, 0x00},//##Channel_1_EQ8_A0 {0x28, 0x00, 0x00, 0x00},//##Channel_1_EQ9_A1 {0x29, 0x00, 0x00, 0x00},//##Channel_1_EQ9_A2 {0x2a, 0x00, 0x00, 0x00},//##Channel_1_EQ9_B1 {0x2b, 0x00, 0x00, 0x00},//##Channel_1_EQ9_B2 {0x2c, 0x20, 0x00, 0x00},//##Channel_1_EQ9_A0 {0x2d, 0x00, 0x00, 0x00},//##Channel_1_EQ10_A1 {0x2e, 0x00, 0x00, 0x00},//##Channel_1_EQ10_A2 {0x2f, 0x00, 0x00, 0x00},//##Channel_1_EQ10_B1 {0x30, 0x00, 0x00, 0x00},//##Channel_1_EQ10_B2 {0x31, 0x20, 0x00, 0x00},//##Channel_1_EQ10_A0 {0x32, 0x00, 0x00, 0x00},//##Channel_1_EQ11_A1 {0x33, 0x00, 0x00, 0x00},//##Channel_1_EQ11_A2 {0x34, 0x00, 0x00, 0x00},//##Channel_1_EQ11_B1 {0x35, 0x00, 0x00, 0x00},//##Channel_1_EQ11_B2 {0x36, 0x20, 0x00, 0x00},//##Channel_1_EQ11_A0 {0x37, 0x00, 0x00, 0x00},//##Channel_1_EQ12_A1 {0x38, 0x00, 0x00, 0x00},//##Channel_1_EQ12_A2 {0x39, 0x00, 0x00, 0x00},//##Channel_1_EQ12_B1 {0x3a, 0x00, 0x00, 0x00},//##Channel_1_EQ12_B2 {0x3b, 0x20, 0x00, 0x00},//##Channel_1_EQ12_A0 {0x3c, 0x00, 0x00, 0x00},//##Channel_1_EQ13_A1 {0x3d, 0x00, 0x00, 0x00},//##Channel_1_EQ13_A2 {0x3e, 0x00, 0x00, 0x00},//##Channel_1_EQ13_B1 {0x3f, 0x00, 0x00, 0x00},//##Channel_1_EQ13_B2 {0x40, 0x20, 0x00, 0x00},//##Channel_1_EQ13_A0 {0x41, 0x00, 0x00, 0x00},//##Channel_1_EQ14_A1 {0x42, 0x00, 0x00, 0x00},//##Channel_1_EQ14_A2 {0x43, 0x00, 0x00, 0x00},//##Channel_1_EQ14_B1 {0x44, 0x00, 0x00, 0x00},//##Channel_1_EQ14_B2 {0x45, 0x20, 0x00, 0x00},//##Channel_1_EQ14_A0 {0x46, 0x00, 0x00, 0x00},//##Channel_1_EQ15_A1 {0x47, 0x00, 0x00, 0x00},//##Channel_1_EQ15_A2 {0x48, 0x00, 0x00, 0x00},//##Channel_1_EQ15_B1 {0x49, 0x00, 0x00, 0x00},//##Channel_1_EQ15_B2 {0x4a, 0x20, 0x00, 0x00},//##Channel_1_EQ15_A0 {0x4b, 0x7f, 0xff, 0xff},//##Channel_1_Mixer1 {0x4c, 0x00, 0x00, 0x00},//##Channel_1_Mixer2 {0x4d, 0x07, 0xe8, 0x8e},//##Channel_1_Prescale {0x4e, 0x20, 0x00, 0x00},//##Channel_1_Postscale {0x4f, 0xc7, 0xb6, 0x91},//##A0_of_L_channel_SRS_HPF {0x50, 0x38, 0x49, 0x6e},//##A1_of_L_channel_SRS_HPF {0x51, 0x0c, 0x46, 0xf8},//##B1_of_L_channel_SRS_HPF {0x52, 0x0e, 0x81, 0xb9},//##A0_of_L_channel_SRS_LPF {0x53, 0xf2, 0x2c, 0x12},//##A1_of_L_channel_SRS_LPF {0x54, 0x0f, 0xca, 0xbb},//##B1_of_L_channel_SRS_LPF {0x55, 0x20, 0x00, 0x00},//##CH1.2_Power_Clipping {0x56, 0x20, 0x00, 0x00},//##CCH1.2_DRC1_Attack_threshold {0x57, 0x08, 0x00, 0x00},//##CH1.2_DRC1_Release_threshold {0x58, 0x20, 0x00, 0x00},//##CH3.4_DRC2_Attack_threshold {0x59, 0x08, 0x00, 0x00},//##CH3.4_DRC2_Release_threshold {0x5a, 0x20, 0x00, 0x00},//##CH5.6_DRC3_Attack_threshold {0x5b, 0x08, 0x00, 0x00},//##CH5.6_DRC3_Release_threshold {0x5c, 0x20, 0x00, 0x00},//##CH7.8_DRC4_Attack_threshold {0x5d, 0x08, 0x00, 0x00},//##CH7.8_DRC4_Release_threshold {0x5e, 0x00, 0x00, 0x1a},//##Noise_Gate_Attack_Level {0x5f, 0x00, 0x00, 0x53},//##Noise_Gate_Release_Level {0x60, 0x00, 0x80, 0x00},//##DRC1_Energy_Coefficient {0x61, 0x00, 0x20, 0x00},//##DRC2_Energy_Coefficient {0x62, 0x00, 0x80, 0x00},//##DRC3_Energy_Coefficient {0x63, 0x00, 0x80, 0x00},//##DRC4_Energy_Coefficient {0x64, 0x00, 0x17, 0x78},//DRC1_Power_Meter {0x65, 0x00, 0x00, 0x00},//DRC3_Power_Mete {0x66, 0x00, 0x00, 0x00},//DRC5_Power_Meter {0x67, 0x00, 0x00, 0x00},//DRC7_Power_Meter {0x68, 0x00, 0x00, 0x00},//##Channel_1_DEQ1_A1 {0x69, 0x00, 0x00, 0x00},//##Channel_1_DEQ1_A2 {0x6a, 0x00, 0x00, 0x00},//##Channel_1_DEQ1_B1 {0x6b, 0x00, 0x00, 0x00},//##Channel_1_DEQ1_B2 {0x6c, 0x20, 0x00, 0x00},//##Channel_1_DEQ1_A0 {0x6d, 0x00, 0x00, 0x00},//##Channel_1_DEQ2_A1 {0x6e, 0x00, 0x00, 0x00},//##Channel_1_DEQ2_A2 {0x6f, 0x00, 0x00, 0x00},//##Channel_1_DEQ2_B1 {0x70, 0x00, 0x00, 0x00},//##Channel_1_DEQ2_B2 {0x71, 0x20, 0x00, 0x00},//##Channel_1_DEQ2_A0 {0x72, 0x00, 0x00, 0x00},//##Channel_1_DEQ3_A1 {0x73, 0x00, 0x00, 0x00},//##Channel_1_DEQ3_A2 {0x74, 0x00, 0x00, 0x00},//##Channel_1_DEQ3_B1 {0x75, 0x00, 0x00, 0x00},//##Channel_1_DEQ3_B2 {0x76, 0x20, 0x00, 0x00},//##Channel_1_DEQ3_A0 {0x77, 0x00, 0x00, 0x00},//##Channel_1_DEQ4_A1 {0x78, 0x00, 0x00, 0x00},//##Channel_1_DEQ4_A2 {0x79, 0x00, 0x00, 0x00},//##Channel_1_DEQ4_B1 {0x7a, 0x00, 0x00, 0x00},//##Channel_1_DEQ4_B2 {0x7b, 0x20, 0x00, 0x00},//##Channel_1_DEQ4_A0 {0x7c, 0x00, 0x00, 0x00},//##Reserve {0x7d, 0x00, 0x00, 0x00},//##Reserve {0x7e, 0x00, 0x00, 0x00},//##Reserve {0x7f, 0x00, 0x00, 0x00},//##Reserve {0x80, 0x00, 0x00, 0x2d},//##Channel_1_MF_LPF1_A1 {0x81, 0x00, 0x00, 0x16},//##Channel_1_MF_LPF1_A2 {0x82, 0x3f, 0xb3, 0x6a},//##Channel_1_MF_LPF1_B1 {0x83, 0xe0, 0x4c, 0x3d},//##Channel_1_MF_LPF1_B2 {0x84, 0x00, 0x00, 0x16},//##Channel_1_MF_LPF1_A0 {0x85, 0x00, 0x00, 0x2d},//##Channel_1_MF_LPF2_A1 {0x86, 0x00, 0x00, 0x16},//##Channel_1_MF_LPF2_A2 {0x87, 0x3f, 0xb3, 0x6a},//##Channel_1_MF_LPF2_B1 {0x88, 0xe0, 0x4c, 0x3d},//##Channel_1_MF_LPF2_B2 {0x89, 0x00, 0x00, 0x16},//##Channel_1_MF_LPF2_A0 {0x8a, 0x00, 0x00, 0x00},//##Channel_1_MF_BPF1_A1 {0x8b, 0xff, 0xe5, 0x51},//##Channel_1_MF_BPF1_A2 {0x8c, 0x3f, 0xb3, 0x6a},//##Channel_1_MF_BPF1_B1 {0x8d, 0xe0, 0x4c, 0x3d},//##Channel_1_MF_BPF1_B2 {0x8e, 0x00, 0x1a, 0xaf},//##Channel_1_MF_BPF1_A0 {0x8f, 0x00, 0x00, 0x00},//##Channel_1_MF_BPF2_A1 {0x90, 0xff, 0xe5, 0x51},//##Channel_1_MF_BPF2_A2 {0x91, 0x3f, 0xb3, 0x6a},//##Channel_1_MF_BPF2_B1 {0x92, 0xe0, 0x4c, 0x3d},//##Channel_1_MF_BPF2_B2 {0x93, 0x00, 0x1a, 0xaf},//##Channel_1_MF_BPF2_A0 {0x94, 0x08, 0x00, 0x00},//##Channel_1_MF_CLIP {0x95, 0x01, 0x9a, 0xfd},//##Channel_1_MF_Gain1 {0x96, 0x08, 0x00, 0x00},//##Channel_1_MF_Gain2 {0x97, 0x0b, 0x4c, 0xe0},//##Channel_1_MF_Gain3 {0x98, 0x08, 0x00, 0x00},//##Reserve {0x99, 0x08, 0x00, 0x00},//##Reserve {0x9a, 0x00, 0x00, 0x00},//##Reserve {0x9b, 0x00, 0x00, 0x00},//##Reserve {0x9c, 0x00, 0x00, 0x00},//##Reserve {0x9d, 0x00, 0x00, 0x00},//##Reserve {0x9e, 0x00, 0x00, 0x00},//##Reserve {0x9f, 0x00, 0x00, 0x00},//##Reserve {0xa0, 0x00, 0x00, 0x00},//##Channel_1_EQ16_A1 {0xa1, 0x00, 0x00, 0x00},//##Channel_1_EQ16_A2 {0xa2, 0x00, 0x00, 0x00},//##Channel_1_EQ16_B1 {0xa3, 0x00, 0x00, 0x00},//##Channel_1_EQ16_B2 {0xa4, 0x20, 0x00, 0x00},//##Channel_1_EQ16_A0 {0xa5, 0x00, 0x00, 0x00},//##Channel_1_EQ17_A1 {0xa6, 0x00, 0x00, 0x00},//##Channel_1_EQ17_A2 {0xa7, 0x00, 0x00, 0x00},//##Channel_1_EQ17_B1 {0xa8, 0x00, 0x00, 0x00},//##Channel_1_EQ17_B2 {0xa9, 0x20, 0x00, 0x00},//##Channel_1_EQ17_A0 {0xaa, 0x00, 0x00, 0x00},//##Channel_1_EQ18_A1 {0xab, 0x00, 0x00, 0x00},//##Channel_1_EQ18_A2 {0xac, 0x00, 0x00, 0x00},//##Channel_1_EQ18_B1 {0xad, 0x00, 0x00, 0x00},//##Channel_1_EQ18_B2 {0xae, 0x20, 0x00, 0x00},//##Channel_1_EQ18_A0 {0xaf, 0x20, 0x00, 0x00},//##Channel_1_SMB_ATH {0xb0, 0x08, 0x00, 0x00},//##Channel_1_SMB_RTH {0xb1, 0x02, 0x00, 0x00},//##Channel_1_Boost_CTRL1 {0xb2, 0x00, 0x80, 0x00},//##Channel_1_Boost_CTRL2 {0xb3, 0x00, 0x20, 0x00},//##Channel_1_Boost_CTRL3 }; static int m_ram2_tab[][4] = { {0x00, 0x00, 0x00, 0x00},//##Channel_2_EQ1_A1 {0x01, 0x00, 0x00, 0x00},//##Channel_2_EQ1_A2 {0x02, 0x00, 0x00, 0x00},//##Channel_2_EQ1_B1 {0x03, 0x00, 0x00, 0x00},//##Channel_2_EQ1_B2 {0x04, 0x20, 0x00, 0x00},//##Channel_2_EQ1_A0 {0x05, 0x00, 0x00, 0x00},//##Channel_2_EQ2_A1 {0x06, 0x00, 0x00, 0x00},//##Channel_2_EQ2_A2 {0x07, 0x00, 0x00, 0x00},//##Channel_2_EQ2_B1 {0x08, 0x00, 0x00, 0x00},//##Channel_2_EQ2_B2 {0x09, 0x20, 0x00, 0x00},//##Channel_2_EQ2_A0 {0x0a, 0x00, 0x00, 0x00},//##Channel_2_EQ3_A1 {0x0b, 0x00, 0x00, 0x00},//##Channel_2_EQ3_A2 {0x0c, 0x00, 0x00, 0x00},//##Channel_2_EQ3_B1 {0x0d, 0x00, 0x00, 0x00},//##Channel_2_EQ3_B2 {0x0e, 0x20, 0x00, 0x00},//##Channel_2_EQ3_A0 {0x0f, 0x00, 0x00, 0x00},//##Channel_2_EQ4_A1 {0x10, 0x00, 0x00, 0x00},//##Channel_2_EQ4_A2 {0x11, 0x00, 0x00, 0x00},//##Channel_2_EQ4_B1 {0x12, 0x00, 0x00, 0x00},//##Channel_2_EQ4_B2 {0x13, 0x20, 0x00, 0x00},//##Channel_2_EQ4_A0 {0x14, 0x00, 0x00, 0x00},//##Channel_2_EQ5_A1 {0x15, 0x00, 0x00, 0x00},//##Channel_2_EQ5_A2 {0x16, 0x00, 0x00, 0x00},//##Channel_2_EQ5_B1 {0x17, 0x00, 0x00, 0x00},//##Channel_2_EQ5_B2 {0x18, 0x20, 0x00, 0x00},//##Channel_2_EQ5_A0 {0x19, 0x00, 0x00, 0x00},//##Channel_2_EQ6_A1 {0x1a, 0x00, 0x00, 0x00},//##Channel_2_EQ6_A2 {0x1b, 0x00, 0x00, 0x00},//##Channel_2_EQ6_B1 {0x1c, 0x00, 0x00, 0x00},//##Channel_2_EQ6_B2 {0x1d, 0x20, 0x00, 0x00},//##Channel_2_EQ6_A0 {0x1e, 0x00, 0x00, 0x00},//##Channel_2_EQ7_A1 {0x1f, 0x00, 0x00, 0x00},//##Channel_2_EQ7_A2 {0x20, 0x00, 0x00, 0x00},//##Channel_2_EQ7_B1 {0x21, 0x00, 0x00, 0x00},//##Channel_2_EQ7_B2 {0x22, 0x20, 0x00, 0x00},//##Channel_2_EQ7_A0 {0x23, 0x00, 0x00, 0x00},//##Channel_2_EQ8_A1 {0x24, 0x00, 0x00, 0x00},//##Channel_2_EQ8_A2 {0x25, 0x00, 0x00, 0x00},//##Channel_2_EQ8_B1 {0x26, 0x00, 0x00, 0x00},//##Channel_2_EQ8_B2 {0x27, 0x20, 0x00, 0x00},//##Channel_2_EQ8_A0 {0x28, 0x00, 0x00, 0x00},//##Channel_2_EQ9_A1 {0x29, 0x00, 0x00, 0x00},//##Channel_2_EQ9_A2 {0x2a, 0x00, 0x00, 0x00},//##Channel_2_EQ9_B1 {0x2b, 0x00, 0x00, 0x00},//##Channel_2_EQ9_B2 {0x2c, 0x20, 0x00, 0x00},//##Channel_2_EQ9_A0 {0x2d, 0x00, 0x00, 0x00},//##Channel_2_EQ10_A1 {0x2e, 0x00, 0x00, 0x00},//##Channel_2_EQ10_A2 {0x2f, 0x00, 0x00, 0x00},//##Channel_2_EQ10_B1 {0x30, 0x00, 0x00, 0x00},//##Channel_2_EQ10_B2 {0x31, 0x20, 0x00, 0x00},//##Channel_2_EQ10_A0 {0x32, 0x00, 0x00, 0x00},//##Channel_2_EQ11_A1 {0x33, 0x00, 0x00, 0x00},//##Channel_2_EQ11_A2 {0x34, 0x00, 0x00, 0x00},//##Channel_2_EQ11_B1 {0x35, 0x00, 0x00, 0x00},//##Channel_2_EQ11_B2 {0x36, 0x20, 0x00, 0x00},//##Channel_2_EQ11_A0 {0x37, 0x00, 0x00, 0x00},//##Channel_2_EQ12_A1 {0x38, 0x00, 0x00, 0x00},//##Channel_2_EQ12_A2 {0x39, 0x00, 0x00, 0x00},//##Channel_2_EQ12_B1 {0x3a, 0x00, 0x00, 0x00},//##Channel_2_EQ12_B2 {0x3b, 0x20, 0x00, 0x00},//##Channel_2_EQ12_A0 {0x3c, 0x00, 0x00, 0x00},//##Channel_2_EQ13_A1 {0x3d, 0x00, 0x00, 0x00},//##Channel_2_EQ13_A2 {0x3e, 0x00, 0x00, 0x00},//##Channel_2_EQ13_B1 {0x3f, 0x00, 0x00, 0x00},//##Channel_2_EQ13_B2 {0x40, 0x20, 0x00, 0x00},//##Channel_2_EQ13_A0 {0x41, 0x00, 0x00, 0x00},//##Channel_2_EQ14_A1 {0x42, 0x00, 0x00, 0x00},//##Channel_2_EQ14_A2 {0x43, 0x00, 0x00, 0x00},//##Channel_2_EQ14_B1 {0x44, 0x00, 0x00, 0x00},//##Channel_2_EQ14_B2 {0x45, 0x20, 0x00, 0x00},//##Channel_2_EQ14_A0 {0x46, 0x00, 0x00, 0x00},//##Channel_2_EQ15_A1 {0x47, 0x00, 0x00, 0x00},//##Channel_2_EQ15_A2 {0x48, 0x00, 0x00, 0x00},//##Channel_2_EQ15_B1 {0x49, 0x00, 0x00, 0x00},//##Channel_2_EQ15_B2 {0x4a, 0x20, 0x00, 0x00},//##Channel_2_EQ15_A0 {0x4b, 0x00, 0x00, 0x00},//##Channel_2_Mixer1 {0x4c, 0x7f, 0xff, 0xff},//##Channel_2_Mixer2 {0x4d, 0x07, 0xe8, 0x8e},//##Channel_2_Prescale {0x4e, 0x20, 0x00, 0x00},//##Channel_2_Postscale {0x4f, 0xc7, 0xb6, 0x91},//##A0_of_R_channel_SRS_HPF {0x50, 0x38, 0x49, 0x6e},//##A1_of_R_channel_SRS_HPF {0x51, 0x0c, 0x46, 0xf8},//##B1_of_R_channel_SRS_HPF {0x52, 0x0e, 0x81, 0xb9},//##A0_of_R_channel_SRS_LPF {0x53, 0xf2, 0x2c, 0x12},//##A1_of_R_channel_SRS_LPF {0x54, 0x0f, 0xca, 0xbb},//##B1_of_R_channel_SRS_LPF {0x55, 0x00, 0x00, 0x00},//##Reserve {0x56, 0x00, 0x00, 0x00},//##Reserve {0x57, 0x00, 0x00, 0x00},//##Reserve {0x58, 0x00, 0x00, 0x00},//##Reserve {0x59, 0x00, 0x00, 0x00},//##Reserve {0x5a, 0x00, 0x00, 0x00},//##Reserve {0x5b, 0x00, 0x00, 0x00},//##Reserve {0x5c, 0x00, 0x00, 0x00},//##Reserve {0x5d, 0x00, 0x00, 0x00},//##Reserve {0x5e, 0x00, 0x00, 0x00},//##Reserve {0x5f, 0x00, 0x00, 0x00},//##Reserve {0x60, 0x00, 0x00, 0x00},//##Reserve {0x61, 0x00, 0x00, 0x00},//##Reserve {0x62, 0x00, 0x00, 0x00},//##Reserve {0x63, 0x00, 0x00, 0x00},//##Reserve {0x64, 0x00, 0x17, 0x7c},//DRC2_Power_Meter {0x65, 0x00, 0x00, 0x00},//DRC4_Power_Mete {0x66, 0x00, 0x00, 0x00},//DRC6_Power_Meter {0x67, 0x00, 0x00, 0x00},//DRC8_Power_Meter {0x68, 0x00, 0x00, 0x00},//##Channel_2_DEQ1_A1 {0x69, 0x00, 0x00, 0x00},//##Channel_2_DEQ1_A2 {0x6a, 0x00, 0x00, 0x00},//##Channel_2_DEQ1_B1 {0x6b, 0x00, 0x00, 0x00},//##Channel_2_DEQ1_B2 {0x6c, 0x20, 0x00, 0x00},//##Channel_2_DEQ1_A0 {0x6d, 0x00, 0x00, 0x00},//##Channel_2_DEQ2_A1 {0x6e, 0x00, 0x00, 0x00},//##Channel_2_DEQ2_A2 {0x6f, 0x00, 0x00, 0x00},//##Channel_2_DEQ2_B1 {0x70, 0x00, 0x00, 0x00},//##Channel_2_DEQ2_B2 {0x71, 0x20, 0x00, 0x00},//##Channel_2_DEQ2_A0 {0x72, 0x00, 0x00, 0x00},//##Channel_2_DEQ3_A1 {0x73, 0x00, 0x00, 0x00},//##Channel_2_DEQ3_A2 {0x74, 0x00, 0x00, 0x00},//##Channel_2_DEQ3_B1 {0x75, 0x00, 0x00, 0x00},//##Channel_2_DEQ3_B2 {0x76, 0x20, 0x00, 0x00},//##Channel_2_DEQ3_A0 {0x77, 0x00, 0x00, 0x00},//##Channel_2_DEQ4_A1 {0x78, 0x00, 0x00, 0x00},//##Channel_2_DEQ4_A2 {0x79, 0x00, 0x00, 0x00},//##Channel_2_DEQ4_B1 {0x7a, 0x00, 0x00, 0x00},//##Channel_2_DEQ4_B2 {0x7b, 0x20, 0x00, 0x00},//##Channel_2_DEQ4_A0 {0x7c, 0x00, 0x00, 0x00},//##Reserve {0x7d, 0x00, 0x00, 0x00},//##Reserve {0x7e, 0x00, 0x00, 0x00},//##Reserve {0x7f, 0x00, 0x00, 0x00},//##Reserve {0x80, 0x00, 0x00, 0x2d},//##Channel_2_MF_LPF1_A1 {0x81, 0x00, 0x00, 0x16},//##Channel_2_MF_LPF1_A2 {0x82, 0x3f, 0xb3, 0x6a},//##Channel_2_MF_LPF1_B1 {0x83, 0xe0, 0x4c, 0x3d},//##Channel_2_MF_LPF1_B2 {0x84, 0x00, 0x00, 0x16},//##Channel_2_MF_LPF1_A0 {0x85, 0x00, 0x00, 0x2d},//##Channel_2_MF_LPF2_A1 {0x86, 0x00, 0x00, 0x16},//##Channel_2_MF_LPF2_A2 {0x87, 0x3f, 0xb3, 0x6a},//##Channel_2_MF_LPF2_B1 {0x88, 0xe0, 0x4c, 0x3d},//##Channel_2_MF_LPF2_B2 {0x89, 0x00, 0x00, 0x16},//##Channel_2_MF_LPF2_A0 {0x8a, 0x00, 0x00, 0x00},//##Channel_2_MF_BPF1_A1 {0x8b, 0xff, 0xe5, 0x51},//##Channel_2_MF_BPF1_A2 {0x8c, 0x3f, 0xb3, 0x6a},//##Channel_2_MF_BPF1_B1 {0x8d, 0xe0, 0x4c, 0x3d},//##Channel_2_MF_BPF1_B2 {0x8e, 0x00, 0x1a, 0xaf},//##Channel_2_MF_BPF1_A0 {0x8f, 0x00, 0x00, 0x00},//##Channel_2_MF_BPF2_A1 {0x90, 0xff, 0xe5, 0x51},//##Channel_2_MF_BPF2_A2 {0x91, 0x3f, 0xb3, 0x6a},//##Channel_2_MF_BPF2_B1 {0x92, 0xe0, 0x4c, 0x3d},//##Channel_2_MF_BPF2_B2 {0x93, 0x00, 0x1a, 0xaf},//##Channel_2_MF_BPF2_A0 {0x94, 0x08, 0x00, 0x00},//##Channel_2_MF_CLIP {0x95, 0x01, 0x9a, 0xfd},//##Channel_2_MF_Gain1 {0x96, 0x08, 0x00, 0x00},//##Channel_2_MF_Gain2 {0x97, 0x0b, 0x4c, 0xe0},//##Channel_2_MF_Gain3 {0x98, 0x08, 0x00, 0x00},//##Reserve {0x99, 0x08, 0x00, 0x00},//##Reserve {0x9a, 0x00, 0x00, 0x00},//##Reserve {0x9b, 0x00, 0x00, 0x00},//##Reserve {0x9c, 0x00, 0x00, 0x00},//##Reserve {0x9d, 0x00, 0x00, 0x00},//##Reserve {0x9e, 0x00, 0x00, 0x00},//##Reserve {0x9f, 0x00, 0x00, 0x00},//##Reserve {0xa0, 0x00, 0x00, 0x00},//##Channel_2_EQ16_A1 {0xa1, 0x00, 0x00, 0x00},//##Channel_2_EQ16_A2 {0xa2, 0x00, 0x00, 0x00},//##Channel_2_EQ16_B1 {0xa3, 0x00, 0x00, 0x00},//##Channel_2_EQ16_B2 {0xa4, 0x20, 0x00, 0x00},//##Channel_2_EQ16_A0 {0xa5, 0x00, 0x00, 0x00},//##Channel_2_EQ17_A1 {0xa6, 0x00, 0x00, 0x00},//##Channel_2_EQ17_A2 {0xa7, 0x00, 0x00, 0x00},//##Channel_2_EQ17_B1 {0xa8, 0x00, 0x00, 0x00},//##Channel_2_EQ17_B2 {0xa9, 0x20, 0x00, 0x00},//##Channel_2_EQ17_A0 {0xaa, 0x00, 0x00, 0x00},//##Channel_2_EQ18_A1 {0xab, 0x00, 0x00, 0x00},//##Channel_2_EQ18_A2 {0xac, 0x00, 0x00, 0x00},//##Channel_2_EQ18_B1 {0xad, 0x00, 0x00, 0x00},//##Channel_2_EQ18_B2 {0xae, 0x20, 0x00, 0x00},//##Channel_2_EQ18_A0 {0xaf, 0x20, 0x00, 0x00},//##Channel_2_SMB_ATH {0xb0, 0x08, 0x00, 0x00},//##Channel_2_SMB_RTH {0xb1, 0x01, 0x00, 0x00},//##Reserve {0xb2, 0x00, 0x40, 0x00},//##Reserve {0xb3, 0x00, 0x10, 0x00},//##Reserve }; struct add2010_data { struct snd_soc_component *component; struct regmap *regmap; struct i2c_client *add2010_client; enum add2010_type devtype; struct regulator_bulk_data supplies[ADD2010_NUM_SUPPLIES]; struct delayed_work fault_check_work; unsigned int last_fault; int ssz_ds; int mute; int init_done; #ifdef ADD2010_CHANGE_EQ_MODE_EN unsigned int eq_mode; unsigned char (*m_ram_tab)[4]; #endif }; static int add2010_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); unsigned int rate = params_rate(params); int ssz_ds; switch (rate) { case 44100: case 48000: ssz_ds = ADD2010_FS_48K; break; case 88200: case 96000: ssz_ds = ADD2010_FS_96K; break; default: dev_err(component->dev, "unsupported sample rate: %u\n", rate); return -EINVAL; } add2010->ssz_ds = ssz_ds; return 0; } static int add2010_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; u8 serial_format; int ret; if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { dev_vdbg(component->dev, "DAI Format master is not found\n"); return -EINVAL; } switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK)) { case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): /* 1st data bit occur one BCLK cycle after the frame sync */ serial_format = ADD2010_SAIF_I2S; break; case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF): /* * Note that although the ADD2010 does not have a dedicated DSP * mode it doesn't care about the LRCLK duty cycle during TDM * operation. Therefore we can use the device's I2S mode with * its delaying of the 1st data bit to receive DSP_A formatted * data. See device datasheet for additional details. */ serial_format = ADD2010_SAIF_I2S; break; case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF): /* * Similar to DSP_A, we can use the fact that the ADD2010 does * not care about the LRCLK duty cycle during TDM to receive * DSP_B formatted data in LEFTJ mode (no delaying of the 1st * data bit). */ serial_format = ADD2010_SAIF_LEFTJ; break; case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF): /* No delay after the frame sync */ serial_format = ADD2010_SAIF_LEFTJ; break; default: dev_vdbg(component->dev, "DAI Format is not found\n"); return -EINVAL; } dev_info(component->dev, "setting add2010 dai format ----- thj\n"); ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL1_REG, ADD2010_SAIF_FORMAT_MASK, serial_format); if (ret < 0) { dev_err(component->dev, "error setting SAIF format: %d\n", ret); return ret; } return 0; } #ifdef ADD2010_CHANGE_EQ_MODE_EN static int add2010_change_eq_mode(struct snd_soc_component *component, int channel) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int eq_seg = 0; int i = 0; int cmd = 0; for (i = 0; i < 15; i++) { // ram addr regmap_write(add2010->regmap, 0x1d, add2010->m_ram_tab[eq_seg][0]); // write A1 regmap_write(add2010->regmap, 0x1e, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, 0x1f, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, 0x20, add2010->m_ram_tab[eq_seg][3]); eq_seg += 1; // write A2 regmap_write(add2010->regmap, 0x21, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, 0x22, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, 0x23, add2010->m_ram_tab[eq_seg][3]); eq_seg += 1; // write B1 regmap_write(add2010->regmap, 0x24, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, 0x25, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, 0x26, add2010->m_ram_tab[eq_seg][3]); eq_seg += 1; // write B2 regmap_write(add2010->regmap, 0x27, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, 0x28, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, 0x29, add2010->m_ram_tab[eq_seg][3]); eq_seg += 1; // write A0 regmap_write(add2010->regmap, 0x2a, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, 0x2b, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, 0x2c, add2010->m_ram_tab[eq_seg][3]); if (channel == 1) cmd = 0x02; else if (channel == 2) cmd = 0x42; regmap_write(add2010->regmap, 0x2d, cmd); eq_seg += 1; if (eq_seg > 0x4a) break; } for (eq_seg = 0x4b; eq_seg <= 0xb3; eq_seg++) { if ((eq_seg >= 0x7c) && (eq_seg <= 0x7f)) continue; if ((eq_seg >= 0x9a) && (eq_seg <= 0x9f)) continue; regmap_write(add2010->regmap, CFADDR, add2010->m_ram_tab[eq_seg][0]); regmap_write(add2010->regmap, A1CF1, add2010->m_ram_tab[eq_seg][1]); regmap_write(add2010->regmap, A1CF2, add2010->m_ram_tab[eq_seg][2]); regmap_write(add2010->regmap, A1CF3, add2010->m_ram_tab[eq_seg][3]); if (channel == 1) cmd = 0x01; if (channel == 2) cmd = 0x41; regmap_write(add2010->regmap, CFUD, cmd); } return 0; } static int add2010_eq_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->access = (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE); uinfo->count = 1; uinfo->value.integer.min = ADD2010_EQ_MODE_MIN; uinfo->value.integer.max = ADD2010_EQ_MODE_MAX; uinfo->value.integer.step = 1; return 0; } static int add2010_eq_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = add2010->eq_mode; return 0; } static int add2010_eq_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int id_reg = 0; if ((ucontrol->value.integer.value[0] > ADD2010_EQ_MODE_MAX) || (ucontrol->value.integer.value[0] < ADD2010_EQ_MODE_MIN)) { dev_err(component->dev, "error mode value setting, please check!\n"); return -1; } id_reg = snd_soc_component_read(component, ADD2010_DEVICE_ID_REG); if ((id_reg&0xf0) != ADD2010_DEVICE_ID) { // amp i2c have not ack ,i2c error dev_err(component->dev, "error device id 0x%02x, please check!\n", id_reg); return -1; } add2010->eq_mode = ucontrol->value.integer.value[0]; dev_info(component->dev, "change add2010 eq mode = %d\n", add2010->eq_mode); if (add2010->eq_mode == 1) { add2010->m_ram_tab = eq_mode_1_ram1_tab; add2010_change_eq_mode(component, 1); #ifdef CONFIG_SND_SOC_ADD2010_2CHANNEL add2010->m_ram_tab = eq_mode_1_ram2_tab; add2010_change_eq_mode(component, 2); #endif } if (add2010->eq_mode == 2) { add2010->m_ram_tab = eq_mode_2_ram1_tab; add2010_change_eq_mode(component, 1); #ifdef CONFIG_SND_SOC_ADD2010_2CHANNEL add2010->m_ram_tab = eq_mode_2_ram2_tab; add2010_change_eq_mode(component, 2); #endif } // add your other eq mode here // ... return 0; } static const struct snd_kcontrol_new add2010_eq_mode_control[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "ADD2010 EQ Mode", // Just fake the name .info = add2010_eq_mode_info, .get = add2010_eq_mode_get, .put = add2010_eq_mode_put, }, }; #endif static int add2010_mute(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int ret = 0; add2010->mute = mute; ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, add2010->mute); if (ret < 0) { dev_err(component->dev, "error (un-)muting device: %d\n", ret); return ret; } return 0; } static int ADD2010_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uinfo) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); struct device *dev = &add2010->add2010_client->dev; if (add2010->init_done) { // add2010->mute = ; dev_err(dev, "in %s %X\n", __func__, add2010->mute); } return 0; } static int ADD2010_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); struct device *dev = &add2010->add2010_client->dev; int ret = 0; if (add2010->init_done) { add2010->mute = (ucontrol->value.integer.value[0]) ? 0x40 : 0x00; ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, add2010->mute); if (ret < 0) { dev_err(dev, "error (un-)muting device: %d\n", ret); return ret; } dev_err(dev, "in %s %X\n", __func__, add2010->mute); } return 0; } static int add2010_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret = 0; struct snd_soc_component *component = dai->component; struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); (void)substream; dev_dbg(component->dev, "%s: init_done %d, mute %X\n", __func__, add2010->init_done, add2010->mute); if (!add2010->init_done) { add2010_codec_probe(component); ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL2_REG, ADD2010_SAMPLE_FREQUENCY_MASK, add2010->ssz_ds); if (ret < 0) { dev_err(component->dev, "error setting sample rate: %d\n", ret); return ret; } add2010->init_done = 1; } ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, add2010->mute); if (ret < 0) { dev_err(component->dev, "error (un-)muting device: %d\n", ret); return ret; } return 0; } static void add2010_fault_check_work(struct work_struct *work) { struct add2010_data *add2010 = container_of(work, struct add2010_data, fault_check_work.work); struct device *dev = add2010->component->dev; struct snd_soc_component *component = add2010->component; unsigned int curr_fault; int ret; ret = regmap_read(add2010->regmap, ADD2010_FAULT_REG, &curr_fault); if (ret < 0) { dev_err(dev, "failed to read FAULT register: %d\n", ret); goto out; } /* Check/handle all errors except SAIF clock errors */ curr_fault &= ADD2010_LVDET | ADD2010_OTE | ADD2010_CLKE; /* * Only flag errors once for a given occurrence. This is needed as * the ADD2010 will take time clearing the fault condition internally * during which we don't want to bombard the system with the same * error message over and over. */ if (!(curr_fault & ADD2010_LVDET) && (add2010->last_fault & ADD2010_LVDET)) dev_crit(dev, "experienced an LVDET fault\n"); if (!(curr_fault & ADD2010_CLKE) && (add2010->last_fault & ADD2010_CLKE)) dev_crit(dev, "experienced an CLK ERROR fault\n"); if (!(curr_fault & ADD2010_OTE) && (add2010->last_fault & ADD2010_OTE)) dev_crit(dev, "experienced an over temperature fault\n"); /* Store current fault value so we can detect any changes next time */ add2010->last_fault = curr_fault; if ((curr_fault&ADD2010_LVDET) && (curr_fault&ADD2010_OTE)) goto out; // MUTE ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, ADD2010_MUTE); if (ret < 0) { dev_err(dev, "failed to MUTE AMP: %d\n", ret); goto out; } msleep(20); // UNMUTE ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, 0); if (ret < 0) { dev_err(dev, "failed to UNMUTE AMP: %d\n", ret); goto out; } out: /* Schedule the next fault check at the specified interval */ schedule_delayed_work(&add2010->fault_check_work, msecs_to_jiffies(ADD2010_FAULT_CHECK_INTERVAL)); } static int add2010_codec_probe_fake(struct snd_soc_component *component) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); add2010->component = component; return 0; } static int add2010_codec_probe(struct snd_soc_component *component) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); //unsigned int device_id, expected_device_id; int ret; int i; int reg_data; #ifdef ADD2010_REG_RAM_CHECK int ram_h8_data; int ram_m8_data; int ram_l8_data; #endif add2010->component = component; dev_info(component->dev, "shx add2010 i2c address = %p, %s!\n", component, __func__); ret = regulator_bulk_enable(ARRAY_SIZE(add2010->supplies), add2010->supplies); if (ret != 0) { dev_err(component->dev, "failed to enable supplies: %d\n", ret); return ret; } msleep(20); // software reset amp ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL5_REG, ADD2010_SW_RESET, 0); if (ret < 0) goto error_snd_soc_component_update_bits; usleep_range(5000, 5050); ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL5_REG, ADD2010_SW_RESET, ADD2010_SW_RESET); if (ret < 0) goto error_snd_soc_component_update_bits; msleep(20); // wait 20ms /* Set device to mute */ ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, ADD2010_MUTE); if (ret < 0) goto error_snd_soc_component_update_bits; // Write register table for (i = 0; i < ADD2010_REGISTER_COUNT; i++) { reg_data = m_reg_tab[i][1]; if (m_reg_tab[i][0] == 0x02) continue; ret = regmap_write(add2010->regmap, m_reg_tab[i][0], reg_data); if (ret < 0) goto error_snd_soc_component_update_bits; } // Write ram1 for (i = 0; i < ADD2010_RAM_TABLE_COUNT; i++) { regmap_write(add2010->regmap, CFADDR, m_ram1_tab[i][0]); regmap_write(add2010->regmap, A1CF1, m_ram1_tab[i][1]); regmap_write(add2010->regmap, A1CF2, m_ram1_tab[i][2]); regmap_write(add2010->regmap, A1CF3, m_ram1_tab[i][3]); regmap_write(add2010->regmap, CFUD, 0x01); } // Write ram2 for (i = 0; i < ADD2010_RAM_TABLE_COUNT; i++) { regmap_write(add2010->regmap, CFADDR, m_ram2_tab[i][0]); regmap_write(add2010->regmap, A1CF1, m_ram2_tab[i][1]); regmap_write(add2010->regmap, A1CF2, m_ram2_tab[i][2]); regmap_write(add2010->regmap, A1CF3, m_ram2_tab[i][3]); regmap_write(add2010->regmap, CFUD, 0x41); } usleep_range(2000, 2050); /* Set device to unmute */ ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, 0); if (ret < 0) goto error_snd_soc_component_update_bits; INIT_DELAYED_WORK(&add2010->fault_check_work, add2010_fault_check_work); dev_info(component->dev, "shx %s success!\n", __func__); #ifdef ADD2010_CHANGE_EQ_MODE_EN ret = snd_soc_add_component_controls(component, add2010_eq_mode_control, 1); if (ret != 0) dev_err(component->dev, "Failed to register add2010_eq_mode_control (%d)\n", ret); #endif #ifdef ADD2010_REG_RAM_CHECK msleep(1000); for (i = 0; i < ADD2010_REGISTER_COUNT; i++) { reg_data = snd_soc_component_read(component, m_reg_tab[i][0]); dev_info(component->dev, "read add2010 register {addr, data} = {0x%02x, 0x%02x}\n", m_reg_tab[i][0], reg_data); } for (i = 0; i < ADD2010_RAM_TABLE_COUNT; i++) { regmap_write(add2010->regmap, CFADDR, m_ram1_tab[i][0]); // write ram addr regmap_write(add2010->regmap, CFUD, 0x04); // write read a single ram data cmd ram_h8_data = snd_soc_component_read(component, A1CF1); ram_m8_data = snd_soc_component_read(component, A1CF2); ram_l8_data = snd_soc_component_read(component, A1CF3); dev_info(component->dev, "read add2010 ram1 {addr, H8, M8, L8} = {0x%02x, 0x%02x, 0x%02x, 0x%02x}\n", m_ram1_tab[i][0], ram_h8_data, ram_m8_data, ram_l8_data); } #endif return 0; error_snd_soc_component_update_bits: dev_err(component->dev, "error configuring device registers: %d\n", ret); //probe_fail: //regulator_bulk_disable(ARRAY_SIZE(add2010->supplies), //add2010->supplies); return ret; } static void add2010_codec_remove(struct snd_soc_component *component) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int ret; dev_info(component->dev, "add2010 codec remove ---- thj\n"); cancel_delayed_work_sync(&add2010->fault_check_work); ret = regulator_bulk_disable(ARRAY_SIZE(add2010->supplies), add2010->supplies); if (ret < 0) dev_err(component->dev, "failed to disable supplies: %d\n", ret); }; static int add2010_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int ret; if (event & SND_SOC_DAPM_POST_PMU) { dev_info(component->dev, "add2010 dac event post PMU ---- thj\n"); /* Take ADD2010 out of shutdown mode */ /* * Observe codec shutdown-to-active time. The datasheet only * lists a nominal value however just use-it as-is without * additional padding to minimize the delay introduced in * starting to play audio (actually there is other setup done * by the ASoC framework that will provide additional delays, * so we should always be safe). */ msleep(25); add2010->mute = 0; ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, 0); if (ret < 0) dev_err(component->dev, "failed to write MUTE register: %d\n", ret); /* Turn on ADD2010 periodic fault checking/handling */ add2010->last_fault = 0xFE; schedule_delayed_work(&add2010->fault_check_work, msecs_to_jiffies(ADD2010_FAULT_CHECK_INTERVAL)); } else if (event & SND_SOC_DAPM_PRE_PMD) { dev_info(component->dev, "add2010 dac event pre PMD ----- thj\n"); /* Disable ADD2010 periodic fault checking/handling */ cancel_delayed_work_sync(&add2010->fault_check_work); /* Place ADD2010 in shutdown mode to minimize current draw */ add2010->mute = ADD2010_MUTE; ret = snd_soc_component_update_bits(component, ADD2010_STATE_CTRL3_REG, ADD2010_MUTE, ADD2010_MUTE); if (ret < 0) dev_err(component->dev, "failed to write MUTE register: %d\n", ret); } return 0; } #ifdef CONFIG_PM static int add2010_suspend(struct snd_soc_component *component) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int ret; regcache_cache_only(add2010->regmap, true); regcache_mark_dirty(add2010->regmap); ret = regulator_bulk_disable(ARRAY_SIZE(add2010->supplies), add2010->supplies); if (ret < 0) dev_err(component->dev, "failed to disable supplies: %d\n", ret); return ret; } static int add2010_resume(struct snd_soc_component *component) { struct add2010_data *add2010 = snd_soc_component_get_drvdata(component); int ret; dev_info(component->dev, "add2010 resume ---- thj\n"); ret = regulator_bulk_enable(ARRAY_SIZE(add2010->supplies), add2010->supplies); if (ret < 0) { dev_err(component->dev, "failed to enable supplies: %d\n", ret); return ret; } regcache_cache_only(add2010->regmap, false); ret = regcache_sync(add2010->regmap); if (ret < 0) { dev_err(component->dev, "failed to sync regcache: %d\n", ret); return ret; } return 0; } #else #define add2010_suspend NULL #define add2010_resume NULL #endif static bool add2010_is_volatile_reg(struct device *dev, unsigned int reg) { #ifdef ADD2010_REG_RAM_CHECK if (reg < ADD2010_MAX_REG) return true; else return false; #else switch (reg) { case ADD2010_FAULT_REG: case ADD2010_STATE_CTRL1_REG: case ADD2010_STATE_CTRL2_REG: case ADD2010_STATE_CTRL3_REG: case ADD2010_STATE_CTRL5_REG: case ADD2010_DEVICE_ID_REG: return true; default: return false; } #endif } static const struct regmap_config add2010_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = ADD2010_MAX_REG, //.reg_defaults = m_reg_tab, // .cache_type = REGCACHE_RBTREE, .volatile_reg = add2010_is_volatile_reg, }; /* * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that * setting the gain below -100 dB (register value <0x7) is effectively a MUTE * as per device datasheet. */ static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); static const struct snd_kcontrol_new add2010_snd_controls[] = { SOC_SINGLE_TLV("PhoneJack Playback Volume", ADD2010_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), SOC_SINGLE_EXT("PhoneJack mute", ADD2010_VOLUME_CTRL_REG, 0, 0xff, 0, ADD2010_get_mute, ADD2010_put_mute), }; static const struct snd_soc_dapm_widget add2010_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, add2010_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_OUTPUT("OUT") }; static const struct snd_soc_dapm_route add2010_audio_map[] = { { "DAC", NULL, "DAC IN" }, { "OUT", NULL, "DAC" }, }; static const struct snd_soc_component_driver soc_component_dev_add2010 = { .probe = add2010_codec_probe_fake, .remove = add2010_codec_remove, .suspend = add2010_suspend, .resume = add2010_resume, .controls = add2010_snd_controls, .num_controls = ARRAY_SIZE(add2010_snd_controls), .dapm_widgets = add2010_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(add2010_dapm_widgets), .dapm_routes = add2010_audio_map, .num_dapm_routes = ARRAY_SIZE(add2010_audio_map), .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, .non_legacy_dai_naming = 1, }; /* PCM rates supported by the ADD2010 driver */ #define ADD2010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) /* Formats supported by ADD2010 driver */ /* * #define ADD2010_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_LE |\ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE) */ #define ADD2010_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops add2010_speaker_dai_ops = { .hw_params = add2010_hw_params, .set_fmt = add2010_set_dai_fmt, .mute_stream = add2010_mute, .prepare = add2010_prepare, }; /* * ADD2010 DAI structure * * Note that were are advertising .playback.channels_max = 2 despite this being * a mono amplifier. The reason for that is that some serial ports such as ESMT's * McASP module have a minimum number of channels (2) that they can output. * Advertising more channels than we have will allow us to interface with such * a serial port without really any negative side effects as the ADD2010 will * simply ignore any extra channel(s) asides from the one channel that is * configured to be played back. */ static struct snd_soc_dai_driver add2010_dai[] = { { .name = "add2010", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = ADD2010_RATES, .formats = ADD2010_FORMATS, }, .ops = &add2010_speaker_dai_ops, }, }; static int add2010_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct add2010_data *data; const struct regmap_config *regmap_config; int ret; int i; dev_info(dev, "shx goin %s 222 start\n", __func__); //add data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->add2010_client = client; data->devtype = id->driver_data; switch (id->driver_data) { case ADD2010: regmap_config = &add2010_regmap_config; break; default: dev_err(dev, "unexpected private driver data\n"); return -EINVAL; } data->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(data->regmap)) { ret = PTR_ERR(data->regmap); dev_err(dev, "failed to allocate register map: %d\n", ret); return ret; } for (i = 0; i < ARRAY_SIZE(data->supplies); i++) data->supplies[i].supply = add2010_supply_names[i]; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies); if (ret != 0) { dev_err(dev, "failed to request supplies: %d\n", ret); return ret; } dev_set_drvdata(dev, data); ret = devm_snd_soc_register_component(&client->dev, &soc_component_dev_add2010, add2010_dai, ARRAY_SIZE(add2010_dai)); if (ret < 0) { dev_err(dev, "failed to register component: %d\n", ret); return ret; } dev_info(dev, "shx goin %s 222 end\n", __func__); //add return 0; } static const struct i2c_device_id add2010_id[] = { { "add2010", ADD2010 }, { } }; MODULE_DEVICE_TABLE(i2c, add2010_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id add2010_of_match[] = { { .compatible = "esmt,add2010", }, { }, }; MODULE_DEVICE_TABLE(of, add2010_of_match); #endif static struct i2c_driver add2010_i2c_driver = { .driver = { .name = "add2010", .of_match_table = of_match_ptr(add2010_of_match), }, .probe = add2010_probe, .id_table = add2010_id, }; module_i2c_driver(add2010_i2c_driver); MODULE_DESCRIPTION("ADD2010 Audio amplifier driver"); MODULE_LICENSE("GPL");