summaryrefslogtreecommitdiffstats
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.c118
1 files changed, 96 insertions, 22 deletions
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index f7b0b37..f5fccc7 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -11,10 +11,13 @@
#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>
@@ -255,6 +258,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:
@@ -389,6 +393,7 @@ 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),
@@ -426,7 +431,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = {
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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -466,7 +471,7 @@ 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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -665,7 +670,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),
@@ -875,7 +880,7 @@ static const char *dmic_mux_text[] = { "ADC", "DMIC" };
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" };
@@ -1175,8 +1180,7 @@ 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_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
@@ -1544,19 +1548,19 @@ 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)
@@ -1673,6 +1677,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
+ max98090->master = false;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* Set to master mode */
@@ -1689,6 +1694,7 @@ 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:
@@ -1792,16 +1798,22 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- 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:
+ /*
+ * 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)) {
+ if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
+ clk_disable_unprepare(max98090->mclk);
+ else
+ clk_prepare_enable(max98090->mclk);
+ }
break;
case SND_SOC_BIAS_STANDBY:
@@ -1872,7 +1884,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- max98090_configure_bclk(codec);
+ if (max98090->master)
+ max98090_configure_bclk(codec);
cdata->rate = max98090->lrclk;
@@ -1930,6 +1943,11 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
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)..
@@ -1951,8 +1969,6 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
max98090->sysclk = freq;
- max98090_configure_bclk(codec);
-
return 0;
}
@@ -2216,6 +2232,10 @@ static int max98090_probe(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "max98090_probe\n");
+ max98090->mclk = devm_clk_get(codec->dev, "mclk");
+ if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
max98090->codec = codec;
/* Reset the codec, the DSP core, and disable all interrupts */
@@ -2224,6 +2244,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
/* Initialize private data */
max98090->sysclk = (unsigned)-1;
+ max98090->master = false;
cdata = &max98090->dai[0];
cdata->rate = (unsigned)-1;
@@ -2293,6 +2314,9 @@ static int max98090_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
M98090_VCM_MODE_MASK);
+ snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
+ M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
+
max98090_handle_pdata(codec);
max98090_add_widgets(codec);
@@ -2329,9 +2353,11 @@ static const struct regmap_config max98090_regmap = {
};
static int max98090_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *i2c_id)
{
struct max98090_priv *max98090;
+ const struct acpi_device_id *acpi_id;
+ kernel_ulong_t driver_data = 0;
int ret;
pr_debug("max98090_i2c_probe\n");
@@ -2341,7 +2367,19 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
if (max98090 == NULL)
return -ENOMEM;
- max98090->devtype = id->driver_data;
+ if (ACPI_HANDLE(&i2c->dev)) {
+ acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
+ &i2c->dev);
+ if (!acpi_id) {
+ dev_err(&i2c->dev, "No driver data\n");
+ return -EINVAL;
+ }
+ driver_data = acpi_id->driver_data;
+ } else if (i2c_id) {
+ driver_data = i2c_id->driver_data;
+ }
+
+ max98090->devtype = driver_data;
i2c_set_clientdata(i2c, max98090);
max98090->pdata = i2c->dev.platform_data;
max98090->irq = i2c->irq;
@@ -2373,6 +2411,8 @@ static int max98090_runtime_resume(struct device *dev)
regcache_cache_only(max98090->regmap, false);
+ max98090_reset(max98090);
+
regcache_sync(max98090->regmap);
return 0;
@@ -2388,9 +2428,34 @@ static int max98090_runtime_suspend(struct device *dev)
}
#endif
+#ifdef CONFIG_PM
+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 int max98090_suspend(struct device *dev)
+{
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops max98090_pm = {
SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
max98090_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume)
};
static const struct i2c_device_id max98090_i2c_id[] = {
@@ -2405,12 +2470,21 @@ static const struct of_device_id max98090_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max98090_of_match);
+#ifdef CONFIG_ACPI
+static 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,
.of_match_table = of_match_ptr(max98090_of_match),
+ .acpi_match_table = ACPI_PTR(max98090_acpi_match),
},
.probe = max98090_i2c_probe,
.remove = max98090_i2c_remove,
OpenPOWER on IntegriCloud