|
@@ -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;
|
|
|
}
|