diff --git a/Documentation/devicetree/bindings/sound/wm8960.txt b/Documentation/devicetree/bindings/sound/wm8960.txt new file mode 100644 index 000000000000..2deb8a3da9c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8960.txt @@ -0,0 +1,31 @@ +WM8960 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8960" + + - reg : the I2C address of the device. + +Optional properties: + - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of + R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins + will be disabled only when ADC (Left and Right) and DAC (Left and Right) + are disabled. + When wm8960 works on synchronize mode and DACLRC pin is used to supply + frame clock, it will no frame clock for captrue unless enable DAC to enable + DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. + + - wlf,capless: This is a boolean property. If present, OUT3 pin will be + enabled and disabled together with HP_L and HP_R pins in response to jack + detect events. + +Example: + +codec: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + + wlf,shared-lrclk; +}; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 09d91d9dc4ee..1173f7fef5a7 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -866,29 +866,6 @@ static struct snd_soc_dai_driver wm8955_dai = { .ops = &wm8955_dai_ops, }; -#ifdef CONFIG_PM -static int wm8955_suspend(struct snd_soc_codec *codec) -{ - struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - - wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); - - regcache_mark_dirty(wm8955->regmap); - - return 0; -} - -static int wm8955_resume(struct snd_soc_codec *codec) -{ - wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm8955_suspend NULL -#define wm8955_resume NULL -#endif - static int wm8955_probe(struct snd_soc_codec *codec) { struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); @@ -964,18 +941,10 @@ err_enable: return ret; } -static int wm8955_remove(struct snd_soc_codec *codec) -{ - wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { .probe = wm8955_probe, - .remove = wm8955_remove, - .suspend = wm8955_suspend, - .resume = wm8955_resume, .set_bias_level = wm8955_set_bias_level, + .suspend_bias_off = true, .controls = wm8955_snd_controls, .num_controls = ARRAY_SIZE(wm8955_snd_controls), diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..031a1ae71d94 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -125,9 +125,10 @@ 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) +#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) /* enumerated controls */ static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", @@ -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; @@ -942,56 +943,15 @@ 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); - struct wm8960_data *pdata = dev_get_platdata(codec->dev); - int ret; + struct wm8960_data *pdata = &wm8960->pdata; - 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; - } - - ret = wm8960_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - 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); - 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); + if (pdata->capless) + wm8960->set_bias_level = wm8960_set_bias_level_capless; + else + wm8960->set_bias_level = wm8960_set_bias_level_out3; snd_soc_add_codec_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls)); @@ -1000,21 +960,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 = { @@ -1029,6 +978,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,7 +1006,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); - if (pdata && pdata->shared_lrclk) { + if (pdata) + memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); + else if (i2c->dev.of_node) + wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + + 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) { @@ -1055,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, @@ -1075,10 +1059,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, diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 41d23e920ad5..eeffd05384b4 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -835,7 +835,6 @@ static struct snd_soc_dai_driver wm8961_dai = { static int wm8961_probe(struct snd_soc_codec *codec) { - struct snd_soc_dapm_context *dapm = &codec->dapm; u16 reg; /* Enable class W */ @@ -871,50 +870,33 @@ static int wm8961_probe(struct snd_soc_codec *codec) reg &= ~WM8961_MANUAL_MODE; snd_soc_write(codec, WM8961_CLOCKING_3, reg); - wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - snd_soc_add_codec_controls(codec, wm8961_snd_controls, - ARRAY_SIZE(wm8961_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, - ARRAY_SIZE(wm8961_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); - - return 0; -} - -static int wm8961_remove(struct snd_soc_codec *codec) -{ - wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } #ifdef CONFIG_PM -static int wm8961_suspend(struct snd_soc_codec *codec) -{ - wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} static int wm8961_resume(struct snd_soc_codec *codec) { snd_soc_cache_sync(codec); - wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } #else -#define wm8961_suspend NULL #define wm8961_resume NULL #endif static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { .probe = wm8961_probe, - .remove = wm8961_remove, - .suspend = wm8961_suspend, .resume = wm8961_resume, .set_bias_level = wm8961_set_bias_level, + .suspend_bias_off = true, + + .controls = wm8961_snd_controls, + .num_controls = ARRAY_SIZE(wm8961_snd_controls), + .dapm_widgets = wm8961_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), }; static const struct regmap_config wm8961_regmap = { diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 61ca4a7cb6ea..1534d88a66e9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3554,8 +3554,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, unsigned int reg; int ret, i, irq_pol, trigger; - wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv), - GFP_KERNEL); + wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL); if (wm8962 == NULL) return -ENOMEM; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 682e9eda1019..ff0e4646b934 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -568,18 +568,6 @@ static struct snd_soc_dai_driver wm8974_dai = { .symmetric_rates = 1, }; -static int wm8974_suspend(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8974_resume(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static const struct regmap_config wm8974_regmap = { .reg_bits = 7, .val_bits = 9, @@ -599,24 +587,13 @@ static int wm8974_probe(struct snd_soc_codec *codec) return ret; } - wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return ret; -} - -/* power down chip */ -static int wm8974_remove(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { .probe = wm8974_probe, - .remove = wm8974_remove, - .suspend = wm8974_suspend, - .resume = wm8974_resume, .set_bias_level = wm8974_set_bias_level, + .suspend_bias_off = true, .controls = wm8974_snd_controls, .num_controls = ARRAY_SIZE(wm8974_snd_controls),