2019-01-22 14:39:10 +08:00
// SPDX-License-Identifier: GPL-2.0
//
// mt6358.c -- mt6358 ALSA SoC audio codec driver
//
// Copyright (c) 2018 MediaTek Inc.
// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
# include <linux/platform_device.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/delay.h>
# include <linux/kthread.h>
# include <linux/sched.h>
# include <linux/mfd/mt6397/core.h>
# include <linux/regulator/consumer.h>
# include <sound/soc.h>
# include <sound/tlv.h>
# include "mt6358.h"
enum {
AUDIO_ANALOG_VOLUME_HSOUTL ,
AUDIO_ANALOG_VOLUME_HSOUTR ,
AUDIO_ANALOG_VOLUME_HPOUTL ,
AUDIO_ANALOG_VOLUME_HPOUTR ,
AUDIO_ANALOG_VOLUME_LINEOUTL ,
AUDIO_ANALOG_VOLUME_LINEOUTR ,
AUDIO_ANALOG_VOLUME_MICAMP1 ,
AUDIO_ANALOG_VOLUME_MICAMP2 ,
AUDIO_ANALOG_VOLUME_TYPE_MAX
} ;
enum {
MUX_ADC_L ,
MUX_ADC_R ,
MUX_PGA_L ,
MUX_PGA_R ,
MUX_MIC_TYPE ,
MUX_HP_L ,
MUX_HP_R ,
MUX_NUM ,
} ;
enum {
DEVICE_HP ,
DEVICE_LO ,
DEVICE_RCV ,
DEVICE_MIC1 ,
DEVICE_MIC2 ,
DEVICE_NUM
} ;
/* Supply widget subseq */
enum {
/* common */
SUPPLY_SEQ_CLK_BUF ,
SUPPLY_SEQ_AUD_GLB ,
SUPPLY_SEQ_CLKSQ ,
SUPPLY_SEQ_VOW_AUD_LPW ,
SUPPLY_SEQ_AUD_VOW ,
SUPPLY_SEQ_VOW_CLK ,
SUPPLY_SEQ_VOW_LDO ,
SUPPLY_SEQ_TOP_CK ,
SUPPLY_SEQ_TOP_CK_LAST ,
SUPPLY_SEQ_AUD_TOP ,
SUPPLY_SEQ_AUD_TOP_LAST ,
SUPPLY_SEQ_AFE ,
/* capture */
SUPPLY_SEQ_ADC_SUPPLY ,
} ;
enum {
CH_L = 0 ,
CH_R ,
NUM_CH ,
} ;
# define REG_STRIDE 2
struct mt6358_priv {
struct device * dev ;
struct regmap * regmap ;
unsigned int dl_rate ;
unsigned int ul_rate ;
int ana_gain [ AUDIO_ANALOG_VOLUME_TYPE_MAX ] ;
unsigned int mux_select [ MUX_NUM ] ;
int dev_counter [ DEVICE_NUM ] ;
int mtkaif_protocol ;
struct regulator * avdd_reg ;
2019-10-19 15:02:52 +08:00
int wov_enabled ;
2020-06-05 18:33:41 +08:00
unsigned int dmic_one_wire_mode ;
2019-01-22 14:39:10 +08:00
} ;
int mt6358_set_mtkaif_protocol ( struct snd_soc_component * cmpnt ,
int mtkaif_protocol )
{
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
priv - > mtkaif_protocol = mtkaif_protocol ;
return 0 ;
}
static void playback_gpio_set ( struct mt6358_priv * priv )
{
/* set gpio mosi mode */
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE2_CLR ,
0x01f8 , 0x01f8 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE2_SET ,
0xffff , 0x0249 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE2 ,
0xffff , 0x0249 ) ;
}
static void playback_gpio_reset ( struct mt6358_priv * priv )
{
/* set pad_aud_*_mosi to GPIO mode and dir input
* reason :
* pad_aud_dat_mosi * , because the pin is used as boot strap
* don ' t clean clk / sync , for mtkaif protocol 2
*/
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE2_CLR ,
0x01f8 , 0x01f8 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE2 ,
0x01f8 , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_DIR0 ,
0xf < < 8 , 0x0 ) ;
}
static void capture_gpio_set ( struct mt6358_priv * priv )
{
/* set gpio miso mode */
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3_CLR ,
0xffff , 0xffff ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3_SET ,
0xffff , 0x0249 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3 ,
0xffff , 0x0249 ) ;
}
static void capture_gpio_reset ( struct mt6358_priv * priv )
{
/* set pad_aud_*_miso to GPIO mode and dir input
* reason :
* pad_aud_clk_miso , because when playback only the miso_clk
* will also have 26 m , so will have power leak
* pad_aud_dat_miso * , because the pin is used as boot strap
*/
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3_CLR ,
0xffff , 0xffff ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3 ,
0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_DIR0 ,
0xf < < 12 , 0x0 ) ;
}
/* use only when not govern by DAPM */
static int mt6358_set_dcxo ( struct mt6358_priv * priv , bool enable )
{
regmap_update_bits ( priv - > regmap , MT6358_DCXO_CW14 ,
0x1 < < RG_XO_AUDIO_EN_M_SFT ,
( enable ? 1 : 0 ) < < RG_XO_AUDIO_EN_M_SFT ) ;
return 0 ;
}
/* use only when not govern by DAPM */
static int mt6358_set_clksq ( struct mt6358_priv * priv , bool enable )
{
/* audio clk source from internal dcxo */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON6 ,
RG_CLKSQ_IN_SEL_TEST_MASK_SFT ,
0x0 ) ;
/* Enable/disable CLKSQ 26MHz */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON6 ,
RG_CLKSQ_EN_MASK_SFT ,
( enable ? 1 : 0 ) < < RG_CLKSQ_EN_SFT ) ;
return 0 ;
}
/* use only when not govern by DAPM */
static int mt6358_set_aud_global_bias ( struct mt6358_priv * priv , bool enable )
{
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
RG_AUDGLB_PWRDN_VA28_MASK_SFT ,
( enable ? 0 : 1 ) < < RG_AUDGLB_PWRDN_VA28_SFT ) ;
return 0 ;
}
/* use only when not govern by DAPM */
static int mt6358_set_topck ( struct mt6358_priv * priv , bool enable )
{
regmap_update_bits ( priv - > regmap , MT6358_AUD_TOP_CKPDN_CON0 ,
0x0066 , enable ? 0x0 : 0x66 ) ;
return 0 ;
}
static int mt6358_mtkaif_tx_enable ( struct mt6358_priv * priv )
{
switch ( priv - > mtkaif_protocol ) {
case MT6358_MTKAIF_PROTOCOL_2_CLK_P2 :
/* MTKAIF TX format setting */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_ADDA_MTKAIF_CFG0 ,
0xffff , 0x0010 ) ;
/* enable aud_pad TX fifos */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_AUD_PAD_TOP ,
0xff00 , 0x3800 ) ;
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_AUD_PAD_TOP ,
0xff00 , 0x3900 ) ;
break ;
case MT6358_MTKAIF_PROTOCOL_2 :
/* MTKAIF TX format setting */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_ADDA_MTKAIF_CFG0 ,
0xffff , 0x0010 ) ;
/* enable aud_pad TX fifos */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_AUD_PAD_TOP ,
0xff00 , 0x3100 ) ;
break ;
case MT6358_MTKAIF_PROTOCOL_1 :
default :
/* MTKAIF TX format setting */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_ADDA_MTKAIF_CFG0 ,
0xffff , 0x0000 ) ;
/* enable aud_pad TX fifos */
regmap_update_bits ( priv - > regmap ,
MT6358_AFE_AUD_PAD_TOP ,
0xff00 , 0x3100 ) ;
break ;
}
return 0 ;
}
static int mt6358_mtkaif_tx_disable ( struct mt6358_priv * priv )
{
/* disable aud_pad TX fifos */
regmap_update_bits ( priv - > regmap , MT6358_AFE_AUD_PAD_TOP ,
0xff00 , 0x3000 ) ;
return 0 ;
}
int mt6358_mtkaif_calibration_enable ( struct snd_soc_component * cmpnt )
{
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
playback_gpio_set ( priv ) ;
capture_gpio_set ( priv ) ;
mt6358_mtkaif_tx_enable ( priv ) ;
mt6358_set_dcxo ( priv , true ) ;
mt6358_set_aud_global_bias ( priv , true ) ;
mt6358_set_clksq ( priv , true ) ;
mt6358_set_topck ( priv , true ) ;
/* set dat_miso_loopback on */
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT ,
1 < < RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT ,
1 < < RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT ) ;
return 0 ;
}
int mt6358_mtkaif_calibration_disable ( struct snd_soc_component * cmpnt )
{
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
/* set dat_miso_loopback off */
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT ,
0 < < RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT ,
0 < < RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT ) ;
mt6358_set_topck ( priv , false ) ;
mt6358_set_clksq ( priv , false ) ;
mt6358_set_aud_global_bias ( priv , false ) ;
mt6358_set_dcxo ( priv , false ) ;
mt6358_mtkaif_tx_disable ( priv ) ;
playback_gpio_reset ( priv ) ;
capture_gpio_reset ( priv ) ;
return 0 ;
}
int mt6358_set_mtkaif_calibration_phase ( struct snd_soc_component * cmpnt ,
int phase_1 , int phase_2 )
{
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT ,
phase_1 < < RG_AUD_PAD_TOP_PHASE_MODE_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDIO_DIG_CFG ,
RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT ,
phase_2 < < RG_AUD_PAD_TOP_PHASE_MODE2_SFT ) ;
return 0 ;
}
/* dl pga gain */
enum {
DL_GAIN_8DB = 0 ,
DL_GAIN_0DB = 8 ,
DL_GAIN_N_1DB = 9 ,
DL_GAIN_N_10DB = 18 ,
DL_GAIN_N_40DB = 0x1f ,
} ;
# define DL_GAIN_N_10DB_REG (DL_GAIN_N_10DB << 7 | DL_GAIN_N_10DB)
# define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
# define DL_GAIN_REG_MASK 0x0f9f
static void hp_zcd_disable ( struct mt6358_priv * priv )
{
regmap_write ( priv - > regmap , MT6358_ZCD_CON0 , 0x0000 ) ;
}
static void hp_main_output_ramp ( struct mt6358_priv * priv , bool up )
{
int i = 0 , stage = 0 ;
int target = 7 ;
/* Enable/Reduce HPL/R main output stage step by step */
for ( i = 0 ; i < = target ; i + + ) {
stage = up ? i : target - i ;
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 ,
0x7 < < 8 , stage < < 8 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 ,
0x7 < < 11 , stage < < 11 ) ;
usleep_range ( 100 , 150 ) ;
}
}
static void hp_aux_feedback_loop_gain_ramp ( struct mt6358_priv * priv , bool up )
{
int i = 0 , stage = 0 ;
/* Reduce HP aux feedback loop gain step by step */
for ( i = 0 ; i < = 0xf ; i + + ) {
stage = up ? i : 0xf - i ;
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 ,
0xf < < 12 , stage < < 12 ) ;
usleep_range ( 100 , 150 ) ;
}
}
static void hp_pull_down ( struct mt6358_priv * priv , bool enable )
{
int i ;
if ( enable ) {
for ( i = 0x0 ; i < = 0x6 ; i + + ) {
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x7 , i ) ;
usleep_range ( 600 , 700 ) ;
}
} else {
for ( i = 0x6 ; i > = 0x1 ; i - - ) {
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x7 , i ) ;
usleep_range ( 600 , 700 ) ;
}
}
}
static bool is_valid_hp_pga_idx ( int reg_idx )
{
return ( reg_idx > = DL_GAIN_8DB & & reg_idx < = DL_GAIN_N_10DB ) | |
reg_idx = = DL_GAIN_N_40DB ;
}
2019-05-07 18:12:18 +08:00
static void headset_volume_ramp ( struct mt6358_priv * priv , int from , int to )
2019-01-22 14:39:10 +08:00
{
2019-05-07 18:12:18 +08:00
int offset = 0 , count = 0 , reg_idx ;
2019-01-22 14:39:10 +08:00
if ( ! is_valid_hp_pga_idx ( from ) | | ! is_valid_hp_pga_idx ( to ) )
dev_warn ( priv - > dev , " %s(), volume index is not valid, from %d, to %d \n " ,
__func__ , from , to ) ;
dev_info ( priv - > dev , " %s(), from %d, to %d \n " ,
__func__ , from , to ) ;
if ( to > from )
offset = to - from ;
else
offset = from - to ;
2019-05-07 18:12:18 +08:00
while ( offset > = 0 ) {
2019-01-22 14:39:10 +08:00
if ( to > from )
reg_idx = from + count ;
else
reg_idx = from - count ;
if ( is_valid_hp_pga_idx ( reg_idx ) ) {
regmap_update_bits ( priv - > regmap ,
MT6358_ZCD_CON2 ,
DL_GAIN_REG_MASK ,
( reg_idx < < 7 ) | reg_idx ) ;
usleep_range ( 200 , 300 ) ;
}
offset - - ;
count + + ;
}
}
2019-05-07 18:12:19 +08:00
static int mt6358_put_volsw ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * component =
snd_soc_kcontrol_component ( kcontrol ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( component ) ;
struct soc_mixer_control * mc =
( struct soc_mixer_control * ) kcontrol - > private_value ;
unsigned int reg ;
int ret ;
ret = snd_soc_put_volsw ( kcontrol , ucontrol ) ;
if ( ret < 0 )
return ret ;
switch ( mc - > reg ) {
case MT6358_ZCD_CON2 :
regmap_read ( priv - > regmap , MT6358_ZCD_CON2 , & reg ) ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTL ] =
( reg > > RG_AUDHPLGAIN_SFT ) & RG_AUDHPLGAIN_MASK ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTR ] =
( reg > > RG_AUDHPRGAIN_SFT ) & RG_AUDHPRGAIN_MASK ;
break ;
case MT6358_ZCD_CON1 :
regmap_read ( priv - > regmap , MT6358_ZCD_CON1 , & reg ) ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_LINEOUTL ] =
( reg > > RG_AUDLOLGAIN_SFT ) & RG_AUDLOLGAIN_MASK ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_LINEOUTR ] =
( reg > > RG_AUDLORGAIN_SFT ) & RG_AUDLORGAIN_MASK ;
break ;
case MT6358_ZCD_CON3 :
regmap_read ( priv - > regmap , MT6358_ZCD_CON3 , & reg ) ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HSOUTL ] =
( reg > > RG_AUDHSGAIN_SFT ) & RG_AUDHSGAIN_MASK ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HSOUTR ] =
( reg > > RG_AUDHSGAIN_SFT ) & RG_AUDHSGAIN_MASK ;
break ;
2019-05-07 18:12:20 +08:00
case MT6358_AUDENC_ANA_CON0 :
case MT6358_AUDENC_ANA_CON1 :
regmap_read ( priv - > regmap , MT6358_AUDENC_ANA_CON0 , & reg ) ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_MICAMP1 ] =
( reg > > RG_AUDPREAMPLGAIN_SFT ) & RG_AUDPREAMPLGAIN_MASK ;
regmap_read ( priv - > regmap , MT6358_AUDENC_ANA_CON1 , & reg ) ;
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_MICAMP2 ] =
( reg > > RG_AUDPREAMPRGAIN_SFT ) & RG_AUDPREAMPRGAIN_MASK ;
break ;
2019-05-07 18:12:19 +08:00
}
return ret ;
}
2019-10-19 15:02:52 +08:00
static void mt6358_restore_pga ( struct mt6358_priv * priv ) ;
static int mt6358_enable_wov_phase2 ( struct mt6358_priv * priv )
{
/* analog */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_DCXO_CW14 , 0xffff , 0xa2b5 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0xffff , 0x0800 ) ;
mt6358_restore_pga ( priv ) ;
regmap_update_bits ( priv - > regmap , MT6358_DCXO_CW13 , 0xffff , 0x9929 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xffff , 0x0025 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON8 ,
0xffff , 0x0005 ) ;
/* digital */
regmap_update_bits ( priv - > regmap , MT6358_AUD_TOP_CKPDN_CON0 ,
0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3 , 0xffff , 0x0120 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG0 , 0xffff , 0xffff ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG1 , 0xffff , 0x0200 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG2 , 0xffff , 0x2424 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG3 , 0xffff , 0xdbac ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG4 , 0xffff , 0x029e ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG5 , 0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_POSDIV_CFG0 ,
0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_HPF_CFG0 ,
0xffff , 0x0451 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_TOP , 0xffff , 0x68d1 ) ;
return 0 ;
}
static int mt6358_disable_wov_phase2 ( struct mt6358_priv * priv )
{
/* digital */
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_TOP , 0xffff , 0xc000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_HPF_CFG0 ,
0xffff , 0x0450 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_POSDIV_CFG0 ,
0xffff , 0x0c00 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG5 , 0xffff , 0x0100 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG4 , 0xffff , 0x006c ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG3 , 0xffff , 0xa879 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG2 , 0xffff , 0x2323 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG1 , 0xffff , 0x0400 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_VOW_CFG0 , 0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_GPIO_MODE3 , 0xffff , 0x02d8 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUD_TOP_CKPDN_CON0 ,
0xffff , 0x0000 ) ;
/* analog */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON8 ,
0xffff , 0x0004 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xffff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_DCXO_CW13 , 0xffff , 0x9829 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0xffff , 0x0000 ) ;
mt6358_restore_pga ( priv ) ;
regmap_update_bits ( priv - > regmap , MT6358_DCXO_CW14 , 0xffff , 0xa2b5 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0xffff , 0x0010 ) ;
return 0 ;
}
static int mt6358_get_wov ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * c = snd_soc_kcontrol_component ( kcontrol ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( c ) ;
ucontrol - > value . integer . value [ 0 ] = priv - > wov_enabled ;
return 0 ;
}
static int mt6358_put_wov ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * c = snd_soc_kcontrol_component ( kcontrol ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( c ) ;
int enabled = ucontrol - > value . integer . value [ 0 ] ;
if ( priv - > wov_enabled ! = enabled ) {
if ( enabled )
mt6358_enable_wov_phase2 ( priv ) ;
else
mt6358_disable_wov_phase2 ( priv ) ;
priv - > wov_enabled = enabled ;
}
return 0 ;
}
2019-01-22 14:39:10 +08:00
static const DECLARE_TLV_DB_SCALE ( playback_tlv , - 1000 , 100 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( pga_tlv , 0 , 600 , 0 ) ;
static const struct snd_kcontrol_new mt6358_snd_controls [ ] = {
/* dl pga gain */
2019-05-07 18:12:19 +08:00
SOC_DOUBLE_EXT_TLV ( " Headphone Volume " ,
MT6358_ZCD_CON2 , 0 , 7 , 0x12 , 1 ,
snd_soc_get_volsw , mt6358_put_volsw , playback_tlv ) ,
SOC_DOUBLE_EXT_TLV ( " Lineout Volume " ,
MT6358_ZCD_CON1 , 0 , 7 , 0x12 , 1 ,
snd_soc_get_volsw , mt6358_put_volsw , playback_tlv ) ,
SOC_SINGLE_EXT_TLV ( " Handset Volume " ,
MT6358_ZCD_CON3 , 0 , 0x12 , 1 ,
snd_soc_get_volsw , mt6358_put_volsw , playback_tlv ) ,
2019-01-22 14:39:10 +08:00
/* ul pga gain */
2019-05-07 18:12:20 +08:00
SOC_DOUBLE_R_EXT_TLV ( " PGA Volume " ,
MT6358_AUDENC_ANA_CON0 , MT6358_AUDENC_ANA_CON1 ,
8 , 4 , 0 ,
snd_soc_get_volsw , mt6358_put_volsw , pga_tlv ) ,
2019-10-19 15:02:52 +08:00
SOC_SINGLE_BOOL_EXT ( " Wake-on-Voice Phase2 Switch " , 0 ,
mt6358_get_wov , mt6358_put_wov ) ,
2019-01-22 14:39:10 +08:00
} ;
/* MUX */
/* LOL MUX */
static const char * const lo_in_mux_map [ ] = {
" Open " , " Mute " , " Playback " , " Test Mode "
} ;
static int lo_in_mux_map_value [ ] = {
0x0 , 0x1 , 0x2 , 0x3 ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( lo_in_mux_map_enum ,
MT6358_AUDDEC_ANA_CON7 ,
RG_AUDLOLMUXINPUTSEL_VAUDP15_SFT ,
RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK ,
lo_in_mux_map ,
lo_in_mux_map_value ) ;
static const struct snd_kcontrol_new lo_in_mux_control =
SOC_DAPM_ENUM ( " In Select " , lo_in_mux_map_enum ) ;
/*HP MUX */
enum {
HP_MUX_OPEN = 0 ,
HP_MUX_HPSPK ,
HP_MUX_HP ,
HP_MUX_TEST_MODE ,
HP_MUX_HP_IMPEDANCE ,
HP_MUX_MASK = 0x7 ,
} ;
static const char * const hp_in_mux_map [ ] = {
" Open " ,
" LoudSPK Playback " ,
" Audio Playback " ,
" Test Mode " ,
" HP Impedance " ,
" undefined1 " ,
" undefined2 " ,
" undefined3 " ,
} ;
static int hp_in_mux_map_value [ ] = {
HP_MUX_OPEN ,
HP_MUX_HPSPK ,
HP_MUX_HP ,
HP_MUX_TEST_MODE ,
HP_MUX_HP_IMPEDANCE ,
HP_MUX_OPEN ,
HP_MUX_OPEN ,
HP_MUX_OPEN ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( hpl_in_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
HP_MUX_MASK ,
hp_in_mux_map ,
hp_in_mux_map_value ) ;
static const struct snd_kcontrol_new hpl_in_mux_control =
SOC_DAPM_ENUM ( " HPL Select " , hpl_in_mux_map_enum ) ;
static SOC_VALUE_ENUM_SINGLE_DECL ( hpr_in_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
HP_MUX_MASK ,
hp_in_mux_map ,
hp_in_mux_map_value ) ;
static const struct snd_kcontrol_new hpr_in_mux_control =
SOC_DAPM_ENUM ( " HPR Select " , hpr_in_mux_map_enum ) ;
/* RCV MUX */
enum {
RCV_MUX_OPEN = 0 ,
RCV_MUX_MUTE ,
RCV_MUX_VOICE_PLAYBACK ,
RCV_MUX_TEST_MODE ,
RCV_MUX_MASK = 0x3 ,
} ;
static const char * const rcv_in_mux_map [ ] = {
" Open " , " Mute " , " Voice Playback " , " Test Mode "
} ;
static int rcv_in_mux_map_value [ ] = {
RCV_MUX_OPEN ,
RCV_MUX_MUTE ,
RCV_MUX_VOICE_PLAYBACK ,
RCV_MUX_TEST_MODE ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( rcv_in_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
RCV_MUX_MASK ,
rcv_in_mux_map ,
rcv_in_mux_map_value ) ;
static const struct snd_kcontrol_new rcv_in_mux_control =
SOC_DAPM_ENUM ( " RCV Select " , rcv_in_mux_map_enum ) ;
/* DAC In MUX */
static const char * const dac_in_mux_map [ ] = {
" Normal Path " , " Sgen "
} ;
static int dac_in_mux_map_value [ ] = {
0x0 , 0x1 ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( dac_in_mux_map_enum ,
MT6358_AFE_TOP_CON0 ,
DL_SINE_ON_SFT ,
DL_SINE_ON_MASK ,
dac_in_mux_map ,
dac_in_mux_map_value ) ;
static const struct snd_kcontrol_new dac_in_mux_control =
SOC_DAPM_ENUM ( " DAC Select " , dac_in_mux_map_enum ) ;
/* AIF Out MUX */
static SOC_VALUE_ENUM_SINGLE_DECL ( aif_out_mux_map_enum ,
MT6358_AFE_TOP_CON0 ,
UL_SINE_ON_SFT ,
UL_SINE_ON_MASK ,
dac_in_mux_map ,
dac_in_mux_map_value ) ;
static const struct snd_kcontrol_new aif_out_mux_control =
SOC_DAPM_ENUM ( " AIF Out Select " , aif_out_mux_map_enum ) ;
/* Mic Type MUX */
enum {
MIC_TYPE_MUX_IDLE = 0 ,
MIC_TYPE_MUX_ACC ,
MIC_TYPE_MUX_DMIC ,
MIC_TYPE_MUX_DCC ,
MIC_TYPE_MUX_DCC_ECM_DIFF ,
MIC_TYPE_MUX_DCC_ECM_SINGLE ,
MIC_TYPE_MUX_MASK = 0x7 ,
} ;
# define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \
( type ) = = MIC_TYPE_MUX_DCC_ECM_DIFF | | \
( type ) = = MIC_TYPE_MUX_DCC_ECM_SINGLE )
static const char * const mic_type_mux_map [ ] = {
" Idle " ,
" ACC " ,
" DMIC " ,
" DCC " ,
" DCC_ECM_DIFF " ,
" DCC_ECM_SINGLE " ,
} ;
static int mic_type_mux_map_value [ ] = {
MIC_TYPE_MUX_IDLE ,
MIC_TYPE_MUX_ACC ,
MIC_TYPE_MUX_DMIC ,
MIC_TYPE_MUX_DCC ,
MIC_TYPE_MUX_DCC_ECM_DIFF ,
MIC_TYPE_MUX_DCC_ECM_SINGLE ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( mic_type_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
MIC_TYPE_MUX_MASK ,
mic_type_mux_map ,
mic_type_mux_map_value ) ;
static const struct snd_kcontrol_new mic_type_mux_control =
SOC_DAPM_ENUM ( " Mic Type Select " , mic_type_mux_map_enum ) ;
/* ADC L MUX */
enum {
ADC_MUX_IDLE = 0 ,
ADC_MUX_AIN0 ,
ADC_MUX_PREAMPLIFIER ,
ADC_MUX_IDLE1 ,
ADC_MUX_MASK = 0x3 ,
} ;
static const char * const adc_left_mux_map [ ] = {
" Idle " , " AIN0 " , " Left Preamplifier " , " Idle_1 "
} ;
static int adc_mux_map_value [ ] = {
ADC_MUX_IDLE ,
ADC_MUX_AIN0 ,
ADC_MUX_PREAMPLIFIER ,
ADC_MUX_IDLE1 ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( adc_left_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
ADC_MUX_MASK ,
adc_left_mux_map ,
adc_mux_map_value ) ;
static const struct snd_kcontrol_new adc_left_mux_control =
SOC_DAPM_ENUM ( " ADC L Select " , adc_left_mux_map_enum ) ;
/* ADC R MUX */
static const char * const adc_right_mux_map [ ] = {
" Idle " , " AIN0 " , " Right Preamplifier " , " Idle_1 "
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( adc_right_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
ADC_MUX_MASK ,
adc_right_mux_map ,
adc_mux_map_value ) ;
static const struct snd_kcontrol_new adc_right_mux_control =
SOC_DAPM_ENUM ( " ADC R Select " , adc_right_mux_map_enum ) ;
/* PGA L MUX */
enum {
PGA_MUX_NONE = 0 ,
PGA_MUX_AIN0 ,
PGA_MUX_AIN1 ,
PGA_MUX_AIN2 ,
PGA_MUX_MASK = 0x3 ,
} ;
static const char * const pga_mux_map [ ] = {
" None " , " AIN0 " , " AIN1 " , " AIN2 "
} ;
static int pga_mux_map_value [ ] = {
PGA_MUX_NONE ,
PGA_MUX_AIN0 ,
PGA_MUX_AIN1 ,
PGA_MUX_AIN2 ,
} ;
static SOC_VALUE_ENUM_SINGLE_DECL ( pga_left_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
PGA_MUX_MASK ,
pga_mux_map ,
pga_mux_map_value ) ;
static const struct snd_kcontrol_new pga_left_mux_control =
SOC_DAPM_ENUM ( " PGA L Select " , pga_left_mux_map_enum ) ;
/* PGA R MUX */
static SOC_VALUE_ENUM_SINGLE_DECL ( pga_right_mux_map_enum ,
SND_SOC_NOPM ,
0 ,
PGA_MUX_MASK ,
pga_mux_map ,
pga_mux_map_value ) ;
static const struct snd_kcontrol_new pga_right_mux_control =
SOC_DAPM_ENUM ( " PGA R Select " , pga_right_mux_map_enum ) ;
static int mt_clksq_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x \n " , __func__ , event ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
/* audio clk source from internal dcxo */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON6 ,
RG_CLKSQ_IN_SEL_TEST_MASK_SFT ,
0x0 ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_sgen_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x \n " , __func__ , event ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
/* sdm audio fifo clock power on */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0006 ) ;
/* scrambler clock on enable */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON0 , 0xCBA1 ) ;
/* sdm power on */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0003 ) ;
/* sdm fifo enable */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x000B ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_SGEN_CFG0 ,
0xff3f ,
0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AFE_SGEN_CFG1 ,
0xffff ,
0x0001 ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
/* DL scrambler disabling sequence */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0000 ) ;
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON0 , 0xcba0 ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_aif_in_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_info ( priv - > dev , " %s(), event 0x%x, rate %d \n " ,
__func__ , event , priv - > dl_rate ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
playback_gpio_set ( priv ) ;
/* sdm audio fifo clock power on */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0006 ) ;
/* scrambler clock on enable */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON0 , 0xCBA1 ) ;
/* sdm power on */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0003 ) ;
/* sdm fifo enable */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x000B ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
/* DL scrambler disabling sequence */
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON2 , 0x0000 ) ;
regmap_write ( priv - > regmap , MT6358_AFUNC_AUD_CON0 , 0xcba0 ) ;
playback_gpio_reset ( priv ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mtk_hp_enable ( struct mt6358_priv * priv )
{
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , true ) ;
/* release HP CMFB gate rstb */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x1 < < 6 , 0x1 < < 6 ) ;
/* Reduce ESD resistance of AU_REFN */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 , 0x4000 ) ;
/* Set HPR/HPL gain as minimum (~ -40dB) */
regmap_write ( priv - > regmap , MT6358_ZCD_CON2 , DL_GAIN_N_40DB_REG ) ;
/* Turn on DA_600K_NCP_VA18 */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON1 , 0x0001 ) ;
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON2 , 0x002c ) ;
/* Toggle RG_DIVCKS_CHG */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON0 , 0x0001 ) ;
/* Set NCP soft start mode as default mode: 100us */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON4 , 0x0003 ) ;
/* Enable NCP */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 , 0x0000 ) ;
usleep_range ( 250 , 270 ) ;
/* Enable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x1055 , 0x1055 ) ;
/* Enable NV regulator (-1.2V) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 , 0x0001 ) ;
usleep_range ( 100 , 120 ) ;
/* Disable AUD_ZCD */
hp_zcd_disable ( priv ) ;
/* Disable headphone short-circuit protection */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x3000 ) ;
/* Enable IBIST */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HP DR bias current optimization, 010: 6uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON11 , 0x4900 ) ;
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HPP/N STB enhance circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 , 0x4033 ) ;
/* Enable HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x000c ) ;
/* Enable HP aux feedback loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x003c ) ;
/* Enable HP aux CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0c00 ) ;
/* Enable HP driver bias circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30c0 ) ;
/* Enable HP driver core circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30f0 ) ;
/* Short HP main output to HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x00fc ) ;
/* Enable HP main CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0e00 ) ;
/* Disable HP aux CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0200 ) ;
/* Select CMFB resistor bulk to AC mode */
/* Selec HS/LO cap size (6.5pF default) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON10 , 0x0000 ) ;
/* Enable HP main output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x00ff ) ;
/* Enable HPR/L main output stage step by step */
hp_main_output_ramp ( priv , true ) ;
/* Reduce HP aux feedback loop gain */
hp_aux_feedback_loop_gain_ramp ( priv , true ) ;
/* Disable HP aux feedback loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fcf ) ;
/* apply volume setting */
headset_volume_ramp ( priv ,
DL_GAIN_N_10DB ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTL ] ) ;
/* Disable HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fc3 ) ;
/* Unshort HP main output to HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3f03 ) ;
usleep_range ( 100 , 120 ) ;
/* Enable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 , 0x1 , 0x1 ) ;
/* Enable Audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30ff ) ;
/* Enable low-noise mode of DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0xf201 ) ;
usleep_range ( 100 , 120 ) ;
/* Switch HPL MUX to audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x32ff ) ;
/* Switch HPR MUX to audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x3aff ) ;
/* Disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , false ) ;
return 0 ;
}
static int mtk_hp_disable ( struct mt6358_priv * priv )
{
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , true ) ;
/* HPR/HPL mux to open */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x0f00 , 0x0000 ) ;
/* Disable low-noise mode of DAC */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 ,
0x0001 , 0x0000 ) ;
/* Disable Audio DAC */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x000f , 0x0000 ) ;
/* Disable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 , 0x1 , 0x0 ) ;
/* Short HP main output to HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fc3 ) ;
/* Enable HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fcf ) ;
/* decrease HPL/R gain to normal gain step by step */
headset_volume_ramp ( priv ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTL ] ,
DL_GAIN_N_40DB ) ;
/* Enable HP aux feedback loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fff ) ;
/* Reduce HP aux feedback loop gain */
hp_aux_feedback_loop_gain_ramp ( priv , false ) ;
/* decrease HPR/L main output stage step by step */
hp_main_output_ramp ( priv , false ) ;
/* Disable HP main output stage */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3 , 0x0 ) ;
/* Enable HP aux CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0e00 ) ;
/* Disable HP main CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0c00 ) ;
/* Unshort HP main output to HP aux output stage */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 ,
0x3 < < 6 , 0x0 ) ;
/* Disable HP driver core circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x3 < < 4 , 0x0 ) ;
/* Disable HP driver bias circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x3 < < 6 , 0x0 ) ;
/* Disable HP aux CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0000 ) ;
/* Disable HP aux feedback loop */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 ,
0x3 < < 4 , 0x0 ) ;
/* Disable HP aux output stage */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 ,
0x3 < < 2 , 0x0 ) ;
/* Disable IBIST */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 ,
0x1 < < 8 , 0x1 < < 8 ) ;
/* Disable NV regulator (-1.2V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 , 0x1 , 0x0 ) ;
/* Disable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x1055 , 0x0 ) ;
/* Disable NCP */
regmap_update_bits ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 ,
0x1 , 0x1 ) ;
/* Increase ESD resistance of AU_REFN */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 ,
0x1 < < 14 , 0x0 ) ;
/* Set HP CMFB gate rstb */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x1 < < 6 , 0x0 ) ;
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , false ) ;
return 0 ;
}
static int mtk_hp_spk_enable ( struct mt6358_priv * priv )
{
/* Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , true ) ;
/* release HP CMFB gate rstb */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x1 < < 6 , 0x1 < < 6 ) ;
/* Reduce ESD resistance of AU_REFN */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 , 0x4000 ) ;
/* Set HPR/HPL gain to -10dB */
regmap_write ( priv - > regmap , MT6358_ZCD_CON2 , DL_GAIN_N_10DB_REG ) ;
/* Turn on DA_600K_NCP_VA18 */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON1 , 0x0001 ) ;
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON2 , 0x002c ) ;
/* Toggle RG_DIVCKS_CHG */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON0 , 0x0001 ) ;
/* Set NCP soft start mode as default mode: 100us */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON4 , 0x0003 ) ;
/* Enable NCP */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 , 0x0000 ) ;
usleep_range ( 250 , 270 ) ;
/* Enable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x1055 , 0x1055 ) ;
/* Enable NV regulator (-1.2V) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 , 0x0001 ) ;
usleep_range ( 100 , 120 ) ;
/* Disable AUD_ZCD */
hp_zcd_disable ( priv ) ;
/* Disable headphone short-circuit protection */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x3000 ) ;
/* Enable IBIST */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HP DR bias current optimization, 010: 6uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON11 , 0x4900 ) ;
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HPP/N STB enhance circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 , 0x4033 ) ;
/* Disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , false ) ;
/* Enable HP driver bias circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30c0 ) ;
/* Enable HP driver core circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30f0 ) ;
/* Enable HP main CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0200 ) ;
/* Select CMFB resistor bulk to AC mode */
/* Selec HS/LO cap size (6.5pF default) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON10 , 0x0000 ) ;
/* Enable HP main output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x0003 ) ;
/* Enable HPR/L main output stage step by step */
hp_main_output_ramp ( priv , true ) ;
/* Set LO gain as minimum (~ -40dB) */
regmap_write ( priv - > regmap , MT6358_ZCD_CON1 , DL_GAIN_N_40DB_REG ) ;
/* apply volume setting */
headset_volume_ramp ( priv ,
DL_GAIN_N_10DB ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTL ] ) ;
/* Set LO STB enhance circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 , 0x0110 ) ;
/* Enable LO driver bias circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 , 0x0112 ) ;
/* Enable LO driver core circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 , 0x0113 ) ;
/* Set LOL gain to normal gain step by step */
regmap_update_bits ( priv - > regmap , MT6358_ZCD_CON1 ,
RG_AUDLOLGAIN_MASK_SFT ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_LINEOUTL ] < <
RG_AUDLOLGAIN_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_ZCD_CON1 ,
RG_AUDLORGAIN_MASK_SFT ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_LINEOUTR ] < <
RG_AUDLORGAIN_SFT ) ;
/* Enable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 , 0x1 , 0x1 ) ;
/* Enable Audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x30f9 ) ;
/* Enable low-noise mode of DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0201 ) ;
/* Switch LOL MUX to audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 , 0x011b ) ;
/* Switch HPL/R MUX to Line-out */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x35f9 ) ;
return 0 ;
}
static int mtk_hp_spk_disable ( struct mt6358_priv * priv )
{
/* HPR/HPL mux to open */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x0f00 , 0x0000 ) ;
/* LOL mux to open */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 ,
0x3 < < 2 , 0x0000 ) ;
/* Disable Audio DAC */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x000f , 0x0000 ) ;
/* Disable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 , 0x1 , 0x0 ) ;
/* decrease HPL/R gain to normal gain step by step */
headset_volume_ramp ( priv ,
priv - > ana_gain [ AUDIO_ANALOG_VOLUME_HPOUTL ] ,
DL_GAIN_N_40DB ) ;
/* decrease LOL gain to minimum gain step by step */
regmap_update_bits ( priv - > regmap , MT6358_ZCD_CON1 ,
DL_GAIN_REG_MASK , DL_GAIN_N_40DB_REG ) ;
/* decrease HPR/L main output stage step by step */
hp_main_output_ramp ( priv , false ) ;
/* Disable HP main output stage */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3 , 0x0 ) ;
/* Short HP main output to HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fc3 ) ;
/* Enable HP aux output stage */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fcf ) ;
/* Enable HP aux feedback loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON1 , 0x3fff ) ;
/* Reduce HP aux feedback loop gain */
hp_aux_feedback_loop_gain_ramp ( priv , false ) ;
/* Disable HP driver core circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x3 < < 4 , 0x0 ) ;
/* Disable LO driver core circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 ,
0x1 , 0x0 ) ;
/* Disable HP driver bias circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x3 < < 6 , 0x0 ) ;
/* Disable LO driver bias circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 ,
0x1 < < 1 , 0x0 ) ;
/* Disable HP aux CMFB loop */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 ,
0xff < < 8 , 0x0000 ) ;
/* Disable IBIST */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 ,
0x1 < < 8 , 0x1 < < 8 ) ;
/* Disable NV regulator (-1.2V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 , 0x1 , 0x0 ) ;
/* Disable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 , 0x1055 , 0x0 ) ;
/* Disable NCP */
regmap_update_bits ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 , 0x1 , 0x1 ) ;
/* Set HP CMFB gate rstb */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON4 ,
0x1 < < 6 , 0x0 ) ;
/* disable Pull-down HPL/R to AVSS28_AUD */
hp_pull_down ( priv , false ) ;
return 0 ;
}
static int mt_hp_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
int device = DEVICE_HP ;
dev_info ( priv - > dev , " %s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u \n " ,
__func__ ,
event ,
priv - > dev_counter [ device ] ,
mux ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
priv - > dev_counter [ device ] + + ;
if ( priv - > dev_counter [ device ] > 1 )
break ; /* already enabled, do nothing */
else if ( priv - > dev_counter [ device ] < = 0 )
dev_warn ( priv - > dev , " %s(), dev_counter[DEV_HP] %d <= 0 \n " ,
__func__ ,
priv - > dev_counter [ device ] ) ;
priv - > mux_select [ MUX_HP_L ] = mux ;
if ( mux = = HP_MUX_HP )
mtk_hp_enable ( priv ) ;
else if ( mux = = HP_MUX_HPSPK )
mtk_hp_spk_enable ( priv ) ;
break ;
case SND_SOC_DAPM_PRE_PMD :
priv - > dev_counter [ device ] - - ;
if ( priv - > dev_counter [ device ] > 0 ) {
break ; /* still being used, don't close */
} else if ( priv - > dev_counter [ device ] < 0 ) {
dev_warn ( priv - > dev , " %s(), dev_counter[DEV_HP] %d < 0 \n " ,
__func__ ,
priv - > dev_counter [ device ] ) ;
priv - > dev_counter [ device ] = 0 ;
break ;
}
if ( priv - > mux_select [ MUX_HP_L ] = = HP_MUX_HP )
mtk_hp_disable ( priv ) ;
else if ( priv - > mux_select [ MUX_HP_L ] = = HP_MUX_HPSPK )
mtk_hp_spk_disable ( priv ) ;
priv - > mux_select [ MUX_HP_L ] = mux ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_rcv_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_info ( priv - > dev , " %s(), event 0x%x, mux %u \n " ,
__func__ ,
event ,
dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
/* Reduce ESD resistance of AU_REFN */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON2 , 0x4000 ) ;
/* Turn on DA_600K_NCP_VA18 */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON1 , 0x0001 ) ;
/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON2 , 0x002c ) ;
/* Toggle RG_DIVCKS_CHG */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON0 , 0x0001 ) ;
/* Set NCP soft start mode as default mode: 100us */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON4 , 0x0003 ) ;
/* Enable NCP */
regmap_write ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 , 0x0000 ) ;
usleep_range ( 250 , 270 ) ;
/* Enable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x1055 , 0x1055 ) ;
/* Enable NV regulator (-1.2V) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 , 0x0001 ) ;
usleep_range ( 100 , 120 ) ;
/* Disable AUD_ZCD */
hp_zcd_disable ( priv ) ;
/* Disable handset short-circuit protection */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 , 0x0010 ) ;
/* Enable IBIST */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HP DR bias current optimization, 010: 6uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON11 , 0x4900 ) ;
/* Set HP & ZCD bias current optimization */
/* 01: ZCD: 4uA, HP/HS/LO: 5uA */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 , 0x0055 ) ;
/* Set HS STB enhance circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 , 0x0090 ) ;
/* Disable HP main CMFB loop */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0000 ) ;
/* Select CMFB resistor bulk to AC mode */
/* Selec HS/LO cap size (6.5pF default) */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON10 , 0x0000 ) ;
/* Enable HS driver bias circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 , 0x0092 ) ;
/* Enable HS driver core circuits */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 , 0x0093 ) ;
/* Enable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0x1 , 0x1 ) ;
/* Enable Audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 , 0x0009 ) ;
/* Enable low-noise mode of DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 , 0x0001 ) ;
/* Switch HS MUX to audio DAC */
regmap_write ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 , 0x009b ) ;
break ;
case SND_SOC_DAPM_PRE_PMD :
/* HS mux to open */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 ,
RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT ,
RCV_MUX_OPEN ) ;
/* Disable Audio DAC */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
0x000f , 0x0000 ) ;
/* Disable AUD_CLK */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0x1 , 0x0 ) ;
/* decrease HS gain to minimum gain step by step */
regmap_write ( priv - > regmap , MT6358_ZCD_CON3 , DL_GAIN_N_40DB ) ;
/* Disable HS driver core circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 ,
0x1 , 0x0 ) ;
/* Disable HS driver bias circuits */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 ,
0x1 < < 1 , 0x0000 ) ;
/* Disable HP aux CMFB loop */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 ,
0xff < < 8 , 0x0 ) ;
/* Enable HP main CMFB Switch */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON9 ,
0xff < < 8 , 0x2 < < 8 ) ;
/* Disable IBIST */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON12 ,
0x1 < < 8 , 0x1 < < 8 ) ;
/* Disable NV regulator (-1.2V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON15 ,
0x1 , 0x0 ) ;
/* Disable cap-less LDOs (1.5V) */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x1055 , 0x0 ) ;
/* Disable NCP */
regmap_update_bits ( priv - > regmap , MT6358_AUDNCP_CLKDIV_CON3 ,
0x1 , 0x1 ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_aif_out_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_dbg ( priv - > dev , " %s(), event 0x%x, rate %d \n " ,
__func__ , event , priv - > ul_rate ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
capture_gpio_set ( priv ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
capture_gpio_reset ( priv ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_adc_supply_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
dev_dbg ( priv - > dev , " %s(), event 0x%x \n " ,
__func__ , event ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
/* Enable audio ADC CLKGEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0x1 < < 5 , 0x1 < < 5 ) ;
/* ADC CLK from CLKGEN (13MHz) */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON3 ,
0x0000 ) ;
/* Enable LCLDO_ENC 1P8V */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x2500 , 0x0100 ) ;
/* LCLDO_ENC remote sense */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x2500 , 0x2500 ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
/* LCLDO_ENC remote sense off */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x2500 , 0x0100 ) ;
/* disable LCLDO_ENC 1P8V */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON14 ,
0x2500 , 0x0000 ) ;
/* ADC CLK from CLKGEN (13MHz) */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON3 , 0x0000 ) ;
/* disable audio ADC CLKGEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON13 ,
0x1 < < 5 , 0x0 < < 5 ) ;
break ;
default :
break ;
}
return 0 ;
}
static int mt6358_amic_enable ( struct mt6358_priv * priv )
{
unsigned int mic_type = priv - > mux_select [ MUX_MIC_TYPE ] ;
unsigned int mux_pga_l = priv - > mux_select [ MUX_PGA_L ] ;
unsigned int mux_pga_r = priv - > mux_select [ MUX_PGA_R ] ;
dev_info ( priv - > dev , " %s(), mux, mic %u, pga l %u, pga r %u \n " ,
__func__ , mic_type , mux_pga_l , mux_pga_r ) ;
if ( IS_DCC_BASE ( mic_type ) ) {
/* DCC 50k CLK (from 26M) */
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2062 ) ;
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2062 ) ;
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2060 ) ;
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2061 ) ;
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG1 , 0x0100 ) ;
}
/* mic bias 0 */
if ( mux_pga_l = = PGA_MUX_AIN0 | | mux_pga_l = = PGA_MUX_AIN2 | |
mux_pga_r = = PGA_MUX_AIN0 | | mux_pga_r = = PGA_MUX_AIN2 ) {
switch ( mic_type ) {
case MIC_TYPE_MUX_DCC_ECM_DIFF :
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xff00 , 0x7700 ) ;
break ;
case MIC_TYPE_MUX_DCC_ECM_SINGLE :
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xff00 , 0x1100 ) ;
break ;
default :
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xff00 , 0x0000 ) ;
break ;
}
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON9 ,
0xff , 0x21 ) ;
}
/* mic bias 1 */
if ( mux_pga_l = = PGA_MUX_AIN1 | | mux_pga_r = = PGA_MUX_AIN1 ) {
/* Enable MICBIAS1, MISBIAS1 = 2P6V */
if ( mic_type = = MIC_TYPE_MUX_DCC_ECM_SINGLE )
regmap_write ( priv - > regmap ,
MT6358_AUDENC_ANA_CON10 , 0x0161 ) ;
else
regmap_write ( priv - > regmap ,
MT6358_AUDENC_ANA_CON10 , 0x0061 ) ;
}
if ( IS_DCC_BASE ( mic_type ) ) {
/* Audio L/R preamplifier DCC precharge */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0xf8ff , 0x0004 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0xf8ff , 0x0004 ) ;
} else {
/* reset reg */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0xf8ff , 0x0000 ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0xf8ff , 0x0000 ) ;
}
if ( mux_pga_l ! = PGA_MUX_NONE ) {
/* L preamplifier input sel */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDPREAMPLINPUTSEL_MASK_SFT ,
mux_pga_l < < RG_AUDPREAMPLINPUTSEL_SFT ) ;
/* L preamplifier enable */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDPREAMPLON_MASK_SFT ,
0x1 < < RG_AUDPREAMPLON_SFT ) ;
if ( IS_DCC_BASE ( mic_type ) ) {
/* L preamplifier DCCEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDPREAMPLDCCEN_MASK_SFT ,
0x1 < < RG_AUDPREAMPLDCCEN_SFT ) ;
}
/* L ADC input sel : L PGA. Enable audio L ADC */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDADCLINPUTSEL_MASK_SFT ,
ADC_MUX_PREAMPLIFIER < <
RG_AUDADCLINPUTSEL_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDADCLPWRUP_MASK_SFT ,
0x1 < < RG_AUDADCLPWRUP_SFT ) ;
}
if ( mux_pga_r ! = PGA_MUX_NONE ) {
/* R preamplifier input sel */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDPREAMPRINPUTSEL_MASK_SFT ,
mux_pga_r < < RG_AUDPREAMPRINPUTSEL_SFT ) ;
/* R preamplifier enable */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDPREAMPRON_MASK_SFT ,
0x1 < < RG_AUDPREAMPRON_SFT ) ;
if ( IS_DCC_BASE ( mic_type ) ) {
/* R preamplifier DCCEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDPREAMPRDCCEN_MASK_SFT ,
0x1 < < RG_AUDPREAMPRDCCEN_SFT ) ;
}
/* R ADC input sel : R PGA. Enable audio R ADC */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDADCRINPUTSEL_MASK_SFT ,
ADC_MUX_PREAMPLIFIER < <
RG_AUDADCRINPUTSEL_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDADCRPWRUP_MASK_SFT ,
0x1 < < RG_AUDADCRPWRUP_SFT ) ;
}
if ( IS_DCC_BASE ( mic_type ) ) {
usleep_range ( 100 , 150 ) ;
/* Audio L preamplifier DCC precharge off */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDPREAMPLDCPRECHARGE_MASK_SFT , 0x0 ) ;
/* Audio R preamplifier DCC precharge off */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDPREAMPRDCPRECHARGE_MASK_SFT , 0x0 ) ;
/* Short body to ground in PGA */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON3 ,
0x1 < < 12 , 0x0 ) ;
}
/* here to set digital part */
mt6358_mtkaif_tx_enable ( priv ) ;
/* UL dmic setting off */
regmap_write ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_H , 0x0000 ) ;
/* UL turn on */
regmap_write ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_L , 0x0001 ) ;
return 0 ;
}
static void mt6358_amic_disable ( struct mt6358_priv * priv )
{
unsigned int mic_type = priv - > mux_select [ MUX_MIC_TYPE ] ;
unsigned int mux_pga_l = priv - > mux_select [ MUX_PGA_L ] ;
unsigned int mux_pga_r = priv - > mux_select [ MUX_PGA_R ] ;
dev_info ( priv - > dev , " %s(), mux, mic %u, pga l %u, pga r %u \n " ,
__func__ , mic_type , mux_pga_l , mux_pga_r ) ;
/* UL turn off */
regmap_update_bits ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_L ,
0x0001 , 0x0000 ) ;
/* disable aud_pad TX fifos */
mt6358_mtkaif_tx_disable ( priv ) ;
/* L ADC input sel : off, disable L ADC */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0xf000 , 0x0000 ) ;
/* L preamplifier DCCEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0x1 < < 1 , 0x0 ) ;
/* L preamplifier input sel : off, L PGA 0 dB gain */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0xfffb , 0x0000 ) ;
/* disable L preamplifier DCC precharge */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
0x1 < < 2 , 0x0 ) ;
/* R ADC input sel : off, disable R ADC */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0xf000 , 0x0000 ) ;
/* R preamplifier DCCEN */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0x1 < < 1 , 0x0 ) ;
/* R preamplifier input sel : off, R PGA 0 dB gain */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0x0ffb , 0x0000 ) ;
/* disable R preamplifier DCC precharge */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
0x1 < < 2 , 0x0 ) ;
/* mic bias */
/* Disable MICBIAS0, MISBIAS0 = 1P7V */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON9 , 0x0000 ) ;
/* Disable MICBIAS1 */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON10 ,
0x0001 , 0x0000 ) ;
if ( IS_DCC_BASE ( mic_type ) ) {
/* dcclk_gen_on=1'b0 */
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2060 ) ;
/* dcclk_pdn=1'b1 */
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2062 ) ;
/* dcclk_ref_ck_sel=2'b00 */
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2062 ) ;
/* dcclk_div=11'b00100000011 */
regmap_write ( priv - > regmap , MT6358_AFE_DCCLK_CFG0 , 0x2062 ) ;
}
}
static int mt6358_dmic_enable ( struct mt6358_priv * priv )
{
dev_info ( priv - > dev , " %s() \n " , __func__ ) ;
/* mic bias */
/* Enable MICBIAS0, MISBIAS0 = 1P9V */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON9 , 0x0021 ) ;
/* RG_BANDGAPGEN=1'b0 */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON10 ,
0x1 < < 12 , 0x0 ) ;
/* DMIC enable */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON8 , 0x0005 ) ;
/* here to set digital part */
mt6358_mtkaif_tx_enable ( priv ) ;
/* UL dmic setting */
2020-06-05 18:33:41 +08:00
if ( priv - > dmic_one_wire_mode )
regmap_write ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_H , 0x0400 ) ;
else
regmap_write ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_H , 0x0080 ) ;
2019-01-22 14:39:10 +08:00
/* UL turn on */
regmap_write ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_L , 0x0003 ) ;
2019-08-05 12:56:37 +08:00
/* Prevent pop noise form dmic hw */
msleep ( 100 ) ;
2019-01-22 14:39:10 +08:00
return 0 ;
}
static void mt6358_dmic_disable ( struct mt6358_priv * priv )
{
dev_info ( priv - > dev , " %s() \n " , __func__ ) ;
/* UL turn off */
regmap_update_bits ( priv - > regmap , MT6358_AFE_UL_SRC_CON0_L ,
0x0003 , 0x0000 ) ;
/* disable aud_pad TX fifos */
mt6358_mtkaif_tx_disable ( priv ) ;
/* DMIC disable */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON8 , 0x0000 ) ;
/* mic bias */
/* MISBIAS0 = 1P7V */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON9 , 0x0001 ) ;
/* RG_BANDGAPGEN=1'b0 */
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON10 ,
0x1 < < 12 , 0x0 ) ;
/* MICBIA0 disable */
regmap_write ( priv - > regmap , MT6358_AUDENC_ANA_CON9 , 0x0000 ) ;
}
2019-05-07 18:12:20 +08:00
static void mt6358_restore_pga ( struct mt6358_priv * priv )
{
unsigned int gain_l , gain_r ;
gain_l = priv - > ana_gain [ AUDIO_ANALOG_VOLUME_MICAMP1 ] ;
gain_r = priv - > ana_gain [ AUDIO_ANALOG_VOLUME_MICAMP2 ] ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON0 ,
RG_AUDPREAMPLGAIN_MASK_SFT ,
gain_l < < RG_AUDPREAMPLGAIN_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDENC_ANA_CON1 ,
RG_AUDPREAMPRGAIN_MASK_SFT ,
gain_r < < RG_AUDPREAMPRGAIN_SFT ) ;
}
2019-01-22 14:39:10 +08:00
static int mt_mic_type_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
dev_dbg ( priv - > dev , " %s(), event 0x%x, mux %u \n " ,
__func__ , event , mux ) ;
switch ( event ) {
case SND_SOC_DAPM_WILL_PMU :
priv - > mux_select [ MUX_MIC_TYPE ] = mux ;
break ;
case SND_SOC_DAPM_PRE_PMU :
switch ( mux ) {
case MIC_TYPE_MUX_DMIC :
mt6358_dmic_enable ( priv ) ;
break ;
default :
mt6358_amic_enable ( priv ) ;
break ;
}
2019-05-07 18:12:20 +08:00
mt6358_restore_pga ( priv ) ;
2019-01-22 14:39:10 +08:00
break ;
case SND_SOC_DAPM_POST_PMD :
switch ( priv - > mux_select [ MUX_MIC_TYPE ] ) {
case MIC_TYPE_MUX_DMIC :
mt6358_dmic_disable ( priv ) ;
break ;
default :
mt6358_amic_disable ( priv ) ;
break ;
}
priv - > mux_select [ MUX_MIC_TYPE ] = mux ;
break ;
default :
break ;
}
return 0 ;
}
static int mt_adc_l_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x, mux %u \n " ,
__func__ , event , mux ) ;
priv - > mux_select [ MUX_ADC_L ] = mux ;
return 0 ;
}
static int mt_adc_r_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x, mux %u \n " ,
__func__ , event , mux ) ;
priv - > mux_select [ MUX_ADC_R ] = mux ;
return 0 ;
}
static int mt_pga_left_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x, mux %u \n " ,
__func__ , event , mux ) ;
priv - > mux_select [ MUX_PGA_L ] = mux ;
return 0 ;
}
static int mt_pga_right_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
struct snd_soc_component * cmpnt = snd_soc_dapm_to_component ( w - > dapm ) ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int mux = dapm_kcontrol_get_value ( w - > kcontrols [ 0 ] ) ;
dev_dbg ( priv - > dev , " %s(), event = 0x%x, mux %u \n " ,
__func__ , event , mux ) ;
priv - > mux_select [ MUX_PGA_R ] = mux ;
return 0 ;
}
static int mt_delay_250_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
usleep_range ( 250 , 270 ) ;
break ;
case SND_SOC_DAPM_PRE_PMD :
usleep_range ( 250 , 270 ) ;
break ;
default :
break ;
}
return 0 ;
}
/* DAPM Widgets */
static const struct snd_soc_dapm_widget mt6358_dapm_widgets [ ] = {
/* Global Supply*/
SND_SOC_DAPM_SUPPLY_S ( " CLK_BUF " , SUPPLY_SEQ_CLK_BUF ,
MT6358_DCXO_CW14 ,
RG_XO_AUDIO_EN_M_SFT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDGLB " , SUPPLY_SEQ_AUD_GLB ,
MT6358_AUDDEC_ANA_CON13 ,
RG_AUDGLB_PWRDN_VA28_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " CLKSQ Audio " , SUPPLY_SEQ_CLKSQ ,
MT6358_AUDENC_ANA_CON6 ,
RG_CLKSQ_EN_SFT , 0 ,
mt_clksq_event ,
SND_SOC_DAPM_PRE_PMU ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDNCP_CK " , SUPPLY_SEQ_TOP_CK ,
MT6358_AUD_TOP_CKPDN_CON0 ,
RG_AUDNCP_CK_PDN_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " ZCD13M_CK " , SUPPLY_SEQ_TOP_CK ,
MT6358_AUD_TOP_CKPDN_CON0 ,
RG_ZCD13M_CK_PDN_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUD_CK " , SUPPLY_SEQ_TOP_CK_LAST ,
MT6358_AUD_TOP_CKPDN_CON0 ,
RG_AUD_CK_PDN_SFT , 1 ,
mt_delay_250_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIF_CK " , SUPPLY_SEQ_TOP_CK ,
MT6358_AUD_TOP_CKPDN_CON0 ,
RG_AUDIF_CK_PDN_SFT , 1 , NULL , 0 ) ,
/* Digital Clock */
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_AFE_CTL " , SUPPLY_SEQ_AUD_TOP_LAST ,
MT6358_AUDIO_TOP_CON0 ,
PDN_AFE_CTL_SFT , 1 ,
mt_delay_250_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_DAC_CTL " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PDN_DAC_CTL_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_ADC_CTL " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PDN_ADC_CTL_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_I2S_DL " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PDN_I2S_DL_CTL_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_PWR_CLK " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PWR_CLK_DIS_CTL_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_PDN_AFE_TESTMODEL " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PDN_AFE_TESTMODEL_CTL_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY_S ( " AUDIO_TOP_PDN_RESERVED " , SUPPLY_SEQ_AUD_TOP ,
MT6358_AUDIO_TOP_CON0 ,
PDN_RESERVED_SFT , 1 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY ( " DL Digital Clock " , SND_SOC_NOPM ,
0 , 0 , NULL , 0 ) ,
/* AFE ON */
SND_SOC_DAPM_SUPPLY_S ( " AFE_ON " , SUPPLY_SEQ_AFE ,
MT6358_AFE_UL_DL_CON0 , AFE_ON_SFT , 0 ,
NULL , 0 ) ,
/* AIF Rx*/
SND_SOC_DAPM_AIF_IN_E ( " AIF_RX " , " AIF1 Playback " , 0 ,
MT6358_AFE_DL_SRC2_CON0_L ,
DL_2_SRC_ON_TMP_CTL_PRE_SFT , 0 ,
mt_aif_in_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD ) ,
/* DL Supply */
SND_SOC_DAPM_SUPPLY ( " DL Power Supply " , SND_SOC_NOPM ,
0 , 0 , NULL , 0 ) ,
/* DAC */
SND_SOC_DAPM_MUX ( " DAC In Mux " , SND_SOC_NOPM , 0 , 0 , & dac_in_mux_control ) ,
SND_SOC_DAPM_DAC ( " DACL " , NULL , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_DAC ( " DACR " , NULL , SND_SOC_NOPM , 0 , 0 ) ,
/* LOL */
SND_SOC_DAPM_MUX ( " LOL Mux " , SND_SOC_NOPM , 0 , 0 , & lo_in_mux_control ) ,
SND_SOC_DAPM_SUPPLY ( " LO Stability Enh " , MT6358_AUDDEC_ANA_CON7 ,
RG_LOOUTPUTSTBENH_VAUDP15_SFT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_OUT_DRV ( " LOL Buffer " , MT6358_AUDDEC_ANA_CON7 ,
RG_AUDLOLPWRUP_VAUDP15_SFT , 0 , NULL , 0 ) ,
/* Headphone */
SND_SOC_DAPM_MUX_E ( " HPL Mux " , SND_SOC_NOPM , 0 , 0 ,
& hpl_in_mux_control ,
mt_hp_event ,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_PRE_PMD ) ,
SND_SOC_DAPM_MUX_E ( " HPR Mux " , SND_SOC_NOPM , 0 , 0 ,
& hpr_in_mux_control ,
mt_hp_event ,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_PRE_PMD ) ,
/* Receiver */
SND_SOC_DAPM_MUX_E ( " RCV Mux " , SND_SOC_NOPM , 0 , 0 ,
& rcv_in_mux_control ,
mt_rcv_event ,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_PRE_PMD ) ,
/* Outputs */
SND_SOC_DAPM_OUTPUT ( " Receiver " ) ,
SND_SOC_DAPM_OUTPUT ( " Headphone L " ) ,
SND_SOC_DAPM_OUTPUT ( " Headphone R " ) ,
SND_SOC_DAPM_OUTPUT ( " Headphone L Ext Spk Amp " ) ,
SND_SOC_DAPM_OUTPUT ( " Headphone R Ext Spk Amp " ) ,
SND_SOC_DAPM_OUTPUT ( " LINEOUT L " ) ,
SND_SOC_DAPM_OUTPUT ( " LINEOUT L HSSPK " ) ,
/* SGEN */
SND_SOC_DAPM_SUPPLY ( " SGEN DL Enable " , MT6358_AFE_SGEN_CFG0 ,
SGEN_DAC_EN_CTL_SFT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY ( " SGEN MUTE " , MT6358_AFE_SGEN_CFG0 ,
SGEN_MUTE_SW_CTL_SFT , 1 ,
mt_sgen_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD ) ,
SND_SOC_DAPM_SUPPLY ( " SGEN DL SRC " , MT6358_AFE_DL_SRC2_CON0_L ,
DL_2_SRC_ON_TMP_CTL_PRE_SFT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_INPUT ( " SGEN DL " ) ,
/* Uplinks */
SND_SOC_DAPM_AIF_OUT_E ( " AIF1TX " , " AIF1 Capture " , 0 ,
SND_SOC_NOPM , 0 , 0 ,
mt_aif_out_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD ) ,
SND_SOC_DAPM_SUPPLY_S ( " ADC Supply " , SUPPLY_SEQ_ADC_SUPPLY ,
SND_SOC_NOPM , 0 , 0 ,
mt_adc_supply_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD ) ,
/* Uplinks MUX */
SND_SOC_DAPM_MUX ( " AIF Out Mux " , SND_SOC_NOPM , 0 , 0 ,
& aif_out_mux_control ) ,
SND_SOC_DAPM_MUX_E ( " Mic Type Mux " , SND_SOC_NOPM , 0 , 0 ,
& mic_type_mux_control ,
mt_mic_type_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_WILL_PMU ) ,
SND_SOC_DAPM_MUX_E ( " ADC L Mux " , SND_SOC_NOPM , 0 , 0 ,
& adc_left_mux_control ,
mt_adc_l_event ,
SND_SOC_DAPM_WILL_PMU ) ,
SND_SOC_DAPM_MUX_E ( " ADC R Mux " , SND_SOC_NOPM , 0 , 0 ,
& adc_right_mux_control ,
mt_adc_r_event ,
SND_SOC_DAPM_WILL_PMU ) ,
SND_SOC_DAPM_ADC ( " ADC L " , NULL , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_ADC ( " ADC R " , NULL , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_MUX_E ( " PGA L Mux " , SND_SOC_NOPM , 0 , 0 ,
& pga_left_mux_control ,
mt_pga_left_event ,
SND_SOC_DAPM_WILL_PMU ) ,
SND_SOC_DAPM_MUX_E ( " PGA R Mux " , SND_SOC_NOPM , 0 , 0 ,
& pga_right_mux_control ,
mt_pga_right_event ,
SND_SOC_DAPM_WILL_PMU ) ,
SND_SOC_DAPM_PGA ( " PGA L " , SND_SOC_NOPM , 0 , 0 , NULL , 0 ) ,
SND_SOC_DAPM_PGA ( " PGA R " , SND_SOC_NOPM , 0 , 0 , NULL , 0 ) ,
/* UL input */
SND_SOC_DAPM_INPUT ( " AIN0 " ) ,
SND_SOC_DAPM_INPUT ( " AIN1 " ) ,
SND_SOC_DAPM_INPUT ( " AIN2 " ) ,
} ;
static const struct snd_soc_dapm_route mt6358_dapm_routes [ ] = {
/* Capture */
{ " AIF1TX " , NULL , " AIF Out Mux " } ,
{ " AIF1TX " , NULL , " CLK_BUF " } ,
{ " AIF1TX " , NULL , " AUDGLB " } ,
{ " AIF1TX " , NULL , " CLKSQ Audio " } ,
{ " AIF1TX " , NULL , " AUD_CK " } ,
{ " AIF1TX " , NULL , " AUDIF_CK " } ,
{ " AIF1TX " , NULL , " AUDIO_TOP_AFE_CTL " } ,
{ " AIF1TX " , NULL , " AUDIO_TOP_ADC_CTL " } ,
{ " AIF1TX " , NULL , " AUDIO_TOP_PWR_CLK " } ,
{ " AIF1TX " , NULL , " AUDIO_TOP_PDN_RESERVED " } ,
{ " AIF1TX " , NULL , " AUDIO_TOP_I2S_DL " } ,
{ " AIF1TX " , NULL , " AFE_ON " } ,
{ " AIF Out Mux " , NULL , " Mic Type Mux " } ,
{ " Mic Type Mux " , " ACC " , " ADC L " } ,
{ " Mic Type Mux " , " ACC " , " ADC R " } ,
{ " Mic Type Mux " , " DCC " , " ADC L " } ,
{ " Mic Type Mux " , " DCC " , " ADC R " } ,
{ " Mic Type Mux " , " DCC_ECM_DIFF " , " ADC L " } ,
{ " Mic Type Mux " , " DCC_ECM_DIFF " , " ADC R " } ,
{ " Mic Type Mux " , " DCC_ECM_SINGLE " , " ADC L " } ,
{ " Mic Type Mux " , " DCC_ECM_SINGLE " , " ADC R " } ,
{ " Mic Type Mux " , " DMIC " , " AIN0 " } ,
{ " Mic Type Mux " , " DMIC " , " AIN2 " } ,
{ " ADC L " , NULL , " ADC L Mux " } ,
{ " ADC L " , NULL , " ADC Supply " } ,
{ " ADC R " , NULL , " ADC R Mux " } ,
{ " ADC R " , NULL , " ADC Supply " } ,
{ " ADC L Mux " , " Left Preamplifier " , " PGA L " } ,
{ " ADC R Mux " , " Right Preamplifier " , " PGA R " } ,
{ " PGA L " , NULL , " PGA L Mux " } ,
{ " PGA R " , NULL , " PGA R Mux " } ,
{ " PGA L Mux " , " AIN0 " , " AIN0 " } ,
{ " PGA L Mux " , " AIN1 " , " AIN1 " } ,
{ " PGA L Mux " , " AIN2 " , " AIN2 " } ,
{ " PGA R Mux " , " AIN0 " , " AIN0 " } ,
{ " PGA R Mux " , " AIN1 " , " AIN1 " } ,
{ " PGA R Mux " , " AIN2 " , " AIN2 " } ,
/* DL Supply */
{ " DL Power Supply " , NULL , " CLK_BUF " } ,
{ " DL Power Supply " , NULL , " AUDGLB " } ,
{ " DL Power Supply " , NULL , " CLKSQ Audio " } ,
{ " DL Power Supply " , NULL , " AUDNCP_CK " } ,
{ " DL Power Supply " , NULL , " ZCD13M_CK " } ,
{ " DL Power Supply " , NULL , " AUD_CK " } ,
{ " DL Power Supply " , NULL , " AUDIF_CK " } ,
/* DL Digital Supply */
{ " DL Digital Clock " , NULL , " AUDIO_TOP_AFE_CTL " } ,
{ " DL Digital Clock " , NULL , " AUDIO_TOP_DAC_CTL " } ,
{ " DL Digital Clock " , NULL , " AUDIO_TOP_PWR_CLK " } ,
{ " DL Digital Clock " , NULL , " AFE_ON " } ,
{ " AIF_RX " , NULL , " DL Digital Clock " } ,
/* DL Path */
{ " DAC In Mux " , " Normal Path " , " AIF_RX " } ,
{ " DAC In Mux " , " Sgen " , " SGEN DL " } ,
{ " SGEN DL " , NULL , " SGEN DL SRC " } ,
{ " SGEN DL " , NULL , " SGEN MUTE " } ,
{ " SGEN DL " , NULL , " SGEN DL Enable " } ,
{ " SGEN DL " , NULL , " DL Digital Clock " } ,
{ " SGEN DL " , NULL , " AUDIO_TOP_PDN_AFE_TESTMODEL " } ,
{ " DACL " , NULL , " DAC In Mux " } ,
{ " DACL " , NULL , " DL Power Supply " } ,
{ " DACR " , NULL , " DAC In Mux " } ,
{ " DACR " , NULL , " DL Power Supply " } ,
/* Lineout Path */
{ " LOL Mux " , " Playback " , " DACL " } ,
{ " LOL Buffer " , NULL , " LOL Mux " } ,
{ " LOL Buffer " , NULL , " LO Stability Enh " } ,
{ " LINEOUT L " , NULL , " LOL Buffer " } ,
/* Headphone Path */
{ " HPL Mux " , " Audio Playback " , " DACL " } ,
{ " HPR Mux " , " Audio Playback " , " DACR " } ,
{ " HPL Mux " , " HP Impedance " , " DACL " } ,
{ " HPR Mux " , " HP Impedance " , " DACR " } ,
{ " HPL Mux " , " LoudSPK Playback " , " DACL " } ,
{ " HPR Mux " , " LoudSPK Playback " , " DACR " } ,
{ " Headphone L " , NULL , " HPL Mux " } ,
{ " Headphone R " , NULL , " HPR Mux " } ,
{ " Headphone L Ext Spk Amp " , NULL , " HPL Mux " } ,
{ " Headphone R Ext Spk Amp " , NULL , " HPR Mux " } ,
{ " LINEOUT L HSSPK " , NULL , " HPL Mux " } ,
/* Receiver Path */
{ " RCV Mux " , " Voice Playback " , " DACL " } ,
{ " Receiver " , NULL , " RCV Mux " } ,
} ;
static int mt6358_codec_dai_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
struct snd_soc_component * cmpnt = dai - > component ;
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
unsigned int rate = params_rate ( params ) ;
dev_info ( priv - > dev , " %s(), substream->stream %d, rate %d, number %d \n " ,
__func__ ,
substream - > stream ,
rate ,
substream - > number ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
priv - > dl_rate = rate ;
else if ( substream - > stream = = SNDRV_PCM_STREAM_CAPTURE )
priv - > ul_rate = rate ;
return 0 ;
}
static const struct snd_soc_dai_ops mt6358_codec_dai_ops = {
. hw_params = mt6358_codec_dai_hw_params ,
} ;
# define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE )
static struct snd_soc_dai_driver mt6358_dai_driver [ ] = {
{
. name = " mt6358-snd-codec-aif1 " ,
. playback = {
. stream_name = " AIF1 Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 |
SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_192000 ,
. formats = MT6358_FORMATS ,
} ,
. capture = {
. stream_name = " AIF1 Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_48000 ,
. formats = MT6358_FORMATS ,
} ,
. ops = & mt6358_codec_dai_ops ,
} ,
} ;
2019-07-09 23:55:43 +05:30
static void mt6358_codec_init_reg ( struct mt6358_priv * priv )
2019-01-22 14:39:10 +08:00
{
/* Disable HeadphoneL/HeadphoneR short circuit protection */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT ,
0x1 < < RG_AUDHPLSCDISABLE_VAUDP15_SFT ) ;
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON0 ,
RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT ,
0x1 < < RG_AUDHPRSCDISABLE_VAUDP15_SFT ) ;
/* Disable voice short circuit protection */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON6 ,
RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT ,
0x1 < < RG_AUDHSSCDISABLE_VAUDP15_SFT ) ;
/* disable LO buffer left short circuit protection */
regmap_update_bits ( priv - > regmap , MT6358_AUDDEC_ANA_CON7 ,
RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT ,
0x1 < < RG_AUDLOLSCDISABLE_VAUDP15_SFT ) ;
/* accdet s/w enable */
regmap_update_bits ( priv - > regmap , MT6358_ACCDET_CON13 ,
0xFFFF , 0x700E ) ;
/* gpio miso driving set to 4mA */
regmap_write ( priv - > regmap , MT6358_DRV_CON3 , 0x8888 ) ;
/* set gpio */
playback_gpio_reset ( priv ) ;
capture_gpio_reset ( priv ) ;
}
static int mt6358_codec_probe ( struct snd_soc_component * cmpnt )
{
struct mt6358_priv * priv = snd_soc_component_get_drvdata ( cmpnt ) ;
int ret ;
snd_soc_component_init_regmap ( cmpnt , priv - > regmap ) ;
mt6358_codec_init_reg ( priv ) ;
priv - > avdd_reg = devm_regulator_get ( priv - > dev , " Avdd " ) ;
if ( IS_ERR ( priv - > avdd_reg ) ) {
dev_err ( priv - > dev , " %s() have no Avdd supply " , __func__ ) ;
return PTR_ERR ( priv - > avdd_reg ) ;
}
ret = regulator_enable ( priv - > avdd_reg ) ;
if ( ret )
return ret ;
return 0 ;
}
static const struct snd_soc_component_driver mt6358_soc_component_driver = {
. probe = mt6358_codec_probe ,
. controls = mt6358_snd_controls ,
. num_controls = ARRAY_SIZE ( mt6358_snd_controls ) ,
. dapm_widgets = mt6358_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( mt6358_dapm_widgets ) ,
. dapm_routes = mt6358_dapm_routes ,
. num_dapm_routes = ARRAY_SIZE ( mt6358_dapm_routes ) ,
} ;
2020-06-05 18:33:41 +08:00
static void mt6358_parse_dt ( struct mt6358_priv * priv )
{
int ret ;
struct device * dev = priv - > dev ;
ret = of_property_read_u32 ( dev - > of_node , " mediatek,dmic-mode " ,
& priv - > dmic_one_wire_mode ) ;
if ( ret ) {
dev_warn ( priv - > dev , " %s() failed to read dmic-mode \n " ,
__func__ ) ;
priv - > dmic_one_wire_mode = 0 ;
}
}
2019-01-22 14:39:10 +08:00
static int mt6358_platform_driver_probe ( struct platform_device * pdev )
{
struct mt6358_priv * priv ;
struct mt6397_chip * mt6397 = dev_get_drvdata ( pdev - > dev . parent ) ;
priv = devm_kzalloc ( & pdev - > dev ,
sizeof ( struct mt6358_priv ) ,
GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
dev_set_drvdata ( & pdev - > dev , priv ) ;
priv - > dev = & pdev - > dev ;
priv - > regmap = mt6397 - > regmap ;
if ( IS_ERR ( priv - > regmap ) )
return PTR_ERR ( priv - > regmap ) ;
2020-06-05 18:33:41 +08:00
mt6358_parse_dt ( priv ) ;
2019-01-22 14:39:10 +08:00
dev_info ( priv - > dev , " %s(), dev name %s \n " ,
__func__ , dev_name ( & pdev - > dev ) ) ;
return devm_snd_soc_register_component ( & pdev - > dev ,
& mt6358_soc_component_driver ,
mt6358_dai_driver ,
ARRAY_SIZE ( mt6358_dai_driver ) ) ;
}
static const struct of_device_id mt6358_of_match [ ] = {
{ . compatible = " mediatek,mt6358-sound " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , mt6358_of_match ) ;
static struct platform_driver mt6358_platform_driver = {
. driver = {
. name = " mt6358-sound " ,
. of_match_table = mt6358_of_match ,
} ,
. probe = mt6358_platform_driver_probe ,
} ;
module_platform_driver ( mt6358_platform_driver )
/* Module information */
MODULE_DESCRIPTION ( " MT6358 ALSA SoC codec driver " ) ;
MODULE_AUTHOR ( " KaiChieh Chuang <kaichieh.chuang@mediatek.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;