Skip to content

Commit

Permalink
ASoC: rt5677: add API to select ASRC clock source
Browse files Browse the repository at this point in the history
This patch defines an API to select the clock source for specified filters.

Signed-off-by: Oder Chiou <oder_chiou@realtek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Oder Chiou authored and Mark Brown committed Mar 16, 2015
1 parent 05a25fd commit c36aa0a
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 0 deletions.
163 changes: 163 additions & 0 deletions sound/soc/codecs/rt5677.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,169 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
return 0;
}

/**
* rt5677_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 RT5677 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 rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
unsigned int asrc3_mask = 0, asrc3_value = 0;
unsigned int asrc4_mask = 0, asrc4_value = 0;
unsigned int asrc5_mask = 0, asrc5_value = 0;
unsigned int asrc6_mask = 0, asrc6_value = 0;
unsigned int asrc7_mask = 0, asrc7_value = 0;

switch (clk_src) {
case RT5677_CLK_SEL_SYS:
case RT5677_CLK_SEL_I2S1_ASRC:
case RT5677_CLK_SEL_I2S2_ASRC:
case RT5677_CLK_SEL_I2S3_ASRC:
case RT5677_CLK_SEL_I2S4_ASRC:
case RT5677_CLK_SEL_I2S5_ASRC:
case RT5677_CLK_SEL_I2S6_ASRC:
case RT5677_CLK_SEL_SYS2:
case RT5677_CLK_SEL_SYS3:
case RT5677_CLK_SEL_SYS4:
case RT5677_CLK_SEL_SYS5:
case RT5677_CLK_SEL_SYS6:
case RT5677_CLK_SEL_SYS7:
break;

default:
return -EINVAL;
}

/* ASRC 3 */
if (filter_mask & RT5677_DA_STEREO_FILTER) {
asrc3_mask |= RT5677_DA_STO_CLK_SEL_MASK;
asrc3_value = (asrc3_value & ~RT5677_DA_STO_CLK_SEL_MASK)
| (clk_src << RT5677_DA_STO_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DA_MONO2_L_FILTER) {
asrc3_mask |= RT5677_DA_MONO2L_CLK_SEL_MASK;
asrc3_value = (asrc3_value & ~RT5677_DA_MONO2L_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO2L_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DA_MONO2_R_FILTER) {
asrc3_mask |= RT5677_DA_MONO2R_CLK_SEL_MASK;
asrc3_value = (asrc3_value & ~RT5677_DA_MONO2R_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO2R_CLK_SEL_SFT);
}

if (asrc3_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_3, asrc3_mask,
asrc3_value);

/* ASRC 4 */
if (filter_mask & RT5677_DA_MONO3_L_FILTER) {
asrc4_mask |= RT5677_DA_MONO3L_CLK_SEL_MASK;
asrc4_value = (asrc4_value & ~RT5677_DA_MONO3L_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO3L_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DA_MONO3_R_FILTER) {
asrc4_mask |= RT5677_DA_MONO3R_CLK_SEL_MASK;
asrc4_value = (asrc4_value & ~RT5677_DA_MONO3R_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO3R_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DA_MONO4_L_FILTER) {
asrc4_mask |= RT5677_DA_MONO4L_CLK_SEL_MASK;
asrc4_value = (asrc4_value & ~RT5677_DA_MONO4L_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO4L_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DA_MONO4_R_FILTER) {
asrc4_mask |= RT5677_DA_MONO4R_CLK_SEL_MASK;
asrc4_value = (asrc4_value & ~RT5677_DA_MONO4R_CLK_SEL_MASK)
| (clk_src << RT5677_DA_MONO4R_CLK_SEL_SFT);
}

if (asrc4_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_4, asrc4_mask,
asrc4_value);

/* ASRC 5 */
if (filter_mask & RT5677_AD_STEREO1_FILTER) {
asrc5_mask |= RT5677_AD_STO1_CLK_SEL_MASK;
asrc5_value = (asrc5_value & ~RT5677_AD_STO1_CLK_SEL_MASK)
| (clk_src << RT5677_AD_STO1_CLK_SEL_SFT);
}

if (filter_mask & RT5677_AD_STEREO2_FILTER) {
asrc5_mask |= RT5677_AD_STO2_CLK_SEL_MASK;
asrc5_value = (asrc5_value & ~RT5677_AD_STO2_CLK_SEL_MASK)
| (clk_src << RT5677_AD_STO2_CLK_SEL_SFT);
}

if (filter_mask & RT5677_AD_STEREO3_FILTER) {
asrc5_mask |= RT5677_AD_STO3_CLK_SEL_MASK;
asrc5_value = (asrc5_value & ~RT5677_AD_STO3_CLK_SEL_MASK)
| (clk_src << RT5677_AD_STO3_CLK_SEL_SFT);
}

if (filter_mask & RT5677_AD_STEREO4_FILTER) {
asrc5_mask |= RT5677_AD_STO4_CLK_SEL_MASK;
asrc5_value = (asrc5_value & ~RT5677_AD_STO4_CLK_SEL_MASK)
| (clk_src << RT5677_AD_STO4_CLK_SEL_SFT);
}

if (asrc5_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_5, asrc5_mask,
asrc5_value);

/* ASRC 6 */
if (filter_mask & RT5677_AD_MONO_L_FILTER) {
asrc6_mask |= RT5677_AD_MONOL_CLK_SEL_MASK;
asrc6_value = (asrc6_value & ~RT5677_AD_MONOL_CLK_SEL_MASK)
| (clk_src << RT5677_AD_MONOL_CLK_SEL_SFT);
}

if (filter_mask & RT5677_AD_MONO_R_FILTER) {
asrc6_mask |= RT5677_AD_MONOR_CLK_SEL_MASK;
asrc6_value = (asrc6_value & ~RT5677_AD_MONOR_CLK_SEL_MASK)
| (clk_src << RT5677_AD_MONOR_CLK_SEL_SFT);
}

if (asrc6_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_6, asrc6_mask,
asrc6_value);

/* ASRC 7 */
if (filter_mask & RT5677_DSP_OB_0_3_FILTER) {
asrc7_mask |= RT5677_DSP_OB_0_3_CLK_SEL_MASK;
asrc7_value = (asrc7_value & ~RT5677_DSP_OB_0_3_CLK_SEL_MASK)
| (clk_src << RT5677_DSP_OB_0_3_CLK_SEL_SFT);
}

if (filter_mask & RT5677_DSP_OB_4_7_FILTER) {
asrc7_mask |= RT5677_DSP_OB_4_7_CLK_SEL_MASK;
asrc7_value = (asrc7_value & ~RT5677_DSP_OB_4_7_CLK_SEL_MASK)
| (clk_src << RT5677_DSP_OB_4_7_CLK_SEL_SFT);
}

if (asrc7_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
asrc7_value);

return 0;
}
EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);

/* Digital Mixer */
static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
Expand Down
79 changes: 79 additions & 0 deletions sound/soc/codecs/rt5677.h
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,46 @@
#define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7)
#define RT5677_DSP_CLK_SRC_BYPASS (0x1 << 7)

/* ASRC Control 3 (0x85) */
#define RT5677_DA_STO_CLK_SEL_MASK (0xf << 12)
#define RT5677_DA_STO_CLK_SEL_SFT 12
#define RT5677_DA_MONO2L_CLK_SEL_MASK (0xf << 4)
#define RT5677_DA_MONO2L_CLK_SEL_SFT 4
#define RT5677_DA_MONO2R_CLK_SEL_MASK (0xf << 0)
#define RT5677_DA_MONO2R_CLK_SEL_SFT 0

/* ASRC Control 4 (0x86) */
#define RT5677_DA_MONO3L_CLK_SEL_MASK (0xf << 12)
#define RT5677_DA_MONO3L_CLK_SEL_SFT 12
#define RT5677_DA_MONO3R_CLK_SEL_MASK (0xf << 8)
#define RT5677_DA_MONO3R_CLK_SEL_SFT 8
#define RT5677_DA_MONO4L_CLK_SEL_MASK (0xf << 4)
#define RT5677_DA_MONO4L_CLK_SEL_SFT 4
#define RT5677_DA_MONO4R_CLK_SEL_MASK (0xf << 0)
#define RT5677_DA_MONO4R_CLK_SEL_SFT 0

/* ASRC Control 5 (0x87) */
#define RT5677_AD_STO1_CLK_SEL_MASK (0xf << 12)
#define RT5677_AD_STO1_CLK_SEL_SFT 12
#define RT5677_AD_STO2_CLK_SEL_MASK (0xf << 8)
#define RT5677_AD_STO2_CLK_SEL_SFT 8
#define RT5677_AD_STO3_CLK_SEL_MASK (0xf << 4)
#define RT5677_AD_STO3_CLK_SEL_SFT 4
#define RT5677_AD_STO4_CLK_SEL_MASK (0xf << 0)
#define RT5677_AD_STO4_CLK_SEL_SFT 0

/* ASRC Control 6 (0x88) */
#define RT5677_AD_MONOL_CLK_SEL_MASK (0xf << 12)
#define RT5677_AD_MONOL_CLK_SEL_SFT 12
#define RT5677_AD_MONOR_CLK_SEL_MASK (0xf << 8)
#define RT5677_AD_MONOR_CLK_SEL_SFT 8

/* ASRC Control 7 (0x89) */
#define RT5677_DSP_OB_0_3_CLK_SEL_MASK (0xf << 12)
#define RT5677_DSP_OB_0_3_CLK_SEL_SFT 12
#define RT5677_DSP_OB_4_7_CLK_SEL_MASK (0xf << 8)
#define RT5677_DSP_OB_4_7_CLK_SEL_SFT 8

/* VAD Function Control 4 (0x9f) */
#define RT5677_VAD_SRC_MASK (0x7 << 8)
#define RT5677_VAD_SRC_SFT 8
Expand Down Expand Up @@ -1670,6 +1710,42 @@ enum rt5677_type {
RT5676,
};

/* ASRC clock source selection */
enum {
RT5677_CLK_SEL_SYS,
RT5677_CLK_SEL_I2S1_ASRC,
RT5677_CLK_SEL_I2S2_ASRC,
RT5677_CLK_SEL_I2S3_ASRC,
RT5677_CLK_SEL_I2S4_ASRC,
RT5677_CLK_SEL_I2S5_ASRC,
RT5677_CLK_SEL_I2S6_ASRC,
RT5677_CLK_SEL_SYS2,
RT5677_CLK_SEL_SYS3,
RT5677_CLK_SEL_SYS4,
RT5677_CLK_SEL_SYS5,
RT5677_CLK_SEL_SYS6,
RT5677_CLK_SEL_SYS7,
};

/* filter mask */
enum {
RT5677_DA_STEREO_FILTER = 0x1,
RT5677_DA_MONO2_L_FILTER = (0x1 << 1),
RT5677_DA_MONO2_R_FILTER = (0x1 << 2),
RT5677_DA_MONO3_L_FILTER = (0x1 << 3),
RT5677_DA_MONO3_R_FILTER = (0x1 << 4),
RT5677_DA_MONO4_L_FILTER = (0x1 << 5),
RT5677_DA_MONO4_R_FILTER = (0x1 << 6),
RT5677_AD_STEREO1_FILTER = (0x1 << 7),
RT5677_AD_STEREO2_FILTER = (0x1 << 8),
RT5677_AD_STEREO3_FILTER = (0x1 << 9),
RT5677_AD_STEREO4_FILTER = (0x1 << 10),
RT5677_AD_MONO_L_FILTER = (0x1 << 11),
RT5677_AD_MONO_R_FILTER = (0x1 << 12),
RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
};

struct rt5677_priv {
struct snd_soc_codec *codec;
struct rt5677_platform_data pdata;
Expand All @@ -1696,4 +1772,7 @@ struct rt5677_priv {
bool is_vref_slow;
};

int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src);

#endif /* __RT5677_H__ */

0 comments on commit c36aa0a

Please sign in to comment.