aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/arizona.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r--sound/soc/codecs/arizona.c70
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);