diff options
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r-- | sound/soc/codecs/arizona.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 5c9cacaf2d52..c167c896eaee 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -229,6 +229,69 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(arizona_out_ev); +static unsigned int arizona_sysclk_48k_rates[] = { + 6144000, + 12288000, + 22579200, + 49152000, +}; + +static unsigned int arizona_sysclk_44k1_rates[] = { + 5644800, + 11289600, + 24576000, + 45158400, +}; + +static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, + unsigned int freq) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + 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) + rates = arizona_sysclk_44k1_rates; + else + rates = arizona_sysclk_48k_rates; + + for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) && + rates[ref] <= refclk; ref++) { + div = 1; + while (rates[ref] / div >= freq && div < 32) { + if (rates[ref] / div == freq) { + dev_dbg(codec->dev, "Configured %dHz OPCLK\n", + freq); + snd_soc_update_bits(codec, reg, + ARIZONA_OPCLK_DIV_MASK | + ARIZONA_OPCLK_SEL_MASK, + (div << + ARIZONA_OPCLK_DIV_SHIFT) | + ref); + return 0; + } + div++; + } + } + + dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq); + return -EINVAL; +} + int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -252,6 +315,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, reg = ARIZONA_ASYNC_CLOCK_1; clk = &priv->asyncclk; break; + case ARIZONA_CLK_OPCLK: + case ARIZONA_CLK_ASYNC_OPCLK: + return arizona_set_opclk(codec, clk_id, freq); default: return -EINVAL; } @@ -426,7 +492,7 @@ static const int arizona_44k1_bclk_rates[] = { 940800, 1411200, 1881600, - 2882400, + 2822400, 3763200, 5644800, 7526400, @@ -666,7 +732,7 @@ static irqreturn_t arizona_fll_lock(int irq, void *data) { struct arizona_fll *fll = data; - arizona_fll_dbg(fll, "Locked\n"); + arizona_fll_dbg(fll, "Lock status changed\n"); complete(&fll->lock); |