ASoC: rt5645: add API to select ASRC clock source

This patch defines an API to select the clock source for specified filters.

Signed-off-by: Fang, Yang A <yang.a.fang@intel.com>
Acked-by: Kevin Strasser <kevin.strasser@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Fang, Yang A 2015-02-04 18:19:31 -08:00 committed by Mark Brown
parent 5c4ca99df7
commit 79080a8b42
2 changed files with 112 additions and 41 deletions

View File

@ -613,6 +613,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
}
/**
* rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
* @codec: SoC audio codec device.
* @filter_mask: mask of filters.
* @clk_src: clock source
*
* The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
* only support standard 32fs or 64fs i2s format, ASRC should be enabled to
* support special i2s clock format such as Intel's 100fs(100 * sampling rate).
* ASRC function will track i2s clock and generate a corresponding system clock
* for codec. This function provides an API to select the clock source for a
* set of filters specified by the mask. And the codec driver will turn on ASRC
* for these filters if ASRC is selected as their clock source.
*/
int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src)
{
unsigned int asrc2_mask = 0;
unsigned int asrc2_value = 0;
unsigned int asrc3_mask = 0;
unsigned int asrc3_value = 0;
switch (clk_src) {
case RT5645_CLK_SEL_SYS:
case RT5645_CLK_SEL_I2S1_ASRC:
case RT5645_CLK_SEL_I2S2_ASRC:
case RT5645_CLK_SEL_SYS2:
break;
default:
return -EINVAL;
}
if (filter_mask & RT5645_DA_STEREO_FILTER) {
asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
| (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
}
if (filter_mask & RT5645_DA_MONO_L_FILTER) {
asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
| (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
}
if (filter_mask & RT5645_DA_MONO_R_FILTER) {
asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
| (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
}
if (filter_mask & RT5645_AD_STEREO_FILTER) {
asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
| (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
}
if (filter_mask & RT5645_AD_MONO_L_FILTER) {
asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
| (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
}
if (filter_mask & RT5645_AD_MONO_R_FILTER) {
asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
| (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
}
if (asrc2_mask)
snd_soc_update_bits(codec, RT5645_ASRC_2,
asrc2_mask, asrc2_value);
if (asrc3_mask)
snd_soc_update_bits(codec, RT5645_ASRC_3,
asrc3_mask, asrc3_value);
return 0;
}
EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
/* Digital Mixer */
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,

View File

@ -1120,50 +1120,27 @@
#define RT5645_DMIC_2_M_NOR (0x0 << 8)
#define RT5645_DMIC_2_M_ASYN (0x1 << 8)
/* ASRC clock source selection (0x84, 0x85) */
#define RT5645_CLK_SEL_SYS (0x0)
#define RT5645_CLK_SEL_I2S1_ASRC (0x1)
#define RT5645_CLK_SEL_I2S2_ASRC (0x2)
#define RT5645_CLK_SEL_SYS2 (0x5)
/* ASRC Control 2 (0x84) */
#define RT5645_MDA_L_M_MASK (0x1 << 15)
#define RT5645_MDA_L_M_SFT 15
#define RT5645_MDA_L_M_NOR (0x0 << 15)
#define RT5645_MDA_L_M_ASYN (0x1 << 15)
#define RT5645_MDA_R_M_MASK (0x1 << 14)
#define RT5645_MDA_R_M_SFT 14
#define RT5645_MDA_R_M_NOR (0x0 << 14)
#define RT5645_MDA_R_M_ASYN (0x1 << 14)
#define RT5645_MAD_L_M_MASK (0x1 << 13)
#define RT5645_MAD_L_M_SFT 13
#define RT5645_MAD_L_M_NOR (0x0 << 13)
#define RT5645_MAD_L_M_ASYN (0x1 << 13)
#define RT5645_MAD_R_M_MASK (0x1 << 12)
#define RT5645_MAD_R_M_SFT 12
#define RT5645_MAD_R_M_NOR (0x0 << 12)
#define RT5645_MAD_R_M_ASYN (0x1 << 12)
#define RT5645_ADC_M_MASK (0x1 << 11)
#define RT5645_ADC_M_SFT 11
#define RT5645_ADC_M_NOR (0x0 << 11)
#define RT5645_ADC_M_ASYN (0x1 << 11)
#define RT5645_STO_DAC_M_MASK (0x1 << 5)
#define RT5645_STO_DAC_M_SFT 5
#define RT5645_STO_DAC_M_NOR (0x0 << 5)
#define RT5645_STO_DAC_M_ASYN (0x1 << 5)
#define RT5645_I2S1_R_D_MASK (0x1 << 4)
#define RT5645_I2S1_R_D_SFT 4
#define RT5645_I2S1_R_D_DIS (0x0 << 4)
#define RT5645_I2S1_R_D_EN (0x1 << 4)
#define RT5645_I2S2_R_D_MASK (0x1 << 3)
#define RT5645_I2S2_R_D_SFT 3
#define RT5645_I2S2_R_D_DIS (0x0 << 3)
#define RT5645_I2S2_R_D_EN (0x1 << 3)
#define RT5645_PRE_SCLK_MASK (0x3)
#define RT5645_PRE_SCLK_SFT 0
#define RT5645_PRE_SCLK_512 (0x0)
#define RT5645_PRE_SCLK_1024 (0x1)
#define RT5645_PRE_SCLK_2048 (0x2)
#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12)
#define RT5645_DA_STO_CLK_SEL_SFT 12
#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8)
#define RT5645_DA_MONOL_CLK_SEL_SFT 8
#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4)
#define RT5645_DA_MONOR_CLK_SEL_SFT 4
#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0)
#define RT5645_AD_STO1_CLK_SEL_SFT 0
/* ASRC Control 3 (0x85) */
#define RT5645_I2S1_RATE_MASK (0xf << 12)
#define RT5645_I2S1_RATE_SFT 12
#define RT5645_I2S2_RATE_MASK (0xf << 8)
#define RT5645_I2S2_RATE_SFT 8
#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4)
#define RT5645_AD_MONOL_CLK_SEL_SFT 4
#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0)
#define RT5645_AD_MONOR_CLK_SEL_SFT 0
/* ASRC Control 4 (0x89) */
#define RT5645_I2S1_PD_MASK (0x7 << 12)
@ -2189,6 +2166,19 @@ enum {
CODEC_TYPE_RT5650,
};
/* filter mask */
enum {
RT5645_DA_STEREO_FILTER = 0x1,
RT5645_DA_MONO_L_FILTER = (0x1 << 1),
RT5645_DA_MONO_R_FILTER = (0x1 << 2),
RT5645_AD_STEREO_FILTER = (0x1 << 3),
RT5645_AD_MONO_L_FILTER = (0x1 << 4),
RT5645_AD_MONO_R_FILTER = (0x1 << 5),
};
int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src);
struct rt5645_priv {
struct snd_soc_codec *codec;
struct rt5645_platform_data pdata;