Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cbd840da authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: arizona: Implement OPCLK support



Arizona devices support two output system clocks. Provide support for
configuring these via set_sysclk(). Once the clock API is more useful
we should migrate over to that.

Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 28d528c8
Loading
Loading
Loading
Loading
+66 −0
Original line number Original line Diff line number Diff line
@@ -229,6 +229,69 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
}
}
EXPORT_SYMBOL_GPL(arizona_out_ev);
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 arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
		       int source, unsigned int freq, int dir)
		       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;
		reg = ARIZONA_ASYNC_CLOCK_1;
		clk = &priv->asyncclk;
		clk = &priv->asyncclk;
		break;
		break;
	case ARIZONA_CLK_OPCLK:
	case ARIZONA_CLK_ASYNC_OPCLK:
		return arizona_set_opclk(codec, clk_id, freq);
	default:
	default:
		return -EINVAL;
		return -EINVAL;
	}
	}
+4 −2
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@


#define ARIZONA_CLK_SYSCLK         1
#define ARIZONA_CLK_SYSCLK         1
#define ARIZONA_CLK_ASYNCCLK       2
#define ARIZONA_CLK_ASYNCCLK       2
#define ARIZONA_CLK_OPCLK          3
#define ARIZONA_CLK_ASYNC_OPCLK    4


#define ARIZONA_CLK_SRC_MCLK1    0x0
#define ARIZONA_CLK_SRC_MCLK1    0x0
#define ARIZONA_CLK_SRC_MCLK2    0x1
#define ARIZONA_CLK_SRC_MCLK2    0x1