From e2280c9040d8bc5039617af35ccf7b8ac4abb428 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 20 Nov 2014 19:07:48 +0800 Subject: ASoC: wm8960: Add device tree support Document the device tree binding for the WM8960 codec, and modify the driver to extract the platform data from device tree, if present. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs/wm8960.c') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..99d6457c87ba 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -125,6 +125,7 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; + struct wm8960_data pdata; }; #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) @@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = { static int wm8960_add_widgets(struct snd_soc_codec *codec) { - struct wm8960_data *pdata = codec->dev->platform_data; struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + struct wm8960_data *pdata = &wm8960->pdata; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w; @@ -961,17 +962,13 @@ static int wm8960_resume(struct snd_soc_codec *codec) static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - struct wm8960_data *pdata = dev_get_platdata(codec->dev); + struct wm8960_data *pdata = &wm8960->pdata; int ret; - wm8960->set_bias_level = wm8960_set_bias_level_out3; - - if (!pdata) { - dev_warn(codec->dev, "No platform data supplied\n"); - } else { - if (pdata->capless) - wm8960->set_bias_level = wm8960_set_bias_level_capless; - } + if (pdata->capless) + wm8960->set_bias_level = wm8960_set_bias_level_capless; + else + wm8960->set_bias_level = wm8960_set_bias_level_out3; ret = wm8960_reset(codec); if (ret < 0) { @@ -1029,6 +1026,18 @@ static const struct regmap_config wm8960_regmap = { .volatile_reg = wm8960_volatile, }; +static void wm8960_set_pdata_from_of(struct i2c_client *i2c, + struct wm8960_data *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + + if (of_property_read_bool(np, "wlf,capless")) + pdata->capless = true; + + if (of_property_read_bool(np, "wlf,shared-lrclk")) + pdata->shared_lrclk = true; +} + static int wm8960_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1045,6 +1054,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); + if (pdata) + memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); + else if (i2c->dev.of_node) + wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + if (pdata && pdata->shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 0x4, 0x4); @@ -1075,10 +1089,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); +static const struct of_device_id wm8960_of_match[] = { + { .compatible = "wlf,wm8960", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8960_of_match); + static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", .owner = THIS_MODULE, + .of_match_table = wm8960_of_match, }, .probe = wm8960_i2c_probe, .remove = wm8960_i2c_remove, -- cgit v1.2.3 From 0a87a6e1c09c3b93d91bf65809e79cf6cf358785 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:33 +0100 Subject: ASoC: wm8960: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'sound/soc/codecs/wm8960.c') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 99d6457c87ba..bc8793cd1d72 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -943,22 +943,6 @@ static struct snd_soc_dai_driver wm8960_dai = { .symmetric_rates = 1, }; -static int wm8960_suspend(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8960_resume(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); @@ -976,8 +960,6 @@ static int wm8960_probe(struct snd_soc_codec *codec) return ret; } - wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Latch the update bits */ snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); @@ -997,21 +979,10 @@ static int wm8960_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int wm8960_remove(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { .probe = wm8960_probe, - .remove = wm8960_remove, - .suspend = wm8960_suspend, - .resume = wm8960_resume, .set_bias_level = wm8960_set_bias_level, + .suspend_bias_off = true, }; static const struct regmap_config wm8960_regmap = { -- cgit v1.2.3 From 3ad5e861a715cbe932cd145d4612c11e5912a72f Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 27 Nov 2014 16:53:08 +0800 Subject: ASoC: wm8960: Move register initialisation to I2C driver probe() We must ensure that the clocking configuration is valid as rapidly as possible. And do software reset before the others registers updates, or the registers will be reset to the default state. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'sound/soc/codecs/wm8960.c') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index bc8793cd1d72..031a1ae71d94 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -128,7 +128,7 @@ struct wm8960_priv { struct wm8960_data pdata; }; -#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) +#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) /* enumerated controls */ static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", @@ -947,31 +947,12 @@ static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_data *pdata = &wm8960->pdata; - int ret; if (pdata->capless) wm8960->set_bias_level = wm8960_set_bias_level_capless; else wm8960->set_bias_level = wm8960_set_bias_level_out3; - ret = wm8960_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - /* Latch the update bits */ - snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100); - snd_soc_add_codec_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls)); wm8960_add_widgets(codec); @@ -1030,7 +1011,13 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, else if (i2c->dev.of_node) wm8960_set_pdata_from_of(i2c, &wm8960->pdata); - if (pdata && pdata->shared_lrclk) { + ret = wm8960_reset(wm8960->regmap); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to issue reset\n"); + return ret; + } + + if (wm8960->pdata.shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 0x4, 0x4); if (ret != 0) { @@ -1040,6 +1027,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, } } + /* Latch the update bits */ + regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); + i2c_set_clientdata(i2c, wm8960); ret = snd_soc_register_codec(&i2c->dev, -- cgit v1.2.3