summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/max98090.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/max98090.c')
-rw-r--r--sound/soc/codecs/max98090.c1340
1 files changed, 831 insertions, 509 deletions
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index ad5313f98f28..13a15459040f 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1,20 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max98090.c -- MAX98090 ALSA SoC Audio driver
*
* Copyright 2011-2012 Maxim Integrated Products
- *
- * 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/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -23,12 +22,8 @@
#include <sound/max98090.h>
#include "max98090.h"
-#define DEBUG
-#define EXTMIC_METHOD
-#define EXTMIC_METHOD_TEST
-
/* Allows for sparsely populated register maps */
-static struct reg_default max98090_reg[] = {
+static const struct reg_default max98090_reg[] = {
{ 0x00, 0x00 }, /* 00 Software Reset */
{ 0x03, 0x04 }, /* 03 Interrupt Masks */
{ 0x04, 0x00 }, /* 04 System Clock Quick */
@@ -255,6 +250,7 @@ static struct reg_default max98090_reg[] = {
static bool max98090_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case M98090_REG_SOFTWARE_RESET:
case M98090_REG_DEVICE_STATUS:
case M98090_REG_JACK_STATUS:
case M98090_REG_REVISION_ID:
@@ -267,75 +263,9 @@ static bool max98090_volatile_register(struct device *dev, unsigned int reg)
static bool max98090_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case M98090_REG_DEVICE_STATUS:
- case M98090_REG_JACK_STATUS:
- case M98090_REG_INTERRUPT_S:
- case M98090_REG_RESERVED:
- case M98090_REG_LINE_INPUT_CONFIG:
- case M98090_REG_LINE_INPUT_LEVEL:
- case M98090_REG_INPUT_MODE:
- case M98090_REG_MIC1_INPUT_LEVEL:
- case M98090_REG_MIC2_INPUT_LEVEL:
- case M98090_REG_MIC_BIAS_VOLTAGE:
- case M98090_REG_DIGITAL_MIC_ENABLE:
- case M98090_REG_DIGITAL_MIC_CONFIG:
- case M98090_REG_LEFT_ADC_MIXER:
- case M98090_REG_RIGHT_ADC_MIXER:
- case M98090_REG_LEFT_ADC_LEVEL:
- case M98090_REG_RIGHT_ADC_LEVEL:
- case M98090_REG_ADC_BIQUAD_LEVEL:
- case M98090_REG_ADC_SIDETONE:
- case M98090_REG_SYSTEM_CLOCK:
- case M98090_REG_CLOCK_MODE:
- case M98090_REG_CLOCK_RATIO_NI_MSB:
- case M98090_REG_CLOCK_RATIO_NI_LSB:
- case M98090_REG_CLOCK_RATIO_MI_MSB:
- case M98090_REG_CLOCK_RATIO_MI_LSB:
- case M98090_REG_MASTER_MODE:
- case M98090_REG_INTERFACE_FORMAT:
- case M98090_REG_TDM_CONTROL:
- case M98090_REG_TDM_FORMAT:
- case M98090_REG_IO_CONFIGURATION:
- case M98090_REG_FILTER_CONFIG:
- case M98090_REG_DAI_PLAYBACK_LEVEL:
- case M98090_REG_DAI_PLAYBACK_LEVEL_EQ:
- case M98090_REG_LEFT_HP_MIXER:
- case M98090_REG_RIGHT_HP_MIXER:
- case M98090_REG_HP_CONTROL:
- case M98090_REG_LEFT_HP_VOLUME:
- case M98090_REG_RIGHT_HP_VOLUME:
- case M98090_REG_LEFT_SPK_MIXER:
- case M98090_REG_RIGHT_SPK_MIXER:
- case M98090_REG_SPK_CONTROL:
- case M98090_REG_LEFT_SPK_VOLUME:
- case M98090_REG_RIGHT_SPK_VOLUME:
- case M98090_REG_DRC_TIMING:
- case M98090_REG_DRC_COMPRESSOR:
- case M98090_REG_DRC_EXPANDER:
- case M98090_REG_DRC_GAIN:
- case M98090_REG_RCV_LOUTL_MIXER:
- case M98090_REG_RCV_LOUTL_CONTROL:
- case M98090_REG_RCV_LOUTL_VOLUME:
- case M98090_REG_LOUTR_MIXER:
- case M98090_REG_LOUTR_CONTROL:
- case M98090_REG_LOUTR_VOLUME:
- case M98090_REG_JACK_DETECT:
- case M98090_REG_INPUT_ENABLE:
- case M98090_REG_OUTPUT_ENABLE:
- case M98090_REG_LEVEL_CONTROL:
- case M98090_REG_DSP_FILTER_ENABLE:
- case M98090_REG_BIAS_CONTROL:
- case M98090_REG_DAC_CONTROL:
- case M98090_REG_ADC_CONTROL:
- case M98090_REG_DEVICE_SHUTDOWN:
- case M98090_REG_EQUALIZER_BASE ... M98090_REG_EQUALIZER_BASE + 0x68:
- case M98090_REG_RECORD_BIQUAD_BASE ... M98090_REG_RECORD_BIQUAD_BASE + 0x0E:
- case M98090_REG_DMIC3_VOLUME:
- case M98090_REG_DMIC4_VOLUME:
- case M98090_REG_DMIC34_BQ_PREATTEN:
- case M98090_REG_RECORD_TDM_SLOT:
- case M98090_REG_SAMPLE_RATE:
- case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+ case M98090_REG_DEVICE_STATUS ... M98090_REG_INTERRUPT_S:
+ case M98090_REG_LINE_INPUT_CONFIG ... 0xD1:
+ case M98090_REG_REVISION_ID:
return true;
default:
return false;
@@ -350,7 +280,7 @@ static int max98090_reset(struct max98090_priv *max98090)
ret = regmap_write(max98090->regmap, M98090_REG_SOFTWARE_RESET,
M98090_SWRESET_MASK);
if (ret < 0) {
- dev_err(max98090->codec->dev,
+ dev_err(max98090->component->dev,
"Failed to reset codec: %d\n", ret);
return ret;
}
@@ -359,22 +289,20 @@ static int max98090_reset(struct max98090_priv *max98090)
return ret;
}
-static const unsigned int max98090_micboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(max98090_mic_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_line_single_ended_tlv,
-600, 600, 0);
-static const unsigned int max98090_line_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_line_tlv,
0, 3, TLV_DB_SCALE_ITEM(-600, 300, 0),
- 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
-};
+ 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0)
+);
static const DECLARE_TLV_DB_SCALE(max98090_avg_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0);
@@ -382,55 +310,49 @@ static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0);
-static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0);
-
-static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0);
-static const unsigned int max98090_mixout_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_mixout_tlv,
0, 1, TLV_DB_SCALE_ITEM(-1200, 250, 0),
- 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0),
-};
+ 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0)
+);
-static const unsigned int max98090_hp_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_hp_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
-static const unsigned int max98090_spk_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_spk_tlv,
0, 4, TLV_DB_SCALE_ITEM(-4800, 400, 0),
5, 10, TLV_DB_SCALE_ITEM(-2900, 300, 0),
11, 14, TLV_DB_SCALE_ITEM(-1200, 200, 0),
15, 29, TLV_DB_SCALE_ITEM(-500, 100, 0),
- 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0),
-};
+ 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0)
+);
-static const unsigned int max98090_rcv_lout_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int mask = (1 << fls(mc->max)) - 1;
- unsigned int val = snd_soc_read(codec, mc->reg);
+ unsigned int val = snd_soc_component_read(component, mc->reg);
unsigned int *select;
switch (mc->reg) {
@@ -465,14 +387,16 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int mask = (1 << fls(mc->max)) - 1;
- unsigned int sel = ucontrol->value.integer.value[0];
- unsigned int val = snd_soc_read(codec, mc->reg);
+ int sel_unchecked = ucontrol->value.integer.value[0];
+ unsigned int sel;
+ unsigned int val = snd_soc_component_read(component, mc->reg);
unsigned int *select;
+ int change;
switch (mc->reg) {
case M98090_REG_MIC1_INPUT_LEVEL:
@@ -490,6 +414,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
val = (val >> mc->shift) & mask;
+ if (sel_unchecked < 0 || sel_unchecked > mc->max)
+ return -EINVAL;
+ sel = sel_unchecked;
+
+ change = *select != sel;
*select = sel;
/* Setting a volume is only valid if it is already On */
@@ -500,11 +429,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
sel = val;
}
- snd_soc_update_bits(codec, mc->reg,
+ snd_soc_component_update_bits(component, mc->reg,
mask << mc->shift,
sel << mc->shift);
- return 0;
+ return change;
}
static const char *max98090_perf_pwr_text[] =
@@ -512,65 +441,75 @@ static const char *max98090_perf_pwr_text[] =
static const char *max98090_pwr_perf_text[] =
{ "Low Power", "High Performance" };
-static const struct soc_enum max98090_vcmbandgap_enum =
- SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum,
+ M98090_REG_BIAS_CONTROL,
+ M98090_VCM_MODE_SHIFT,
+ max98090_pwr_perf_text);
static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
-static const struct soc_enum max98090_osr128_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
- ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text);
+static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum,
+ M98090_REG_ADC_CONTROL,
+ M98090_OSR128_SHIFT,
+ max98090_osr128_text);
static const char *max98090_mode_text[] = { "Voice", "Music" };
-static const struct soc_enum max98090_mode_enum =
- SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT,
- ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_mode_enum,
+ M98090_REG_FILTER_CONFIG,
+ M98090_MODE_SHIFT,
+ max98090_mode_text);
-static const struct soc_enum max98090_filter_dmic34mode_enum =
- SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG,
- M98090_FLT_DMIC34MODE_SHIFT,
- ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum,
+ M98090_REG_FILTER_CONFIG,
+ M98090_FLT_DMIC34MODE_SHIFT,
+ max98090_mode_text);
static const char *max98090_drcatk_text[] =
{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
-static const struct soc_enum max98090_drcatk_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
- ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum,
+ M98090_REG_DRC_TIMING,
+ M98090_DRCATK_SHIFT,
+ max98090_drcatk_text);
static const char *max98090_drcrls_text[] =
{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
-static const struct soc_enum max98090_drcrls_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
- ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum,
+ M98090_REG_DRC_TIMING,
+ M98090_DRCRLS_SHIFT,
+ max98090_drcrls_text);
static const char *max98090_alccmp_text[] =
{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
-static const struct soc_enum max98090_alccmp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
- ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum,
+ M98090_REG_DRC_COMPRESSOR,
+ M98090_DRCCMP_SHIFT,
+ max98090_alccmp_text);
static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
-static const struct soc_enum max98090_drcexp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
- ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum,
+ M98090_REG_DRC_EXPANDER,
+ M98090_DRCEXP_SHIFT,
+ max98090_drcexp_text);
-static const struct soc_enum max98090_dac_perfmode_enum =
- SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT,
- ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum,
+ M98090_REG_DAC_CONTROL,
+ M98090_PERFMODE_SHIFT,
+ max98090_perf_pwr_text);
-static const struct soc_enum max98090_dachp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum,
+ M98090_REG_DAC_CONTROL,
+ M98090_DACHP_SHIFT,
+ max98090_pwr_perf_text);
-static const struct soc_enum max98090_adchp_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum,
+ M98090_REG_ADC_CONTROL,
+ M98090_ADCHP_SHIFT,
+ max98090_pwr_perf_text);
static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum),
@@ -654,7 +593,7 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_SINGLE_EXT_TLV("Digital Sidetone Volume",
M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT,
M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv,
- max98090_put_enab_tlv, max98090_micboost_tlv),
+ max98090_put_enab_tlv, max98090_sdg_tlv),
SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL,
M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0,
max98090_dvg_tlv),
@@ -794,17 +733,16 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
- unsigned int val = snd_soc_read(codec, w->reg);
+ unsigned int val = snd_soc_component_read(component, w->reg);
if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
val = (val & M98090_MIC_PA1EN_MASK) >> M98090_MIC_PA1EN_SHIFT;
else
val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT;
-
if (val >= 1) {
if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) {
max98090->pa1en = val - 1; /* Update for volatile */
@@ -830,50 +768,64 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
}
if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
- snd_soc_update_bits(codec, w->reg, M98090_MIC_PA1EN_MASK,
+ snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA1EN_MASK,
val << M98090_MIC_PA1EN_SHIFT);
else
- snd_soc_update_bits(codec, w->reg, M98090_MIC_PA2EN_MASK,
+ snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA2EN_MASK,
val << M98090_MIC_PA2EN_SHIFT);
return 0;
}
+static int max98090_shdn_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+ if (event & SND_SOC_DAPM_POST_PMU)
+ max98090->shdn_pending = true;
+
+ return 0;
+
+}
+
static const char *mic1_mux_text[] = { "IN12", "IN56" };
-static const struct soc_enum mic1_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT,
- ARRAY_SIZE(mic1_mux_text), mic1_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
+ M98090_REG_INPUT_MODE,
+ M98090_EXTMIC1_SHIFT,
+ mic1_mux_text);
static const struct snd_kcontrol_new max98090_mic1_mux =
SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum);
static const char *mic2_mux_text[] = { "IN34", "IN56" };
-static const struct soc_enum mic2_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT,
- ARRAY_SIZE(mic2_mux_text), mic2_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic2_mux_enum,
+ M98090_REG_INPUT_MODE,
+ M98090_EXTMIC2_SHIFT,
+ mic2_mux_text);
static const struct snd_kcontrol_new max98090_mic2_mux =
SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
static const char *dmic_mux_text[] = { "ADC", "DMIC" };
-static const struct soc_enum dmic_mux_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
static const struct snd_kcontrol_new max98090_dmic_mux =
- SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
+ SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);
-static const char *max98090_micpre_text[] = { "Off", "On" };
+static const char * const dmic_mX_mux_text[] = { "Enable", "Disable" };
-static const struct soc_enum max98090_pa1en_enum =
- SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
- ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_m1_enum, dmic_mX_mux_text);
+static const struct snd_kcontrol_new max98090_dmic_m1_mux =
+ SOC_DAPM_ENUM("DMIC M1 Mux", dmic_m1_enum);
-static const struct soc_enum max98090_pa2en_enum =
- SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT,
- ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_m2_enum, dmic_mX_mux_text);
+static const struct snd_kcontrol_new max98090_dmic_m2_mux =
+ SOC_DAPM_ENUM("DMIC M2 Mux", dmic_m2_enum);
/* LINEA mixer switch */
static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = {
@@ -937,13 +889,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = {
static const char *lten_mux_text[] = { "Normal", "Loopthrough" };
-static const struct soc_enum ltenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
- ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LTEN_SHIFT,
+ lten_mux_text);
-static const struct soc_enum ltenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
- ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LTEN_SHIFT,
+ lten_mux_text);
static const struct snd_kcontrol_new max98090_ltenl_mux =
SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum);
@@ -953,13 +907,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux =
static const char *lben_mux_text[] = { "Normal", "Loopback" };
-static const struct soc_enum lbenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
- ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LBEN_SHIFT,
+ lben_mux_text);
-static const struct soc_enum lbenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
- ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LBEN_SHIFT,
+ lben_mux_text);
static const struct snd_kcontrol_new max98090_lbenl_mux =
SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum);
@@ -971,13 +927,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };
static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" };
-static const struct soc_enum stenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT,
- ARRAY_SIZE(stenl_mux_text), stenl_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenl_mux_enum,
+ M98090_REG_ADC_SIDETONE,
+ M98090_DSTSL_SHIFT,
+ stenl_mux_text);
-static const struct soc_enum stenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT,
- ARRAY_SIZE(stenr_mux_text), stenr_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenr_mux_enum,
+ M98090_REG_ADC_SIDETONE,
+ M98090_DSTSR_SHIFT,
+ stenr_mux_text);
static const struct snd_kcontrol_new max98090_stenl_mux =
SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum);
@@ -1085,9 +1043,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = {
static const char *linmod_mux_text[] = { "Left Only", "Left and Right" };
-static const struct soc_enum linmod_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT,
- ARRAY_SIZE(linmod_mux_text), linmod_mux_text);
+static SOC_ENUM_SINGLE_DECL(linmod_mux_enum,
+ M98090_REG_LOUTR_MIXER,
+ M98090_LINMOD_SHIFT,
+ linmod_mux_text);
static const struct snd_kcontrol_new max98090_linmod_mux =
SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum);
@@ -1097,22 +1056,23 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" };
/*
* This is a mux as it selects the HP output, but to DAPM it is a Mixer enable
*/
-static const struct soc_enum mixhplsel_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT,
- ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum,
+ M98090_REG_HP_CONTROL,
+ M98090_MIXHPLSEL_SHIFT,
+ mixhpsel_mux_text);
static const struct snd_kcontrol_new max98090_mixhplsel_mux =
SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum);
-static const struct soc_enum mixhprsel_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT,
- ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum,
+ M98090_REG_HP_CONTROL,
+ M98090_MIXHPRSEL_SHIFT,
+ mixhpsel_mux_text);
static const struct snd_kcontrol_new max98090_mixhprsel_mux =
SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum);
static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
-
SND_SOC_DAPM_INPUT("MIC1"),
SND_SOC_DAPM_INPUT("MIC2"),
SND_SOC_DAPM_INPUT("DMICL"),
@@ -1136,9 +1096,11 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION,
M98090_SDOEN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICL_SHIFT, 0, NULL, 0),
+ M98090_DIGMICL_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICR_SHIFT, 0, NULL, 0),
+ M98090_DIGMICR_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG,
M98090_AHPF_SHIFT, 0, NULL, 0),
@@ -1152,8 +1114,10 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
0, 0, &max98090_mic2_mux),
- SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM,
- 0, 0, &max98090_dmic_mux),
+ SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),
+
+ SND_SOC_DAPM_MUX("DMIC M1 Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_dmic_m1_mux),
SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
@@ -1184,14 +1148,16 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
&max98090_right_adc_mixer_controls[0],
ARRAY_SIZE(max98090_right_adc_mixer_controls)),
- SND_SOC_DAPM_ADC("ADCL", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADLEN_SHIFT, 0),
- SND_SOC_DAPM_ADC("ADCR", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADREN_SHIFT, 0),
+ SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE,
+ M98090_ADLEN_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE,
+ M98090_ADREN_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 1,
+ SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("LBENL Mux", SND_SOC_NOPM,
@@ -1244,14 +1210,14 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
&max98090_right_rcv_mixer_controls[0],
ARRAY_SIZE(max98090_right_rcv_mixer_controls)),
- SND_SOC_DAPM_MUX("LINMOD Mux", M98090_REG_LOUTR_MIXER,
- M98090_LINMOD_SHIFT, 0, &max98090_linmod_mux),
+ SND_SOC_DAPM_MUX("LINMOD Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_linmod_mux),
- SND_SOC_DAPM_MUX("MIXHPLSEL Mux", M98090_REG_HP_CONTROL,
- M98090_MIXHPLSEL_SHIFT, 0, &max98090_mixhplsel_mux),
+ SND_SOC_DAPM_MUX("MIXHPLSEL Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_mixhplsel_mux),
- SND_SOC_DAPM_MUX("MIXHPRSEL Mux", M98090_REG_HP_CONTROL,
- M98090_MIXHPRSEL_SHIFT, 0, &max98090_mixhprsel_mux),
+ SND_SOC_DAPM_MUX("MIXHPRSEL Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_mixhprsel_mux),
SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE,
M98090_HPLEN_SHIFT, 0, NULL, 0),
@@ -1277,22 +1243,34 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
};
static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = {
-
SND_SOC_DAPM_INPUT("DMIC3"),
SND_SOC_DAPM_INPUT("DMIC4"),
SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC3_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC3_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC4_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC4_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC34_HPF", M98090_REG_FILTER_CONFIG,
+ M98090_FLT_DMIC34HPF_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("DMIC M2 Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_dmic_m2_mux),
+
+ SND_SOC_DAPM_AIF_OUT("AIFOUT2L", "HiFi Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIFOUT2R", "HiFi Capture", 0,
+ SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
-
{"MIC1 Input", NULL, "MIC1"},
{"MIC2 Input", NULL, "MIC2"},
{"DMICL", NULL, "DMICL_ENA"},
+ {"DMICL", NULL, "DMICR_ENA"},
+ {"DMICR", NULL, "DMICL_ENA"},
{"DMICR", NULL, "DMICR_ENA"},
{"DMICL", NULL, "AHPF"},
{"DMICR", NULL, "AHPF"},
@@ -1347,10 +1325,12 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"ADCL", NULL, "SHDN"},
{"ADCR", NULL, "SHDN"},
+ {"DMIC M1 Mux", "Enable", "DMICL"},
+ {"DMIC M1 Mux", "Enable", "DMICR"},
+
{"DMIC Mux", "ADC", "ADCL"},
{"DMIC Mux", "ADC", "ADCR"},
- {"DMIC Mux", "DMIC", "DMICL"},
- {"DMIC Mux", "DMIC", "DMICR"},
+ {"DMIC Mux", "DMIC", "DMIC M1 Mux"},
{"LBENL Mux", "Normal", "DMIC Mux"},
{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1376,8 +1356,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"STENL Mux", "Sidetone Left", "DMICL"},
{"STENR Mux", "Sidetone Right", "ADCR"},
{"STENR Mux", "Sidetone Right", "DMICR"},
- {"DACL", "NULL", "STENL Mux"},
- {"DACR", "NULL", "STENL Mux"},
+ {"DACL", NULL, "STENL Mux"},
+ {"DACR", NULL, "STENR Mux"},
{"AIFINL", NULL, "SHDN"},
{"AIFINR", NULL, "SHDN"},
@@ -1466,29 +1446,36 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"SPKR", NULL, "SPK Right Out"},
{"RCVL", NULL, "RCV Left Out"},
{"RCVR", NULL, "RCV Right Out"},
-
};
static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
-
/* DMIC inputs */
{"DMIC3", NULL, "DMIC3_ENA"},
{"DMIC4", NULL, "DMIC4_ENA"},
- {"DMIC3", NULL, "AHPF"},
- {"DMIC4", NULL, "AHPF"},
-
+ {"DMIC3", NULL, "DMIC34_HPF"},
+ {"DMIC4", NULL, "DMIC34_HPF"},
+
+ {"DMIC M2 Mux", "Enable", "DMIC3"},
+ {"DMIC M2 Mux", "Enable", "DMIC4"},
+
+ {"AIFOUT2L", NULL, "DMIC M2 Mux"},
+ {"AIFOUT2R", NULL, "DMIC M2 Mux"},
+ {"AIFOUT2L", NULL, "SHDN"},
+ {"AIFOUT2R", NULL, "SHDN"},
+ {"AIFOUT2L", NULL, "SDOEN"},
+ {"AIFOUT2R", NULL, "SDOEN"},
};
-static int max98090_add_widgets(struct snd_soc_codec *codec)
+static int max98090_add_widgets(struct snd_soc_component *component)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_add_codec_controls(codec, max98090_snd_controls,
+ snd_soc_add_component_controls(component, max98090_snd_controls,
ARRAY_SIZE(max98090_snd_controls));
if (max98090->devtype == MAX98091) {
- snd_soc_add_codec_controls(codec, max98091_snd_controls,
+ snd_soc_add_component_controls(component, max98091_snd_controls,
ARRAY_SIZE(max98091_snd_controls));
}
@@ -1504,7 +1491,6 @@ static int max98090_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(dapm, max98091_dapm_routes,
ARRAY_SIZE(max98091_dapm_routes));
-
}
return 0;
@@ -1521,39 +1507,39 @@ static const int lrclk_rates[] = {
};
static const int user_pclk_rates[] = {
- 13000000, 13000000
+ 13000000, 13000000, 19200000, 19200000,
};
static const int user_lrclk_rates[] = {
- 44100, 48000
+ 44100, 48000, 44100, 48000,
};
static const unsigned long long ni_value[] = {
- 3528, 768
+ 3528, 768, 441, 8
};
static const unsigned long long mi_value[] = {
- 8125, 1625
+ 8125, 1625, 1500, 25
};
-static void max98090_configure_bclk(struct snd_soc_codec *codec)
+static void max98090_configure_bclk(struct snd_soc_component *component)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
unsigned long long ni;
int i;
if (!max98090->sysclk) {
- dev_err(codec->dev, "No SYSCLK configured\n");
+ dev_err(component->dev, "No SYSCLK configured\n");
return;
}
if (!max98090->bclk || !max98090->lrclk) {
- dev_err(codec->dev, "No audio clocks configured\n");
+ dev_err(component->dev, "No audio clocks configured\n");
return;
}
/* Skip configuration when operating as slave */
- if (!(snd_soc_read(codec, M98090_REG_MASTER_MODE) &
+ if (!(snd_soc_component_read(component, M98090_REG_MASTER_MODE) &
M98090_MAS_MASK)) {
return;
}
@@ -1562,14 +1548,14 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) {
if ((pclk_rates[i] == max98090->sysclk) &&
(lrclk_rates[i] == max98090->lrclk)) {
- dev_dbg(codec->dev,
+ dev_dbg(component->dev,
"Found supported PCLK to LRCLK rates 0x%x\n",
i + 0x8);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_FREQ_MASK,
(i + 0x8) << M98090_FREQ_SHIFT);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
return;
}
@@ -1579,24 +1565,24 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(user_pclk_rates); i++) {
if ((user_pclk_rates[i] == max98090->sysclk) &&
(user_lrclk_rates[i] == max98090->lrclk)) {
- dev_dbg(codec->dev,
+ dev_dbg(component->dev,
"Found user supported PCLK to LRCLK rates\n");
- dev_dbg(codec->dev, "i %d ni %lld mi %lld\n",
+ dev_dbg(component->dev, "i %d ni %lld mi %lld\n",
i, ni_value[i], mi_value[i]);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_FREQ_MASK, 0);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK,
1 << M98090_USE_M1_SHIFT);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB,
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
(ni_value[i] >> 8) & 0x7F);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB,
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB,
ni_value[i] & 0xFF);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_MSB,
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_MSB,
(mi_value[i] >> 8) & 0x7F);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_LSB,
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_LSB,
mi_value[i] & 0xFF);
return;
@@ -1606,9 +1592,9 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
/*
* Calculate based on MI = 65536 (not as good as either method above)
*/
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_FREQ_MASK, 0);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
/*
@@ -1619,20 +1605,20 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
ni = 65536ULL * (max98090->lrclk < 50000 ? 96ULL : 48ULL)
* (unsigned long long int)max98090->lrclk;
do_div(ni, (unsigned long long int)max98090->sysclk);
- dev_info(codec->dev, "No better method found\n");
- dev_info(codec->dev, "Calculating ni %lld with mi 65536\n", ni);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB,
+ dev_info(component->dev, "No better method found\n");
+ dev_info(component->dev, "Calculating ni %lld with mi 65536\n", ni);
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
(ni >> 8) & 0x7F);
- snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF);
+ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF);
}
static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = codec_dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
- u8 regval;
+ u8 regval, tdm_regval;
max98090->dai_fmt = fmt;
cdata = &max98090->dai[0];
@@ -1641,18 +1627,20 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
cdata->fmt = fmt;
regval = 0;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Set to slave mode PLL - MAS mode off */
- snd_soc_write(codec,
+ tdm_regval = 0;
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ /* Set to consumer mode PLL - MAS mode off */
+ snd_soc_component_write(component,
M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
- snd_soc_write(codec,
+ snd_soc_component_write(component,
M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
- snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+ snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
+ max98090->master = false;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- /* Set to master mode */
+ case SND_SOC_DAIFMT_CBP_CFP:
+ /* Set to provider mode */
if (max98090->tdm_slots == 4) {
/* TDM */
regval |= M98090_MAS_MASK |
@@ -1666,14 +1654,13 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_MAS_MASK |
M98090_BSEL_32;
}
+ max98090->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
default:
- dev_err(codec->dev, "DAI clock mode unsupported");
+ dev_err(component->dev, "DAI clock mode unsupported");
return -EINVAL;
}
- snd_soc_write(codec, M98090_REG_MASTER_MODE, regval);
+ snd_soc_component_write(component, M98090_REG_MASTER_MODE, regval);
regval = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -1686,9 +1673,10 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_RJ_MASK;
break;
case SND_SOC_DAIFMT_DSP_A:
- /* Not supported mode */
+ tdm_regval |= M98090_TDM_MASK;
+ break;
default:
- dev_err(codec->dev, "DAI format unsupported");
+ dev_err(component->dev, "DAI format unsupported");
return -EINVAL;
}
@@ -1705,7 +1693,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_BCI_MASK|M98090_WCI_MASK;
break;
default:
- dev_err(codec->dev, "DAI invert mode unsupported");
+ dev_err(component->dev, "DAI invert mode unsupported");
return -EINVAL;
}
@@ -1715,11 +1703,20 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
* seen for the case of TDM mode. The remaining cases have
* normal logic.
*/
- if (max98090->tdm_slots > 1)
+ if (tdm_regval)
regval ^= M98090_BCI_MASK;
- snd_soc_write(codec,
+ snd_soc_component_write(component,
M98090_REG_INTERFACE_FORMAT, regval);
+
+ regval = 0;
+ if (tdm_regval)
+ regval = max98090->tdm_lslot << M98090_TDM_SLOTL_SHIFT |
+ max98090->tdm_rslot << M98090_TDM_SLOTR_SHIFT |
+ 0 << M98090_TDM_SLOTDLY_SHIFT;
+
+ snd_soc_component_write(component, M98090_REG_TDM_FORMAT, regval);
+ snd_soc_component_write(component, M98090_REG_TDM_CONTROL, tdm_regval);
}
return 0;
@@ -1728,110 +1725,251 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
- struct max98090_cdata *cdata;
- cdata = &max98090->dai[0];
+ struct snd_soc_component *component = codec_dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
if (slots < 0 || slots > 4)
return -EINVAL;
- max98090->tdm_slots = slots;
- max98090->tdm_width = slot_width;
-
- if (max98090->tdm_slots > 1) {
- /* SLOTL SLOTR SLOTDLY */
- snd_soc_write(codec, M98090_REG_TDM_FORMAT,
- 0 << M98090_TDM_SLOTL_SHIFT |
- 1 << M98090_TDM_SLOTR_SHIFT |
- 0 << M98090_TDM_SLOTDLY_SHIFT);
-
- /* FSW TDM */
- snd_soc_update_bits(codec, M98090_REG_TDM_CONTROL,
- M98090_TDM_MASK,
- M98090_TDM_MASK);
- }
+ if (slot_width != 16)
+ return -EINVAL;
- /*
- * Normally advisable to set TDM first, but this permits either order
- */
- cdata->fmt = 0;
- max98090_dai_set_fmt(codec_dai, max98090->dai_fmt);
+ if (rx_mask != tx_mask)
+ return -EINVAL;
+
+ if (!rx_mask)
+ return -EINVAL;
+
+ max98090->tdm_slots = slots;
+ max98090->tdm_lslot = ffs(rx_mask) - 1;
+ max98090->tdm_rslot = fls(rx_mask) - 1;
return 0;
}
-static int max98090_set_bias_level(struct snd_soc_codec *codec,
+static int max98090_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
case SND_SOC_BIAS_ON:
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = regcache_sync(max98090->regmap);
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /*
+ * SND_SOC_BIAS_PREPARE is called while preparing for a
+ * transition to ON or away from ON. If current bias_level
+ * is SND_SOC_BIAS_ON, then it is preparing for a transition
+ * away from ON. Disable the clock in that case, otherwise
+ * enable it.
+ */
+ if (IS_ERR(max98090->mclk))
+ break;
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
+ clk_disable_unprepare(max98090->mclk);
+ } else {
+ ret = clk_prepare_enable(max98090->mclk);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
+ ret = regcache_sync(max98090->regmap);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"Failed to sync cache: %d\n", ret);
return ret;
}
}
-
- if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
- /*
- * Set to normal bias level.
- */
- snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
- M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
- }
break;
- case SND_SOC_BIAS_PREPARE:
- break;
-
- case SND_SOC_BIAS_STANDBY:
case SND_SOC_BIAS_OFF:
/* Set internal pull-up to lowest power mode */
- snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+ snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
M98090_JDWK_MASK, M98090_JDWK_MASK);
regcache_mark_dirty(max98090->regmap);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
-static const int comp_pclk_rates[] = {
- 11289600, 12288000, 12000000, 13000000, 19200000
-};
-
-static const int dmic_micclk[] = {
- 2, 2, 2, 2, 4, 2
-};
+static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 };
static const int comp_lrclk_rates[] = {
8000, 16000, 32000, 44100, 48000, 96000
};
-static const int dmic_comp[6][6] = {
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 1, 1, 1},
- {7, 8, 3, 1, 2, 2},
- {7, 8, 3, 3, 3, 3}
+struct dmic_table {
+ int pclk;
+ struct {
+ int freq;
+ int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */
+ } settings[6]; /* One for each dmic divisor. */
+};
+
+static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
+ {
+ .pclk = 11289600,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ },
+ },
+ {
+ .pclk = 12000000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ }
+ },
+ {
+ .pclk = 12288000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ }
+ },
+ {
+ .pclk = 13000000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ }
+ },
+ {
+ .pclk = 19200000,
+ .settings = {
+ { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } },
+ { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ }
+ },
};
+static int max98090_find_divisor(int target_freq, int pclk)
+{
+ int current_diff = INT_MAX;
+ int test_diff;
+ int divisor_index = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) {
+ test_diff = abs(target_freq - (pclk / dmic_divisors[i]));
+ if (test_diff < current_diff) {
+ current_diff = test_diff;
+ divisor_index = i;
+ }
+ }
+
+ return divisor_index;
+}
+
+static int max98090_find_closest_pclk(int pclk)
+{
+ int m1;
+ int m2;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dmic_table); i++) {
+ if (pclk == dmic_table[i].pclk)
+ return i;
+ if (pclk < dmic_table[i].pclk) {
+ if (i == 0)
+ return i;
+ m1 = pclk - dmic_table[i-1].pclk;
+ m2 = dmic_table[i].pclk - pclk;
+ if (m1 < m2)
+ return i - 1;
+ else
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int max98090_configure_dmic(struct max98090_priv *max98090,
+ int target_dmic_clk, int pclk, int fs)
+{
+ int micclk_index;
+ int pclk_index;
+ int dmic_freq;
+ int dmic_comp;
+ int i;
+
+ pclk_index = max98090_find_closest_pclk(pclk);
+ if (pclk_index < 0)
+ return pclk_index;
+
+ micclk_index = max98090_find_divisor(target_dmic_clk, pclk);
+
+ for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
+ if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2)
+ break;
+ }
+
+ dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
+ dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
+
+ regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
+ M98090_MICCLK_MASK,
+ micclk_index << M98090_MICCLK_SHIFT);
+
+ regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG,
+ M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
+ dmic_comp << M98090_DMIC_COMP_SHIFT |
+ dmic_freq << M98090_DMIC_FREQ_SHIFT);
+
+ return 0;
+}
+
+static int max98090_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+ unsigned int fmt = max98090->dai_fmt;
+
+ /* Remove 24-bit format support if it is not in right justified mode. */
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_RIGHT_J) {
+ substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(substream->runtime, 0, 16, 16);
+ }
+ return 0;
+}
+
static int max98090_dai_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 max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
- int i, j;
cdata = &max98090->dai[0];
max98090->bclk = snd_soc_params_to_bclk(params);
@@ -1840,56 +1978,38 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
max98090->lrclk = params_rate(params);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT,
+ switch (params_width(params)) {
+ case 16:
+ snd_soc_component_update_bits(component, M98090_REG_INTERFACE_FORMAT,
M98090_WS_MASK, 0);
break;
default:
return -EINVAL;
}
- max98090_configure_bclk(codec);
+ if (max98090->master)
+ max98090_configure_bclk(component);
cdata->rate = max98090->lrclk;
/* Update filter mode */
if (max98090->lrclk < 24000)
- snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+ snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
M98090_MODE_MASK, 0);
else
- snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+ snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
M98090_MODE_MASK, M98090_MODE_MASK);
/* Update sample rate mode */
if (max98090->lrclk < 50000)
- snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+ snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
M98090_DHF_MASK, 0);
else
- snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+ snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
M98090_DHF_MASK, M98090_DHF_MASK);
- /* Check for supported PCLK to LRCLK ratios */
- for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) {
- if (comp_pclk_rates[j] == max98090->sysclk) {
- break;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
- if (max98090->lrclk <= (comp_lrclk_rates[i] +
- comp_lrclk_rates[i + 1]) / 2) {
- break;
- }
- }
-
- snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_MICCLK_MASK,
- dmic_micclk[j] << M98090_MICCLK_SHIFT);
-
- snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG,
- M98090_DMIC_COMP_MASK,
- dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT);
+ max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
+ max98090->lrclk);
return 0;
}
@@ -1900,58 +2020,174 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
/* Requested clock frequency is already setup */
if (freq == max98090->sysclk)
return 0;
+ if (!IS_ERR(max98090->mclk)) {
+ freq = clk_round_rate(max98090->mclk, freq);
+ clk_set_rate(max98090->mclk, freq);
+ }
+
/* Setup clocks for slave mode, and using the PLL
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
* 0x02 (when master clk is 20MHz to 40MHz)..
* 0x03 (when master clk is 40MHz to 60MHz)..
*/
- if ((freq >= 10000000) && (freq < 20000000)) {
- snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+ if ((freq >= 10000000) && (freq <= 20000000)) {
+ snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV1);
- } else if ((freq >= 20000000) && (freq < 40000000)) {
- snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+ max98090->pclk = freq;
+ } else if ((freq > 20000000) && (freq <= 40000000)) {
+ snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV2);
- } else if ((freq >= 40000000) && (freq < 60000000)) {
- snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+ max98090->pclk = freq >> 1;
+ } else if ((freq > 40000000) && (freq <= 60000000)) {
+ snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV4);
+ max98090->pclk = freq >> 2;
} else {
- dev_err(codec->dev, "Invalid master clock frequency\n");
+ dev_err(component->dev, "Invalid master clock frequency\n");
return -EINVAL;
}
max98090->sysclk = freq;
- max98090_configure_bclk(codec);
-
return 0;
}
-static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+static int max98090_dai_mute(struct snd_soc_dai *codec_dai, int mute,
+ int direction)
{
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_component *component = codec_dai->component;
int regval;
regval = mute ? M98090_DVM_MASK : 0;
- snd_soc_update_bits(codec, M98090_REG_DAI_PLAYBACK_LEVEL,
+ snd_soc_component_update_bits(component, M98090_REG_DAI_PLAYBACK_LEVEL,
M98090_DVM_MASK, regval);
return 0;
}
+static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!max98090->master && snd_soc_dai_active(dai) == 1)
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->pll_det_enable_work,
+ msecs_to_jiffies(10));
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!max98090->master && snd_soc_dai_active(dai) == 1)
+ schedule_work(&max98090->pll_det_disable_work);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void max98090_pll_det_enable_work(struct work_struct *work)
+{
+ struct max98090_priv *max98090 =
+ container_of(work, struct max98090_priv,
+ pll_det_enable_work.work);
+ struct snd_soc_component *component = max98090->component;
+ unsigned int status, mask;
+
+ /*
+ * Clear status register in order to clear possibly already occurred
+ * PLL unlock. If PLL hasn't still locked, the status will be set
+ * again and PLL unlock interrupt will occur.
+ * Note this will clear all status bits
+ */
+ regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+ /*
+ * Queue jack work in case jack state has just changed but handler
+ * hasn't run yet
+ */
+ regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+ status &= mask;
+ if (status & M98090_JDET_MASK)
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->jack_work,
+ msecs_to_jiffies(100));
+
+ /* Enable PLL unlock interrupt */
+ snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+ M98090_IULK_MASK,
+ 1 << M98090_IULK_SHIFT);
+}
+
+static void max98090_pll_det_disable_work(struct work_struct *work)
+{
+ struct max98090_priv *max98090 =
+ container_of(work, struct max98090_priv, pll_det_disable_work);
+ struct snd_soc_component *component = max98090->component;
+
+ cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+
+ /* Disable PLL unlock interrupt */
+ snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+ M98090_IULK_MASK, 0);
+}
+
+static void max98090_pll_work(struct max98090_priv *max98090)
+{
+ struct snd_soc_component *component = max98090->component;
+ unsigned int pll;
+ int i;
+
+ if (!snd_soc_component_active(component))
+ return;
+
+ dev_info_ratelimited(component->dev, "PLL unlocked\n");
+
+ /*
+ * As the datasheet suggested, the maximum PLL lock time should be
+ * 7 msec. The workaround resets the codec softly by toggling SHDN
+ * off and on if PLL failed to lock for 10 msec. Notably, there is
+ * no suggested hold time for SHDN off.
+ */
+
+ /* Toggle shutdown OFF then ON */
+ snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, 0);
+ snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+
+ for (i = 0; i < 10; ++i) {
+ /* Give PLL time to lock */
+ usleep_range(1000, 1200);
+
+ /* Check lock status */
+ pll = snd_soc_component_read(
+ component, M98090_REG_DEVICE_STATUS);
+ if (!(pll & M98090_ULK_MASK))
+ break;
+ }
+}
+
static void max98090_jack_work(struct work_struct *work)
{
struct max98090_priv *max98090 = container_of(work,
struct max98090_priv,
jack_work.work);
- struct snd_soc_codec *codec = max98090->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_component *component = max98090->component;
int status = 0;
int reg;
@@ -1959,25 +2195,23 @@ static void max98090_jack_work(struct work_struct *work)
if (max98090->jack_state == M98090_JACK_STATE_NO_HEADSET) {
/* Strong pull up allows mic detection */
- snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+ snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
M98090_JDWK_MASK, 0);
msleep(50);
- reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
+ snd_soc_component_read(component, M98090_REG_JACK_STATUS);
/* Weak pull up allows only insertion detection */
- snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+ snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
M98090_JDWK_MASK, M98090_JDWK_MASK);
- } else {
- reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
}
- reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
+ reg = snd_soc_component_read(component, M98090_REG_JACK_STATUS);
switch (reg & (M98090_LSNS_MASK | M98090_JKSNS_MASK)) {
case M98090_LSNS_MASK | M98090_JKSNS_MASK:
- dev_dbg(codec->dev, "No Headset Detected\n");
+ dev_dbg(component->dev, "No Headset Detected\n");
max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
@@ -1989,7 +2223,7 @@ static void max98090_jack_work(struct work_struct *work)
if (max98090->jack_state ==
M98090_JACK_STATE_HEADSET) {
- dev_dbg(codec->dev,
+ dev_dbg(component->dev,
"Headset Button Down Detected\n");
/*
@@ -2006,7 +2240,7 @@ static void max98090_jack_work(struct work_struct *work)
/* Line is reported as Headphone */
/* Nokia Headset is reported as Headphone */
/* Mono Headphone is reported as Headphone */
- dev_dbg(codec->dev, "Headphone Detected\n");
+ dev_dbg(component->dev, "Headphone Detected\n");
max98090->jack_state = M98090_JACK_STATE_HEADPHONE;
@@ -2015,7 +2249,7 @@ static void max98090_jack_work(struct work_struct *work)
break;
case M98090_JKSNS_MASK:
- dev_dbg(codec->dev, "Headset Detected\n");
+ dev_dbg(component->dev, "Headset Detected\n");
max98090->jack_state = M98090_JACK_STATE_HEADSET;
@@ -2024,30 +2258,32 @@ static void max98090_jack_work(struct work_struct *work)
break;
default:
- dev_dbg(codec->dev, "Unrecognized Jack Status\n");
+ dev_dbg(component->dev, "Unrecognized Jack Status\n");
break;
}
snd_soc_jack_report(max98090->jack, status,
SND_JACK_HEADSET | SND_JACK_BTN_0);
-
- snd_soc_dapm_sync(dapm);
}
static irqreturn_t max98090_interrupt(int irq, void *data)
{
- struct snd_soc_codec *codec = data;
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = data;
+ struct snd_soc_component *component = max98090->component;
int ret;
unsigned int mask;
unsigned int active;
- dev_dbg(codec->dev, "***** max98090_interrupt *****\n");
+ /* Treat interrupt before codec is initialized as spurious */
+ if (component == NULL)
+ return IRQ_NONE;
+
+ dev_dbg(component->dev, "***** max98090_interrupt *****\n");
ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"failed to read M98090_REG_INTERRUPT_S: %d\n",
ret);
return IRQ_NONE;
@@ -2056,13 +2292,13 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
ret = regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &active);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"failed to read M98090_REG_DEVICE_STATUS: %d\n",
ret);
return IRQ_NONE;
}
- dev_dbg(codec->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n",
+ dev_dbg(component->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n",
active, mask, active & mask);
active &= mask;
@@ -2071,28 +2307,31 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
return IRQ_NONE;
if (active & M98090_CLD_MASK)
- dev_err(codec->dev, "M98090_CLD_MASK\n");
+ dev_err(component->dev, "M98090_CLD_MASK\n");
if (active & M98090_SLD_MASK)
- dev_dbg(codec->dev, "M98090_SLD_MASK\n");
+ dev_dbg(component->dev, "M98090_SLD_MASK\n");
- if (active & M98090_ULK_MASK)
- dev_err(codec->dev, "M98090_ULK_MASK\n");
+ if (active & M98090_ULK_MASK) {
+ dev_dbg(component->dev, "M98090_ULK_MASK\n");
+ max98090_pll_work(max98090);
+ }
if (active & M98090_JDET_MASK) {
- dev_dbg(codec->dev, "M98090_JDET_MASK\n");
+ dev_dbg(component->dev, "M98090_JDET_MASK\n");
- pm_wakeup_event(codec->dev, 100);
+ pm_wakeup_event(component->dev, 100);
- schedule_delayed_work(&max98090->jack_work,
- msecs_to_jiffies(100));
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->jack_work,
+ msecs_to_jiffies(100));
}
if (active & M98090_DRCACT_MASK)
- dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
+ dev_dbg(component->dev, "M98090_DRCACT_MASK\n");
if (active & M98090_DRCCLP_MASK)
- dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
+ dev_err(component->dev, "M98090_DRCCLP_MASK\n");
return IRQ_HANDLED;
}
@@ -2100,7 +2339,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
/**
* max98090_mic_detect - Enable microphone detection via the MAX98090 IRQ
*
- * @codec: MAX98090 codec
+ * @component: MAX98090 component
* @jack: jack to report detection events on
*
* Enable microphone detection via IRQ on the MAX98090. If GPIOs are
@@ -2110,20 +2349,20 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
*
* If no jack is supplied detection will be disabled.
*/
-int max98090_mic_detect(struct snd_soc_codec *codec,
+int max98090_mic_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
- dev_dbg(codec->dev, "max98090_mic_detect\n");
+ dev_dbg(component->dev, "max98090_mic_detect\n");
max98090->jack = jack;
if (jack) {
- snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+ snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
M98090_IJDET_MASK,
1 << M98090_IJDET_SHIFT);
} else {
- snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+ snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
M98090_IJDET_MASK,
0);
}
@@ -2132,8 +2371,9 @@ int max98090_mic_detect(struct snd_soc_codec *codec,
snd_soc_jack_report(max98090->jack, 0,
SND_JACK_HEADSET | SND_JACK_BTN_0);
- schedule_delayed_work(&max98090->jack_work,
- msecs_to_jiffies(100));
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->jack_work,
+ msecs_to_jiffies(100));
return 0;
}
@@ -2142,16 +2382,18 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect);
#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops max98090_dai_ops = {
+static const struct snd_soc_dai_ops max98090_dai_ops = {
+ .startup = max98090_dai_startup,
.set_sysclk = max98090_dai_set_sysclk,
.set_fmt = max98090_dai_set_fmt,
.set_tdm_slot = max98090_set_tdm_slot,
.hw_params = max98090_dai_hw_params,
- .digital_mute = max98090_dai_digital_mute,
+ .mute_stream = max98090_dai_mute,
+ .trigger = max98090_dai_trigger,
+ .no_capture_mute = 1,
};
-static struct snd_soc_dai_driver max98090_dai[] = {
-{
+static struct snd_soc_dai_driver max98090_dai = {
.name = "HiFi",
.playback = {
.stream_name = "HiFi Playback",
@@ -2163,43 +2405,29 @@ static struct snd_soc_dai_driver max98090_dai[] = {
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rates = MAX98090_RATES,
.formats = MAX98090_FORMATS,
},
- .ops = &max98090_dai_ops,
-}
+ .ops = &max98090_dai_ops,
};
-static void max98090_handle_pdata(struct snd_soc_codec *codec)
-{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
- struct max98090_pdata *pdata = max98090->pdata;
-
- if (!pdata) {
- dev_err(codec->dev, "No platform data\n");
- return;
- }
-
-}
-
-static int max98090_probe(struct snd_soc_codec *codec)
+static int max98090_probe(struct snd_soc_component *component)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
+ enum max98090_type devtype;
int ret = 0;
+ int err;
+ unsigned int micbias;
- dev_dbg(codec->dev, "max98090_probe\n");
+ dev_dbg(component->dev, "max98090_probe\n");
- max98090->codec = codec;
+ max98090->mclk = devm_clk_get(component->dev, "mclk");
+ if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
- codec->control_data = max98090->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
+ max98090->component = component;
/* Reset the codec, the DSP core, and disable all interrupts */
max98090_reset(max98090);
@@ -2207,6 +2435,8 @@ static int max98090_probe(struct snd_soc_codec *codec)
/* Initialize private data */
max98090->sysclk = (unsigned)-1;
+ max98090->pclk = (unsigned)-1;
+ max98090->master = false;
cdata = &max98090->dai[0];
cdata->rate = (unsigned)-1;
@@ -2215,88 +2445,118 @@ static int max98090_probe(struct snd_soc_codec *codec)
max98090->lin_state = 0;
max98090->pa1en = 0;
max98090->pa2en = 0;
- max98090->extmic_mux = 0;
- ret = snd_soc_read(codec, M98090_REG_REVISION_ID);
+ max98090->tdm_lslot = 0;
+ max98090->tdm_rslot = 1;
+
+ ret = snd_soc_component_read(component, M98090_REG_REVISION_ID);
if (ret < 0) {
- dev_err(codec->dev, "Failed to read device revision: %d\n",
+ dev_err(component->dev, "Failed to read device revision: %d\n",
ret);
goto err_access;
}
if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) {
- max98090->devtype = MAX98090;
- dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret);
+ devtype = MAX98090;
+ dev_info(component->dev, "MAX98090 REVID=0x%02x\n", ret);
} else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) {
- max98090->devtype = MAX98091;
- dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret);
+ devtype = MAX98091;
+ dev_info(component->dev, "MAX98091 REVID=0x%02x\n", ret);
} else {
- max98090->devtype = MAX98090;
- dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret);
+ devtype = MAX98090;
+ dev_err(component->dev, "Unrecognized revision 0x%02x\n", ret);
+ }
+
+ if (max98090->devtype != devtype) {
+ dev_warn(component->dev, "Mismatch in DT specified CODEC type.\n");
+ max98090->devtype = devtype;
}
max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work);
+ INIT_DELAYED_WORK(&max98090->pll_det_enable_work,
+ max98090_pll_det_enable_work);
+ INIT_WORK(&max98090->pll_det_disable_work,
+ max98090_pll_det_disable_work);
/* Enable jack detection */
- snd_soc_write(codec, M98090_REG_JACK_DETECT,
+ snd_soc_component_write(component, M98090_REG_JACK_DETECT,
M98090_JDETEN_MASK | M98090_JDEB_25MS);
- /* Register for interrupts */
- dev_dbg(codec->dev, "irq = %d\n", max98090->irq);
-
- ret = request_threaded_irq(max98090->irq, NULL,
- max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "max98090_interrupt", codec);
- if (ret < 0) {
- dev_err(codec->dev, "request_irq failed: %d\n",
- ret);
- }
-
/*
* Clear any old interrupts.
* An old interrupt ocurring prior to installing the ISR
* can keep a new interrupt from generating a trigger.
*/
- snd_soc_read(codec, M98090_REG_DEVICE_STATUS);
+ snd_soc_component_read(component, M98090_REG_DEVICE_STATUS);
/* High Performance is default */
- snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL,
+ snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
M98090_DACHP_MASK,
1 << M98090_DACHP_SHIFT);
- snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL,
+ snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
M98090_PERFMODE_MASK,
0 << M98090_PERFMODE_SHIFT);
- snd_soc_update_bits(codec, M98090_REG_ADC_CONTROL,
+ snd_soc_component_update_bits(component, M98090_REG_ADC_CONTROL,
M98090_ADCHP_MASK,
1 << M98090_ADCHP_SHIFT);
/* Turn on VCM bandgap reference */
- snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
+ snd_soc_component_write(component, M98090_REG_BIAS_CONTROL,
M98090_VCM_MODE_MASK);
- max98090_handle_pdata(codec);
+ err = device_property_read_u32(component->dev, "maxim,micbias", &micbias);
+ if (err) {
+ micbias = M98090_MBVSEL_2V8;
+ dev_info(component->dev, "use default 2.8v micbias\n");
+ } else if (micbias > M98090_MBVSEL_2V8) {
+ dev_err(component->dev, "micbias out of range 0x%x\n", micbias);
+ micbias = M98090_MBVSEL_2V8;
+ }
+
+ snd_soc_component_update_bits(component, M98090_REG_MIC_BIAS_VOLTAGE,
+ M98090_MBVSEL_MASK, micbias);
- max98090_add_widgets(codec);
+ max98090_add_widgets(component);
err_access:
return ret;
}
-static int max98090_remove(struct snd_soc_codec *codec)
+static void max98090_remove(struct snd_soc_component *component)
{
- struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
cancel_delayed_work_sync(&max98090->jack_work);
+ cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+ cancel_work_sync(&max98090->pll_det_disable_work);
+ max98090->component = NULL;
+}
- return 0;
+static void max98090_seq_notifier(struct snd_soc_component *component,
+ enum snd_soc_dapm_type event, int subseq)
+{
+ struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+ if (max98090->shdn_pending) {
+ snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, 0);
+ msleep(40);
+ snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+ max98090->shdn_pending = false;
+ }
}
-static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
- .probe = max98090_probe,
- .remove = max98090_remove,
- .set_bias_level = max98090_set_bias_level,
+static const struct snd_soc_component_driver soc_component_dev_max98090 = {
+ .probe = max98090_probe,
+ .remove = max98090_remove,
+ .seq_notifier = max98090_seq_notifier,
+ .set_bias_level = max98090_set_bias_level,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
};
static const struct regmap_config max98090_regmap = {
@@ -2311,8 +2571,14 @@ static const struct regmap_config max98090_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-static int max98090_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static const struct i2c_device_id max98090_i2c_id[] = {
+ { "max98090", MAX98090 },
+ { "max98091", MAX98091 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
+
+static int max98090_i2c_probe(struct i2c_client *i2c)
{
struct max98090_priv *max98090;
int ret;
@@ -2324,11 +2590,14 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
if (max98090 == NULL)
return -ENOMEM;
- max98090->devtype = id->driver_data;
+ max98090->devtype = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, max98090);
- max98090->control_data = i2c;
max98090->pdata = i2c->dev.platform_data;
- max98090->irq = i2c->irq;
+
+ ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq",
+ &max98090->dmic_freq);
+ if (ret < 0)
+ max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ;
max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
if (IS_ERR(max98090->regmap)) {
@@ -2337,26 +2606,50 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
goto err_enable;
}
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_max98090, max98090_dai,
- ARRAY_SIZE(max98090_dai));
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "max98090_interrupt", max98090);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "request_irq failed: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_max98090,
+ &max98090_dai, 1);
err_enable:
return ret;
}
-static int max98090_i2c_remove(struct i2c_client *client)
+static void max98090_i2c_shutdown(struct i2c_client *i2c)
{
- snd_soc_unregister_codec(&client->dev);
- return 0;
+ struct max98090_priv *max98090 = dev_get_drvdata(&i2c->dev);
+
+ /*
+ * Enable volume smoothing, disable zero cross. This will cause
+ * a quick 40ms ramp to mute on shutdown.
+ */
+ regmap_write(max98090->regmap,
+ M98090_REG_LEVEL_CONTROL, M98090_VSENN_MASK);
+ regmap_write(max98090->regmap,
+ M98090_REG_DEVICE_SHUTDOWN, 0x00);
+ msleep(40);
+}
+
+static void max98090_i2c_remove(struct i2c_client *client)
+{
+ max98090_i2c_shutdown(client);
}
-#ifdef CONFIG_PM_RUNTIME
static int max98090_runtime_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
regcache_cache_only(max98090->regmap, false);
+ max98090_reset(max98090);
+
regcache_sync(max98090->regmap);
return 0;
@@ -2370,26 +2663,55 @@ static int max98090_runtime_suspend(struct device *dev)
return 0;
}
-#endif
+
+static int max98090_resume(struct device *dev)
+{
+ struct max98090_priv *max98090 = dev_get_drvdata(dev);
+ unsigned int status;
+
+ regcache_mark_dirty(max98090->regmap);
+
+ max98090_reset(max98090);
+
+ /* clear IRQ status */
+ regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+ regcache_sync(max98090->regmap);
+
+ return 0;
+}
static const struct dev_pm_ops max98090_pm = {
- SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
- max98090_runtime_resume, NULL)
+ RUNTIME_PM_OPS(max98090_runtime_suspend, max98090_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume)
};
-static const struct i2c_device_id max98090_i2c_id[] = {
- { "max98090", MAX98090 },
+#ifdef CONFIG_OF
+static const struct of_device_id max98090_of_match[] = {
+ { .compatible = "maxim,max98090", },
+ { .compatible = "maxim,max98091", },
{ }
};
-MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
+MODULE_DEVICE_TABLE(of, max98090_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98090_acpi_match[] = {
+ { "193C9890", MAX98090 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
+#endif
static struct i2c_driver max98090_i2c_driver = {
.driver = {
.name = "max98090",
- .owner = THIS_MODULE,
- .pm = &max98090_pm,
+ .pm = pm_ptr(&max98090_pm),
+ .of_match_table = of_match_ptr(max98090_of_match),
+ .acpi_match_table = ACPI_PTR(max98090_acpi_match),
},
- .probe = max98090_i2c_probe,
+ .probe = max98090_i2c_probe,
+ .shutdown = max98090_i2c_shutdown,
.remove = max98090_i2c_remove,
.id_table = max98090_i2c_id,
};