2019-05-19 15:51:31 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-03-02 14:52:32 +01:00
/*
* linux / sound / soc / codecs / tlv320aic32x4 . c
*
* Copyright 2011 Vista Silicon S . L .
*
* Author : Javier Martin < javier . martin @ vista - silicon . com >
*
* Based on sound / soc / codecs / wm8974 and TI driver for kernel 2.6 .27 .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
2012-10-31 11:53:34 +01:00
# include <linux/gpio.h>
2014-01-27 13:03:08 +01:00
# include <linux/of_gpio.h>
2011-03-02 14:52:32 +01:00
# include <linux/cdev.h>
# include <linux/slab.h>
2014-02-20 18:22:58 +01:00
# include <linux/clk.h>
2019-03-21 17:58:45 -07:00
# include <linux/of_clk.h>
2014-02-20 18:22:59 +01:00
# include <linux/regulator/consumer.h>
2011-03-02 14:52:32 +01:00
# include <sound/tlv320aic32x4.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/soc-dapm.h>
# include <sound/initval.h>
# include <sound/tlv.h>
# include "tlv320aic32x4.h"
struct aic32x4_priv {
2013-09-25 11:37:53 +01:00
struct regmap * regmap ;
2011-03-02 14:52:32 +01:00
u32 power_cfg ;
u32 micpga_routing ;
bool swapdacs ;
2012-10-31 11:53:34 +01:00
int rstn_gpio ;
2019-03-21 17:58:45 -07:00
const char * mclk_name ;
2014-02-20 18:22:59 +01:00
struct regulator * supply_ldo ;
struct regulator * supply_iov ;
struct regulator * supply_dv ;
struct regulator * supply_av ;
2017-07-12 13:37:00 -05:00
struct aic32x4_setup_data * setup ;
struct device * dev ;
} ;
2019-01-09 22:41:21 +05:30
static int mic_bias_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
/* Change Mic Bias Registor */
snd_soc_component_update_bits ( component , AIC32X4_MICBIAS ,
AIC32x4_MICBIAS_MASK ,
AIC32X4_MICBIAS_LDOIN |
AIC32X4_MICBIAS_2075V ) ;
printk ( KERN_DEBUG " %s: Mic Bias will be turned ON \n " , __func__ ) ;
break ;
case SND_SOC_DAPM_PRE_PMD :
snd_soc_component_update_bits ( component , AIC32X4_MICBIAS ,
AIC32x4_MICBIAS_MASK , 0 ) ;
printk ( KERN_DEBUG " %s: Mic Bias will be turned OFF \n " ,
__func__ ) ;
break ;
}
return 0 ;
}
2017-07-12 13:37:00 -05:00
static int aic32x4_get_mfp1_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_DINCTL ) ;
2017-07-12 13:37:00 -05:00
ucontrol - > value . integer . value [ 0 ] = ( val & 0x01 ) ;
return 0 ;
} ;
static int aic32x4_set_mfp2_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
u8 gpio_check ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_DOUTCTL ) ;
2017-07-12 13:37:00 -05:00
gpio_check = ( val & AIC32X4_MFP_GPIO_ENABLED ) ;
if ( gpio_check ! = AIC32X4_MFP_GPIO_ENABLED ) {
printk ( KERN_ERR " %s: MFP2 is not configure as a GPIO output \n " ,
__func__ ) ;
return - EINVAL ;
}
if ( ucontrol - > value . integer . value [ 0 ] = = ( val & AIC32X4_MFP2_GPIO_OUT_HIGH ) )
return 0 ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = ucontrol - > value . integer . value [ 0 ] ;
else
val & = ~ AIC32X4_MFP2_GPIO_OUT_HIGH ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_DOUTCTL , val ) ;
2017-07-12 13:37:00 -05:00
return 0 ;
} ;
static int aic32x4_get_mfp3_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_SCLKCTL ) ;
2017-07-12 13:37:00 -05:00
ucontrol - > value . integer . value [ 0 ] = ( val & 0x01 ) ;
return 0 ;
} ;
static int aic32x4_set_mfp4_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
u8 gpio_check ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_MISOCTL ) ;
2017-07-12 13:37:00 -05:00
gpio_check = ( val & AIC32X4_MFP_GPIO_ENABLED ) ;
if ( gpio_check ! = AIC32X4_MFP_GPIO_ENABLED ) {
printk ( KERN_ERR " %s: MFP4 is not configure as a GPIO output \n " ,
__func__ ) ;
return - EINVAL ;
}
if ( ucontrol - > value . integer . value [ 0 ] = = ( val & AIC32X4_MFP5_GPIO_OUT_HIGH ) )
return 0 ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = ucontrol - > value . integer . value [ 0 ] ;
else
val & = ~ AIC32X4_MFP5_GPIO_OUT_HIGH ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_MISOCTL , val ) ;
2017-07-12 13:37:00 -05:00
return 0 ;
} ;
static int aic32x4_get_mfp5_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_GPIOCTL ) ;
2017-07-12 13:37:00 -05:00
ucontrol - > value . integer . value [ 0 ] = ( ( val & 0x2 ) > > 1 ) ;
return 0 ;
} ;
static int aic32x4_set_mfp5_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 13:37:00 -05:00
u8 val ;
u8 gpio_check ;
2018-01-29 04:14:49 +00:00
val = snd_soc_component_read32 ( component , AIC32X4_GPIOCTL ) ;
2017-07-12 13:37:00 -05:00
gpio_check = ( val & AIC32X4_MFP5_GPIO_OUTPUT ) ;
if ( gpio_check ! = AIC32X4_MFP5_GPIO_OUTPUT ) {
printk ( KERN_ERR " %s: MFP5 is not configure as a GPIO output \n " ,
__func__ ) ;
return - EINVAL ;
}
if ( ucontrol - > value . integer . value [ 0 ] = = ( val & 0x1 ) )
return 0 ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = ucontrol - > value . integer . value [ 0 ] ;
else
val & = 0xfe ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_GPIOCTL , val ) ;
2017-07-12 13:37:00 -05:00
return 0 ;
} ;
static const struct snd_kcontrol_new aic32x4_mfp1 [ ] = {
SOC_SINGLE_BOOL_EXT ( " MFP1 GPIO " , 0 , aic32x4_get_mfp1_gpio , NULL ) ,
} ;
static const struct snd_kcontrol_new aic32x4_mfp2 [ ] = {
SOC_SINGLE_BOOL_EXT ( " MFP2 GPIO " , 0 , NULL , aic32x4_set_mfp2_gpio ) ,
} ;
static const struct snd_kcontrol_new aic32x4_mfp3 [ ] = {
SOC_SINGLE_BOOL_EXT ( " MFP3 GPIO " , 0 , aic32x4_get_mfp3_gpio , NULL ) ,
} ;
static const struct snd_kcontrol_new aic32x4_mfp4 [ ] = {
SOC_SINGLE_BOOL_EXT ( " MFP4 GPIO " , 0 , NULL , aic32x4_set_mfp4_gpio ) ,
} ;
static const struct snd_kcontrol_new aic32x4_mfp5 [ ] = {
SOC_SINGLE_BOOL_EXT ( " MFP5 GPIO " , 0 , aic32x4_get_mfp5_gpio ,
aic32x4_set_mfp5_gpio ) ,
2011-03-02 14:52:32 +01:00
} ;
/* 0dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE ( tlv_step_0_5 , 0 , 50 , 0 ) ;
2014-01-27 13:03:07 +01:00
/* -63.5dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE ( tlv_pcm , - 6350 , 50 , 0 ) ;
/* -6dB min, 1dB steps */
static DECLARE_TLV_DB_SCALE ( tlv_driver_gain , - 600 , 100 , 0 ) ;
/* -12dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE ( tlv_adc_vol , - 1200 , 50 , 0 ) ;
2011-03-02 14:52:32 +01:00
2019-04-03 21:01:54 -07:00
static const char * const lo_cm_text [ ] = {
" Full Chip " , " 1.65V " ,
} ;
static SOC_ENUM_SINGLE_DECL ( lo_cm_enum , AIC32X4_CMMODE , 3 , lo_cm_text ) ;
2019-04-03 21:01:55 -07:00
static const char * const ptm_text [ ] = {
" P3 " , " P2 " , " P1 " ,
} ;
static SOC_ENUM_SINGLE_DECL ( l_ptm_enum , AIC32X4_LPLAYBACK , 2 , ptm_text ) ;
static SOC_ENUM_SINGLE_DECL ( r_ptm_enum , AIC32X4_RPLAYBACK , 2 , ptm_text ) ;
2011-03-02 14:52:32 +01:00
static const struct snd_kcontrol_new aic32x4_snd_controls [ ] = {
2014-01-27 13:03:07 +01:00
SOC_DOUBLE_R_S_TLV ( " PCM Playback Volume " , AIC32X4_LDACVOL ,
AIC32X4_RDACVOL , 0 , - 0x7f , 0x30 , 7 , 0 , tlv_pcm ) ,
2019-04-03 21:01:55 -07:00
SOC_ENUM ( " DAC Left Playback PowerTune Switch " , l_ptm_enum ) ,
SOC_ENUM ( " DAC Right Playback PowerTune Switch " , r_ptm_enum ) ,
2014-01-27 13:03:07 +01:00
SOC_DOUBLE_R_S_TLV ( " HP Driver Gain Volume " , AIC32X4_HPLGAIN ,
AIC32X4_HPRGAIN , 0 , - 0x6 , 0x1d , 5 , 0 ,
tlv_driver_gain ) ,
SOC_DOUBLE_R_S_TLV ( " LO Driver Gain Volume " , AIC32X4_LOLGAIN ,
AIC32X4_LORGAIN , 0 , - 0x6 , 0x1d , 5 , 0 ,
tlv_driver_gain ) ,
2011-03-02 14:52:32 +01:00
SOC_DOUBLE_R ( " HP DAC Playback Switch " , AIC32X4_HPLGAIN ,
AIC32X4_HPRGAIN , 6 , 0x01 , 1 ) ,
SOC_DOUBLE_R ( " LO DAC Playback Switch " , AIC32X4_LOLGAIN ,
AIC32X4_LORGAIN , 6 , 0x01 , 1 ) ,
2019-04-03 21:01:54 -07:00
SOC_ENUM ( " LO Playback Common Mode Switch " , lo_cm_enum ) ,
2011-03-02 14:52:32 +01:00
SOC_DOUBLE_R ( " Mic PGA Switch " , AIC32X4_LMICPGAVOL ,
AIC32X4_RMICPGAVOL , 7 , 0x01 , 1 ) ,
SOC_SINGLE ( " ADCFGA Left Mute Switch " , AIC32X4_ADCFGA , 7 , 1 , 0 ) ,
SOC_SINGLE ( " ADCFGA Right Mute Switch " , AIC32X4_ADCFGA , 3 , 1 , 0 ) ,
2014-01-27 13:03:07 +01:00
SOC_DOUBLE_R_S_TLV ( " ADC Level Volume " , AIC32X4_LADCVOL ,
AIC32X4_RADCVOL , 0 , - 0x18 , 0x28 , 6 , 0 , tlv_adc_vol ) ,
2011-03-02 14:52:32 +01:00
SOC_DOUBLE_R_TLV ( " PGA Level Volume " , AIC32X4_LMICPGAVOL ,
AIC32X4_RMICPGAVOL , 0 , 0x5f , 0 , tlv_step_0_5 ) ,
SOC_SINGLE ( " Auto-mute Switch " , AIC32X4_DACMUTE , 4 , 7 , 0 ) ,
SOC_SINGLE ( " AGC Left Switch " , AIC32X4_LAGC1 , 7 , 1 , 0 ) ,
SOC_SINGLE ( " AGC Right Switch " , AIC32X4_RAGC1 , 7 , 1 , 0 ) ,
SOC_DOUBLE_R ( " AGC Target Level " , AIC32X4_LAGC1 , AIC32X4_RAGC1 ,
4 , 0x07 , 0 ) ,
SOC_DOUBLE_R ( " AGC Gain Hysteresis " , AIC32X4_LAGC1 , AIC32X4_RAGC1 ,
0 , 0x03 , 0 ) ,
SOC_DOUBLE_R ( " AGC Hysteresis " , AIC32X4_LAGC2 , AIC32X4_RAGC2 ,
6 , 0x03 , 0 ) ,
SOC_DOUBLE_R ( " AGC Noise Threshold " , AIC32X4_LAGC2 , AIC32X4_RAGC2 ,
1 , 0x1F , 0 ) ,
SOC_DOUBLE_R ( " AGC Max PGA " , AIC32X4_LAGC3 , AIC32X4_RAGC3 ,
0 , 0x7F , 0 ) ,
SOC_DOUBLE_R ( " AGC Attack Time " , AIC32X4_LAGC4 , AIC32X4_RAGC4 ,
3 , 0x1F , 0 ) ,
SOC_DOUBLE_R ( " AGC Decay Time " , AIC32X4_LAGC5 , AIC32X4_RAGC5 ,
3 , 0x1F , 0 ) ,
SOC_DOUBLE_R ( " AGC Noise Debounce " , AIC32X4_LAGC6 , AIC32X4_RAGC6 ,
0 , 0x1F , 0 ) ,
SOC_DOUBLE_R ( " AGC Signal Debounce " , AIC32X4_LAGC7 , AIC32X4_RAGC7 ,
0 , 0x0F , 0 ) ,
} ;
static const struct snd_kcontrol_new hpl_output_mixer_controls [ ] = {
SOC_DAPM_SINGLE ( " L_DAC Switch " , AIC32X4_HPLROUTE , 3 , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " IN1_L Switch " , AIC32X4_HPLROUTE , 2 , 1 , 0 ) ,
} ;
static const struct snd_kcontrol_new hpr_output_mixer_controls [ ] = {
SOC_DAPM_SINGLE ( " R_DAC Switch " , AIC32X4_HPRROUTE , 3 , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " IN1_R Switch " , AIC32X4_HPRROUTE , 2 , 1 , 0 ) ,
} ;
static const struct snd_kcontrol_new lol_output_mixer_controls [ ] = {
SOC_DAPM_SINGLE ( " L_DAC Switch " , AIC32X4_LOLROUTE , 3 , 1 , 0 ) ,
} ;
static const struct snd_kcontrol_new lor_output_mixer_controls [ ] = {
SOC_DAPM_SINGLE ( " R_DAC Switch " , AIC32X4_LORROUTE , 3 , 1 , 0 ) ,
} ;
2016-04-20 11:39:11 -07:00
static const char * const resistor_text [ ] = {
" Off " , " 10 kOhm " , " 20 kOhm " , " 40 kOhm " ,
} ;
2016-05-11 12:09:53 -07:00
/* Left mixer pins */
static SOC_ENUM_SINGLE_DECL ( in1l_lpga_p_enum , AIC32X4_LMICPGAPIN , 6 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in2l_lpga_p_enum , AIC32X4_LMICPGAPIN , 4 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in3l_lpga_p_enum , AIC32X4_LMICPGAPIN , 2 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in1r_lpga_p_enum , AIC32X4_LMICPGAPIN , 0 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( cml_lpga_n_enum , AIC32X4_LMICPGANIN , 6 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in2r_lpga_n_enum , AIC32X4_LMICPGANIN , 4 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in3r_lpga_n_enum , AIC32X4_LMICPGANIN , 2 , resistor_text ) ;
static const struct snd_kcontrol_new in1l_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN1_L L+ Switch " , in1l_lpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in2l_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN2_L L+ Switch " , in2l_lpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in3l_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN3_L L+ Switch " , in3l_lpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in1r_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN1_R L+ Switch " , in1r_lpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new cml_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " CM_L L- Switch " , cml_lpga_n_enum ) ,
} ;
static const struct snd_kcontrol_new in2r_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN2_R L- Switch " , in2r_lpga_n_enum ) ,
} ;
static const struct snd_kcontrol_new in3r_to_lmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN3_R L- Switch " , in3r_lpga_n_enum ) ,
2011-03-02 14:52:32 +01:00
} ;
2019-03-21 17:58:45 -07:00
/* Right mixer pins */
2016-05-11 12:09:53 -07:00
static SOC_ENUM_SINGLE_DECL ( in1r_rpga_p_enum , AIC32X4_RMICPGAPIN , 6 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in2r_rpga_p_enum , AIC32X4_RMICPGAPIN , 4 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in3r_rpga_p_enum , AIC32X4_RMICPGAPIN , 2 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in2l_rpga_p_enum , AIC32X4_RMICPGAPIN , 0 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( cmr_rpga_n_enum , AIC32X4_RMICPGANIN , 6 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in1l_rpga_n_enum , AIC32X4_RMICPGANIN , 4 , resistor_text ) ;
static SOC_ENUM_SINGLE_DECL ( in3l_rpga_n_enum , AIC32X4_RMICPGANIN , 2 , resistor_text ) ;
static const struct snd_kcontrol_new in1r_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN1_R R+ Switch " , in1r_rpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in2r_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN2_R R+ Switch " , in2r_rpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in3r_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN3_R R+ Switch " , in3r_rpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new in2l_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN2_L R+ Switch " , in2l_rpga_p_enum ) ,
} ;
static const struct snd_kcontrol_new cmr_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " CM_R R- Switch " , cmr_rpga_n_enum ) ,
} ;
static const struct snd_kcontrol_new in1l_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN1_L R- Switch " , in1l_rpga_n_enum ) ,
} ;
static const struct snd_kcontrol_new in3l_to_rmixer_controls [ ] = {
SOC_DAPM_ENUM ( " IN3_L R- Switch " , in3l_rpga_n_enum ) ,
2011-03-02 14:52:32 +01:00
} ;
static const struct snd_soc_dapm_widget aic32x4_dapm_widgets [ ] = {
SND_SOC_DAPM_DAC ( " Left DAC " , " Left Playback " , AIC32X4_DACSETUP , 7 , 0 ) ,
SND_SOC_DAPM_MIXER ( " HPL Output Mixer " , SND_SOC_NOPM , 0 , 0 ,
& hpl_output_mixer_controls [ 0 ] ,
ARRAY_SIZE ( hpl_output_mixer_controls ) ) ,
SND_SOC_DAPM_PGA ( " HPL Power " , AIC32X4_OUTPWRCTL , 5 , 0 , NULL , 0 ) ,
SND_SOC_DAPM_MIXER ( " LOL Output Mixer " , SND_SOC_NOPM , 0 , 0 ,
& lol_output_mixer_controls [ 0 ] ,
ARRAY_SIZE ( lol_output_mixer_controls ) ) ,
SND_SOC_DAPM_PGA ( " LOL Power " , AIC32X4_OUTPWRCTL , 3 , 0 , NULL , 0 ) ,
SND_SOC_DAPM_DAC ( " Right DAC " , " Right Playback " , AIC32X4_DACSETUP , 6 , 0 ) ,
SND_SOC_DAPM_MIXER ( " HPR Output Mixer " , SND_SOC_NOPM , 0 , 0 ,
& hpr_output_mixer_controls [ 0 ] ,
ARRAY_SIZE ( hpr_output_mixer_controls ) ) ,
SND_SOC_DAPM_PGA ( " HPR Power " , AIC32X4_OUTPWRCTL , 4 , 0 , NULL , 0 ) ,
SND_SOC_DAPM_MIXER ( " LOR Output Mixer " , SND_SOC_NOPM , 0 , 0 ,
& lor_output_mixer_controls [ 0 ] ,
ARRAY_SIZE ( lor_output_mixer_controls ) ) ,
SND_SOC_DAPM_PGA ( " LOR Power " , AIC32X4_OUTPWRCTL , 2 , 0 , NULL , 0 ) ,
2016-05-11 12:09:53 -07:00
2011-03-02 14:52:32 +01:00
SND_SOC_DAPM_ADC ( " Right ADC " , " Right Capture " , AIC32X4_ADCSETUP , 6 , 0 ) ,
2016-05-11 12:09:53 -07:00
SND_SOC_DAPM_MUX ( " IN1_R to Right Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in1r_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN2_R to Right Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in2r_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN3_R to Right Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in3r_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN2_L to Right Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in2l_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " CM_R to Right Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
cmr_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN1_L to Right Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
in1l_to_rmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN3_L to Right Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
in3l_to_rmixer_controls ) ,
SND_SOC_DAPM_ADC ( " Left ADC " , " Left Capture " , AIC32X4_ADCSETUP , 7 , 0 ) ,
SND_SOC_DAPM_MUX ( " IN1_L to Left Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in1l_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN2_L to Left Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in2l_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN3_L to Left Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in3l_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN1_R to Left Mixer Positive Resistor " , SND_SOC_NOPM , 0 , 0 ,
in1r_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " CM_L to Left Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
cml_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN2_R to Left Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
in2r_to_lmixer_controls ) ,
SND_SOC_DAPM_MUX ( " IN3_R to Left Mixer Negative Resistor " , SND_SOC_NOPM , 0 , 0 ,
in3r_to_lmixer_controls ) ,
2019-01-09 22:41:21 +05:30
SND_SOC_DAPM_SUPPLY ( " Mic Bias " , AIC32X4_MICBIAS , 6 , 0 , mic_bias_event ,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD ) ,
2011-03-02 14:52:32 +01:00
SND_SOC_DAPM_OUTPUT ( " HPL " ) ,
SND_SOC_DAPM_OUTPUT ( " HPR " ) ,
SND_SOC_DAPM_OUTPUT ( " LOL " ) ,
SND_SOC_DAPM_OUTPUT ( " LOR " ) ,
SND_SOC_DAPM_INPUT ( " IN1_L " ) ,
SND_SOC_DAPM_INPUT ( " IN1_R " ) ,
SND_SOC_DAPM_INPUT ( " IN2_L " ) ,
SND_SOC_DAPM_INPUT ( " IN2_R " ) ,
SND_SOC_DAPM_INPUT ( " IN3_L " ) ,
SND_SOC_DAPM_INPUT ( " IN3_R " ) ,
2019-03-30 09:02:02 -07:00
SND_SOC_DAPM_INPUT ( " CM_L " ) ,
SND_SOC_DAPM_INPUT ( " CM_R " ) ,
2011-03-02 14:52:32 +01:00
} ;
static const struct snd_soc_dapm_route aic32x4_dapm_routes [ ] = {
/* Left Output */
{ " HPL Output Mixer " , " L_DAC Switch " , " Left DAC " } ,
{ " HPL Output Mixer " , " IN1_L Switch " , " IN1_L " } ,
{ " HPL Power " , NULL , " HPL Output Mixer " } ,
{ " HPL " , NULL , " HPL Power " } ,
{ " LOL Output Mixer " , " L_DAC Switch " , " Left DAC " } ,
{ " LOL Power " , NULL , " LOL Output Mixer " } ,
{ " LOL " , NULL , " LOL Power " } ,
/* Right Output */
{ " HPR Output Mixer " , " R_DAC Switch " , " Right DAC " } ,
{ " HPR Output Mixer " , " IN1_R Switch " , " IN1_R " } ,
{ " HPR Power " , NULL , " HPR Output Mixer " } ,
{ " HPR " , NULL , " HPR Power " } ,
{ " LOR Output Mixer " , " R_DAC Switch " , " Right DAC " } ,
{ " LOR Power " , NULL , " LOR Output Mixer " } ,
{ " LOR " , NULL , " LOR Power " } ,
/* Right Input */
2016-05-11 12:09:53 -07:00
{ " Right ADC " , NULL , " IN1_R to Right Mixer Positive Resistor " } ,
{ " IN1_R to Right Mixer Positive Resistor " , " 10 kOhm " , " IN1_R " } ,
{ " IN1_R to Right Mixer Positive Resistor " , " 20 kOhm " , " IN1_R " } ,
{ " IN1_R to Right Mixer Positive Resistor " , " 40 kOhm " , " IN1_R " } ,
{ " Right ADC " , NULL , " IN2_R to Right Mixer Positive Resistor " } ,
{ " IN2_R to Right Mixer Positive Resistor " , " 10 kOhm " , " IN2_R " } ,
{ " IN2_R to Right Mixer Positive Resistor " , " 20 kOhm " , " IN2_R " } ,
{ " IN2_R to Right Mixer Positive Resistor " , " 40 kOhm " , " IN2_R " } ,
{ " Right ADC " , NULL , " IN3_R to Right Mixer Positive Resistor " } ,
{ " IN3_R to Right Mixer Positive Resistor " , " 10 kOhm " , " IN3_R " } ,
{ " IN3_R to Right Mixer Positive Resistor " , " 20 kOhm " , " IN3_R " } ,
{ " IN3_R to Right Mixer Positive Resistor " , " 40 kOhm " , " IN3_R " } ,
{ " Right ADC " , NULL , " IN2_L to Right Mixer Positive Resistor " } ,
{ " IN2_L to Right Mixer Positive Resistor " , " 10 kOhm " , " IN2_L " } ,
{ " IN2_L to Right Mixer Positive Resistor " , " 20 kOhm " , " IN2_L " } ,
{ " IN2_L to Right Mixer Positive Resistor " , " 40 kOhm " , " IN2_L " } ,
{ " Right ADC " , NULL , " CM_R to Right Mixer Negative Resistor " } ,
{ " CM_R to Right Mixer Negative Resistor " , " 10 kOhm " , " CM_R " } ,
{ " CM_R to Right Mixer Negative Resistor " , " 20 kOhm " , " CM_R " } ,
{ " CM_R to Right Mixer Negative Resistor " , " 40 kOhm " , " CM_R " } ,
{ " Right ADC " , NULL , " IN1_L to Right Mixer Negative Resistor " } ,
{ " IN1_L to Right Mixer Negative Resistor " , " 10 kOhm " , " IN1_L " } ,
{ " IN1_L to Right Mixer Negative Resistor " , " 20 kOhm " , " IN1_L " } ,
{ " IN1_L to Right Mixer Negative Resistor " , " 40 kOhm " , " IN1_L " } ,
{ " Right ADC " , NULL , " IN3_L to Right Mixer Negative Resistor " } ,
{ " IN3_L to Right Mixer Negative Resistor " , " 10 kOhm " , " IN3_L " } ,
{ " IN3_L to Right Mixer Negative Resistor " , " 20 kOhm " , " IN3_L " } ,
{ " IN3_L to Right Mixer Negative Resistor " , " 40 kOhm " , " IN3_L " } ,
/* Left Input */
{ " Left ADC " , NULL , " IN1_L to Left Mixer Positive Resistor " } ,
{ " IN1_L to Left Mixer Positive Resistor " , " 10 kOhm " , " IN1_L " } ,
{ " IN1_L to Left Mixer Positive Resistor " , " 20 kOhm " , " IN1_L " } ,
{ " IN1_L to Left Mixer Positive Resistor " , " 40 kOhm " , " IN1_L " } ,
{ " Left ADC " , NULL , " IN2_L to Left Mixer Positive Resistor " } ,
{ " IN2_L to Left Mixer Positive Resistor " , " 10 kOhm " , " IN2_L " } ,
{ " IN2_L to Left Mixer Positive Resistor " , " 20 kOhm " , " IN2_L " } ,
{ " IN2_L to Left Mixer Positive Resistor " , " 40 kOhm " , " IN2_L " } ,
{ " Left ADC " , NULL , " IN3_L to Left Mixer Positive Resistor " } ,
{ " IN3_L to Left Mixer Positive Resistor " , " 10 kOhm " , " IN3_L " } ,
{ " IN3_L to Left Mixer Positive Resistor " , " 20 kOhm " , " IN3_L " } ,
{ " IN3_L to Left Mixer Positive Resistor " , " 40 kOhm " , " IN3_L " } ,
{ " Left ADC " , NULL , " IN1_R to Left Mixer Positive Resistor " } ,
{ " IN1_R to Left Mixer Positive Resistor " , " 10 kOhm " , " IN1_R " } ,
{ " IN1_R to Left Mixer Positive Resistor " , " 20 kOhm " , " IN1_R " } ,
{ " IN1_R to Left Mixer Positive Resistor " , " 40 kOhm " , " IN1_R " } ,
{ " Left ADC " , NULL , " CM_L to Left Mixer Negative Resistor " } ,
{ " CM_L to Left Mixer Negative Resistor " , " 10 kOhm " , " CM_L " } ,
{ " CM_L to Left Mixer Negative Resistor " , " 20 kOhm " , " CM_L " } ,
{ " CM_L to Left Mixer Negative Resistor " , " 40 kOhm " , " CM_L " } ,
{ " Left ADC " , NULL , " IN2_R to Left Mixer Negative Resistor " } ,
{ " IN2_R to Left Mixer Negative Resistor " , " 10 kOhm " , " IN2_R " } ,
{ " IN2_R to Left Mixer Negative Resistor " , " 20 kOhm " , " IN2_R " } ,
{ " IN2_R to Left Mixer Negative Resistor " , " 40 kOhm " , " IN2_R " } ,
{ " Left ADC " , NULL , " IN3_R to Left Mixer Negative Resistor " } ,
{ " IN3_R to Left Mixer Negative Resistor " , " 10 kOhm " , " IN3_R " } ,
{ " IN3_R to Left Mixer Negative Resistor " , " 20 kOhm " , " IN3_R " } ,
{ " IN3_R to Left Mixer Negative Resistor " , " 40 kOhm " , " IN3_R " } ,
2011-03-02 14:52:32 +01:00
} ;
2013-09-25 11:37:53 +01:00
static const struct regmap_range_cfg aic32x4_regmap_pages [ ] = {
{
. selector_reg = 0 ,
2019-03-21 17:58:45 -07:00
. selector_mask = 0xff ,
2013-09-25 11:37:53 +01:00
. window_start = 0 ,
. window_len = 128 ,
2014-01-15 18:12:40 +01:00
. range_min = 0 ,
2014-01-11 14:48:30 +01:00
. range_max = AIC32X4_RMICPGAVOL ,
2013-09-25 11:37:53 +01:00
} ,
} ;
2011-03-02 14:52:32 +01:00
2016-04-18 17:24:05 -07:00
const struct regmap_config aic32x4_regmap_config = {
2013-09-25 11:37:53 +01:00
. max_register = AIC32X4_RMICPGAVOL ,
. ranges = aic32x4_regmap_pages ,
. num_ranges = ARRAY_SIZE ( aic32x4_regmap_pages ) ,
} ;
2016-04-18 17:24:05 -07:00
EXPORT_SYMBOL ( aic32x4_regmap_config ) ;
2011-03-02 14:52:32 +01:00
static int aic32x4_set_dai_sysclk ( struct snd_soc_dai * codec_dai ,
int clk_id , unsigned int freq , int dir )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = codec_dai - > component ;
2019-03-21 17:58:52 -07:00
struct clk * mclk ;
struct clk * pll ;
2011-03-02 14:52:32 +01:00
2019-03-21 17:58:52 -07:00
pll = devm_clk_get ( component - > dev , " pll " ) ;
2019-10-18 16:14:49 +08:00
if ( IS_ERR ( pll ) )
return PTR_ERR ( pll ) ;
2019-03-21 17:58:52 -07:00
mclk = clk_get_parent ( pll ) ;
return clk_set_rate ( mclk , freq ) ;
2011-03-02 14:52:32 +01:00
}
static int aic32x4_set_dai_fmt ( struct snd_soc_dai * codec_dai , unsigned int fmt )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = codec_dai - > component ;
2017-12-12 16:43:10 -06:00
u8 iface_reg_1 = 0 ;
u8 iface_reg_2 = 0 ;
u8 iface_reg_3 = 0 ;
2011-03-02 14:52:32 +01:00
/* set master/slave audio interface */
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBM_CFM :
iface_reg_1 | = AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER ;
break ;
case SND_SOC_DAIFMT_CBS_CFS :
break ;
default :
printk ( KERN_ERR " aic32x4: invalid DAI master/slave interface \n " ) ;
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_I2S :
break ;
case SND_SOC_DAIFMT_DSP_A :
2017-12-12 16:43:05 -06:00
iface_reg_1 | = ( AIC32X4_DSP_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2017-12-12 16:43:10 -06:00
iface_reg_3 | = AIC32X4_BCLKINV_MASK ; /* invert bit clock */
2011-03-02 14:52:32 +01:00
iface_reg_2 = 0x01 ; /* add offset 1 */
break ;
case SND_SOC_DAIFMT_DSP_B :
2017-12-12 16:43:05 -06:00
iface_reg_1 | = ( AIC32X4_DSP_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2017-12-12 16:43:10 -06:00
iface_reg_3 | = AIC32X4_BCLKINV_MASK ; /* invert bit clock */
2011-03-02 14:52:32 +01:00
break ;
case SND_SOC_DAIFMT_RIGHT_J :
2017-12-12 16:43:05 -06:00
iface_reg_1 | = ( AIC32X4_RIGHT_JUSTIFIED_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
case SND_SOC_DAIFMT_LEFT_J :
2017-12-12 16:43:05 -06:00
iface_reg_1 | = ( AIC32X4_LEFT_JUSTIFIED_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
default :
printk ( KERN_ERR " aic32x4: invalid DAI interface format \n " ) ;
return - EINVAL ;
}
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE1 ,
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATATYPE_MASK |
AIC32X4_IFACE1_MASTER_MASK , iface_reg_1 ) ;
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE2 ,
2019-03-21 17:58:45 -07:00
AIC32X4_DATA_OFFSET_MASK , iface_reg_2 ) ;
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE3 ,
2019-03-21 17:58:45 -07:00
AIC32X4_BCLKINV_MASK , iface_reg_3 ) ;
2017-12-12 16:43:10 -06:00
2011-03-02 14:52:32 +01:00
return 0 ;
}
2019-03-21 17:58:50 -07:00
static int aic32x4_set_aosr ( struct snd_soc_component * component , u8 aosr )
{
return snd_soc_component_write ( component , AIC32X4_AOSR , aosr ) ;
}
static int aic32x4_set_dosr ( struct snd_soc_component * component , u16 dosr )
{
snd_soc_component_write ( component , AIC32X4_DOSRMSB , dosr > > 8 ) ;
snd_soc_component_write ( component , AIC32X4_DOSRLSB ,
( dosr & 0xff ) ) ;
return 0 ;
}
2019-03-20 19:38:44 -07:00
static int aic32x4_set_processing_blocks ( struct snd_soc_component * component ,
u8 r_block , u8 p_block )
{
if ( r_block > 18 | | p_block > 25 )
return - EINVAL ;
snd_soc_component_write ( component , AIC32X4_ADCSPB , r_block ) ;
snd_soc_component_write ( component , AIC32X4_DACSPB , p_block ) ;
return 0 ;
}
2019-03-18 20:37:44 -07:00
static int aic32x4_setup_clocks ( struct snd_soc_component * component ,
2019-03-21 17:58:51 -07:00
unsigned int sample_rate )
2011-03-02 14:52:32 +01:00
{
2019-03-21 17:58:51 -07:00
u8 aosr ;
u16 dosr ;
u8 adc_resource_class , dac_resource_class ;
u8 madc , nadc , mdac , ndac , max_nadc , min_mdac , max_ndac ;
u8 dosr_increment ;
u16 max_dosr , min_dosr ;
2019-04-17 23:01:57 +08:00
unsigned long adc_clock_rate , dac_clock_rate ;
2019-03-21 17:58:45 -07:00
int ret ;
struct clk_bulk_data clocks [ ] = {
{ . id = " pll " } ,
2019-03-21 17:58:47 -07:00
{ . id = " nadc " } ,
{ . id = " madc " } ,
{ . id = " ndac " } ,
{ . id = " mdac " } ,
2019-03-21 17:58:48 -07:00
{ . id = " bdiv " } ,
2019-03-21 17:58:45 -07:00
} ;
ret = devm_clk_bulk_get ( component - > dev , ARRAY_SIZE ( clocks ) , clocks ) ;
if ( ret )
return ret ;
2019-03-21 17:58:51 -07:00
if ( sample_rate < = 48000 ) {
aosr = 128 ;
adc_resource_class = 6 ;
dac_resource_class = 8 ;
dosr_increment = 8 ;
aic32x4_set_processing_blocks ( component , 1 , 1 ) ;
} else if ( sample_rate < = 96000 ) {
aosr = 64 ;
adc_resource_class = 6 ;
dac_resource_class = 8 ;
dosr_increment = 4 ;
aic32x4_set_processing_blocks ( component , 1 , 9 ) ;
} else if ( sample_rate = = 192000 ) {
aosr = 32 ;
adc_resource_class = 3 ;
dac_resource_class = 4 ;
dosr_increment = 2 ;
aic32x4_set_processing_blocks ( component , 13 , 19 ) ;
} else {
dev_err ( component - > dev , " Sampling rate not supported \n " ) ;
return - EINVAL ;
}
2019-03-20 19:38:44 -07:00
2019-03-21 17:58:51 -07:00
madc = DIV_ROUND_UP ( ( 32 * adc_resource_class ) , aosr ) ;
max_dosr = ( AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment ) *
dosr_increment ;
min_dosr = ( AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment ) *
dosr_increment ;
max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / ( madc * aosr * sample_rate ) ;
for ( nadc = max_nadc ; nadc > 0 ; - - nadc ) {
adc_clock_rate = nadc * madc * aosr * sample_rate ;
for ( dosr = max_dosr ; dosr > = min_dosr ;
dosr - = dosr_increment ) {
min_mdac = DIV_ROUND_UP ( ( 32 * dac_resource_class ) , dosr ) ;
max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
( min_mdac * dosr * sample_rate ) ;
for ( mdac = min_mdac ; mdac < = 128 ; + + mdac ) {
for ( ndac = max_ndac ; ndac > 0 ; - - ndac ) {
dac_clock_rate = ndac * mdac * dosr *
sample_rate ;
if ( dac_clock_rate = = adc_clock_rate ) {
if ( clk_round_rate ( clocks [ 0 ] . clk , dac_clock_rate ) = = 0 )
continue ;
clk_set_rate ( clocks [ 0 ] . clk ,
dac_clock_rate ) ;
clk_set_rate ( clocks [ 1 ] . clk ,
sample_rate * aosr *
madc ) ;
clk_set_rate ( clocks [ 2 ] . clk ,
sample_rate * aosr ) ;
aic32x4_set_aosr ( component ,
aosr ) ;
clk_set_rate ( clocks [ 3 ] . clk ,
sample_rate * dosr *
mdac ) ;
clk_set_rate ( clocks [ 4 ] . clk ,
sample_rate * dosr ) ;
aic32x4_set_dosr ( component ,
dosr ) ;
clk_set_rate ( clocks [ 5 ] . clk ,
sample_rate * 32 ) ;
return 0 ;
}
}
}
}
}
2011-03-02 14:52:32 +01:00
2019-03-21 17:58:51 -07:00
dev_err ( component - > dev ,
" Could not set clocks to support sample rate. \n " ) ;
return - EINVAL ;
2019-03-18 20:37:44 -07:00
}
static int aic32x4_hw_params ( struct snd_pcm_substream * substream ,
2019-03-21 17:58:47 -07:00
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
2019-03-18 20:37:44 -07:00
{
struct snd_soc_component * component = dai - > component ;
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
u8 iface1_reg = 0 ;
u8 dacsetup_reg = 0 ;
2019-03-21 17:58:51 -07:00
aic32x4_setup_clocks ( component , params_rate ( params ) ) ;
2019-03-18 20:37:44 -07:00
2014-07-31 12:48:27 +01:00
switch ( params_width ( params ) ) {
case 16 :
2017-12-12 16:43:09 -06:00
iface1_reg | = ( AIC32X4_WORD_LEN_16BITS < <
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
2014-07-31 12:48:27 +01:00
case 20 :
2017-12-12 16:43:09 -06:00
iface1_reg | = ( AIC32X4_WORD_LEN_20BITS < <
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
2014-07-31 12:48:27 +01:00
case 24 :
2017-12-12 16:43:09 -06:00
iface1_reg | = ( AIC32X4_WORD_LEN_24BITS < <
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
2014-07-31 12:48:27 +01:00
case 32 :
2017-12-12 16:43:09 -06:00
iface1_reg | = ( AIC32X4_WORD_LEN_32BITS < <
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 14:52:32 +01:00
break ;
}
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE1 ,
2019-03-21 17:58:45 -07:00
AIC32X4_IFACE1_DATALEN_MASK , iface1_reg ) ;
2011-03-02 14:52:32 +01:00
2014-01-27 13:03:05 +01:00
if ( params_channels ( params ) = = 1 ) {
2017-12-12 16:43:09 -06:00
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN ;
2014-01-27 13:03:05 +01:00
} else {
if ( aic32x4 - > swapdacs )
2017-12-12 16:43:09 -06:00
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN ;
2014-01-27 13:03:05 +01:00
else
2017-12-12 16:43:09 -06:00
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN ;
2014-01-27 13:03:05 +01:00
}
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_DACSETUP ,
2019-03-21 17:58:45 -07:00
AIC32X4_DAC_CHAN_MASK , dacsetup_reg ) ;
2014-01-27 13:03:05 +01:00
2011-03-02 14:52:32 +01:00
return 0 ;
}
static int aic32x4_mute ( struct snd_soc_dai * dai , int mute )
{
2018-01-29 04:14:49 +00:00
struct snd_soc_component * component = dai - > component ;
2011-03-02 14:52:32 +01:00
2018-01-29 04:14:49 +00:00
snd_soc_component_update_bits ( component , AIC32X4_DACMUTE ,
2019-03-21 17:58:45 -07:00
AIC32X4_MUTEON , mute ? AIC32X4_MUTEON : 0 ) ;
2017-12-12 16:43:08 -06:00
2011-03-02 14:52:32 +01:00
return 0 ;
}
2018-01-29 04:14:49 +00:00
static int aic32x4_set_bias_level ( struct snd_soc_component * component ,
2011-03-02 14:52:32 +01:00
enum snd_soc_bias_level level )
{
2014-02-20 18:22:58 +01:00
int ret ;
2019-03-21 17:58:49 -07:00
struct clk_bulk_data clocks [ ] = {
{ . id = " madc " } ,
{ . id = " mdac " } ,
{ . id = " bdiv " } ,
} ;
ret = devm_clk_bulk_get ( component - > dev , ARRAY_SIZE ( clocks ) , clocks ) ;
if ( ret )
return ret ;
2011-03-02 14:52:32 +01:00
switch ( level ) {
case SND_SOC_BIAS_ON :
2019-03-21 17:58:49 -07:00
ret = clk_bulk_prepare_enable ( ARRAY_SIZE ( clocks ) , clocks ) ;
2014-02-20 18:22:58 +01:00
if ( ret ) {
2019-03-21 17:58:49 -07:00
dev_err ( component - > dev , " Failed to enable clocks \n " ) ;
2014-02-20 18:22:58 +01:00
return ret ;
}
2011-03-02 14:52:32 +01:00
break ;
case SND_SOC_BIAS_PREPARE :
break ;
case SND_SOC_BIAS_STANDBY :
2019-01-07 22:30:22 +05:30
/* Initial cold start */
if ( snd_soc_component_get_bias_level ( component ) = = SND_SOC_BIAS_OFF )
break ;
2019-03-21 17:58:49 -07:00
clk_bulk_disable_unprepare ( ARRAY_SIZE ( clocks ) , clocks ) ;
2011-03-02 14:52:32 +01:00
break ;
case SND_SOC_BIAS_OFF :
break ;
}
return 0 ;
}
2019-03-21 17:58:54 -07:00
# define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000
2019-03-21 17:58:45 -07:00
# define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
2011-03-02 14:52:32 +01:00
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE )
2011-11-23 11:40:40 +01:00
static const struct snd_soc_dai_ops aic32x4_ops = {
2011-03-02 14:52:32 +01:00
. hw_params = aic32x4_hw_params ,
. digital_mute = aic32x4_mute ,
. set_fmt = aic32x4_set_dai_fmt ,
. set_sysclk = aic32x4_set_dai_sysclk ,
} ;
static struct snd_soc_dai_driver aic32x4_dai = {
. name = " tlv320aic32x4-hifi " ,
. playback = {
2019-03-21 17:58:45 -07:00
. stream_name = " Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = AIC32X4_RATES ,
. formats = AIC32X4_FORMATS , } ,
2011-03-02 14:52:32 +01:00
. capture = {
2019-03-21 17:58:45 -07:00
. stream_name = " Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = AIC32X4_RATES ,
. formats = AIC32X4_FORMATS , } ,
2011-03-02 14:52:32 +01:00
. ops = & aic32x4_ops ,
. symmetric_rates = 1 ,
} ;
2018-01-29 04:14:49 +00:00
static void aic32x4_setup_gpios ( struct snd_soc_component * component )
2017-07-12 13:37:00 -05:00
{
2018-01-29 04:14:49 +00:00
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2017-07-12 13:37:00 -05:00
/* setup GPIO functions */
/* MFP1 */
if ( aic32x4 - > setup - > gpio_func [ 0 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_DINCTL ,
2019-03-21 17:58:45 -07:00
aic32x4 - > setup - > gpio_func [ 0 ] ) ;
2018-01-29 04:14:49 +00:00
snd_soc_add_component_controls ( component , aic32x4_mfp1 ,
2017-07-12 13:37:00 -05:00
ARRAY_SIZE ( aic32x4_mfp1 ) ) ;
}
/* MFP2 */
if ( aic32x4 - > setup - > gpio_func [ 1 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_DOUTCTL ,
2019-03-21 17:58:45 -07:00
aic32x4 - > setup - > gpio_func [ 1 ] ) ;
2018-01-29 04:14:49 +00:00
snd_soc_add_component_controls ( component , aic32x4_mfp2 ,
2017-07-12 13:37:00 -05:00
ARRAY_SIZE ( aic32x4_mfp2 ) ) ;
}
/* MFP3 */
if ( aic32x4 - > setup - > gpio_func [ 2 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_SCLKCTL ,
2019-03-21 17:58:45 -07:00
aic32x4 - > setup - > gpio_func [ 2 ] ) ;
2018-01-29 04:14:49 +00:00
snd_soc_add_component_controls ( component , aic32x4_mfp3 ,
2017-07-12 13:37:00 -05:00
ARRAY_SIZE ( aic32x4_mfp3 ) ) ;
}
/* MFP4 */
if ( aic32x4 - > setup - > gpio_func [ 3 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_MISOCTL ,
2019-03-21 17:58:45 -07:00
aic32x4 - > setup - > gpio_func [ 3 ] ) ;
2018-01-29 04:14:49 +00:00
snd_soc_add_component_controls ( component , aic32x4_mfp4 ,
2017-07-12 13:37:00 -05:00
ARRAY_SIZE ( aic32x4_mfp4 ) ) ;
}
/* MFP5 */
if ( aic32x4 - > setup - > gpio_func [ 4 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_GPIOCTL ,
2019-03-21 17:58:45 -07:00
aic32x4 - > setup - > gpio_func [ 4 ] ) ;
2018-01-29 04:14:49 +00:00
snd_soc_add_component_controls ( component , aic32x4_mfp5 ,
2017-07-12 13:37:00 -05:00
ARRAY_SIZE ( aic32x4_mfp5 ) ) ;
}
}
2018-01-29 04:14:49 +00:00
static int aic32x4_component_probe ( struct snd_soc_component * component )
2011-03-02 14:52:32 +01:00
{
2018-01-29 04:14:49 +00:00
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2011-03-02 14:52:32 +01:00
u32 tmp_reg ;
2019-03-21 17:58:46 -07:00
int ret ;
struct clk_bulk_data clocks [ ] = {
2019-03-21 17:58:47 -07:00
{ . id = " codec_clkin " } ,
{ . id = " pll " } ,
2019-03-21 17:58:48 -07:00
{ . id = " bdiv " } ,
{ . id = " mdac " } ,
2019-03-21 17:58:46 -07:00
} ;
ret = devm_clk_bulk_get ( component - > dev , ARRAY_SIZE ( clocks ) , clocks ) ;
if ( ret )
return ret ;
2011-03-02 14:52:32 +01:00
2014-01-16 16:30:25 +01:00
if ( gpio_is_valid ( aic32x4 - > rstn_gpio ) ) {
2012-10-31 11:53:34 +01:00
ndelay ( 10 ) ;
gpio_set_value ( aic32x4 - > rstn_gpio , 1 ) ;
2019-02-11 22:06:30 +01:00
mdelay ( 1 ) ;
2012-10-31 11:53:34 +01:00
}
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_RESET , 0x01 ) ;
2011-03-02 14:52:32 +01:00
2017-07-12 13:37:00 -05:00
if ( aic32x4 - > setup )
2018-01-29 04:14:49 +00:00
aic32x4_setup_gpios ( component ) ;
2017-07-12 13:37:00 -05:00
2019-03-21 17:58:46 -07:00
clk_set_parent ( clocks [ 0 ] . clk , clocks [ 1 ] . clk ) ;
2019-03-21 17:58:48 -07:00
clk_set_parent ( clocks [ 2 ] . clk , clocks [ 3 ] . clk ) ;
2019-03-21 17:58:46 -07:00
2011-03-02 14:52:32 +01:00
/* Power platform configuration */
if ( aic32x4 - > power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN ) {
2019-03-21 17:58:45 -07:00
snd_soc_component_write ( component , AIC32X4_MICBIAS ,
AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V ) ;
2011-03-02 14:52:32 +01:00
}
2014-06-13 11:18:47 +05:30
if ( aic32x4 - > power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE )
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_PWRCFG , AIC32X4_AVDDWEAKDISABLE ) ;
2012-01-18 11:48:59 +01:00
tmp_reg = ( aic32x4 - > power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE ) ?
AIC32X4_LDOCTLEN : 0 ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_LDOCTL , tmp_reg ) ;
2012-01-18 11:48:59 +01:00
2018-01-29 04:14:49 +00:00
tmp_reg = snd_soc_component_read32 ( component , AIC32X4_CMMODE ) ;
2014-06-13 11:18:47 +05:30
if ( aic32x4 - > power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 )
2011-03-02 14:52:32 +01:00
tmp_reg | = AIC32X4_LDOIN_18_36 ;
2014-06-13 11:18:47 +05:30
if ( aic32x4 - > power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED )
2011-03-02 14:52:32 +01:00
tmp_reg | = AIC32X4_LDOIN2HP ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_CMMODE , tmp_reg ) ;
2011-03-02 14:52:32 +01:00
/* Mic PGA routing */
2014-01-27 13:03:06 +01:00
if ( aic32x4 - > micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K )
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_LMICPGANIN ,
2014-06-13 11:18:48 +05:30
AIC32X4_LMICPGANIN_IN2R_10K ) ;
2014-01-27 13:03:06 +01:00
else
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_LMICPGANIN ,
2014-06-13 11:18:48 +05:30
AIC32X4_LMICPGANIN_CM1L_10K ) ;
2014-01-27 13:03:06 +01:00
if ( aic32x4 - > micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K )
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_RMICPGANIN ,
2014-06-13 11:18:48 +05:30
AIC32X4_RMICPGANIN_IN1L_10K ) ;
2014-01-27 13:03:06 +01:00
else
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_RMICPGANIN ,
2014-06-13 11:18:48 +05:30
AIC32X4_RMICPGANIN_CM1R_10K ) ;
2011-03-02 14:52:32 +01:00
2012-10-31 11:53:33 +01:00
/*
* Workaround : for an unknown reason , the ADC needs to be powered up
* and down for the first capture to work properly . It seems related to
* a HW BUG or some kind of behavior not documented in the datasheet .
*/
2018-01-29 04:14:49 +00:00
tmp_reg = snd_soc_component_read32 ( component , AIC32X4_ADCSETUP ) ;
snd_soc_component_write ( component , AIC32X4_ADCSETUP , tmp_reg |
2012-10-31 11:53:33 +01:00
AIC32X4_LADC_EN | AIC32X4_RADC_EN ) ;
2018-01-29 04:14:49 +00:00
snd_soc_component_write ( component , AIC32X4_ADCSETUP , tmp_reg ) ;
2012-10-31 11:53:33 +01:00
2011-03-02 14:52:32 +01:00
return 0 ;
}
2018-01-29 04:14:49 +00:00
static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
. probe = aic32x4_component_probe ,
. set_bias_level = aic32x4_set_bias_level ,
. controls = aic32x4_snd_controls ,
. num_controls = ARRAY_SIZE ( aic32x4_snd_controls ) ,
. dapm_widgets = aic32x4_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( aic32x4_dapm_widgets ) ,
. dapm_routes = aic32x4_dapm_routes ,
. num_dapm_routes = ARRAY_SIZE ( aic32x4_dapm_routes ) ,
. suspend_bias_off = 1 ,
. idle_bias_on = 1 ,
. use_pmdown_time = 1 ,
. endianness = 1 ,
. non_legacy_dai_naming = 1 ,
2011-03-02 14:52:32 +01:00
} ;
2014-01-27 13:03:08 +01:00
static int aic32x4_parse_dt ( struct aic32x4_priv * aic32x4 ,
struct device_node * np )
{
2017-07-12 13:37:00 -05:00
struct aic32x4_setup_data * aic32x4_setup ;
2019-03-21 17:58:45 -07:00
int ret ;
2017-07-12 13:37:00 -05:00
aic32x4_setup = devm_kzalloc ( aic32x4 - > dev , sizeof ( * aic32x4_setup ) ,
GFP_KERNEL ) ;
if ( ! aic32x4_setup )
return - ENOMEM ;
2019-03-21 17:58:45 -07:00
ret = of_property_match_string ( np , " clock-names " , " mclk " ) ;
if ( ret < 0 )
return - EINVAL ;
aic32x4 - > mclk_name = of_clk_get_parent_name ( np , ret ) ;
2014-01-27 13:03:08 +01:00
aic32x4 - > swapdacs = false ;
aic32x4 - > micpga_routing = 0 ;
aic32x4 - > rstn_gpio = of_get_named_gpio ( np , " reset-gpios " , 0 ) ;
2017-07-12 13:37:00 -05:00
if ( of_property_read_u32_array ( np , " aic32x4-gpio-func " ,
aic32x4_setup - > gpio_func , 5 ) > = 0 )
aic32x4 - > setup = aic32x4_setup ;
2014-01-27 13:03:08 +01:00
return 0 ;
}
2014-02-20 18:22:59 +01:00
static void aic32x4_disable_regulators ( struct aic32x4_priv * aic32x4 )
{
regulator_disable ( aic32x4 - > supply_iov ) ;
if ( ! IS_ERR ( aic32x4 - > supply_ldo ) )
regulator_disable ( aic32x4 - > supply_ldo ) ;
if ( ! IS_ERR ( aic32x4 - > supply_dv ) )
regulator_disable ( aic32x4 - > supply_dv ) ;
if ( ! IS_ERR ( aic32x4 - > supply_av ) )
regulator_disable ( aic32x4 - > supply_av ) ;
}
static int aic32x4_setup_regulators ( struct device * dev ,
struct aic32x4_priv * aic32x4 )
{
int ret = 0 ;
aic32x4 - > supply_ldo = devm_regulator_get_optional ( dev , " ldoin " ) ;
aic32x4 - > supply_iov = devm_regulator_get ( dev , " iov " ) ;
aic32x4 - > supply_dv = devm_regulator_get_optional ( dev , " dv " ) ;
aic32x4 - > supply_av = devm_regulator_get_optional ( dev , " av " ) ;
/* Check if the regulator requirements are fulfilled */
if ( IS_ERR ( aic32x4 - > supply_iov ) ) {
dev_err ( dev , " Missing supply 'iov' \n " ) ;
return PTR_ERR ( aic32x4 - > supply_iov ) ;
}
if ( IS_ERR ( aic32x4 - > supply_ldo ) ) {
if ( PTR_ERR ( aic32x4 - > supply_ldo ) = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
if ( IS_ERR ( aic32x4 - > supply_dv ) ) {
dev_err ( dev , " Missing supply 'dv' or 'ldoin' \n " ) ;
return PTR_ERR ( aic32x4 - > supply_dv ) ;
}
if ( IS_ERR ( aic32x4 - > supply_av ) ) {
dev_err ( dev , " Missing supply 'av' or 'ldoin' \n " ) ;
return PTR_ERR ( aic32x4 - > supply_av ) ;
}
} else {
if ( IS_ERR ( aic32x4 - > supply_dv ) & &
PTR_ERR ( aic32x4 - > supply_dv ) = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
if ( IS_ERR ( aic32x4 - > supply_av ) & &
PTR_ERR ( aic32x4 - > supply_av ) = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
}
ret = regulator_enable ( aic32x4 - > supply_iov ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulator iov \n " ) ;
return ret ;
}
if ( ! IS_ERR ( aic32x4 - > supply_ldo ) ) {
ret = regulator_enable ( aic32x4 - > supply_ldo ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulator ldo \n " ) ;
goto error_ldo ;
}
}
if ( ! IS_ERR ( aic32x4 - > supply_dv ) ) {
ret = regulator_enable ( aic32x4 - > supply_dv ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulator dv \n " ) ;
goto error_dv ;
}
}
if ( ! IS_ERR ( aic32x4 - > supply_av ) ) {
ret = regulator_enable ( aic32x4 - > supply_av ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulator av \n " ) ;
goto error_av ;
}
}
if ( ! IS_ERR ( aic32x4 - > supply_ldo ) & & IS_ERR ( aic32x4 - > supply_av ) )
aic32x4 - > power_cfg | = AIC32X4_PWR_AIC32X4_LDO_ENABLE ;
return 0 ;
error_av :
if ( ! IS_ERR ( aic32x4 - > supply_dv ) )
regulator_disable ( aic32x4 - > supply_dv ) ;
error_dv :
if ( ! IS_ERR ( aic32x4 - > supply_ldo ) )
regulator_disable ( aic32x4 - > supply_ldo ) ;
error_ldo :
regulator_disable ( aic32x4 - > supply_iov ) ;
return ret ;
}
2016-04-18 17:24:05 -07:00
int aic32x4_probe ( struct device * dev , struct regmap * regmap )
2011-03-02 14:52:32 +01:00
{
struct aic32x4_priv * aic32x4 ;
2016-04-18 17:24:05 -07:00
struct aic32x4_pdata * pdata = dev - > platform_data ;
struct device_node * np = dev - > of_node ;
2011-03-02 14:52:32 +01:00
int ret ;
2016-04-18 17:24:05 -07:00
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
aic32x4 = devm_kzalloc ( dev , sizeof ( struct aic32x4_priv ) ,
2019-03-21 17:58:45 -07:00
GFP_KERNEL ) ;
2011-03-02 14:52:32 +01:00
if ( aic32x4 = = NULL )
return - ENOMEM ;
2017-07-12 13:37:00 -05:00
aic32x4 - > dev = dev ;
2016-04-18 17:24:05 -07:00
dev_set_drvdata ( dev , aic32x4 ) ;
2011-03-02 14:52:32 +01:00
if ( pdata ) {
aic32x4 - > power_cfg = pdata - > power_cfg ;
aic32x4 - > swapdacs = pdata - > swapdacs ;
aic32x4 - > micpga_routing = pdata - > micpga_routing ;
2012-10-31 11:53:34 +01:00
aic32x4 - > rstn_gpio = pdata - > rstn_gpio ;
2019-03-21 17:58:45 -07:00
aic32x4 - > mclk_name = " mclk " ;
2014-01-27 13:03:08 +01:00
} else if ( np ) {
ret = aic32x4_parse_dt ( aic32x4 , np ) ;
if ( ret ) {
2016-04-18 17:24:05 -07:00
dev_err ( dev , " Failed to parse DT node \n " ) ;
2014-01-27 13:03:08 +01:00
return ret ;
}
2011-03-02 14:52:32 +01:00
} else {
aic32x4 - > power_cfg = 0 ;
aic32x4 - > swapdacs = false ;
aic32x4 - > micpga_routing = 0 ;
2012-10-31 11:53:34 +01:00
aic32x4 - > rstn_gpio = - 1 ;
2019-03-21 17:58:45 -07:00
aic32x4 - > mclk_name = " mclk " ;
2011-03-02 14:52:32 +01:00
}
2019-03-21 17:58:45 -07:00
ret = aic32x4_register_clocks ( dev , aic32x4 - > mclk_name ) ;
if ( ret )
return ret ;
2014-01-16 16:30:25 +01:00
if ( gpio_is_valid ( aic32x4 - > rstn_gpio ) ) {
2016-04-18 17:24:05 -07:00
ret = devm_gpio_request_one ( dev , aic32x4 - > rstn_gpio ,
2013-09-25 11:36:26 +01:00
GPIOF_OUT_INIT_LOW , " tlv320aic32x4 rstn " ) ;
if ( ret ! = 0 )
return ret ;
}
2016-04-18 17:24:05 -07:00
ret = aic32x4_setup_regulators ( dev , aic32x4 ) ;
2014-02-20 18:22:59 +01:00
if ( ret ) {
2016-04-18 17:24:05 -07:00
dev_err ( dev , " Failed to setup regulators \n " ) ;
2014-02-20 18:22:59 +01:00
return ret ;
}
2018-01-29 04:14:49 +00:00
ret = devm_snd_soc_register_component ( dev ,
& soc_component_dev_aic32x4 , & aic32x4_dai , 1 ) ;
2014-02-20 18:22:59 +01:00
if ( ret ) {
2018-01-29 04:14:49 +00:00
dev_err ( dev , " Failed to register component \n " ) ;
2014-02-20 18:22:59 +01:00
aic32x4_disable_regulators ( aic32x4 ) ;
return ret ;
}
return 0 ;
2011-03-02 14:52:32 +01:00
}
2016-04-18 17:24:05 -07:00
EXPORT_SYMBOL ( aic32x4_probe ) ;
2011-03-02 14:52:32 +01:00
2016-04-18 17:24:05 -07:00
int aic32x4_remove ( struct device * dev )
2011-03-02 14:52:32 +01:00
{
2016-04-18 17:24:05 -07:00
struct aic32x4_priv * aic32x4 = dev_get_drvdata ( dev ) ;
2014-02-20 18:22:59 +01:00
aic32x4_disable_regulators ( aic32x4 ) ;
2011-03-02 14:52:32 +01:00
return 0 ;
}
2016-04-18 17:24:05 -07:00
EXPORT_SYMBOL ( aic32x4_remove ) ;
2011-03-02 14:52:32 +01:00
MODULE_DESCRIPTION ( " ASoC tlv320aic32x4 codec driver " ) ;
MODULE_AUTHOR ( " Javier Martin <javier.martin@vista-silicon.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;