Enable WM8904 to support common clock framework. And also supports different clk configuration.
Signed-off-by: Bo Shen voice.shen@atmel.com ---
Documentation/devicetree/bindings/sound/wm8904.txt | 57 ++++++++++++++++++++++ sound/soc/codecs/wm8904.c | 39 +++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8904.txt
diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt new file mode 100644 index 0000000..039374d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8904.txt @@ -0,0 +1,57 @@ +WM8904 audio CODEC + +This device supports I2C only. + +Required properties: + - compatible: "wlf,wm8904" + - reg: the I2C address of the device. + + if work with CCF, the following properties as required: + - wlf,sysclk-from-mclk: set the sys clock is driven from mclk, + - wlf,mclk-use-xtal: if the mclk is generated by crystal. + if without this property, the mclk is generated from SOC. + - clocks: which clock generated clock to mclk. + - clock-names: the clock names use for retrieve. + - wlf,mclk-freq: mclk's frequency + + +Pins on the device (for linking into audio routes): + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * MICBIAS + +Examples: + +1. General usage: +codec: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; +}; + +2. Working with CCF supports and using crystall provide mclk: +codec: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + wlf,sysclk-from-mclk; + wlf,mclk-use-xtal; + wlf,mclk-freq = <12000000>; +}; + +3. Working with CCF supports and using SoC provide mclk: +codec: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + wlf,sysclk-from-mclk; + clocks = <&pck0>; + clock-names = "mclk"; + wlf,mclk-freq = <32768>; +}; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 49c35c3..99e3e90 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */
+#include <linux/clk.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -49,6 +50,10 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = { /* codec private data */ struct wm8904_priv { struct regmap *regmap; + struct clk *mclk; + bool sysclk_from_mclk; + bool mclk_use_xtal; + u32 mclk_freq;
enum wm8904_type devtype;
@@ -1828,6 +1833,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
switch (level) { case SND_SOC_BIAS_ON: + if (IS_ENABLED(CONFIG_COMMON_CLK)) + if (!wm8904->mclk_use_xtal) + clk_prepare_enable(wm8904->mclk); break;
case SND_SOC_BIAS_PREPARE: @@ -1894,6 +1902,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + if (!wm8904->mclk_use_xtal) + clk_disable_unprepare(wm8904->mclk); break; } codec->dapm.bias_level = level; @@ -2139,6 +2150,34 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, return ret; }
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) { + struct device_node *np = i2c->dev.of_node; + wm8904->sysclk_from_mclk = + of_property_read_bool(np, "wlf,sysclk-from-mclk"); + if (wm8904->sysclk_from_mclk) { + wm8904->mclk_use_xtal = + of_property_read_bool(np, "wlf,mclk-use-xtal"); + + ret = of_property_read_u32(np, "wlf,mclk-freq", + &wm8904->mclk_freq); + if (ret) { + dev_err(&i2c->dev, "Failed to read mclk freq"); + goto err_enable; + } + + if (!wm8904->mclk_use_xtal) { + wm8904->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(wm8904->mclk)) { + dev_err(&i2c->dev, "Failed to get MCLK\n"); + ret = PTR_ERR(wm8904->mclk); + goto err_enable; + } + + clk_set_rate(wm8904->mclk, wm8904->mclk_freq); + } + } + } + ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val); if (ret < 0) { dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);