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

Commit 171a0138 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown
Browse files

ASoC: ak4642: enable to use MCKO as fixed rate output pin on DT



ak4642 chip can output clock via MCKO pin as audio reference clock.
This patch supports it on DT

Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2719a752
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -7,7 +7,14 @@ Required properties:
  - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
  - reg : The chip select number on the I2C bus

Example:
Optional properties:

  - #clock-cells :		common clock binding; shall be set to 0
  - clocks :			common clock binding; MCKI clock
  - clock-frequency :		common clock binding; frequency of MCKO
  - clock-output-names :	common clock binding; MCKO clock name

Example 1:

&i2c {
	ak4648: ak4648@0x12 {
@@ -15,3 +22,16 @@ Example:
		reg = <0x12>;
	};
};

Example 2:

&i2c {
	ak4643: codec@12 {
		compatible = "asahi-kasei,ak4643";
		reg = <0x12>;
		#clock-cells = <0>;
		clocks = <&audio_clock>;
		clock-frequency = <12288000>;
		clock-output-names = "ak4643_mcko";
	};
};
+93 −48
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
 * AK4648 is tested.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -128,11 +130,8 @@
#define I2S		(3 << 0)

/* MD_CTL2 */
#define FS0		(1 << 0)
#define FS1		(1 << 1)
#define FS2		(1 << 2)
#define FS3		(1 << 5)
#define FS_MASK		(FS0 | FS1 | FS2 | FS3)
#define FS(val)		(((val & 0x7) << 0) | ((val & 0x8) << 2))
#define PS(val)		((val & 0x3) << 6)

/* MD_CTL3 */
#define BST1		(1 << 3)
@@ -147,6 +146,7 @@ struct ak4642_drvdata {

struct ak4642_priv {
	const struct ak4642_drvdata *drvdata;
	struct clk *mcko;
};

/*
@@ -430,56 +430,55 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
	return 0;
}

static int ak4642_set_mcko(struct snd_soc_codec *codec,
			   u32 frequency)
{
	u32 fs_list[] = {
		[0] = 8000,
		[1] = 12000,
		[2] = 16000,
		[3] = 24000,
		[4] = 7350,
		[5] = 11025,
		[6] = 14700,
		[7] = 22050,
		[10] = 32000,
		[11] = 48000,
		[14] = 29400,
		[15] = 44100,
	};
	u32 ps_list[] = {
		[0] = 256,
		[1] = 128,
		[2] = 64,
		[3] = 32
	};
	int ps, fs;

	for (ps = 0; ps < ARRAY_SIZE(ps_list); ps++) {
		for (fs = 0; fs < ARRAY_SIZE(fs_list); fs++) {
			if (frequency == ps_list[ps] * fs_list[fs]) {
				snd_soc_write(codec, MD_CTL2, PS(ps) | FS(fs));
				return 0;
			}
		}
	}

	return 0;
}

static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	u8 rate;
	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
	u32 rate = clk_get_rate(priv->mcko);

	switch (params_rate(params)) {
	case 7350:
		rate = FS2;
		break;
	case 8000:
		rate = 0;
		break;
	case 11025:
		rate = FS2 | FS0;
		break;
	case 12000:
		rate = FS0;
		break;
	case 14700:
		rate = FS2 | FS1;
		break;
	case 16000:
		rate = FS1;
		break;
	case 22050:
		rate = FS2 | FS1 | FS0;
		break;
	case 24000:
		rate = FS1 | FS0;
		break;
	case 29400:
		rate = FS3 | FS2 | FS1;
		break;
	case 32000:
		rate = FS3 | FS1;
		break;
	case 44100:
		rate = FS3 | FS2 | FS1 | FS0;
		break;
	case 48000:
		rate = FS3 | FS1 | FS0;
		break;
	default:
		return -EINVAL;
	}
	snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
	if (!rate)
		rate = params_rate(params) * 256;

	return 0;
	return ak4642_set_mcko(codec, rate);
}

static int ak4642_set_bias_level(struct snd_soc_codec *codec,
@@ -532,7 +531,18 @@ static int ak4642_resume(struct snd_soc_codec *codec)
	return 0;
}

static int ak4642_probe(struct snd_soc_codec *codec)
{
	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);

	if (priv->mcko)
		ak4642_set_mcko(codec, clk_get_rate(priv->mcko));

	return 0;
}

static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
	.probe			= ak4642_probe,
	.resume			= ak4642_resume,
	.set_bias_level		= ak4642_set_bias_level,
	.controls		= ak4642_snd_controls,
@@ -580,6 +590,35 @@ static const struct ak4642_drvdata ak4648_drvdata = {
	.extended_frequencies = 1,
};

#ifdef CONFIG_COMMON_CLK
static struct clk *ak4642_of_parse_mcko(struct device *dev)
{
	struct device_node *np = dev->of_node;
	struct clk *clk;
	const char *clk_name = np->name;
	const char *parent_clk_name = NULL;
	u32 rate;

	if (of_property_read_u32(np, "clock-frequency", &rate))
		return NULL;

	if (of_property_read_bool(np, "clocks"))
		parent_clk_name = of_clk_get_parent_name(np, 0);

	of_property_read_string(np, "clock-output-names", &clk_name);

	clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name,
				      (parent_clk_name) ? 0 : CLK_IS_ROOT,
				      rate);
	if (!IS_ERR(clk))
		of_clk_add_provider(np, of_clk_src_simple_get, clk);

	return clk;
}
#else
#define ak4642_of_parse_mcko(d) 0
#endif

static const struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
@@ -589,10 +628,15 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
	const struct ak4642_drvdata *drvdata = NULL;
	struct regmap *regmap;
	struct ak4642_priv *priv;
	struct clk *mcko = NULL;

	if (np) {
		const struct of_device_id *of_id;

		mcko = ak4642_of_parse_mcko(dev);
		if (IS_ERR(mcko))
			mcko = NULL;

		of_id = of_match_device(ak4642_of_match, dev);
		if (of_id)
			drvdata = of_id->data;
@@ -610,6 +654,7 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
		return -ENOMEM;

	priv->drvdata = drvdata;
	priv->mcko = mcko;

	i2c_set_clientdata(i2c, priv);