summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/dmic.c52
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c415
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c25
-rw-r--r--sound/soc/codecs/rt5663.c18
-rw-r--r--sound/soc/codecs/rt5665.c4
-rw-r--r--sound/soc/codecs/rt5665.h4
-rw-r--r--sound/soc/codecs/sgtl5000.c4
8 files changed, 482 insertions, 42 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 024ddc9938ed..aee9ef16dae6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -71,7 +71,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DIO2125
- select SND_SOC_DMIC
+ select SND_SOC_DMIC if GPIOLIB
select SND_SOC_ES8316 if I2C
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 6fe6c0ac4f0b..b88a1ee66f80 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -19,6 +19,8 @@
*
*/
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -27,6 +29,34 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+static int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai);
+
+ if (!dmic_en)
+ return 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ gpiod_set_value(dmic_en, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ gpiod_set_value(dmic_en, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .trigger = dmic_daiops_trigger,
+};
+
static struct snd_soc_dai_driver dmic_dai = {
.name = "dmic-hifi",
.capture = {
@@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &dmic_dai_ops,
};
+static int dmic_codec_probe(struct snd_soc_codec *codec)
+{
+ struct gpio_desc *dmic_en;
+
+ dmic_en = devm_gpiod_get_optional(codec->dev,
+ "dmicen", GPIOD_OUT_LOW);
+ if (IS_ERR(dmic_en))
+ return PTR_ERR(dmic_en);
+
+ snd_soc_codec_set_drvdata(codec, dmic_en);
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
SND_SOC_NOPM, 0, 0),
@@ -51,6 +96,7 @@ static const struct snd_soc_dapm_route intercon[] = {
};
static const struct snd_soc_codec_driver soc_dmic = {
+ .probe = dmic_codec_probe,
.component_driver = {
.dapm_widgets = dmic_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
@@ -73,9 +119,15 @@ static int dmic_dev_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:dmic-codec");
+static const struct of_device_id dmic_dev_match[] = {
+ {.compatible = "dmic-codec"},
+ {}
+};
+
static struct platform_driver dmic_driver = {
.driver = {
.name = "dmic-codec",
+ .of_match_table = dmic_dev_match,
},
.probe = dmic_dev_probe,
.remove = dmic_dev_remove,
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index f07674eddc52..4aa878d29098 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -12,9 +12,16 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
+#include <sound/jack.h>
#define CDC_D_REVISION1 (0xf000)
#define CDC_D_PERPH_SUBTYPE (0xf005)
+#define CDC_D_INT_EN_SET (0x015)
+#define CDC_D_INT_EN_CLR (0x016)
+#define MBHC_SWITCH_INT BIT(7)
+#define MBHC_MIC_ELECTRICAL_INS_REM_DET BIT(6)
+#define MBHC_BUTTON_PRESS_DET BIT(5)
+#define MBHC_BUTTON_RELEASE_DET BIT(4)
#define CDC_D_CDC_RST_CTL (0xf046)
#define RST_CTL_DIG_SW_RST_N_MASK BIT(7)
#define RST_CTL_DIG_SW_RST_N_RESET 0
@@ -36,7 +43,9 @@
#define CDC_D_CDC_DIG_CLK_CTL (0xf04A)
#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0)
#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1)
-#define DIG_CLK_CTL_RXD3_CLK_EN BIT(3)
+#define DIG_CLK_CTL_RXD3_CLK_EN BIT(2)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK BIT(3)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN BIT(3)
#define DIG_CLK_CTL_TXD_CLK_EN BIT(4)
#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6)
#define DIG_CLK_CTL_NCP_CLK_EN BIT(6)
@@ -93,8 +102,12 @@
#define MICB_1_EN_TX3_GND_SEL_TX_GND 0
#define CDC_A_MICB_1_VAL (0xf141)
+#define MICB_MIN_VAL 1600
+#define MICB_STEP_SIZE 50
+#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE)
#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3)
#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3)
#define CDC_A_MICB_1_CTL (0xf142)
#define MICB_1_CTL_CFILT_REF_SEL_MASK BIT(1)
@@ -128,8 +141,51 @@
#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0
#define CDC_A_MICB_2_EN (0xf144)
+#define CDC_A_MICB_2_EN_ENABLE BIT(7)
+#define CDC_A_MICB_2_PULL_DOWN_EN_MASK BIT(5)
+#define CDC_A_MICB_2_PULL_DOWN_EN BIT(5)
#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145)
#define CDC_A_MASTER_BIAS_CTL (0xf146)
+#define CDC_A_MBHC_DET_CTL_1 (0xf147)
+#define CDC_A_MBHC_DET_CTL_L_DET_EN BIT(7)
+#define CDC_A_MBHC_DET_CTL_GND_DET_EN BIT(6)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL (0)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT (5)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO BIT(4)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL BIT(3)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK GENMASK(4, 3)
+#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN BIT(2)
+#define CDC_A_MBHC_DET_CTL_2 (0xf150)
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 (BIT(7) | BIT(6))
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD BIT(5)
+#define CDC_A_PLUG_TYPE_MASK GENMASK(4, 3)
+#define CDC_A_HPHL_PLUG_TYPE_NO BIT(4)
+#define CDC_A_GND_PLUG_TYPE_NO BIT(3)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK BIT(0)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN BIT(0)
+#define CDC_A_MBHC_FSM_CTL (0xf151)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN BIT(7)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK BIT(7)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA (0x3 << 4)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK GENMASK(6, 4)
+#define CDC_A_MBHC_DBNC_TIMER (0xf152)
+#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS BIT(3)
+#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS (0x9 << 4)
+#define CDC_A_MBHC_BTN0_ZDET_CTL_0 (0xf153)
+#define CDC_A_MBHC_BTN1_ZDET_CTL_1 (0xf154)
+#define CDC_A_MBHC_BTN2_ZDET_CTL_2 (0xf155)
+#define CDC_A_MBHC_BTN3_CTL (0xf156)
+#define CDC_A_MBHC_BTN4_CTL (0xf157)
+#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT (2)
+#define CDC_A_MBHC_BTN_VREF_FINE_MASK GENMASK(4, 2)
+#define CDC_A_MBHC_BTN_VREF_COARSE_MASK GENMASK(7, 5)
+#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
+#define CDC_A_MBHC_BTN_VREF_MASK (CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
+ CDC_A_MBHC_BTN_VREF_FINE_MASK)
+#define CDC_A_MBHC_RESULT_1 (0xf158)
+#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK GENMASK(4, 0)
#define CDC_A_TX_1_EN (0xf160)
#define CDC_A_TX_2_EN (0xf161)
#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162)
@@ -213,18 +269,37 @@
#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
static const char * const supply_names[] = {
"vdd-cdc-io",
"vdd-cdc-tx-rx-cx",
};
+#define MBHC_MAX_BUTTONS (5)
+
struct pm8916_wcd_analog_priv {
u16 pmic_rev;
u16 codec_version;
+ bool mbhc_btn_enabled;
+ /* special event to detect accessory type */
+ bool mbhc_btn0_pressed;
+ bool detect_accessory_type;
struct clk *mclk;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ struct snd_soc_jack *jack;
+ bool hphl_jack_type_normally_open;
+ bool gnd_jack_type_normally_open;
+ /* Voltage threshold when internal current source of 100uA is used */
+ u32 vref_btn_cs[MBHC_MAX_BUTTONS];
+ /* Voltage threshold when microphone bias is ON */
+ u32 vref_btn_micb[MBHC_MAX_BUTTONS];
unsigned int micbias1_cap_mode;
unsigned int micbias2_cap_mode;
+ unsigned int micbias_mv;
};
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -265,18 +340,25 @@ static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
{
+ struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
MICB_1_CTL_EXT_PRECHARG_EN_MASK |
MICB_1_CTL_INT_PRECHARG_BYP_MASK,
MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
| MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
- snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V);
- /*
- * Special headset needs MICBIAS as 2.7V so wait for
- * 50 msec for the MICBIAS to reach 2.7 volts.
- */
- msleep(50);
+ if (wcd->micbias_mv) {
+ snd_soc_write(codec, CDC_A_MICB_1_VAL,
+ MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
+ /*
+ * Special headset needs MICBIAS as 2.7V so wait for
+ * 50 msec for the MICBIAS to reach 2.7 volts.
+ */
+ if (wcd->micbias_mv >= 2700)
+ msleep(50);
+ }
+
snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
MICB_1_CTL_EXT_PRECHARG_EN_MASK |
MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
@@ -361,6 +443,97 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
wcd->micbias1_cap_mode);
}
+static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
+{
+ struct snd_soc_codec *codec = wcd->codec;
+ u32 plug_type = 0;
+ u32 int_en_mask;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
+ CDC_A_MBHC_DET_CTL_L_DET_EN |
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
+ CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
+ CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
+
+ if (wcd->hphl_jack_type_normally_open)
+ plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
+
+ if (wcd->gnd_jack_type_normally_open)
+ plug_type |= CDC_A_GND_PLUG_TYPE_NO;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
+ CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
+ CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
+ plug_type |
+ CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
+
+
+ snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
+ CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
+ CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
+
+ /* enable MBHC clock */
+ snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+ DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
+ DIG_CLK_CTL_D_MBHC_CLK_EN);
+
+ int_en_mask = MBHC_SWITCH_INT;
+ if (wcd->mbhc_btn_enabled)
+ int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
+
+ snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
+ snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+ wcd->mbhc_btn0_pressed = false;
+ wcd->detect_accessory_type = true;
+}
+
+static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
+ bool micbias2_enabled)
+{
+ struct snd_soc_codec *codec = priv->codec;
+ u32 coarse, fine, reg_val, reg_addr;
+ int *vrefs, i;
+
+ if (!micbias2_enabled) { /* use internal 100uA Current source */
+ /* Enable internal 2.2k Internal Rbias Resistor */
+ snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+ MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+ MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+ /* Remove pull down on MIC BIAS2 */
+ snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
+ CDC_A_MICB_2_PULL_DOWN_EN_MASK,
+ 0);
+ /* enable 100uA internal current source */
+ snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+ CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
+ CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
+ }
+ snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+ CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
+ CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
+
+ if (micbias2_enabled)
+ vrefs = &priv->vref_btn_micb[0];
+ else
+ vrefs = &priv->vref_btn_cs[0];
+
+ /* program vref ranges for all the buttons */
+ reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
+ for (i = 0; i < MBHC_MAX_BUTTONS; i++) {
+ /* split mv in to coarse parts of 100mv & fine parts of 12mv */
+ coarse = (vrefs[i] / 100);
+ fine = ((vrefs[i] % 100) / 12);
+ reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
+ (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
+ snd_soc_update_bits(codec, reg_addr,
+ CDC_A_MBHC_BTN_VREF_MASK,
+ reg_val);
+ reg_addr++;
+ }
+
+ return 0;
+}
+
static int pm8916_wcd_analog_enable_micbias_int2(struct
snd_soc_dapm_widget
*w, struct snd_kcontrol
@@ -369,6 +542,15 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ pm8916_mbhc_configure_bias(wcd, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ pm8916_mbhc_configure_bias(wcd, false);
+ break;
+ }
+
return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
wcd->micbias2_cap_mode);
}
@@ -536,6 +718,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
wcd_reg_defaults_2_0[reg].def);
+ priv->codec = codec;
+
+ snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+ RST_CTL_DIG_SW_RST_N_MASK,
+ RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+ pm8916_wcd_setup_mbhc(priv);
+
return 0;
}
@@ -543,6 +733,9 @@ static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec)
{
struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+ snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+ RST_CTL_DIG_SW_RST_N_MASK, 0);
+
return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
priv->supplies);
}
@@ -731,32 +924,128 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
};
+static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack,
+ void *data)
+{
+ struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+ wcd->jack = jack;
+
+ return 0;
+}
+
static struct regmap *pm8916_get_regmap(struct device *dev)
{
return dev_get_regmap(dev->parent, NULL);
}
-static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
{
- snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
- RST_CTL_DIG_SW_RST_N_MASK,
- RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+ struct pm8916_wcd_analog_priv *priv = arg;
- return 0;
+ if (priv->detect_accessory_type) {
+ struct snd_soc_codec *codec = priv->codec;
+ u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
+
+ /* check if its BTN0 thats released */
+ if ((val >= 0) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
+ priv->mbhc_btn0_pressed = false;
+
+ } else {
+ snd_soc_jack_report(priv->jack, 0, btn_mask);
+ }
+
+ return IRQ_HANDLED;
}
-static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
{
- snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
- RST_CTL_DIG_SW_RST_N_MASK, 0);
+ struct pm8916_wcd_analog_priv *priv = arg;
+ struct snd_soc_codec *codec = priv->codec;
+ u32 btn_result;
+
+ btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
+ CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
+
+ switch (btn_result) {
+ case 0xf:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
+ break;
+ case 0x7:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
+ break;
+ case 0x3:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
+ break;
+ case 0x1:
+ snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
+ break;
+ case 0x0:
+ /* handle BTN_0 specially for type detection */
+ if (priv->detect_accessory_type)
+ priv->mbhc_btn0_pressed = true;
+ else
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_BTN_0, btn_mask);
+ break;
+ default:
+ dev_err(codec->dev,
+ "Unexpected button press result (%x)", btn_result);
+ break;
+ }
+
+ return IRQ_HANDLED;
}
-static const struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = {
- .startup = pm8916_wcd_analog_startup,
- .shutdown = pm8916_wcd_analog_shutdown,
-};
+static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
+{
+ struct pm8916_wcd_analog_priv *priv = arg;
+ struct snd_soc_codec *codec = priv->codec;
+ bool ins = false;
+
+ if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
+ ins = true;
+
+ /* Set the detection type appropriately */
+ snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
+ (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
+
+
+ if (ins) { /* hs insertion */
+ bool micbias_enabled = false;
+
+ if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
+ CDC_A_MICB_2_EN_ENABLE)
+ micbias_enabled = true;
+
+ pm8916_mbhc_configure_bias(priv, micbias_enabled);
+
+ /*
+ * if only a btn0 press event is receive just before
+ * insert event then its a 3 pole headphone else if
+ * both press and release event received then its
+ * a headset.
+ */
+ if (priv->mbhc_btn0_pressed)
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_HEADPHONE, hs_jack_mask);
+ else
+ snd_soc_jack_report(priv->jack,
+ SND_JACK_HEADSET, hs_jack_mask);
+
+ priv->detect_accessory_type = false;
+
+ } else { /* removal */
+ snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
+ priv->detect_accessory_type = true;
+ priv->mbhc_btn0_pressed = false;
+ }
+
+ return IRQ_HANDLED;
+}
static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
[0] = {
@@ -769,7 +1058,6 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
.channels_min = 1,
.channels_max = 3,
},
- .ops = &pm8916_wcd_analog_dai_ops,
},
[1] = {
.name = "pm8916_wcd_analog_pdm_tx",
@@ -781,13 +1069,13 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
.channels_min = 1,
.channels_max = 4,
},
- .ops = &pm8916_wcd_analog_dai_ops,
},
};
static const struct snd_soc_codec_driver pm8916_wcd_analog = {
.probe = pm8916_wcd_analog_probe,
.remove = pm8916_wcd_analog_remove,
+ .set_jack = pm8916_wcd_analog_set_jack,
.get_regmap = pm8916_get_regmap,
.component_driver = {
.controls = pm8916_wcd_analog_snd_controls,
@@ -802,6 +1090,7 @@ static const struct snd_soc_codec_driver pm8916_wcd_analog = {
static int pm8916_wcd_analog_parse_dt(struct device *dev,
struct pm8916_wcd_analog_priv *priv)
{
+ int rval;
if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
@@ -813,6 +1102,42 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev,
else
priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+ of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
+ &priv->micbias_mv);
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,hphl-jack-type-normally-open"))
+ priv->hphl_jack_type_normally_open = true;
+ else
+ priv->hphl_jack_type_normally_open = false;
+
+ if (of_property_read_bool(dev->of_node,
+ "qcom,gnd-jack-type-normally-open"))
+ priv->gnd_jack_type_normally_open = true;
+ else
+ priv->gnd_jack_type_normally_open = false;
+
+ priv->mbhc_btn_enabled = true;
+ rval = of_property_read_u32_array(dev->of_node,
+ "qcom,mbhc-vthreshold-low",
+ &priv->vref_btn_cs[0],
+ MBHC_MAX_BUTTONS);
+ if (rval < 0) {
+ priv->mbhc_btn_enabled = false;
+ } else {
+ rval = of_property_read_u32_array(dev->of_node,
+ "qcom,mbhc-vthreshold-high",
+ &priv->vref_btn_micb[0],
+ MBHC_MAX_BUTTONS);
+ if (rval < 0)
+ priv->mbhc_btn_enabled = false;
+ }
+
+ if (!priv->mbhc_btn_enabled)
+ dev_err(dev,
+ "DT property missing, MBHC btn detection disabled\n");
+
+
return 0;
}
@@ -820,7 +1145,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
{
struct pm8916_wcd_analog_priv *priv;
struct device *dev = &pdev->dev;
- int ret, i;
+ int ret, i, irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -852,6 +1177,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
return ret;
}
+ irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
+ if (irq < 0) {
+ dev_err(dev, "failed to get mbhc switch irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "mbhc switch irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc switch irq\n");
+
+ if (priv->mbhc_btn_enabled) {
+ irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
+ if (irq < 0) {
+ dev_err(dev, "failed to get button press irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "mbhc btn press irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc button press irq\n");
+
+ irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
+ if (irq < 0) {
+ dev_err(dev, "failed to get button release irq\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "mbhc btn release irq", priv);
+ if (ret)
+ dev_err(dev, "cannot request mbhc button release irq\n");
+
+ }
+
dev_set_drvdata(dev, priv);
return snd_soc_register_codec(dev, &pm8916_wcd_analog,
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index 43a915c725a0..66df8f810f0d 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -218,6 +218,8 @@ static const char *const rx_mix1_text[] = {
static const char *const dec_mux_text[] = {
"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
};
+
+static const char *const cic_mux_text[] = { "AMIC", "DMIC" };
static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@ -256,11 +258,21 @@ static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE(
LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
+/* CIC */
+static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE(
+ LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text);
+static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE(
+ LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text);
+
/* RDAC2 MUX */
static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM(
"DEC1 MUX Mux", dec1_mux_enum);
static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM(
"DEC2 MUX Mux", dec2_mux_enum);
+static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM(
+ "CIC1 MUX Mux", cic1_mux_enum);
+static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM(
+ "CIC2 MUX Mux", cic2_mux_enum);
static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM(
"RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM(
@@ -500,6 +512,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
&rx3_mix1_inp3_mux),
+ SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux),
+ SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux),
/* TX */
SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -536,6 +550,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
/* Connectivity Clock */
SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0,
NULL, 0),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
};
@@ -655,6 +671,11 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
{"AIF1 Capture", NULL, "I2S TX2"},
{"AIF1 Capture", NULL, "I2S TX3"},
+ {"CIC1 MUX", "DMIC", "DEC1 MUX"},
+ {"CIC1 MUX", "AMIC", "DEC1 MUX"},
+ {"CIC2 MUX", "DMIC", "DEC2 MUX"},
+ {"CIC2 MUX", "AMIC", "DEC2 MUX"},
+
/* Decimator Inputs */
{"DEC1 MUX", "DMIC1", "DMIC1"},
{"DEC1 MUX", "DMIC2", "DMIC2"},
@@ -673,8 +694,8 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
{"DMIC1", NULL, "DMIC_CLK"},
{"DMIC2", NULL, "DMIC_CLK"},
- {"I2S TX1", NULL, "DEC1 MUX"},
- {"I2S TX2", NULL, "DEC2 MUX"},
+ {"I2S TX1", NULL, "CIC1 MUX"},
+ {"I2S TX2", NULL, "CIC2 MUX"},
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 1bbe36338cd3..7a6b1bb0b437 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -466,7 +466,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0006, 0x1000 },
{ 0x000a, 0x0000 },
{ 0x0010, 0x000f },
- { 0x0015, 0x42c1 },
+ { 0x0015, 0x42f1 },
{ 0x0016, 0x0000 },
{ 0x0018, 0x000b },
{ 0x0019, 0xafaf },
@@ -509,7 +509,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x008a, 0x0000 },
{ 0x008b, 0x0000 },
{ 0x008c, 0x0003 },
- { 0x008e, 0x0004 },
+ { 0x008e, 0x0008 },
{ 0x008f, 0x1000 },
{ 0x0090, 0x0646 },
{ 0x0091, 0x0e3e },
@@ -520,7 +520,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0098, 0x0000 },
{ 0x009a, 0x0000 },
{ 0x009f, 0x0000 },
- { 0x00ae, 0x2000 },
+ { 0x00ae, 0x6000 },
{ 0x00af, 0x0000 },
{ 0x00b6, 0x0000 },
{ 0x00b7, 0x0000 },
@@ -538,7 +538,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x00d9, 0x08f9 },
{ 0x00db, 0x0008 },
{ 0x00dc, 0x00c0 },
- { 0x00dd, 0x6724 },
+ { 0x00dd, 0x6729 },
{ 0x00de, 0x3131 },
{ 0x00df, 0x0008 },
{ 0x00e0, 0x4000 },
@@ -578,7 +578,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0116, 0x0000 },
{ 0x0117, 0x0f00 },
{ 0x0118, 0x0006 },
- { 0x0125, 0x2224 },
+ { 0x0125, 0x2424 },
{ 0x0126, 0x5550 },
{ 0x0127, 0x0400 },
{ 0x0128, 0x7711 },
@@ -596,8 +596,8 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0145, 0x0002 },
{ 0x0146, 0x0000 },
{ 0x0160, 0x0e80 },
- { 0x0161, 0x0020 },
- { 0x0162, 0x0080 },
+ { 0x0161, 0x0080 },
+ { 0x0162, 0x0200 },
{ 0x0163, 0x0800 },
{ 0x0164, 0x0000 },
{ 0x0165, 0x0000 },
@@ -676,8 +676,8 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0251, 0x0000 },
{ 0x0252, 0x028a },
{ 0x02fa, 0x0000 },
- { 0x02fb, 0x0000 },
- { 0x02fc, 0x0000 },
+ { 0x02fb, 0x00a4 },
+ { 0x02fc, 0x0300 },
{ 0x0300, 0x0000 },
{ 0x03d0, 0x0000 },
{ 0x03d1, 0x0000 },
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 2c405456d89f..02493bbb07e1 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4368,12 +4368,12 @@ static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
switch (dai->id) {
case RT5665_AIF2_1:
case RT5665_AIF2_2:
- snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+ snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
RT5665_I2S_BCLK_MS2_MASK,
RT5665_I2S_BCLK_MS2_64);
break;
case RT5665_AIF3:
- snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+ snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
RT5665_I2S_BCLK_MS3_MASK,
RT5665_I2S_BCLK_MS3_64);
break;
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
index 1db5c6a62a8e..d95249c4c47b 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1692,8 +1692,8 @@
#define RT5665_GP6_PIN_MASK (0x3 << 5)
#define RT5665_GP6_PIN_SFT 5
#define RT5665_GP6_PIN_GPIO6 (0x0 << 5)
-#define RT5665_GP6_PIN_BCLK3 (0x0 << 5)
-#define RT5665_GP6_PIN_PDM_SCL (0x1 << 5)
+#define RT5665_GP6_PIN_BCLK3 (0x1 << 5)
+#define RT5665_GP6_PIN_PDM_SCL (0x2 << 5)
#define RT5665_GP7_PIN_MASK (0x3 << 3)
#define RT5665_GP7_PIN_SFT 3
#define RT5665_GP7_PIN_GPIO7 (0x0 << 3)
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 68e7020b2875..f2bb4feba3b6 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -409,7 +409,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
static int avc_get_threshold(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);
int db, i;
u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
@@ -442,7 +442,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
static int avc_put_threshold(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);
int db;
u16 reg;
OpenPOWER on IntegriCloud