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

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
......@@ -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";
};
};
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment