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

Commit 20d5c84b authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'asoc/topic/wm8960', 'asoc/topic/wm8978' and...

Merge remote-tracking branches 'asoc/topic/wm8960', 'asoc/topic/wm8978' and 'asoc/topic/zte-tdm' into asoc-next
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
ZTE TDM DAI driver

Required properties:

- compatible : should be one of the following.
       * zte,zx296718-tdm
- reg : physical base address of the controller and length of memory mapped
    region.
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
- clock-names: "wclk" for the wclk.
               "pclk" for the pclk.
-#clock-cells: should be 1.
- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling
    the dma. includes:
	phandle of sysctrl.
	register offset in sysctrl for control dma.
	mask of the register that be written to sysctrl.

Example:

	tdm: tdm@1487000 {
		compatible = "zte,zx296718-tdm";
		reg = <0x01487000 0x1000>;
		clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>;
		clock-names = "wclk", "pclk";
		#clock-cells = <1>;
		pinctrl-names = "default";
		pinctrl-0 = <&tdm_global_pin>;
		zte,tdm-dma-sysctrl = <&sysctrl 0x10c 4>;
	};
+146 −49
Original line number Diff line number Diff line
@@ -604,12 +604,150 @@ static const int bclk_divs[] = {
	120, 160, 220, 240, 320, 320, 320
};

/**
 * wm8960_configure_sysclk - checks if there is a sysclk frequency available
 *	The sysclk must be chosen such that:
 *		- sysclk     = MCLK / sysclk_divs
 *		- lrclk      = sysclk / dac_divs
 *		- 10 * bclk  = sysclk / bclk_divs
 *
 *	If we cannot find an exact match for (sysclk, lrclk, bclk)
 *	triplet, we relax the bclk such that bclk is chosen as the
 *	closest available frequency greater than expected bclk.
 *
 * @wm8960_priv: wm8960 codec private data
 * @mclk: MCLK used to derive sysclk
 * @sysclk_idx: sysclk_divs index for found sysclk
 * @dac_idx: dac_divs index for found lrclk
 * @bclk_idx: bclk_divs index for found bclk
 *
 * Returns:
 *  -1, in case no sysclk frequency available found
 * >=0, in case we could derive bclk and lrclk from sysclk using
 *      (@sysclk_idx, @dac_idx, @bclk_idx) dividers
 */
static
int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
			    int *sysclk_idx, int *dac_idx, int *bclk_idx)
{
	int sysclk, bclk, lrclk;
	int i, j, k;
	int diff, closest = mclk;

	/* marker for no match */
	*bclk_idx = -1;

	bclk = wm8960->bclk;
	lrclk = wm8960->lrclk;

	/* check if the sysclk frequency is available. */
	for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
		if (sysclk_divs[i] == -1)
			continue;
		sysclk = mclk / sysclk_divs[i];
		for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
			if (sysclk != dac_divs[j] * lrclk)
				continue;
			for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
				diff = sysclk - bclk * bclk_divs[k] / 10;
				if (diff == 0) {
					*sysclk_idx = i;
					*dac_idx = j;
					*bclk_idx = k;
					break;
				}
				if (diff > 0 && closest > diff) {
					*sysclk_idx = i;
					*dac_idx = j;
					*bclk_idx = k;
					closest = diff;
				}
			}
			if (k != ARRAY_SIZE(bclk_divs))
				break;
		}
		if (j != ARRAY_SIZE(dac_divs))
			break;
	}
	return *bclk_idx;
}

/**
 * wm8960_configure_pll - checks if there is a PLL out frequency available
 *	The PLL out frequency must be chosen such that:
 *		- sysclk      = lrclk * dac_divs
 *		- freq_out    = sysclk * sysclk_divs
 *		- 10 * sysclk = bclk * bclk_divs
 *
 * 	If we cannot find an exact match for (sysclk, lrclk, bclk)
 * 	triplet, we relax the bclk such that bclk is chosen as the
 * 	closest available frequency greater than expected bclk.
 *
 * @codec: codec structure
 * @freq_in: input frequency used to derive freq out via PLL
 * @sysclk_idx: sysclk_divs index for found sysclk
 * @dac_idx: dac_divs index for found lrclk
 * @bclk_idx: bclk_divs index for found bclk
 *
 * Returns:
 * < 0, in case no PLL frequency out available was found
 * >=0, in case we could derive bclk, lrclk, sysclk from PLL out using
 *      (@sysclk_idx, @dac_idx, @bclk_idx) dividers
 */
static
int wm8960_configure_pll(struct snd_soc_codec *codec, int freq_in,
			 int *sysclk_idx, int *dac_idx, int *bclk_idx)
{
	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
	int sysclk, bclk, lrclk, freq_out;
	int diff, closest, best_freq_out;
	int i, j, k;

	bclk = wm8960->bclk;
	lrclk = wm8960->lrclk;
	closest = freq_in;

	best_freq_out = -EINVAL;
	*sysclk_idx = *dac_idx = *bclk_idx = -1;

	for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
		if (sysclk_divs[i] == -1)
			continue;
		for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
			sysclk = lrclk * dac_divs[j];
			freq_out = sysclk * sysclk_divs[i];

			for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
				if (!is_pll_freq_available(freq_in, freq_out))
					continue;

				diff = sysclk - bclk * bclk_divs[k] / 10;
				if (diff == 0) {
					*sysclk_idx = i;
					*dac_idx = j;
					*bclk_idx = k;
					return freq_out;
				}
				if (diff > 0 && closest > diff) {
					*sysclk_idx = i;
					*dac_idx = j;
					*bclk_idx = k;
					closest = diff;
					best_freq_out = freq_out;
				}
			}
		}
	}

	return best_freq_out;
}
static int wm8960_configure_clocking(struct snd_soc_codec *codec)
{
	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
	int sysclk, bclk, lrclk, freq_out, freq_in;
	int freq_out, freq_in;
	u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
	int i, j, k;
	int ret;

	if (!(iface1 & (1<<6))) {
		dev_dbg(codec->dev,
@@ -623,8 +761,6 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
	}

	freq_in = wm8960->freq_in;
	bclk = wm8960->bclk;
	lrclk = wm8960->lrclk;
	/*
	 * If it's sysclk auto mode, check if the MCLK can provide sysclk or
	 * not. If MCLK can provide sysclk, using MCLK to provide sysclk
@@ -643,60 +779,21 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
	}

	if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
		/* check if the sysclk frequency is available. */
		for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
			if (sysclk_divs[i] == -1)
				continue;
			sysclk = freq_out / sysclk_divs[i];
			for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
				if (sysclk != dac_divs[j] * lrclk)
					continue;
				for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
					if (sysclk == bclk * bclk_divs[k] / 10)
						break;
				if (k != ARRAY_SIZE(bclk_divs))
					break;
			}
			if (j != ARRAY_SIZE(dac_divs))
				break;
		}

		if (i != ARRAY_SIZE(sysclk_divs)) {
		ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k);
		if (ret >= 0) {
			goto configure_clock;
		} else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
			dev_err(codec->dev, "failed to configure clock\n");
			return -EINVAL;
		}
	}
	/* get a available pll out frequency and set pll */
	for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
		if (sysclk_divs[i] == -1)
			continue;
		for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
			sysclk = lrclk * dac_divs[j];
			freq_out = sysclk * sysclk_divs[i];

			for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
				if (sysclk == bclk * bclk_divs[k] / 10 &&
				    is_pll_freq_available(freq_in, freq_out)) {
					wm8960_set_pll(codec,
						       freq_in, freq_out);
					break;
				} else {
					continue;
				}
			}
			if (k != ARRAY_SIZE(bclk_divs))
				break;
		}
		if (j != ARRAY_SIZE(dac_divs))
			break;
	}

	if (i == ARRAY_SIZE(sysclk_divs)) {
		dev_err(codec->dev, "failed to configure clock\n");
		return -EINVAL;
	freq_out = wm8960_configure_pll(codec, freq_in, &i, &j, &k);
	if (freq_out < 0) {
		dev_err(codec->dev, "failed to configure clock via PLL\n");
		return freq_out;
	}
	wm8960_set_pll(codec, freq_in, freq_out);

configure_clock:
	/* configure sysclk clock */
+7 −0
Original line number Diff line number Diff line
@@ -1071,9 +1071,16 @@ static const struct i2c_device_id wm8978_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);

static const struct of_device_id wm8978_of_match[] = {
	{ .compatible = "wlf,wm8978", },
	{ }
};
MODULE_DEVICE_TABLE(of, wm8978_of_match);

static struct i2c_driver wm8978_i2c_driver = {
	.driver = {
		.name = "wm8978",
		.of_match_table = wm8978_of_match,
	},
	.probe =    wm8978_i2c_probe,
	.remove =   wm8978_i2c_remove,
+8 −0
Original line number Diff line number Diff line
@@ -15,3 +15,11 @@ config ZX_I2S
	help
	  Say Y or M if you want to add support for codecs attached to the
	  ZTE ZX I2S interface

config ZX_TDM
        tristate "ZTE ZX TDM Driver Support"
        depends on COMMON_CLK
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to the
          ZTE ZX TDM interface
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_ZX_SPDIF)	+= zx-spdif.o
obj-$(CONFIG_ZX_I2S)	+= zx-i2s.o
obj-$(CONFIG_ZX_TDM)	+= zx-tdm.o
Loading