2018-01-19 00:37:03 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017, Maxim Integrated
2018-01-03 21:39:17 +03:00
# include <linux/acpi.h>
2018-09-07 03:27:28 +03:00
# include <linux/delay.h>
2018-01-03 21:39:17 +03:00
# include <linux/i2c.h>
# include <linux/module.h>
2022-06-17 00:08:25 +03:00
# include <linux/pm_runtime.h>
2018-01-03 21:39:17 +03:00
# include <linux/regmap.h>
# include <linux/slab.h>
# include <linux/cdev.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <linux/gpio.h>
2019-07-15 12:55:56 +03:00
# include <linux/of.h>
2018-01-03 21:39:17 +03:00
# include <linux/of_gpio.h>
# include <sound/tlv.h>
# include "max98373.h"
static int max98373_dac_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
2018-01-29 07:09:48 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct max98373_priv * max98373 = snd_soc_component_get_drvdata ( component ) ;
2018-01-03 21:39:17 +03:00
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R20FF_GLOBAL_SHDN ,
MAX98373_GLOBAL_EN_MASK , 1 ) ;
2021-03-25 06:35:54 +03:00
usleep_range ( 30000 , 31000 ) ;
2018-01-03 21:39:17 +03:00
break ;
2023-04-06 18:45:35 +03:00
case SND_SOC_DAPM_PRE_PMD :
2018-01-03 21:39:17 +03:00
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R20FF_GLOBAL_SHDN ,
MAX98373_GLOBAL_EN_MASK , 0 ) ;
2021-03-25 06:35:54 +03:00
usleep_range ( 30000 , 31000 ) ;
2019-01-05 05:02:35 +03:00
max98373 - > tdm_mode = false ;
2018-01-03 21:39:17 +03:00
break ;
default :
return 0 ;
}
return 0 ;
}
static const char * const max98373_switch_text [ ] = {
" Left " , " Right " , " LeftRight " } ;
static const struct soc_enum dai_sel_enum =
SOC_ENUM_SINGLE ( MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 ,
MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT ,
3 , max98373_switch_text ) ;
static const struct snd_kcontrol_new max98373_dai_controls =
SOC_DAPM_ENUM ( " DAI Sel " , dai_sel_enum ) ;
static const struct snd_kcontrol_new max98373_vi_control =
SOC_DAPM_SINGLE ( " Switch " , MAX98373_R202C_PCM_TX_EN , 0 , 1 , 0 ) ;
static const struct snd_kcontrol_new max98373_spkfb_control =
SOC_DAPM_SINGLE ( " Switch " , MAX98373_R2043_AMP_EN , 1 , 1 , 0 ) ;
static const struct snd_soc_dapm_widget max98373_dapm_widgets [ ] = {
SND_SOC_DAPM_DAC_E ( " Amp Enable " , " HiFi Playback " ,
MAX98373_R202B_PCM_RX_EN , 0 , 0 , max98373_dac_event ,
2023-04-06 18:45:35 +03:00
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD ) ,
2018-01-03 21:39:17 +03:00
SND_SOC_DAPM_MUX ( " DAI Sel Mux " , SND_SOC_NOPM , 0 , 0 ,
& max98373_dai_controls ) ,
SND_SOC_DAPM_OUTPUT ( " BE_OUT " ) ,
SND_SOC_DAPM_AIF_OUT ( " Voltage Sense " , " HiFi Capture " , 0 ,
MAX98373_R2047_IV_SENSE_ADC_EN , 0 , 0 ) ,
SND_SOC_DAPM_AIF_OUT ( " Current Sense " , " HiFi Capture " , 0 ,
MAX98373_R2047_IV_SENSE_ADC_EN , 1 , 0 ) ,
SND_SOC_DAPM_AIF_OUT ( " Speaker FB Sense " , " HiFi Capture " , 0 ,
SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_SWITCH ( " VI Sense " , SND_SOC_NOPM , 0 , 0 ,
& max98373_vi_control ) ,
SND_SOC_DAPM_SWITCH ( " SpkFB Sense " , SND_SOC_NOPM , 0 , 0 ,
& max98373_spkfb_control ) ,
SND_SOC_DAPM_SIGGEN ( " VMON " ) ,
SND_SOC_DAPM_SIGGEN ( " IMON " ) ,
SND_SOC_DAPM_SIGGEN ( " FBMON " ) ,
} ;
2018-10-11 02:26:06 +03:00
static DECLARE_TLV_DB_SCALE ( max98373_digital_tlv , - 6350 , 50 , 1 ) ;
2018-01-03 21:39:17 +03:00
static const DECLARE_TLV_DB_RANGE ( max98373_spk_tlv ,
0 , 8 , TLV_DB_SCALE_ITEM ( 0 , 50 , 0 ) ,
9 , 10 , TLV_DB_SCALE_ITEM ( 500 , 100 , 0 ) ,
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_spkgain_max_tlv ,
0 , 9 , TLV_DB_SCALE_ITEM ( 800 , 100 , 0 ) ,
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_dht_step_size_tlv ,
0 , 1 , TLV_DB_SCALE_ITEM ( 25 , 25 , 0 ) ,
2 , 4 , TLV_DB_SCALE_ITEM ( 100 , 100 , 0 ) ,
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_dht_spkgain_min_tlv ,
0 , 9 , TLV_DB_SCALE_ITEM ( 800 , 100 , 0 ) ,
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_dht_rotation_point_tlv ,
2018-10-11 02:26:17 +03:00
0 , 1 , TLV_DB_SCALE_ITEM ( - 3000 , 500 , 0 ) ,
2 , 4 , TLV_DB_SCALE_ITEM ( - 2200 , 200 , 0 ) ,
5 , 6 , TLV_DB_SCALE_ITEM ( - 1500 , 300 , 0 ) ,
7 , 9 , TLV_DB_SCALE_ITEM ( - 1000 , 200 , 0 ) ,
10 , 13 , TLV_DB_SCALE_ITEM ( - 500 , 100 , 0 ) ,
14 , 15 , TLV_DB_SCALE_ITEM ( - 100 , 50 , 0 ) ,
2018-01-03 21:39:17 +03:00
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_limiter_thresh_tlv ,
2018-10-11 02:26:10 +03:00
0 , 15 , TLV_DB_SCALE_ITEM ( - 1500 , 100 , 0 ) ,
2018-01-03 21:39:17 +03:00
) ;
static const DECLARE_TLV_DB_RANGE ( max98373_bde_gain_tlv ,
2018-10-11 02:26:13 +03:00
0 , 60 , TLV_DB_SCALE_ITEM ( - 1500 , 25 , 0 ) ,
2018-01-03 21:39:17 +03:00
) ;
static const char * const max98373_output_voltage_lvl_text [ ] = {
" 5.43V " , " 6.09V " , " 6.83V " , " 7.67V " , " 8.60V " ,
" 9.65V " , " 10.83V " , " 12.15V " , " 13.63V " , " 15.29V "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_out_volt_enum ,
MAX98373_R203E_AMP_PATH_GAIN , 0 ,
max98373_output_voltage_lvl_text ) ;
static const char * const max98373_dht_attack_rate_text [ ] = {
" 17.5us " , " 35us " , " 70us " , " 140us " ,
" 280us " , " 560us " , " 1120us " , " 2240us "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_dht_attack_rate_enum ,
MAX98373_R20D2_DHT_ATTACK_CFG , 0 ,
max98373_dht_attack_rate_text ) ;
static const char * const max98373_dht_release_rate_text [ ] = {
" 45ms " , " 225ms " , " 450ms " , " 1150ms " ,
" 2250ms " , " 3100ms " , " 4500ms " , " 6750ms "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_dht_release_rate_enum ,
MAX98373_R20D3_DHT_RELEASE_CFG , 0 ,
max98373_dht_release_rate_text ) ;
static const char * const max98373_limiter_attack_rate_text [ ] = {
" 10us " , " 20us " , " 40us " , " 80us " ,
" 160us " , " 320us " , " 640us " , " 1.28ms " ,
" 2.56ms " , " 5.12ms " , " 10.24ms " , " 20.48ms " ,
" 40.96ms " , " 81.92ms " , " 16.384ms " , " 32.768ms "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_limiter_attack_rate_enum ,
MAX98373_R20E1_LIMITER_ATK_REL_RATES , 4 ,
max98373_limiter_attack_rate_text ) ;
static const char * const max98373_limiter_release_rate_text [ ] = {
" 40us " , " 80us " , " 160us " , " 320us " ,
" 640us " , " 1.28ms " , " 2.56ms " , " 5.120ms " ,
" 10.24ms " , " 20.48ms " , " 40.96ms " , " 81.92ms " ,
" 163.84ms " , " 327.68ms " , " 655.36ms " , " 1310.72ms "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_limiter_release_rate_enum ,
MAX98373_R20E1_LIMITER_ATK_REL_RATES , 0 ,
max98373_limiter_release_rate_text ) ;
static const char * const max98373_ADC_samplerate_text [ ] = {
" 333kHz " , " 192kHz " , " 64kHz " , " 48kHz "
} ;
static SOC_ENUM_SINGLE_DECL ( max98373_adc_samplerate_enum ,
MAX98373_R2051_MEAS_ADC_SAMPLING_RATE , 0 ,
max98373_ADC_samplerate_text ) ;
2020-12-17 10:45:56 +03:00
static int max98373_feedback_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
struct soc_mixer_control * mc =
( struct soc_mixer_control * ) kcontrol - > private_value ;
struct max98373_priv * max98373 = snd_soc_component_get_drvdata ( component ) ;
int i ;
if ( snd_soc_component_get_bias_level ( component ) = = SND_SOC_BIAS_OFF ) {
/*
* Register values will be cached before suspend . The cached value
* will be a valid value and userspace will happy with that .
*/
for ( i = 0 ; i < max98373 - > cache_num ; i + + ) {
if ( mc - > reg = = max98373 - > cache [ i ] . reg ) {
ucontrol - > value . integer . value [ 0 ] = max98373 - > cache [ i ] . val ;
return 0 ;
}
}
}
2021-01-27 16:56:20 +03:00
return snd_soc_get_volsw ( kcontrol , ucontrol ) ;
2020-12-17 10:45:56 +03:00
}
2018-01-03 21:39:17 +03:00
static const struct snd_kcontrol_new max98373_snd_controls [ ] = {
SOC_SINGLE ( " Digital Vol Sel Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_VOL_SEL_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " Volume Location Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_VOL_SEL_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " Ramp Up Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " Ramp Down Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT , 1 , 0 ) ,
2021-03-25 06:35:55 +03:00
/* Speaker Amplifier Overcurrent Automatic Restart Enable */
SOC_SINGLE ( " OVC Autorestart Switch " , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG ,
MAX98373_OVC_AUTORESTART_SHIFT , 1 , 0 ) ,
/* Thermal Shutdown Automatic Restart Enable */
SOC_SINGLE ( " THERM Autorestart Switch " , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG ,
MAX98373_THERM_AUTORESTART_SHIFT , 1 , 0 ) ,
/* Clock Monitor Automatic Restart Enable */
SOC_SINGLE ( " CMON Autorestart Switch " , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG ,
MAX98373_CMON_AUTORESTART_SHIFT , 1 , 0 ) ,
2018-01-03 21:39:17 +03:00
SOC_SINGLE ( " CLK Monitor Switch " , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG ,
MAX98373_CLOCK_MON_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " Dither Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_DSP_CFG_DITH_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " DC Blocker Switch " , MAX98373_R203F_AMP_DSP_CFG ,
MAX98373_AMP_DSP_CFG_DCBLK_SHIFT , 1 , 0 ) ,
SOC_SINGLE_TLV ( " Digital Volume " , MAX98373_R203D_AMP_DIG_VOL_CTRL ,
2018-10-11 02:26:06 +03:00
0 , 0x7F , 1 , max98373_digital_tlv ) ,
2018-01-03 21:39:17 +03:00
SOC_SINGLE_TLV ( " Speaker Volume " , MAX98373_R203E_AMP_PATH_GAIN ,
MAX98373_SPK_DIGI_GAIN_SHIFT , 10 , 0 , max98373_spk_tlv ) ,
SOC_SINGLE_TLV ( " FS Max Volume " , MAX98373_R203E_AMP_PATH_GAIN ,
MAX98373_FS_GAIN_MAX_SHIFT , 9 , 0 , max98373_spkgain_max_tlv ) ,
SOC_ENUM ( " Output Voltage " , max98373_out_volt_enum ) ,
/* Dynamic Headroom Tracking */
SOC_SINGLE ( " DHT Switch " , MAX98373_R20D4_DHT_EN ,
MAX98373_DHT_EN_SHIFT , 1 , 0 ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " DHT Min Volume " , MAX98373_R20D1_DHT_CFG ,
2018-01-03 21:39:17 +03:00
MAX98373_DHT_SPK_GAIN_MIN_SHIFT , 9 , 0 , max98373_dht_spkgain_min_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " DHT Rot Pnt Volume " , MAX98373_R20D1_DHT_CFG ,
2018-10-11 02:26:17 +03:00
MAX98373_DHT_ROT_PNT_SHIFT , 15 , 1 , max98373_dht_rotation_point_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " DHT Attack Step Volume " , MAX98373_R20D2_DHT_ATTACK_CFG ,
2018-01-03 21:39:17 +03:00
MAX98373_DHT_ATTACK_STEP_SHIFT , 4 , 0 , max98373_dht_step_size_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " DHT Release Step Volume " , MAX98373_R20D3_DHT_RELEASE_CFG ,
2018-01-03 21:39:17 +03:00
MAX98373_DHT_RELEASE_STEP_SHIFT , 4 , 0 , max98373_dht_step_size_tlv ) ,
SOC_ENUM ( " DHT Attack Rate " , max98373_dht_attack_rate_enum ) ,
SOC_ENUM ( " DHT Release Rate " , max98373_dht_release_rate_enum ) ,
/* ADC configuration */
SOC_SINGLE ( " ADC PVDD CH Switch " , MAX98373_R2056_MEAS_ADC_PVDD_CH_EN , 0 , 1 , 0 ) ,
SOC_SINGLE ( " ADC PVDD FLT Switch " , MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG ,
MAX98373_FLT_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " ADC TEMP FLT Switch " , MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG ,
MAX98373_FLT_EN_SHIFT , 1 , 0 ) ,
2020-12-17 10:45:56 +03:00
SOC_SINGLE_EXT ( " ADC PVDD " , MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK , 0 , 0xFF , 0 ,
max98373_feedback_get , NULL ) ,
SOC_SINGLE_EXT ( " ADC TEMP " , MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK , 0 , 0xFF , 0 ,
max98373_feedback_get , NULL ) ,
2018-01-03 21:39:17 +03:00
SOC_SINGLE ( " ADC PVDD FLT Coeff " , MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG ,
0 , 0x3 , 0 ) ,
SOC_SINGLE ( " ADC TEMP FLT Coeff " , MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG ,
0 , 0x3 , 0 ) ,
SOC_ENUM ( " ADC SampleRate " , max98373_adc_samplerate_enum ) ,
/* Brownout Detection Engine */
SOC_SINGLE ( " BDE Switch " , MAX98373_R20B5_BDE_EN , MAX98373_BDE_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " BDE LVL4 Mute Switch " , MAX98373_R20B2_BDE_L4_CFG_2 ,
MAX98373_LVL4_MUTE_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " BDE LVL4 Hold Switch " , MAX98373_R20B2_BDE_L4_CFG_2 ,
MAX98373_LVL4_HOLD_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " BDE LVL1 Thresh " , MAX98373_R2097_BDE_L1_THRESH , 0 , 0xFF , 0 ) ,
SOC_SINGLE ( " BDE LVL2 Thresh " , MAX98373_R2098_BDE_L2_THRESH , 0 , 0xFF , 0 ) ,
SOC_SINGLE ( " BDE LVL3 Thresh " , MAX98373_R2099_BDE_L3_THRESH , 0 , 0xFF , 0 ) ,
SOC_SINGLE ( " BDE LVL4 Thresh " , MAX98373_R209A_BDE_L4_THRESH , 0 , 0xFF , 0 ) ,
2020-12-17 10:45:56 +03:00
SOC_SINGLE_EXT ( " BDE Active Level " , MAX98373_R20B6_BDE_CUR_STATE_READBACK , 0 , 8 , 0 ,
max98373_feedback_get , NULL ) ,
2018-01-03 21:39:17 +03:00
SOC_SINGLE ( " BDE Clip Mode Switch " , MAX98373_R2092_BDE_CLIPPER_MODE , 0 , 1 , 0 ) ,
SOC_SINGLE ( " BDE Thresh Hysteresis " , MAX98373_R209B_BDE_THRESH_HYST , 0 , 0xFF , 0 ) ,
SOC_SINGLE ( " BDE Hold Time " , MAX98373_R2090_BDE_LVL_HOLD , 0 , 0xFF , 0 ) ,
SOC_SINGLE ( " BDE Attack Rate " , MAX98373_R2091_BDE_GAIN_ATK_REL_RATE , 4 , 0xF , 0 ) ,
SOC_SINGLE ( " BDE Release Rate " , MAX98373_R2091_BDE_GAIN_ATK_REL_RATE , 0 , 0xF , 0 ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL1 Clip Thresh Volume " , MAX98373_R20A9_BDE_L1_CFG_2 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL2 Clip Thresh Volume " , MAX98373_R20AC_BDE_L2_CFG_2 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL3 Clip Thresh Volume " , MAX98373_R20AF_BDE_L3_CFG_2 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL4 Clip Thresh Volume " , MAX98373_R20B2_BDE_L4_CFG_2 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL1 Clip Reduction Volume " , MAX98373_R20AA_BDE_L1_CFG_3 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL2 Clip Reduction Volume " , MAX98373_R20AD_BDE_L2_CFG_3 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL3 Clip Reduction Volume " , MAX98373_R20B0_BDE_L3_CFG_3 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL4 Clip Reduction Volume " , MAX98373_R20B3_BDE_L4_CFG_3 ,
2018-10-11 02:26:13 +03:00
0 , 0x3C , 1 , max98373_bde_gain_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL1 Limiter Thresh Volume " , MAX98373_R20A8_BDE_L1_CFG_1 ,
2018-10-11 02:26:10 +03:00
0 , 0xF , 1 , max98373_limiter_thresh_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL2 Limiter Thresh Volume " , MAX98373_R20AB_BDE_L2_CFG_1 ,
2018-10-11 02:26:10 +03:00
0 , 0xF , 1 , max98373_limiter_thresh_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL3 Limiter Thresh Volume " , MAX98373_R20AE_BDE_L3_CFG_1 ,
2018-10-11 02:26:10 +03:00
0 , 0xF , 1 , max98373_limiter_thresh_tlv ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " BDE LVL4 Limiter Thresh Volume " , MAX98373_R20B1_BDE_L4_CFG_1 ,
2018-10-11 02:26:10 +03:00
0 , 0xF , 1 , max98373_limiter_thresh_tlv ) ,
2018-01-03 21:39:17 +03:00
/* Limiter */
SOC_SINGLE ( " Limiter Switch " , MAX98373_R20E2_LIMITER_EN ,
MAX98373_LIMITER_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " Limiter Src Switch " , MAX98373_R20E0_LIMITER_THRESH_CFG ,
MAX98373_LIMITER_THRESH_SRC_SHIFT , 1 , 0 ) ,
2018-01-10 08:02:01 +03:00
SOC_SINGLE_TLV ( " Limiter Thresh Volume " , MAX98373_R20E0_LIMITER_THRESH_CFG ,
2018-01-03 21:39:17 +03:00
MAX98373_LIMITER_THRESH_SHIFT , 15 , 0 , max98373_limiter_thresh_tlv ) ,
SOC_ENUM ( " Limiter Attack Rate " , max98373_limiter_attack_rate_enum ) ,
SOC_ENUM ( " Limiter Release Rate " , max98373_limiter_release_rate_enum ) ,
} ;
static const struct snd_soc_dapm_route max98373_audio_map [ ] = {
/* Plabyack */
{ " DAI Sel Mux " , " Left " , " Amp Enable " } ,
{ " DAI Sel Mux " , " Right " , " Amp Enable " } ,
{ " DAI Sel Mux " , " LeftRight " , " Amp Enable " } ,
{ " BE_OUT " , NULL , " DAI Sel Mux " } ,
/* Capture */
{ " VI Sense " , " Switch " , " VMON " } ,
{ " VI Sense " , " Switch " , " IMON " } ,
{ " SpkFB Sense " , " Switch " , " FBMON " } ,
{ " Voltage Sense " , NULL , " VI Sense " } ,
{ " Current Sense " , NULL , " VI Sense " } ,
{ " Speaker FB Sense " , NULL , " SpkFB Sense " } ,
} ;
2020-07-08 23:32:12 +03:00
void max98373_reset ( struct max98373_priv * max98373 , struct device * dev )
2018-11-30 06:21:09 +03:00
{
int ret , reg , count ;
/* Software Reset */
ret = regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2000_SW_RESET ,
MAX98373_SOFT_RESET ,
MAX98373_SOFT_RESET ) ;
if ( ret )
dev_err ( dev , " Reset command failed. (ret:%d) \n " , ret ) ;
count = 0 ;
while ( count < 3 ) {
usleep_range ( 10000 , 11000 ) ;
/* Software Reset Verification */
ret = regmap_read ( max98373 - > regmap ,
MAX98373_R21FF_REV_ID , & reg ) ;
if ( ! ret ) {
dev_info ( dev , " Reset completed (retry:%d) \n " , count ) ;
return ;
}
count + + ;
}
dev_err ( dev , " Reset failed. (ret:%d) \n " , ret ) ;
}
2020-07-08 23:32:12 +03:00
EXPORT_SYMBOL_GPL ( max98373_reset ) ;
2018-11-30 06:21:09 +03:00
2018-01-29 07:09:48 +03:00
static int max98373_probe ( struct snd_soc_component * component )
2018-01-03 21:39:17 +03:00
{
2018-01-29 07:09:48 +03:00
struct max98373_priv * max98373 = snd_soc_component_get_drvdata ( component ) ;
2018-01-03 21:39:17 +03:00
/* Software Reset */
2018-11-30 06:21:09 +03:00
max98373_reset ( max98373 , component - > dev ) ;
2018-01-03 21:39:17 +03:00
/* IV default slot configuration */
regmap_write ( max98373 - > regmap ,
MAX98373_R2020_PCM_TX_HIZ_EN_1 ,
0xFF ) ;
regmap_write ( max98373 - > regmap ,
MAX98373_R2021_PCM_TX_HIZ_EN_2 ,
0xFF ) ;
/* L/R mix configuration */
regmap_write ( max98373 - > regmap ,
MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 ,
0x80 ) ;
regmap_write ( max98373 - > regmap ,
MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2 ,
0x1 ) ;
/* Enable DC blocker */
regmap_write ( max98373 - > regmap ,
MAX98373_R203F_AMP_DSP_CFG ,
0x3 ) ;
/* Enable IMON VMON DC blocker */
regmap_write ( max98373 - > regmap ,
MAX98373_R2046_IV_SENSE_ADC_DSP_CFG ,
0x7 ) ;
/* voltage, current slot configuration */
regmap_write ( max98373 - > regmap ,
MAX98373_R2022_PCM_TX_SRC_1 ,
( max98373 - > i_slot < < MAX98373_PCM_TX_CH_SRC_A_I_SHIFT |
max98373 - > v_slot ) & 0xFF ) ;
if ( max98373 - > v_slot < 8 )
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2020_PCM_TX_HIZ_EN_1 ,
1 < < max98373 - > v_slot , 0 ) ;
else
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2021_PCM_TX_HIZ_EN_2 ,
1 < < ( max98373 - > v_slot - 8 ) , 0 ) ;
if ( max98373 - > i_slot < 8 )
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2020_PCM_TX_HIZ_EN_1 ,
1 < < max98373 - > i_slot , 0 ) ;
else
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2021_PCM_TX_HIZ_EN_2 ,
1 < < ( max98373 - > i_slot - 8 ) , 0 ) ;
2021-03-25 06:35:55 +03:00
/* enable auto restart function by default */
regmap_write ( max98373 - > regmap ,
MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG ,
0xF ) ;
2018-01-03 21:39:17 +03:00
/* speaker feedback slot configuration */
regmap_write ( max98373 - > regmap ,
MAX98373_R2023_PCM_TX_SRC_2 ,
max98373 - > spkfb_slot & 0xFF ) ;
/* Set interleave mode */
if ( max98373 - > interleave_mode )
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2024_PCM_DATA_FMT_CFG ,
MAX98373_PCM_TX_CH_INTERLEAVE_MASK ,
MAX98373_PCM_TX_CH_INTERLEAVE_MASK ) ;
/* Speaker enable */
regmap_update_bits ( max98373 - > regmap ,
MAX98373_R2043_AMP_EN ,
MAX98373_SPK_EN_MASK , 1 ) ;
return 0 ;
}
2020-07-08 23:32:12 +03:00
const struct snd_soc_component_driver soc_codec_dev_max98373 = {
2018-01-29 07:09:48 +03:00
. probe = max98373_probe ,
. controls = max98373_snd_controls ,
. num_controls = ARRAY_SIZE ( max98373_snd_controls ) ,
. dapm_widgets = max98373_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( max98373_dapm_widgets ) ,
. dapm_routes = max98373_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( max98373_audio_map ) ,
. use_pmdown_time = 1 ,
. endianness = 1 ,
2018-01-03 21:39:17 +03:00
} ;
2020-07-08 23:32:12 +03:00
EXPORT_SYMBOL_GPL ( soc_codec_dev_max98373 ) ;
2018-01-03 21:39:17 +03:00
2022-06-17 00:08:25 +03:00
static int max98373_sdw_probe ( struct snd_soc_component * component )
{
int ret ;
ret = pm_runtime_resume ( component - > dev ) ;
if ( ret < 0 & & ret ! = - EACCES )
return ret ;
return 0 ;
}
2020-07-08 23:32:13 +03:00
const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = {
2022-06-17 00:08:25 +03:00
. probe = max98373_sdw_probe ,
2020-07-08 23:32:13 +03:00
. controls = max98373_snd_controls ,
. num_controls = ARRAY_SIZE ( max98373_snd_controls ) ,
. dapm_widgets = max98373_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( max98373_dapm_widgets ) ,
. dapm_routes = max98373_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( max98373_audio_map ) ,
. use_pmdown_time = 1 ,
. endianness = 1 ,
} ;
EXPORT_SYMBOL_GPL ( soc_codec_dev_max98373_sdw ) ;
2020-07-08 23:32:12 +03:00
void max98373_slot_config ( struct device * dev ,
struct max98373_priv * max98373 )
2018-01-03 21:39:17 +03:00
{
int value ;
if ( ! device_property_read_u32 ( dev , " maxim,vmon-slot-no " , & value ) )
max98373 - > v_slot = value & 0xF ;
else
max98373 - > v_slot = 0 ;
if ( ! device_property_read_u32 ( dev , " maxim,imon-slot-no " , & value ) )
max98373 - > i_slot = value & 0xF ;
else
max98373 - > i_slot = 1 ;
2019-09-28 23:22:30 +03:00
if ( dev - > of_node ) {
max98373 - > reset_gpio = of_get_named_gpio ( dev - > of_node ,
2019-07-15 12:55:56 +03:00
" maxim,reset-gpio " , 0 ) ;
2019-09-28 23:22:30 +03:00
if ( ! gpio_is_valid ( max98373 - > reset_gpio ) ) {
dev_err ( dev , " Looking up %s property in node %s failed %d \n " ,
" maxim,reset-gpio " , dev - > of_node - > full_name ,
max98373 - > reset_gpio ) ;
} else {
dev_dbg ( dev , " maxim,reset-gpio=%d " ,
max98373 - > reset_gpio ) ;
}
2019-07-15 12:55:56 +03:00
} else {
2019-09-28 23:22:30 +03:00
/* this makes reset_gpio as invalid */
max98373 - > reset_gpio = - 1 ;
2019-07-15 12:55:56 +03:00
}
2018-01-03 21:39:17 +03:00
if ( ! device_property_read_u32 ( dev , " maxim,spkfb-slot-no " , & value ) )
max98373 - > spkfb_slot = value & 0xF ;
else
max98373 - > spkfb_slot = 2 ;
}
2020-07-08 23:32:12 +03:00
EXPORT_SYMBOL_GPL ( max98373_slot_config ) ;
2018-01-03 21:39:17 +03:00
MODULE_DESCRIPTION ( " ALSA SoC MAX98373 driver " ) ;
MODULE_AUTHOR ( " Ryan Lee <ryans.lee@maximintegrated.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;