2011-01-14 18:49:40 +03:00
/*
* wm8991 . c - - WM8991 ALSA Soc Audio driver
*
* Copyright 2007 - 2010 Wolfson Microelectronics PLC .
* Author : Graeme Gregory
2011-10-06 14:10:01 +04:00
* Graeme . Gregory @ wolfsonmicro . com
2011-01-14 18:49:40 +03:00
*
* 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 .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
# include <linux/i2c.h>
2013-11-22 17:28:55 +04:00
# include <linux/regmap.h>
2011-01-14 18:49:40 +03:00
# include <linux/slab.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 <asm/div64.h>
# include "wm8991.h"
struct wm8991_priv {
2013-11-22 17:28:55 +04:00
struct regmap * regmap ;
2011-01-14 18:49:40 +03:00
unsigned int pcmclk ;
} ;
2013-11-22 17:28:55 +04:00
static const struct reg_default wm8991_reg_defaults [ ] = {
{ 1 , 0x0000 } , /* R1 - Power Management (1) */
{ 2 , 0x6000 } , /* R2 - Power Management (2) */
{ 3 , 0x0000 } , /* R3 - Power Management (3) */
{ 4 , 0x4050 } , /* R4 - Audio Interface (1) */
{ 5 , 0x4000 } , /* R5 - Audio Interface (2) */
{ 6 , 0x01C8 } , /* R6 - Clocking (1) */
{ 7 , 0x0000 } , /* R7 - Clocking (2) */
{ 8 , 0x0040 } , /* R8 - Audio Interface (3) */
{ 9 , 0x0040 } , /* R9 - Audio Interface (4) */
{ 10 , 0x0004 } , /* R10 - DAC CTRL */
{ 11 , 0x00C0 } , /* R11 - Left DAC Digital Volume */
{ 12 , 0x00C0 } , /* R12 - Right DAC Digital Volume */
{ 13 , 0x0000 } , /* R13 - Digital Side Tone */
{ 14 , 0x0100 } , /* R14 - ADC CTRL */
{ 15 , 0x00C0 } , /* R15 - Left ADC Digital Volume */
{ 16 , 0x00C0 } , /* R16 - Right ADC Digital Volume */
{ 18 , 0x0000 } , /* R18 - GPIO CTRL 1 */
{ 19 , 0x1000 } , /* R19 - GPIO1 & GPIO2 */
{ 20 , 0x1010 } , /* R20 - GPIO3 & GPIO4 */
{ 21 , 0x1010 } , /* R21 - GPIO5 & GPIO6 */
{ 22 , 0x8000 } , /* R22 - GPIOCTRL 2 */
{ 23 , 0x0800 } , /* R23 - GPIO_POL */
{ 24 , 0x008B } , /* R24 - Left Line Input 1&2 Volume */
{ 25 , 0x008B } , /* R25 - Left Line Input 3&4 Volume */
{ 26 , 0x008B } , /* R26 - Right Line Input 1&2 Volume */
{ 27 , 0x008B } , /* R27 - Right Line Input 3&4 Volume */
{ 28 , 0x0000 } , /* R28 - Left Output Volume */
{ 29 , 0x0000 } , /* R29 - Right Output Volume */
{ 30 , 0x0066 } , /* R30 - Line Outputs Volume */
{ 31 , 0x0022 } , /* R31 - Out3/4 Volume */
{ 32 , 0x0079 } , /* R32 - Left OPGA Volume */
{ 33 , 0x0079 } , /* R33 - Right OPGA Volume */
{ 34 , 0x0003 } , /* R34 - Speaker Volume */
{ 35 , 0x0003 } , /* R35 - ClassD1 */
{ 37 , 0x0100 } , /* R37 - ClassD3 */
{ 39 , 0x0000 } , /* R39 - Input Mixer1 */
{ 40 , 0x0000 } , /* R40 - Input Mixer2 */
{ 41 , 0x0000 } , /* R41 - Input Mixer3 */
{ 42 , 0x0000 } , /* R42 - Input Mixer4 */
{ 43 , 0x0000 } , /* R43 - Input Mixer5 */
{ 44 , 0x0000 } , /* R44 - Input Mixer6 */
{ 45 , 0x0000 } , /* R45 - Output Mixer1 */
{ 46 , 0x0000 } , /* R46 - Output Mixer2 */
{ 47 , 0x0000 } , /* R47 - Output Mixer3 */
{ 48 , 0x0000 } , /* R48 - Output Mixer4 */
{ 49 , 0x0000 } , /* R49 - Output Mixer5 */
{ 50 , 0x0000 } , /* R50 - Output Mixer6 */
{ 51 , 0x0180 } , /* R51 - Out3/4 Mixer */
{ 52 , 0x0000 } , /* R52 - Line Mixer1 */
{ 53 , 0x0000 } , /* R53 - Line Mixer2 */
{ 54 , 0x0000 } , /* R54 - Speaker Mixer */
{ 55 , 0x0000 } , /* R55 - Additional Control */
{ 56 , 0x0000 } , /* R56 - AntiPOP1 */
{ 57 , 0x0000 } , /* R57 - AntiPOP2 */
{ 58 , 0x0000 } , /* R58 - MICBIAS */
{ 60 , 0x0008 } , /* R60 - PLL1 */
{ 61 , 0x0031 } , /* R61 - PLL2 */
{ 62 , 0x0026 } , /* R62 - PLL3 */
2011-01-14 18:49:40 +03:00
} ;
2013-11-22 17:28:55 +04:00
static bool wm8991_volatile ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case WM8991_RESET :
return true ;
default :
return false ;
}
}
ASoC: wm8991: fix wrong usage of DECLARE_TLV_DB_LINEAR()
As long as reading datasheet of WM8991, this driver includes wrong usage
of DECLARE_TLV_DB_LINEAR().
In "Table 6 Input PGA Volume Range", volume is represented in 5 bits by
1.5 dB/step between -16.5/30.0 dB. Thus, 'in_pga_tlv' should be dB step
representation.
In "Table 34 LOMIX and ROMIX Volume Range", volume is represented in three
bits by -3 dB/step from 0 to -21 dB. Thus, 'out_mix_tlv' should be dB step
represenation.
In "Table 36 LOPGA, ROPGA, LOUT, ROUT and SPKVOL Volume Range", volume is
represented in 7 bits by 1 dB/step from -73 to 6 dB, including mute. Thus,
'out_pga_tlv' should be dB step representation.
In "Table 26 Digital Volume Range", volume is represented in 8 bits by
3/8 dB/step from -71.625 to 0 dB. Thus, 'out_dac_tlv' should be dB step
representation.
In "Table 16 ADC Digital Volume Range", volume is represented in 8 bits by
3/8 dB/step from -71.625 to 17.625 dB. Thus, 'in_adc_tlv' should be dB step
representation.
In "Table 23 Digital Sidetone Volume", volume is represented in 5 bits by
3 dB/step from -36 to 0 dB. Thus, 'out_sidetone_tlv' should be dB step
representation.
In "Table 12 Left Input Mixer Volume Control", volume is represented in
3 bits by 3 dB/step from -12 to 6 dB
Totally, current implementation includes misuse of TLV-related macro.
This commit replaces usage of DECLARE_TLV_DB_LINEAR() with proper macros,
to give proper information to applications in user land.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-09-27 02:25:27 +03:00
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE ( in_pga_tlv , - 1650 , 150 , 0 ) ;
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE ( out_mix_tlv , - 2100 , 300 , 0 ) ;
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE ( out_pga_tlv ,
0x00 , 0x2f , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( SNDRV_CTL_TLVD_DB_GAIN_MUTE , 0 , 1 ) ,
0x30 , 0x7f , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( - 7300 , 100 , 0 ) ,
) ;
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE ( out_dac_tlv ,
0x00 , 0xbf , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( - 71625 , 375 , 1 ) ,
0xc0 , 0xff , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( 0 , 0 , 0 ) ,
) ;
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE ( in_adc_tlv ,
0x00 , 0xef , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( - 71625 , 375 , 1 ) ,
0xf0 , 0xff , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( 17625 , 0 , 0 ) ,
) ;
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE ( out_sidetone_tlv ,
0x00 , 0x0c , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( - 3600 , 300 , 0 ) ,
0x0d , 0x0f , SNDRV_CTL_TLVD_DB_SCALE_ITEM ( 0 , 0 , 0 ) ,
) ;
2011-01-14 18:49:40 +03:00
static int wm899x_outpga_put_volsw_vu ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2014-03-18 12:02:04 +04:00
struct snd_soc_codec * codec = snd_soc_kcontrol_codec ( kcontrol ) ;
2011-01-14 18:49:40 +03:00
int reg = kcontrol - > private_value & 0xff ;
int ret ;
u16 val ;
ret = snd_soc_put_volsw ( kcontrol , ucontrol ) ;
if ( ret < 0 )
return ret ;
/* now hit the volume update bits (always bit 8) */
val = snd_soc_read ( codec , reg ) ;
return snd_soc_write ( codec , reg , val | 0x0100 ) ;
}
static const char * wm8991_digital_sidetone [ ] =
{ " None " , " Left ADC " , " Right ADC " , " Reserved " } ;
2014-02-18 12:44:23 +04:00
static SOC_ENUM_SINGLE_DECL ( wm8991_left_digital_sidetone_enum ,
WM8991_DIGITAL_SIDE_TONE ,
WM8991_ADC_TO_DACL_SHIFT ,
wm8991_digital_sidetone ) ;
static SOC_ENUM_SINGLE_DECL ( wm8991_right_digital_sidetone_enum ,
WM8991_DIGITAL_SIDE_TONE ,
WM8991_ADC_TO_DACR_SHIFT ,
wm8991_digital_sidetone ) ;
2011-01-14 18:49:40 +03:00
static const char * wm8991_adcmode [ ] =
{ " Hi-fi mode " , " Voice mode 1 " , " Voice mode 2 " , " Voice mode 3 " } ;
2014-02-18 12:44:23 +04:00
static SOC_ENUM_SINGLE_DECL ( wm8991_right_adcmode_enum ,
WM8991_ADC_CTRL ,
WM8991_ADC_HPF_CUT_SHIFT ,
wm8991_adcmode ) ;
2011-01-14 18:49:40 +03:00
static const struct snd_kcontrol_new wm8991_snd_controls [ ] = {
/* INMIXL */
SOC_SINGLE ( " LIN12 PGA Boost " , WM8991_INPUT_MIXER3 , WM8991_L12MNBST_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LIN34 PGA Boost " , WM8991_INPUT_MIXER3 , WM8991_L34MNBST_BIT , 1 , 0 ) ,
/* INMIXR */
SOC_SINGLE ( " RIN12 PGA Boost " , WM8991_INPUT_MIXER3 , WM8991_R12MNBST_BIT , 1 , 0 ) ,
SOC_SINGLE ( " RIN34 PGA Boost " , WM8991_INPUT_MIXER3 , WM8991_R34MNBST_BIT , 1 , 0 ) ,
/* LOMIX */
SOC_SINGLE_TLV ( " LOMIX LIN3 Bypass Volume " , WM8991_OUTPUT_MIXER3 ,
WM8991_LLI3LOVOL_SHIFT , WM8991_LLI3LOVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " LOMIX RIN12 PGA Bypass Volume " , WM8991_OUTPUT_MIXER3 ,
WM8991_LR12LOVOL_SHIFT , WM8991_LR12LOVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " LOMIX LIN12 PGA Bypass Volume " , WM8991_OUTPUT_MIXER3 ,
WM8991_LL12LOVOL_SHIFT , WM8991_LL12LOVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " LOMIX RIN3 Bypass Volume " , WM8991_OUTPUT_MIXER5 ,
WM8991_LRI3LOVOL_SHIFT , WM8991_LRI3LOVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " LOMIX AINRMUX Bypass Volume " , WM8991_OUTPUT_MIXER5 ,
WM8991_LRBLOVOL_SHIFT , WM8991_LRBLOVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " LOMIX AINLMUX Bypass Volume " , WM8991_OUTPUT_MIXER5 ,
WM8991_LRBLOVOL_SHIFT , WM8991_LRBLOVOL_MASK , 1 , out_mix_tlv ) ,
/* ROMIX */
SOC_SINGLE_TLV ( " ROMIX RIN3 Bypass Volume " , WM8991_OUTPUT_MIXER4 ,
WM8991_RRI3ROVOL_SHIFT , WM8991_RRI3ROVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " ROMIX LIN12 PGA Bypass Volume " , WM8991_OUTPUT_MIXER4 ,
WM8991_RL12ROVOL_SHIFT , WM8991_RL12ROVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " ROMIX RIN12 PGA Bypass Volume " , WM8991_OUTPUT_MIXER4 ,
WM8991_RR12ROVOL_SHIFT , WM8991_RR12ROVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " ROMIX LIN3 Bypass Volume " , WM8991_OUTPUT_MIXER6 ,
WM8991_RLI3ROVOL_SHIFT , WM8991_RLI3ROVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " ROMIX AINLMUX Bypass Volume " , WM8991_OUTPUT_MIXER6 ,
WM8991_RLBROVOL_SHIFT , WM8991_RLBROVOL_MASK , 1 , out_mix_tlv ) ,
SOC_SINGLE_TLV ( " ROMIX AINRMUX Bypass Volume " , WM8991_OUTPUT_MIXER6 ,
WM8991_RRBROVOL_SHIFT , WM8991_RRBROVOL_MASK , 1 , out_mix_tlv ) ,
/* LOUT */
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " LOUT Volume " , WM8991_LEFT_OUTPUT_VOLUME ,
WM8991_LOUTVOL_SHIFT , WM8991_LOUTVOL_MASK , 0 , out_pga_tlv ) ,
SOC_SINGLE ( " LOUT ZC " , WM8991_LEFT_OUTPUT_VOLUME , WM8991_LOZC_BIT , 1 , 0 ) ,
/* ROUT */
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " ROUT Volume " , WM8991_RIGHT_OUTPUT_VOLUME ,
WM8991_ROUTVOL_SHIFT , WM8991_ROUTVOL_MASK , 0 , out_pga_tlv ) ,
SOC_SINGLE ( " ROUT ZC " , WM8991_RIGHT_OUTPUT_VOLUME , WM8991_ROZC_BIT , 1 , 0 ) ,
/* LOPGA */
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " LOPGA Volume " , WM8991_LEFT_OPGA_VOLUME ,
WM8991_LOPGAVOL_SHIFT , WM8991_LOPGAVOL_MASK , 0 , out_pga_tlv ) ,
SOC_SINGLE ( " LOPGA ZC Switch " , WM8991_LEFT_OPGA_VOLUME ,
WM8991_LOPGAZC_BIT , 1 , 0 ) ,
/* ROPGA */
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " ROPGA Volume " , WM8991_RIGHT_OPGA_VOLUME ,
WM8991_ROPGAVOL_SHIFT , WM8991_ROPGAVOL_MASK , 0 , out_pga_tlv ) ,
SOC_SINGLE ( " ROPGA ZC Switch " , WM8991_RIGHT_OPGA_VOLUME ,
WM8991_ROPGAZC_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LON Mute Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_LONMUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LOP Mute Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_LOPMUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LOP Attenuation Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_LOATTN_BIT , 1 , 0 ) ,
SOC_SINGLE ( " RON Mute Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_RONMUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " ROP Mute Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_ROPMUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " ROP Attenuation Switch " , WM8991_LINE_OUTPUTS_VOLUME ,
WM8991_ROATTN_BIT , 1 , 0 ) ,
SOC_SINGLE ( " OUT3 Mute Switch " , WM8991_OUT3_4_VOLUME ,
WM8991_OUT3MUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " OUT3 Attenuation Switch " , WM8991_OUT3_4_VOLUME ,
WM8991_OUT3ATTN_BIT , 1 , 0 ) ,
SOC_SINGLE ( " OUT4 Mute Switch " , WM8991_OUT3_4_VOLUME ,
WM8991_OUT4MUTE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " OUT4 Attenuation Switch " , WM8991_OUT3_4_VOLUME ,
WM8991_OUT4ATTN_BIT , 1 , 0 ) ,
SOC_SINGLE ( " Speaker Mode Switch " , WM8991_CLASSD1 ,
WM8991_CDMODE_BIT , 1 , 0 ) ,
SOC_SINGLE ( " Speaker Output Attenuation Volume " , WM8991_SPEAKER_VOLUME ,
WM8991_SPKVOL_SHIFT , WM8991_SPKVOL_MASK , 0 ) ,
SOC_SINGLE ( " Speaker DC Boost Volume " , WM8991_CLASSD3 ,
WM8991_DCGAIN_SHIFT , WM8991_DCGAIN_MASK , 0 ) ,
SOC_SINGLE ( " Speaker AC Boost Volume " , WM8991_CLASSD3 ,
WM8991_ACGAIN_SHIFT , WM8991_ACGAIN_MASK , 0 ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " Left DAC Digital Volume " ,
WM8991_LEFT_DAC_DIGITAL_VOLUME ,
WM8991_DACL_VOL_SHIFT ,
WM8991_DACL_VOL_MASK ,
0 ,
out_dac_tlv ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " Right DAC Digital Volume " ,
WM8991_RIGHT_DAC_DIGITAL_VOLUME ,
WM8991_DACR_VOL_SHIFT ,
WM8991_DACR_VOL_MASK ,
0 ,
out_dac_tlv ) ,
SOC_ENUM ( " Left Digital Sidetone " , wm8991_left_digital_sidetone_enum ) ,
SOC_ENUM ( " Right Digital Sidetone " , wm8991_right_digital_sidetone_enum ) ,
SOC_SINGLE_TLV ( " Left Digital Sidetone Volume " , WM8991_DIGITAL_SIDE_TONE ,
WM8991_ADCL_DAC_SVOL_SHIFT , WM8991_ADCL_DAC_SVOL_MASK , 0 ,
out_sidetone_tlv ) ,
SOC_SINGLE_TLV ( " Right Digital Sidetone Volume " , WM8991_DIGITAL_SIDE_TONE ,
WM8991_ADCR_DAC_SVOL_SHIFT , WM8991_ADCR_DAC_SVOL_MASK , 0 ,
out_sidetone_tlv ) ,
SOC_SINGLE ( " ADC Digital High Pass Filter Switch " , WM8991_ADC_CTRL ,
WM8991_ADC_HPF_ENA_BIT , 1 , 0 ) ,
SOC_ENUM ( " ADC HPF Mode " , wm8991_right_adcmode_enum ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " Left ADC Digital Volume " ,
WM8991_LEFT_ADC_DIGITAL_VOLUME ,
WM8991_ADCL_VOL_SHIFT ,
WM8991_ADCL_VOL_MASK ,
0 ,
in_adc_tlv ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " Right ADC Digital Volume " ,
WM8991_RIGHT_ADC_DIGITAL_VOLUME ,
WM8991_ADCR_VOL_SHIFT ,
WM8991_ADCR_VOL_MASK ,
0 ,
in_adc_tlv ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " LIN12 Volume " ,
WM8991_LEFT_LINE_INPUT_1_2_VOLUME ,
WM8991_LIN12VOL_SHIFT ,
WM8991_LIN12VOL_MASK ,
0 ,
in_pga_tlv ) ,
SOC_SINGLE ( " LIN12 ZC Switch " , WM8991_LEFT_LINE_INPUT_1_2_VOLUME ,
WM8991_LI12ZC_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LIN12 Mute Switch " , WM8991_LEFT_LINE_INPUT_1_2_VOLUME ,
WM8991_LI12MUTE_BIT , 1 , 0 ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " LIN34 Volume " ,
WM8991_LEFT_LINE_INPUT_3_4_VOLUME ,
WM8991_LIN34VOL_SHIFT ,
WM8991_LIN34VOL_MASK ,
0 ,
in_pga_tlv ) ,
SOC_SINGLE ( " LIN34 ZC Switch " , WM8991_LEFT_LINE_INPUT_3_4_VOLUME ,
WM8991_LI34ZC_BIT , 1 , 0 ) ,
SOC_SINGLE ( " LIN34 Mute Switch " , WM8991_LEFT_LINE_INPUT_3_4_VOLUME ,
WM8991_LI34MUTE_BIT , 1 , 0 ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " RIN12 Volume " ,
WM8991_RIGHT_LINE_INPUT_1_2_VOLUME ,
WM8991_RIN12VOL_SHIFT ,
WM8991_RIN12VOL_MASK ,
0 ,
in_pga_tlv ) ,
SOC_SINGLE ( " RIN12 ZC Switch " , WM8991_RIGHT_LINE_INPUT_1_2_VOLUME ,
WM8991_RI12ZC_BIT , 1 , 0 ) ,
SOC_SINGLE ( " RIN12 Mute Switch " , WM8991_RIGHT_LINE_INPUT_1_2_VOLUME ,
WM8991_RI12MUTE_BIT , 1 , 0 ) ,
SOC_WM899X_OUTPGA_SINGLE_R_TLV ( " RIN34 Volume " ,
WM8991_RIGHT_LINE_INPUT_3_4_VOLUME ,
WM8991_RIN34VOL_SHIFT ,
WM8991_RIN34VOL_MASK ,
0 ,
in_pga_tlv ) ,
SOC_SINGLE ( " RIN34 ZC Switch " , WM8991_RIGHT_LINE_INPUT_3_4_VOLUME ,
WM8991_RI34ZC_BIT , 1 , 0 ) ,
SOC_SINGLE ( " RIN34 Mute Switch " , WM8991_RIGHT_LINE_INPUT_3_4_VOLUME ,
WM8991_RI34MUTE_BIT , 1 , 0 ) ,
} ;
/*
* _DAPM_ Controls
*/
static int outmixer_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
2015-01-13 12:27:25 +03:00
struct snd_soc_codec * codec = snd_soc_dapm_to_codec ( w - > dapm ) ;
2011-01-14 18:49:40 +03:00
u32 reg_shift = kcontrol - > private_value & 0xfff ;
int ret = 0 ;
u16 reg ;
switch ( reg_shift ) {
case WM8991_SPEAKER_MIXER | ( WM8991_LDSPK_BIT < < 8 ) :
2015-01-13 12:27:25 +03:00
reg = snd_soc_read ( codec , WM8991_OUTPUT_MIXER1 ) ;
2011-01-14 18:49:40 +03:00
if ( reg & WM8991_LDLO ) {
printk ( KERN_WARNING
" Cannot set as Output Mixer 1 LDLO Set \n " ) ;
ret = - 1 ;
}
break ;
case WM8991_SPEAKER_MIXER | ( WM8991_RDSPK_BIT < < 8 ) :
2015-01-13 12:27:25 +03:00
reg = snd_soc_read ( codec , WM8991_OUTPUT_MIXER2 ) ;
2011-01-14 18:49:40 +03:00
if ( reg & WM8991_RDRO ) {
printk ( KERN_WARNING
" Cannot set as Output Mixer 2 RDRO Set \n " ) ;
ret = - 1 ;
}
break ;
case WM8991_OUTPUT_MIXER1 | ( WM8991_LDLO_BIT < < 8 ) :
2015-01-13 12:27:25 +03:00
reg = snd_soc_read ( codec , WM8991_SPEAKER_MIXER ) ;
2011-01-14 18:49:40 +03:00
if ( reg & WM8991_LDSPK ) {
printk ( KERN_WARNING
" Cannot set as Speaker Mixer LDSPK Set \n " ) ;
ret = - 1 ;
}
break ;
case WM8991_OUTPUT_MIXER2 | ( WM8991_RDRO_BIT < < 8 ) :
2015-01-13 12:27:25 +03:00
reg = snd_soc_read ( codec , WM8991_SPEAKER_MIXER ) ;
2011-01-14 18:49:40 +03:00
if ( reg & WM8991_RDSPK ) {
printk ( KERN_WARNING
" Cannot set as Speaker Mixer RDSPK Set \n " ) ;
ret = - 1 ;
}
break ;
}
return ret ;
}
/* INMIX dB values */
ASoC: wm8991: fix wrong usage of DECLARE_TLV_DB_LINEAR()
As long as reading datasheet of WM8991, this driver includes wrong usage
of DECLARE_TLV_DB_LINEAR().
In "Table 6 Input PGA Volume Range", volume is represented in 5 bits by
1.5 dB/step between -16.5/30.0 dB. Thus, 'in_pga_tlv' should be dB step
representation.
In "Table 34 LOMIX and ROMIX Volume Range", volume is represented in three
bits by -3 dB/step from 0 to -21 dB. Thus, 'out_mix_tlv' should be dB step
represenation.
In "Table 36 LOPGA, ROPGA, LOUT, ROUT and SPKVOL Volume Range", volume is
represented in 7 bits by 1 dB/step from -73 to 6 dB, including mute. Thus,
'out_pga_tlv' should be dB step representation.
In "Table 26 Digital Volume Range", volume is represented in 8 bits by
3/8 dB/step from -71.625 to 0 dB. Thus, 'out_dac_tlv' should be dB step
representation.
In "Table 16 ADC Digital Volume Range", volume is represented in 8 bits by
3/8 dB/step from -71.625 to 17.625 dB. Thus, 'in_adc_tlv' should be dB step
representation.
In "Table 23 Digital Sidetone Volume", volume is represented in 5 bits by
3 dB/step from -36 to 0 dB. Thus, 'out_sidetone_tlv' should be dB step
representation.
In "Table 12 Left Input Mixer Volume Control", volume is represented in
3 bits by 3 dB/step from -12 to 6 dB
Totally, current implementation includes misuse of TLV-related macro.
This commit replaces usage of DECLARE_TLV_DB_LINEAR() with proper macros,
to give proper information to applications in user land.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-09-27 02:25:27 +03:00
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE ( in_mix_tlv , - 1200 , 300 , 1 ) ;
2011-01-14 18:49:40 +03:00
/* Left In PGA Connections */
static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls [ ] = {
SOC_DAPM_SINGLE ( " LIN1 Switch " , WM8991_INPUT_MIXER2 , WM8991_LMN1_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LIN2 Switch " , WM8991_INPUT_MIXER2 , WM8991_LMP2_BIT , 1 , 0 ) ,
} ;
static const struct snd_kcontrol_new wm8991_dapm_lin34_pga_controls [ ] = {
SOC_DAPM_SINGLE ( " LIN3 Switch " , WM8991_INPUT_MIXER2 , WM8991_LMN3_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LIN4 Switch " , WM8991_INPUT_MIXER2 , WM8991_LMP4_BIT , 1 , 0 ) ,
} ;
/* Right In PGA Connections */
static const struct snd_kcontrol_new wm8991_dapm_rin12_pga_controls [ ] = {
SOC_DAPM_SINGLE ( " RIN1 Switch " , WM8991_INPUT_MIXER2 , WM8991_RMN1_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " RIN2 Switch " , WM8991_INPUT_MIXER2 , WM8991_RMP2_BIT , 1 , 0 ) ,
} ;
static const struct snd_kcontrol_new wm8991_dapm_rin34_pga_controls [ ] = {
SOC_DAPM_SINGLE ( " RIN3 Switch " , WM8991_INPUT_MIXER2 , WM8991_RMN3_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " RIN4 Switch " , WM8991_INPUT_MIXER2 , WM8991_RMP4_BIT , 1 , 0 ) ,
} ;
/* INMIXL */
static const struct snd_kcontrol_new wm8991_dapm_inmixl_controls [ ] = {
SOC_DAPM_SINGLE_TLV ( " Record Left Volume " , WM8991_INPUT_MIXER3 ,
WM8991_LDBVOL_SHIFT , WM8991_LDBVOL_MASK , 0 , in_mix_tlv ) ,
SOC_DAPM_SINGLE_TLV ( " LIN2 Volume " , WM8991_INPUT_MIXER5 , WM8991_LI2BVOL_SHIFT ,
7 , 0 , in_mix_tlv ) ,
SOC_DAPM_SINGLE ( " LINPGA12 Switch " , WM8991_INPUT_MIXER3 , WM8991_L12MNB_BIT ,
1 , 0 ) ,
SOC_DAPM_SINGLE ( " LINPGA34 Switch " , WM8991_INPUT_MIXER3 , WM8991_L34MNB_BIT ,
1 , 0 ) ,
} ;
/* INMIXR */
static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls [ ] = {
SOC_DAPM_SINGLE_TLV ( " Record Right Volume " , WM8991_INPUT_MIXER4 ,
WM8991_RDBVOL_SHIFT , WM8991_RDBVOL_MASK , 0 , in_mix_tlv ) ,
SOC_DAPM_SINGLE_TLV ( " RIN2 Volume " , WM8991_INPUT_MIXER6 , WM8991_RI2BVOL_SHIFT ,
7 , 0 , in_mix_tlv ) ,
SOC_DAPM_SINGLE ( " RINPGA12 Switch " , WM8991_INPUT_MIXER3 , WM8991_L12MNB_BIT ,
1 , 0 ) ,
SOC_DAPM_SINGLE ( " RINPGA34 Switch " , WM8991_INPUT_MIXER3 , WM8991_L34MNB_BIT ,
1 , 0 ) ,
} ;
/* AINLMUX */
static const char * wm8991_ainlmux [ ] =
{ " INMIXL Mix " , " RXVOICE Mix " , " DIFFINL Mix " } ;
2014-02-18 12:44:23 +04:00
static SOC_ENUM_SINGLE_DECL ( wm8991_ainlmux_enum ,
WM8991_INPUT_MIXER1 , WM8991_AINLMODE_SHIFT ,
wm8991_ainlmux ) ;
2011-01-14 18:49:40 +03:00
static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
SOC_DAPM_ENUM ( " Route " , wm8991_ainlmux_enum ) ;
/* DIFFINL */
/* AINRMUX */
static const char * wm8991_ainrmux [ ] =
{ " INMIXR Mix " , " RXVOICE Mix " , " DIFFINR Mix " } ;
2014-02-18 12:44:23 +04:00
static SOC_ENUM_SINGLE_DECL ( wm8991_ainrmux_enum ,
WM8991_INPUT_MIXER1 , WM8991_AINRMODE_SHIFT ,
wm8991_ainrmux ) ;
2011-01-14 18:49:40 +03:00
static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
SOC_DAPM_ENUM ( " Route " , wm8991_ainrmux_enum ) ;
/* RXVOICE */
static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls [ ] = {
SOC_DAPM_SINGLE_TLV ( " LIN4RXN " , WM8991_INPUT_MIXER5 , WM8991_LR4BVOL_SHIFT ,
WM8991_LR4BVOL_MASK , 0 , in_mix_tlv ) ,
SOC_DAPM_SINGLE_TLV ( " RIN4RXP " , WM8991_INPUT_MIXER6 , WM8991_RL4BVOL_SHIFT ,
WM8991_RL4BVOL_MASK , 0 , in_mix_tlv ) ,
} ;
/* LOMIX */
static const struct snd_kcontrol_new wm8991_dapm_lomix_controls [ ] = {
SOC_DAPM_SINGLE ( " LOMIX Right ADC Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LRBLO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX Left ADC Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LLBLO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX RIN3 Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LRI3LO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX LIN3 Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LLI3LO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX RIN12 PGA Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LR12LO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX LIN12 PGA Bypass Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LL12LO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOMIX Left DAC Switch " , WM8991_OUTPUT_MIXER1 ,
WM8991_LDLO_BIT , 1 , 0 ) ,
} ;
/* ROMIX */
static const struct snd_kcontrol_new wm8991_dapm_romix_controls [ ] = {
SOC_DAPM_SINGLE ( " ROMIX Left ADC Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RLBRO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX Right ADC Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RRBRO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX LIN3 Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RLI3RO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX RIN3 Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RRI3RO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX LIN12 PGA Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RL12RO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX RIN12 PGA Bypass Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RR12RO_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROMIX Right DAC Switch " , WM8991_OUTPUT_MIXER2 ,
WM8991_RDRO_BIT , 1 , 0 ) ,
} ;
/* LONMIX */
static const struct snd_kcontrol_new wm8991_dapm_lonmix_controls [ ] = {
SOC_DAPM_SINGLE ( " LONMIX Left Mixer PGA Switch " , WM8991_LINE_MIXER1 ,
WM8991_LLOPGALON_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LONMIX Right Mixer PGA Switch " , WM8991_LINE_MIXER1 ,
WM8991_LROPGALON_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LONMIX Inverted LOP Switch " , WM8991_LINE_MIXER1 ,
WM8991_LOPLON_BIT , 1 , 0 ) ,
} ;
/* LOPMIX */
static const struct snd_kcontrol_new wm8991_dapm_lopmix_controls [ ] = {
SOC_DAPM_SINGLE ( " LOPMIX Right Mic Bypass Switch " , WM8991_LINE_MIXER1 ,
WM8991_LR12LOP_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOPMIX Left Mic Bypass Switch " , WM8991_LINE_MIXER1 ,
WM8991_LL12LOP_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " LOPMIX Left Mixer PGA Switch " , WM8991_LINE_MIXER1 ,
WM8991_LLOPGALOP_BIT , 1 , 0 ) ,
} ;
/* RONMIX */
static const struct snd_kcontrol_new wm8991_dapm_ronmix_controls [ ] = {
SOC_DAPM_SINGLE ( " RONMIX Right Mixer PGA Switch " , WM8991_LINE_MIXER2 ,
WM8991_RROPGARON_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " RONMIX Left Mixer PGA Switch " , WM8991_LINE_MIXER2 ,
WM8991_RLOPGARON_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " RONMIX Inverted ROP Switch " , WM8991_LINE_MIXER2 ,
WM8991_ROPRON_BIT , 1 , 0 ) ,
} ;
/* ROPMIX */
static const struct snd_kcontrol_new wm8991_dapm_ropmix_controls [ ] = {
SOC_DAPM_SINGLE ( " ROPMIX Left Mic Bypass Switch " , WM8991_LINE_MIXER2 ,
WM8991_RL12ROP_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROPMIX Right Mic Bypass Switch " , WM8991_LINE_MIXER2 ,
WM8991_RR12ROP_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " ROPMIX Right Mixer PGA Switch " , WM8991_LINE_MIXER2 ,
WM8991_RROPGAROP_BIT , 1 , 0 ) ,
} ;
/* OUT3MIX */
static const struct snd_kcontrol_new wm8991_dapm_out3mix_controls [ ] = {
SOC_DAPM_SINGLE ( " OUT3MIX LIN4RXN Bypass Switch " , WM8991_OUT3_4_MIXER ,
WM8991_LI4O3_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " OUT3MIX Left Out PGA Switch " , WM8991_OUT3_4_MIXER ,
WM8991_LPGAO3_BIT , 1 , 0 ) ,
} ;
/* OUT4MIX */
static const struct snd_kcontrol_new wm8991_dapm_out4mix_controls [ ] = {
SOC_DAPM_SINGLE ( " OUT4MIX Right Out PGA Switch " , WM8991_OUT3_4_MIXER ,
WM8991_RPGAO4_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " OUT4MIX RIN4RXP Bypass Switch " , WM8991_OUT3_4_MIXER ,
WM8991_RI4O4_BIT , 1 , 0 ) ,
} ;
/* SPKMIX */
static const struct snd_kcontrol_new wm8991_dapm_spkmix_controls [ ] = {
SOC_DAPM_SINGLE ( " SPKMIX LIN2 Bypass Switch " , WM8991_SPEAKER_MIXER ,
WM8991_LI2SPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX LADC Bypass Switch " , WM8991_SPEAKER_MIXER ,
WM8991_LB2SPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX Left Mixer PGA Switch " , WM8991_SPEAKER_MIXER ,
WM8991_LOPGASPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX Left DAC Switch " , WM8991_SPEAKER_MIXER ,
WM8991_LDSPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX Right DAC Switch " , WM8991_SPEAKER_MIXER ,
WM8991_RDSPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX Right Mixer PGA Switch " , WM8991_SPEAKER_MIXER ,
WM8991_ROPGASPK_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX RADC Bypass Switch " , WM8991_SPEAKER_MIXER ,
WM8991_RL12ROP_BIT , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " SPKMIX RIN2 Bypass Switch " , WM8991_SPEAKER_MIXER ,
WM8991_RI2SPK_BIT , 1 , 0 ) ,
} ;
static const struct snd_soc_dapm_widget wm8991_dapm_widgets [ ] = {
/* Input Side */
/* Input Lines */
SND_SOC_DAPM_INPUT ( " LIN1 " ) ,
SND_SOC_DAPM_INPUT ( " LIN2 " ) ,
SND_SOC_DAPM_INPUT ( " LIN3 " ) ,
SND_SOC_DAPM_INPUT ( " LIN4RXN " ) ,
SND_SOC_DAPM_INPUT ( " RIN3 " ) ,
SND_SOC_DAPM_INPUT ( " RIN4RXP " ) ,
SND_SOC_DAPM_INPUT ( " RIN1 " ) ,
SND_SOC_DAPM_INPUT ( " RIN2 " ) ,
SND_SOC_DAPM_INPUT ( " Internal ADC Source " ) ,
2013-11-22 15:16:18 +04:00
SND_SOC_DAPM_SUPPLY ( " INL " , WM8991_POWER_MANAGEMENT_2 ,
WM8991_AINL_ENA_BIT , 0 , NULL , 0 ) ,
SND_SOC_DAPM_SUPPLY ( " INR " , WM8991_POWER_MANAGEMENT_2 ,
WM8991_AINR_ENA_BIT , 0 , NULL , 0 ) ,
2011-01-14 18:49:40 +03:00
/* DACs */
SND_SOC_DAPM_ADC ( " Left ADC " , " Left Capture " , WM8991_POWER_MANAGEMENT_2 ,
WM8991_ADCL_ENA_BIT , 0 ) ,
SND_SOC_DAPM_ADC ( " Right ADC " , " Right Capture " , WM8991_POWER_MANAGEMENT_2 ,
WM8991_ADCR_ENA_BIT , 0 ) ,
/* Input PGAs */
SND_SOC_DAPM_MIXER ( " LIN12 PGA " , WM8991_POWER_MANAGEMENT_2 , WM8991_LIN12_ENA_BIT ,
0 , & wm8991_dapm_lin12_pga_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_lin12_pga_controls ) ) ,
SND_SOC_DAPM_MIXER ( " LIN34 PGA " , WM8991_POWER_MANAGEMENT_2 , WM8991_LIN34_ENA_BIT ,
0 , & wm8991_dapm_lin34_pga_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_lin34_pga_controls ) ) ,
SND_SOC_DAPM_MIXER ( " RIN12 PGA " , WM8991_POWER_MANAGEMENT_2 , WM8991_RIN12_ENA_BIT ,
0 , & wm8991_dapm_rin12_pga_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_rin12_pga_controls ) ) ,
SND_SOC_DAPM_MIXER ( " RIN34 PGA " , WM8991_POWER_MANAGEMENT_2 , WM8991_RIN34_ENA_BIT ,
0 , & wm8991_dapm_rin34_pga_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_rin34_pga_controls ) ) ,
/* INMIXL */
2013-11-22 15:16:18 +04:00
SND_SOC_DAPM_MIXER ( " INMIXL " , SND_SOC_NOPM , 0 , 0 ,
2011-01-14 18:49:40 +03:00
& wm8991_dapm_inmixl_controls [ 0 ] ,
2013-11-22 15:16:18 +04:00
ARRAY_SIZE ( wm8991_dapm_inmixl_controls ) ) ,
2011-01-14 18:49:40 +03:00
/* AINLMUX */
2013-11-22 15:16:18 +04:00
SND_SOC_DAPM_MUX ( " AINLMUX " , SND_SOC_NOPM , 0 , 0 ,
& wm8991_dapm_ainlmux_controls ) ,
2011-01-14 18:49:40 +03:00
/* INMIXR */
2013-11-22 15:16:18 +04:00
SND_SOC_DAPM_MIXER ( " INMIXR " , SND_SOC_NOPM , 0 , 0 ,
2011-01-14 18:49:40 +03:00
& wm8991_dapm_inmixr_controls [ 0 ] ,
2013-11-22 15:16:18 +04:00
ARRAY_SIZE ( wm8991_dapm_inmixr_controls ) ) ,
2011-01-14 18:49:40 +03:00
/* AINRMUX */
2013-11-22 15:16:18 +04:00
SND_SOC_DAPM_MUX ( " AINRMUX " , SND_SOC_NOPM , 0 , 0 ,
& wm8991_dapm_ainrmux_controls ) ,
2011-01-14 18:49:40 +03:00
/* Output Side */
/* DACs */
SND_SOC_DAPM_DAC ( " Left DAC " , " Left Playback " , WM8991_POWER_MANAGEMENT_3 ,
WM8991_DACL_ENA_BIT , 0 ) ,
SND_SOC_DAPM_DAC ( " Right DAC " , " Right Playback " , WM8991_POWER_MANAGEMENT_3 ,
WM8991_DACR_ENA_BIT , 0 ) ,
/* LOMIX */
SND_SOC_DAPM_MIXER_E ( " LOMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_LOMIX_ENA_BIT ,
0 , & wm8991_dapm_lomix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_lomix_controls ) ,
outmixer_event , SND_SOC_DAPM_PRE_REG ) ,
/* LONMIX */
SND_SOC_DAPM_MIXER ( " LONMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_LON_ENA_BIT , 0 ,
& wm8991_dapm_lonmix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_lonmix_controls ) ) ,
/* LOPMIX */
SND_SOC_DAPM_MIXER ( " LOPMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_LOP_ENA_BIT , 0 ,
& wm8991_dapm_lopmix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_lopmix_controls ) ) ,
/* OUT3MIX */
SND_SOC_DAPM_MIXER ( " OUT3MIX " , WM8991_POWER_MANAGEMENT_1 , WM8991_OUT3_ENA_BIT , 0 ,
& wm8991_dapm_out3mix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_out3mix_controls ) ) ,
/* SPKMIX */
SND_SOC_DAPM_MIXER_E ( " SPKMIX " , WM8991_POWER_MANAGEMENT_1 , WM8991_SPK_ENA_BIT , 0 ,
& wm8991_dapm_spkmix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_spkmix_controls ) , outmixer_event ,
SND_SOC_DAPM_PRE_REG ) ,
/* OUT4MIX */
SND_SOC_DAPM_MIXER ( " OUT4MIX " , WM8991_POWER_MANAGEMENT_1 , WM8991_OUT4_ENA_BIT , 0 ,
& wm8991_dapm_out4mix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_out4mix_controls ) ) ,
/* ROPMIX */
SND_SOC_DAPM_MIXER ( " ROPMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_ROP_ENA_BIT , 0 ,
& wm8991_dapm_ropmix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_ropmix_controls ) ) ,
/* RONMIX */
SND_SOC_DAPM_MIXER ( " RONMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_RON_ENA_BIT , 0 ,
& wm8991_dapm_ronmix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_ronmix_controls ) ) ,
/* ROMIX */
SND_SOC_DAPM_MIXER_E ( " ROMIX " , WM8991_POWER_MANAGEMENT_3 , WM8991_ROMIX_ENA_BIT ,
0 , & wm8991_dapm_romix_controls [ 0 ] ,
ARRAY_SIZE ( wm8991_dapm_romix_controls ) ,
outmixer_event , SND_SOC_DAPM_PRE_REG ) ,
/* LOUT PGA */
SND_SOC_DAPM_PGA ( " LOUT PGA " , WM8991_POWER_MANAGEMENT_1 , WM8991_LOUT_ENA_BIT , 0 ,
NULL , 0 ) ,
/* ROUT PGA */
SND_SOC_DAPM_PGA ( " ROUT PGA " , WM8991_POWER_MANAGEMENT_1 , WM8991_ROUT_ENA_BIT , 0 ,
NULL , 0 ) ,
/* LOPGA */
SND_SOC_DAPM_PGA ( " LOPGA " , WM8991_POWER_MANAGEMENT_3 , WM8991_LOPGA_ENA_BIT , 0 ,
NULL , 0 ) ,
/* ROPGA */
SND_SOC_DAPM_PGA ( " ROPGA " , WM8991_POWER_MANAGEMENT_3 , WM8991_ROPGA_ENA_BIT , 0 ,
NULL , 0 ) ,
/* MICBIAS */
2011-10-27 11:48:39 +04:00
SND_SOC_DAPM_SUPPLY ( " MICBIAS " , WM8991_POWER_MANAGEMENT_1 ,
WM8991_MICBIAS_ENA_BIT , 0 , NULL , 0 ) ,
2011-01-14 18:49:40 +03:00
SND_SOC_DAPM_OUTPUT ( " LON " ) ,
SND_SOC_DAPM_OUTPUT ( " LOP " ) ,
SND_SOC_DAPM_OUTPUT ( " OUT3 " ) ,
SND_SOC_DAPM_OUTPUT ( " LOUT " ) ,
SND_SOC_DAPM_OUTPUT ( " SPKN " ) ,
SND_SOC_DAPM_OUTPUT ( " SPKP " ) ,
SND_SOC_DAPM_OUTPUT ( " ROUT " ) ,
SND_SOC_DAPM_OUTPUT ( " OUT4 " ) ,
SND_SOC_DAPM_OUTPUT ( " ROP " ) ,
SND_SOC_DAPM_OUTPUT ( " RON " ) ,
SND_SOC_DAPM_OUTPUT ( " OUT " ) ,
SND_SOC_DAPM_OUTPUT ( " Internal DAC Sink " ) ,
} ;
2013-11-22 16:28:06 +04:00
static const struct snd_soc_dapm_route wm8991_dapm_routes [ ] = {
2011-01-14 18:49:40 +03:00
/* Make DACs turn on when playing even if not mixed into any outputs */
{ " Internal DAC Sink " , NULL , " Left DAC " } ,
{ " Internal DAC Sink " , NULL , " Right DAC " } ,
/* Make ADCs turn on when recording even if not mixed from any inputs */
{ " Left ADC " , NULL , " Internal ADC Source " } ,
{ " Right ADC " , NULL , " Internal ADC Source " } ,
/* Input Side */
2013-11-22 15:16:18 +04:00
{ " INMIXL " , NULL , " INL " } ,
{ " AINLMUX " , NULL , " INL " } ,
{ " INMIXR " , NULL , " INR " } ,
{ " AINRMUX " , NULL , " INR " } ,
2011-01-14 18:49:40 +03:00
/* LIN12 PGA */
{ " LIN12 PGA " , " LIN1 Switch " , " LIN1 " } ,
{ " LIN12 PGA " , " LIN2 Switch " , " LIN2 " } ,
/* LIN34 PGA */
{ " LIN34 PGA " , " LIN3 Switch " , " LIN3 " } ,
{ " LIN34 PGA " , " LIN4 Switch " , " LIN4RXN " } ,
/* INMIXL */
{ " INMIXL " , " Record Left Volume " , " LOMIX " } ,
{ " INMIXL " , " LIN2 Volume " , " LIN2 " } ,
{ " INMIXL " , " LINPGA12 Switch " , " LIN12 PGA " } ,
{ " INMIXL " , " LINPGA34 Switch " , " LIN34 PGA " } ,
/* AINLMUX */
{ " AINLMUX " , " INMIXL Mix " , " INMIXL " } ,
{ " AINLMUX " , " DIFFINL Mix " , " LIN12 PGA " } ,
{ " AINLMUX " , " DIFFINL Mix " , " LIN34 PGA " } ,
{ " AINLMUX " , " RXVOICE Mix " , " LIN4RXN " } ,
{ " AINLMUX " , " RXVOICE Mix " , " RIN4RXP " } ,
/* ADC */
{ " Left ADC " , NULL , " AINLMUX " } ,
/* RIN12 PGA */
{ " RIN12 PGA " , " RIN1 Switch " , " RIN1 " } ,
{ " RIN12 PGA " , " RIN2 Switch " , " RIN2 " } ,
/* RIN34 PGA */
{ " RIN34 PGA " , " RIN3 Switch " , " RIN3 " } ,
{ " RIN34 PGA " , " RIN4 Switch " , " RIN4RXP " } ,
/* INMIXL */
{ " INMIXR " , " Record Right Volume " , " ROMIX " } ,
{ " INMIXR " , " RIN2 Volume " , " RIN2 " } ,
{ " INMIXR " , " RINPGA12 Switch " , " RIN12 PGA " } ,
{ " INMIXR " , " RINPGA34 Switch " , " RIN34 PGA " } ,
/* AINRMUX */
{ " AINRMUX " , " INMIXR Mix " , " INMIXR " } ,
{ " AINRMUX " , " DIFFINR Mix " , " RIN12 PGA " } ,
{ " AINRMUX " , " DIFFINR Mix " , " RIN34 PGA " } ,
{ " AINRMUX " , " RXVOICE Mix " , " LIN4RXN " } ,
{ " AINRMUX " , " RXVOICE Mix " , " RIN4RXP " } ,
/* ADC */
{ " Right ADC " , NULL , " AINRMUX " } ,
/* LOMIX */
{ " LOMIX " , " LOMIX RIN3 Bypass Switch " , " RIN3 " } ,
{ " LOMIX " , " LOMIX LIN3 Bypass Switch " , " LIN3 " } ,
{ " LOMIX " , " LOMIX LIN12 PGA Bypass Switch " , " LIN12 PGA " } ,
{ " LOMIX " , " LOMIX RIN12 PGA Bypass Switch " , " RIN12 PGA " } ,
{ " LOMIX " , " LOMIX Right ADC Bypass Switch " , " AINRMUX " } ,
{ " LOMIX " , " LOMIX Left ADC Bypass Switch " , " AINLMUX " } ,
{ " LOMIX " , " LOMIX Left DAC Switch " , " Left DAC " } ,
/* ROMIX */
{ " ROMIX " , " ROMIX RIN3 Bypass Switch " , " RIN3 " } ,
{ " ROMIX " , " ROMIX LIN3 Bypass Switch " , " LIN3 " } ,
{ " ROMIX " , " ROMIX LIN12 PGA Bypass Switch " , " LIN12 PGA " } ,
{ " ROMIX " , " ROMIX RIN12 PGA Bypass Switch " , " RIN12 PGA " } ,
{ " ROMIX " , " ROMIX Right ADC Bypass Switch " , " AINRMUX " } ,
{ " ROMIX " , " ROMIX Left ADC Bypass Switch " , " AINLMUX " } ,
{ " ROMIX " , " ROMIX Right DAC Switch " , " Right DAC " } ,
/* SPKMIX */
{ " SPKMIX " , " SPKMIX LIN2 Bypass Switch " , " LIN2 " } ,
{ " SPKMIX " , " SPKMIX RIN2 Bypass Switch " , " RIN2 " } ,
{ " SPKMIX " , " SPKMIX LADC Bypass Switch " , " AINLMUX " } ,
{ " SPKMIX " , " SPKMIX RADC Bypass Switch " , " AINRMUX " } ,
{ " SPKMIX " , " SPKMIX Left Mixer PGA Switch " , " LOPGA " } ,
{ " SPKMIX " , " SPKMIX Right Mixer PGA Switch " , " ROPGA " } ,
{ " SPKMIX " , " SPKMIX Right DAC Switch " , " Right DAC " } ,
{ " SPKMIX " , " SPKMIX Left DAC Switch " , " Right DAC " } ,
/* LONMIX */
{ " LONMIX " , " LONMIX Left Mixer PGA Switch " , " LOPGA " } ,
{ " LONMIX " , " LONMIX Right Mixer PGA Switch " , " ROPGA " } ,
{ " LONMIX " , " LONMIX Inverted LOP Switch " , " LOPMIX " } ,
/* LOPMIX */
{ " LOPMIX " , " LOPMIX Right Mic Bypass Switch " , " RIN12 PGA " } ,
{ " LOPMIX " , " LOPMIX Left Mic Bypass Switch " , " LIN12 PGA " } ,
{ " LOPMIX " , " LOPMIX Left Mixer PGA Switch " , " LOPGA " } ,
/* OUT3MIX */
{ " OUT3MIX " , " OUT3MIX LIN4RXN Bypass Switch " , " LIN4RXN " } ,
{ " OUT3MIX " , " OUT3MIX Left Out PGA Switch " , " LOPGA " } ,
/* OUT4MIX */
{ " OUT4MIX " , " OUT4MIX Right Out PGA Switch " , " ROPGA " } ,
{ " OUT4MIX " , " OUT4MIX RIN4RXP Bypass Switch " , " RIN4RXP " } ,
/* RONMIX */
{ " RONMIX " , " RONMIX Right Mixer PGA Switch " , " ROPGA " } ,
{ " RONMIX " , " RONMIX Left Mixer PGA Switch " , " LOPGA " } ,
{ " RONMIX " , " RONMIX Inverted ROP Switch " , " ROPMIX " } ,
/* ROPMIX */
{ " ROPMIX " , " ROPMIX Left Mic Bypass Switch " , " LIN12 PGA " } ,
{ " ROPMIX " , " ROPMIX Right Mic Bypass Switch " , " RIN12 PGA " } ,
{ " ROPMIX " , " ROPMIX Right Mixer PGA Switch " , " ROPGA " } ,
/* Out Mixer PGAs */
{ " LOPGA " , NULL , " LOMIX " } ,
{ " ROPGA " , NULL , " ROMIX " } ,
{ " LOUT PGA " , NULL , " LOMIX " } ,
{ " ROUT PGA " , NULL , " ROMIX " } ,
/* Output Pins */
{ " LON " , NULL , " LONMIX " } ,
{ " LOP " , NULL , " LOPMIX " } ,
{ " OUT " , NULL , " OUT3MIX " } ,
{ " LOUT " , NULL , " LOUT PGA " } ,
{ " SPKN " , NULL , " SPKMIX " } ,
{ " ROUT " , NULL , " ROUT PGA " } ,
{ " OUT4 " , NULL , " OUT4MIX " } ,
{ " ROP " , NULL , " ROPMIX " } ,
{ " RON " , NULL , " RONMIX " } ,
} ;
/* PLL divisors */
struct _pll_div {
u32 div2 ;
u32 n ;
u32 k ;
} ;
/* The size in bits of the pll divide multiplied by 10
* to allow rounding later */
# define FIXED_PLL_SIZE ((1 << 16) * 10)
static void pll_factors ( struct _pll_div * pll_div , unsigned int target ,
unsigned int source )
{
u64 Kpart ;
unsigned int K , Ndiv , Nmod ;
Ndiv = target / source ;
if ( Ndiv < 6 ) {
source > > = 1 ;
pll_div - > div2 = 1 ;
Ndiv = target / source ;
} else
pll_div - > div2 = 0 ;
if ( ( Ndiv < 6 ) | | ( Ndiv > 12 ) )
printk ( KERN_WARNING
" WM8991 N value outwith recommended range! N = %d \n " , Ndiv ) ;
pll_div - > n = Ndiv ;
Nmod = target % source ;
Kpart = FIXED_PLL_SIZE * ( long long ) Nmod ;
do_div ( Kpart , source ) ;
K = Kpart & 0xFFFFFFFF ;
/* Check if we need to round */
if ( ( K % 10 ) > = 5 )
K + = 5 ;
/* Move down to proper range now rounding is done */
K / = 10 ;
pll_div - > k = K ;
}
static int wm8991_set_dai_pll ( struct snd_soc_dai * codec_dai ,
int pll_id , int src , unsigned int freq_in , unsigned int freq_out )
{
u16 reg ;
struct snd_soc_codec * codec = codec_dai - > codec ;
struct _pll_div pll_div ;
if ( freq_in & & freq_out ) {
pll_factors ( & pll_div , freq_out * 4 , freq_in ) ;
/* Turn on PLL */
reg = snd_soc_read ( codec , WM8991_POWER_MANAGEMENT_2 ) ;
reg | = WM8991_PLL_ENA ;
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_2 , reg ) ;
/* sysclk comes from PLL */
reg = snd_soc_read ( codec , WM8991_CLOCKING_2 ) ;
snd_soc_write ( codec , WM8991_CLOCKING_2 , reg | WM8991_SYSCLK_SRC ) ;
2011-03-31 05:57:33 +04:00
/* set up N , fractional mode and pre-divisor if necessary */
2011-01-14 18:49:40 +03:00
snd_soc_write ( codec , WM8991_PLL1 , pll_div . n | WM8991_SDM |
( pll_div . div2 ? WM8991_PRESCALE : 0 ) ) ;
snd_soc_write ( codec , WM8991_PLL2 , ( u8 ) ( pll_div . k > > 8 ) ) ;
snd_soc_write ( codec , WM8991_PLL3 , ( u8 ) ( pll_div . k & 0xFF ) ) ;
} else {
/* Turn on PLL */
reg = snd_soc_read ( codec , WM8991_POWER_MANAGEMENT_2 ) ;
reg & = ~ WM8991_PLL_ENA ;
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_2 , reg ) ;
}
return 0 ;
}
/*
* Set ' s ADC and Voice DAC format .
*/
static int wm8991_set_dai_fmt ( struct snd_soc_dai * codec_dai ,
unsigned int fmt )
{
struct snd_soc_codec * codec = codec_dai - > codec ;
u16 audio1 , audio3 ;
audio1 = snd_soc_read ( codec , WM8991_AUDIO_INTERFACE_1 ) ;
audio3 = snd_soc_read ( codec , WM8991_AUDIO_INTERFACE_3 ) ;
/* set master/slave audio interface */
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
audio3 & = ~ WM8991_AIF_MSTR1 ;
break ;
case SND_SOC_DAIFMT_CBM_CFM :
audio3 | = WM8991_AIF_MSTR1 ;
break ;
default :
return - EINVAL ;
}
audio1 & = ~ WM8991_AIF_FMT_MASK ;
/* interface format */
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_I2S :
audio1 | = WM8991_AIF_TMF_I2S ;
audio1 & = ~ WM8991_AIF_LRCLK_INV ;
break ;
case SND_SOC_DAIFMT_RIGHT_J :
audio1 | = WM8991_AIF_TMF_RIGHTJ ;
audio1 & = ~ WM8991_AIF_LRCLK_INV ;
break ;
case SND_SOC_DAIFMT_LEFT_J :
audio1 | = WM8991_AIF_TMF_LEFTJ ;
audio1 & = ~ WM8991_AIF_LRCLK_INV ;
break ;
case SND_SOC_DAIFMT_DSP_A :
audio1 | = WM8991_AIF_TMF_DSP ;
audio1 & = ~ WM8991_AIF_LRCLK_INV ;
break ;
case SND_SOC_DAIFMT_DSP_B :
audio1 | = WM8991_AIF_TMF_DSP | WM8991_AIF_LRCLK_INV ;
break ;
default :
return - EINVAL ;
}
snd_soc_write ( codec , WM8991_AUDIO_INTERFACE_1 , audio1 ) ;
snd_soc_write ( codec , WM8991_AUDIO_INTERFACE_3 , audio3 ) ;
return 0 ;
}
static int wm8991_set_dai_clkdiv ( struct snd_soc_dai * codec_dai ,
int div_id , int div )
{
struct snd_soc_codec * codec = codec_dai - > codec ;
u16 reg ;
switch ( div_id ) {
case WM8991_MCLK_DIV :
reg = snd_soc_read ( codec , WM8991_CLOCKING_2 ) &
~ WM8991_MCLK_DIV_MASK ;
snd_soc_write ( codec , WM8991_CLOCKING_2 , reg | div ) ;
break ;
case WM8991_DACCLK_DIV :
reg = snd_soc_read ( codec , WM8991_CLOCKING_2 ) &
~ WM8991_DAC_CLKDIV_MASK ;
snd_soc_write ( codec , WM8991_CLOCKING_2 , reg | div ) ;
break ;
case WM8991_ADCCLK_DIV :
reg = snd_soc_read ( codec , WM8991_CLOCKING_2 ) &
~ WM8991_ADC_CLKDIV_MASK ;
snd_soc_write ( codec , WM8991_CLOCKING_2 , reg | div ) ;
break ;
case WM8991_BCLK_DIV :
reg = snd_soc_read ( codec , WM8991_CLOCKING_1 ) &
~ WM8991_BCLK_DIV_MASK ;
snd_soc_write ( codec , WM8991_CLOCKING_1 , reg | div ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/*
* Set PCM DAI bit size and sample rate .
*/
static int wm8991_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 ;
u16 audio1 = snd_soc_read ( codec , WM8991_AUDIO_INTERFACE_1 ) ;
audio1 & = ~ WM8991_AIF_WL_MASK ;
/* bit size */
2014-07-31 15:54:38 +04:00
switch ( params_width ( params ) ) {
case 16 :
2011-01-14 18:49:40 +03:00
break ;
2014-07-31 15:54:38 +04:00
case 20 :
2011-01-14 18:49:40 +03:00
audio1 | = WM8991_AIF_WL_20BITS ;
break ;
2014-07-31 15:54:38 +04:00
case 24 :
2011-01-14 18:49:40 +03:00
audio1 | = WM8991_AIF_WL_24BITS ;
break ;
2014-07-31 15:54:38 +04:00
case 32 :
2011-01-14 18:49:40 +03:00
audio1 | = WM8991_AIF_WL_32BITS ;
break ;
}
snd_soc_write ( codec , WM8991_AUDIO_INTERFACE_1 , audio1 ) ;
return 0 ;
}
static int wm8991_mute ( struct snd_soc_dai * dai , int mute )
{
struct snd_soc_codec * codec = dai - > codec ;
u16 val ;
val = snd_soc_read ( codec , WM8991_DAC_CTRL ) & ~ WM8991_DAC_MUTE ;
if ( mute )
snd_soc_write ( codec , WM8991_DAC_CTRL , val | WM8991_DAC_MUTE ) ;
else
snd_soc_write ( codec , WM8991_DAC_CTRL , val ) ;
return 0 ;
}
static int wm8991_set_bias_level ( struct snd_soc_codec * codec ,
enum snd_soc_bias_level level )
{
2013-11-22 17:28:55 +04:00
struct wm8991_priv * wm8991 = snd_soc_codec_get_drvdata ( codec ) ;
2011-01-14 18:49:40 +03:00
u16 val ;
switch ( level ) {
case SND_SOC_BIAS_ON :
break ;
case SND_SOC_BIAS_PREPARE :
/* VMID=2*50k */
val = snd_soc_read ( codec , WM8991_POWER_MANAGEMENT_1 ) &
~ WM8991_VMID_MODE_MASK ;
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , val | 0x2 ) ;
break ;
case SND_SOC_BIAS_STANDBY :
2015-06-01 11:10:58 +03:00
if ( snd_soc_codec_get_bias_level ( codec ) = = SND_SOC_BIAS_OFF ) {
2013-11-22 17:28:55 +04:00
regcache_sync ( wm8991 - > regmap ) ;
2011-01-14 18:49:40 +03:00
/* Enable all output discharge bits */
snd_soc_write ( codec , WM8991_ANTIPOP1 , WM8991_DIS_LLINE |
WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
WM8991_DIS_ROUT ) ;
/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_SOFTST |
WM8991_BUFDCOPEN | WM8991_POBCTRL |
WM8991_VMIDTOG ) ;
/* Delay to allow output caps to discharge */
msleep ( 300 ) ;
/* Disable VMIDTOG */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_SOFTST |
WM8991_BUFDCOPEN | WM8991_POBCTRL ) ;
/* disable all output discharge bits */
snd_soc_write ( codec , WM8991_ANTIPOP1 , 0 ) ;
/* Enable outputs */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x1b00 ) ;
msleep ( 50 ) ;
/* Enable VMID at 2x50k */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x1f02 ) ;
msleep ( 100 ) ;
/* Enable VREF */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x1f03 ) ;
msleep ( 600 ) ;
/* Enable BUFIOEN */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_SOFTST |
WM8991_BUFDCOPEN | WM8991_POBCTRL |
WM8991_BUFIOEN ) ;
/* Disable outputs */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x3 ) ;
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_BUFIOEN ) ;
}
/* VMID=2*250k */
val = snd_soc_read ( codec , WM8991_POWER_MANAGEMENT_1 ) &
~ WM8991_VMID_MODE_MASK ;
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , val | 0x4 ) ;
break ;
case SND_SOC_BIAS_OFF :
/* Enable POBCTRL and SOFT_ST */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_SOFTST |
WM8991_POBCTRL | WM8991_BUFIOEN ) ;
/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write ( codec , WM8991_ANTIPOP2 , WM8991_SOFTST |
WM8991_BUFDCOPEN | WM8991_POBCTRL |
WM8991_BUFIOEN ) ;
/* mute DAC */
val = snd_soc_read ( codec , WM8991_DAC_CTRL ) ;
snd_soc_write ( codec , WM8991_DAC_CTRL , val | WM8991_DAC_MUTE ) ;
/* Enable any disabled outputs */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x1f03 ) ;
/* Disable VMID */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x1f01 ) ;
msleep ( 300 ) ;
/* Enable all output discharge bits */
snd_soc_write ( codec , WM8991_ANTIPOP1 , WM8991_DIS_LLINE |
WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
WM8991_DIS_ROUT ) ;
/* Disable VREF */
snd_soc_write ( codec , WM8991_POWER_MANAGEMENT_1 , 0x0 ) ;
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write ( codec , WM8991_ANTIPOP2 , 0x0 ) ;
2013-11-22 17:28:55 +04:00
regcache_mark_dirty ( wm8991 - > regmap ) ;
2011-01-14 18:49:40 +03:00
break ;
}
return 0 ;
}
# define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE )
2011-11-23 14:40:40 +04:00
static const struct snd_soc_dai_ops wm8991_ops = {
2011-01-14 18:49:40 +03:00
. hw_params = wm8991_hw_params ,
. digital_mute = wm8991_mute ,
. set_fmt = wm8991_set_dai_fmt ,
. set_clkdiv = wm8991_set_dai_clkdiv ,
. set_pll = wm8991_set_dai_pll
} ;
/*
* The WM8991 supports 2 different and mutually exclusive DAI
* configurations .
*
* 1. ADC / DAC on Primary Interface
* 2. ADC on Primary Interface / DAC on secondary
*/
static struct snd_soc_dai_driver wm8991_dai = {
/* ADC/DAC on primary */
. name = " wm8991 " ,
. id = 1 ,
. playback = {
. stream_name = " Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_96000 ,
. formats = WM8991_FORMATS
} ,
. capture = {
. stream_name = " Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_96000 ,
. formats = WM8991_FORMATS
} ,
. ops = & wm8991_ops
} ;
2016-09-01 00:52:27 +03:00
static const struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
2011-01-14 18:49:40 +03:00
. set_bias_level = wm8991_set_bias_level ,
2014-11-23 15:37:41 +03:00
. suspend_bias_off = true ,
2016-08-08 12:33:47 +03:00
. component_driver = {
. controls = wm8991_snd_controls ,
. num_controls = ARRAY_SIZE ( wm8991_snd_controls ) ,
. dapm_widgets = wm8991_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( wm8991_dapm_widgets ) ,
. dapm_routes = wm8991_dapm_routes ,
. num_dapm_routes = ARRAY_SIZE ( wm8991_dapm_routes ) ,
} ,
2013-11-22 17:28:55 +04:00
} ;
static const struct regmap_config wm8991_regmap = {
. reg_bits = 8 ,
. val_bits = 16 ,
. max_register = WM8991_PLL3 ,
. volatile_reg = wm8991_volatile ,
. reg_defaults = wm8991_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( wm8991_reg_defaults ) ,
. cache_type = REGCACHE_RBTREE ,
2011-01-14 18:49:40 +03:00
} ;
2012-12-07 18:26:37 +04:00
static int wm8991_i2c_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * id )
2011-01-14 18:49:40 +03:00
{
struct wm8991_priv * wm8991 ;
2013-11-22 17:34:48 +04:00
unsigned int val ;
2011-01-14 18:49:40 +03:00
int ret ;
2012-09-12 05:28:08 +04:00
wm8991 = devm_kzalloc ( & i2c - > dev , sizeof ( * wm8991 ) , GFP_KERNEL ) ;
2011-01-14 18:49:40 +03:00
if ( ! wm8991 )
return - ENOMEM ;
2013-11-22 17:28:55 +04:00
wm8991 - > regmap = devm_regmap_init_i2c ( i2c , & wm8991_regmap ) ;
if ( IS_ERR ( wm8991 - > regmap ) )
return PTR_ERR ( wm8991 - > regmap ) ;
2011-01-14 18:49:40 +03:00
i2c_set_clientdata ( i2c , wm8991 ) ;
2013-11-22 17:34:48 +04:00
ret = regmap_read ( wm8991 - > regmap , WM8991_RESET , & val ) ;
if ( ret ! = 0 ) {
dev_err ( & i2c - > dev , " Failed to read device ID: %d \n " , ret ) ;
return ret ;
}
if ( val ! = 0x8991 ) {
dev_err ( & i2c - > dev , " Device with ID %x is not a WM8991 \n " , val ) ;
return - EINVAL ;
}
2013-11-22 17:32:36 +04:00
ret = regmap_write ( wm8991 - > regmap , WM8991_RESET , 0 ) ;
if ( ret < 0 ) {
dev_err ( & i2c - > dev , " Failed to issue reset: %d \n " , ret ) ;
return ret ;
}
regmap_update_bits ( wm8991 - > regmap , WM8991_AUDIO_INTERFACE_4 ,
WM8991_ALRCGPIO1 , WM8991_ALRCGPIO1 ) ;
regmap_update_bits ( wm8991 - > regmap , WM8991_GPIO1_GPIO2 ,
WM8991_GPIO1_SEL_MASK , 1 ) ;
regmap_update_bits ( wm8991 - > regmap , WM8991_POWER_MANAGEMENT_1 ,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK ,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK ) ;
regmap_update_bits ( wm8991 - > regmap , WM8991_POWER_MANAGEMENT_2 ,
WM8991_OPCLK_ENA , WM8991_OPCLK_ENA ) ;
regmap_write ( wm8991 - > regmap , WM8991_DAC_CTRL , 0 ) ;
regmap_write ( wm8991 - > regmap , WM8991_LEFT_OUTPUT_VOLUME ,
0x50 | ( 1 < < 8 ) ) ;
regmap_write ( wm8991 - > regmap , WM8991_RIGHT_OUTPUT_VOLUME ,
0x50 | ( 1 < < 8 ) ) ;
2011-01-14 18:49:40 +03:00
ret = snd_soc_register_codec ( & i2c - > dev ,
& soc_codec_dev_wm8991 , & wm8991_dai , 1 ) ;
2012-09-12 05:28:08 +04:00
2011-01-14 18:49:40 +03:00
return ret ;
}
2012-12-07 18:26:37 +04:00
static int wm8991_i2c_remove ( struct i2c_client * client )
2011-01-14 18:49:40 +03:00
{
snd_soc_unregister_codec ( & client - > dev ) ;
2012-09-12 05:28:08 +04:00
2011-01-14 18:49:40 +03:00
return 0 ;
}
static const struct i2c_device_id wm8991_i2c_id [ ] = {
{ " wm8991 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , wm8991_i2c_id ) ;
static struct i2c_driver wm8991_i2c_driver = {
. driver = {
. name = " wm8991 " ,
} ,
. probe = wm8991_i2c_probe ,
2012-12-07 18:26:37 +04:00
. remove = wm8991_i2c_remove ,
2011-01-14 18:49:40 +03:00
. id_table = wm8991_i2c_id ,
} ;
2012-08-06 15:55:40 +04:00
module_i2c_driver ( wm8991_i2c_driver ) ;
2011-01-14 18:49:40 +03:00
MODULE_DESCRIPTION ( " ASoC WM8991 driver " ) ;
MODULE_AUTHOR ( " Graeme Gregory " ) ;
MODULE_LICENSE ( " GPL " ) ;