2015-03-10 01:50:34 +03:00
/*
* max98925 . c - - ALSA SoC Stereo MAX98925 driver
* Copyright 2013 - 15 Maxim Integrated Products
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/delay.h>
# include <linux/i2c.h>
# include <linux/module.h>
# include <linux/regmap.h>
# include <linux/slab.h>
# include <linux/cdev.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/tlv.h>
# include "max98925.h"
static const char * const dai_text [ ] = {
" Left " , " Right " , " LeftRight " , " LeftRightDiv2 " ,
} ;
static const char * const max98925_boost_voltage_text [ ] = {
" 8.5V " , " 8.25V " , " 8.0V " , " 7.75V " , " 7.5V " , " 7.25V " , " 7.0V " , " 6.75V " ,
" 6.5V " , " 6.5V " , " 6.5V " , " 6.5V " , " 6.5V " , " 6.5V " , " 6.5V " , " 6.5V "
} ;
static SOC_ENUM_SINGLE_DECL ( max98925_boost_voltage ,
MAX98925_CONFIGURATION , M98925_BST_VOUT_SHIFT ,
max98925_boost_voltage_text ) ;
static const char * const hpf_text [ ] = {
" Disable " , " DC Block " , " 100Hz " , " 200Hz " , " 400Hz " , " 800Hz " ,
} ;
2015-03-20 14:35:45 +03:00
static const struct reg_default max98925_reg [ ] = {
2015-03-10 01:50:34 +03:00
{ 0x0B , 0x00 } , /* IRQ Enable0 */
{ 0x0C , 0x00 } , /* IRQ Enable1 */
{ 0x0D , 0x00 } , /* IRQ Enable2 */
{ 0x0E , 0x00 } , /* IRQ Clear0 */
{ 0x0F , 0x00 } , /* IRQ Clear1 */
{ 0x10 , 0x00 } , /* IRQ Clear2 */
{ 0x11 , 0xC0 } , /* Map0 */
{ 0x12 , 0x00 } , /* Map1 */
{ 0x13 , 0x00 } , /* Map2 */
{ 0x14 , 0xF0 } , /* Map3 */
{ 0x15 , 0x00 } , /* Map4 */
{ 0x16 , 0xAB } , /* Map5 */
{ 0x17 , 0x89 } , /* Map6 */
{ 0x18 , 0x00 } , /* Map7 */
{ 0x19 , 0x00 } , /* Map8 */
{ 0x1A , 0x06 } , /* DAI Clock Mode 1 */
{ 0x1B , 0xC0 } , /* DAI Clock Mode 2 */
{ 0x1C , 0x00 } , /* DAI Clock Divider Denominator MSBs */
{ 0x1D , 0x00 } , /* DAI Clock Divider Denominator LSBs */
{ 0x1E , 0xF0 } , /* DAI Clock Divider Numerator MSBs */
{ 0x1F , 0x00 } , /* DAI Clock Divider Numerator LSBs */
{ 0x20 , 0x50 } , /* Format */
{ 0x21 , 0x00 } , /* TDM Slot Select */
{ 0x22 , 0x00 } , /* DOUT Configuration VMON */
{ 0x23 , 0x00 } , /* DOUT Configuration IMON */
{ 0x24 , 0x00 } , /* DOUT Configuration VBAT */
{ 0x25 , 0x00 } , /* DOUT Configuration VBST */
{ 0x26 , 0x00 } , /* DOUT Configuration FLAG */
{ 0x27 , 0xFF } , /* DOUT HiZ Configuration 1 */
{ 0x28 , 0xFF } , /* DOUT HiZ Configuration 2 */
{ 0x29 , 0xFF } , /* DOUT HiZ Configuration 3 */
{ 0x2A , 0xFF } , /* DOUT HiZ Configuration 4 */
{ 0x2B , 0x02 } , /* DOUT Drive Strength */
{ 0x2C , 0x90 } , /* Filters */
{ 0x2D , 0x00 } , /* Gain */
{ 0x2E , 0x02 } , /* Gain Ramping */
{ 0x2F , 0x00 } , /* Speaker Amplifier */
{ 0x30 , 0x0A } , /* Threshold */
{ 0x31 , 0x00 } , /* ALC Attack */
{ 0x32 , 0x80 } , /* ALC Atten and Release */
{ 0x33 , 0x00 } , /* ALC Infinite Hold Release */
{ 0x34 , 0x92 } , /* ALC Configuration */
{ 0x35 , 0x01 } , /* Boost Converter */
{ 0x36 , 0x00 } , /* Block Enable */
{ 0x37 , 0x00 } , /* Configuration */
{ 0x38 , 0x00 } , /* Global Enable */
{ 0x3A , 0x00 } , /* Boost Limiter */
} ;
static const struct soc_enum max98925_dai_enum =
SOC_ENUM_SINGLE ( MAX98925_GAIN , 5 , ARRAY_SIZE ( dai_text ) , dai_text ) ;
static const struct soc_enum max98925_hpf_enum =
SOC_ENUM_SINGLE ( MAX98925_FILTERS , 0 , ARRAY_SIZE ( hpf_text ) , hpf_text ) ;
static const struct snd_kcontrol_new max98925_hpf_sel_mux =
SOC_DAPM_ENUM ( " Rc Filter MUX Mux " , max98925_hpf_enum ) ;
static const struct snd_kcontrol_new max98925_dai_sel_mux =
SOC_DAPM_ENUM ( " DAI IN MUX Mux " , max98925_dai_enum ) ;
static int max98925_dac_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
struct snd_soc_codec * codec = snd_soc_kcontrol_codec ( kcontrol ) ;
struct max98925_priv * max98925 = snd_soc_codec_get_drvdata ( codec ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_BLOCK_ENABLE ,
M98925_BST_EN_MASK |
M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK ,
M98925_BST_EN_MASK |
M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK ) ;
break ;
case SND_SOC_DAPM_POST_PMD :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_BLOCK_ENABLE , M98925_BST_EN_MASK |
M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK , 0 ) ;
break ;
default :
return 0 ;
}
return 0 ;
}
static const struct snd_soc_dapm_widget max98925_dapm_widgets [ ] = {
SND_SOC_DAPM_AIF_IN ( " DAI_OUT " , " HiFi Playback " , 0 , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_MUX ( " DAI IN MUX " , SND_SOC_NOPM , 0 , 0 ,
& max98925_dai_sel_mux ) ,
SND_SOC_DAPM_MUX ( " Rc Filter MUX " , SND_SOC_NOPM , 0 , 0 ,
& max98925_hpf_sel_mux ) ,
SND_SOC_DAPM_DAC_E ( " Amp Enable " , NULL , MAX98925_BLOCK_ENABLE ,
M98925_SPK_EN_SHIFT , 0 , max98925_dac_event ,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD ) ,
SND_SOC_DAPM_SUPPLY ( " Global Enable " , MAX98925_GLOBAL_ENABLE ,
M98925_EN_SHIFT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_OUTPUT ( " BE_OUT " ) ,
} ;
static const struct snd_soc_dapm_route max98925_audio_map [ ] = {
{ " DAI IN MUX " , " Left " , " DAI_OUT " } ,
{ " DAI IN MUX " , " Right " , " DAI_OUT " } ,
{ " DAI IN MUX " , " LeftRight " , " DAI_OUT " } ,
{ " DAI IN MUX " , " LeftRightDiv2 " , " DAI_OUT " } ,
{ " Rc Filter MUX " , " Disable " , " DAI IN MUX " } ,
{ " Rc Filter MUX " , " DC Block " , " DAI IN MUX " } ,
{ " Rc Filter MUX " , " 100Hz " , " DAI IN MUX " } ,
{ " Rc Filter MUX " , " 200Hz " , " DAI IN MUX " } ,
{ " Rc Filter MUX " , " 400Hz " , " DAI IN MUX " } ,
{ " Rc Filter MUX " , " 800Hz " , " DAI IN MUX " } ,
{ " Amp Enable " , NULL , " Rc Filter MUX " } ,
{ " BE_OUT " , NULL , " Amp Enable " } ,
{ " BE_OUT " , NULL , " Global Enable " } ,
} ;
static bool max98925_volatile_register ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case MAX98925_VBAT_DATA :
case MAX98925_VBST_DATA :
case MAX98925_LIVE_STATUS0 :
case MAX98925_LIVE_STATUS1 :
case MAX98925_LIVE_STATUS2 :
case MAX98925_STATE0 :
case MAX98925_STATE1 :
case MAX98925_STATE2 :
case MAX98925_FLAG0 :
case MAX98925_FLAG1 :
case MAX98925_FLAG2 :
case MAX98925_REV_VERSION :
return true ;
default :
return false ;
}
}
static bool max98925_readable_register ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case MAX98925_IRQ_CLEAR0 :
case MAX98925_IRQ_CLEAR1 :
case MAX98925_IRQ_CLEAR2 :
case MAX98925_ALC_HOLD_RLS :
return false ;
default :
return true ;
}
}
2015-03-11 22:05:44 +03:00
static DECLARE_TLV_DB_SCALE ( max98925_spk_tlv , - 600 , 100 , 0 ) ;
2015-03-10 01:50:34 +03:00
static const struct snd_kcontrol_new max98925_snd_controls [ ] = {
SOC_SINGLE_TLV ( " Speaker Volume " , MAX98925_GAIN ,
M98925_SPK_GAIN_SHIFT , ( 1 < < M98925_SPK_GAIN_WIDTH ) - 1 , 0 ,
max98925_spk_tlv ) ,
SOC_SINGLE ( " Ramp Switch " , MAX98925_GAIN_RAMPING ,
M98925_SPK_RMP_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " ZCD Switch " , MAX98925_GAIN_RAMPING ,
M98925_SPK_ZCD_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " ALC Switch " , MAX98925_THRESHOLD ,
M98925_ALC_EN_SHIFT , 1 , 0 ) ,
SOC_SINGLE ( " ALC Threshold " , MAX98925_THRESHOLD , M98925_ALC_TH_SHIFT ,
( 1 < < M98925_ALC_TH_WIDTH ) - 1 , 0 ) ,
SOC_ENUM ( " Boost Output Voltage " , max98925_boost_voltage ) ,
} ;
/* codec sample rate and n/m dividers parameter table */
static const struct {
int rate ;
int sr ;
int divisors [ 3 ] [ 2 ] ;
} rate_table [ ] = {
{
. rate = 8000 ,
. sr = 0 ,
. divisors = { { 1 , 375 } , { 5 , 1764 } , { 1 , 384 } }
} ,
{
. rate = 11025 ,
. sr = 1 ,
. divisors = { { 147 , 40000 } , { 1 , 256 } , { 147 , 40960 } }
} ,
{
. rate = 12000 ,
. sr = 2 ,
. divisors = { { 1 , 250 } , { 5 , 1176 } , { 1 , 256 } }
} ,
{
. rate = 16000 ,
. sr = 3 ,
. divisors = { { 2 , 375 } , { 5 , 882 } , { 1 , 192 } }
} ,
{
. rate = 22050 ,
. sr = 4 ,
. divisors = { { 147 , 20000 } , { 1 , 128 } , { 147 , 20480 } }
} ,
{
. rate = 24000 ,
. sr = 5 ,
. divisors = { { 1 , 125 } , { 5 , 588 } , { 1 , 128 } }
} ,
{
. rate = 32000 ,
. sr = 6 ,
. divisors = { { 4 , 375 } , { 5 , 441 } , { 1 , 96 } }
} ,
{
. rate = 44100 ,
. sr = 7 ,
. divisors = { { 147 , 10000 } , { 1 , 64 } , { 147 , 10240 } }
} ,
{
. rate = 48000 ,
. sr = 8 ,
. divisors = { { 2 , 125 } , { 5 , 294 } , { 1 , 64 } }
} ,
} ;
static inline int max98925_rate_value ( struct snd_soc_codec * codec ,
int rate , int clock , int * value , int * n , int * m )
{
int ret = - EINVAL ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( rate_table ) ; i + + ) {
if ( rate_table [ i ] . rate > = rate ) {
* value = rate_table [ i ] . sr ;
* n = rate_table [ i ] . divisors [ clock ] [ 0 ] ;
* m = rate_table [ i ] . divisors [ clock ] [ 1 ] ;
ret = 0 ;
break ;
}
}
return ret ;
}
static void max98925_set_sense_data ( struct max98925_priv * max98925 )
{
/* set VMON slots */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DOUT_CFG_VMON ,
M98925_DAI_VMON_EN_MASK , M98925_DAI_VMON_EN_MASK ) ;
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DOUT_CFG_VMON ,
M98925_DAI_VMON_SLOT_MASK ,
max98925 - > v_slot < < M98925_DAI_VMON_SLOT_SHIFT ) ;
/* set IMON slots */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DOUT_CFG_IMON ,
M98925_DAI_IMON_EN_MASK , M98925_DAI_IMON_EN_MASK ) ;
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DOUT_CFG_IMON ,
M98925_DAI_IMON_SLOT_MASK ,
max98925 - > i_slot < < M98925_DAI_IMON_SLOT_SHIFT ) ;
}
static int max98925_dai_set_fmt ( struct snd_soc_dai * codec_dai ,
unsigned int fmt )
{
struct snd_soc_codec * codec = codec_dai - > codec ;
struct max98925_priv * max98925 = snd_soc_codec_get_drvdata ( codec ) ;
unsigned int invert = 0 ;
dev_dbg ( codec - > dev , " %s: fmt 0x%08X \n " , __func__ , fmt ) ;
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
/* set DAI to slave mode */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_MAS_MASK , 0 ) ;
max98925_set_sense_data ( max98925 ) ;
break ;
case SND_SOC_DAIFMT_CBM_CFM :
/*
* set left channel DAI to master mode ,
* right channel always slave
*/
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_MAS_MASK , M98925_DAI_MAS_MASK ) ;
break ;
case SND_SOC_DAIFMT_CBS_CFM :
case SND_SOC_DAIFMT_CBM_CFS :
default :
dev_err ( codec - > dev , " DAI clock mode unsupported " ) ;
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_INV_MASK ) {
case SND_SOC_DAIFMT_NB_NF :
break ;
case SND_SOC_DAIFMT_NB_IF :
invert = M98925_DAI_WCI_MASK ;
break ;
case SND_SOC_DAIFMT_IB_NF :
invert = M98925_DAI_BCI_MASK ;
break ;
case SND_SOC_DAIFMT_IB_IF :
invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK ;
break ;
default :
dev_err ( codec - > dev , " DAI invert mode unsupported " ) ;
return - EINVAL ;
}
regmap_update_bits ( max98925 - > regmap , MAX98925_FORMAT ,
2015-05-26 15:35:08 +03:00
M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK , invert ) ;
2015-03-10 01:50:34 +03:00
return 0 ;
}
static int max98925_set_clock ( struct max98925_priv * max98925 ,
struct snd_pcm_hw_params * params )
{
unsigned int dai_sr = 0 , clock , mdll , n , m ;
struct snd_soc_codec * codec = max98925 - > codec ;
int rate = params_rate ( params ) ;
/* BCLK/LRCLK ratio calculation */
int blr_clk_ratio = params_channels ( params ) * max98925 - > ch_size ;
switch ( blr_clk_ratio ) {
case 32 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_BSEL_MASK , M98925_DAI_BSEL_32 ) ;
break ;
case 48 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_BSEL_MASK , M98925_DAI_BSEL_48 ) ;
break ;
case 64 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_BSEL_MASK , M98925_DAI_BSEL_64 ) ;
break ;
default :
return - EINVAL ;
}
switch ( max98925 - > sysclk ) {
case 6000000 :
clock = 0 ;
mdll = M98925_MDLL_MULT_MCLKx16 ;
break ;
case 11289600 :
clock = 1 ;
mdll = M98925_MDLL_MULT_MCLKx8 ;
break ;
case 12000000 :
clock = 0 ;
mdll = M98925_MDLL_MULT_MCLKx8 ;
break ;
case 12288000 :
clock = 2 ;
mdll = M98925_MDLL_MULT_MCLKx8 ;
break ;
default :
dev_info ( max98925 - > codec - > dev , " unsupported sysclk %d \n " ,
max98925 - > sysclk ) ;
return - EINVAL ;
}
if ( max98925_rate_value ( codec , rate , clock , & dai_sr , & n , & m ) )
return - EINVAL ;
/* set DAI_SR to correct LRCLK frequency */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE2 ,
M98925_DAI_SR_MASK , dai_sr < < M98925_DAI_SR_SHIFT ) ;
/* set DAI m divider */
regmap_write ( max98925 - > regmap ,
MAX98925_DAI_CLK_DIV_M_MSBS , m > > 8 ) ;
regmap_write ( max98925 - > regmap ,
MAX98925_DAI_CLK_DIV_M_LSBS , m & 0xFF ) ;
/* set DAI n divider */
regmap_write ( max98925 - > regmap ,
MAX98925_DAI_CLK_DIV_N_MSBS , n > > 8 ) ;
regmap_write ( max98925 - > regmap ,
MAX98925_DAI_CLK_DIV_N_LSBS , n & 0xFF ) ;
/* set MDLL */
regmap_update_bits ( max98925 - > regmap , MAX98925_DAI_CLK_MODE1 ,
M98925_MDLL_MULT_MASK , mdll < < M98925_MDLL_MULT_SHIFT ) ;
return 0 ;
}
static int max98925_dai_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
struct snd_soc_codec * codec = dai - > codec ;
struct max98925_priv * max98925 = snd_soc_codec_get_drvdata ( codec ) ;
2015-07-24 11:11:25 +03:00
switch ( params_width ( params ) ) {
2015-03-10 01:50:34 +03:00
case 16 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_FORMAT ,
M98925_DAI_CHANSZ_MASK , M98925_DAI_CHANSZ_16 ) ;
max98925 - > ch_size = 16 ;
break ;
case 24 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_FORMAT ,
2015-03-27 12:25:21 +03:00
M98925_DAI_CHANSZ_MASK , M98925_DAI_CHANSZ_24 ) ;
max98925 - > ch_size = 24 ;
2015-03-10 01:50:34 +03:00
break ;
case 32 :
regmap_update_bits ( max98925 - > regmap ,
MAX98925_FORMAT ,
M98925_DAI_CHANSZ_MASK , M98925_DAI_CHANSZ_32 ) ;
max98925 - > ch_size = 32 ;
break ;
default :
pr_err ( " %s: format unsupported %d " ,
__func__ , params_format ( params ) ) ;
return - EINVAL ;
}
dev_dbg ( codec - > dev , " %s: format supported %d " ,
__func__ , params_format ( params ) ) ;
return max98925_set_clock ( max98925 , params ) ;
}
static int max98925_dai_set_sysclk ( struct snd_soc_dai * dai ,
int clk_id , unsigned int freq , int dir )
{
struct snd_soc_codec * codec = dai - > codec ;
struct max98925_priv * max98925 = snd_soc_codec_get_drvdata ( codec ) ;
switch ( clk_id ) {
case 0 :
/* use MCLK for Left channel, right channel always BCLK */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE1 ,
M98925_DAI_CLK_SOURCE_MASK , 0 ) ;
break ;
case 1 :
/* configure dai clock source to BCLK instead of MCLK */
regmap_update_bits ( max98925 - > regmap ,
MAX98925_DAI_CLK_MODE1 ,
M98925_DAI_CLK_SOURCE_MASK ,
M98925_DAI_CLK_SOURCE_MASK ) ;
break ;
default :
return - EINVAL ;
}
max98925 - > sysclk = freq ;
return 0 ;
}
# define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE )
2015-03-20 14:35:45 +03:00
static const struct snd_soc_dai_ops max98925_dai_ops = {
2015-03-10 01:50:34 +03:00
. set_sysclk = max98925_dai_set_sysclk ,
. set_fmt = max98925_dai_set_fmt ,
. hw_params = max98925_dai_hw_params ,
} ;
static struct snd_soc_dai_driver max98925_dai [ ] = {
{
. name = " max98925-aif1 " ,
. playback = {
. stream_name = " HiFi Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = MAX98925_FORMATS ,
} ,
. capture = {
. stream_name = " HiFi Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = MAX98925_FORMATS ,
} ,
. ops = & max98925_dai_ops ,
}
} ;
static int max98925_probe ( struct snd_soc_codec * codec )
{
struct max98925_priv * max98925 = snd_soc_codec_get_drvdata ( codec ) ;
max98925 - > codec = codec ;
regmap_write ( max98925 - > regmap , MAX98925_GLOBAL_ENABLE , 0x00 ) ;
/* It's not the default but we need to set DAI_DLY */
regmap_write ( max98925 - > regmap ,
MAX98925_FORMAT , M98925_DAI_DLY_MASK ) ;
regmap_write ( max98925 - > regmap , MAX98925_TDM_SLOT_SELECT , 0xC8 ) ;
regmap_write ( max98925 - > regmap , MAX98925_DOUT_HIZ_CFG1 , 0xFF ) ;
regmap_write ( max98925 - > regmap , MAX98925_DOUT_HIZ_CFG2 , 0xFF ) ;
regmap_write ( max98925 - > regmap , MAX98925_DOUT_HIZ_CFG3 , 0xFF ) ;
regmap_write ( max98925 - > regmap , MAX98925_DOUT_HIZ_CFG4 , 0xF0 ) ;
regmap_write ( max98925 - > regmap , MAX98925_FILTERS , 0xD8 ) ;
regmap_write ( max98925 - > regmap , MAX98925_ALC_CONFIGURATION , 0xF8 ) ;
regmap_write ( max98925 - > regmap , MAX98925_CONFIGURATION , 0xF0 ) ;
/* Disable ALC muting */
regmap_write ( max98925 - > regmap , MAX98925_BOOST_LIMITER , 0xF8 ) ;
return 0 ;
}
2015-03-20 14:35:45 +03:00
static const struct snd_soc_codec_driver soc_codec_dev_max98925 = {
2015-03-10 01:50:34 +03:00
. probe = max98925_probe ,
2016-08-08 12:19:29 +03:00
. component_driver = {
. controls = max98925_snd_controls ,
. num_controls = ARRAY_SIZE ( max98925_snd_controls ) ,
. dapm_routes = max98925_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( max98925_audio_map ) ,
. dapm_widgets = max98925_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( max98925_dapm_widgets ) ,
} ,
2015-03-10 01:50:34 +03:00
} ;
2015-03-20 14:35:45 +03:00
static const struct regmap_config max98925_regmap = {
2015-03-10 01:50:34 +03:00
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = MAX98925_REV_VERSION ,
. reg_defaults = max98925_reg ,
. num_reg_defaults = ARRAY_SIZE ( max98925_reg ) ,
. volatile_reg = max98925_volatile_register ,
. readable_reg = max98925_readable_register ,
. cache_type = REGCACHE_RBTREE ,
} ;
static int max98925_i2c_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * id )
{
int ret , reg ;
u32 value ;
struct max98925_priv * max98925 ;
max98925 = devm_kzalloc ( & i2c - > dev ,
sizeof ( * max98925 ) , GFP_KERNEL ) ;
if ( ! max98925 )
return - ENOMEM ;
i2c_set_clientdata ( i2c , max98925 ) ;
max98925 - > regmap = devm_regmap_init_i2c ( i2c , & max98925_regmap ) ;
if ( IS_ERR ( max98925 - > regmap ) ) {
ret = PTR_ERR ( max98925 - > regmap ) ;
dev_err ( & i2c - > dev ,
" Failed to allocate regmap: %d \n " , ret ) ;
goto err_out ;
}
if ( ! of_property_read_u32 ( i2c - > dev . of_node , " vmon-slot-no " , & value ) ) {
if ( value > M98925_DAI_VMON_SLOT_1E_1F ) {
dev_err ( & i2c - > dev , " vmon slot number is wrong: \n " ) ;
return - EINVAL ;
}
max98925 - > v_slot = value ;
}
if ( ! of_property_read_u32 ( i2c - > dev . of_node , " imon-slot-no " , & value ) ) {
if ( value > M98925_DAI_IMON_SLOT_1E_1F ) {
dev_err ( & i2c - > dev , " imon slot number is wrong: \n " ) ;
return - EINVAL ;
}
max98925 - > i_slot = value ;
}
ret = regmap_read ( max98925 - > regmap ,
MAX98925_REV_VERSION , & reg ) ;
if ( ( ret < 0 ) | |
( ( reg ! = MAX98925_VERSION ) & &
( reg ! = MAX98925_VERSION1 ) ) ) {
dev_err ( & i2c - > dev ,
" device initialization error (%d 0x%02X) \n " ,
ret , reg ) ;
goto err_out ;
}
dev_info ( & i2c - > dev , " device version 0x%02X \n " , reg ) ;
ret = snd_soc_register_codec ( & i2c - > dev , & soc_codec_dev_max98925 ,
max98925_dai , ARRAY_SIZE ( max98925_dai ) ) ;
if ( ret < 0 )
dev_err ( & i2c - > dev ,
" Failed to register codec: %d \n " , ret ) ;
err_out :
return ret ;
}
static int max98925_i2c_remove ( struct i2c_client * client )
{
snd_soc_unregister_codec ( & client - > dev ) ;
return 0 ;
}
static const struct i2c_device_id max98925_i2c_id [ ] = {
{ " max98925 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , max98925_i2c_id ) ;
static const struct of_device_id max98925_of_match [ ] = {
{ . compatible = " maxim,max98925 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , max98925_of_match ) ;
static struct i2c_driver max98925_i2c_driver = {
. driver = {
. name = " max98925 " ,
. of_match_table = of_match_ptr ( max98925_of_match ) ,
. pm = NULL ,
} ,
. probe = max98925_i2c_probe ,
. remove = max98925_i2c_remove ,
. id_table = max98925_i2c_id ,
} ;
module_i2c_driver ( max98925_i2c_driver )
MODULE_DESCRIPTION ( " ALSA SoC MAX98925 driver " ) ;
MODULE_AUTHOR ( " Ralph Birt <rdbirt@gmail.com>, Anish kumar <anish.kumar@maximintegrated.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;