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.c297
1 files changed, 196 insertions, 101 deletions
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 1cc23a05ffe4..e9e317ce6898 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -82,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
@@ -956,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:
@@ -1480,9 +1480,9 @@ static int wm8962_dsp2_write_config(struct snd_soc_component *component)
static int wm8962_dsp2_set_enable(struct snd_soc_component *component, u16 val)
{
- u16 adcl = snd_soc_component_read32(component, WM8962_LEFT_ADC_VOLUME);
- u16 adcr = snd_soc_component_read32(component, WM8962_RIGHT_ADC_VOLUME);
- u16 dac = snd_soc_component_read32(component, 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_component_write(component, WM8962_LEFT_ADC_VOLUME, 0);
@@ -1545,7 +1545,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int shift = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ 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);
@@ -1557,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_component *component = snd_soc_kcontrol_component(kcontrol);
+ 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_component_read32(component, 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);
@@ -1595,7 +1595,7 @@ out:
static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1604,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_component_read32(component, WM8962_PWR_MGMT_2);
+ ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2);
if (ret & WM8962_HPOUTL_PGA_ENA) {
snd_soc_component_write(component, WM8962_HPOUTL_VOLUME,
- snd_soc_component_read32(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_component_write(component, WM8962_HPOUTR_VOLUME,
- snd_soc_component_read32(component, WM8962_HPOUTR_VOLUME));
+ snd_soc_component_read(component, WM8962_HPOUTR_VOLUME));
return 1;
}
@@ -1625,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_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1634,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_component_read32(component, WM8962_PWR_MGMT_2);
+ ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2);
if (ret & WM8962_SPKOUTL_PGA_ENA) {
snd_soc_component_write(component, WM8962_SPKOUTL_VOLUME,
- snd_soc_component_read32(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_component_write(component, WM8962_SPKOUTR_VOLUME,
- snd_soc_component_read32(component, WM8962_SPKOUTR_VOLUME));
+ snd_soc_component_read(component, WM8962_SPKOUTR_VOLUME));
return 1;
}
@@ -1703,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),
@@ -1839,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)
{
@@ -1888,7 +1933,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
timeout = 0;
do {
msleep(1);
- reg = snd_soc_component_read32(component, WM8962_DC_SERVO_6);
+ reg = snd_soc_component_read(component, WM8962_DC_SERVO_6);
if (reg < 0) {
dev_err(component->dev,
"Failed to read DCS status: %d\n",
@@ -1975,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_component_write(component, reg, snd_soc_component_read32(component, reg));
+ return snd_soc_component_write(component, reg,
+ snd_soc_component_read(component, reg));
default:
WARN(1, "Invalid event %d\n", event);
return -EINVAL;
@@ -2047,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),
@@ -2131,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)),
@@ -2145,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),
@@ -2172,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[] = {
@@ -2179,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"),
};
@@ -2194,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"),
};
@@ -2224,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" },
@@ -2306,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" },
+
+ { "SPKOUTR Output", NULL, "Speaker PGA" },
+ { "SPKOUTR Output", NULL, "SYSCLK" },
+ { "SPKOUTR Output", NULL, "TOCLK" },
+ { "SPKOUTR Output", NULL, "TEMP_SPK" },
- { "SPKOUT", NULL, "Speaker Output" },
+ { "SPKOUT", NULL, "SPKOUTL Output" },
+ { "SPKOUT", NULL, "SPKOUTR Output" },
};
static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
@@ -2353,7 +2419,7 @@ static int wm8962_add_widgets(struct snd_soc_component *component)
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct wm8962_pdata *pdata = &wm8962->pdata;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_add_component_controls(component, wm8962_snd_controls,
ARRAY_SIZE(wm8962_snd_controls));
@@ -2400,7 +2466,9 @@ static const int sysclk_rates[] = {
static void wm8962_configure_bclk(struct snd_soc_component *component)
{
+ 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;
@@ -2438,13 +2506,21 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
* 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_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+ 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_component_read32(component, 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_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+ 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);
@@ -2471,23 +2547,25 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
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(component->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(component->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(component->dev, "Selected LRCLK divisor %d for %dHz\n",
@@ -2502,6 +2580,8 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
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;
@@ -2519,7 +2599,7 @@ static int wm8962_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x100);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
msleep(100);
break;
@@ -2552,6 +2632,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
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;
@@ -2602,7 +2683,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
wm8962->bclk, wm8962->lrclk);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON)
wm8962_configure_bclk(component);
return 0;
@@ -2639,12 +2720,13 @@ 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_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;
- /* fall through */
+ fallthrough;
case SND_SOC_DAIFMT_DSP_A:
aif0 |= 3;
@@ -2685,11 +2767,13 @@ 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;
@@ -2810,7 +2894,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
{
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;
@@ -2843,8 +2927,12 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
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_component_update_bits(component, WM8962_FLL_CONTROL_1,
@@ -2853,7 +2941,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
break;
default:
- dev_err(component->dev, "Unknown FLL source %d\n", ret);
+ dev_err(component->dev, "Unknown FLL source %d\n", source);
return -EINVAL;
}
@@ -2878,9 +2966,8 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
reinit_completion(&wm8962->fll_lock);
- ret = pm_runtime_get_sync(component->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
- pm_runtime_put_noidle(component->dev);
dev_err(component->dev, "Failed to resume device: %d\n", ret);
return ret;
}
@@ -2895,14 +2982,14 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
* 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) {
+ 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);
@@ -2917,7 +3004,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
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_component *component = dai->component;
int val, ret;
@@ -2950,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 = {
@@ -2970,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)
@@ -2983,7 +3071,7 @@ static void wm8962_mic_work(struct work_struct *work)
int irq_pol = 0;
int reg;
- reg = snd_soc_component_read32(component, WM8962_ADDITIONAL_CONTROL_4);
+ reg = snd_soc_component_read(component, WM8962_ADDITIONAL_CONTROL_4);
if (reg & WM8962_MICDET_STS) {
status |= SND_JACK_MICROPHONE;
@@ -3011,9 +3099,8 @@ 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) {
- pm_runtime_put_noidle(dev);
dev_err(dev, "Failed to resume: %d\n", ret);
return IRQ_NONE;
}
@@ -3110,7 +3197,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int irq_mask, enable;
wm8962->jack = jack;
@@ -3156,7 +3243,7 @@ static void wm8962_beep_work(struct work_struct *work)
struct wm8962_priv *wm8962 =
container_of(work, struct wm8962_priv, beep_work);
struct snd_soc_component *component = wm8962->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
int reg = 0;
int best = 0;
@@ -3200,6 +3287,7 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
case SND_BELL:
if (hz)
hz = 1000;
+ fallthrough;
case SND_TONE:
break;
default:
@@ -3212,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;
@@ -3229,7 +3316,7 @@ 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_component *component)
{
@@ -3328,13 +3415,16 @@ 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_component *component = wm8962->component;
- snd_soc_component_update_bits(component, 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,
@@ -3402,7 +3492,7 @@ static void wm8962_free_gpio(struct snd_soc_component *component)
static int wm8962_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int i;
@@ -3436,8 +3526,14 @@ static int wm8962_probe(struct snd_soc_component *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_component_read32(component, 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,7 +3547,7 @@ static int wm8962_probe(struct snd_soc_component *component)
}
if (!dmicclk || !dmicdat) {
dev_dbg(component->dev, "DMIC not in use, disabling\n");
- snd_soc_dapm_nc_pin(dapm, "DMICDAT");
+ snd_soc_dapm_disable_pin(dapm, "DMICDAT");
}
if (dmicclk != dmicdat)
dev_warn(component->dev, "DMIC GPIOs partially configured\n");
@@ -3479,7 +3575,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8962 = {
.set_pll = wm8962_set_fll,
.use_pmdown_time = 1,
.endianness = 1,
- .non_legacy_dai_naming = 1,
};
/* Improve power consumption for IN4 DC measurement mode */
@@ -3498,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,
@@ -3526,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;
@@ -3560,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,6 +3836,11 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
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 */
@@ -3766,13 +3856,11 @@ err:
return ret;
}
-static int wm8962_i2c_remove(struct i2c_client *client)
+static void wm8962_i2c_remove(struct i2c_client *client)
{
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);
@@ -3823,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;
@@ -3836,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);
@@ -3852,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);
@@ -3874,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,