diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic32x4.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic32x4.c | 190 |
1 files changed, 87 insertions, 103 deletions
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index bf3a80237b03..625528500f8d 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -47,21 +47,6 @@ #include "tlv320aic32x4.h" -struct aic32x4_rate_divs { - u32 mclk; - u32 rate; - unsigned long pll_rate; - u16 dosr; - unsigned long ndac_rate; - unsigned long mdac_rate; - u8 aosr; - unsigned long nadc_rate; - unsigned long madc_rate; - unsigned long bdiv_rate; - u8 r_block; - u8 p_block; -}; - struct aic32x4_priv { struct regmap *regmap; u32 sysclk; @@ -307,58 +292,6 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = { 0, 0x0F, 0), }; -static const struct aic32x4_rate_divs aic32x4_divs[] = { - /* 8k rate */ - { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000, - 1024000, 256000, 1, 1 }, - { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000, - 512000, 256000, 1, 1 }, - { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000, - 512000, 256000, 1, 1 }, - /* 11.025k rate */ - { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600, - 1411200, 352800, 1, 1 }, - { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400, - 705600, 352800, 1, 1 }, - /* 16k rate */ - { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000, - 2048000, 512000, 1, 1 }, - { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000, - 1024000, 512000, 1, 1 }, - { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000, - 1024000, 512000, 1, 1 }, - /* 22.05k rate */ - { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200, - 2822400, 705600, 1, 1 }, - { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800, - 1411200, 705600, 1, 1 }, - { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800, - 1411200, 705600, 1, 1 }, - /* 32k rate */ - { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000, - 2048000, 1024000, 1, 1 }, - { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000, - 2048000, 1024000, 1, 1 }, - /* 44.1k rate */ - { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400, - 5644800, 1411200, 1, 1 }, - { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600, - 2822400, 1411200, 1, 1 }, - { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600, - 2822400, 1411200, 1, 1 }, - /* 48k rate */ - { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000, - 6144000, 1536000, 1, 1 }, - { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000, - 3072000, 1536000, 1, 1 }, - { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000, - 3072000, 1536000, 1, 1 }, - - /* 96k rate */ - { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000, - 6144000, 3072000, 1, 9 }, -}; - static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0), SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0), @@ -630,20 +563,6 @@ const struct regmap_config aic32x4_regmap_config = { }; EXPORT_SYMBOL(aic32x4_regmap_config); -static inline int aic32x4_get_divs(int mclk, int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) { - if ((aic32x4_divs[i].rate == rate) - && (aic32x4_divs[i].mclk == mclk)) { - return i; - } - } - printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n"); - return -EINVAL; -} - static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { @@ -745,11 +664,17 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component, } static int aic32x4_setup_clocks(struct snd_soc_component *component, - unsigned int sample_rate, - unsigned int parent_rate) + unsigned int sample_rate) { - int i; + u8 aosr; + u16 dosr; + u8 adc_resource_class, dac_resource_class; + u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac; + u8 dosr_increment; + u16 max_dosr, min_dosr; + unsigned long mclk_rate, adc_clock_rate, dac_clock_rate; int ret; + struct clk *mclk; struct clk_bulk_data clocks[] = { { .id = "pll" }, @@ -759,30 +684,89 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, { .id = "mdac" }, { .id = "bdiv" }, }; - - i = aic32x4_get_divs(parent_rate, sample_rate); - if (i < 0) { - printk(KERN_ERR "aic32x4: sampling rate not supported\n"); - return i; - } - ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks); if (ret) return ret; - clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate); - clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate); - clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate); - clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate); - clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate); - clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate); - - aic32x4_set_aosr(component, aic32x4_divs[i].aosr); - aic32x4_set_dosr(component, aic32x4_divs[i].dosr); + mclk = clk_get_parent(clocks[1].clk); + mclk_rate = clk_get_rate(mclk); + + if (sample_rate <= 48000) { + aosr = 128; + adc_resource_class = 6; + dac_resource_class = 8; + dosr_increment = 8; + aic32x4_set_processing_blocks(component, 1, 1); + } else if (sample_rate <= 96000) { + aosr = 64; + adc_resource_class = 6; + dac_resource_class = 8; + dosr_increment = 4; + aic32x4_set_processing_blocks(component, 1, 9); + } else if (sample_rate == 192000) { + aosr = 32; + adc_resource_class = 3; + dac_resource_class = 4; + dosr_increment = 2; + aic32x4_set_processing_blocks(component, 13, 19); + } else { + dev_err(component->dev, "Sampling rate not supported\n"); + return -EINVAL; + } - aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block); + madc = DIV_ROUND_UP((32 * adc_resource_class), aosr); + max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) * + dosr_increment; + min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) * + dosr_increment; + max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate); + + for (nadc = max_nadc; nadc > 0; --nadc) { + adc_clock_rate = nadc * madc * aosr * sample_rate; + for (dosr = max_dosr; dosr >= min_dosr; + dosr -= dosr_increment) { + min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr); + max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ / + (min_mdac * dosr * sample_rate); + for (mdac = min_mdac; mdac <= 128; ++mdac) { + for (ndac = max_ndac; ndac > 0; --ndac) { + dac_clock_rate = ndac * mdac * dosr * + sample_rate; + if (dac_clock_rate == adc_clock_rate) { + if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) + continue; + + clk_set_rate(clocks[0].clk, + dac_clock_rate); + + clk_set_rate(clocks[1].clk, + sample_rate * aosr * + madc); + clk_set_rate(clocks[2].clk, + sample_rate * aosr); + aic32x4_set_aosr(component, + aosr); + + clk_set_rate(clocks[3].clk, + sample_rate * dosr * + mdac); + clk_set_rate(clocks[4].clk, + sample_rate * dosr); + aic32x4_set_dosr(component, + dosr); + + clk_set_rate(clocks[5].clk, + sample_rate * 32); + return 0; + } + } + } + } + } - return 0; + dev_err(component->dev, + "Could not set clocks to support sample rate.\n"); + return -EINVAL; } static int aic32x4_hw_params(struct snd_pcm_substream *substream, @@ -794,7 +778,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, u8 iface1_reg = 0; u8 dacsetup_reg = 0; - aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk); + aic32x4_setup_clocks(component, params_rate(params)); switch (params_width(params)) { case 16: |