2011-03-02 16:52:32 +03: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 .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
2012-10-31 14:53:34 +04:00
# include <linux/gpio.h>
2014-01-27 16:03:08 +04:00
# include <linux/of_gpio.h>
2011-03-02 16:52:32 +03:00
# include <linux/cdev.h>
# include <linux/slab.h>
2014-02-20 21:22:58 +04:00
# include <linux/clk.h>
2014-02-20 21:22:59 +04:00
# include <linux/regulator/consumer.h>
2011-03-02 16:52:32 +03: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_rate_divs {
u32 mclk ;
u32 rate ;
u8 p_val ;
u8 pll_j ;
u16 pll_d ;
u16 dosr ;
u8 ndac ;
u8 mdac ;
u8 aosr ;
u8 nadc ;
u8 madc ;
u8 blck_N ;
} ;
struct aic32x4_priv {
2013-09-25 14:37:53 +04:00
struct regmap * regmap ;
2011-03-02 16:52:32 +03:00
u32 sysclk ;
u32 power_cfg ;
u32 micpga_routing ;
bool swapdacs ;
2012-10-31 14:53:34 +04:00
int rstn_gpio ;
2014-02-20 21:22:58 +04:00
struct clk * mclk ;
2014-02-20 21:22:59 +04:00
struct regulator * supply_ldo ;
struct regulator * supply_iov ;
struct regulator * supply_dv ;
struct regulator * supply_av ;
2017-07-12 21:37:00 +03:00
struct aic32x4_setup_data * setup ;
struct device * dev ;
} ;
2019-01-09 20:11:21 +03:00
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 21:37:00 +03:00
static int aic32x4_get_mfp1_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_DINCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
u8 gpio_check ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_DOUTCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_DOUTCTL , val ) ;
2017-07-12 21:37:00 +03:00
return 0 ;
} ;
static int aic32x4_get_mfp3_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_SCLKCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
u8 gpio_check ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_MISOCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_MISOCTL , val ) ;
2017-07-12 21:37:00 +03:00
return 0 ;
} ;
static int aic32x4_get_mfp5_gpio ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_GPIOCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
struct snd_soc_component * component = snd_kcontrol_chip ( kcontrol ) ;
2017-07-12 21:37:00 +03:00
u8 val ;
u8 gpio_check ;
2018-01-29 07:14:49 +03:00
val = snd_soc_component_read32 ( component , AIC32X4_GPIOCTL ) ;
2017-07-12 21:37:00 +03: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 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_GPIOCTL , val ) ;
2017-07-12 21:37:00 +03: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 16:52:32 +03:00
} ;
/* 0dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE ( tlv_step_0_5 , 0 , 50 , 0 ) ;
2014-01-27 16:03:07 +04: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 16:52:32 +03:00
static const struct snd_kcontrol_new aic32x4_snd_controls [ ] = {
2014-01-27 16:03:07 +04:00
SOC_DOUBLE_R_S_TLV ( " PCM Playback Volume " , AIC32X4_LDACVOL ,
AIC32X4_RDACVOL , 0 , - 0x7f , 0x30 , 7 , 0 , tlv_pcm ) ,
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 16:52:32 +03: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 ) ,
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 16:03:07 +04:00
SOC_DOUBLE_R_S_TLV ( " ADC Level Volume " , AIC32X4_LADCVOL ,
AIC32X4_RADCVOL , 0 , - 0x18 , 0x28 , 6 , 0 , tlv_adc_vol ) ,
2011-03-02 16:52:32 +03: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 aic32x4_rate_divs aic32x4_divs [ ] = {
/* 8k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 8000 , 1 , 7 , 6800 , 768 , 5 , 3 , 128 , 5 , 18 , 24 } ,
{ 24000000 , 8000 , 2 , 7 , 6800 , 768 , 15 , 1 , 64 , 45 , 4 , 24 } ,
{ 25000000 , 8000 , 2 , 7 , 3728 , 768 , 15 , 1 , 64 , 45 , 4 , 24 } ,
2011-03-02 16:52:32 +03:00
/* 11.025k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 11025 , 1 , 7 , 5264 , 512 , 8 , 2 , 128 , 8 , 8 , 16 } ,
{ 24000000 , 11025 , 2 , 7 , 5264 , 512 , 16 , 1 , 64 , 32 , 4 , 16 } ,
2011-03-02 16:52:32 +03:00
/* 16k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 16000 , 1 , 7 , 6800 , 384 , 5 , 3 , 128 , 5 , 9 , 12 } ,
{ 24000000 , 16000 , 2 , 7 , 6800 , 384 , 15 , 1 , 64 , 18 , 5 , 12 } ,
{ 25000000 , 16000 , 2 , 7 , 3728 , 384 , 15 , 1 , 64 , 18 , 5 , 12 } ,
2011-03-02 16:52:32 +03:00
/* 22.05k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 22050 , 1 , 7 , 5264 , 256 , 4 , 4 , 128 , 4 , 8 , 8 } ,
{ 24000000 , 22050 , 2 , 7 , 5264 , 256 , 16 , 1 , 64 , 16 , 4 , 8 } ,
{ 25000000 , 22050 , 2 , 7 , 2253 , 256 , 16 , 1 , 64 , 16 , 4 , 8 } ,
2011-03-02 16:52:32 +03:00
/* 32k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 32000 , 1 , 7 , 1680 , 192 , 2 , 7 , 64 , 2 , 21 , 6 } ,
{ 24000000 , 32000 , 2 , 7 , 1680 , 192 , 7 , 2 , 64 , 7 , 6 , 6 } ,
2011-03-02 16:52:32 +03:00
/* 44.1k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 44100 , 1 , 7 , 5264 , 128 , 2 , 8 , 128 , 2 , 8 , 4 } ,
{ 24000000 , 44100 , 2 , 7 , 5264 , 128 , 8 , 2 , 64 , 8 , 4 , 4 } ,
{ 25000000 , 44100 , 2 , 7 , 2253 , 128 , 8 , 2 , 64 , 8 , 4 , 4 } ,
2011-03-02 16:52:32 +03:00
/* 48k rate */
2017-12-13 01:43:04 +03:00
{ 12000000 , 48000 , 1 , 8 , 1920 , 128 , 2 , 8 , 128 , 2 , 8 , 4 } ,
{ 24000000 , 48000 , 2 , 8 , 1920 , 128 , 8 , 2 , 64 , 8 , 4 , 4 } ,
{ 25000000 , 48000 , 2 , 7 , 8643 , 128 , 8 , 2 , 64 , 8 , 4 , 4 } ,
2016-04-19 19:59:04 +03:00
/* 96k rate */
2017-12-13 01:43:04 +03:00
{ 25000000 , 96000 , 2 , 7 , 8643 , 64 , 4 , 4 , 64 , 4 , 4 , 1 } ,
2011-03-02 16:52:32 +03:00
} ;
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 21:39:11 +03:00
static const char * const resistor_text [ ] = {
" Off " , " 10 kOhm " , " 20 kOhm " , " 40 kOhm " ,
} ;
2016-05-11 22:09:53 +03: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 16:52:32 +03:00
} ;
2016-05-11 22:09:53 +03:00
/* Right mixer pins */
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 16:52:32 +03: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 22:09:53 +03:00
2011-03-02 16:52:32 +03:00
SND_SOC_DAPM_ADC ( " Right ADC " , " Right Capture " , AIC32X4_ADCSETUP , 6 , 0 ) ,
2016-05-11 22:09:53 +03: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 20:11:21 +03:00
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 16:52:32 +03: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 19:02:02 +03:00
SND_SOC_DAPM_INPUT ( " CM_L " ) ,
SND_SOC_DAPM_INPUT ( " CM_R " ) ,
2011-03-02 16:52:32 +03: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 22:09:53 +03: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 16:52:32 +03:00
} ;
2013-09-25 14:37:53 +04:00
static const struct regmap_range_cfg aic32x4_regmap_pages [ ] = {
{
. selector_reg = 0 ,
. selector_mask = 0xff ,
. window_start = 0 ,
. window_len = 128 ,
2014-01-15 21:12:40 +04:00
. range_min = 0 ,
2014-01-11 17:48:30 +04:00
. range_max = AIC32X4_RMICPGAVOL ,
2013-09-25 14:37:53 +04:00
} ,
} ;
2011-03-02 16:52:32 +03:00
2016-04-19 03:24:05 +03:00
const struct regmap_config aic32x4_regmap_config = {
2013-09-25 14:37:53 +04:00
. max_register = AIC32X4_RMICPGAVOL ,
. ranges = aic32x4_regmap_pages ,
. num_ranges = ARRAY_SIZE ( aic32x4_regmap_pages ) ,
} ;
2016-04-19 03:24:05 +03:00
EXPORT_SYMBOL ( aic32x4_regmap_config ) ;
2011-03-02 16:52:32 +03:00
static inline int aic32x4_get_divs ( int mclk , int rate )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( aic32x4_divs ) ; i + + ) {
if ( ( aic32x4_divs [ i ] . rate = = rate )
& & ( aic32x4_divs [ i ] . mclk = = mclk ) ) {
return i ;
}
}
printk ( KERN_ERR " aic32x4: master clock and sample rate is not supported \n " ) ;
return - EINVAL ;
}
static int aic32x4_set_dai_sysclk ( struct snd_soc_dai * codec_dai ,
int clk_id , unsigned int freq , int dir )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = codec_dai - > component ;
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2011-03-02 16:52:32 +03:00
switch ( freq ) {
2017-12-13 01:43:04 +03:00
case 12000000 :
case 24000000 :
case 25000000 :
2011-03-02 16:52:32 +03:00
aic32x4 - > sysclk = freq ;
return 0 ;
}
printk ( KERN_ERR " aic32x4: invalid frequency to set DAI system clock \n " ) ;
return - EINVAL ;
}
static int aic32x4_set_dai_fmt ( struct snd_soc_dai * codec_dai , unsigned int fmt )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = codec_dai - > component ;
2017-12-13 01:43:10 +03:00
u8 iface_reg_1 = 0 ;
u8 iface_reg_2 = 0 ;
u8 iface_reg_3 = 0 ;
2011-03-02 16:52:32 +03: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-13 01:43:05 +03:00
iface_reg_1 | = ( AIC32X4_DSP_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2017-12-13 01:43:10 +03:00
iface_reg_3 | = AIC32X4_BCLKINV_MASK ; /* invert bit clock */
2011-03-02 16:52:32 +03:00
iface_reg_2 = 0x01 ; /* add offset 1 */
break ;
case SND_SOC_DAIFMT_DSP_B :
2017-12-13 01:43:05 +03:00
iface_reg_1 | = ( AIC32X4_DSP_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2017-12-13 01:43:10 +03:00
iface_reg_3 | = AIC32X4_BCLKINV_MASK ; /* invert bit clock */
2011-03-02 16:52:32 +03:00
break ;
case SND_SOC_DAIFMT_RIGHT_J :
2017-12-13 01:43:05 +03:00
iface_reg_1 | = ( AIC32X4_RIGHT_JUSTIFIED_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
case SND_SOC_DAIFMT_LEFT_J :
2017-12-13 01:43:05 +03:00
iface_reg_1 | = ( AIC32X4_LEFT_JUSTIFIED_MODE < <
AIC32X4_IFACE1_DATATYPE_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
default :
printk ( KERN_ERR " aic32x4: invalid DAI interface format \n " ) ;
return - EINVAL ;
}
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE1 ,
2017-12-13 01:43:10 +03:00
AIC32X4_IFACE1_DATATYPE_MASK |
AIC32X4_IFACE1_MASTER_MASK , iface_reg_1 ) ;
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE2 ,
2017-12-13 01:43:10 +03:00
AIC32X4_DATA_OFFSET_MASK , iface_reg_2 ) ;
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE3 ,
2017-12-13 01:43:10 +03:00
AIC32X4_BCLKINV_MASK , iface_reg_3 ) ;
2011-03-02 16:52:32 +03:00
return 0 ;
}
static int aic32x4_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = dai - > component ;
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2017-12-13 01:43:09 +03:00
u8 iface1_reg = 0 ;
u8 dacsetup_reg = 0 ;
2011-03-02 16:52:32 +03:00
int i ;
i = aic32x4_get_divs ( aic32x4 - > sysclk , params_rate ( params ) ) ;
if ( i < 0 ) {
printk ( KERN_ERR " aic32x4: sampling rate not supported \n " ) ;
return i ;
}
2017-12-13 01:43:09 +03:00
/* MCLK as PLL_CLKIN */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_CLKMUX , AIC32X4_PLL_CLKIN_MASK ,
2017-12-13 01:43:09 +03:00
AIC32X4_PLL_CLKIN_MCLK < < AIC32X4_PLL_CLKIN_SHIFT ) ;
/* PLL as CODEC_CLKIN */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_CLKMUX , AIC32X4_CODEC_CLKIN_MASK ,
2017-12-13 01:43:09 +03:00
AIC32X4_CODEC_CLKIN_PLL < < AIC32X4_CODEC_CLKIN_SHIFT ) ;
/* DAC_MOD_CLK as BDIV_CLKIN */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE3 , AIC32X4_BDIVCLK_MASK ,
2017-12-13 01:43:09 +03:00
AIC32X4_DACMOD2BCLK < < AIC32X4_BDIVCLK_SHIFT ) ;
2011-03-02 16:52:32 +03:00
2017-12-13 01:43:09 +03:00
/* We will fix R value to 1 and will make P & J=K.D as variable */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_PLLPR , AIC32X4_PLL_R_MASK , 0x01 ) ;
2011-03-02 16:52:32 +03:00
2017-12-13 01:43:09 +03:00
/* PLL P value */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_PLLPR , AIC32X4_PLL_P_MASK ,
2017-12-13 01:43:09 +03:00
aic32x4_divs [ i ] . p_val < < AIC32X4_PLL_P_SHIFT ) ;
/* PLL J value */
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_PLLJ , aic32x4_divs [ i ] . pll_j ) ;
2011-03-02 16:52:32 +03:00
2017-12-13 01:43:09 +03:00
/* PLL D value */
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_PLLDMSB , ( aic32x4_divs [ i ] . pll_d > > 8 ) ) ;
snd_soc_component_write ( component , AIC32X4_PLLDLSB , ( aic32x4_divs [ i ] . pll_d & 0xff ) ) ;
2011-03-02 16:52:32 +03:00
/* NDAC divider value */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NDAC ,
2017-12-13 01:43:09 +03:00
AIC32X4_NDAC_MASK , aic32x4_divs [ i ] . ndac ) ;
2011-03-02 16:52:32 +03:00
/* MDAC divider value */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MDAC ,
2017-12-13 01:43:09 +03:00
AIC32X4_MDAC_MASK , aic32x4_divs [ i ] . mdac ) ;
2011-03-02 16:52:32 +03:00
/* DOSR MSB & LSB values */
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_DOSRMSB , aic32x4_divs [ i ] . dosr > > 8 ) ;
snd_soc_component_write ( component , AIC32X4_DOSRLSB , ( aic32x4_divs [ i ] . dosr & 0xff ) ) ;
2011-03-02 16:52:32 +03:00
/* NADC divider value */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NADC ,
2017-12-13 01:43:09 +03:00
AIC32X4_NADC_MASK , aic32x4_divs [ i ] . nadc ) ;
2011-03-02 16:52:32 +03:00
/* MADC divider value */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MADC ,
2017-12-13 01:43:09 +03:00
AIC32X4_MADC_MASK , aic32x4_divs [ i ] . madc ) ;
2011-03-02 16:52:32 +03:00
/* AOSR value */
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_AOSR , aic32x4_divs [ i ] . aosr ) ;
2011-03-02 16:52:32 +03:00
/* BCLK N divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_BCLKN ,
2017-12-13 01:43:09 +03:00
AIC32X4_BCLK_MASK , aic32x4_divs [ i ] . blck_N ) ;
2011-03-02 16:52:32 +03:00
2014-07-31 15:48:27 +04:00
switch ( params_width ( params ) ) {
case 16 :
2017-12-13 01:43:09 +03:00
iface1_reg | = ( AIC32X4_WORD_LEN_16BITS < <
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
2014-07-31 15:48:27 +04:00
case 20 :
2017-12-13 01:43:09 +03:00
iface1_reg | = ( AIC32X4_WORD_LEN_20BITS < <
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
2014-07-31 15:48:27 +04:00
case 24 :
2017-12-13 01:43:09 +03:00
iface1_reg | = ( AIC32X4_WORD_LEN_24BITS < <
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
2014-07-31 15:48:27 +04:00
case 32 :
2017-12-13 01:43:09 +03:00
iface1_reg | = ( AIC32X4_WORD_LEN_32BITS < <
AIC32X4_IFACE1_DATALEN_SHIFT ) ;
2011-03-02 16:52:32 +03:00
break ;
}
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_IFACE1 ,
2017-12-13 01:43:09 +03:00
AIC32X4_IFACE1_DATALEN_MASK , iface1_reg ) ;
2011-03-02 16:52:32 +03:00
2014-01-27 16:03:05 +04:00
if ( params_channels ( params ) = = 1 ) {
2017-12-13 01:43:09 +03:00
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN ;
2014-01-27 16:03:05 +04:00
} else {
if ( aic32x4 - > swapdacs )
2017-12-13 01:43:09 +03:00
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN ;
2014-01-27 16:03:05 +04:00
else
2017-12-13 01:43:09 +03:00
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN ;
2014-01-27 16:03:05 +04:00
}
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_DACSETUP ,
2017-12-13 01:43:09 +03:00
AIC32X4_DAC_CHAN_MASK , dacsetup_reg ) ;
2014-01-27 16:03:05 +04:00
2011-03-02 16:52:32 +03:00
return 0 ;
}
static int aic32x4_mute ( struct snd_soc_dai * dai , int mute )
{
2018-01-29 07:14:49 +03:00
struct snd_soc_component * component = dai - > component ;
2011-03-02 16:52:32 +03:00
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_DACMUTE ,
2017-12-13 01:43:08 +03:00
AIC32X4_MUTEON , mute ? AIC32X4_MUTEON : 0 ) ;
2011-03-02 16:52:32 +03:00
return 0 ;
}
2018-01-29 07:14:49 +03:00
static int aic32x4_set_bias_level ( struct snd_soc_component * component ,
2011-03-02 16:52:32 +03:00
enum snd_soc_bias_level level )
{
2018-01-29 07:14:49 +03:00
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2014-02-20 21:22:58 +04:00
int ret ;
2011-03-02 16:52:32 +03:00
switch ( level ) {
case SND_SOC_BIAS_ON :
2014-02-20 21:22:58 +04:00
/* Switch on master clock */
ret = clk_prepare_enable ( aic32x4 - > mclk ) ;
if ( ret ) {
2018-01-29 07:14:49 +03:00
dev_err ( component - > dev , " Failed to enable master clock \n " ) ;
2014-02-20 21:22:58 +04:00
return ret ;
}
2012-01-18 14:48:58 +04:00
/* Switch on PLL */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_PLLPR ,
2012-01-18 14:48:58 +04:00
AIC32X4_PLLEN , AIC32X4_PLLEN ) ;
/* Switch on NDAC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NDAC ,
2012-01-18 14:48:58 +04:00
AIC32X4_NDACEN , AIC32X4_NDACEN ) ;
/* Switch on MDAC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MDAC ,
2012-01-18 14:48:58 +04:00
AIC32X4_MDACEN , AIC32X4_MDACEN ) ;
/* Switch on NADC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NADC ,
2012-01-18 14:48:58 +04:00
AIC32X4_NADCEN , AIC32X4_NADCEN ) ;
/* Switch on MADC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MADC ,
2012-01-18 14:48:58 +04:00
AIC32X4_MADCEN , AIC32X4_MADCEN ) ;
/* Switch on BCLK_N Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_BCLKN ,
2012-01-18 14:48:58 +04:00
AIC32X4_BCLKEN , AIC32X4_BCLKEN ) ;
2011-03-02 16:52:32 +03:00
break ;
case SND_SOC_BIAS_PREPARE :
break ;
case SND_SOC_BIAS_STANDBY :
2019-01-07 20:00:22 +03:00
/* Initial cold start */
if ( snd_soc_component_get_bias_level ( component ) = = SND_SOC_BIAS_OFF )
break ;
2014-02-20 21:23:00 +04:00
/* Switch off BCLK_N Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_BCLKN ,
2014-02-20 21:23:00 +04:00
AIC32X4_BCLKEN , 0 ) ;
2012-01-18 14:48:58 +04:00
2014-02-20 21:23:00 +04:00
/* Switch off MADC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MADC ,
2014-02-20 21:23:00 +04:00
AIC32X4_MADCEN , 0 ) ;
2012-01-18 14:48:58 +04:00
/* Switch off NADC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NADC ,
2012-01-18 14:48:58 +04:00
AIC32X4_NADCEN , 0 ) ;
2014-02-20 21:23:00 +04:00
/* Switch off MDAC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_MDAC ,
2014-02-20 21:23:00 +04:00
AIC32X4_MDACEN , 0 ) ;
2012-01-18 14:48:58 +04:00
2014-02-20 21:23:00 +04:00
/* Switch off NDAC Divider */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_NDAC ,
2014-02-20 21:23:00 +04:00
AIC32X4_NDACEN , 0 ) ;
/* Switch off PLL */
2018-01-29 07:14:49 +03:00
snd_soc_component_update_bits ( component , AIC32X4_PLLPR ,
2014-02-20 21:23:00 +04:00
AIC32X4_PLLEN , 0 ) ;
2014-02-20 21:22:58 +04:00
/* Switch off master clock */
clk_disable_unprepare ( aic32x4 - > mclk ) ;
2011-03-02 16:52:32 +03:00
break ;
case SND_SOC_BIAS_OFF :
break ;
}
return 0 ;
}
2016-04-19 19:59:04 +03:00
# define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
2011-03-02 16:52:32 +03:00
# define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE )
2011-11-23 14:40:40 +04:00
static const struct snd_soc_dai_ops aic32x4_ops = {
2011-03-02 16:52:32 +03: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 = {
. stream_name = " Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = AIC32X4_RATES ,
. formats = AIC32X4_FORMATS , } ,
. capture = {
. stream_name = " Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = AIC32X4_RATES ,
. formats = AIC32X4_FORMATS , } ,
. ops = & aic32x4_ops ,
. symmetric_rates = 1 ,
} ;
2018-01-29 07:14:49 +03:00
static void aic32x4_setup_gpios ( struct snd_soc_component * component )
2017-07-12 21:37:00 +03:00
{
2018-01-29 07:14:49 +03:00
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2017-07-12 21:37:00 +03:00
/* setup GPIO functions */
/* MFP1 */
if ( aic32x4 - > setup - > gpio_func [ 0 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_DINCTL ,
2017-07-12 21:37:00 +03:00
aic32x4 - > setup - > gpio_func [ 0 ] ) ;
2018-01-29 07:14:49 +03:00
snd_soc_add_component_controls ( component , aic32x4_mfp1 ,
2017-07-12 21:37:00 +03:00
ARRAY_SIZE ( aic32x4_mfp1 ) ) ;
}
/* MFP2 */
if ( aic32x4 - > setup - > gpio_func [ 1 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_DOUTCTL ,
2017-07-12 21:37:00 +03:00
aic32x4 - > setup - > gpio_func [ 1 ] ) ;
2018-01-29 07:14:49 +03:00
snd_soc_add_component_controls ( component , aic32x4_mfp2 ,
2017-07-12 21:37:00 +03:00
ARRAY_SIZE ( aic32x4_mfp2 ) ) ;
}
/* MFP3 */
if ( aic32x4 - > setup - > gpio_func [ 2 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_SCLKCTL ,
2017-07-12 21:37:00 +03:00
aic32x4 - > setup - > gpio_func [ 2 ] ) ;
2018-01-29 07:14:49 +03:00
snd_soc_add_component_controls ( component , aic32x4_mfp3 ,
2017-07-12 21:37:00 +03:00
ARRAY_SIZE ( aic32x4_mfp3 ) ) ;
}
/* MFP4 */
if ( aic32x4 - > setup - > gpio_func [ 3 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_MISOCTL ,
2017-07-12 21:37:00 +03:00
aic32x4 - > setup - > gpio_func [ 3 ] ) ;
2018-01-29 07:14:49 +03:00
snd_soc_add_component_controls ( component , aic32x4_mfp4 ,
2017-07-12 21:37:00 +03:00
ARRAY_SIZE ( aic32x4_mfp4 ) ) ;
}
/* MFP5 */
if ( aic32x4 - > setup - > gpio_func [ 4 ] ! = AIC32X4_MFPX_DEFAULT_VALUE ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_GPIOCTL ,
2017-07-12 21:37:00 +03:00
aic32x4 - > setup - > gpio_func [ 4 ] ) ;
2018-01-29 07:14:49 +03:00
snd_soc_add_component_controls ( component , aic32x4_mfp5 ,
2017-07-12 21:37:00 +03:00
ARRAY_SIZE ( aic32x4_mfp5 ) ) ;
}
}
2018-01-29 07:14:49 +03:00
static int aic32x4_component_probe ( struct snd_soc_component * component )
2011-03-02 16:52:32 +03:00
{
2018-01-29 07:14:49 +03:00
struct aic32x4_priv * aic32x4 = snd_soc_component_get_drvdata ( component ) ;
2011-03-02 16:52:32 +03:00
u32 tmp_reg ;
2014-01-16 19:30:25 +04:00
if ( gpio_is_valid ( aic32x4 - > rstn_gpio ) ) {
2012-10-31 14:53:34 +04:00
ndelay ( 10 ) ;
gpio_set_value ( aic32x4 - > rstn_gpio , 1 ) ;
2019-02-12 00:06:30 +03:00
mdelay ( 1 ) ;
2012-10-31 14:53:34 +04:00
}
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_RESET , 0x01 ) ;
2011-03-02 16:52:32 +03:00
2017-07-12 21:37:00 +03:00
if ( aic32x4 - > setup )
2018-01-29 07:14:49 +03:00
aic32x4_setup_gpios ( component ) ;
2017-07-12 21:37:00 +03:00
2011-03-02 16:52:32 +03:00
/* Power platform configuration */
if ( aic32x4 - > power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN ) {
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_MICBIAS , AIC32X4_MICBIAS_LDOIN |
2011-03-02 16:52:32 +03:00
AIC32X4_MICBIAS_2075V ) ;
}
2014-06-13 09:48:47 +04:00
if ( aic32x4 - > power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE )
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_PWRCFG , AIC32X4_AVDDWEAKDISABLE ) ;
2012-01-18 14:48:59 +04:00
tmp_reg = ( aic32x4 - > power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE ) ?
AIC32X4_LDOCTLEN : 0 ;
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_LDOCTL , tmp_reg ) ;
2012-01-18 14:48:59 +04:00
2018-01-29 07:14:49 +03:00
tmp_reg = snd_soc_component_read32 ( component , AIC32X4_CMMODE ) ;
2014-06-13 09:48:47 +04:00
if ( aic32x4 - > power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 )
2011-03-02 16:52:32 +03:00
tmp_reg | = AIC32X4_LDOIN_18_36 ;
2014-06-13 09:48:47 +04:00
if ( aic32x4 - > power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED )
2011-03-02 16:52:32 +03:00
tmp_reg | = AIC32X4_LDOIN2HP ;
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_CMMODE , tmp_reg ) ;
2011-03-02 16:52:32 +03:00
/* Mic PGA routing */
2014-01-27 16:03:06 +04:00
if ( aic32x4 - > micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K )
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_LMICPGANIN ,
2014-06-13 09:48:48 +04:00
AIC32X4_LMICPGANIN_IN2R_10K ) ;
2014-01-27 16:03:06 +04:00
else
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_LMICPGANIN ,
2014-06-13 09:48:48 +04:00
AIC32X4_LMICPGANIN_CM1L_10K ) ;
2014-01-27 16:03:06 +04:00
if ( aic32x4 - > micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K )
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_RMICPGANIN ,
2014-06-13 09:48:48 +04:00
AIC32X4_RMICPGANIN_IN1L_10K ) ;
2014-01-27 16:03:06 +04:00
else
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_RMICPGANIN ,
2014-06-13 09:48:48 +04:00
AIC32X4_RMICPGANIN_CM1R_10K ) ;
2011-03-02 16:52:32 +03:00
2012-10-31 14:53:33 +04: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 07:14:49 +03:00
tmp_reg = snd_soc_component_read32 ( component , AIC32X4_ADCSETUP ) ;
snd_soc_component_write ( component , AIC32X4_ADCSETUP , tmp_reg |
2012-10-31 14:53:33 +04:00
AIC32X4_LADC_EN | AIC32X4_RADC_EN ) ;
2018-01-29 07:14:49 +03:00
snd_soc_component_write ( component , AIC32X4_ADCSETUP , tmp_reg ) ;
2012-10-31 14:53:33 +04:00
2011-03-02 16:52:32 +03:00
return 0 ;
}
2018-01-29 07:14:49 +03: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 16:52:32 +03:00
} ;
2014-01-27 16:03:08 +04:00
static int aic32x4_parse_dt ( struct aic32x4_priv * aic32x4 ,
struct device_node * np )
{
2017-07-12 21:37:00 +03:00
struct aic32x4_setup_data * aic32x4_setup ;
aic32x4_setup = devm_kzalloc ( aic32x4 - > dev , sizeof ( * aic32x4_setup ) ,
GFP_KERNEL ) ;
if ( ! aic32x4_setup )
return - ENOMEM ;
2014-01-27 16:03:08 +04:00
aic32x4 - > swapdacs = false ;
aic32x4 - > micpga_routing = 0 ;
aic32x4 - > rstn_gpio = of_get_named_gpio ( np , " reset-gpios " , 0 ) ;
2017-07-12 21:37:00 +03:00
if ( of_property_read_u32_array ( np , " aic32x4-gpio-func " ,
aic32x4_setup - > gpio_func , 5 ) > = 0 )
aic32x4 - > setup = aic32x4_setup ;
2014-01-27 16:03:08 +04:00
return 0 ;
}
2014-02-20 21:22:59 +04: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-19 03:24:05 +03:00
int aic32x4_probe ( struct device * dev , struct regmap * regmap )
2011-03-02 16:52:32 +03:00
{
struct aic32x4_priv * aic32x4 ;
2016-04-19 03:24:05 +03:00
struct aic32x4_pdata * pdata = dev - > platform_data ;
struct device_node * np = dev - > of_node ;
2011-03-02 16:52:32 +03:00
int ret ;
2016-04-19 03:24:05 +03:00
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
aic32x4 = devm_kzalloc ( dev , sizeof ( struct aic32x4_priv ) ,
2011-12-26 16:57:24 +04:00
GFP_KERNEL ) ;
2011-03-02 16:52:32 +03:00
if ( aic32x4 = = NULL )
return - ENOMEM ;
2017-07-12 21:37:00 +03:00
aic32x4 - > dev = dev ;
2016-04-19 03:24:05 +03:00
dev_set_drvdata ( dev , aic32x4 ) ;
2011-03-02 16:52:32 +03:00
if ( pdata ) {
aic32x4 - > power_cfg = pdata - > power_cfg ;
aic32x4 - > swapdacs = pdata - > swapdacs ;
aic32x4 - > micpga_routing = pdata - > micpga_routing ;
2012-10-31 14:53:34 +04:00
aic32x4 - > rstn_gpio = pdata - > rstn_gpio ;
2014-01-27 16:03:08 +04:00
} else if ( np ) {
ret = aic32x4_parse_dt ( aic32x4 , np ) ;
if ( ret ) {
2016-04-19 03:24:05 +03:00
dev_err ( dev , " Failed to parse DT node \n " ) ;
2014-01-27 16:03:08 +04:00
return ret ;
}
2011-03-02 16:52:32 +03:00
} else {
aic32x4 - > power_cfg = 0 ;
aic32x4 - > swapdacs = false ;
aic32x4 - > micpga_routing = 0 ;
2012-10-31 14:53:34 +04:00
aic32x4 - > rstn_gpio = - 1 ;
2011-03-02 16:52:32 +03:00
}
2016-04-19 03:24:05 +03:00
aic32x4 - > mclk = devm_clk_get ( dev , " mclk " ) ;
2014-02-20 21:22:58 +04:00
if ( IS_ERR ( aic32x4 - > mclk ) ) {
2016-04-19 03:24:05 +03:00
dev_err ( dev , " Failed getting the mclk. The current implementation does not support the usage of this codec without mclk \n " ) ;
2014-02-20 21:22:58 +04:00
return PTR_ERR ( aic32x4 - > mclk ) ;
}
2014-01-16 19:30:25 +04:00
if ( gpio_is_valid ( aic32x4 - > rstn_gpio ) ) {
2016-04-19 03:24:05 +03:00
ret = devm_gpio_request_one ( dev , aic32x4 - > rstn_gpio ,
2013-09-25 14:36:26 +04:00
GPIOF_OUT_INIT_LOW , " tlv320aic32x4 rstn " ) ;
if ( ret ! = 0 )
return ret ;
}
2016-04-19 03:24:05 +03:00
ret = aic32x4_setup_regulators ( dev , aic32x4 ) ;
2014-02-20 21:22:59 +04:00
if ( ret ) {
2016-04-19 03:24:05 +03:00
dev_err ( dev , " Failed to setup regulators \n " ) ;
2014-02-20 21:22:59 +04:00
return ret ;
}
2018-01-29 07:14:49 +03:00
ret = devm_snd_soc_register_component ( dev ,
& soc_component_dev_aic32x4 , & aic32x4_dai , 1 ) ;
2014-02-20 21:22:59 +04:00
if ( ret ) {
2018-01-29 07:14:49 +03:00
dev_err ( dev , " Failed to register component \n " ) ;
2014-02-20 21:22:59 +04:00
aic32x4_disable_regulators ( aic32x4 ) ;
return ret ;
}
return 0 ;
2011-03-02 16:52:32 +03:00
}
2016-04-19 03:24:05 +03:00
EXPORT_SYMBOL ( aic32x4_probe ) ;
2011-03-02 16:52:32 +03:00
2016-04-19 03:24:05 +03:00
int aic32x4_remove ( struct device * dev )
2011-03-02 16:52:32 +03:00
{
2016-04-19 03:24:05 +03:00
struct aic32x4_priv * aic32x4 = dev_get_drvdata ( dev ) ;
2014-02-20 21:22:59 +04:00
aic32x4_disable_regulators ( aic32x4 ) ;
2011-03-02 16:52:32 +03:00
return 0 ;
}
2016-04-19 03:24:05 +03:00
EXPORT_SYMBOL ( aic32x4_remove ) ;
2011-03-02 16:52:32 +03:00
MODULE_DESCRIPTION ( " ASoC tlv320aic32x4 codec driver " ) ;
MODULE_AUTHOR ( " Javier Martin <javier.martin@vista-silicon.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;