summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wm8962.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8962.c')
-rw-r--r--sound/soc/codecs/wm8962.c651
1 files changed, 370 insertions, 281 deletions
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index fd2731d171dd..e9e317ce6898 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm8962.c -- WM8962 ALSA SoC Audio driver
*
* Copyright 2010-2 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
@@ -55,7 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
struct wm8962_priv {
struct wm8962_pdata pdata;
struct regmap *regmap;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
int sysclk;
int sysclk_rate;
@@ -86,6 +82,7 @@ struct wm8962_priv {
#endif
int irq;
+ bool master_flag;
};
/* We can't use the same notifier block for more than one supply and
@@ -122,7 +119,7 @@ static const struct reg_default wm8962_reg[] = {
{ 5, 0x0018 }, /* R5 - ADC & DAC Control 1 */
{ 6, 0x2008 }, /* R6 - ADC & DAC Control 2 */
{ 7, 0x000A }, /* R7 - Audio Interface 0 */
-
+ { 8, 0x01E4 }, /* R8 - Clocking2 */
{ 9, 0x0300 }, /* R9 - Audio Interface 1 */
{ 10, 0x00C0 }, /* R10 - Left DAC volume */
{ 11, 0x00C0 }, /* R11 - Right DAC volume */
@@ -792,7 +789,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8962_CLOCKING1:
- case WM8962_CLOCKING2:
case WM8962_SOFTWARE_RESET:
case WM8962_THERMAL_SHUTDOWN_STATUS:
case WM8962_ADDITIONAL_CONTROL_4:
@@ -961,7 +957,6 @@ static bool wm8962_readable_register(struct device *dev, unsigned int reg)
case WM8962_EQ39:
case WM8962_EQ40:
case WM8962_EQ41:
- case WM8962_GPIO_BASE:
case WM8962_GPIO_2:
case WM8962_GPIO_3:
case WM8962_GPIO_5:
@@ -1475,55 +1470,55 @@ static const DECLARE_TLV_DB_RANGE(classd_tlv,
);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
-static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
+static int wm8962_dsp2_write_config(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
return regcache_sync_region(wm8962->regmap,
WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
}
-static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
+static int wm8962_dsp2_set_enable(struct snd_soc_component *component, u16 val)
{
- u16 adcl = snd_soc_read(codec, WM8962_LEFT_ADC_VOLUME);
- u16 adcr = snd_soc_read(codec, WM8962_RIGHT_ADC_VOLUME);
- u16 dac = snd_soc_read(codec, WM8962_ADC_DAC_CONTROL_1);
+ u16 adcl = snd_soc_component_read(component, WM8962_LEFT_ADC_VOLUME);
+ u16 adcr = snd_soc_component_read(component, WM8962_RIGHT_ADC_VOLUME);
+ u16 dac = snd_soc_component_read(component, WM8962_ADC_DAC_CONTROL_1);
/* Mute the ADCs and DACs */
- snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, 0);
- snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
- snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, 0);
+ snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
+ snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
WM8962_DAC_MUTE, WM8962_DAC_MUTE);
- snd_soc_write(codec, WM8962_SOUNDSTAGE_ENABLES_0, val);
+ snd_soc_component_write(component, WM8962_SOUNDSTAGE_ENABLES_0, val);
/* Restore the ADCs and DACs */
- snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, adcl);
- snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, adcr);
- snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, adcl);
+ snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, adcr);
+ snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
WM8962_DAC_MUTE, dac);
return 0;
}
-static int wm8962_dsp2_start(struct snd_soc_codec *codec)
+static int wm8962_dsp2_start(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
- wm8962_dsp2_write_config(codec);
+ wm8962_dsp2_write_config(component);
- snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
+ snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
- wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+ wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
return 0;
}
-static int wm8962_dsp2_stop(struct snd_soc_codec *codec)
+static int wm8962_dsp2_stop(struct snd_soc_component *component)
{
- wm8962_dsp2_set_enable(codec, 0);
+ wm8962_dsp2_set_enable(component, 0);
- snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
+ snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
return 0;
}
@@ -1550,8 +1545,8 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int shift = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
@@ -1562,11 +1557,11 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int shift = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int old = wm8962->dsp2_ena;
int ret = 0;
- int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) &
+ int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) &
WM8962_DSP2_ENA;
mutex_lock(&wm8962->dsp2_ena_lock);
@@ -1583,9 +1578,9 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
if (dsp2_running) {
if (wm8962->dsp2_ena)
- wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+ wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
else
- wm8962_dsp2_stop(codec);
+ wm8962_dsp2_stop(component);
}
out:
@@ -1600,7 +1595,7 @@ out:
static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1609,17 +1604,17 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
return 0;
/* If the left PGA is enabled hit that VU bit... */
- ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+ ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2);
if (ret & WM8962_HPOUTL_PGA_ENA) {
- snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
- snd_soc_read(codec, WM8962_HPOUTL_VOLUME));
+ snd_soc_component_write(component, WM8962_HPOUTL_VOLUME,
+ snd_soc_component_read(component, WM8962_HPOUTL_VOLUME));
return 1;
}
/* ...otherwise the right. The VU is stereo. */
if (ret & WM8962_HPOUTR_PGA_ENA)
- snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
- snd_soc_read(codec, WM8962_HPOUTR_VOLUME));
+ snd_soc_component_write(component, WM8962_HPOUTR_VOLUME,
+ snd_soc_component_read(component, WM8962_HPOUTR_VOLUME));
return 1;
}
@@ -1630,7 +1625,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1639,17 +1634,17 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
return 0;
/* If the left PGA is enabled hit that VU bit... */
- ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+ ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2);
if (ret & WM8962_SPKOUTL_PGA_ENA) {
- snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
- snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
+ snd_soc_component_write(component, WM8962_SPKOUTL_VOLUME,
+ snd_soc_component_read(component, WM8962_SPKOUTL_VOLUME));
return 1;
}
/* ...otherwise the right. The VU is stereo. */
if (ret & WM8962_SPKOUTR_PGA_ENA)
- snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
- snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
+ snd_soc_component_write(component, WM8962_SPKOUTR_VOLUME,
+ snd_soc_component_read(component, WM8962_SPKOUTR_VOLUME));
return 1;
}
@@ -1708,6 +1703,8 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0),
SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0),
+SOC_SINGLE("DAC Monomix Switch", WM8962_DAC_DSP_MIXING_1, WM8962_DAC_MONOMIX_SHIFT, 1, 0),
+SOC_SINGLE("ADC Monomix Switch", WM8962_THREED1, WM8962_ADC_MONOMIX_SHIFT, 1, 0),
SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
5, 1, 0),
@@ -1844,6 +1841,49 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
4, 1, 0, inmix_tlv),
};
+static int tp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int ret, reg, val, mask;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ dev_err(component->dev, "Failed to resume device: %d\n", ret);
+ return ret;
+ }
+
+ reg = WM8962_ADDITIONAL_CONTROL_4;
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_HP")) {
+ mask = WM8962_TEMP_ENA_HP_MASK;
+ val = WM8962_TEMP_ENA_HP;
+ } else if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_SPK")) {
+ mask = WM8962_TEMP_ENA_SPK_MASK;
+ val = WM8962_TEMP_ENA_SPK;
+ } else {
+ pm_runtime_put(component->dev);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ val = 0;
+ fallthrough;
+ case SND_SOC_DAPM_POST_PMU:
+ ret = snd_soc_component_update_bits(component, reg, mask, val);
+ break;
+ default:
+ WARN(1, "Invalid event %d\n", event);
+ pm_runtime_put(component->dev);
+ return -EINVAL;
+ }
+
+ pm_runtime_put(component->dev);
+
+ return 0;
+}
+
static int cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1863,7 +1903,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
static int hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
int timeout;
int reg;
int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
@@ -1871,17 +1911,17 @@ static int hp_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_ENA | WM8962_HP1R_ENA,
WM8962_HP1L_ENA | WM8962_HP1R_ENA);
udelay(20);
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
/* Start the DC servo */
- snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
WM8962_HP1L_DCS_STARTUP |
WM8962_HP1R_DCS_STARTUP,
@@ -1893,30 +1933,30 @@ static int hp_event(struct snd_soc_dapm_widget *w,
timeout = 0;
do {
msleep(1);
- reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+ reg = snd_soc_component_read(component, WM8962_DC_SERVO_6);
if (reg < 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"Failed to read DCS status: %d\n",
reg);
continue;
}
- dev_dbg(codec->dev, "DCS status: %x\n", reg);
+ dev_dbg(component->dev, "DCS status: %x\n", reg);
} while (++timeout < 200 && (reg & expected) != expected);
if ((reg & expected) != expected)
- dev_err(codec->dev, "DC servo timed out\n");
+ dev_err(component->dev, "DC servo timed out\n");
else
- dev_dbg(codec->dev, "DC servo complete after %dms\n",
+ dev_dbg(component->dev, "DC servo complete after %dms\n",
timeout);
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_ENA_OUTP |
WM8962_HP1R_ENA_OUTP,
WM8962_HP1L_ENA_OUTP |
WM8962_HP1R_ENA_OUTP);
udelay(20);
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_RMV_SHORT |
WM8962_HP1R_RMV_SHORT,
WM8962_HP1L_RMV_SHORT |
@@ -1924,19 +1964,19 @@ static int hp_event(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_RMV_SHORT |
WM8962_HP1R_RMV_SHORT, 0);
udelay(20);
- snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
WM8962_HP1L_DCS_STARTUP |
WM8962_HP1R_DCS_STARTUP,
0);
- snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
WM8962_HP1L_ENA | WM8962_HP1R_ENA |
WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
WM8962_HP1L_ENA_OUTP |
@@ -1957,7 +1997,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
static int out_pga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
int reg;
switch (w->shift) {
@@ -1980,7 +2020,8 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
+ return snd_soc_component_write(component, reg,
+ snd_soc_component_read(component, reg));
default:
WARN(1, "Invalid event %d\n", event);
return -EINVAL;
@@ -1990,18 +2031,18 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
static int dsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (wm8962->dsp2_ena)
- wm8962_dsp2_start(codec);
+ wm8962_dsp2_start(component);
break;
case SND_SOC_DAPM_PRE_PMD:
if (wm8962->dsp2_ena)
- wm8962_dsp2_stop(codec);
+ wm8962_dsp2_stop(component);
break;
default:
@@ -2052,6 +2093,13 @@ static SOC_ENUM_SINGLE_DECL(hpoutl_enum,
static const struct snd_kcontrol_new hpoutl_mux =
SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+static const char * const input_mode_text[] = { "Analog", "Digital" };
+
+static SOC_ENUM_SINGLE_VIRT_DECL(input_mode_enum, input_mode_text);
+
+static const struct snd_kcontrol_new input_mode_mux =
+ SOC_DAPM_ENUM("Input Mode", input_mode_enum);
+
static const struct snd_kcontrol_new inpgal[] = {
SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
@@ -2136,8 +2184,10 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_HP", SND_SOC_NOPM, 0, 0, tp_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TEMP_SPK", SND_SOC_NOPM, 0, 0, tp_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
inpgal, ARRAY_SIZE(inpgal)),
@@ -2150,6 +2200,9 @@ SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+SND_SOC_DAPM_MUX("Input Mode L", SND_SOC_NOPM, 0, 0, &input_mode_mux),
+SND_SOC_DAPM_MUX("Input Mode R", SND_SOC_NOPM, 0, 0, &input_mode_mux),
+
SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
@@ -2177,6 +2230,9 @@ SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
+
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
};
static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
@@ -2184,7 +2240,6 @@ SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
spkmixl, ARRAY_SIZE(spkmixl)),
SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
out_pga_event, SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("SPKOUT"),
};
@@ -2199,9 +2254,6 @@ SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
out_pga_event, SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
-
SND_SOC_DAPM_OUTPUT("SPKOUTL"),
SND_SOC_DAPM_OUTPUT("SPKOUTR"),
};
@@ -2229,16 +2281,19 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
{ "DMIC_ENA", NULL, "DMICDAT" },
+ { "Input Mode L", "Analog", "MIXINL" },
+ { "Input Mode L", "Digital", "DMIC_ENA" },
+ { "Input Mode R", "Analog", "MIXINR" },
+ { "Input Mode R", "Digital", "DMIC_ENA" },
+
{ "ADCL", NULL, "SYSCLK" },
{ "ADCL", NULL, "TOCLK" },
- { "ADCL", NULL, "MIXINL" },
- { "ADCL", NULL, "DMIC_ENA" },
+ { "ADCL", NULL, "Input Mode L" },
{ "ADCL", NULL, "DSP2" },
{ "ADCR", NULL, "SYSCLK" },
{ "ADCR", NULL, "TOCLK" },
- { "ADCR", NULL, "MIXINR" },
- { "ADCR", NULL, "DMIC_ENA" },
+ { "ADCR", NULL, "Input Mode R" },
{ "ADCR", NULL, "DSP2" },
{ "STL", "Left", "ADCL" },
@@ -2311,12 +2366,18 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
{ "Speaker PGA", "Mixer", "Speaker Mixer" },
{ "Speaker PGA", "DAC", "DACL" },
- { "Speaker Output", NULL, "Speaker PGA" },
- { "Speaker Output", NULL, "SYSCLK" },
- { "Speaker Output", NULL, "TOCLK" },
- { "Speaker Output", NULL, "TEMP_SPK" },
+ { "SPKOUTL Output", NULL, "Speaker PGA" },
+ { "SPKOUTL Output", NULL, "SYSCLK" },
+ { "SPKOUTL Output", NULL, "TOCLK" },
+ { "SPKOUTL Output", NULL, "TEMP_SPK" },
- { "SPKOUT", NULL, "Speaker Output" },
+ { "SPKOUTR Output", NULL, "Speaker PGA" },
+ { "SPKOUTR Output", NULL, "SYSCLK" },
+ { "SPKOUTR Output", NULL, "TOCLK" },
+ { "SPKOUTR Output", NULL, "TEMP_SPK" },
+
+ { "SPKOUT", NULL, "SPKOUTL Output" },
+ { "SPKOUT", NULL, "SPKOUTR Output" },
};
static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
@@ -2354,19 +2415,19 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
{ "SPKOUTR", NULL, "SPKOUTR Output" },
};
-static int wm8962_add_widgets(struct snd_soc_codec *codec)
+static int wm8962_add_widgets(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct wm8962_pdata *pdata = &wm8962->pdata;
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_add_codec_controls(codec, wm8962_snd_controls,
+ snd_soc_add_component_controls(component, wm8962_snd_controls,
ARRAY_SIZE(wm8962_snd_controls));
if (pdata->spk_mono)
- snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
+ snd_soc_add_component_controls(component, wm8962_spk_mono_controls,
ARRAY_SIZE(wm8962_spk_mono_controls));
else
- snd_soc_add_codec_controls(codec, wm8962_spk_stereo_controls,
+ snd_soc_add_component_controls(component, wm8962_spk_stereo_controls,
ARRAY_SIZE(wm8962_spk_stereo_controls));
@@ -2403,21 +2464,23 @@ static const int sysclk_rates[] = {
64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144
};
-static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+static void wm8962_configure_bclk(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+ int best, min_diff, diff;
int dspclk, i;
int clocking2 = 0;
int clocking4 = 0;
int aif2 = 0;
if (!wm8962->sysclk_rate) {
- dev_dbg(codec->dev, "No SYSCLK configured\n");
+ dev_dbg(component->dev, "No SYSCLK configured\n");
return;
}
if (!wm8962->bclk || !wm8962->lrclk) {
- dev_dbg(codec->dev, "No audio clocks configured\n");
+ dev_dbg(component->dev, "No audio clocks configured\n");
return;
}
@@ -2429,32 +2492,40 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
}
if (i == ARRAY_SIZE(sysclk_rates)) {
- dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+ dev_err(component->dev, "Unsupported sysclk ratio %d\n",
wm8962->sysclk_rate / wm8962->lrclk);
return;
}
- dev_dbg(codec->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
+ dev_dbg(component->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
- snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+ snd_soc_component_update_bits(component, WM8962_CLOCKING_4,
WM8962_SYSCLK_RATE_MASK, clocking4);
/* DSPCLK_DIV can be only generated correctly after enabling SYSCLK.
* So we here provisionally enable it and then disable it afterward
* if current bias_level hasn't reached SND_SOC_BIAS_ON.
*/
- if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON)
+ snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
- dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+ /* DSPCLK_DIV field in WM8962_CLOCKING1 register is used to generate
+ * correct frequency of LRCLK and BCLK. Sometimes the read-only value
+ * can't be updated timely after enabling SYSCLK. This results in wrong
+ * calculation values. Delay is introduced here to wait for newest
+ * value from register. The time of the delay should be at least
+ * 500~1000us according to test.
+ */
+ usleep_range(500, 1000);
+ dspclk = snd_soc_component_read(component, WM8962_CLOCKING1);
- if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON)
+ snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, 0);
if (dspclk < 0) {
- dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+ dev_err(component->dev, "Failed to read DSPCLK: %d\n", dspclk);
return;
}
@@ -2470,61 +2541,65 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
dspclk = wm8962->sysclk_rate / 4;
break;
default:
- dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+ dev_warn(component->dev, "Unknown DSPCLK divisor read back\n");
dspclk = wm8962->sysclk_rate;
}
- dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+ dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
- /* We're expecting an exact match */
+ /* Search a proper bclk, not exact match. */
+ best = 0;
+ min_diff = INT_MAX;
for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
if (bclk_divs[i] < 0)
continue;
- if (dspclk / bclk_divs[i] == wm8962->bclk) {
- dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
- bclk_divs[i], wm8962->bclk);
- clocking2 |= i;
+ diff = (dspclk / bclk_divs[i]) - wm8962->bclk;
+ if (diff < 0) /* Table is sorted */
break;
+ if (diff < min_diff) {
+ best = i;
+ min_diff = diff;
}
}
- if (i == ARRAY_SIZE(bclk_divs)) {
- dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
- dspclk / wm8962->bclk);
- return;
- }
+ wm8962->bclk = dspclk / bclk_divs[best];
+ clocking2 |= best;
+ dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n",
+ bclk_divs[best], wm8962->bclk);
aif2 |= wm8962->bclk / wm8962->lrclk;
- dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+ dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n",
wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_BCLK_DIV_MASK, clocking2);
- snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+ snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_2,
WM8962_AIF_RATE_MASK, aif2);
}
-static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+static int wm8962_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
/* VMID 2*50k */
- snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x80);
- wm8962_configure_bclk(codec);
+ wm8962_configure_bclk(component);
break;
case SND_SOC_BIAS_STANDBY:
/* VMID 2*250k */
- snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x100);
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
msleep(100);
break;
@@ -2556,8 +2631,9 @@ static int wm8962_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;
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int i;
int aif0 = 0;
int adctl3 = 0;
@@ -2575,7 +2651,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
}
}
if (i == ARRAY_SIZE(sr_vals)) {
- dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
+ dev_err(component->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
return -EINVAL;
}
@@ -2598,17 +2674,17 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
WM8962_WL_MASK, aif0);
- snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+ snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_3,
WM8962_SAMPLE_RATE_INT_MODE |
WM8962_SAMPLE_RATE_MASK, adctl3);
- dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
+ dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
wm8962->bclk, wm8962->lrclk);
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
- wm8962_configure_bclk(codec);
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON)
+ wm8962_configure_bclk(component);
return 0;
}
@@ -2616,8 +2692,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int src;
switch (clk_id) {
@@ -2633,7 +2709,7 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return -EINVAL;
}
- snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+ snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
src);
wm8962->sysclk_rate = freq;
@@ -2643,12 +2719,14 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_component *component = dai->component;
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int aif0 = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif0 |= WM8962_LRCLK_INV | 3;
+ fallthrough;
case SND_SOC_DAIFMT_DSP_A:
aif0 |= 3;
@@ -2689,17 +2767,19 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
+ wm8962->master_flag = false;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif0 |= WM8962_MSTR;
+ wm8962->master_flag = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
}
- snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
WM8962_LRCLK_INV, aif0);
@@ -2791,7 +2871,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
if (target % Fref == 0) {
fll_div->theta = 0;
- fll_div->lambda = 0;
+ fll_div->lambda = 1;
} else {
gcd_fll = gcd(target, fratio * Fref);
@@ -2809,12 +2889,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
return 0;
}
-static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct _fll_div fll_div;
- unsigned long timeout;
+ unsigned long time_left;
int ret;
int fll1 = 0;
@@ -2824,15 +2904,15 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
return 0;
if (Fout == 0) {
- dev_dbg(codec->dev, "FLL disabled\n");
+ dev_dbg(component->dev, "FLL disabled\n");
wm8962->fll_fref = 0;
wm8962->fll_fout = 0;
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, 0);
- pm_runtime_put(codec->dev);
+ pm_runtime_put(component->dev);
return 0;
}
@@ -2842,74 +2922,78 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
return ret;
/* Parameters good, disable so we can reprogram */
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
switch (fll_id) {
case WM8962_FLL_MCLK:
case WM8962_FLL_BCLK:
+ fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ break;
case WM8962_FLL_OSC:
fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ snd_soc_component_update_bits(component, WM8962_PLL2,
+ WM8962_OSC_ENA, WM8962_OSC_ENA);
break;
case WM8962_FLL_INT:
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_5,
WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
break;
default:
- dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+ dev_err(component->dev, "Unknown FLL source %d\n", source);
return -EINVAL;
}
- if (fll_div.theta || fll_div.lambda)
+ if (fll_div.theta)
fll1 |= WM8962_FLL_FRAC;
/* Stop the FLL while we reconfigure */
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_2,
WM8962_FLL_OUTDIV_MASK |
WM8962_FLL_REFCLK_DIV_MASK,
(fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
(fll_div.fll_refclk_div));
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_3,
WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
- snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
- snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
- snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+ snd_soc_component_write(component, WM8962_FLL_CONTROL_6, fll_div.theta);
+ snd_soc_component_write(component, WM8962_FLL_CONTROL_7, fll_div.lambda);
+ snd_soc_component_write(component, WM8962_FLL_CONTROL_8, fll_div.n);
reinit_completion(&wm8962->fll_lock);
- ret = pm_runtime_get_sync(codec->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
- dev_err(codec->dev, "Failed to resume device: %d\n", ret);
+ dev_err(component->dev, "Failed to resume device: %d\n", ret);
return ret;
}
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA);
- dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+ dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
/* This should be a massive overestimate but go even
* higher if we'll error out
*/
if (wm8962->irq)
- timeout = msecs_to_jiffies(5);
+ time_left = msecs_to_jiffies(5);
else
- timeout = msecs_to_jiffies(1);
+ time_left = msecs_to_jiffies(1);
- timeout = wait_for_completion_timeout(&wm8962->fll_lock,
- timeout);
+ time_left = wait_for_completion_timeout(&wm8962->fll_lock,
+ time_left);
- if (timeout == 0 && wm8962->irq) {
- dev_err(codec->dev, "FLL lock timed out");
- snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ if (time_left == 0 && wm8962->irq) {
+ dev_err(component->dev, "FLL lock timed out");
+ snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, 0);
- pm_runtime_put(codec->dev);
+ pm_runtime_put(component->dev);
return -ETIMEDOUT;
}
@@ -2920,9 +3004,9 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
return 0;
}
-static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+static int wm8962_mute(struct snd_soc_dai *dai, int mute, int direction)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_component *component = dai->component;
int val, ret;
if (mute)
@@ -2934,12 +3018,12 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute)
* The DAC mute bit is mirrored in two registers, update both to keep
* the register cache consistent.
*/
- ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
+ ret = snd_soc_component_update_bits(component, WM8962_CLASS_D_CONTROL_1,
WM8962_DAC_MUTE_ALT, val);
if (ret < 0)
return ret;
- return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ return snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
WM8962_DAC_MUTE, val);
}
@@ -2953,7 +3037,8 @@ static const struct snd_soc_dai_ops wm8962_dai_ops = {
.hw_params = wm8962_hw_params,
.set_sysclk = wm8962_set_dai_sysclk,
.set_fmt = wm8962_set_dai_fmt,
- .digital_mute = wm8962_mute,
+ .mute_stream = wm8962_mute,
+ .no_capture_mute = 1,
};
static struct snd_soc_dai_driver wm8962_dai = {
@@ -2973,7 +3058,7 @@ static struct snd_soc_dai_driver wm8962_dai = {
.formats = WM8962_FORMATS,
},
.ops = &wm8962_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
};
static void wm8962_mic_work(struct work_struct *work)
@@ -2981,12 +3066,12 @@ static void wm8962_mic_work(struct work_struct *work)
struct wm8962_priv *wm8962 = container_of(work,
struct wm8962_priv,
mic_work.work);
- struct snd_soc_codec *codec = wm8962->codec;
+ struct snd_soc_component *component = wm8962->component;
int status = 0;
int irq_pol = 0;
int reg;
- reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+ reg = snd_soc_component_read(component, WM8962_ADDITIONAL_CONTROL_4);
if (reg & WM8962_MICDET_STS) {
status |= SND_JACK_MICROPHONE;
@@ -3001,7 +3086,7 @@ static void wm8962_mic_work(struct work_struct *work)
snd_soc_jack_report(wm8962->jack, status,
SND_JACK_MICROPHONE | SND_JACK_BTN_0);
- snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+ snd_soc_component_update_bits(component, WM8962_MICINT_SOURCE_POL,
WM8962_MICSCD_IRQ_POL |
WM8962_MICD_IRQ_POL, irq_pol);
}
@@ -3014,7 +3099,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
unsigned int active;
int reg, ret;
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Failed to resume: %d\n", ret);
return IRQ_NONE;
@@ -3099,7 +3184,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
/**
* wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
*
- * @codec: WM8962 codec
+ * @component: WM8962 component
* @jack: jack to report detection events on
*
* Enable microphone detection via IRQ on the WM8962. If GPIOs are
@@ -3109,10 +3194,10 @@ static irqreturn_t wm8962_irq(int irq, void *data)
*
* If no jack is supplied detection will be disabled.
*/
-int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int irq_mask, enable;
wm8962->jack = jack;
@@ -3124,9 +3209,9 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
enable = 0;
}
- snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+ snd_soc_component_update_bits(component, WM8962_INTERRUPT_STATUS_2_MASK,
WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
- snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+ snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_4,
WM8962_MICDET_ENA, enable);
/* Send an initial empty report */
@@ -3157,8 +3242,8 @@ static void wm8962_beep_work(struct work_struct *work)
{
struct wm8962_priv *wm8962 =
container_of(work, struct wm8962_priv, beep_work);
- struct snd_soc_codec *codec = wm8962->codec;
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_component *component = wm8962->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
int reg = 0;
int best = 0;
@@ -3170,18 +3255,18 @@ static void wm8962_beep_work(struct work_struct *work)
best = i;
}
- dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+ dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
beep_rates[best], wm8962->beep_rate);
reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
snd_soc_dapm_enable_pin(dapm, "Beep");
} else {
- dev_dbg(codec->dev, "Disabling beep\n");
+ dev_dbg(component->dev, "Disabling beep\n");
snd_soc_dapm_disable_pin(dapm, "Beep");
}
- snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+ snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1,
WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
snd_soc_dapm_sync(dapm);
@@ -3193,15 +3278,16 @@ static void wm8962_beep_work(struct work_struct *work)
static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
unsigned int code, int hz)
{
- struct snd_soc_codec *codec = input_get_drvdata(dev);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = input_get_drvdata(dev);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
- dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+ dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
switch (code) {
case SND_BELL:
if (hz)
hz = 1000;
+ fallthrough;
case SND_TONE:
break;
default:
@@ -3214,9 +3300,8 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
return 0;
}
-static ssize_t wm8962_beep_set(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t beep_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
long int time;
@@ -3231,16 +3316,16 @@ static ssize_t wm8962_beep_set(struct device *dev,
return count;
}
-static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+static DEVICE_ATTR_WO(beep);
-static void wm8962_init_beep(struct snd_soc_codec *codec)
+static void wm8962_init_beep(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int ret;
- wm8962->beep = devm_input_allocate_device(codec->dev);
+ wm8962->beep = devm_input_allocate_device(component->dev);
if (!wm8962->beep) {
- dev_err(codec->dev, "Failed to allocate beep device\n");
+ dev_err(component->dev, "Failed to allocate beep device\n");
return;
}
@@ -3248,37 +3333,37 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
wm8962->beep_rate = 0;
wm8962->beep->name = "WM8962 Beep Generator";
- wm8962->beep->phys = dev_name(codec->dev);
+ wm8962->beep->phys = dev_name(component->dev);
wm8962->beep->id.bustype = BUS_I2C;
wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
wm8962->beep->event = wm8962_beep_event;
- wm8962->beep->dev.parent = codec->dev;
- input_set_drvdata(wm8962->beep, codec);
+ wm8962->beep->dev.parent = component->dev;
+ input_set_drvdata(wm8962->beep, component);
ret = input_register_device(wm8962->beep);
if (ret != 0) {
wm8962->beep = NULL;
- dev_err(codec->dev, "Failed to register beep device\n");
+ dev_err(component->dev, "Failed to register beep device\n");
}
- ret = device_create_file(codec->dev, &dev_attr_beep);
+ ret = device_create_file(component->dev, &dev_attr_beep);
if (ret != 0) {
- dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+ dev_err(component->dev, "Failed to create keyclick file: %d\n",
ret);
}
}
-static void wm8962_free_beep(struct snd_soc_codec *codec)
+static void wm8962_free_beep(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
- device_remove_file(codec->dev, &dev_attr_beep);
+ device_remove_file(component->dev, &dev_attr_beep);
cancel_work_sync(&wm8962->beep_work);
wm8962->beep = NULL;
- snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+ snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
}
static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
@@ -3330,26 +3415,29 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
-static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm8962_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
- struct snd_soc_codec *codec = wm8962->codec;
+ struct snd_soc_component *component = wm8962->component;
- snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
- WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT);
+ return snd_soc_component_update_bits(component,
+ WM8962_GPIO_BASE + offset,
+ WM8962_GP2_LVL,
+ !!value << WM8962_GP2_LVL_SHIFT);
}
static int wm8962_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
- struct snd_soc_codec *codec = wm8962->codec;
+ struct snd_soc_component *component = wm8962->component;
int ret, val;
/* Force function 1 (logic output) */
val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
- ret = snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+ ret = snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
if (ret < 0)
return ret;
@@ -3366,15 +3454,15 @@ static const struct gpio_chip wm8962_template_chip = {
.can_sleep = 1,
};
-static void wm8962_init_gpio(struct snd_soc_codec *codec)
+static void wm8962_init_gpio(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct wm8962_pdata *pdata = &wm8962->pdata;
int ret;
wm8962->gpio_chip = wm8962_template_chip;
wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
- wm8962->gpio_chip.parent = codec->dev;
+ wm8962->gpio_chip.parent = component->dev;
if (pdata->gpio_base)
wm8962->gpio_chip.base = pdata->gpio_base;
@@ -3383,34 +3471,34 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962);
if (ret != 0)
- dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+ dev_err(component->dev, "Failed to add GPIOs: %d\n", ret);
}
-static void wm8962_free_gpio(struct snd_soc_codec *codec)
+static void wm8962_free_gpio(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
gpiochip_remove(&wm8962->gpio_chip);
}
#else
-static void wm8962_init_gpio(struct snd_soc_codec *codec)
+static void wm8962_init_gpio(struct snd_soc_component *component)
{
}
-static void wm8962_free_gpio(struct snd_soc_codec *codec)
+static void wm8962_free_gpio(struct snd_soc_component *component)
{
}
#endif
-static int wm8962_probe(struct snd_soc_codec *codec)
+static int wm8962_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int i;
bool dmicclk, dmicdat;
- wm8962->codec = codec;
+ wm8962->component = component;
wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
@@ -3423,22 +3511,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
- ret = regulator_register_notifier(wm8962->supplies[i].consumer,
- &wm8962->disable_nb[i]);
+ ret = devm_regulator_register_notifier(
+ wm8962->supplies[i].consumer,
+ &wm8962->disable_nb[i]);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"Failed to register regulator notifier: %d\n",
ret);
}
}
- wm8962_add_widgets(codec);
+ wm8962_add_widgets(component);
/* Save boards having to disable DMIC when not in use */
dmicclk = false;
dmicdat = false;
- for (i = 0; i < WM8962_MAX_GPIO; i++) {
- switch (snd_soc_read(codec, WM8962_GPIO_BASE + i)
+ for (i = 1; i < WM8962_MAX_GPIO; i++) {
+ /*
+ * Register 515 (WM8962_GPIO_BASE + 3) does not exist,
+ * so skip its access
+ */
+ if (i == 3)
+ continue;
+ switch (snd_soc_component_read(component, WM8962_GPIO_BASE + i)
& WM8962_GP2_FN_MASK) {
case WM8962_GPIO_FN_DMICCLK:
dmicclk = true;
@@ -3451,40 +3546,35 @@ static int wm8962_probe(struct snd_soc_codec *codec)
}
}
if (!dmicclk || !dmicdat) {
- dev_dbg(codec->dev, "DMIC not in use, disabling\n");
- snd_soc_dapm_nc_pin(dapm, "DMICDAT");
+ dev_dbg(component->dev, "DMIC not in use, disabling\n");
+ snd_soc_dapm_disable_pin(dapm, "DMICDAT");
}
if (dmicclk != dmicdat)
- dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
+ dev_warn(component->dev, "DMIC GPIOs partially configured\n");
- wm8962_init_beep(codec);
- wm8962_init_gpio(codec);
+ wm8962_init_beep(component);
+ wm8962_init_gpio(component);
return 0;
}
-static int wm8962_remove(struct snd_soc_codec *codec)
+static void wm8962_remove(struct snd_soc_component *component)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- int i;
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
cancel_delayed_work_sync(&wm8962->mic_work);
- wm8962_free_gpio(codec);
- wm8962_free_beep(codec);
- for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
- regulator_unregister_notifier(wm8962->supplies[i].consumer,
- &wm8962->disable_nb[i]);
-
- return 0;
+ wm8962_free_gpio(component);
+ wm8962_free_beep(component);
}
-static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
- .probe = wm8962_probe,
- .remove = wm8962_remove,
- .set_bias_level = wm8962_set_bias_level,
- .set_pll = wm8962_set_fll,
- .idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm8962 = {
+ .probe = wm8962_probe,
+ .remove = wm8962_remove,
+ .set_bias_level = wm8962_set_bias_level,
+ .set_pll = wm8962_set_fll,
+ .use_pmdown_time = 1,
+ .endianness = 1,
};
/* Improve power consumption for IN4 DC measurement mode */
@@ -3503,7 +3593,7 @@ static const struct regmap_config wm8962_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm8962_reg),
.volatile_reg = wm8962_volatile_register,
.readable_reg = wm8962_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
@@ -3531,13 +3621,11 @@ static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
pdata->gpio_init[i] = 0x0;
}
- pdata->mclk = devm_clk_get(&i2c->dev, NULL);
-
- return 0;
+ pdata->mclk = devm_clk_get_optional(&i2c->dev, NULL);
+ return PTR_ERR_OR_ZERO(pdata->mclk);
}
-static int wm8962_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8962_i2c_probe(struct i2c_client *i2c)
{
struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);
struct wm8962_priv *wm8962;
@@ -3565,14 +3653,6 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
return ret;
}
- /* Mark the mclk pointer to NULL if no mclk assigned */
- if (IS_ERR(wm8962->pdata.mclk)) {
- /* But do not ignore the request for probe defer */
- if (PTR_ERR(wm8962->pdata.mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- wm8962->pdata.mclk = NULL;
- }
-
for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
wm8962->supplies[i].supply = wm8962_supply_names[i];
@@ -3751,11 +3831,16 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
pm_runtime_enable(&i2c->dev);
pm_request_idle(&i2c->dev);
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_wm8962, &wm8962_dai, 1);
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_wm8962, &wm8962_dai, 1);
if (ret < 0)
goto err_pm_runtime;
+ regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_TEMP_ENA_HP_MASK, 0);
+ regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_TEMP_ENA_SPK_MASK, 0);
+
regcache_cache_only(wm8962->regmap, true);
/* The drivers should power up as needed */
@@ -3771,14 +3856,11 @@ err:
return ret;
}
-static int wm8962_i2c_remove(struct i2c_client *client)
+static void wm8962_i2c_remove(struct i2c_client *client)
{
- snd_soc_unregister_codec(&client->dev);
pm_runtime_disable(&client->dev);
- return 0;
}
-#ifdef CONFIG_PM
static int wm8962_runtime_resume(struct device *dev)
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
@@ -3806,8 +3888,8 @@ static int wm8962_runtime_resume(struct device *dev)
/* SYSCLK defaults to on; make sure it is off so we can safely
* write to registers if the device is declocked.
*/
- regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
- WM8962_SYSCLK_ENA, 0);
+ regmap_write_bits(wm8962->regmap, WM8962_CLOCKING2,
+ WM8962_SYSCLK_ENA, 0);
/* Ensure we have soft control over all registers */
regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
@@ -3829,6 +3911,9 @@ static int wm8962_runtime_resume(struct device *dev)
WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
WM8962_BIAS_ENA | 0x180);
+ if (wm8962->master_flag)
+ regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0,
+ WM8962_MSTR, WM8962_MSTR);
msleep(5);
return 0;
@@ -3842,6 +3927,10 @@ static int wm8962_runtime_suspend(struct device *dev)
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+ if (wm8962->master_flag)
+ regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0,
+ WM8962_MSTR, 0);
+
regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
@@ -3858,14 +3947,14 @@ static int wm8962_runtime_suspend(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops wm8962_pm = {
- SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
};
static const struct i2c_device_id wm8962_i2c_id[] = {
- { "wm8962", 0 },
+ { "wm8962" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
@@ -3880,7 +3969,7 @@ static struct i2c_driver wm8962_i2c_driver = {
.driver = {
.name = "wm8962",
.of_match_table = wm8962_of_match,
- .pm = &wm8962_pm,
+ .pm = pm_ptr(&wm8962_pm),
},
.probe = wm8962_i2c_probe,
.remove = wm8962_i2c_remove,