Skip to content

Commit

Permalink
ASoC: sunxi: i2s: Implement set_sysclk
Browse files Browse the repository at this point in the history
In our i2s driver, we were previously trying to guess which oversample the
user wanted to use by looking at the rate and trying to max it.

However, the cards, and especially simple-card with its mclk-fs property
will already provide the expected oversample ratio by using the set_sysclk
callback.

We can thus implement it and remove the logic to deal with the runtime
guess.

Signed-off-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
mripard authored and broonie committed Nov 9, 2016
1 parent 300a18d commit b2b7b56
Showing 1 changed file with 38 additions and 15 deletions.
53 changes: 38 additions & 15 deletions sound/soc/sunxi/sun4i-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ struct sun4i_i2s {
struct clk *mod_clk;
struct regmap *regmap;

unsigned int mclk_freq;

struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
};
Expand Down Expand Up @@ -158,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
}

static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
{
int i;

for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++)
if (sun4i_i2s_oversample_rates[i] == oversample)
return true;

return false;
}

static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
unsigned int rate,
unsigned int word_size)
{
unsigned int clk_rate;
unsigned int oversample_rate, clk_rate;
int bclk_div, mclk_div;
int ret, i;
int ret;

switch (rate) {
case 176400:
Expand Down Expand Up @@ -197,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
if (ret)
return ret;

/* Always favor the highest oversampling rate */
for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) {
unsigned int oversample_rate = sun4i_i2s_oversample_rates[i];

bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
word_size);
mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
clk_rate,
rate);
oversample_rate = i2s->mclk_freq / rate;
if (!sun4i_i2s_oversample_is_valid(oversample_rate))
return -EINVAL;

if ((bclk_div >= 0) && (mclk_div >= 0))
break;
}
bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
word_size);
if (bclk_div < 0)
return -EINVAL;

if ((bclk_div < 0) || (mclk_div < 0))
mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
clk_rate, rate);
if (mclk_div < 0)
return -EINVAL;

regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
Expand Down Expand Up @@ -481,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
}

static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);

if (clk_id != 0)
return -EINVAL;

i2s->mclk_freq = freq;

return 0;
}

static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.hw_params = sun4i_i2s_hw_params,
.set_fmt = sun4i_i2s_set_fmt,
.set_sysclk = sun4i_i2s_set_sysclk,
.shutdown = sun4i_i2s_shutdown,
.startup = sun4i_i2s_startup,
.trigger = sun4i_i2s_trigger,
Expand Down

0 comments on commit b2b7b56

Please sign in to comment.