2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-06-19 00:08:44 +04:00
/*
* arizona . c - Wolfson Arizona class device shared support
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author : Mark Brown < broonie @ opensource . wolfsonmicro . com >
*/
2013-02-15 21:27:22 +04:00
# include <linux/delay.h>
2012-06-19 00:08:44 +04:00
# include <linux/gcd.h>
# include <linux/module.h>
2017-09-04 18:41:49 +03:00
# include <linux/of.h>
2012-06-19 00:08:44 +04:00
# include <linux/pm_runtime.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/tlv.h>
# include <linux/mfd/arizona/core.h>
# include <linux/mfd/arizona/registers.h>
# include "arizona.h"
# define ARIZONA_AIF_BCLK_CTRL 0x00
# define ARIZONA_AIF_TX_PIN_CTRL 0x01
# define ARIZONA_AIF_RX_PIN_CTRL 0x02
# define ARIZONA_AIF_RATE_CTRL 0x03
# define ARIZONA_AIF_FORMAT 0x04
# define ARIZONA_AIF_TX_BCLK_RATE 0x05
# define ARIZONA_AIF_RX_BCLK_RATE 0x06
# define ARIZONA_AIF_FRAME_CTRL_1 0x07
# define ARIZONA_AIF_FRAME_CTRL_2 0x08
# define ARIZONA_AIF_FRAME_CTRL_3 0x09
# define ARIZONA_AIF_FRAME_CTRL_4 0x0A
# define ARIZONA_AIF_FRAME_CTRL_5 0x0B
# define ARIZONA_AIF_FRAME_CTRL_6 0x0C
# define ARIZONA_AIF_FRAME_CTRL_7 0x0D
# define ARIZONA_AIF_FRAME_CTRL_8 0x0E
# define ARIZONA_AIF_FRAME_CTRL_9 0x0F
# define ARIZONA_AIF_FRAME_CTRL_10 0x10
# define ARIZONA_AIF_FRAME_CTRL_11 0x11
# define ARIZONA_AIF_FRAME_CTRL_12 0x12
# define ARIZONA_AIF_FRAME_CTRL_13 0x13
# define ARIZONA_AIF_FRAME_CTRL_14 0x14
# define ARIZONA_AIF_FRAME_CTRL_15 0x15
# define ARIZONA_AIF_FRAME_CTRL_16 0x16
# define ARIZONA_AIF_FRAME_CTRL_17 0x17
# define ARIZONA_AIF_FRAME_CTRL_18 0x18
# define ARIZONA_AIF_TX_ENABLES 0x19
# define ARIZONA_AIF_RX_ENABLES 0x1A
# define ARIZONA_AIF_FORCE_WRITE 0x1B
2014-03-07 20:34:25 +04:00
# define ARIZONA_FLL_VCO_CORNER 141900000
2014-03-07 20:34:18 +04:00
# define ARIZONA_FLL_MAX_FREF 13500000
# define ARIZONA_FLL_MIN_FVCO 90000000
2014-03-07 20:34:25 +04:00
# define ARIZONA_FLL_MAX_FRATIO 16
2014-03-07 20:34:18 +04:00
# define ARIZONA_FLL_MAX_REFDIV 8
# define ARIZONA_FLL_MIN_OUTDIV 2
# define ARIZONA_FLL_MAX_OUTDIV 7
2014-11-12 19:12:46 +03:00
# define ARIZONA_FMT_DSP_MODE_A 0
# define ARIZONA_FMT_DSP_MODE_B 1
# define ARIZONA_FMT_I2S_MODE 2
# define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
2012-06-19 00:08:44 +04:00
# define arizona_fll_err(_fll, fmt, ...) \
dev_err ( _fll - > arizona - > dev , " FLL%d: " fmt , _fll - > id , # # __VA_ARGS__ )
# define arizona_fll_warn(_fll, fmt, ...) \
dev_warn ( _fll - > arizona - > dev , " FLL%d: " fmt , _fll - > id , # # __VA_ARGS__ )
# define arizona_fll_dbg(_fll, fmt, ...) \
2013-02-06 21:58:57 +04:00
dev_dbg ( _fll - > arizona - > dev , " FLL%d: " fmt , _fll - > id , # # __VA_ARGS__ )
2012-06-19 00:08:44 +04:00
# define arizona_aif_err(_dai, fmt, ...) \
dev_err ( _dai - > dev , " AIF%d: " fmt , _dai - > id , # # __VA_ARGS__ )
# define arizona_aif_warn(_dai, fmt, ...) \
dev_warn ( _dai - > dev , " AIF%d: " fmt , _dai - > id , # # __VA_ARGS__ )
# define arizona_aif_dbg(_dai, fmt, ...) \
2013-02-06 21:58:57 +04:00
dev_dbg ( _dai - > dev , " AIF%d: " fmt , _dai - > id , # # __VA_ARGS__ )
2012-06-19 00:08:44 +04:00
2013-01-10 18:45:58 +04:00
static int arizona_spk_ev ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona * arizona = dev_get_drvdata ( component - > dev - > parent ) ;
2013-03-13 16:22:39 +04:00
int val ;
2013-01-10 18:45:58 +04:00
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
2020-06-16 08:20:33 +03:00
val = snd_soc_component_read ( component ,
2018-02-20 19:08:11 +03:00
ARIZONA_INTERRUPT_RAW_STATUS_3 ) ;
2014-07-15 14:21:47 +04:00
if ( val & ARIZONA_SPK_OVERHEAT_STS ) {
2013-03-13 16:22:39 +04:00
dev_crit ( arizona - > dev ,
" Speaker not enabled due to temperature \n " ) ;
return - EBUSY ;
}
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap ,
ARIZONA_OUTPUT_ENABLES_1 ,
1 < < w - > shift , 1 < < w - > shift ) ;
2013-01-10 18:45:58 +04:00
break ;
case SND_SOC_DAPM_PRE_PMD :
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap ,
ARIZONA_OUTPUT_ENABLES_1 ,
1 < < w - > shift , 0 ) ;
2013-01-10 18:45:58 +04:00
break ;
2015-09-16 15:59:40 +03:00
default :
break ;
2013-01-10 18:45:58 +04:00
}
2016-09-27 18:35:45 +03:00
return arizona_out_ev ( w , kcontrol , event ) ;
2013-01-10 18:45:58 +04:00
}
2013-03-13 16:32:10 +04:00
static irqreturn_t arizona_thermal_warn ( int irq , void * data )
{
struct arizona * arizona = data ;
unsigned int val ;
int ret ;
ret = regmap_read ( arizona - > regmap , ARIZONA_INTERRUPT_RAW_STATUS_3 ,
& val ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to read thermal status: %d \n " ,
ret ) ;
2014-07-15 14:21:47 +04:00
} else if ( val & ARIZONA_SPK_OVERHEAT_WARN_STS ) {
2013-03-13 16:32:10 +04:00
dev_crit ( arizona - > dev , " Thermal warning \n " ) ;
}
return IRQ_HANDLED ;
}
static irqreturn_t arizona_thermal_shutdown ( int irq , void * data )
{
struct arizona * arizona = data ;
unsigned int val ;
int ret ;
ret = regmap_read ( arizona - > regmap , ARIZONA_INTERRUPT_RAW_STATUS_3 ,
& val ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to read thermal status: %d \n " ,
ret ) ;
2014-07-15 14:21:47 +04:00
} else if ( val & ARIZONA_SPK_OVERHEAT_STS ) {
2013-03-13 16:32:10 +04:00
dev_crit ( arizona - > dev , " Thermal shutdown \n " ) ;
2013-03-13 16:22:39 +04:00
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_OUTPUT_ENABLES_1 ,
ARIZONA_OUT4L_ENA |
ARIZONA_OUT4R_ENA , 0 ) ;
if ( ret ! = 0 )
dev_crit ( arizona - > dev ,
" Failed to disable speaker outputs: %d \n " ,
ret ) ;
2013-03-13 16:32:10 +04:00
}
return IRQ_HANDLED ;
}
2013-01-10 18:45:58 +04:00
static const struct snd_soc_dapm_widget arizona_spkl =
2013-03-13 16:22:39 +04:00
SND_SOC_DAPM_PGA_E ( " OUT4L " , SND_SOC_NOPM ,
2013-01-10 18:45:58 +04:00
ARIZONA_OUT4L_ENA_SHIFT , 0 , NULL , 0 , arizona_spk_ev ,
2016-09-27 18:35:45 +03:00
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD ) ;
2013-01-10 18:45:58 +04:00
static const struct snd_soc_dapm_widget arizona_spkr =
2013-03-13 16:22:39 +04:00
SND_SOC_DAPM_PGA_E ( " OUT4R " , SND_SOC_NOPM ,
2013-01-10 18:45:58 +04:00
ARIZONA_OUT4R_ENA_SHIFT , 0 , NULL , 0 , arizona_spk_ev ,
2016-09-27 18:35:45 +03:00
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD ) ;
2013-01-10 18:45:58 +04:00
2018-02-13 05:03:12 +03:00
int arizona_init_spk ( struct snd_soc_component * component )
2013-01-10 18:45:58 +04:00
{
2018-02-13 05:03:12 +03:00
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-03-13 16:32:10 +04:00
struct arizona * arizona = priv - > arizona ;
2013-01-10 18:45:58 +04:00
int ret ;
2015-06-01 11:10:24 +03:00
ret = snd_soc_dapm_new_controls ( dapm , & arizona_spkl , 1 ) ;
2013-01-10 18:45:58 +04:00
if ( ret ! = 0 )
return ret ;
2013-08-13 02:46:55 +04:00
switch ( arizona - > type ) {
case WM8997 :
2016-04-08 18:50:14 +03:00
case CS47L24 :
case WM1831 :
2013-08-13 02:46:55 +04:00
break ;
default :
2015-06-01 11:10:24 +03:00
ret = snd_soc_dapm_new_controls ( dapm , & arizona_spkr , 1 ) ;
2013-08-13 02:46:55 +04:00
if ( ret ! = 0 )
return ret ;
break ;
}
2013-01-10 18:45:58 +04:00
2016-10-26 12:59:57 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_spk ) ;
int arizona_init_spk_irqs ( struct arizona * arizona )
{
int ret ;
2014-07-15 14:21:47 +04:00
ret = arizona_request_irq ( arizona , ARIZONA_IRQ_SPK_OVERHEAT_WARN ,
2013-03-13 16:32:10 +04:00
" Thermal warning " , arizona_thermal_warn ,
arizona ) ;
if ( ret ! = 0 )
dev_err ( arizona - > dev ,
" Failed to get thermal warning IRQ: %d \n " ,
ret ) ;
2014-07-15 14:21:47 +04:00
ret = arizona_request_irq ( arizona , ARIZONA_IRQ_SPK_OVERHEAT ,
2013-03-13 16:32:10 +04:00
" Thermal shutdown " , arizona_thermal_shutdown ,
arizona ) ;
if ( ret ! = 0 )
dev_err ( arizona - > dev ,
" Failed to get thermal shutdown IRQ: %d \n " ,
ret ) ;
2013-01-10 18:45:58 +04:00
return 0 ;
}
2016-10-26 12:59:57 +03:00
EXPORT_SYMBOL_GPL ( arizona_init_spk_irqs ) ;
2013-01-10 18:45:58 +04:00
2016-10-26 12:59:57 +03:00
int arizona_free_spk_irqs ( struct arizona * arizona )
2016-04-15 15:11:56 +03:00
{
arizona_free_irq ( arizona , ARIZONA_IRQ_SPK_OVERHEAT_WARN , arizona ) ;
arizona_free_irq ( arizona , ARIZONA_IRQ_SPK_OVERHEAT , arizona ) ;
return 0 ;
}
2016-10-26 12:59:57 +03:00
EXPORT_SYMBOL_GPL ( arizona_free_spk_irqs ) ;
2016-04-15 15:11:56 +03:00
2014-06-10 21:41:02 +04:00
static const struct snd_soc_dapm_route arizona_mono_routes [ ] = {
{ " OUT1R " , NULL , " OUT1L " } ,
{ " OUT2R " , NULL , " OUT2L " } ,
{ " OUT3R " , NULL , " OUT3L " } ,
{ " OUT4R " , NULL , " OUT4L " } ,
{ " OUT5R " , NULL , " OUT5L " } ,
{ " OUT6R " , NULL , " OUT6L " } ,
} ;
2018-02-13 05:03:12 +03:00
int arizona_init_mono ( struct snd_soc_component * component )
2014-06-10 21:41:02 +04:00
{
2018-02-13 05:03:12 +03:00
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2014-06-10 21:41:02 +04:00
struct arizona * arizona = priv - > arizona ;
int i ;
for ( i = 0 ; i < ARIZONA_MAX_OUTPUT ; + + i ) {
if ( arizona - > pdata . out_mono [ i ] )
2015-06-01 11:10:24 +03:00
snd_soc_dapm_add_routes ( dapm ,
2014-06-10 21:41:02 +04:00
& arizona_mono_routes [ i ] , 1 ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_mono ) ;
2018-02-13 05:03:12 +03:00
int arizona_init_gpio ( struct snd_soc_component * component )
2013-07-04 11:56:28 +04:00
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-07-04 11:56:28 +04:00
struct arizona * arizona = priv - > arizona ;
int i ;
switch ( arizona - > type ) {
case WM5110 :
2015-01-17 18:21:27 +03:00
case WM8280 :
2016-11-29 18:44:39 +03:00
snd_soc_component_disable_pin ( component ,
" DRC2 Signal Activity " ) ;
2013-07-04 19:53:03 +04:00
break ;
default :
break ;
2013-07-04 11:56:28 +04:00
}
2016-11-29 18:44:39 +03:00
snd_soc_component_disable_pin ( component , " DRC1 Signal Activity " ) ;
2013-07-04 11:56:28 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( arizona - > pdata . gpio_defaults ) ; i + + ) {
switch ( arizona - > pdata . gpio_defaults [ i ] & ARIZONA_GPN_FN_MASK ) {
case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT :
2016-11-29 18:44:39 +03:00
snd_soc_component_enable_pin ( component ,
" DRC1 Signal Activity " ) ;
2013-07-04 11:56:28 +04:00
break ;
case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT :
2016-11-29 18:44:39 +03:00
snd_soc_component_enable_pin ( component ,
" DRC2 Signal Activity " ) ;
2013-07-04 11:56:28 +04:00
break ;
default :
break ;
}
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_gpio ) ;
2017-09-04 18:41:48 +03:00
int arizona_init_common ( struct arizona * arizona )
2016-05-13 18:45:18 +03:00
{
2017-09-04 18:41:49 +03:00
struct arizona_pdata * pdata = & arizona - > pdata ;
unsigned int val , mask ;
int i ;
2016-05-13 18:45:18 +03:00
BLOCKING_INIT_NOTIFIER_HEAD ( & arizona - > notifier ) ;
2017-09-04 18:41:49 +03:00
for ( i = 0 ; i < ARIZONA_MAX_OUTPUT ; + + i ) {
/* Default is 0 so noop with defaults */
if ( pdata - > out_mono [ i ] )
val = ARIZONA_OUT1_MONO ;
else
val = 0 ;
regmap_update_bits ( arizona - > regmap ,
ARIZONA_OUTPUT_PATH_CONFIG_1L + ( i * 8 ) ,
ARIZONA_OUT1_MONO , val ) ;
}
for ( i = 0 ; i < ARIZONA_MAX_PDM_SPK ; i + + ) {
if ( pdata - > spk_mute [ i ] )
regmap_update_bits ( arizona - > regmap ,
ARIZONA_PDM_SPK1_CTRL_1 + ( i * 2 ) ,
ARIZONA_SPK1_MUTE_ENDIAN_MASK |
ARIZONA_SPK1_MUTE_SEQ1_MASK ,
pdata - > spk_mute [ i ] ) ;
if ( pdata - > spk_fmt [ i ] )
regmap_update_bits ( arizona - > regmap ,
ARIZONA_PDM_SPK1_CTRL_2 + ( i * 2 ) ,
ARIZONA_SPK1_FMT_MASK ,
pdata - > spk_fmt [ i ] ) ;
}
for ( i = 0 ; i < ARIZONA_MAX_INPUT ; i + + ) {
/* Default for both is 0 so noop with defaults */
val = pdata - > dmic_ref [ i ] < < ARIZONA_IN1_DMIC_SUP_SHIFT ;
if ( pdata - > inmode [ i ] & ARIZONA_INMODE_DMIC )
val | = 1 < < ARIZONA_IN1_MODE_SHIFT ;
switch ( arizona - > type ) {
case WM8998 :
case WM1814 :
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ADC_DIGITAL_VOLUME_1L + ( i * 8 ) ,
ARIZONA_IN1L_SRC_SE_MASK ,
( pdata - > inmode [ i ] & ARIZONA_INMODE_SE )
< < ARIZONA_IN1L_SRC_SE_SHIFT ) ;
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ADC_DIGITAL_VOLUME_1R + ( i * 8 ) ,
ARIZONA_IN1R_SRC_SE_MASK ,
( pdata - > inmode [ i ] & ARIZONA_INMODE_SE )
< < ARIZONA_IN1R_SRC_SE_SHIFT ) ;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK ;
break ;
default :
if ( pdata - > inmode [ i ] & ARIZONA_INMODE_SE )
val | = 1 < < ARIZONA_IN1_SINGLE_ENDED_SHIFT ;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK |
ARIZONA_IN1_SINGLE_ENDED_MASK ;
break ;
}
regmap_update_bits ( arizona - > regmap ,
ARIZONA_IN1L_CONTROL + ( i * 8 ) ,
mask , val ) ;
}
2016-05-13 18:45:18 +03:00
return 0 ;
}
2017-09-04 18:41:48 +03:00
EXPORT_SYMBOL_GPL ( arizona_init_common ) ;
2016-05-13 18:45:18 +03:00
2017-09-04 18:41:53 +03:00
int arizona_init_vol_limit ( struct arizona * arizona )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( arizona - > pdata . out_vol_limit ) ; + + i ) {
if ( arizona - > pdata . out_vol_limit [ i ] )
regmap_update_bits ( arizona - > regmap ,
ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4 ,
ARIZONA_OUT1L_VOL_LIM_MASK ,
arizona - > pdata . out_vol_limit [ i ] ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_vol_limit ) ;
2015-12-03 21:15:06 +03:00
const char * const arizona_mixer_texts [ ARIZONA_NUM_MIXER_INPUTS ] = {
2012-06-19 00:08:44 +04:00
" None " ,
" Tone Generator 1 " ,
" Tone Generator 2 " ,
" Haptics " ,
" AEC " ,
2015-09-28 16:01:09 +03:00
" AEC2 " ,
2012-06-19 00:08:44 +04:00
" Mic Mute Mixer " ,
" Noise Generator " ,
" IN1L " ,
" IN1R " ,
" IN2L " ,
" IN2R " ,
" IN3L " ,
" IN3R " ,
2012-07-09 22:09:01 +04:00
" IN4L " ,
" IN4R " ,
2012-06-19 00:08:44 +04:00
" AIF1RX1 " ,
" AIF1RX2 " ,
" AIF1RX3 " ,
" AIF1RX4 " ,
" AIF1RX5 " ,
" AIF1RX6 " ,
" AIF1RX7 " ,
" AIF1RX8 " ,
" AIF2RX1 " ,
" AIF2RX2 " ,
2013-11-20 17:17:07 +04:00
" AIF2RX3 " ,
" AIF2RX4 " ,
" AIF2RX5 " ,
" AIF2RX6 " ,
2012-06-19 00:08:44 +04:00
" AIF3RX1 " ,
" AIF3RX2 " ,
" SLIMRX1 " ,
" SLIMRX2 " ,
" SLIMRX3 " ,
" SLIMRX4 " ,
" SLIMRX5 " ,
" SLIMRX6 " ,
" SLIMRX7 " ,
" SLIMRX8 " ,
" EQ1 " ,
" EQ2 " ,
" EQ3 " ,
" EQ4 " ,
" DRC1L " ,
" DRC1R " ,
" DRC2L " ,
" DRC2R " ,
" LHPF1 " ,
" LHPF2 " ,
" LHPF3 " ,
" LHPF4 " ,
" DSP1.1 " ,
" DSP1.2 " ,
" DSP1.3 " ,
" DSP1.4 " ,
" DSP1.5 " ,
" DSP1.6 " ,
2012-09-26 19:43:44 +04:00
" DSP2.1 " ,
" DSP2.2 " ,
" DSP2.3 " ,
" DSP2.4 " ,
" DSP2.5 " ,
" DSP2.6 " ,
" DSP3.1 " ,
" DSP3.2 " ,
" DSP3.3 " ,
" DSP3.4 " ,
" DSP3.5 " ,
" DSP3.6 " ,
" DSP4.1 " ,
" DSP4.2 " ,
" DSP4.3 " ,
" DSP4.4 " ,
" DSP4.5 " ,
" DSP4.6 " ,
2012-06-19 00:08:44 +04:00
" ASRC1L " ,
" ASRC1R " ,
" ASRC2L " ,
" ASRC2R " ,
2012-12-05 15:35:24 +04:00
" ISRC1INT1 " ,
" ISRC1INT2 " ,
" ISRC1INT3 " ,
" ISRC1INT4 " ,
" ISRC1DEC1 " ,
" ISRC1DEC2 " ,
" ISRC1DEC3 " ,
" ISRC1DEC4 " ,
" ISRC2INT1 " ,
" ISRC2INT2 " ,
" ISRC2INT3 " ,
" ISRC2INT4 " ,
" ISRC2DEC1 " ,
" ISRC2DEC2 " ,
" ISRC2DEC3 " ,
" ISRC2DEC4 " ,
" ISRC3INT1 " ,
" ISRC3INT2 " ,
" ISRC3INT3 " ,
" ISRC3INT4 " ,
" ISRC3DEC1 " ,
" ISRC3DEC2 " ,
" ISRC3DEC3 " ,
" ISRC3DEC4 " ,
2012-06-19 00:08:44 +04:00
} ;
EXPORT_SYMBOL_GPL ( arizona_mixer_texts ) ;
2015-12-03 21:15:06 +03:00
unsigned int arizona_mixer_values [ ARIZONA_NUM_MIXER_INPUTS ] = {
2012-06-19 00:08:44 +04:00
0x00 , /* None */
0x04 , /* Tone */
0x05 ,
0x06 , /* Haptics */
0x08 , /* AEC */
2015-09-28 16:01:09 +03:00
0x09 , /* AEC2 */
2012-06-19 00:08:44 +04:00
0x0c , /* Noise mixer */
0x0d , /* Comfort noise */
0x10 , /* IN1L */
0x11 ,
0x12 ,
0x13 ,
0x14 ,
0x15 ,
2012-07-09 22:09:01 +04:00
0x16 ,
0x17 ,
2012-06-19 00:08:44 +04:00
0x20 , /* AIF1RX1 */
0x21 ,
0x22 ,
0x23 ,
0x24 ,
0x25 ,
0x26 ,
0x27 ,
0x28 , /* AIF2RX1 */
0x29 ,
2013-11-20 17:17:07 +04:00
0x2a ,
0x2b ,
0x2c ,
0x2d ,
2012-06-19 00:08:44 +04:00
0x30 , /* AIF3RX1 */
0x31 ,
0x38 , /* SLIMRX1 */
0x39 ,
0x3a ,
0x3b ,
0x3c ,
0x3d ,
0x3e ,
0x3f ,
0x50 , /* EQ1 */
0x51 ,
0x52 ,
0x53 ,
0x58 , /* DRC1L */
0x59 ,
0x5a ,
0x5b ,
0x60 , /* LHPF1 */
0x61 ,
0x62 ,
0x63 ,
0x68 , /* DSP1.1 */
0x69 ,
0x6a ,
0x6b ,
0x6c ,
0x6d ,
2012-09-26 19:43:44 +04:00
0x70 , /* DSP2.1 */
0x71 ,
0x72 ,
0x73 ,
0x74 ,
0x75 ,
0x78 , /* DSP3.1 */
0x79 ,
0x7a ,
0x7b ,
0x7c ,
0x7d ,
0x80 , /* DSP4.1 */
0x81 ,
0x82 ,
0x83 ,
0x84 ,
0x85 ,
2012-06-19 00:08:44 +04:00
0x90 , /* ASRC1L */
0x91 ,
0x92 ,
0x93 ,
2012-12-05 15:35:24 +04:00
0xa0 , /* ISRC1INT1 */
0xa1 ,
0xa2 ,
0xa3 ,
0xa4 , /* ISRC1DEC1 */
0xa5 ,
0xa6 ,
0xa7 ,
0xa8 , /* ISRC2DEC1 */
0xa9 ,
0xaa ,
0xab ,
0xac , /* ISRC2INT1 */
0xad ,
0xae ,
0xaf ,
0xb0 , /* ISRC3DEC1 */
0xb1 ,
0xb2 ,
0xb3 ,
0xb4 , /* ISRC3INT1 */
0xb5 ,
0xb6 ,
0xb7 ,
2012-06-19 00:08:44 +04:00
} ;
EXPORT_SYMBOL_GPL ( arizona_mixer_values ) ;
const DECLARE_TLV_DB_SCALE ( arizona_mixer_tlv , - 3200 , 100 , 0 ) ;
EXPORT_SYMBOL_GPL ( arizona_mixer_tlv ) ;
2015-09-28 16:01:09 +03:00
const char * const arizona_sample_rate_text [ ARIZONA_SAMPLE_RATE_ENUM_SIZE ] = {
" 12kHz " , " 24kHz " , " 48kHz " , " 96kHz " , " 192kHz " ,
" 11.025kHz " , " 22.05kHz " , " 44.1kHz " , " 88.2kHz " , " 176.4kHz " ,
" 4kHz " , " 8kHz " , " 16kHz " , " 32kHz " ,
} ;
EXPORT_SYMBOL_GPL ( arizona_sample_rate_text ) ;
const unsigned int arizona_sample_rate_val [ ARIZONA_SAMPLE_RATE_ENUM_SIZE ] = {
0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x09 , 0x0A , 0x0B , 0x0C , 0x0D ,
0x10 , 0x11 , 0x12 , 0x13 ,
} ;
EXPORT_SYMBOL_GPL ( arizona_sample_rate_val ) ;
const char * arizona_sample_rate_val_to_name ( unsigned int rate_val )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( arizona_sample_rate_val ) ; + + i ) {
if ( arizona_sample_rate_val [ i ] = = rate_val )
return arizona_sample_rate_text [ i ] ;
}
return " Illegal " ;
}
EXPORT_SYMBOL_GPL ( arizona_sample_rate_val_to_name ) ;
2015-12-03 21:15:06 +03:00
const char * const arizona_rate_text [ ARIZONA_RATE_ENUM_SIZE ] = {
2013-02-18 23:09:23 +04:00
" SYNCCLK rate " , " 8kHz " , " 16kHz " , " ASYNCCLK rate " ,
} ;
EXPORT_SYMBOL_GPL ( arizona_rate_text ) ;
2015-12-03 21:15:06 +03:00
const unsigned int arizona_rate_val [ ARIZONA_RATE_ENUM_SIZE ] = {
2013-02-18 23:09:23 +04:00
0 , 1 , 2 , 8 ,
} ;
EXPORT_SYMBOL_GPL ( arizona_rate_val ) ;
2013-12-19 13:30:12 +04:00
const struct soc_enum arizona_isrc_fsh [ ] = {
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_1_CTRL_1 ,
ARIZONA_ISRC1_FSH_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_2_CTRL_1 ,
ARIZONA_ISRC2_FSH_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_3_CTRL_1 ,
ARIZONA_ISRC3_FSH_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_isrc_fsh ) ;
2013-02-18 23:09:23 +04:00
const struct soc_enum arizona_isrc_fsl [ ] = {
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_1_CTRL_2 ,
ARIZONA_ISRC1_FSL_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_2_CTRL_2 ,
ARIZONA_ISRC2_FSL_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ISRC_3_CTRL_2 ,
ARIZONA_ISRC3_FSL_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_isrc_fsl ) ;
2013-12-19 13:30:13 +04:00
const struct soc_enum arizona_asrc_rate1 =
SOC_VALUE_ENUM_SINGLE ( ARIZONA_ASRC_RATE1 ,
ARIZONA_ASRC_RATE1_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE - 1 ,
arizona_rate_text , arizona_rate_val ) ;
EXPORT_SYMBOL_GPL ( arizona_asrc_rate1 ) ;
2016-06-13 15:35:14 +03:00
static const char * const arizona_vol_ramp_text [ ] = {
2012-12-09 07:25:52 +04:00
" 0ms/6dB " , " 0.5ms/6dB " , " 1ms/6dB " , " 2ms/6dB " , " 4ms/6dB " , " 8ms/6dB " ,
" 15ms/6dB " , " 30ms/6dB " ,
} ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_in_vd_ramp ,
ARIZONA_INPUT_VOLUME_RAMP ,
ARIZONA_IN_VD_RAMP_SHIFT ,
arizona_vol_ramp_text ) ;
2012-12-09 07:25:52 +04:00
EXPORT_SYMBOL_GPL ( arizona_in_vd_ramp ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_in_vi_ramp ,
ARIZONA_INPUT_VOLUME_RAMP ,
ARIZONA_IN_VI_RAMP_SHIFT ,
arizona_vol_ramp_text ) ;
2012-12-09 07:25:52 +04:00
EXPORT_SYMBOL_GPL ( arizona_in_vi_ramp ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_out_vd_ramp ,
ARIZONA_OUTPUT_VOLUME_RAMP ,
ARIZONA_OUT_VD_RAMP_SHIFT ,
arizona_vol_ramp_text ) ;
2012-12-09 07:25:52 +04:00
EXPORT_SYMBOL_GPL ( arizona_out_vd_ramp ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_out_vi_ramp ,
ARIZONA_OUTPUT_VOLUME_RAMP ,
ARIZONA_OUT_VI_RAMP_SHIFT ,
arizona_vol_ramp_text ) ;
2012-12-09 07:25:52 +04:00
EXPORT_SYMBOL_GPL ( arizona_out_vi_ramp ) ;
2016-06-13 15:35:14 +03:00
static const char * const arizona_lhpf_mode_text [ ] = {
2012-06-19 00:08:44 +04:00
" Low-pass " , " High-pass "
} ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_lhpf1_mode ,
ARIZONA_HPLPF1_1 ,
ARIZONA_LHPF1_MODE_SHIFT ,
arizona_lhpf_mode_text ) ;
2012-06-19 00:08:44 +04:00
EXPORT_SYMBOL_GPL ( arizona_lhpf1_mode ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_lhpf2_mode ,
ARIZONA_HPLPF2_1 ,
ARIZONA_LHPF2_MODE_SHIFT ,
arizona_lhpf_mode_text ) ;
2012-06-19 00:08:44 +04:00
EXPORT_SYMBOL_GPL ( arizona_lhpf2_mode ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_lhpf3_mode ,
ARIZONA_HPLPF3_1 ,
ARIZONA_LHPF3_MODE_SHIFT ,
arizona_lhpf_mode_text ) ;
2012-06-19 00:08:44 +04:00
EXPORT_SYMBOL_GPL ( arizona_lhpf3_mode ) ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_lhpf4_mode ,
ARIZONA_HPLPF4_1 ,
ARIZONA_LHPF4_MODE_SHIFT ,
arizona_lhpf_mode_text ) ;
2012-06-19 00:08:44 +04:00
EXPORT_SYMBOL_GPL ( arizona_lhpf4_mode ) ;
2016-06-13 15:35:14 +03:00
static const char * const arizona_ng_hold_text [ ] = {
2012-12-18 17:47:57 +04:00
" 30ms " , " 120ms " , " 250ms " , " 500ms " ,
} ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_ng_hold ,
ARIZONA_NOISE_GATE_CONTROL ,
ARIZONA_NGATE_HOLD_SHIFT ,
arizona_ng_hold_text ) ;
2012-12-18 17:47:57 +04:00
EXPORT_SYMBOL_GPL ( arizona_ng_hold ) ;
2013-11-19 20:04:03 +04:00
static const char * const arizona_in_hpf_cut_text [ ] = {
" 2.5Hz " , " 5Hz " , " 10Hz " , " 20Hz " , " 40Hz "
} ;
2014-02-18 13:01:43 +04:00
SOC_ENUM_SINGLE_DECL ( arizona_in_hpf_cut_enum ,
ARIZONA_HPF_CONTROL ,
ARIZONA_IN_HPF_CUT_SHIFT ,
arizona_in_hpf_cut_text ) ;
2013-11-19 20:04:03 +04:00
EXPORT_SYMBOL_GPL ( arizona_in_hpf_cut_enum ) ;
2013-08-06 20:03:55 +04:00
static const char * const arizona_in_dmic_osr_text [ ] = {
2014-11-12 17:55:26 +03:00
" 1.536MHz " , " 3.072MHz " , " 6.144MHz " , " 768kHz " ,
2013-08-06 20:03:55 +04:00
} ;
const struct soc_enum arizona_in_dmic_osr [ ] = {
SOC_ENUM_SINGLE ( ARIZONA_IN1L_CONTROL , ARIZONA_IN1_OSR_SHIFT ,
ARRAY_SIZE ( arizona_in_dmic_osr_text ) ,
arizona_in_dmic_osr_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_IN2L_CONTROL , ARIZONA_IN2_OSR_SHIFT ,
ARRAY_SIZE ( arizona_in_dmic_osr_text ) ,
arizona_in_dmic_osr_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_IN3L_CONTROL , ARIZONA_IN3_OSR_SHIFT ,
ARRAY_SIZE ( arizona_in_dmic_osr_text ) ,
arizona_in_dmic_osr_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_IN4L_CONTROL , ARIZONA_IN4_OSR_SHIFT ,
ARRAY_SIZE ( arizona_in_dmic_osr_text ) ,
arizona_in_dmic_osr_text ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_in_dmic_osr ) ;
2015-11-19 19:11:10 +03:00
static const char * const arizona_anc_input_src_text [ ] = {
" None " , " IN1 " , " IN2 " , " IN3 " , " IN4 " ,
} ;
static const char * const arizona_anc_channel_src_text [ ] = {
" None " , " Left " , " Right " , " Combine " ,
} ;
const struct soc_enum arizona_anc_input_src [ ] = {
SOC_ENUM_SINGLE ( ARIZONA_ANC_SRC ,
ARIZONA_IN_RXANCL_SEL_SHIFT ,
ARRAY_SIZE ( arizona_anc_input_src_text ) ,
arizona_anc_input_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_FCL_ADC_REFORMATTER_CONTROL ,
2017-08-14 17:46:24 +03:00
ARIZONA_FCL_MIC_MODE_SEL_SHIFT ,
2015-11-19 19:11:10 +03:00
ARRAY_SIZE ( arizona_anc_channel_src_text ) ,
arizona_anc_channel_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_ANC_SRC ,
ARIZONA_IN_RXANCR_SEL_SHIFT ,
ARRAY_SIZE ( arizona_anc_input_src_text ) ,
arizona_anc_input_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_FCR_ADC_REFORMATTER_CONTROL ,
2017-08-14 17:46:24 +03:00
ARIZONA_FCR_MIC_MODE_SEL_SHIFT ,
2015-11-19 19:11:10 +03:00
ARRAY_SIZE ( arizona_anc_channel_src_text ) ,
arizona_anc_channel_src_text ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_anc_input_src ) ;
static const char * const arizona_anc_ng_texts [ ] = {
" None " ,
" Internal " ,
" External " ,
} ;
SOC_ENUM_SINGLE_DECL ( arizona_anc_ng_enum , SND_SOC_NOPM , 0 ,
arizona_anc_ng_texts ) ;
EXPORT_SYMBOL_GPL ( arizona_anc_ng_enum ) ;
static const char * const arizona_output_anc_src_text [ ] = {
" None " , " RXANCL " , " RXANCR " ,
} ;
const struct soc_enum arizona_output_anc_src [ ] = {
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_1L ,
ARIZONA_OUT1L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_1R ,
ARIZONA_OUT1R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_2L ,
ARIZONA_OUT2L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_2R ,
ARIZONA_OUT2R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_3L ,
ARIZONA_OUT3L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_DAC_VOLUME_LIMIT_3R ,
ARIZONA_OUT3R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_4L ,
ARIZONA_OUT4L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_4R ,
ARIZONA_OUT4R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_5L ,
ARIZONA_OUT5L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_5R ,
ARIZONA_OUT5R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_6L ,
ARIZONA_OUT6L_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
SOC_ENUM_SINGLE ( ARIZONA_OUTPUT_PATH_CONFIG_6R ,
ARIZONA_OUT6R_ANC_SRC_SHIFT ,
ARRAY_SIZE ( arizona_output_anc_src_text ) ,
arizona_output_anc_src_text ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_output_anc_src ) ;
2016-05-13 18:45:16 +03:00
const struct snd_kcontrol_new arizona_voice_trigger_switch [ ] = {
SOC_DAPM_SINGLE ( " Switch " , SND_SOC_NOPM , 0 , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " Switch " , SND_SOC_NOPM , 1 , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " Switch " , SND_SOC_NOPM , 2 , 1 , 0 ) ,
SOC_DAPM_SINGLE ( " Switch " , SND_SOC_NOPM , 3 , 1 , 0 ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_voice_trigger_switch ) ;
2018-02-13 05:03:12 +03:00
static void arizona_in_set_vu ( struct snd_soc_component * component , int ena )
2013-02-15 21:27:22 +04:00
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-02-15 21:27:22 +04:00
unsigned int val ;
int i ;
if ( ena )
val = ARIZONA_IN_VU ;
else
val = 0 ;
for ( i = 0 ; i < priv - > num_inputs ; i + + )
2018-02-13 05:03:12 +03:00
snd_soc_component_update_bits ( component ,
2013-02-15 21:27:22 +04:00
ARIZONA_ADC_DIGITAL_VOLUME_1L + ( i * 4 ) ,
ARIZONA_IN_VU , val ) ;
}
2018-02-13 05:03:12 +03:00
bool arizona_input_analog ( struct snd_soc_component * component , int shift )
2015-09-16 15:59:41 +03:00
{
unsigned int reg = ARIZONA_IN1L_CONTROL + ( ( shift / 2 ) * 8 ) ;
2020-06-16 08:20:33 +03:00
unsigned int val = snd_soc_component_read ( component , reg ) ;
2015-09-16 15:59:41 +03:00
return ! ( val & ARIZONA_IN1_MODE_MASK ) ;
}
EXPORT_SYMBOL_GPL ( arizona_input_analog ) ;
2012-06-19 00:08:44 +04:00
int arizona_in_ev ( struct snd_soc_dapm_widget * w , struct snd_kcontrol * kcontrol ,
int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-02-06 20:57:29 +04:00
unsigned int reg ;
if ( w - > shift % 2 )
reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ( ( w - > shift / 2 ) * 8 ) ;
else
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ( ( w - > shift / 2 ) * 8 ) ;
switch ( event ) {
2013-02-15 21:27:22 +04:00
case SND_SOC_DAPM_PRE_PMU :
priv - > in_pending + + ;
break ;
2013-02-06 20:57:29 +04:00
case SND_SOC_DAPM_POST_PMU :
2018-02-20 19:08:11 +03:00
snd_soc_component_update_bits ( component , reg ,
ARIZONA_IN1L_MUTE , 0 ) ;
2013-02-15 21:27:22 +04:00
/* If this is the last input pending then allow VU */
priv - > in_pending - - ;
if ( priv - > in_pending = = 0 ) {
msleep ( 1 ) ;
2018-02-13 05:03:12 +03:00
arizona_in_set_vu ( component , 1 ) ;
2013-02-15 21:27:22 +04:00
}
2013-02-06 20:57:29 +04:00
break ;
case SND_SOC_DAPM_PRE_PMD :
2018-02-13 05:03:12 +03:00
snd_soc_component_update_bits ( component , reg ,
2013-02-15 21:27:22 +04:00
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU ,
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU ) ;
2013-02-06 20:57:29 +04:00
break ;
2013-02-15 21:27:22 +04:00
case SND_SOC_DAPM_POST_PMD :
/* Disable volume updates if no inputs are enabled */
2020-06-16 08:20:33 +03:00
reg = snd_soc_component_read ( component , ARIZONA_INPUT_ENABLES ) ;
2013-02-15 21:27:22 +04:00
if ( reg = = 0 )
2018-02-13 05:03:12 +03:00
arizona_in_set_vu ( component , 0 ) ;
2015-09-16 15:59:40 +03:00
break ;
default :
break ;
2013-02-06 20:57:29 +04:00
}
2012-06-19 00:08:44 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_in_ev ) ;
int arizona_out_ev ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2016-09-27 18:35:45 +03:00
struct arizona * arizona = priv - > arizona ;
2015-01-20 19:31:50 +03:00
2013-03-25 02:50:23 +04:00
switch ( event ) {
2015-01-20 19:31:51 +03:00
case SND_SOC_DAPM_PRE_PMU :
switch ( w - > shift ) {
case ARIZONA_OUT1L_ENA_SHIFT :
case ARIZONA_OUT1R_ENA_SHIFT :
case ARIZONA_OUT2L_ENA_SHIFT :
case ARIZONA_OUT2R_ENA_SHIFT :
case ARIZONA_OUT3L_ENA_SHIFT :
case ARIZONA_OUT3R_ENA_SHIFT :
priv - > out_up_pending + + ;
priv - > out_up_delay + = 17 ;
break ;
2016-09-27 18:35:45 +03:00
case ARIZONA_OUT4L_ENA_SHIFT :
case ARIZONA_OUT4R_ENA_SHIFT :
priv - > out_up_pending + + ;
switch ( arizona - > type ) {
case WM5102 :
case WM8997 :
break ;
default :
priv - > out_up_delay + = 10 ;
break ;
}
break ;
2015-01-20 19:31:51 +03:00
default :
break ;
}
break ;
2013-03-25 02:50:23 +04:00
case SND_SOC_DAPM_POST_PMU :
switch ( w - > shift ) {
case ARIZONA_OUT1L_ENA_SHIFT :
case ARIZONA_OUT1R_ENA_SHIFT :
case ARIZONA_OUT2L_ENA_SHIFT :
case ARIZONA_OUT2R_ENA_SHIFT :
case ARIZONA_OUT3L_ENA_SHIFT :
case ARIZONA_OUT3R_ENA_SHIFT :
2016-09-27 18:35:45 +03:00
case ARIZONA_OUT4L_ENA_SHIFT :
case ARIZONA_OUT4R_ENA_SHIFT :
2015-01-20 19:31:51 +03:00
priv - > out_up_pending - - ;
2016-09-27 18:35:45 +03:00
if ( ! priv - > out_up_pending & & priv - > out_up_delay ) {
2018-02-13 05:03:12 +03:00
dev_dbg ( component - > dev , " Power up delay: %d \n " ,
2016-09-27 18:35:44 +03:00
priv - > out_up_delay ) ;
2015-01-20 19:31:51 +03:00
msleep ( priv - > out_up_delay ) ;
priv - > out_up_delay = 0 ;
}
2013-03-25 02:50:23 +04:00
break ;
default :
break ;
}
break ;
2015-01-20 19:31:50 +03:00
case SND_SOC_DAPM_PRE_PMD :
switch ( w - > shift ) {
case ARIZONA_OUT1L_ENA_SHIFT :
case ARIZONA_OUT1R_ENA_SHIFT :
case ARIZONA_OUT2L_ENA_SHIFT :
case ARIZONA_OUT2R_ENA_SHIFT :
case ARIZONA_OUT3L_ENA_SHIFT :
case ARIZONA_OUT3R_ENA_SHIFT :
priv - > out_down_pending + + ;
priv - > out_down_delay + + ;
break ;
2016-09-27 18:35:45 +03:00
case ARIZONA_OUT4L_ENA_SHIFT :
case ARIZONA_OUT4R_ENA_SHIFT :
priv - > out_down_pending + + ;
switch ( arizona - > type ) {
case WM5102 :
case WM8997 :
break ;
case WM8998 :
case WM1814 :
priv - > out_down_delay + = 5 ;
break ;
default :
priv - > out_down_delay + + ;
break ;
}
2020-11-20 21:23:50 +03:00
break ;
2015-01-20 19:31:50 +03:00
default :
break ;
}
break ;
case SND_SOC_DAPM_POST_PMD :
switch ( w - > shift ) {
case ARIZONA_OUT1L_ENA_SHIFT :
case ARIZONA_OUT1R_ENA_SHIFT :
case ARIZONA_OUT2L_ENA_SHIFT :
case ARIZONA_OUT2R_ENA_SHIFT :
case ARIZONA_OUT3L_ENA_SHIFT :
case ARIZONA_OUT3R_ENA_SHIFT :
2016-09-27 18:35:45 +03:00
case ARIZONA_OUT4L_ENA_SHIFT :
case ARIZONA_OUT4R_ENA_SHIFT :
2015-01-20 19:31:50 +03:00
priv - > out_down_pending - - ;
2016-09-27 18:35:45 +03:00
if ( ! priv - > out_down_pending & & priv - > out_down_delay ) {
2018-02-13 05:03:12 +03:00
dev_dbg ( component - > dev , " Power down delay: %d \n " ,
2016-09-27 18:35:44 +03:00
priv - > out_down_delay ) ;
2015-01-20 19:31:50 +03:00
msleep ( priv - > out_down_delay ) ;
priv - > out_down_delay = 0 ;
}
break ;
default :
break ;
}
break ;
2015-09-16 15:59:40 +03:00
default :
break ;
2013-03-25 02:50:23 +04:00
}
2012-06-19 00:08:44 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_out_ev ) ;
2018-02-20 19:08:11 +03:00
int arizona_hp_ev ( struct snd_soc_dapm_widget * w , struct snd_kcontrol * kcontrol ,
int event )
2013-02-22 22:36:53 +04:00
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-12-12 04:49:22 +04:00
struct arizona * arizona = priv - > arizona ;
2013-02-22 22:36:53 +04:00
unsigned int mask = 1 < < w - > shift ;
unsigned int val ;
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
val = mask ;
break ;
case SND_SOC_DAPM_PRE_PMD :
val = 0 ;
break ;
2015-01-20 19:31:51 +03:00
case SND_SOC_DAPM_PRE_PMU :
2015-01-20 19:31:50 +03:00
case SND_SOC_DAPM_POST_PMD :
return arizona_out_ev ( w , kcontrol , event ) ;
2013-02-22 22:36:53 +04:00
default :
return - EINVAL ;
}
/* Store the desired state for the HP outputs */
priv - > arizona - > hp_ena & = ~ mask ;
priv - > arizona - > hp_ena | = val ;
2015-02-16 18:41:02 +03:00
/* Force off if HPDET clamp is active */
if ( priv - > arizona - > hpdet_clamp )
2013-02-22 22:36:53 +04:00
val = 0 ;
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , ARIZONA_OUTPUT_ENABLES_1 ,
mask , val ) ;
2013-02-22 22:36:53 +04:00
return arizona_out_ev ( w , kcontrol , event ) ;
}
EXPORT_SYMBOL_GPL ( arizona_hp_ev ) ;
2018-02-13 05:03:12 +03:00
static int arizona_dvfs_enable ( struct snd_soc_component * component )
2015-06-02 13:53:33 +03:00
{
2018-02-13 05:03:12 +03:00
const struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2015-06-02 13:53:33 +03:00
struct arizona * arizona = priv - > arizona ;
int ret ;
ret = regulator_set_voltage ( arizona - > dcvdd , 1800000 , 1800000 ) ;
if ( ret ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Failed to boost DCVDD: %d \n " , ret ) ;
2015-06-02 13:53:33 +03:00
return ret ;
}
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1 ,
ARIZONA_SUBSYS_MAX_FREQ ,
ARIZONA_SUBSYS_MAX_FREQ ) ;
if ( ret ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Failed to enable subsys max: %d \n " , ret ) ;
2015-06-02 13:53:33 +03:00
regulator_set_voltage ( arizona - > dcvdd , 1200000 , 1800000 ) ;
return ret ;
}
return 0 ;
}
2018-02-13 05:03:12 +03:00
static int arizona_dvfs_disable ( struct snd_soc_component * component )
2015-06-02 13:53:33 +03:00
{
2018-02-13 05:03:12 +03:00
const struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2015-06-02 13:53:33 +03:00
struct arizona * arizona = priv - > arizona ;
int ret ;
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1 ,
ARIZONA_SUBSYS_MAX_FREQ , 0 ) ;
if ( ret ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Failed to disable subsys max: %d \n " , ret ) ;
2015-06-02 13:53:33 +03:00
return ret ;
}
ret = regulator_set_voltage ( arizona - > dcvdd , 1200000 , 1800000 ) ;
if ( ret ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Failed to unboost DCVDD: %d \n " , ret ) ;
2015-06-02 13:53:33 +03:00
return ret ;
}
return 0 ;
}
2018-02-13 05:03:12 +03:00
int arizona_dvfs_up ( struct snd_soc_component * component , unsigned int flags )
2015-06-02 13:53:33 +03:00
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2015-06-02 13:53:33 +03:00
int ret = 0 ;
mutex_lock ( & priv - > dvfs_lock ) ;
if ( ! priv - > dvfs_cached & & ! priv - > dvfs_reqs ) {
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_enable ( component ) ;
2015-06-02 13:53:33 +03:00
if ( ret )
goto err ;
}
priv - > dvfs_reqs | = flags ;
err :
mutex_unlock ( & priv - > dvfs_lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_dvfs_up ) ;
2018-02-13 05:03:12 +03:00
int arizona_dvfs_down ( struct snd_soc_component * component , unsigned int flags )
2015-06-02 13:53:33 +03:00
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2015-06-02 13:53:33 +03:00
unsigned int old_reqs ;
int ret = 0 ;
mutex_lock ( & priv - > dvfs_lock ) ;
old_reqs = priv - > dvfs_reqs ;
priv - > dvfs_reqs & = ~ flags ;
if ( ! priv - > dvfs_cached & & old_reqs & & ! priv - > dvfs_reqs )
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_disable ( component ) ;
2015-06-02 13:53:33 +03:00
mutex_unlock ( & priv - > dvfs_lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_dvfs_down ) ;
int arizona_dvfs_sysclk_ev ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2015-06-02 13:53:33 +03:00
int ret = 0 ;
mutex_lock ( & priv - > dvfs_lock ) ;
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
if ( priv - > dvfs_reqs )
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_enable ( component ) ;
2015-06-02 13:53:33 +03:00
priv - > dvfs_cached = false ;
break ;
case SND_SOC_DAPM_PRE_PMD :
/* We must ensure DVFS is disabled before the codec goes into
* suspend so that we are never in an illegal state of DVFS
* enabled without enough DCVDD
*/
priv - > dvfs_cached = true ;
if ( priv - > dvfs_reqs )
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_disable ( component ) ;
2015-06-02 13:53:33 +03:00
break ;
default :
break ;
}
mutex_unlock ( & priv - > dvfs_lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_dvfs_sysclk_ev ) ;
void arizona_init_dvfs ( struct arizona_priv * priv )
{
mutex_init ( & priv - > dvfs_lock ) ;
}
EXPORT_SYMBOL_GPL ( arizona_init_dvfs ) ;
2015-11-19 19:11:10 +03:00
int arizona_anc_ev ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol ,
int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
2015-11-19 19:11:10 +03:00
unsigned int val ;
switch ( event ) {
case SND_SOC_DAPM_POST_PMU :
val = 1 < < w - > shift ;
break ;
case SND_SOC_DAPM_PRE_PMD :
val = 1 < < ( w - > shift + 1 ) ;
break ;
default :
return 0 ;
}
2018-02-13 05:03:12 +03:00
snd_soc_component_write ( component , ARIZONA_CLOCK_CONTROL , val ) ;
2015-11-19 19:11:10 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_anc_ev ) ;
2015-11-03 17:24:12 +03:00
static unsigned int arizona_opclk_ref_48k_rates [ ] = {
2012-08-08 20:52:44 +04:00
6144000 ,
12288000 ,
2012-11-15 15:41:30 +04:00
24576000 ,
2012-08-08 20:52:44 +04:00
49152000 ,
} ;
2015-11-03 17:24:12 +03:00
static unsigned int arizona_opclk_ref_44k1_rates [ ] = {
2012-08-08 20:52:44 +04:00
5644800 ,
11289600 ,
2012-11-15 15:41:30 +04:00
22579200 ,
2012-08-08 20:52:44 +04:00
45158400 ,
} ;
2018-02-20 19:08:11 +03:00
static int arizona_set_opclk ( struct snd_soc_component * component ,
unsigned int clk , unsigned int freq )
2012-08-08 20:52:44 +04:00
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2012-08-08 20:52:44 +04:00
unsigned int reg ;
unsigned int * rates ;
int ref , div , refclk ;
switch ( clk ) {
case ARIZONA_CLK_OPCLK :
reg = ARIZONA_OUTPUT_SYSTEM_CLOCK ;
refclk = priv - > sysclk ;
break ;
case ARIZONA_CLK_ASYNC_OPCLK :
reg = ARIZONA_OUTPUT_ASYNC_CLOCK ;
refclk = priv - > asyncclk ;
break ;
default :
return - EINVAL ;
}
if ( refclk % 8000 )
2015-11-03 17:24:12 +03:00
rates = arizona_opclk_ref_44k1_rates ;
2012-08-08 20:52:44 +04:00
else
2015-11-03 17:24:12 +03:00
rates = arizona_opclk_ref_48k_rates ;
2012-08-08 20:52:44 +04:00
2015-11-03 17:24:12 +03:00
for ( ref = 0 ; ref < ARRAY_SIZE ( arizona_opclk_ref_48k_rates ) & &
2018-02-20 19:08:11 +03:00
rates [ ref ] < = refclk ; ref + + ) {
2012-08-08 20:52:44 +04:00
div = 1 ;
while ( rates [ ref ] / div > = freq & & div < 32 ) {
if ( rates [ ref ] / div = = freq ) {
2018-02-13 05:03:12 +03:00
dev_dbg ( component - > dev , " Configured %dHz OPCLK \n " ,
2012-08-08 20:52:44 +04:00
freq ) ;
2018-02-13 05:03:12 +03:00
snd_soc_component_update_bits ( component , reg ,
2012-08-08 20:52:44 +04:00
ARIZONA_OPCLK_DIV_MASK |
ARIZONA_OPCLK_SEL_MASK ,
( div < <
ARIZONA_OPCLK_DIV_SHIFT ) |
ref ) ;
return 0 ;
}
div + + ;
}
}
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Unable to generate %dHz OPCLK \n " , freq ) ;
2012-08-08 20:52:44 +04:00
return - EINVAL ;
}
2016-10-21 16:15:57 +03:00
int arizona_clk_ev ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * kcontrol , int event )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( w - > dapm ) ;
struct arizona * arizona = dev_get_drvdata ( component - > dev - > parent ) ;
2016-10-21 16:15:57 +03:00
unsigned int val ;
int clk_idx ;
int ret ;
ret = regmap_read ( arizona - > regmap , w - > reg , & val ) ;
if ( ret ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Failed to check clock source: %d \n " , ret ) ;
2016-10-21 16:15:57 +03:00
return ret ;
}
val = ( val & ARIZONA_SYSCLK_SRC_MASK ) > > ARIZONA_SYSCLK_SRC_SHIFT ;
switch ( val ) {
case ARIZONA_CLK_SRC_MCLK1 :
clk_idx = ARIZONA_MCLK1 ;
break ;
case ARIZONA_CLK_SRC_MCLK2 :
clk_idx = ARIZONA_MCLK2 ;
break ;
default :
return 0 ;
}
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
return clk_prepare_enable ( arizona - > mclk [ clk_idx ] ) ;
case SND_SOC_DAPM_POST_PMD :
clk_disable_unprepare ( arizona - > mclk [ clk_idx ] ) ;
return 0 ;
default :
return 0 ;
}
}
EXPORT_SYMBOL_GPL ( arizona_clk_ev ) ;
2018-02-13 05:03:12 +03:00
int arizona_set_sysclk ( struct snd_soc_component * component , int clk_id ,
2012-06-19 00:08:44 +04:00
int source , unsigned int freq , int dir )
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2012-06-19 00:08:44 +04:00
struct arizona * arizona = priv - > arizona ;
char * name ;
unsigned int reg ;
unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK ;
unsigned int val = source < < ARIZONA_SYSCLK_SRC_SHIFT ;
2015-12-03 21:15:07 +03:00
int * clk ;
2012-06-19 00:08:44 +04:00
switch ( clk_id ) {
case ARIZONA_CLK_SYSCLK :
name = " SYSCLK " ;
reg = ARIZONA_SYSTEM_CLOCK_1 ;
clk = & priv - > sysclk ;
mask | = ARIZONA_SYSCLK_FRAC ;
break ;
case ARIZONA_CLK_ASYNCCLK :
name = " ASYNCCLK " ;
reg = ARIZONA_ASYNC_CLOCK_1 ;
clk = & priv - > asyncclk ;
break ;
2012-08-08 20:52:44 +04:00
case ARIZONA_CLK_OPCLK :
case ARIZONA_CLK_ASYNC_OPCLK :
2018-02-13 05:03:12 +03:00
return arizona_set_opclk ( component , clk_id , freq ) ;
2012-06-19 00:08:44 +04:00
default :
return - EINVAL ;
}
switch ( freq ) {
case 5644800 :
case 6144000 :
break ;
case 11289600 :
case 12288000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_12MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-06-19 00:08:44 +04:00
break ;
case 22579200 :
case 24576000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_24MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-06-19 00:08:44 +04:00
break ;
case 45158400 :
case 49152000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_49MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-06-19 00:08:44 +04:00
break ;
2012-11-26 20:01:37 +04:00
case 67737600 :
case 73728000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_73MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-11-26 20:01:37 +04:00
break ;
case 90316800 :
case 98304000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_98MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-11-26 20:01:37 +04:00
break ;
case 135475200 :
case 147456000 :
2013-03-08 11:22:29 +04:00
val | = ARIZONA_CLK_147MHZ < < ARIZONA_SYSCLK_FREQ_SHIFT ;
2012-11-26 20:01:37 +04:00
break ;
2013-01-21 11:09:36 +04:00
case 0 :
dev_dbg ( arizona - > dev , " %s cleared \n " , name ) ;
* clk = freq ;
return 0 ;
2012-06-19 00:08:44 +04:00
default :
return - EINVAL ;
}
* clk = freq ;
if ( freq % 6144000 )
val | = ARIZONA_SYSCLK_FRAC ;
dev_dbg ( arizona - > dev , " %s set to %uHz " , name , freq ) ;
return regmap_update_bits ( arizona - > regmap , reg , mask , val ) ;
}
EXPORT_SYMBOL_GPL ( arizona_set_sysclk ) ;
static int arizona_set_fmt ( struct snd_soc_dai * dai , unsigned int fmt )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-12-12 04:49:22 +04:00
struct arizona * arizona = priv - > arizona ;
2012-06-19 00:08:44 +04:00
int lrclk , bclk , mode , base ;
base = dai - > driver - > base ;
lrclk = 0 ;
bclk = 0 ;
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_DSP_A :
2014-11-12 19:12:46 +03:00
mode = ARIZONA_FMT_DSP_MODE_A ;
break ;
case SND_SOC_DAIFMT_DSP_B :
if ( ( fmt & SND_SOC_DAIFMT_MASTER_MASK )
! = SND_SOC_DAIFMT_CBM_CFM ) {
arizona_aif_err ( dai , " DSP_B not valid in slave mode \n " ) ;
return - EINVAL ;
}
mode = ARIZONA_FMT_DSP_MODE_B ;
2012-06-19 00:08:44 +04:00
break ;
case SND_SOC_DAIFMT_I2S :
2014-11-12 19:12:46 +03:00
mode = ARIZONA_FMT_I2S_MODE ;
break ;
case SND_SOC_DAIFMT_LEFT_J :
if ( ( fmt & SND_SOC_DAIFMT_MASTER_MASK )
! = SND_SOC_DAIFMT_CBM_CFM ) {
arizona_aif_err ( dai , " LEFT_J not valid in slave mode \n " ) ;
return - EINVAL ;
}
mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE ;
2012-06-19 00:08:44 +04:00
break ;
default :
arizona_aif_err ( dai , " Unsupported DAI format %d \n " ,
fmt & SND_SOC_DAIFMT_FORMAT_MASK ) ;
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
break ;
case SND_SOC_DAIFMT_CBS_CFM :
lrclk | = ARIZONA_AIF1TX_LRCLK_MSTR ;
break ;
case SND_SOC_DAIFMT_CBM_CFS :
bclk | = ARIZONA_AIF1_BCLK_MSTR ;
break ;
case SND_SOC_DAIFMT_CBM_CFM :
bclk | = ARIZONA_AIF1_BCLK_MSTR ;
lrclk | = ARIZONA_AIF1TX_LRCLK_MSTR ;
break ;
default :
arizona_aif_err ( dai , " Unsupported master mode %d \n " ,
fmt & SND_SOC_DAIFMT_MASTER_MASK ) ;
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_INV_MASK ) {
case SND_SOC_DAIFMT_NB_NF :
break ;
case SND_SOC_DAIFMT_IB_IF :
bclk | = ARIZONA_AIF1_BCLK_INV ;
lrclk | = ARIZONA_AIF1TX_LRCLK_INV ;
break ;
case SND_SOC_DAIFMT_IB_NF :
bclk | = ARIZONA_AIF1_BCLK_INV ;
break ;
case SND_SOC_DAIFMT_NB_IF :
lrclk | = ARIZONA_AIF1TX_LRCLK_INV ;
break ;
default :
return - EINVAL ;
}
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , base + ARIZONA_AIF_BCLK_CTRL ,
ARIZONA_AIF1_BCLK_INV |
ARIZONA_AIF1_BCLK_MSTR ,
bclk ) ;
regmap_update_bits_async ( arizona - > regmap , base + ARIZONA_AIF_TX_PIN_CTRL ,
ARIZONA_AIF1TX_LRCLK_INV |
ARIZONA_AIF1TX_LRCLK_MSTR , lrclk ) ;
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_RX_PIN_CTRL ,
ARIZONA_AIF1RX_LRCLK_INV |
ARIZONA_AIF1RX_LRCLK_MSTR , lrclk ) ;
regmap_update_bits ( arizona - > regmap , base + ARIZONA_AIF_FORMAT ,
ARIZONA_AIF1_FMT_MASK , mode ) ;
2012-06-19 00:08:44 +04:00
return 0 ;
}
2012-07-04 21:58:04 +04:00
static const int arizona_48k_bclk_rates [ ] = {
2012-06-19 00:08:44 +04:00
- 1 ,
48000 ,
64000 ,
96000 ,
128000 ,
192000 ,
256000 ,
384000 ,
512000 ,
768000 ,
1024000 ,
1536000 ,
2048000 ,
3072000 ,
4096000 ,
6144000 ,
8192000 ,
12288000 ,
24576000 ,
} ;
2012-07-04 21:58:04 +04:00
static const int arizona_44k1_bclk_rates [ ] = {
2012-06-19 00:08:44 +04:00
- 1 ,
44100 ,
58800 ,
88200 ,
117600 ,
177640 ,
235200 ,
352800 ,
470400 ,
705600 ,
940800 ,
1411200 ,
1881600 ,
2012-09-05 13:02:10 +04:00
2822400 ,
2012-06-19 00:08:44 +04:00
3763200 ,
5644800 ,
7526400 ,
11289600 ,
22579200 ,
} ;
2016-02-04 19:29:01 +03:00
static const unsigned int arizona_sr_vals [ ] = {
2012-06-19 00:08:44 +04:00
0 ,
12000 ,
24000 ,
48000 ,
96000 ,
192000 ,
384000 ,
768000 ,
0 ,
11025 ,
22050 ,
44100 ,
88200 ,
176400 ,
352800 ,
705600 ,
4000 ,
8000 ,
16000 ,
32000 ,
64000 ,
128000 ,
256000 ,
512000 ,
} ;
2016-02-04 19:29:01 +03:00
# define ARIZONA_48K_RATE_MASK 0x0F003E
# define ARIZONA_44K1_RATE_MASK 0x003E00
# define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
static const struct snd_pcm_hw_constraint_list arizona_constraint = {
. count = ARRAY_SIZE ( arizona_sr_vals ) ,
. list = arizona_sr_vals ,
} ;
2012-07-04 20:32:05 +04:00
static int arizona_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2012-07-04 20:32:05 +04:00
struct arizona_dai_priv * dai_priv = & priv - > dai [ dai - > id - 1 ] ;
unsigned int base_rate ;
2015-12-29 12:49:19 +03:00
if ( ! substream - > runtime )
return 0 ;
2012-07-04 20:32:05 +04:00
switch ( dai_priv - > clk ) {
case ARIZONA_CLK_SYSCLK :
base_rate = priv - > sysclk ;
break ;
case ARIZONA_CLK_ASYNCCLK :
base_rate = priv - > asyncclk ;
break ;
default :
return 0 ;
}
2013-01-21 11:09:36 +04:00
if ( base_rate = = 0 )
2016-02-04 19:29:01 +03:00
dai_priv - > constraint . mask = ARIZONA_RATE_MASK ;
else if ( base_rate % 8000 )
dai_priv - > constraint . mask = ARIZONA_44K1_RATE_MASK ;
2012-07-04 20:32:05 +04:00
else
2016-02-04 19:29:01 +03:00
dai_priv - > constraint . mask = ARIZONA_48K_RATE_MASK ;
2012-07-04 20:32:05 +04:00
return snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE ,
2016-02-04 19:29:01 +03:00
& dai_priv - > constraint ) ;
2012-07-04 20:32:05 +04:00
}
2018-02-13 05:03:12 +03:00
static void arizona_wm5102_set_dac_comp ( struct snd_soc_component * component ,
2014-06-06 17:14:05 +04:00
unsigned int rate )
{
2018-02-13 05:03:12 +03:00
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2014-06-06 17:14:05 +04:00
struct arizona * arizona = priv - > arizona ;
2015-07-16 18:36:21 +03:00
struct reg_sequence dac_comp [ ] = {
2014-06-06 17:14:05 +04:00
{ 0x80 , 0x3 } ,
{ ARIZONA_DAC_COMP_1 , 0 } ,
{ ARIZONA_DAC_COMP_2 , 0 } ,
{ 0x80 , 0x0 } ,
} ;
2014-11-09 19:00:59 +03:00
mutex_lock ( & arizona - > dac_comp_lock ) ;
2014-06-06 17:14:05 +04:00
dac_comp [ 1 ] . def = arizona - > dac_comp_coeff ;
if ( rate > = 176400 )
dac_comp [ 2 ] . def = arizona - > dac_comp_enabled ;
2014-11-09 19:00:59 +03:00
mutex_unlock ( & arizona - > dac_comp_lock ) ;
2014-06-06 17:14:05 +04:00
regmap_multi_reg_write ( arizona - > regmap ,
dac_comp ,
ARRAY_SIZE ( dac_comp ) ) ;
}
2012-10-10 10:10:08 +04:00
static int arizona_hw_params_rate ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2012-10-10 10:10:08 +04:00
struct arizona_dai_priv * dai_priv = & priv - > dai [ dai - > id - 1 ] ;
int base = dai - > driver - > base ;
2015-06-02 13:53:35 +03:00
int i , sr_val , ret ;
2012-10-10 10:10:08 +04:00
/*
* We will need to be more flexible than this in future ,
* currently we use a single sample rate for SYSCLK .
*/
for ( i = 0 ; i < ARRAY_SIZE ( arizona_sr_vals ) ; i + + )
if ( arizona_sr_vals [ i ] = = params_rate ( params ) )
break ;
if ( i = = ARRAY_SIZE ( arizona_sr_vals ) ) {
arizona_aif_err ( dai , " Unsupported sample rate %dHz \n " ,
params_rate ( params ) ) ;
return - EINVAL ;
}
sr_val = i ;
2015-06-02 13:53:35 +03:00
switch ( priv - > arizona - > type ) {
case WM5102 :
case WM8997 :
if ( arizona_sr_vals [ sr_val ] > = 88200 )
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_up ( component , ARIZONA_DVFS_SR1_RQ ) ;
2015-06-02 13:53:35 +03:00
else
2018-02-13 05:03:12 +03:00
ret = arizona_dvfs_down ( component , ARIZONA_DVFS_SR1_RQ ) ;
2015-06-02 13:53:35 +03:00
if ( ret ) {
arizona_aif_err ( dai , " Failed to change DVFS %d \n " , ret ) ;
return ret ;
}
break ;
default :
break ;
}
2012-10-10 10:10:08 +04:00
switch ( dai_priv - > clk ) {
case ARIZONA_CLK_SYSCLK :
2014-06-06 17:14:05 +04:00
switch ( priv - > arizona - > type ) {
case WM5102 :
2018-02-13 05:03:12 +03:00
arizona_wm5102_set_dac_comp ( component ,
2014-06-06 17:14:05 +04:00
params_rate ( params ) ) ;
break ;
default :
break ;
}
2018-02-13 05:03:12 +03:00
snd_soc_component_update_bits ( component , ARIZONA_SAMPLE_RATE_1 ,
2018-02-20 19:08:11 +03:00
ARIZONA_SAMPLE_RATE_1_MASK ,
sr_val ) ;
2012-10-10 10:10:08 +04:00
if ( base )
2018-02-20 19:08:11 +03:00
snd_soc_component_update_bits ( component ,
base + ARIZONA_AIF_RATE_CTRL ,
ARIZONA_AIF1_RATE_MASK , 0 ) ;
2012-10-10 10:10:08 +04:00
break ;
case ARIZONA_CLK_ASYNCCLK :
2018-02-20 19:08:11 +03:00
snd_soc_component_update_bits ( component ,
ARIZONA_ASYNC_SAMPLE_RATE_1 ,
ARIZONA_ASYNC_SAMPLE_RATE_1_MASK ,
sr_val ) ;
2012-10-10 10:10:08 +04:00
if ( base )
2018-02-20 19:08:11 +03:00
snd_soc_component_update_bits ( component ,
base + ARIZONA_AIF_RATE_CTRL ,
ARIZONA_AIF1_RATE_MASK ,
8 < < ARIZONA_AIF1_RATE_SHIFT ) ;
2012-10-10 10:10:08 +04:00
break ;
default :
arizona_aif_err ( dai , " Invalid clock %d \n " , dai_priv - > clk ) ;
return - EINVAL ;
}
return 0 ;
}
2018-02-13 05:03:12 +03:00
static bool arizona_aif_cfg_changed ( struct snd_soc_component * component ,
2014-07-22 14:42:06 +04:00
int base , int bclk , int lrclk , int frame )
{
int val ;
2020-06-16 08:20:33 +03:00
val = snd_soc_component_read ( component , base + ARIZONA_AIF_BCLK_CTRL ) ;
2014-07-22 14:42:06 +04:00
if ( bclk ! = ( val & ARIZONA_AIF1_BCLK_FREQ_MASK ) )
return true ;
2022-06-28 18:34:09 +03:00
val = snd_soc_component_read ( component , base + ARIZONA_AIF_RX_BCLK_RATE ) ;
if ( lrclk ! = ( val & ARIZONA_AIF1RX_BCPF_MASK ) )
2014-07-22 14:42:06 +04:00
return true ;
2020-06-16 08:20:33 +03:00
val = snd_soc_component_read ( component , base + ARIZONA_AIF_FRAME_CTRL_1 ) ;
2014-07-22 14:42:06 +04:00
if ( frame ! = ( val & ( ARIZONA_AIF1TX_WL_MASK |
ARIZONA_AIF1TX_SLOT_LEN_MASK ) ) )
return true ;
return false ;
}
2012-06-19 00:08:44 +04:00
static int arizona_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2013-01-17 11:35:14 +04:00
struct arizona * arizona = priv - > arizona ;
2012-06-19 00:08:44 +04:00
int base = dai - > driver - > base ;
const int * rates ;
2013-03-05 10:17:47 +04:00
int i , ret , val ;
2014-06-04 13:11:06 +04:00
int channels = params_channels ( params ) ;
2013-01-17 11:35:14 +04:00
int chan_limit = arizona - > pdata . max_channels_clocked [ dai - > id - 1 ] ;
2014-06-04 13:11:06 +04:00
int tdm_width = arizona - > tdm_width [ dai - > id - 1 ] ;
int tdm_slots = arizona - > tdm_slots [ dai - > id - 1 ] ;
2013-01-17 11:35:14 +04:00
int bclk , lrclk , wl , frame , bclk_target ;
2014-07-22 14:42:06 +04:00
bool reconfig ;
unsigned int aif_tx_state , aif_rx_state ;
2012-06-19 00:08:44 +04:00
2015-12-23 17:18:05 +03:00
if ( params_rate ( params ) % 4000 )
2012-07-04 21:58:04 +04:00
rates = & arizona_44k1_bclk_rates [ 0 ] ;
2012-06-19 00:08:44 +04:00
else
2012-07-04 21:58:04 +04:00
rates = & arizona_48k_bclk_rates [ 0 ] ;
2012-06-19 00:08:44 +04:00
2015-07-09 13:28:46 +03:00
wl = params_width ( params ) ;
2014-08-12 18:30:32 +04:00
2014-06-04 13:11:06 +04:00
if ( tdm_slots ) {
arizona_aif_dbg ( dai , " Configuring for %d %d bit TDM slots \n " ,
tdm_slots , tdm_width ) ;
bclk_target = tdm_slots * tdm_width * params_rate ( params ) ;
channels = tdm_slots ;
} else {
bclk_target = snd_soc_params_to_bclk ( params ) ;
2014-08-12 18:30:32 +04:00
tdm_width = wl ;
2014-06-04 13:11:06 +04:00
}
if ( chan_limit & & chan_limit < channels ) {
2013-01-17 11:35:14 +04:00
arizona_aif_dbg ( dai , " Limiting to %d channels \n " , chan_limit ) ;
2014-06-04 13:11:06 +04:00
bclk_target / = channels ;
2013-01-17 11:35:14 +04:00
bclk_target * = chan_limit ;
}
2014-06-04 13:11:06 +04:00
/* Force multiple of 2 channels for I2S mode */
2020-06-16 08:20:33 +03:00
val = snd_soc_component_read ( component , base + ARIZONA_AIF_FORMAT ) ;
2014-11-12 19:12:46 +03:00
val & = ARIZONA_AIF1_FMT_MASK ;
if ( ( channels & 1 ) & & ( val = = ARIZONA_FMT_I2S_MODE ) ) {
2013-03-05 10:17:47 +04:00
arizona_aif_dbg ( dai , " Forcing stereo mode \n " ) ;
2014-06-04 13:11:06 +04:00
bclk_target / = channels ;
bclk_target * = channels + 1 ;
2013-03-05 10:17:47 +04:00
}
2012-07-04 21:58:04 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( arizona_44k1_bclk_rates ) ; i + + ) {
2013-01-17 11:35:14 +04:00
if ( rates [ i ] > = bclk_target & &
2012-07-04 22:07:09 +04:00
rates [ i ] % params_rate ( params ) = = 0 ) {
2012-06-19 00:08:44 +04:00
bclk = i ;
break ;
}
}
2012-07-04 21:58:04 +04:00
if ( i = = ARRAY_SIZE ( arizona_44k1_bclk_rates ) ) {
2012-06-19 00:08:44 +04:00
arizona_aif_err ( dai , " Unsupported sample rate %dHz \n " ,
params_rate ( params ) ) ;
return - EINVAL ;
}
2013-01-17 09:15:59 +04:00
lrclk = rates [ bclk ] / params_rate ( params ) ;
2012-06-19 00:08:44 +04:00
arizona_aif_dbg ( dai , " BCLK %dHz LRCLK %dHz \n " ,
rates [ bclk ] , rates [ bclk ] / lrclk ) ;
2014-08-12 18:30:32 +04:00
frame = wl < < ARIZONA_AIF1TX_WL_SHIFT | tdm_width ;
2012-06-19 00:08:44 +04:00
2018-02-13 05:03:12 +03:00
reconfig = arizona_aif_cfg_changed ( component , base , bclk , lrclk , frame ) ;
2014-07-22 14:42:06 +04:00
if ( reconfig ) {
/* Save AIF TX/RX state */
2020-06-16 08:20:33 +03:00
aif_tx_state = snd_soc_component_read ( component ,
2014-07-22 14:42:06 +04:00
base + ARIZONA_AIF_TX_ENABLES ) ;
2020-06-16 08:20:33 +03:00
aif_rx_state = snd_soc_component_read ( component ,
2014-07-22 14:42:06 +04:00
base + ARIZONA_AIF_RX_ENABLES ) ;
/* Disable AIF TX/RX before reconfiguring it */
regmap_update_bits_async ( arizona - > regmap ,
2018-02-20 19:08:11 +03:00
base + ARIZONA_AIF_TX_ENABLES ,
0xff , 0x0 ) ;
2014-07-22 14:42:06 +04:00
regmap_update_bits ( arizona - > regmap ,
2018-02-20 19:08:11 +03:00
base + ARIZONA_AIF_RX_ENABLES , 0xff , 0x0 ) ;
2014-07-22 14:42:06 +04:00
}
2012-10-10 10:10:08 +04:00
ret = arizona_hw_params_rate ( substream , params , dai ) ;
if ( ret ! = 0 )
2014-07-22 14:42:06 +04:00
goto restore_aif ;
2012-07-04 23:05:57 +04:00
2014-07-22 14:42:06 +04:00
if ( reconfig ) {
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_BCLK_CTRL ,
ARIZONA_AIF1_BCLK_FREQ_MASK , bclk ) ;
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_TX_BCLK_RATE ,
ARIZONA_AIF1TX_BCPF_MASK , lrclk ) ;
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_RX_BCLK_RATE ,
ARIZONA_AIF1RX_BCPF_MASK , lrclk ) ;
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_FRAME_CTRL_1 ,
ARIZONA_AIF1TX_WL_MASK |
ARIZONA_AIF1TX_SLOT_LEN_MASK , frame ) ;
regmap_update_bits ( arizona - > regmap ,
base + ARIZONA_AIF_FRAME_CTRL_2 ,
ARIZONA_AIF1RX_WL_MASK |
ARIZONA_AIF1RX_SLOT_LEN_MASK , frame ) ;
}
2012-06-19 00:08:44 +04:00
2014-07-22 14:42:06 +04:00
restore_aif :
if ( reconfig ) {
/* Restore AIF TX/RX state */
regmap_update_bits_async ( arizona - > regmap ,
base + ARIZONA_AIF_TX_ENABLES ,
0xff , aif_tx_state ) ;
regmap_update_bits ( arizona - > regmap ,
base + ARIZONA_AIF_RX_ENABLES ,
0xff , aif_rx_state ) ;
}
return ret ;
2012-06-19 00:08:44 +04:00
}
2012-07-05 20:26:59 +04:00
static const char * arizona_dai_clk_str ( int clk_id )
{
switch ( clk_id ) {
case ARIZONA_CLK_SYSCLK :
return " SYSCLK " ;
case ARIZONA_CLK_ASYNCCLK :
return " ASYNCCLK " ;
default :
return " Unknown clock " ;
}
}
2012-07-04 20:32:05 +04:00
static int arizona_dai_set_sysclk ( struct snd_soc_dai * dai ,
int clk_id , unsigned int freq , int dir )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm ( component ) ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2012-07-04 20:32:05 +04:00
struct arizona_dai_priv * dai_priv = & priv - > dai [ dai - > id - 1 ] ;
2012-07-05 20:26:59 +04:00
struct snd_soc_dapm_route routes [ 2 ] ;
2012-07-04 20:32:05 +04:00
switch ( clk_id ) {
case ARIZONA_CLK_SYSCLK :
case ARIZONA_CLK_ASYNCCLK :
break ;
default :
return - EINVAL ;
}
2012-07-05 20:26:59 +04:00
if ( clk_id = = dai_priv - > clk )
return 0 ;
2020-05-15 03:47:11 +03:00
if ( snd_soc_dai_active ( dai ) ) {
2018-02-13 05:03:12 +03:00
dev_err ( component - > dev , " Can't change clock on active DAI %d \n " ,
2012-07-04 20:32:05 +04:00
dai - > id ) ;
return - EBUSY ;
}
2018-02-13 05:03:12 +03:00
dev_dbg ( component - > dev , " Setting AIF%d to %s \n " , dai - > id + 1 ,
2012-12-07 07:49:40 +04:00
arizona_dai_clk_str ( clk_id ) ) ;
2012-07-05 20:26:59 +04:00
memset ( & routes , 0 , sizeof ( routes ) ) ;
routes [ 0 ] . sink = dai - > driver - > capture . stream_name ;
routes [ 1 ] . sink = dai - > driver - > playback . stream_name ;
2012-07-04 20:32:05 +04:00
2012-07-05 20:26:59 +04:00
routes [ 0 ] . source = arizona_dai_clk_str ( dai_priv - > clk ) ;
routes [ 1 ] . source = arizona_dai_clk_str ( dai_priv - > clk ) ;
2015-06-01 11:10:24 +03:00
snd_soc_dapm_del_routes ( dapm , routes , ARRAY_SIZE ( routes ) ) ;
2012-07-05 20:26:59 +04:00
routes [ 0 ] . source = arizona_dai_clk_str ( clk_id ) ;
routes [ 1 ] . source = arizona_dai_clk_str ( clk_id ) ;
2015-06-01 11:10:24 +03:00
snd_soc_dapm_add_routes ( dapm , routes , ARRAY_SIZE ( routes ) ) ;
2012-07-05 20:26:59 +04:00
2012-12-06 13:22:25 +04:00
dai_priv - > clk = clk_id ;
2015-06-01 11:10:24 +03:00
return snd_soc_dapm_sync ( dapm ) ;
2012-07-04 20:32:05 +04:00
}
2012-12-12 11:22:08 +04:00
static int arizona_set_tristate ( struct snd_soc_dai * dai , int tristate )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
2012-12-12 11:22:08 +04:00
int base = dai - > driver - > base ;
unsigned int reg ;
if ( tristate )
reg = ARIZONA_AIF1_TRI ;
else
reg = 0 ;
2018-02-20 19:08:11 +03:00
return snd_soc_component_update_bits ( component ,
base + ARIZONA_AIF_RATE_CTRL ,
ARIZONA_AIF1_TRI , reg ) ;
2012-12-12 11:22:08 +04:00
}
2014-06-04 13:11:06 +04:00
static void arizona_set_channels_to_mask ( struct snd_soc_dai * dai ,
unsigned int base ,
int channels , unsigned int mask )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2014-06-04 13:11:06 +04:00
struct arizona * arizona = priv - > arizona ;
int slot , i ;
for ( i = 0 ; i < channels ; + + i ) {
slot = ffs ( mask ) - 1 ;
if ( slot < 0 )
return ;
regmap_write ( arizona - > regmap , base + i , slot ) ;
mask & = ~ ( 1 < < slot ) ;
}
if ( mask )
arizona_aif_warn ( dai , " Too many channels in TDM mask \n " ) ;
}
static int arizona_set_tdm_slot ( struct snd_soc_dai * dai , unsigned int tx_mask ,
unsigned int rx_mask , int slots , int slot_width )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = dai - > component ;
struct arizona_priv * priv = snd_soc_component_get_drvdata ( component ) ;
2014-06-04 13:11:06 +04:00
struct arizona * arizona = priv - > arizona ;
int base = dai - > driver - > base ;
int rx_max_chan = dai - > driver - > playback . channels_max ;
int tx_max_chan = dai - > driver - > capture . channels_max ;
/* Only support TDM for the physical AIFs */
if ( dai - > id > ARIZONA_MAX_AIF )
return - ENOTSUPP ;
if ( slots = = 0 ) {
tx_mask = ( 1 < < tx_max_chan ) - 1 ;
rx_mask = ( 1 < < rx_max_chan ) - 1 ;
}
arizona_set_channels_to_mask ( dai , base + ARIZONA_AIF_FRAME_CTRL_3 ,
tx_max_chan , tx_mask ) ;
arizona_set_channels_to_mask ( dai , base + ARIZONA_AIF_FRAME_CTRL_11 ,
rx_max_chan , rx_mask ) ;
arizona - > tdm_width [ dai - > id - 1 ] = slot_width ;
arizona - > tdm_slots [ dai - > id - 1 ] = slots ;
return 0 ;
}
2012-06-19 00:08:44 +04:00
const struct snd_soc_dai_ops arizona_dai_ops = {
2012-07-04 20:32:05 +04:00
. startup = arizona_startup ,
2012-06-19 00:08:44 +04:00
. set_fmt = arizona_set_fmt ,
2014-06-04 13:11:06 +04:00
. set_tdm_slot = arizona_set_tdm_slot ,
2012-06-19 00:08:44 +04:00
. hw_params = arizona_hw_params ,
2012-07-04 20:32:05 +04:00
. set_sysclk = arizona_dai_set_sysclk ,
2012-12-12 11:22:08 +04:00
. set_tristate = arizona_set_tristate ,
2012-06-19 00:08:44 +04:00
} ;
2012-07-09 15:16:41 +04:00
EXPORT_SYMBOL_GPL ( arizona_dai_ops ) ;
2012-06-19 00:08:44 +04:00
2013-05-17 16:29:03 +04:00
const struct snd_soc_dai_ops arizona_simple_dai_ops = {
. startup = arizona_startup ,
. hw_params = arizona_hw_params_rate ,
. set_sysclk = arizona_dai_set_sysclk ,
} ;
EXPORT_SYMBOL_GPL ( arizona_simple_dai_ops ) ;
2012-07-04 20:32:05 +04:00
int arizona_init_dai ( struct arizona_priv * priv , int id )
{
struct arizona_dai_priv * dai_priv = & priv - > dai [ id ] ;
dai_priv - > clk = ARIZONA_CLK_SYSCLK ;
2016-02-04 19:29:01 +03:00
dai_priv - > constraint = arizona_constraint ;
2012-07-04 20:32:05 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_dai ) ;
2012-06-19 00:08:44 +04:00
static struct {
unsigned int min ;
unsigned int max ;
u16 fratio ;
int ratio ;
} fll_fratios [ ] = {
{ 0 , 64000 , 4 , 16 } ,
{ 64000 , 128000 , 3 , 8 } ,
{ 128000 , 256000 , 2 , 4 } ,
{ 256000 , 1000000 , 1 , 2 } ,
{ 1000000 , 13500000 , 0 , 1 } ,
} ;
2016-02-10 14:56:13 +03:00
static const unsigned int pseudo_fref_max [ ARIZONA_FLL_MAX_FRATIO ] = {
13500000 ,
6144000 ,
6144000 ,
3072000 ,
3072000 ,
2822400 ,
2822400 ,
1536000 ,
1536000 ,
1536000 ,
1536000 ,
1536000 ,
1536000 ,
1536000 ,
1536000 ,
768000 ,
} ;
2013-03-05 08:08:57 +04:00
static struct {
unsigned int min ;
unsigned int max ;
u16 gain ;
} fll_gains [ ] = {
{ 0 , 256000 , 0 } ,
{ 256000 , 1000000 , 2 } ,
{ 1000000 , 13500000 , 4 } ,
} ;
2012-06-19 00:08:44 +04:00
struct arizona_fll_cfg {
int n ;
2016-09-02 18:52:43 +03:00
unsigned int theta ;
unsigned int lambda ;
2012-06-19 00:08:44 +04:00
int refdiv ;
int outdiv ;
int fratio ;
2013-03-05 08:08:57 +04:00
int gain ;
2012-06-19 00:08:44 +04:00
} ;
2014-03-07 20:34:20 +04:00
static int arizona_validate_fll ( struct arizona_fll * fll ,
unsigned int Fref ,
unsigned int Fout )
2012-06-19 00:08:44 +04:00
{
2014-03-07 20:34:20 +04:00
unsigned int Fvco_min ;
2014-07-09 20:41:49 +04:00
if ( fll - > fout & & Fout ! = fll - > fout ) {
arizona_fll_err ( fll ,
" Can't change output on active FLL \n " ) ;
return - EINVAL ;
}
2014-03-07 20:34:20 +04:00
if ( Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF ) {
arizona_fll_err ( fll ,
" Can't scale %dMHz in to <=13.5MHz \n " ,
Fref ) ;
return - EINVAL ;
}
2012-06-19 00:08:44 +04:00
2014-03-07 20:34:20 +04:00
Fvco_min = ARIZONA_FLL_MIN_FVCO * fll - > vco_mult ;
if ( Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min ) {
arizona_fll_err ( fll , " No FLL_OUTDIV for Fout=%uHz \n " ,
Fout ) ;
return - EINVAL ;
}
return 0 ;
}
2014-03-07 20:34:25 +04:00
static int arizona_find_fratio ( unsigned int Fref , int * fratio )
{
int i ;
/* Find an appropriate FLL_FRATIO */
for ( i = 0 ; i < ARRAY_SIZE ( fll_fratios ) ; i + + ) {
if ( fll_fratios [ i ] . min < = Fref & & Fref < = fll_fratios [ i ] . max ) {
if ( fratio )
* fratio = fll_fratios [ i ] . fratio ;
return fll_fratios [ i ] . ratio ;
}
}
return - EINVAL ;
}
static int arizona_calc_fratio ( struct arizona_fll * fll ,
struct arizona_fll_cfg * cfg ,
unsigned int target ,
unsigned int Fref , bool sync )
{
int init_ratio , ratio ;
int refdiv , div ;
2012-06-19 00:08:44 +04:00
2014-03-07 20:34:25 +04:00
/* Fref must be <=13.5MHz, find initial refdiv */
2012-06-19 00:08:44 +04:00
div = 1 ;
cfg - > refdiv = 0 ;
2014-03-07 20:34:25 +04:00
while ( Fref > ARIZONA_FLL_MAX_FREF ) {
2012-06-19 00:08:44 +04:00
div * = 2 ;
2014-03-07 20:34:25 +04:00
Fref / = 2 ;
2012-06-19 00:08:44 +04:00
cfg - > refdiv + + ;
2014-03-07 20:34:25 +04:00
if ( div > ARIZONA_FLL_MAX_REFDIV )
2012-06-19 00:08:44 +04:00
return - EINVAL ;
2014-03-07 20:34:25 +04:00
}
/* Find an appropriate FLL_FRATIO */
init_ratio = arizona_find_fratio ( Fref , & cfg - > fratio ) ;
if ( init_ratio < 0 ) {
arizona_fll_err ( fll , " Unable to find FRATIO for Fref=%uHz \n " ,
Fref ) ;
return init_ratio ;
}
switch ( fll - > arizona - > type ) {
2015-12-16 20:06:24 +03:00
case WM5102 :
case WM8997 :
return init_ratio ;
2014-03-07 20:34:25 +04:00
case WM5110 :
2015-01-17 18:21:27 +03:00
case WM8280 :
2014-03-07 20:34:25 +04:00
if ( fll - > arizona - > rev < 3 | | sync )
return init_ratio ;
break ;
2015-12-16 20:06:24 +03:00
default :
2015-09-28 16:01:09 +03:00
if ( sync )
return init_ratio ;
break ;
2014-03-07 20:34:25 +04:00
}
cfg - > fratio = init_ratio - 1 ;
/* Adjust FRATIO/refdiv to avoid integer mode if possible */
refdiv = cfg - > refdiv ;
2016-02-10 14:56:13 +03:00
arizona_fll_dbg ( fll , " pseudo: initial ratio=%u fref=%u refdiv=%u \n " ,
init_ratio , Fref , refdiv ) ;
2014-03-07 20:34:25 +04:00
while ( div < = ARIZONA_FLL_MAX_REFDIV ) {
2016-04-21 16:04:14 +03:00
/* start from init_ratio because this may already give a
* fractional N . K
*/
for ( ratio = init_ratio ; ratio > 0 ; ratio - - ) {
if ( target % ( ratio * Fref ) ) {
cfg - > refdiv = refdiv ;
cfg - > fratio = ratio - 1 ;
arizona_fll_dbg ( fll ,
" pseudo: found fref=%u refdiv=%d(%d) ratio=%d \n " ,
Fref , refdiv , div , ratio ) ;
return ratio ;
}
}
for ( ratio = init_ratio + 1 ; ratio < = ARIZONA_FLL_MAX_FRATIO ;
2014-03-07 20:34:25 +04:00
ratio + + ) {
2014-07-09 20:41:45 +04:00
if ( ( ARIZONA_FLL_VCO_CORNER / 2 ) /
2016-02-10 14:56:13 +03:00
( fll - > vco_mult * ratio ) < Fref ) {
arizona_fll_dbg ( fll , " pseudo: hit VCO corner \n " ) ;
2014-07-09 20:41:44 +04:00
break ;
2016-02-10 14:56:13 +03:00
}
if ( Fref > pseudo_fref_max [ ratio - 1 ] ) {
arizona_fll_dbg ( fll ,
" pseudo: exceeded max fref(%u) for ratio=%u \n " ,
pseudo_fref_max [ ratio - 1 ] ,
ratio ) ;
break ;
}
2014-07-09 20:41:44 +04:00
2014-03-07 20:34:25 +04:00
if ( target % ( ratio * Fref ) ) {
cfg - > refdiv = refdiv ;
cfg - > fratio = ratio - 1 ;
2016-02-10 14:56:13 +03:00
arizona_fll_dbg ( fll ,
" pseudo: found fref=%u refdiv=%d(%d) ratio=%d \n " ,
Fref , refdiv , div , ratio ) ;
2014-03-07 20:34:25 +04:00
return ratio ;
}
}
div * = 2 ;
Fref / = 2 ;
refdiv + + ;
init_ratio = arizona_find_fratio ( Fref , NULL ) ;
2016-02-10 14:56:13 +03:00
arizona_fll_dbg ( fll ,
" pseudo: change fref=%u refdiv=%d(%d) ratio=%u \n " ,
Fref , refdiv , div , init_ratio ) ;
2012-06-19 00:08:44 +04:00
}
2014-03-07 20:34:25 +04:00
arizona_fll_warn ( fll , " Falling back to integer mode operation \n " ) ;
return cfg - > fratio + 1 ;
}
2012-06-19 00:08:44 +04:00
static int arizona_calc_fll ( struct arizona_fll * fll ,
struct arizona_fll_cfg * cfg ,
2014-03-07 20:34:25 +04:00
unsigned int Fref , bool sync )
2012-06-19 00:08:44 +04:00
{
unsigned int target , div , gcd_fll ;
int i , ratio ;
2014-03-07 20:34:21 +04:00
arizona_fll_dbg ( fll , " Fref=%u Fout=%u \n " , Fref , fll - > fout ) ;
2012-06-19 00:08:44 +04:00
2012-07-10 20:03:46 +04:00
/* Fvco should be over the targt; don't check the upper bound */
2014-03-07 20:34:22 +04:00
div = ARIZONA_FLL_MIN_OUTDIV ;
while ( fll - > fout * div < ARIZONA_FLL_MIN_FVCO * fll - > vco_mult ) {
2012-06-19 00:08:44 +04:00
div + + ;
2014-03-07 20:34:22 +04:00
if ( div > ARIZONA_FLL_MAX_OUTDIV )
2012-06-19 00:08:44 +04:00
return - EINVAL ;
}
2014-03-07 20:34:22 +04:00
target = fll - > fout * div / fll - > vco_mult ;
2012-06-19 00:08:44 +04:00
cfg - > outdiv = div ;
arizona_fll_dbg ( fll , " Fvco=%dHz \n " , target ) ;
2014-03-07 20:34:25 +04:00
/* Find an appropriate FLL_FRATIO and refdiv */
ratio = arizona_calc_fratio ( fll , cfg , target , Fref , sync ) ;
if ( ratio < 0 )
return ratio ;
2012-06-19 00:08:44 +04:00
/* Apply the division for our remaining calculations */
2014-03-07 20:34:25 +04:00
Fref = Fref / ( 1 < < cfg - > refdiv ) ;
2013-03-05 08:08:57 +04:00
2012-06-19 00:08:44 +04:00
cfg - > n = target / ( ratio * Fref ) ;
2013-02-03 12:18:00 +04:00
if ( target % ( ratio * Fref ) ) {
2012-06-19 00:08:44 +04:00
gcd_fll = gcd ( target , ratio * Fref ) ;
arizona_fll_dbg ( fll , " GCD=%u \n " , gcd_fll ) ;
cfg - > theta = ( target - ( cfg - > n * ratio * Fref ) )
/ gcd_fll ;
cfg - > lambda = ( ratio * Fref ) / gcd_fll ;
} else {
cfg - > theta = 0 ;
cfg - > lambda = 0 ;
}
2013-02-03 12:18:00 +04:00
/* Round down to 16bit range with cost of accuracy lost.
* Denominator must be bigger than numerator so we only
* take care of it .
*/
while ( cfg - > lambda > = ( 1 < < 16 ) ) {
cfg - > theta > > = 1 ;
cfg - > lambda > > = 1 ;
}
2014-03-07 20:34:23 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( fll_gains ) ; i + + ) {
if ( fll_gains [ i ] . min < = Fref & & Fref < = fll_gains [ i ] . max ) {
cfg - > gain = fll_gains [ i ] . gain ;
break ;
}
}
if ( i = = ARRAY_SIZE ( fll_gains ) ) {
arizona_fll_err ( fll , " Unable to find gain for Fref=%uHz \n " ,
Fref ) ;
return - EINVAL ;
}
2016-02-23 17:16:32 +03:00
arizona_fll_dbg ( fll , " N=%d THETA=%d LAMBDA=%d \n " ,
2012-06-19 00:08:44 +04:00
cfg - > n , cfg - > theta , cfg - > lambda ) ;
2016-02-23 17:16:32 +03:00
arizona_fll_dbg ( fll , " FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d) \n " ,
cfg - > fratio , ratio , cfg - > outdiv ,
cfg - > refdiv , 1 < < cfg - > refdiv ) ;
arizona_fll_dbg ( fll , " GAIN=0x%x(%d) \n " , cfg - > gain , 1 < < cfg - > gain ) ;
2012-06-19 00:08:44 +04:00
return 0 ;
}
static void arizona_apply_fll ( struct arizona * arizona , unsigned int base ,
2013-03-05 08:08:57 +04:00
struct arizona_fll_cfg * cfg , int source ,
bool sync )
2012-06-19 00:08:44 +04:00
{
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , base + 3 ,
ARIZONA_FLL1_THETA_MASK , cfg - > theta ) ;
regmap_update_bits_async ( arizona - > regmap , base + 4 ,
ARIZONA_FLL1_LAMBDA_MASK , cfg - > lambda ) ;
regmap_update_bits_async ( arizona - > regmap , base + 5 ,
ARIZONA_FLL1_FRATIO_MASK ,
cfg - > fratio < < ARIZONA_FLL1_FRATIO_SHIFT ) ;
regmap_update_bits_async ( arizona - > regmap , base + 6 ,
ARIZONA_FLL1_CLK_REF_DIV_MASK |
ARIZONA_FLL1_CLK_REF_SRC_MASK ,
cfg - > refdiv < < ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
source < < ARIZONA_FLL1_CLK_REF_SRC_SHIFT ) ;
2012-06-19 00:08:44 +04:00
2014-03-07 20:34:19 +04:00
if ( sync ) {
regmap_update_bits ( arizona - > regmap , base + 0x7 ,
ARIZONA_FLL1_GAIN_MASK ,
cfg - > gain < < ARIZONA_FLL1_GAIN_SHIFT ) ;
} else {
regmap_update_bits ( arizona - > regmap , base + 0x5 ,
ARIZONA_FLL1_OUTDIV_MASK ,
cfg - > outdiv < < ARIZONA_FLL1_OUTDIV_SHIFT ) ;
regmap_update_bits ( arizona - > regmap , base + 0x9 ,
ARIZONA_FLL1_GAIN_MASK ,
cfg - > gain < < ARIZONA_FLL1_GAIN_SHIFT ) ;
}
2013-03-05 08:08:57 +04:00
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , base + 2 ,
ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK ,
ARIZONA_FLL1_CTRL_UPD | cfg - > n ) ;
2012-06-19 00:08:44 +04:00
}
2016-09-02 18:52:44 +03:00
static int arizona_is_enabled_fll ( struct arizona_fll * fll , int base )
2013-02-20 21:28:36 +04:00
{
struct arizona * arizona = fll - > arizona ;
unsigned int reg ;
int ret ;
2016-09-02 18:52:44 +03:00
ret = regmap_read ( arizona - > regmap , base + 1 , & reg ) ;
2013-02-20 21:28:36 +04:00
if ( ret ! = 0 ) {
arizona_fll_err ( fll , " Failed to read current state: %d \n " ,
ret ) ;
return ret ;
}
return reg & ARIZONA_FLL1_ENA ;
}
2016-10-21 16:15:58 +03:00
static int arizona_set_fll_clks ( struct arizona_fll * fll , int base , bool ena )
{
struct arizona * arizona = fll - > arizona ;
unsigned int val ;
struct clk * clk ;
int ret ;
ret = regmap_read ( arizona - > regmap , base + 6 , & val ) ;
if ( ret ! = 0 ) {
arizona_fll_err ( fll , " Failed to read current source: %d \n " ,
ret ) ;
return ret ;
}
val & = ARIZONA_FLL1_CLK_REF_SRC_MASK ;
val > > = ARIZONA_FLL1_CLK_REF_SRC_SHIFT ;
switch ( val ) {
case ARIZONA_FLL_SRC_MCLK1 :
clk = arizona - > mclk [ ARIZONA_MCLK1 ] ;
break ;
case ARIZONA_FLL_SRC_MCLK2 :
clk = arizona - > mclk [ ARIZONA_MCLK2 ] ;
break ;
default :
return 0 ;
}
if ( ena ) {
return clk_prepare_enable ( clk ) ;
} else {
clk_disable_unprepare ( clk ) ;
return 0 ;
}
}
2014-07-09 20:41:47 +04:00
static int arizona_enable_fll ( struct arizona_fll * fll )
2013-02-20 21:28:38 +04:00
{
struct arizona * arizona = fll - > arizona ;
2013-09-16 18:34:35 +04:00
bool use_sync = false ;
2016-09-02 18:52:44 +03:00
int already_enabled = arizona_is_enabled_fll ( fll , fll - > base ) ;
2016-09-02 18:52:45 +03:00
int sync_enabled = arizona_is_enabled_fll ( fll , fll - > base + 0x10 ) ;
2014-03-07 20:34:20 +04:00
struct arizona_fll_cfg cfg ;
2015-08-25 14:43:48 +03:00
int i ;
unsigned int val ;
2013-02-20 21:28:38 +04:00
2014-07-09 20:41:47 +04:00
if ( already_enabled < 0 )
return already_enabled ;
2016-09-02 18:52:45 +03:00
if ( sync_enabled < 0 )
return sync_enabled ;
2014-07-09 20:41:47 +04:00
2014-07-09 20:41:49 +04:00
if ( already_enabled ) {
/* Facilitate smooth refclk across the transition */
2015-11-30 20:37:28 +03:00
regmap_update_bits ( fll - > arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_FREERUN , ARIZONA_FLL1_FREERUN ) ;
udelay ( 32 ) ;
2016-08-30 12:30:40 +03:00
regmap_update_bits_async ( fll - > arizona - > regmap , fll - > base + 0x9 ,
ARIZONA_FLL1_GAIN_MASK , 0 ) ;
2016-10-21 16:15:58 +03:00
if ( arizona_is_enabled_fll ( fll , fll - > base + 0x10 ) > 0 )
arizona_set_fll_clks ( fll , fll - > base + 0x10 , false ) ;
arizona_set_fll_clks ( fll , fll - > base , false ) ;
2014-07-09 20:41:49 +04:00
}
2013-03-04 12:00:19 +04:00
/*
* If we have both REFCLK and SYNCCLK then enable both ,
* otherwise apply the SYNCCLK settings to REFCLK .
*/
2013-09-16 18:34:35 +04:00
if ( fll - > ref_src > = 0 & & fll - > ref_freq & &
fll - > ref_src ! = fll - > sync_src ) {
2014-03-07 20:34:25 +04:00
arizona_calc_fll ( fll , & cfg , fll - > ref_freq , false ) ;
2013-03-04 12:00:19 +04:00
2016-09-02 18:52:43 +03:00
/* Ref path hardcodes lambda to 65536 when sync is on */
if ( fll - > sync_src > = 0 & & cfg . lambda )
cfg . theta = ( cfg . theta * ( 1 < < 16 ) ) / cfg . lambda ;
2014-03-07 20:34:20 +04:00
arizona_apply_fll ( arizona , fll - > base , & cfg , fll - > ref_src ,
2013-03-05 08:08:57 +04:00
false ) ;
2013-09-16 18:34:35 +04:00
if ( fll - > sync_src > = 0 ) {
2014-03-07 20:34:25 +04:00
arizona_calc_fll ( fll , & cfg , fll - > sync_freq , true ) ;
2014-03-07 20:34:20 +04:00
arizona_apply_fll ( arizona , fll - > base + 0x10 , & cfg ,
2013-03-05 08:08:57 +04:00
fll - > sync_src , true ) ;
2013-09-16 18:34:35 +04:00
use_sync = true ;
}
2013-03-04 12:00:19 +04:00
} else if ( fll - > sync_src > = 0 ) {
2014-03-07 20:34:25 +04:00
arizona_calc_fll ( fll , & cfg , fll - > sync_freq , false ) ;
2013-03-04 12:00:19 +04:00
2014-03-07 20:34:20 +04:00
arizona_apply_fll ( arizona , fll - > base , & cfg ,
2013-03-05 08:08:57 +04:00
fll - > sync_src , false ) ;
2013-03-05 20:09:59 +04:00
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 0x11 ,
ARIZONA_FLL1_SYNC_ENA , 0 ) ;
2013-03-04 12:00:19 +04:00
} else {
arizona_fll_err ( fll , " No clocks provided \n " ) ;
2014-07-09 20:41:47 +04:00
return - EINVAL ;
2013-03-04 12:00:19 +04:00
}
2013-02-20 21:28:38 +04:00
2016-09-02 18:52:45 +03:00
if ( already_enabled & & ! ! sync_enabled ! = use_sync )
arizona_fll_warn ( fll , " Synchroniser changed on active FLL \n " ) ;
2013-03-05 08:07:16 +04:00
/*
* Increase the bandwidth if we ' re not using a low frequency
* sync source .
*/
2013-09-16 18:34:35 +04:00
if ( use_sync & & fll - > sync_freq > 100000 )
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 0x17 ,
ARIZONA_FLL1_SYNC_BW , 0 ) ;
2013-03-05 08:07:16 +04:00
else
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 0x17 ,
ARIZONA_FLL1_SYNC_BW ,
ARIZONA_FLL1_SYNC_BW ) ;
2013-03-05 08:07:16 +04:00
2014-07-09 20:41:47 +04:00
if ( ! already_enabled )
2016-08-25 13:39:32 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2013-02-20 21:28:38 +04:00
2016-10-21 16:15:58 +03:00
if ( use_sync ) {
arizona_set_fll_clks ( fll , fll - > base + 0x10 , true ) ;
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 0x11 ,
ARIZONA_FLL1_SYNC_ENA ,
ARIZONA_FLL1_SYNC_ENA ) ;
2016-10-21 16:15:58 +03:00
}
arizona_set_fll_clks ( fll , fll - > base , true ) ;
2016-09-02 18:52:45 +03:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_ENA , ARIZONA_FLL1_ENA ) ;
2013-02-20 21:28:38 +04:00
2014-07-09 20:41:49 +04:00
if ( already_enabled )
regmap_update_bits_async ( arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_FREERUN , 0 ) ;
2015-08-25 14:43:48 +03:00
arizona_fll_dbg ( fll , " Waiting for FLL lock... \n " ) ;
val = 0 ;
for ( i = 0 ; i < 15 ; i + + ) {
if ( i < 5 )
usleep_range ( 200 , 400 ) ;
else
msleep ( 20 ) ;
regmap_read ( arizona - > regmap ,
ARIZONA_INTERRUPT_RAW_STATUS_5 ,
& val ) ;
if ( val & ( ARIZONA_FLL1_CLOCK_OK_STS < < ( fll - > id - 1 ) ) )
break ;
}
if ( i = = 15 )
2013-02-20 21:28:38 +04:00
arizona_fll_warn ( fll , " Timed out waiting for lock \n " ) ;
2015-08-25 14:43:48 +03:00
else
arizona_fll_dbg ( fll , " FLL locked (%d polls) \n " , i ) ;
2014-07-09 20:41:47 +04:00
return 0 ;
2013-02-20 21:28:38 +04:00
}
2013-02-20 21:28:37 +04:00
static void arizona_disable_fll ( struct arizona_fll * fll )
{
struct arizona * arizona = fll - > arizona ;
2016-10-21 16:15:58 +03:00
bool ref_change , sync_change ;
2013-02-20 21:28:37 +04:00
2013-12-12 04:49:22 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_FREERUN , ARIZONA_FLL1_FREERUN ) ;
2013-02-20 21:28:37 +04:00
regmap_update_bits_check ( arizona - > regmap , fll - > base + 1 ,
2016-10-21 16:15:58 +03:00
ARIZONA_FLL1_ENA , 0 , & ref_change ) ;
regmap_update_bits_check ( arizona - > regmap , fll - > base + 0x11 ,
ARIZONA_FLL1_SYNC_ENA , 0 , & sync_change ) ;
2014-07-09 20:41:48 +04:00
regmap_update_bits_async ( arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_FREERUN , 0 ) ;
2013-02-20 21:28:37 +04:00
2016-10-21 16:15:58 +03:00
if ( sync_change )
arizona_set_fll_clks ( fll , fll - > base + 0x10 , false ) ;
if ( ref_change ) {
arizona_set_fll_clks ( fll , fll - > base , false ) ;
2013-02-20 21:28:37 +04:00
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2016-10-21 16:15:58 +03:00
}
2013-02-20 21:28:37 +04:00
}
2013-02-20 21:28:40 +04:00
int arizona_set_fll_refclk ( struct arizona_fll * fll , int source ,
unsigned int Fref , unsigned int Fout )
{
2014-07-09 20:41:47 +04:00
int ret = 0 ;
2013-02-20 21:28:40 +04:00
2013-02-22 21:10:37 +04:00
if ( fll - > ref_src = = source & & fll - > ref_freq = = Fref )
2013-02-20 21:28:40 +04:00
return 0 ;
2014-03-07 20:34:20 +04:00
if ( fll - > fout & & Fref > 0 ) {
ret = arizona_validate_fll ( fll , Fref , fll - > fout ) ;
if ( ret ! = 0 )
return ret ;
2013-02-20 21:28:40 +04:00
}
fll - > ref_src = source ;
fll - > ref_freq = Fref ;
2018-02-20 19:08:11 +03:00
if ( fll - > fout & & Fref > 0 )
2014-07-09 20:41:47 +04:00
ret = arizona_enable_fll ( fll ) ;
2013-02-20 21:28:40 +04:00
2014-07-09 20:41:47 +04:00
return ret ;
2013-02-20 21:28:40 +04:00
}
EXPORT_SYMBOL_GPL ( arizona_set_fll_refclk ) ;
2012-06-19 00:08:44 +04:00
int arizona_set_fll ( struct arizona_fll * fll , int source ,
unsigned int Fref , unsigned int Fout )
{
2014-07-09 20:41:47 +04:00
int ret = 0 ;
2012-06-19 00:08:44 +04:00
2013-03-04 12:00:19 +04:00
if ( fll - > sync_src = = source & &
fll - > sync_freq = = Fref & & fll - > fout = = Fout )
return 0 ;
2013-02-20 21:28:35 +04:00
2013-03-04 12:00:19 +04:00
if ( Fout ) {
if ( fll - > ref_src > = 0 ) {
2014-03-07 20:34:20 +04:00
ret = arizona_validate_fll ( fll , fll - > ref_freq , Fout ) ;
2013-02-20 21:28:35 +04:00
if ( ret ! = 0 )
return ret ;
}
2014-03-07 20:34:20 +04:00
ret = arizona_validate_fll ( fll , Fref , Fout ) ;
2013-03-04 12:00:19 +04:00
if ( ret ! = 0 )
return ret ;
2013-02-20 21:28:35 +04:00
}
2013-03-04 12:00:19 +04:00
fll - > sync_src = source ;
fll - > sync_freq = Fref ;
2013-02-20 21:28:39 +04:00
fll - > fout = Fout ;
2013-02-20 21:28:35 +04:00
2014-07-09 20:41:46 +04:00
if ( Fout )
2014-07-09 20:41:47 +04:00
ret = arizona_enable_fll ( fll ) ;
2014-07-09 20:41:46 +04:00
else
2013-02-20 21:28:37 +04:00
arizona_disable_fll ( fll ) ;
2012-06-19 00:08:44 +04:00
2014-07-09 20:41:47 +04:00
return ret ;
2012-06-19 00:08:44 +04:00
}
EXPORT_SYMBOL_GPL ( arizona_set_fll ) ;
int arizona_init_fll ( struct arizona * arizona , int id , int base , int lock_irq ,
int ok_irq , struct arizona_fll * fll )
{
2013-02-20 21:28:34 +04:00
unsigned int val ;
2012-06-19 00:08:44 +04:00
fll - > id = id ;
fll - > base = base ;
fll - > arizona = arizona ;
2013-02-20 21:28:41 +04:00
fll - > sync_src = ARIZONA_FLL_SRC_NONE ;
2012-06-19 00:08:44 +04:00
2013-02-20 21:28:34 +04:00
/* Configure default refclk to 32kHz if we have one */
regmap_read ( arizona - > regmap , ARIZONA_CLOCK_32K_1 , & val ) ;
switch ( val & ARIZONA_CLK_32K_SRC_MASK ) {
case ARIZONA_CLK_SRC_MCLK1 :
case ARIZONA_CLK_SRC_MCLK2 :
fll - > ref_src = val & ARIZONA_CLK_32K_SRC_MASK ;
break ;
default :
2013-02-20 21:28:41 +04:00
fll - > ref_src = ARIZONA_FLL_SRC_NONE ;
2013-02-20 21:28:34 +04:00
}
fll - > ref_freq = 32768 ;
2012-06-19 00:08:44 +04:00
snprintf ( fll - > lock_name , sizeof ( fll - > lock_name ) , " FLL%d lock " , id ) ;
snprintf ( fll - > clock_ok_name , sizeof ( fll - > clock_ok_name ) ,
" FLL%d clock OK " , id ) ;
2013-01-07 20:41:45 +04:00
regmap_update_bits ( arizona - > regmap , fll - > base + 1 ,
ARIZONA_FLL1_FREERUN , 0 ) ;
2012-06-19 00:08:44 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_init_fll ) ;
2013-01-04 23:31:00 +04:00
/**
* arizona_set_output_mode - Set the mode of the specified output
*
2018-02-13 05:03:12 +03:00
* @ component : Device to configure
2013-01-04 23:31:00 +04:00
* @ output : Output number
* @ diff : True to set the output to differential mode
*
* Some systems use external analogue switches to connect more
* analogue devices to the CODEC than are supported by the device . In
* some systems this requires changing the switched output from single
* ended to differential mode dynamically at runtime , an operation
* supported using this function .
*
* Most systems have a single static configuration and should use
* platform data instead .
*/
2018-02-20 19:08:11 +03:00
int arizona_set_output_mode ( struct snd_soc_component * component , int output ,
bool diff )
2013-01-04 23:31:00 +04:00
{
unsigned int reg , val ;
if ( output < 1 | | output > 6 )
return - EINVAL ;
reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + ( output - 1 ) * 8 ;
if ( diff )
val = ARIZONA_OUT1_MONO ;
else
val = 0 ;
2018-02-20 19:08:11 +03:00
return snd_soc_component_update_bits ( component , reg ,
ARIZONA_OUT1_MONO , val ) ;
2013-01-04 23:31:00 +04:00
}
EXPORT_SYMBOL_GPL ( arizona_set_output_mode ) ;
2015-06-18 15:43:19 +03:00
static const struct soc_enum arizona_adsp2_rate_enum [ ] = {
SOC_VALUE_ENUM_SINGLE ( ARIZONA_DSP1_CONTROL_1 ,
ARIZONA_DSP1_RATE_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_DSP2_CONTROL_1 ,
ARIZONA_DSP1_RATE_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_DSP3_CONTROL_1 ,
ARIZONA_DSP1_RATE_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
SOC_VALUE_ENUM_SINGLE ( ARIZONA_DSP4_CONTROL_1 ,
ARIZONA_DSP1_RATE_SHIFT , 0xf ,
ARIZONA_RATE_ENUM_SIZE ,
arizona_rate_text , arizona_rate_val ) ,
} ;
const struct snd_kcontrol_new arizona_adsp2_rate_controls [ ] = {
SOC_ENUM ( " DSP1 Rate " , arizona_adsp2_rate_enum [ 0 ] ) ,
SOC_ENUM ( " DSP2 Rate " , arizona_adsp2_rate_enum [ 1 ] ) ,
SOC_ENUM ( " DSP3 Rate " , arizona_adsp2_rate_enum [ 2 ] ) ,
SOC_ENUM ( " DSP4 Rate " , arizona_adsp2_rate_enum [ 3 ] ) ,
} ;
EXPORT_SYMBOL_GPL ( arizona_adsp2_rate_controls ) ;
2015-06-25 11:35:11 +03:00
static bool arizona_eq_filter_unstable ( bool mode , __be16 _a , __be16 _b )
{
s16 a = be16_to_cpu ( _a ) ;
s16 b = be16_to_cpu ( _b ) ;
if ( ! mode ) {
return abs ( a ) > = 4096 ;
} else {
if ( abs ( b ) > = 4096 )
return true ;
return ( abs ( ( a < < 16 ) / ( 4096 - b ) ) > = 4096 < < 4 ) ;
}
}
int arizona_eq_coeff_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_kcontrol_component ( kcontrol ) ;
struct arizona * arizona = dev_get_drvdata ( component - > dev - > parent ) ;
2015-06-25 11:35:11 +03:00
struct soc_bytes * params = ( void * ) kcontrol - > private_value ;
unsigned int val ;
__be16 * data ;
int len ;
int ret ;
len = params - > num_regs * regmap_get_val_bytes ( arizona - > regmap ) ;
data = kmemdup ( ucontrol - > value . bytes . data , len , GFP_KERNEL | GFP_DMA ) ;
if ( ! data )
return - ENOMEM ;
data [ 0 ] & = cpu_to_be16 ( ARIZONA_EQ1_B1_MODE ) ;
if ( arizona_eq_filter_unstable ( ! ! data [ 0 ] , data [ 1 ] , data [ 2 ] ) | |
arizona_eq_filter_unstable ( true , data [ 4 ] , data [ 5 ] ) | |
arizona_eq_filter_unstable ( true , data [ 8 ] , data [ 9 ] ) | |
arizona_eq_filter_unstable ( true , data [ 12 ] , data [ 13 ] ) | |
arizona_eq_filter_unstable ( false , data [ 16 ] , data [ 17 ] ) ) {
dev_err ( arizona - > dev , " Rejecting unstable EQ coefficients \n " ) ;
ret = - EINVAL ;
goto out ;
}
ret = regmap_read ( arizona - > regmap , params - > base , & val ) ;
if ( ret ! = 0 )
goto out ;
val & = ~ ARIZONA_EQ1_B1_MODE ;
data [ 0 ] | = cpu_to_be16 ( val ) ;
ret = regmap_raw_write ( arizona - > regmap , params - > base , data , len ) ;
out :
kfree ( data ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_eq_coeff_put ) ;
2015-06-25 11:35:12 +03:00
int arizona_lhpf_coeff_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2018-02-13 05:03:12 +03:00
struct snd_soc_component * component = snd_soc_kcontrol_component ( kcontrol ) ;
struct arizona * arizona = dev_get_drvdata ( component - > dev - > parent ) ;
2015-06-25 11:35:12 +03:00
__be16 * data = ( __be16 * ) ucontrol - > value . bytes . data ;
s16 val = be16_to_cpu ( * data ) ;
if ( abs ( val ) > = 4096 ) {
dev_err ( arizona - > dev , " Rejecting unstable LHPF coefficients \n " ) ;
return - EINVAL ;
}
return snd_soc_bytes_put ( kcontrol , ucontrol ) ;
}
EXPORT_SYMBOL_GPL ( arizona_lhpf_coeff_put ) ;
2017-09-04 18:41:49 +03:00
int arizona_of_get_audio_pdata ( struct arizona * arizona )
{
struct arizona_pdata * pdata = & arizona - > pdata ;
struct device_node * np = arizona - > dev - > of_node ;
struct property * prop ;
const __be32 * cur ;
u32 val ;
u32 pdm_val [ ARIZONA_MAX_PDM_SPK ] ;
int ret ;
int count = 0 ;
count = 0 ;
of_property_for_each_u32 ( np , " wlf,inmode " , prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > inmode ) )
break ;
pdata - > inmode [ count ] = val ;
count + + ;
}
count = 0 ;
of_property_for_each_u32 ( np , " wlf,dmic-ref " , prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > dmic_ref ) )
break ;
pdata - > dmic_ref [ count ] = val ;
count + + ;
}
count = 0 ;
of_property_for_each_u32 ( np , " wlf,out-mono " , prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > out_mono ) )
break ;
pdata - > out_mono [ count ] = ! ! val ;
count + + ;
}
count = 0 ;
of_property_for_each_u32 ( np , " wlf,max-channels-clocked " , prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > max_channels_clocked ) )
break ;
pdata - > max_channels_clocked [ count ] = val ;
count + + ;
}
2017-09-04 18:41:53 +03:00
count = 0 ;
of_property_for_each_u32 ( np , " wlf,out-volume-limit " , prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > out_vol_limit ) )
break ;
pdata - > out_vol_limit [ count ] = val ;
count + + ;
}
2017-09-04 18:41:49 +03:00
ret = of_property_read_u32_array ( np , " wlf,spk-fmt " ,
pdm_val , ARRAY_SIZE ( pdm_val ) ) ;
if ( ret > = 0 )
for ( count = 0 ; count < ARRAY_SIZE ( pdata - > spk_fmt ) ; + + count )
pdata - > spk_fmt [ count ] = pdm_val [ count ] ;
ret = of_property_read_u32_array ( np , " wlf,spk-mute " ,
pdm_val , ARRAY_SIZE ( pdm_val ) ) ;
if ( ret > = 0 )
for ( count = 0 ; count < ARRAY_SIZE ( pdata - > spk_mute ) ; + + count )
pdata - > spk_mute [ count ] = pdm_val [ count ] ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_of_get_audio_pdata ) ;
2012-06-19 00:08:44 +04:00
MODULE_DESCRIPTION ( " ASoC Wolfson Arizona class device support " ) ;
MODULE_AUTHOR ( " Mark Brown <broonie@opensource.wolfsonmicro.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;