diff options
Diffstat (limited to 'sound/soc/codecs/wm8904.c')
| -rw-r--r-- | sound/soc/codecs/wm8904.c | 393 |
1 files changed, 162 insertions, 231 deletions
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 812acd83fb4..f7c549949c5 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1,7 +1,7 @@ /* * wm8904.c -- WM8904 ALSA SoC Audio driver * - * Copyright 2009 Wolfson Microelectronics plc + * Copyright 2009-12 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * @@ -100,7 +100,7 @@ static const struct reg_default wm8904_reg_defaults[] = { { 14, 0x0000 }, /* R14 - Power Management 2 */ { 15, 0x0000 }, /* R15 - Power Management 3 */ { 18, 0x0000 }, /* R18 - Power Management 6 */ - { 19, 0x945E }, /* R20 - Clock Rates 0 */ + { 20, 0x945E }, /* R20 - Clock Rates 0 */ { 21, 0x0C05 }, /* R21 - Clock Rates 1 */ { 22, 0x0006 }, /* R22 - Clock Rates 2 */ { 24, 0x0050 }, /* R24 - Audio Interface 0 */ @@ -314,11 +314,6 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg) } } -static int wm8904_reset(struct snd_soc_codec *codec) -{ - return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0); -} - static int wm8904_configure_clocking(struct snd_soc_codec *codec) { struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); @@ -396,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec) static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -414,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->drc_cfg; @@ -467,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec) static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_pdata *pdata = wm8904->pdata; int value = ucontrol->value.integer.value[0]; @@ -485,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg; @@ -525,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec) static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wm8904->deemph; @@ -535,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); int deemph = ucontrol->value.enumerated.item[0]; @@ -557,23 +552,25 @@ static const char *input_mode_text[] = { "Single-Ended", "Differential Line", "Differential Mic" }; -static const struct soc_enum lin_mode = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(lin_mode, + WM8904_ANALOGUE_LEFT_INPUT_1, 0, + input_mode_text); -static const struct soc_enum rin_mode = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); +static SOC_ENUM_SINGLE_DECL(rin_mode, + WM8904_ANALOGUE_RIGHT_INPUT_1, 0, + input_mode_text); static const char *hpf_mode_text[] = { "Hi-fi", "Voice 1", "Voice 2", "Voice 3" }; -static const struct soc_enum hpf_mode = - SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); +static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5, + hpf_mode_text); static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); unsigned int val; int ret; @@ -608,21 +605,15 @@ SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), SOC_ENUM("High Pass Filter Mode", hpf_mode), - -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "ADC 128x OSR Switch", - .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, - .put = wm8904_adc_osr_put, - .private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0), -}, +SOC_SINGLE_EXT("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0, + snd_soc_get_volsw, wm8904_adc_osr_put), }; static const char *drc_path_text[] = { "ADC", "DAC" }; -static const struct soc_enum drc_path = - SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); +static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text); static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { SOC_SINGLE_TLV("Digital Playback Boost Volume", @@ -668,7 +659,8 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv), static int cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - BUG_ON(event != SND_SOC_DAPM_POST_PMU); + if (WARN_ON(event != SND_SOC_DAPM_POST_PMU)) + return -EINVAL; /* Maximum startup time */ udelay(500); @@ -750,7 +742,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, dcs_r = 3; break; default: - BUG(); + WARN(1, "Invalid reg %d\n", reg); return -EINVAL; } @@ -867,14 +859,14 @@ static const char *lin_text[] = { "IN1L", "IN2L", "IN3L" }; -static const struct soc_enum lin_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text); +static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2, + lin_text); static const struct snd_kcontrol_new lin_mux = SOC_DAPM_ENUM("Left Capture Mux", lin_enum); -static const struct soc_enum lin_inv_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text); +static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4, + lin_text); static const struct snd_kcontrol_new lin_inv_mux = SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); @@ -883,14 +875,14 @@ static const char *rin_text[] = { "IN1R", "IN2R", "IN3R" }; -static const struct soc_enum rin_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text); +static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2, + rin_text); static const struct snd_kcontrol_new rin_mux = SOC_DAPM_ENUM("Right Capture Mux", rin_enum); -static const struct soc_enum rin_inv_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text); +static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4, + rin_text); static const struct snd_kcontrol_new rin_inv_mux = SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); @@ -899,26 +891,26 @@ static const char *aif_text[] = { "Left", "Right" }; -static const struct soc_enum aifoutl_enum = - SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7, + aif_text); static const struct snd_kcontrol_new aifoutl_mux = SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); -static const struct soc_enum aifoutr_enum = - SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6, + aif_text); static const struct snd_kcontrol_new aifoutr_mux = SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); -static const struct soc_enum aifinl_enum = - SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5, + aif_text); static const struct snd_kcontrol_new aifinl_mux = SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); -static const struct soc_enum aifinr_enum = - SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text); +static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4, + aif_text); static const struct snd_kcontrol_new aifinr_mux = SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); @@ -1000,42 +992,42 @@ static const char *out_mux_text[] = { "DAC", "Bypass" }; -static const struct soc_enum hpl_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3, + out_mux_text); static const struct snd_kcontrol_new hpl_mux = SOC_DAPM_ENUM("HPL Mux", hpl_enum); -static const struct soc_enum hpr_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2, + out_mux_text); static const struct snd_kcontrol_new hpr_mux = SOC_DAPM_ENUM("HPR Mux", hpr_enum); -static const struct soc_enum linel_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1, + out_mux_text); static const struct snd_kcontrol_new linel_mux = SOC_DAPM_ENUM("LINEL Mux", linel_enum); -static const struct soc_enum liner_enum = - SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); +static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0, + out_mux_text); static const struct snd_kcontrol_new liner_mux = - SOC_DAPM_ENUM("LINEL Mux", liner_enum); + SOC_DAPM_ENUM("LINER Mux", liner_enum); static const char *sidetone_text[] = { "None", "Left", "Right" }; -static const struct soc_enum dacl_sidetone_enum = - SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2, + sidetone_text); static const struct snd_kcontrol_new dacl_sidetone_mux = SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); -static const struct soc_enum dacr_sidetone_enum = - SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0, + sidetone_text); static const struct snd_kcontrol_new dacr_sidetone_mux = SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); @@ -1190,8 +1182,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_new_controls(dapm, wm8904_dapm_widgets, ARRAY_SIZE(wm8904_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, core_intercon, - ARRAY_SIZE(core_intercon)); snd_soc_dapm_add_routes(dapm, adc_intercon, ARRAY_SIZE(adc_intercon)); snd_soc_dapm_add_routes(dapm, dac_intercon, @@ -1214,7 +1204,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec) break; } - snd_soc_dapm_new_widgets(dapm); return 0; } @@ -1456,7 +1445,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_B: - aif1 |= WM8904_AIF_LRCLK_INV; + aif1 |= 0x3 | WM8904_AIF_LRCLK_INV; case SND_SOC_DAIFMT_DSP_A: aif1 |= 0x3; break; @@ -1945,25 +1934,6 @@ static struct snd_soc_dai_driver wm8904_dai = { .symmetric_rates = 1, }; -#ifdef CONFIG_PM -static int wm8904_suspend(struct snd_soc_codec *codec) -{ - wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8904_resume(struct snd_soc_codec *codec) -{ - wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm8904_suspend NULL -#define wm8904_resume NULL -#endif - static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) { struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); @@ -2012,7 +1982,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", wm8904->num_retune_mobile_texts); - wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; + wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts; wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; ret = snd_soc_add_codec_controls(codec, &control, 1); @@ -2053,7 +2023,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) for (i = 0; i < pdata->num_drc_cfgs; i++) wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; - wm8904->drc_enum.max = pdata->num_drc_cfgs; + wm8904->drc_enum.items = pdata->num_drc_cfgs; wm8904->drc_enum.texts = wm8904->drc_texts; ret = snd_soc_add_codec_controls(codec, &control, 1); @@ -2078,10 +2048,6 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) static int wm8904_probe(struct snd_soc_codec *codec) { struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - struct wm8904_pdata *pdata = wm8904->pdata; - int ret, i; - - codec->control_data = wm8904->regmap; switch (wm8904->devtype) { case WM8904: @@ -2095,89 +2061,143 @@ static int wm8904_probe(struct snd_soc_codec *codec) return -EINVAL; } - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + wm8904_handle_pdata(codec); + + wm8904_add_widgets(codec); + + return 0; +} + +static int wm8904_remove(struct snd_soc_codec *codec) +{ + struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); + + kfree(wm8904->retune_mobile_texts); + kfree(wm8904->drc_texts); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { + .probe = wm8904_probe, + .remove = wm8904_remove, + .set_bias_level = wm8904_set_bias_level, + .idle_bias_off = true, +}; + +static const struct regmap_config wm8904_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = WM8904_MAX_REGISTER, + .volatile_reg = wm8904_volatile_register, + .readable_reg = wm8904_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8904_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), +}; + +static int wm8904_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8904_priv *wm8904; + unsigned int val; + int ret, i; + + wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), + GFP_KERNEL); + if (wm8904 == NULL) + return -ENOMEM; + + wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap); + if (IS_ERR(wm8904->regmap)) { + ret = PTR_ERR(wm8904->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); return ret; } + wm8904->devtype = id->driver_data; + i2c_set_clientdata(i2c, wm8904); + wm8904->pdata = i2c->dev.platform_data; + for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) wm8904->supplies[i].supply = wm8904_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies), - wm8904->supplies); + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; } - ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID); + ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val); if (ret < 0) { - dev_err(codec->dev, "Failed to read ID register\n"); + dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); goto err_enable; } - if (ret != 0x8904) { - dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret); + if (val != 0x8904) { + dev_err(&i2c->dev, "Device is not a WM8904, ID is %x\n", val); ret = -EINVAL; goto err_enable; } - ret = snd_soc_read(codec, WM8904_REVISION); + ret = regmap_read(wm8904->regmap, WM8904_REVISION, &val); if (ret < 0) { - dev_err(codec->dev, "Failed to read device revision: %d\n", + dev_err(&i2c->dev, "Failed to read device revision: %d\n", ret); goto err_enable; } - dev_info(codec->dev, "revision %c\n", ret + 'A'); + dev_info(&i2c->dev, "revision %c\n", val + 'A'); - ret = wm8904_reset(codec); + ret = regmap_write(wm8904->regmap, WM8904_SW_RESET_AND_ID, 0); if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); + dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); goto err_enable; } - regcache_cache_only(wm8904->regmap, true); /* Change some default settings - latch VU and enable ZC */ - snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT, - WM8904_ADC_VU, WM8904_ADC_VU); - snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT, - WM8904_ADC_VU, WM8904_ADC_VU); - snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT, - WM8904_DAC_VU, WM8904_DAC_VU); - snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT, - WM8904_DAC_VU, WM8904_DAC_VU); - snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT, - WM8904_HPOUT_VU | WM8904_HPOUTLZC, - WM8904_HPOUT_VU | WM8904_HPOUTLZC); - snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT, - WM8904_HPOUT_VU | WM8904_HPOUTRZC, - WM8904_HPOUT_VU | WM8904_HPOUTRZC); - snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT, - WM8904_LINEOUT_VU | WM8904_LINEOUTLZC, - WM8904_LINEOUT_VU | WM8904_LINEOUTLZC); - snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT, - WM8904_LINEOUT_VU | WM8904_LINEOUTRZC, - WM8904_LINEOUT_VU | WM8904_LINEOUTRZC); - snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, - WM8904_SR_MODE, 0); + regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_LEFT, + WM8904_ADC_VU, WM8904_ADC_VU); + regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_RIGHT, + WM8904_ADC_VU, WM8904_ADC_VU); + regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_LEFT, + WM8904_DAC_VU, WM8904_DAC_VU); + regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_RIGHT, + WM8904_DAC_VU, WM8904_DAC_VU); + regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_LEFT, + WM8904_HPOUT_VU | WM8904_HPOUTLZC, + WM8904_HPOUT_VU | WM8904_HPOUTLZC); + regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_RIGHT, + WM8904_HPOUT_VU | WM8904_HPOUTRZC, + WM8904_HPOUT_VU | WM8904_HPOUTRZC); + regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_LEFT, + WM8904_LINEOUT_VU | WM8904_LINEOUTLZC, + WM8904_LINEOUT_VU | WM8904_LINEOUTLZC); + regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_RIGHT, + WM8904_LINEOUT_VU | WM8904_LINEOUTRZC, + WM8904_LINEOUT_VU | WM8904_LINEOUTRZC); + regmap_update_bits(wm8904->regmap, WM8904_CLOCK_RATES_0, + WM8904_SR_MODE, 0); /* Apply configuration from the platform data. */ if (wm8904->pdata) { for (i = 0; i < WM8904_GPIO_REGS; i++) { - if (!pdata->gpio_cfg[i]) + if (!wm8904->pdata->gpio_cfg[i]) continue; regmap_update_bits(wm8904->regmap, WM8904_GPIO_CONTROL_1 + i, 0xffff, - pdata->gpio_cfg[i]); + wm8904->pdata->gpio_cfg[i]); } /* Zero is the default value for these anyway */ @@ -2185,111 +2205,38 @@ static int wm8904_probe(struct snd_soc_codec *codec) regmap_update_bits(wm8904->regmap, WM8904_MIC_BIAS_CONTROL_0 + i, 0xffff, - pdata->mic_cfg[i]); + wm8904->pdata->mic_cfg[i]); } /* Set Class W by default - this will be managed by the Class * G widget at runtime where bypass paths are available. */ - snd_soc_update_bits(codec, WM8904_CLASS_W_0, + regmap_update_bits(wm8904->regmap, WM8904_CLASS_W_0, WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR); /* Use normal bias source */ - snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, + regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0, WM8904_POBCTRL, 0); - wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* Bias level configuration will have done an extra enable */ - regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); - - wm8904_handle_pdata(codec); - - wm8904_add_widgets(codec); - - return 0; - -err_enable: + /* Can leave the device powered off until we need it */ + regcache_cache_only(wm8904->regmap, true); regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); - return ret; -} - -static int wm8904_remove(struct snd_soc_codec *codec) -{ - struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - - wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); - kfree(wm8904->retune_mobile_texts); - kfree(wm8904->drc_texts); - - return 0; -} - -static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { - .probe = wm8904_probe, - .remove = wm8904_remove, - .suspend = wm8904_suspend, - .resume = wm8904_resume, - .set_bias_level = wm8904_set_bias_level, - .idle_bias_off = true, -}; - -static const struct regmap_config wm8904_regmap = { - .reg_bits = 8, - .val_bits = 16, - - .max_register = WM8904_MAX_REGISTER, - .volatile_reg = wm8904_volatile_register, - .readable_reg = wm8904_readable_register, - - .cache_type = REGCACHE_RBTREE, - .reg_defaults = wm8904_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), -}; - -static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8904_priv *wm8904; - int ret; - - wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), - GFP_KERNEL); - if (wm8904 == NULL) - return -ENOMEM; - - wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap); - if (IS_ERR(wm8904->regmap)) { - ret = PTR_ERR(wm8904->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - - wm8904->devtype = id->driver_data; - i2c_set_clientdata(i2c, wm8904); - wm8904->pdata = i2c->dev.platform_data; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8904, &wm8904_dai, 1); if (ret != 0) - goto err; + return ret; return 0; -err: - regmap_exit(wm8904->regmap); +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); return ret; } -static __devexit int wm8904_i2c_remove(struct i2c_client *client) +static int wm8904_i2c_remove(struct i2c_client *client) { - struct wm8904_priv *wm8904 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8904->regmap); return 0; } @@ -2307,27 +2254,11 @@ static struct i2c_driver wm8904_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8904_i2c_probe, - .remove = __devexit_p(wm8904_i2c_remove), + .remove = wm8904_i2c_remove, .id_table = wm8904_i2c_id, }; -static int __init wm8904_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8904_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8904_modinit); - -static void __exit wm8904_exit(void) -{ - i2c_del_driver(&wm8904_i2c_driver); -} -module_exit(wm8904_exit); +module_i2c_driver(wm8904_i2c_driver); MODULE_DESCRIPTION("ASoC WM8904 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
