ASoC: wcd9304: Pull in pending fixes for sitar.
Fix Lineout and DMIC configurations. The configurations are similar
to tabla codec driver and hence pull in changes to sitar driver.
Change-Id: Ia00359e6f8888c08365b85423197821fc16f963b
Signed-off-by: Asish Bhattacharya <asishb@codeaurora.org>
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index acef55e..6e23930 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -344,8 +344,7 @@
ch_h[i] = tx[idx].ch_h;
sph[i] = tx[idx].sph;
slave_port_id = idx ;
- if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) ||
- (slave_port_id == 0)) {
+ if (slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) {
pr_err("SLIMbus: invalid slave port id: %d",
slave_port_id);
ret = -EINVAL;
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
index df54e02..65e4728 100644
--- a/include/linux/mfd/wcd9xxx/wcd9304_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -413,66 +413,95 @@
#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00000000)
#define SITAR_A_CDC_TX1_VOL_CTL_GAIN (0x221)
#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX1_VOL_CTL_CFG (0x222)
-#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX2_VOL_CTL_GAIN (0x229)
+#define SITAR_A_CDC_TX2_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX3_VOL_CTL_GAIN (0x231)
+#define SITAR_A_CDC_TX3_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN (0x239)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX5_VOL_CTL_GAIN (0x241)
+#define SITAR_A_CDC_TX5_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG (0x222)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX2_VOL_CTL_CFG (0x22A)
+#define SITAR_A_CDC_TX2_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX3_VOL_CTL_CFG (0x232)
+#define SITAR_A_CDC_TX3_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG (0x23A)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG__POR (0x00000000)
+
#define SITAR_A_CDC_TX1_MUX_CTL (0x223)
#define SITAR_A_CDC_TX1_MUX_CTL__POR (0x00000008)
#define SITAR_A_CDC_TX1_CLK_FS_CTL (0x224)
#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR (0x00000003)
#define SITAR_A_CDC_TX1_DMIC_CTL (0x225)
#define SITAR_A_CDC_TX1_DMIC_CTL__POR (0x00000000)
+#define SITAR_A_CDC_TX2_MUX_CTL (0x22B)
+#define SITAR_A_CDC_TX2_MUX_CTL__POR (0x00000008)
+#define SITAR_A_CDC_TX3_MUX_CTL (0x233)
+#define SITAR_A_CDC_TX3_MUX_CTL__POR (0x00000008)
+#define SITAR_A_CDC_TX4_MUX_CTL (0x23B)
+#define SITAR_A_CDC_TX4_MUX_CTL__POR (0x00000008)
+#define SITAR_A_CDC_TX5_MUX_CTL (0x243)
+#define SITAR_A_CDC_TX5_MUX_CTL__POR (0x00000008)
+
#define SITAR_A_CDC_SRC1_PDA_CFG (0x2A0)
#define SITAR_A_CDC_SRC1_PDA_CFG__POR (0x00000000)
#define SITAR_A_CDC_SRC1_FS_CTL (0x2A1)
#define SITAR_A_CDC_SRC1_FS_CTL__POR (0x0000001b)
#define SITAR_A_CDC_RX1_B1_CTL (0x000002B0)
-#define SITAR_A_CDC_RX1_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_B1_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX2_B1_CTL (0x000002B8)
-#define SITAR_A_CDC_RX2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B1_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX3_B1_CTL (0x000002C0)
-#define SITAR_A_CDC_RX3_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B1_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_B2_CTL (0x000002B1)
-#define SITAR_A_CDC_RX1_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_B2_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX2_B2_CTL (0x000002B9)
-#define SITAR_A_CDC_RX2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B2_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX3_B2_CTL (0x000002C1)
-#define SITAR_A_CDC_RX3_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B2_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_B3_CTL (0x000002B2)
-#define SITAR_A_CDC_RX1_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_B3_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX2_B3_CTL (0x000002BA)
-#define SITAR_A_CDC_RX2_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B3_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX3_B3_CTL (0x000002C2)
-#define SITAR_A_CDC_RX3_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B3_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_B4_CTL (0x000002B3)
-#define SITAR_A_CDC_RX1_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_B4_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX2_B4_CTL (0x000002BB)
-#define SITAR_A_CDC_RX2_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B4_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX3_B4_CTL (0x000002C3)
-#define SITAR_A_CDC_RX3_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B4_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_B5_CTL (0x000002B4)
-#define SITAR_A_CDC_RX1_B5_CTL__POR (0x00000060)
+#define SITAR_A_CDC_RX1_B5_CTL__POR (0x00000060)
#define SITAR_A_CDC_RX2_B5_CTL (0x000002BC)
-#define SITAR_A_CDC_RX2_B5_CTL__POR (0x00000060)
+#define SITAR_A_CDC_RX2_B5_CTL__POR (0x00000060)
#define SITAR_A_CDC_RX3_B5_CTL (0x000002C4)
-#define SITAR_A_CDC_RX3_B5_CTL__POR (0x00000060)
+#define SITAR_A_CDC_RX3_B5_CTL__POR (0x00000060)
#define SITAR_A_CDC_RX1_B6_CTL (0x000002B5)
-#define SITAR_A_CDC_RX1_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_B6_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX2_B6_CTL (0x000002BD)
-#define SITAR_A_CDC_RX2_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B6_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX3_B6_CTL (0x000002C5)
-#define SITAR_A_CDC_RX3_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B6_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00000000)
#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL (0x2B7)
#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL (0x2BF)
+#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL (0x2C7)
+#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL__POR (0x00000000)
+
#define SITAR_A_CDC_CLK_ANC_RESET_CTL (0x300)
#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR (0x00000000)
#define SITAR_A_CDC_CLK_RX_RESET_CTL (0x301)
@@ -722,9 +751,9 @@
#define SITAR_A_CDC_MBHC_SPARE (0x3DF)
#define SITAR_A_CDC_MBHC_SPARE__POR (0x00000000)
/* SLIMBUS Slave Registers */
-#define SITAR_SLIM_PGD_PORT_INT_EN0 (0x30)
+#define SITAR_SLIM_PGD_PORT_INT_EN0 (0x30)
#define SITAR_SLIM_PGD_PORT_INT_STATUS0 (0x34)
-#define SITAR_SLIM_PGD_PORT_INT_CLR0 (0x38)
+#define SITAR_SLIM_PGD_PORT_INT_CLR0 (0x38)
#define SITAR_SLIM_PGD_PORT_INT_SOURCE0 (0x60)
/* Macros for Packing Register Writes into a U32 */
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index c9c8e25..5ce83b5 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -39,6 +39,17 @@
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
+#define SITAR_CFILT_FAST_MODE 0x00
+#define SITAR_CFILT_SLOW_MODE 0x40
+#define MBHC_FW_READ_ATTEMPTS 15
+#define MBHC_FW_READ_TIMEOUT 2000000
+
+#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+
+#define SITAR_I2S_MASTER_MODE_MASK 0x08
+
+#define SITAR_OCP_ATTEMPT 1
+
#define AIF1_PB 1
#define AIF1_CAP 2
#define NUM_CODEC_DAIS 2
@@ -49,15 +60,12 @@
u32 ch_act;
u32 ch_tot;
};
-#define SITAR_CFILT_FAST_MODE 0x00
-#define SITAR_CFILT_SLOW_MODE 0x40
+#define SITAR_MCLK_RATE_12288KHZ 12288000
+#define SITAR_MCLK_RATE_9600KHZ 9600000
-#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
-
-#define SITAR_I2S_MASTER_MODE_MASK 0x08
-
-#define SITAR_OCP_ATTEMPT 1
+#define SITAR_FAKE_INS_THRESHOLD_MS 2500
+#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
@@ -109,8 +117,31 @@
SITAR_HPHR_DAC_OFF_ACK
};
+/* Data used by MBHC */
+struct mbhc_internal_cal_data {
+ u16 dce_z;
+ u16 dce_mb;
+ u16 sta_z;
+ u16 sta_mb;
+ u32 t_sta_dce;
+ u32 t_dce;
+ u32 t_sta;
+ u32 micb_mv;
+ u16 v_ins_hu;
+ u16 v_ins_h;
+ u16 v_b1_hu;
+ u16 v_b1_h;
+ u16 v_b1_huc;
+ u16 v_brh;
+ u16 v_brl;
+ u16 v_no_mic;
+ u8 npoll;
+ u8 nbounce_wait;
+};
+
struct sitar_priv {
struct snd_soc_codec *codec;
+ u32 mclk_freq;
u32 adc_count;
u32 cfilt1_cnt;
u32 cfilt2_cnt;
@@ -121,10 +152,20 @@
bool clock_active;
bool config_mode_active;
bool mbhc_polling_active;
- bool fake_insert_context;
+ unsigned long mbhc_fake_ins_start;
int buttons_pressed;
- struct sitar_mbhc_calibration *calibration;
+ enum sitar_micbias_num micbias;
+ /* void* calibration contains:
+ * struct sitar_mbhc_general_cfg generic;
+ * struct sitar_mbhc_plug_detect_cfg plug_det;
+ * struct sitar_mbhc_plug_type_cfg plug_type;
+ * struct sitar_mbhc_btn_detect_cfg btn_det;
+ * struct sitar_mbhc_imped_detect_cfg imped_det;
+ * Note: various size depends on btn_det->num_btn
+ */
+ void *calibration;
+ struct mbhc_internal_cal_data mbhc_data;
struct snd_soc_jack *headset_jack;
struct snd_soc_jack *button_jack;
@@ -154,13 +195,16 @@
struct work_struct hphlocp_work; /* reporting left hph ocp off */
struct work_struct hphrocp_work; /* reporting right hph ocp off */
- /* pm_cnt holds number of sleep lock holders + 1
- * so if pm_cnt is 1 system is sleep-able. */
- atomic_t pm_cnt;
- wait_queue_head_t pm_wq;
-
u8 hphlocp_cnt; /* headphone left ocp retry */
u8 hphrocp_cnt; /* headphone right ocp retry */
+
+ /* Callback function to enable MCLK */
+ int (*mclk_cb) (struct snd_soc_codec*, int);
+
+ /* Work to perform MBHC Firmware Read */
+ struct delayed_work mbhc_firmware_dwork;
+ const struct firmware *mbhc_fw;
+
/* num of slim ports required */
struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
};
@@ -419,9 +463,20 @@
SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
-84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
digital_gain),
+ SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+
SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
40, digital_gain),
SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
@@ -432,6 +487,7 @@
40, digital_gain),
SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
@@ -501,7 +557,7 @@
};
static const char *rx_dac3_text[] = {
- "ZERO", "RX1", "RX1_INV", "RX2"
+ "ZERO", "RX1", "INV_RX1", "RX2"
};
static const char *rx_dac4_text[] = {
@@ -523,6 +579,11 @@
"DEC3"
};
+static const char *sb_tx4_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC4"
+};
+
static const char *sb_tx5_mux_text[] = {
"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
"DEC5"
@@ -582,6 +643,9 @@
static const struct soc_enum sb_tx5_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+static const struct soc_enum sb_tx4_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
+
static const struct soc_enum sb_tx3_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
@@ -595,13 +659,13 @@
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
static const struct soc_enum dec2_mux_enum =
- SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 2, 8, dec2_mux_text);
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
static const struct soc_enum dec3_mux_enum =
- SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 4, 8, dec3_mux_text);
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
static const struct soc_enum dec4_mux_enum =
- SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 6, 8, dec4_mux_text);
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
static const struct soc_enum iir1_inp1_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
@@ -625,20 +689,23 @@
SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
static const struct snd_kcontrol_new rx_dac1_mux =
- SOC_DAPM_ENUM("RX1 DAC Mux", rx_dac1_enum);
+ SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
static const struct snd_kcontrol_new rx_dac2_mux =
- SOC_DAPM_ENUM("RX2 DAC Mux", rx_dac2_enum);
+ SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
static const struct snd_kcontrol_new rx_dac3_mux =
- SOC_DAPM_ENUM("RX3 DAC Mux", rx_dac3_enum);
+ SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
static const struct snd_kcontrol_new rx_dac4_mux =
- SOC_DAPM_ENUM("RX4 DAC Mux", rx_dac4_enum);
+ SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
static const struct snd_kcontrol_new sb_tx5_mux =
SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+static const struct snd_kcontrol_new sb_tx4_mux =
+ SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
+
static const struct snd_kcontrol_new sb_tx3_mux =
SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
@@ -726,6 +793,25 @@
return 0;
}
+static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -749,7 +835,7 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
break;
case SND_SOC_DAPM_POST_PMU:
pr_err("%s: sleeping 16 ms after %s PA turn on\n",
@@ -757,7 +843,7 @@
usleep_range(16000, 16000);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
break;
}
return 0;
@@ -767,7 +853,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
+ u16 tx_dmic_ctl_reg;
u8 dmic_clk_sel, dmic_clk_en;
unsigned int dmic;
int ret;
@@ -797,15 +883,12 @@
return -EINVAL;
}
- tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
pr_err("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
-
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
dmic_clk_sel, dmic_clk_sel);
@@ -843,6 +926,9 @@
} else {
sitar_codec_disable_button_presses(codec);
}
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
}
static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
@@ -1089,7 +1175,7 @@
&& sitar->mbhc_micbias_switched)
sitar_codec_switch_micbias(codec, 0);
- snd_soc_update_bits(codec, w->reg, 0x1E, 0x0A);
+ snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
if (strnstr(w->name, internal1_text, 30))
@@ -1099,7 +1185,7 @@
break;
case SND_SOC_DAPM_POST_PMU:
if (sitar->mbhc_polling_active &&
- (sitar->calibration->bias == micb_line)) {
+ sitar->micbias == micb_line) {
sitar_codec_pause_hs_polling(codec);
sitar_codec_start_hs_polling(codec);
}
@@ -1338,10 +1424,9 @@
struct mbhc_micbias_regs *micbias_regs)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- struct sitar_mbhc_calibration *calibration = sitar->calibration;
unsigned int cfilt;
- switch (calibration->bias) {
+ switch (sitar->micbias) {
case SITAR_MICBIAS1:
cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
@@ -1366,10 +1451,12 @@
case SITAR_CFILT1_SEL:
micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
+ sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
break;
case SITAR_CFILT2_SEL:
micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
+ sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
break;
}
}
@@ -1448,6 +1535,13 @@
SND_SOC_DAPM_OUTPUT("LINEOUT1"),
SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
+ , sitar_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
+ , sitar_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1498,9 +1592,12 @@
SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
/* TX */
+
SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1508,7 +1605,6 @@
sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_INPUT("AMIC2"),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1525,13 +1621,23 @@
SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
+ sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
&dec1_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+ &dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+ &dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+ &dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
0, sitar_codec_enable_slimtx,
@@ -1544,12 +1650,9 @@
SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
0, sitar_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
- &dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
- &dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
- &dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -1558,11 +1661,9 @@
SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -1581,35 +1682,40 @@
{"DAC1", NULL, "CP"},
{"DAC1", NULL, "EAR DRIVER"},
- {"LINEOUT1", NULL, "CP"},
- {"LINEOUT2", NULL, "CP"},
+ {"CP", NULL, "RX_BIAS"},
+
+ {"LINEOUT1 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT2 DAC", NULL, "RX_BIAS"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
- {"LINEOUT2 PA", "NULL", "DAC3 MUX"},
+ {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
+ {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
- {"LINEOUT1 PA", "NULL", "DAC2 MUX"},
+ {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+ {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
+
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
{"HEADPHONE", NULL, "HPHR"},
{"HPHL", NULL, "HPHL DAC"},
- {"HPHL DAC", NULL, "DAC4 MUX"},
+ {"HPHL DAC", "Switch", "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHL DAC", NULL, "RX3 MIX1"},
+ {"HPHR DAC", NULL, "RX3 MIX1"},
{"DAC1 MUX", "RX1", "RX1 CHAIN"},
{"DAC2 MUX", "RX1", "RX1 CHAIN"},
+
{"DAC3 MUX", "RX1", "RX1 CHAIN"},
- {"DAC3 MUX", "RX1_INV", "RX1 CHAIN"},
+ {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
{"DAC3 MUX", "RX2", "RX2 MIX1"},
+
{"DAC4 MUX", "ON", "RX2 MIX1"},
{"RX1 CHAIN", NULL, "RX1 MIX1"},
- {"CP", NULL, "RX_BIAS"},
-
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
@@ -1654,46 +1760,48 @@
/* TX */
{"SLIM TX1", NULL, "SLIM TX1 MUX"},
- {"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
-
- {"SLIM TX2", NULL, "SLIM TX2 MUX"},
- {"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
-
- {"SLIM TX1", NULL, "SLIM TX1 MUX"},
{"SLIM TX2", NULL, "SLIM TX2 MUX"},
{"SLIM TX3", NULL, "SLIM TX3 MUX"},
+ {"SLIM TX4", NULL, "SLIM TX4 MUX"},
{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
/* Decimator Inputs */
{"DEC1 MUX", "DMIC1", "DMIC1"},
{"DEC1 MUX", "DMIC4", "DMIC4"},
{"DEC1 MUX", "ADC1", "ADC1"},
{"DEC1 MUX", "ADC2", "ADC2"},
-
+ {"DEC1 MUX", "ADC3", "ADC3"},
+ {"DEC1 MUX", NULL, "CDC_CONN"},
{"DEC2 MUX", "DMIC2", "DMIC2"},
{"DEC2 MUX", "DMIC3", "DMIC3"},
{"DEC2 MUX", "ADC1", "ADC1"},
{"DEC2 MUX", "ADC2", "ADC2"},
-
+ {"DEC2 MUX", "ADC3", "ADC3"},
+ {"DEC2 MUX", NULL, "CDC_CONN"},
{"DEC3 MUX", "DMIC3", "DMIC3"},
{"DEC3 MUX", "ADC1", "ADC1"},
{"DEC3 MUX", "ADC2", "ADC2"},
+ {"DEC3 MUX", "ADC3", "ADC3"},
{"DEC3 MUX", "DMIC2", "DMIC2"},
{"DEC3 MUX", "DMIC3", "DMIC4"},
-
+ {"DEC3 MUX", NULL, "CDC_CONN"},
{"DEC4 MUX", "DMIC4", "DMIC4"},
{"DEC4 MUX", "ADC1", "ADC1"},
{"DEC4 MUX", "ADC2", "ADC2"},
+ {"DEC4 MUX", "ADC3", "ADC3"},
{"DEC4 MUX", "DMIC3", "DMIC3"},
{"DEC4 MUX", "DMIC2", "DMIC2"},
{"DEC4 MUX", "DMIC1", "DMIC1"},
+ {"DEC4 MUX", NULL, "CDC_CONN"},
/* ADC Connections */
{"ADC1", NULL, "AMIC1"},
{"ADC2", NULL, "AMIC2"},
+ {"ADC3", NULL, "AMIC3"},
/* IIR */
{"IIR1", NULL, "IIR1 INP1 MUX"},
@@ -1768,8 +1876,9 @@
static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
{
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x61);
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x04);
snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
usleep_range(1000, 1000);
snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -1819,13 +1928,43 @@
usleep_range(100, 100);
sitar_codec_enable_audio_mode_bandgap(codec);
} else if (choice == SITAR_BANDGAP_OFF) {
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0xFF, 0x65);
+ usleep_range(1000, 1000);
} else {
pr_err("%s: Error, Invalid bandgap settings\n", __func__);
}
sitar->bandgap_type = choice;
}
+static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ if (enable) {
+ snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
+ snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
+ usleep_range(5, 5);
+ snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
+ 0x80);
+ usleep_range(10, 10);
+ snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
+ usleep_range(20, 20);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
+ } else {
+ snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
+ 0);
+ snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
+ }
+ sitar->config_mode_active = enable ? true : false;
+
+ return 0;
+}
static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
int config_mode)
@@ -1835,6 +1974,7 @@
pr_err("%s\n", __func__);
if (config_mode) {
+ sitar_codec_enable_config_mode(codec, 1);
snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
@@ -1842,12 +1982,16 @@
} else
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
+ if (!config_mode && sitar->mbhc_polling_active) {
+ snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
+ sitar_codec_enable_config_mode(codec, 0);
+
+ }
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
- snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
usleep_range(50, 50);
sitar->clock_active = true;
return 0;
@@ -1856,7 +2000,7 @@
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
pr_err("%s\n", __func__);
- snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x00);
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
ndelay(160);
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
@@ -1864,26 +2008,61 @@
sitar->clock_active = false;
}
+static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
+{
+ if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ)
+ return 0;
+ else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ)
+ return 1;
+ else {
+ BUG_ON(1);
+ return -EINVAL;
+ }
+}
+
static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
{
- /* TODO store register values in calibration */
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+ u8 *n_ready, *n_cic;
+ struct sitar_mbhc_btn_detect_cfg *btn_det;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
+ sitar->mbhc_data.v_ins_hu & 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
+ (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 3);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL, 9);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL, 30);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 120);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_B2_CTL, 11);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
+ sitar->mbhc_data.v_b1_hu & 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
+ (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
+ sitar->mbhc_data.v_b1_h & 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
+ (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
+ sitar->mbhc_data.v_brh & 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
+ (sitar->mbhc_data.v_brh >> 8) & 0xFF);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
+ sitar->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
+ (sitar->mbhc_data.v_brl >> 8) & 0xFF);
+
+ n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
+ n_ready[sitar_codec_mclk_index(sitar)]);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
+ sitar->mbhc_data.npoll);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
+ sitar->mbhc_data.nbounce_wait);
+ n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
+ n_cic[sitar_codec_mclk_index(sitar)]);
}
static int sitar_startup(struct snd_pcm_substream *substream,
@@ -2064,7 +2243,7 @@
} else if (dai->id == AIF1_CAP) {
*tx_num = sitar_dai[dai->id - 1].capture.channels_max;
while (cnt < *tx_num) {
- tx_slot[cnt] = tx_ch[6 + cnt];
+ tx_slot[cnt] = tx_ch[1 + cnt];
cnt++;
}
}
@@ -2374,42 +2553,49 @@
return bias_value;
}
-static short sitar_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
- int dce)
+static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce)
{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
short bias_value;
+ /* Turn on the override */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
if (dce) {
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ usleep_range(sitar->mbhc_data.t_sta_dce,
+ sitar->mbhc_data.t_sta_dce);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
- usleep_range(60000, 60000);
+ usleep_range(sitar->mbhc_data.t_dce,
+ sitar->mbhc_data.t_dce);
bias_value = sitar_codec_read_dce_result(codec);
} else {
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
- usleep_range(5000, 5000);
+ usleep_range(sitar->mbhc_data.t_sta_dce,
+ sitar->mbhc_data.t_sta_dce);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
- usleep_range(50, 50);
+ usleep_range(sitar->mbhc_data.t_sta,
+ sitar->mbhc_data.t_sta);
bias_value = sitar_codec_read_sta_result(codec);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
}
+ /* Turn off the override after measuring mic voltage */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
- pr_err("read microphone bias value %x\n", bias_value);
return bias_value;
}
static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- struct sitar_mbhc_calibration *calibration = sitar->calibration;
short bias_value;
u8 cfilt_mode;
- if (!calibration) {
+ if (!sitar->calibration) {
pr_err("Error, no sitar calibration\n");
return -ENODEV;
}
@@ -2432,23 +2618,25 @@
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
0x70, 0x00);
- snd_soc_update_bits(codec,
- sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
-
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+ snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
+ snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
+ snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
+
+ snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
sitar_codec_calibrate_hs_polling(codec);
- bias_value = sitar_codec_measure_micbias_voltage(codec, 0);
- snd_soc_update_bits(codec,
- sitar->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+ bias_value = sitar_codec_sta_dce(codec, 0);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
return bias_value;
@@ -2458,11 +2646,14 @@
int insertion)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- struct sitar_mbhc_calibration *calibration = sitar->calibration;
int central_bias_enabled = 0;
+ const struct sitar_mbhc_general_cfg *generic =
+ SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
+ const struct sitar_mbhc_plug_detect_cfg *plug_det =
+ SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->calibration);
u8 wg_time;
- if (!calibration) {
+ if (!sitar->calibration) {
pr_err("Error, no sitar calibration\n");
return -EINVAL;
}
@@ -2483,7 +2674,7 @@
/* Enable HPH Schmitt Trigger */
snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
- calibration->hph_current << 2);
+ plug_det->hph_current << 2);
/* Turn off HPH PAs and DAC's during insertion detection to
* avoid false insertion interrupts
@@ -2506,10 +2697,10 @@
/* enable the mic line schmitt trigger */
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
- calibration->mic_current << 5);
+ plug_det->mic_current << 5);
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
0x80, 0x80);
- usleep_range(calibration->mic_pid, calibration->mic_pid);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
0x10, 0x10);
@@ -2519,10 +2710,12 @@
if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
if (!(sitar->clock_active)) {
+ sitar_codec_enable_config_mode(codec, 1);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
0x06, 0);
- usleep_range(calibration->shutdown_plug_removal,
- calibration->shutdown_plug_removal);
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
+ sitar_codec_enable_config_mode(codec, 0);
} else
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
0x06, 0);
@@ -2533,8 +2726,8 @@
/* If central bandgap disabled */
if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x3, 0x3);
- usleep_range(calibration->bg_fast_settle,
- calibration->bg_fast_settle);
+ usleep_range(generic->t_bg_fast_settle,
+ generic->t_bg_fast_settle);
central_bias_enabled = 1;
}
@@ -2542,7 +2735,7 @@
if (snd_soc_read(codec, SITAR_A_PIN_CTL_OE0) & 0x80) {
snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
- usleep_range(calibration->tldoh, calibration->tldoh);
+ usleep_range(generic->t_ldoh, generic->t_ldoh);
snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
if (central_bias_enabled)
@@ -2554,23 +2747,82 @@
return 0;
}
+static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
+ s16 vin_mv)
+{
+ short diff, zero;
+ struct sitar_priv *sitar;
+ u32 mb_mv, in;
+
+ sitar = snd_soc_codec_get_drvdata(codec);
+ mb_mv = sitar->mbhc_data.micb_mv;
+
+ if (mb_mv == 0) {
+ pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dce) {
+ diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
+ zero = sitar->mbhc_data.dce_z;
+ } else {
+ diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
+ zero = sitar->mbhc_data.sta_z;
+ }
+ in = (u32) diff * vin_mv;
+
+ return (u16) (in / mb_mv) + zero;
+}
+
+static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
+ u16 bias_value)
+{
+ struct sitar_priv *sitar;
+ s32 mv;
+
+ sitar = snd_soc_codec_get_drvdata(codec);
+
+ if (dce) {
+ mv = ((s32)bias_value - (s32)sitar->mbhc_data.dce_z) *
+ (s32)sitar->mbhc_data.micb_mv /
+ (s32)(sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z);
+ } else {
+ mv = ((s32)bias_value - (s32)sitar->mbhc_data.sta_z) *
+ (s32)sitar->mbhc_data.micb_mv /
+ (s32)(sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z);
+ }
+
+ return mv;
+}
+
static void btn0_lpress_fn(struct work_struct *work)
{
struct delayed_work *delayed_work;
struct sitar_priv *sitar;
+ short bias_value;
+ int dce_mv, sta_mv;
+ struct sitar *core;
- pr_err("%s:\n", __func__);
+ pr_debug("%s:\n", __func__);
delayed_work = to_delayed_work(work);
sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+ core = dev_get_drvdata(sitar->codec->dev->parent);
if (sitar) {
if (sitar->button_jack) {
- pr_err("%s: Reporting long button press event\n",
- __func__);
+ bias_value = sitar_codec_read_sta_result(sitar->codec);
+ sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
+ bias_value);
+ bias_value = sitar_codec_read_dce_result(sitar->codec);
+ dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
+ bias_value);
+ pr_debug("%s: Reporting long button press event"
+ " STA: %d, DCE: %d\n", __func__,
+ sta_mv, dce_mv);
sitar_snd_soc_jack_report(sitar, sitar->button_jack,
- SND_JACK_BTN_0,
- SND_JACK_BTN_0);
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
}
} else {
pr_err("%s: Bad sitar private data\n", __func__);
@@ -2578,31 +2830,361 @@
}
-int sitar_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
- struct sitar_mbhc_calibration *calibration)
+void sitar_mbhc_cal(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar;
- int rc;
+ struct sitar_mbhc_btn_detect_cfg *btn_det;
+ u8 cfilt_mode, bg_mode;
+ u8 ncic, nmeas, navg;
+ u32 mclk_rate;
+ u32 dce_wait, sta_wait;
+ u8 *n_cic;
+
+ sitar = snd_soc_codec_get_drvdata(codec);
+
+ /* First compute the DCE / STA wait times
+ * depending on tunable parameters.
+ * The value is computed in microseconds
+ */
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+ n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
+ ncic = n_cic[sitar_codec_mclk_index(sitar)];
+ nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration)->n_meas;
+ navg = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration)->mbhc_navg;
+ mclk_rate = sitar->mclk_freq;
+ dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
+ sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
+
+ sitar->mbhc_data.t_dce = dce_wait;
+ sitar->mbhc_data.t_sta = sta_wait;
+
+ /* LDOH and CFILT are already configured during pdata handling.
+ * Only need to make sure CFILT and bandgap are in Fast mode.
+ * Need to restore defaults once calculation is done.
+ */
+ cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
+ bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
+ 0x02);
+
+ /* Micbias, CFILT, LDOH, MBHC MUX mode settings
+ * to perform ADC calibration
+ */
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
+ sitar->micbias << 5);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
+
+ /* DCE measurement for 0 volts */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
+ sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
+
+ /* DCE measurment for MB voltage */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
+ sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
+
+ /* Sta measuremnt for 0 volts */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
+ sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
+
+ /* STA Measurement for MB Voltage */
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
+ sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
+
+ /* Restore default settings. */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
+
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+ usleep_range(100, 100);
+}
+
+void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
+ const enum sitar_mbhc_btn_det_mem mem)
+{
+ void *ret = &btn_det->_v_btn_low;
+
+ switch (mem) {
+ case SITAR_BTN_DET_GAIN:
+ ret += sizeof(btn_det->_n_cic);
+ case SITAR_BTN_DET_N_CIC:
+ ret += sizeof(btn_det->_n_ready);
+ case SITAR_BTN_DET_N_READY:
+ ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
+ case SITAR_BTN_DET_V_BTN_HIGH:
+ ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
+ case SITAR_BTN_DET_V_BTN_LOW:
+ /* do nothing */
+ break;
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar;
+ s16 btn_mv = 0, btn_delta_mv;
+ struct sitar_mbhc_btn_detect_cfg *btn_det;
+ struct sitar_mbhc_plug_type_cfg *plug_type;
+ u16 *btn_high;
+ u8 *n_ready;
+ int i;
+
+ sitar = snd_soc_codec_get_drvdata(codec);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+ plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->calibration);
+
+ n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
+ if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ) {
+ sitar->mbhc_data.npoll = 9;
+ sitar->mbhc_data.nbounce_wait = 30;
+ } else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ) {
+ sitar->mbhc_data.npoll = 7;
+ sitar->mbhc_data.nbounce_wait = 23;
+ }
+
+ sitar->mbhc_data.t_sta_dce = ((1000 * 256) / (sitar->mclk_freq / 1000) *
+ n_ready[sitar_codec_mclk_index(sitar)]) +
+ 10;
+ sitar->mbhc_data.v_ins_hu =
+ sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
+ sitar->mbhc_data.v_ins_h =
+ sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
+
+ btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
+ for (i = 0; i < btn_det->num_btn; i++)
+ btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
+
+ sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
+
+ sitar->mbhc_data.v_b1_hu =
+ sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
+
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+
+ sitar->mbhc_data.v_b1_huc =
+ sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
+
+ sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
+ sitar->mbhc_data.v_brl = 0xFA55;
+
+ sitar->mbhc_data.v_no_mic =
+ sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
+}
+
+void sitar_mbhc_init(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar;
+ struct sitar_mbhc_general_cfg *generic;
+ struct sitar_mbhc_btn_detect_cfg *btn_det;
+ int n;
+ u8 *n_cic, *gain;
+
+ sitar = snd_soc_codec_get_drvdata(codec);
+ generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+
+ for (n = 0; n < 8; n++) {
+ if (n != 7) {
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_MBHC_FIR_B1_CFG,
+ 0x07, n);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
+ btn_det->c[n]);
+ }
+ }
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
+ btn_det->nc);
+
+ n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
+ n_cic[sitar_codec_mclk_index(sitar)]);
+
+ gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
+ gain[sitar_codec_mclk_index(sitar)] << 3);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
+ generic->mbhc_nsa << 4);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
+ btn_det->n_meas);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
+ btn_det->mbhc_nsc << 3);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+}
+
+static bool sitar_mbhc_fw_validate(const struct firmware *fw)
+{
+ u32 cfg_offset;
+ struct sitar_mbhc_imped_detect_cfg *imped_cfg;
+ struct sitar_mbhc_btn_detect_cfg *btn_cfg;
+
+ if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to num_btn
+ */
+ btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
+ if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to start of impedance detection configuration
+ */
+ imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
+
+ if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
+ return false;
+
+ if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
+ return false;
+
+ return true;
+}
+static void mbhc_fw_read(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct sitar_priv *sitar;
+ struct snd_soc_codec *codec;
+ const struct firmware *fw;
+ int ret = -1, retry = 0, rc;
+
+ dwork = to_delayed_work(work);
+ sitar = container_of(dwork, struct sitar_priv,
+ mbhc_firmware_dwork);
+ codec = sitar->codec;
+
+ while (retry < MBHC_FW_READ_ATTEMPTS) {
+ retry++;
+ pr_info("%s:Attempt %d to request MBHC firmware\n",
+ __func__, retry);
+ ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
+ codec->dev);
+
+ if (ret != 0) {
+ usleep_range(MBHC_FW_READ_TIMEOUT,
+ MBHC_FW_READ_TIMEOUT);
+ } else {
+ pr_info("%s: MBHC Firmware read succesful\n", __func__);
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ pr_err("%s: Cannot load MBHC firmware use default cal\n",
+ __func__);
+ } else if (sitar_mbhc_fw_validate(fw) == false) {
+ pr_err("%s: Invalid MBHC cal data size use default cal\n",
+ __func__);
+ release_firmware(fw);
+ } else {
+ sitar->calibration = (void *)fw->data;
+ sitar->mbhc_fw = fw;
+ }
+
+ sitar->mclk_cb(codec, 1);
+ sitar_mbhc_init(codec);
+ sitar_mbhc_cal(codec);
+ sitar_mbhc_calc_thres(codec);
+ sitar->mclk_cb(codec, 0);
+ sitar_codec_calibrate_hs_polling(codec);
+ rc = sitar_codec_enable_hs_detect(codec, 1);
+
+ if (IS_ERR_VALUE(rc))
+ pr_err("%s: Failed to setup MBHC detection\n", __func__);
+
+}
+
+int sitar_hs_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *headset_jack,
+ struct snd_soc_jack *button_jack,
+ void *calibration, enum sitar_micbias_num micbias,
+ int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+ int read_fw_bin, u32 mclk_rate)
+{
+ struct sitar_priv *sitar;
+ int rc = 0;
if (!codec || !calibration) {
pr_err("Error: no codec or calibration\n");
return -EINVAL;
}
+
+ if (mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
+ if (mclk_rate == SITAR_MCLK_RATE_9600KHZ)
+ pr_err("Error: clock rate %dHz is not yet supported\n",
+ mclk_rate);
+ else
+ pr_err("Error: unsupported clock rate %d\n", mclk_rate);
+ return -EINVAL;
+ }
+
sitar = snd_soc_codec_get_drvdata(codec);
sitar->headset_jack = headset_jack;
sitar->button_jack = button_jack;
+ sitar->micbias = micbias;
sitar->calibration = calibration;
+ sitar->mclk_cb = mclk_cb_fn;
+ sitar->mclk_freq = mclk_rate;
sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
/* Put CFILT in fast mode by default */
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
0x40, SITAR_CFILT_FAST_MODE);
-
+ INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
- rc = sitar_codec_enable_hs_detect(codec, 1);
+
+ if (!read_fw_bin) {
+ sitar->mclk_cb(codec, 1);
+ sitar_mbhc_init(codec);
+ sitar_mbhc_cal(codec);
+ sitar_mbhc_calc_thres(codec);
+ sitar->mclk_cb(codec, 0);
+ sitar_codec_calibrate_hs_polling(codec);
+ rc = sitar_codec_enable_hs_detect(codec, 1);
+ } else {
+ schedule_delayed_work(&sitar->mbhc_firmware_dwork,
+ usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
+ }
if (!IS_ERR_VALUE(rc)) {
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
@@ -2617,36 +3199,139 @@
}
EXPORT_SYMBOL_GPL(sitar_hs_detect);
+static int sitar_determine_button(const struct sitar_priv *priv,
+ const s32 bias_mv)
+{
+ s16 *v_btn_low, *v_btn_high;
+ struct sitar_mbhc_btn_detect_cfg *btn_det;
+ int i, btn = -1;
+
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+ v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
+ v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
+ SITAR_BTN_DET_V_BTN_HIGH);
+ for (i = 0; i < btn_det->num_btn; i++) {
+ if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
+ btn = i;
+ break;
+ }
+ }
+
+ if (btn == -1)
+ pr_debug("%s: couldn't find button number for mic mv %d\n",
+ __func__, bias_mv);
+
+ return btn;
+}
+
+static int sitar_get_button_mask(const int btn)
+{
+ int mask = 0;
+ switch (btn) {
+ case 0:
+ mask = SND_JACK_BTN_0;
+ break;
+ case 1:
+ mask = SND_JACK_BTN_1;
+ break;
+ case 2:
+ mask = SND_JACK_BTN_2;
+ break;
+ case 3:
+ mask = SND_JACK_BTN_3;
+ break;
+ case 4:
+ mask = SND_JACK_BTN_4;
+ break;
+ case 5:
+ mask = SND_JACK_BTN_5;
+ break;
+ case 6:
+ mask = SND_JACK_BTN_6;
+ break;
+ case 7:
+ mask = SND_JACK_BTN_7;
+ break;
+ }
+ return mask;
+}
+
static irqreturn_t sitar_dce_handler(int irq, void *data)
{
+ int i, mask;
+ short bias_value_dce;
+ s32 bias_mv_dce;
+ int btn = -1, meas = 0;
struct sitar_priv *priv = data;
+ const struct sitar_mbhc_btn_detect_cfg *d =
+ SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+ short btnmeas[d->n_btn_meas + 1];
struct snd_soc_codec *codec = priv->codec;
- short bias_value;
struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
- bias_value = sitar_codec_read_dce_result(codec);
- pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
- __func__, bias_value);
+ bias_value_dce = sitar_codec_read_dce_result(codec);
+ bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
- bias_value = sitar_codec_read_sta_result(codec);
- pr_err("%s: button press interrupt, bias value(STA Read)=%d\n",
- __func__, bias_value);
- /*
- * TODO: If button pressed is not button 0,
- * report the button press event immediately.
- */
- priv->buttons_pressed |= SND_JACK_BTN_0;
+ /* determine pressed button */
+ btnmeas[meas++] = sitar_determine_button(priv, bias_mv_dce);
+ pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
+ meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
+ if (d->n_btn_meas == 0)
+ btn = btnmeas[0];
+ for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
+ bias_value_dce = sitar_codec_sta_dce(codec, 1);
+ bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
+ btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
+ pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
+ __func__, meas, bias_value_dce, bias_mv_dce,
+ btnmeas[meas]);
+ /* if large enough measurements are collected,
+ * start to check if last all n_btn_con measurements were
+ * in same button low/high range */
+ if (meas + 1 >= d->n_btn_con) {
+ for (i = 0; i < d->n_btn_con; i++)
+ if ((btnmeas[meas] < 0) ||
+ (btnmeas[meas] != btnmeas[meas - i]))
+ break;
+ if (i == d->n_btn_con) {
+ /* button pressed */
+ btn = btnmeas[meas];
+ break;
+ }
+ }
+ /* if left measurements are less than n_btn_con,
+ * it's impossible to find button number */
+ if ((d->n_btn_meas - meas) < d->n_btn_con)
+ break;
+ }
- msleep(100);
+ if (btn >= 0) {
+ mask = sitar_get_button_mask(btn);
+ priv->buttons_pressed |= mask;
- wcd9xxx_lock_sleep(core);
- if (schedule_delayed_work(&priv->btn0_dwork,
- msecs_to_jiffies(400)) == 0) {
- WARN(1, "Button pressed twice without release event\n");
- wcd9xxx_unlock_sleep(core);
+ msleep(100);
+
+ /* XXX: assuming button 0 has the lowest micbias voltage */
+ if (btn == 0) {
+ wcd9xxx_lock_sleep(core);
+ if (schedule_delayed_work(&priv->btn0_dwork,
+ msecs_to_jiffies(400)) == 0) {
+ WARN(1, "Button pressed twice without release"
+ "event\n");
+ wcd9xxx_unlock_sleep(core);
+ }
+ } else {
+ pr_debug("%s: Reporting short button %d(0x%x) press\n",
+ __func__, btn, mask);
+ sitar_snd_soc_jack_report(priv, priv->button_jack, mask,
+ mask);
+ }
+ } else {
+ pr_debug("%s: bogus button press, too short press?\n",
+ __func__);
}
return IRQ_HANDLED;
@@ -2654,62 +3339,65 @@
static irqreturn_t sitar_release_handler(int irq, void *data)
{
+ int ret;
+ short mb_v;
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- int ret, mic_voltage;
struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
- pr_err("%s\n", __func__);
+ pr_debug("%s: enter\n", __func__);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
- mic_voltage = sitar_codec_read_dce_result(codec);
- pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
- __func__, mic_voltage);
-
if (priv->buttons_pressed & SND_JACK_BTN_0) {
ret = cancel_delayed_work(&priv->btn0_dwork);
if (ret == 0) {
-
- pr_err("%s: Reporting long button release event\n",
- __func__);
- if (priv->button_jack) {
+ pr_debug("%s: Reporting long button 0 release event\n",
+ __func__);
+ if (priv->button_jack)
sitar_snd_soc_jack_report(priv,
- priv->button_jack, 0,
- SND_JACK_BTN_0);
- }
-
+ priv->button_jack, 0,
+ SND_JACK_BTN_0);
} else {
/* if scheduled btn0_dwork is canceled from here,
- * we have to unlock from here instead btn0_work */
+ * we have to unlock from here instead btn0_work */
wcd9xxx_unlock_sleep(core);
- mic_voltage =
- sitar_codec_measure_micbias_voltage(codec, 0);
- pr_err("%s: Mic Voltage on release(new STA) = %d\n",
- __func__, mic_voltage);
+ mb_v = sitar_codec_sta_dce(codec, 0);
+ pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
+ __func__, mb_v,
+ sitar_codec_sta_dce_v(codec, 0, mb_v));
- if (mic_voltage < -2000 || mic_voltage > -670) {
- pr_err("%s: Fake buttton press interrupt\n",
- __func__);
- } else {
-
- if (priv->button_jack) {
- pr_err("%s:reporting short button press and release\n",
- __func__);
-
- sitar_snd_soc_jack_report(priv,
- priv->button_jack,
- SND_JACK_BTN_0, SND_JACK_BTN_0);
- sitar_snd_soc_jack_report(priv,
- priv->button_jack,
- 0, SND_JACK_BTN_0);
- }
+ if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
+ mb_v > (short)priv->mbhc_data.v_ins_hu)
+ pr_debug("%s: Fake buttton press interrupt\n",
+ __func__);
+ else if (priv->button_jack) {
+ pr_debug("%s: Reporting short button 0 "
+ "press and release\n", __func__);
+ sitar_snd_soc_jack_report(priv,
+ priv->button_jack,
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ sitar_snd_soc_jack_report(priv,
+ priv->button_jack, 0,
+ SND_JACK_BTN_0);
}
}
priv->buttons_pressed &= ~SND_JACK_BTN_0;
}
+ if (priv->buttons_pressed) {
+ pr_debug("%s:reporting button release mask 0x%x\n", __func__,
+ priv->buttons_pressed);
+ sitar_snd_soc_jack_report(priv, priv->button_jack, 0,
+ priv->buttons_pressed);
+ /* hardware doesn't detect another button press until
+ * already pressed button is released.
+ * therefore buttons_pressed has only one button's mask. */
+ priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
+ }
+
sitar_codec_start_hs_polling(codec);
return IRQ_HANDLED;
}
@@ -2717,17 +3405,23 @@
static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- struct sitar_mbhc_calibration *calibration = sitar->calibration;
+ const struct sitar_mbhc_general_cfg *generic =
+ SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
+
+ if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+ sitar_codec_enable_config_mode(codec, 1);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
- snd_soc_update_bits(codec,
- sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
- usleep_range(calibration->shutdown_plug_removal,
- calibration->shutdown_plug_removal);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+ if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+ sitar_codec_enable_config_mode(codec, 0);
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
}
@@ -2740,8 +3434,8 @@
if (!sitar->mclk_enabled) {
snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
- sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_AUDIO_MODE);
- sitar_codec_enable_clock_block(codec, 0);
+ sitar_codec_disable_clock_block(codec);
+ sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
}
sitar->mbhc_polling_active = false;
@@ -2759,19 +3453,19 @@
if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
pr_info("%s: retry\n", __func__);
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
- 0x00);
+ 0x00);
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
- 0x10);
+ 0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
sitar->hphlocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHL;
if (sitar->headset_jack)
sitar_snd_soc_jack_report(sitar,
- sitar->headset_jack,
- sitar->hph_status,
- SITAR_JACK_MASK);
+ sitar->headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
}
} else {
pr_err("%s: Bad sitar private data\n", __func__);
@@ -2846,45 +3540,48 @@
{
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
+ const struct sitar_mbhc_plug_detect_cfg *plug_det =
+ SITAR_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
int ldo_h_on, micb_cfilt_on;
- short mic_voltage;
- short threshold_no_mic = 0xF7F6;
- short threshold_fake_insert = 0xFD30;
+ short mb_v;
u8 is_removal;
+ int mic_mv;
- pr_err("%s\n", __func__);
+ pr_debug("%s: enter\n", __func__);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
/* Turn off both HPH and MIC line schmitt triggers */
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x90, 0x00);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
- if (priv->fake_insert_context) {
- pr_err("%s: fake context interrupt, reset insertion\n",
- __func__);
- priv->fake_insert_context = false;
+ if (priv->mbhc_fake_ins_start &&
+ time_after(jiffies, priv->mbhc_fake_ins_start +
+ msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
+ pr_debug("%s: fake context interrupt, reset insertion\n",
+ __func__);
+ priv->mbhc_fake_ins_start = 0;
sitar_codec_shutdown_hs_polling(codec);
sitar_codec_enable_hs_detect(codec, 1);
return IRQ_HANDLED;
}
-
ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
- micb_cfilt_on = snd_soc_read(codec,
- priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+ micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
+ & 0x80;
if (!ldo_h_on)
snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
if (!micb_cfilt_on)
snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
- 0x80, 0x80);
-
- usleep_range(priv->calibration->setup_plug_removal_delay,
- priv->calibration->setup_plug_removal_delay);
+ 0x80, 0x80);
+ if (plug_det->t_ins_complete > 20)
+ msleep(plug_det->t_ins_complete);
+ else
+ usleep_range(plug_det->t_ins_complete * 1000,
+ plug_det->t_ins_complete * 1000);
if (!ldo_h_on)
snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
@@ -2926,56 +3623,78 @@
return IRQ_HANDLED;
}
- mic_voltage = sitar_codec_setup_hs_polling(codec);
+ mb_v = sitar_codec_setup_hs_polling(codec);
+ mic_mv = sitar_codec_sta_dce_v(codec, 0, mb_v);
- if (mic_voltage > threshold_fake_insert) {
- pr_err("%s: Fake insertion interrupt, mic_voltage = %x\n",
- __func__, mic_voltage);
-
- /* Disable HPH trigger and enable MIC line trigger */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
-
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
- priv->calibration->mic_current << 5);
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x80, 0x80);
- usleep_range(priv->calibration->mic_pid,
- priv->calibration->mic_pid);
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
- 0x10, 0x10);
-
+ if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
+ pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
+ "STA : %d,%d\n", __func__,
+ (priv->mbhc_fake_ins_start ?
+ jiffies_to_msecs(jiffies -
+ priv->mbhc_fake_ins_start) :
+ 0),
+ mb_v, mic_mv);
+ if (time_after(jiffies,
+ priv->mbhc_fake_ins_start +
+ msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
+ /* Disable HPH trigger and enable MIC line trigger */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12,
+ 0x00);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg, 0x60,
+ plug_det->mic_current << 5);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+ } else {
+ if (priv->mbhc_fake_ins_start == 0)
+ priv->mbhc_fake_ins_start = jiffies;
+ /* Setup normal insert detection
+ * Enable HPH Schmitt Trigger
+ */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
+ 0x13 | 0x0C,
+ 0x13 | plug_det->hph_current << 2);
+ }
/* Setup for insertion detection */
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
- priv->fake_insert_context = true;
wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_MBHC_INSERTION);
+ SITAR_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
- } else if (mic_voltage < threshold_no_mic) {
- pr_err("%s: Headphone Detected, mic_voltage = %x\n",
- __func__, mic_voltage);
+ } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
+ pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
+ __func__, mb_v, mic_mv);
+ priv->mbhc_fake_ins_start = 0;
priv->hph_status |= SND_JACK_HEADPHONE;
if (priv->headset_jack) {
- pr_err("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADPHONE);
+ pr_debug("%s: Reporting insertion %d\n", __func__,
+ SND_JACK_HEADPHONE);
sitar_snd_soc_jack_report(priv, priv->headset_jack,
- priv->hph_status,
- SITAR_JACK_MASK);
+ priv->hph_status,
+ SITAR_JACK_MASK);
}
sitar_codec_shutdown_hs_polling(codec);
sitar_codec_enable_hs_detect(codec, 0);
sitar_sync_hph_state(priv);
} else {
- pr_err("%s: Headset detected, mic_voltage = %x\n",
- __func__, mic_voltage);
+ pr_debug("%s: Headset detected, mb_v: %d,%d\n",
+ __func__, mb_v, mic_mv);
+ priv->mbhc_fake_ins_start = 0;
priv->hph_status |= SND_JACK_HEADSET;
if (priv->headset_jack) {
- pr_err("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADSET);
+ pr_debug("%s: Reporting insertion %d\n", __func__,
+ SND_JACK_HEADSET);
sitar_snd_soc_jack_report(priv, priv->headset_jack,
- priv->hph_status,
- SITAR_JACK_MASK);
+ priv->hph_status,
+ SITAR_JACK_MASK);
}
+ /* avoid false button press detect */
+ msleep(50);
sitar_codec_start_hs_polling(codec);
sitar_sync_hph_state(priv);
}
@@ -2985,29 +3704,42 @@
static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
{
+ short bias_value;
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- short bias_value;
+ const struct sitar_mbhc_general_cfg *generic =
+ SITAR_MBHC_CAL_GENERAL_PTR(priv->calibration);
+ int fake_removal = 0;
+ int min_us = SITAR_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
+ pr_debug("%s: enter, removal interrupt\n", __func__);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
- usleep_range(priv->calibration->shutdown_plug_removal,
- priv->calibration->shutdown_plug_removal);
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
- bias_value = sitar_codec_measure_micbias_voltage(codec, 1);
- pr_err("removal interrupt, bias value is %d\n", bias_value);
+ do {
+ bias_value = sitar_codec_sta_dce(codec, 1);
+ pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
+ sitar_codec_sta_dce_v(codec, 1, bias_value), min_us);
+ if (bias_value < (short)priv->mbhc_data.v_ins_h) {
+ fake_removal = 1;
+ break;
+ }
+ min_us -= priv->mbhc_data.t_dce;
+ } while (min_us > 0);
- if (bias_value < -90) {
- pr_err("False alarm, headset not actually removed\n");
+ if (fake_removal) {
+ pr_debug("False alarm, headset not actually removed\n");
sitar_codec_start_hs_polling(codec);
} else {
/*
- * If this removal is not false, first check the micbias
- * switch status and switch it to LDOH if it is already
- * switched to VDDIO.
- */
+ * If this removal is not false, first check the micbias
+ * switch status and switch it to LDOH if it is already
+ * switched to VDDIO.
+ */
if (priv->mbhc_micbias_switched)
sitar_codec_switch_micbias(codec, 0);
priv->hph_status &= ~SND_JACK_HEADSET;
@@ -3129,6 +3861,14 @@
0x03, val_txfe);
}
}
+ if (flag & 0x40) {
+ value = (leg_mode & 0x40) ? 0x10 : 0x00;
+ value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
+ value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
+ snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
+ 0x13, value);
+ }
+
if (pdata->ocp.use_pdata) {
/* not defined in CODEC specification */
@@ -3203,11 +3943,12 @@
{SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
/* Use 16 bit sample size for TX1 to TX6 */
- {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x28},
+ {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
{SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
{SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
{SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
{SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+ {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
/* Use 16 bit sample size for RX */
{SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
@@ -3215,12 +3956,12 @@
/*enable HPF filter for TX paths */
{SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+ {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
};
static void sitar_codec_init_reg(struct snd_soc_codec *codec)
{
u32 i;
-
for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
sitar_codec_reg_init_val[i].mask,
@@ -3252,6 +3993,12 @@
sitar->cfilt_k_value = 0;
sitar->mbhc_micbias_switched = false;
+ /* Make sure mbhc intenal calibration data is zeroed out */
+ memset(&sitar->mbhc_data, 0,
+ sizeof(struct mbhc_internal_cal_data));
+ sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
+ sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+ sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
snd_soc_codec_set_drvdata(codec, sitar);
sitar->mclk_enabled = false;
@@ -3259,13 +4006,9 @@
sitar->clock_active = false;
sitar->config_mode_active = false;
sitar->mbhc_polling_active = false;
- sitar->fake_insert_context = false;
sitar->no_mic_headset_override = false;
sitar->codec = codec;
sitar->pdata = dev_get_platdata(codec->dev->parent);
- atomic_set(&sitar->pm_cnt, 1);
- init_waitqueue_head(&sitar->pm_wq);
-
sitar_update_reg_defaults(codec);
sitar_codec_init_reg(codec);
@@ -3414,6 +4157,8 @@
wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
sitar_codec_disable_clock_block(codec);
sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+ if (sitar->mbhc_fw)
+ release_firmware(sitar->mbhc_fw);
for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
kfree(sitar->dai[i].ch_num);
kfree(sitar);
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
index 07a1ca0..cfe839b 100644
--- a/sound/soc/codecs/wcd9304.h
+++ b/sound/soc/codecs/wcd9304.h
@@ -13,24 +13,36 @@
#include <sound/soc.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
-#define SITAR_VERSION_1_0 0x00
-
-#define SITAR_NUM_REGISTERS 0x3E0
+#define SITAR_NUM_REGISTERS 0x400
#define SITAR_MAX_REGISTER (SITAR_NUM_REGISTERS-1)
#define SITAR_CACHE_SIZE SITAR_NUM_REGISTERS
+#define SITAR_1_X_ONLY_REGISTERS 3
+#define SITAR_2_HIGHER_ONLY_REGISTERS 3
#define SITAR_REG_VAL(reg, val) {reg, 0, val}
-/* Local to the core only */
-#define SITAR_SLIM_MAX_RX_PORTS 5
-#define SITAR_SLIM_MAX_TX_PORTS 5
+#define DEFAULT_DCE_STA_WAIT 55
+#define DEFAULT_DCE_WAIT 60000
+#define DEFAULT_STA_WAIT 5000
+
+#define STA 0
+#define DCE 1
+
+#define SITAR_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
+ SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
+ SND_JACK_BTN_6 | SND_JACK_BTN_7)
extern const u8 sitar_reg_readable[SITAR_CACHE_SIZE];
+extern const u32 sitar_1_reg_readable[SITAR_1_X_ONLY_REGISTERS];
+extern const u32 sitar_2_reg_readable[SITAR_2_HIGHER_ONLY_REGISTERS];
extern const u8 sitar_reg_defaults[SITAR_CACHE_SIZE];
enum sitar_micbias_num {
SITAR_MICBIAS1,
SITAR_MICBIAS2,
+ SITAR_MICBIAS3,
+ SITAR_MICBIAS4,
};
enum sitar_pid_current {
@@ -40,26 +52,116 @@
SITAR_PID_MIC_20_UA,
};
-struct sitar_mbhc_calibration {
- enum sitar_micbias_num bias;
- int tldoh;
- int bg_fast_settle;
- enum sitar_pid_current mic_current;
- int mic_pid;
- enum sitar_pid_current hph_current;
- int setup_plug_removal_delay;
- int shutdown_plug_removal;
-};
-
struct sitar_reg_mask_val {
u16 reg;
u8 mask;
u8 val;
};
+enum sitar_mbhc_clk_freq {
+ SITAR_MCLK_12P2MHZ = 0,
+ SITAR_MCLK_9P6MHZ,
+ SITAR_NUM_CLK_FREQS,
+};
+
+enum sitar_mbhc_analog_pwr_cfg {
+ SITAR_ANALOG_PWR_COLLAPSED = 0,
+ SITAR_ANALOG_PWR_ON,
+ SITAR_NUM_ANALOG_PWR_CONFIGS,
+};
+
+enum sitar_mbhc_btn_det_mem {
+ SITAR_BTN_DET_V_BTN_LOW,
+ SITAR_BTN_DET_V_BTN_HIGH,
+ SITAR_BTN_DET_N_READY,
+ SITAR_BTN_DET_N_CIC,
+ SITAR_BTN_DET_GAIN
+};
+
+struct sitar_mbhc_general_cfg {
+ u8 t_ldoh;
+ u8 t_bg_fast_settle;
+ u8 t_shutdown_plug_rem;
+ u8 mbhc_nsa;
+ u8 mbhc_navg;
+ u8 v_micbias_l;
+ u8 v_micbias;
+ u8 mbhc_reserved;
+ u16 settle_wait;
+ u16 t_micbias_rampup;
+ u16 t_micbias_rampdown;
+ u16 t_supply_bringup;
+} __packed;
+
+struct sitar_mbhc_plug_detect_cfg {
+ u32 mic_current;
+ u32 hph_current;
+ u16 t_mic_pid;
+ u16 t_ins_complete;
+ u16 t_ins_retry;
+ u16 v_removal_delta;
+ u8 micbias_slow_ramp;
+ u8 reserved0;
+ u8 reserved1;
+ u8 reserved2;
+} __packed;
+
+struct sitar_mbhc_plug_type_cfg {
+ u8 av_detect;
+ u8 mono_detect;
+ u8 num_ins_tries;
+ u8 reserved0;
+ s16 v_no_mic;
+ s16 v_av_min;
+ s16 v_av_max;
+ s16 v_hs_min;
+ s16 v_hs_max;
+ u16 reserved1;
+} __packed;
+
+
+struct sitar_mbhc_btn_detect_cfg {
+ s8 c[8];
+ u8 nc;
+ u8 n_meas;
+ u8 mbhc_nsc;
+ u8 n_btn_meas;
+ u8 n_btn_con;
+ u8 num_btn;
+ u8 reserved0;
+ u8 reserved1;
+ u16 t_poll;
+ u16 t_bounce_wait;
+ u16 t_rel_timeout;
+ s16 v_btn_press_delta_sta;
+ s16 v_btn_press_delta_cic;
+ u16 t_btn0_timeout;
+ s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
+ s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
+ u8 _n_ready[SITAR_NUM_CLK_FREQS];
+ u8 _n_cic[SITAR_NUM_CLK_FREQS];
+ u8 _gain[SITAR_NUM_CLK_FREQS];
+} __packed;
+
+struct sitar_mbhc_imped_detect_cfg {
+ u8 _hs_imped_detect;
+ u8 _n_rload;
+ u8 _hph_keep_on;
+ u8 _repeat_rload_calc;
+ u16 _t_dac_ramp_time;
+ u16 _rhph_high;
+ u16 _rhph_low;
+ u16 _rload[0]; /* rload[n_rload] */
+ u16 _alpha[0]; /* alpha[n_rload] */
+ u16 _beta[3];
+} __packed;
+
extern int sitar_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
- struct sitar_mbhc_calibration *calibration);
+ struct snd_soc_jack *headset_jack,
+ struct snd_soc_jack *button_jack,
+ void *calibration, enum sitar_micbias_num micbis,
+ int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+ int read_fw_bin, u32 mclk_rate);
#ifndef anc_header_dec
struct anc_header {
@@ -70,3 +172,62 @@
#endif
extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+
+extern void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg
+ *btn_det,
+ const enum sitar_mbhc_btn_det_mem mem);
+
+#define SITAR_MBHC_CAL_SIZE(buttons, rload) ( \
+ sizeof(enum sitar_micbias_num) + \
+ sizeof(struct sitar_mbhc_general_cfg) + \
+ sizeof(struct sitar_mbhc_plug_detect_cfg) + \
+ ((sizeof(s16) + sizeof(s16)) * buttons) + \
+ sizeof(struct sitar_mbhc_plug_type_cfg) + \
+ sizeof(struct sitar_mbhc_btn_detect_cfg) + \
+ sizeof(struct sitar_mbhc_imped_detect_cfg) + \
+ ((sizeof(u16) + sizeof(u16)) * rload) \
+ )
+
+#define SITAR_MBHC_CAL_GENERAL_PTR(cali) ( \
+ (struct sitar_mbhc_general_cfg *) cali)
+#define SITAR_MBHC_CAL_PLUG_DET_PTR(cali) ( \
+ (struct sitar_mbhc_plug_detect_cfg *) \
+ &(SITAR_MBHC_CAL_GENERAL_PTR(cali)[1]))
+#define SITAR_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
+ (struct sitar_mbhc_plug_type_cfg *) \
+ &(SITAR_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
+#define SITAR_MBHC_CAL_BTN_DET_PTR(cali) ( \
+ (struct sitar_mbhc_btn_detect_cfg *) \
+ &(SITAR_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
+#define SITAR_MBHC_CAL_IMPED_DET_PTR(cali) ( \
+ (struct sitar_mbhc_imped_detect_cfg *) \
+ (((void *)&SITAR_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
+ (SITAR_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
+ (sizeof(SITAR_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
+ sizeof(SITAR_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
+ )
+
+/* minimum size of calibration data assuming there is only one button and
+ * one rload.
+ */
+#define SITAR_MBHC_CAL_MIN_SIZE ( \
+ sizeof(struct sitar_mbhc_general_cfg) + \
+ sizeof(struct sitar_mbhc_plug_detect_cfg) + \
+ sizeof(struct sitar_mbhc_plug_type_cfg) + \
+ sizeof(struct sitar_mbhc_btn_detect_cfg) + \
+ sizeof(struct sitar_mbhc_imped_detect_cfg) + \
+ (sizeof(u16) * 2))
+
+#define SITAR_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
+ sizeof(struct sitar_mbhc_btn_detect_cfg) + \
+ (cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
+ sizeof(cfg_ptr->_v_btn_high[0]))))
+
+#define SITAR_MBHC_CAL_IMPED_MIN_SZ ( \
+ sizeof(struct sitar_mbhc_imped_detect_cfg) + \
+ sizeof(u16) * 2)
+
+#define SITAR_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
+ sizeof(struct sitar_mbhc_imped_detect_cfg) + \
+ (cfg_ptr->_n_rload * (sizeof(cfg_ptr->_rload[0]) + \
+ sizeof(cfg_ptr->_alpha[0]))))
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a081253..e254cce 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -13,10 +13,9 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/misc.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
@@ -31,28 +30,12 @@
/* 8930 machine driver */
-#define PM8921_GPIO_BASE NR_GPIO_IRQS
-#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
-
#define MSM8930_SPK_ON 1
#define MSM8930_SPK_OFF 0
-#define msm8930_SLIM_0_RX_MAX_CHANNELS 2
-#define msm8930_SLIM_0_TX_MAX_CHANNELS 4
-
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
-#define BOTTOM_SPK_AMP_POS 0x1
-#define BOTTOM_SPK_AMP_NEG 0x2
-#define TOP_SPK_AMP_POS 0x4
-#define TOP_SPK_AMP_NEG 0x8
-
-#define GPIO_AUX_PCM_DOUT 63
-#define GPIO_AUX_PCM_DIN 64
-#define GPIO_AUX_PCM_SYNC 65
-#define GPIO_AUX_PCM_CLK 66
-
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -72,17 +55,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
-
-struct sitar_mbhc_calibration sitar_calib = {
- .bias = SITAR_MICBIAS2,
- .tldoh = 100,
- .bg_fast_settle = 100,
- .mic_current = SITAR_PID_MIC_5_UA,
- .mic_pid = 100,
- .hph_current = SITAR_PID_MIC_5_UA,
- .setup_plug_removal_delay = 1000000,
- .shutdown_plug_removal = 100000,
-};
+static void *sitar_mbhc_cal;
static void msm8930_ext_control(struct snd_soc_codec *codec)
{
@@ -91,10 +64,10 @@
pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
if (msm8930_spk_control == MSM8930_SPK_ON) {
snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk left Neg");
} else {
snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Right Pos");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Neg");
}
snd_soc_dapm_sync(dapm);
@@ -128,6 +101,7 @@
/* TODO: add external speaker power amps support */
return 0;
}
+
int msm8930_enable_codec_ext_clk(
struct snd_soc_codec *codec, int enable)
{
@@ -140,10 +114,10 @@
if (codec_clk) {
clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
- clk_enable(codec_clk);
+ clk_prepare_enable(codec_clk);
sitar_mclk_enable(codec, 1);
} else {
- pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ pr_err("%s: Error setting Sitar MCLK\n", __func__);
clk_users--;
return -EINVAL;
}
@@ -155,7 +129,7 @@
if (!clk_users) {
pr_debug("%s: disabling MCLK. clk_users = %d\n",
__func__, clk_users);
- clk_disable(codec_clk);
+ clk_disable_unprepare(codec_clk);
sitar_mclk_enable(codec, 0);
}
}
@@ -182,9 +156,8 @@
msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Right Pos", msm8930_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
- SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Digital Mic1", NULL),
SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
@@ -207,15 +180,18 @@
/* Speaker path */
{"Ext Spk Left Pos", NULL, "LINEOUT1"},
- {"Ext Spk Right Pos", NULL, "LINEOUT2"},
+ {"Ext Spk Left Neg", NULL, "LINEOUT2"},
-
+ /* Headset Mic */
{"AMIC2", NULL, "MIC BIAS2 Internal1"},
{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
/* Microphone path */
- {"AMIC1", NULL, "MIC BIAS1 Internal1"},
- {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+ {"AMIC1", NULL, "MIC BIAS2 Internal1"},
+ {"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
+
+ {"AMIC3", NULL, "MIC BIAS2 Internal1"},
+ {"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
{"HEADPHONE", NULL, "LDO_H"},
@@ -227,7 +203,7 @@
/**
* Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
* Digital Mic GM5 on CDP mainboard.
- * Conncted to DMIC2 Input on Tabla codec.
+ * Conncted to DMIC2 Input on Sitar codec.
*/
{"DMIC1", NULL, "MIC BIAS1 External"},
{"MIC BIAS1 External", NULL, "Digital Mic1"},
@@ -235,25 +211,25 @@
/**
* Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
* Digital Mic GM6 on CDP mainboard.
- * Conncted to DMIC1 Input on Tabla codec.
+ * Conncted to DMIC1 Input on Sitar codec.
*/
{"DMIC2", NULL, "MIC BIAS1 External"},
{"MIC BIAS1 External", NULL, "Digital Mic2"},
/**
* Digital Mic3. Back Bottom Digital Mic on Fluid.
* Digital Mic GM1 on CDP mainboard.
- * Conncted to DMIC4 Input on Tabla codec.
+ * Conncted to DMIC4 Input on Sitar codec.
*/
- {"DMIC3", NULL, "MIC BIAS2 External"},
- {"MIC BIAS2 External", NULL, "Digital Mic3"},
+ {"DMIC3", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic3"},
/**
* Digital Mic4. Back top Digital Mic on Fluid.
* Digital Mic GM2 on CDP mainboard.
- * Conncted to DMIC3 Input on Tabla codec.
+ * Conncted to DMIC3 Input on Sitar codec.
*/
- {"DMIC4", NULL, "MIC BIAS2 External"},
- {"MIC BIAS2 External", NULL, "Digital Mic4"},
+ {"DMIC4", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic4"},
};
@@ -277,7 +253,7 @@
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
- msm8930_slim_0_rx_ch);
+ msm8930_slim_0_rx_ch);
ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
return 0;
}
@@ -288,7 +264,7 @@
msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
- msm8930_slim_0_rx_ch);
+ msm8930_slim_0_rx_ch);
return 1;
}
@@ -364,6 +340,83 @@
return 0;
}
+static void *def_sitar_mbhc_cal(void)
+{
+ void *sitar_cal;
+ struct sitar_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ sitar_cal = kzalloc(SITAR_MBHC_CAL_SIZE(SITAR_MBHC_DEF_BUTTONS,
+ SITAR_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!sitar_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((SITAR_MBHC_CAL_GENERAL_PTR(sitar_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_DET_PTR(sitar_cal)->X) = (Y))
+ S(mic_current, SITAR_PID_MIC_5_UA);
+ S(hph_current, SITAR_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 250);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 1550);
+#undef S
+#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
+ S(c[0], 62);
+ S(c[1], 124);
+ S(nc, 1);
+ S(n_meas, 3);
+ S(mbhc_nsc, 11);
+ S(n_btn_meas, 1);
+ S(n_btn_con, 2);
+ S(num_btn, SITAR_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal);
+ btn_low = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_LOW);
+ btn_high = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = -50;
+ btn_high[0] = 10;
+ btn_low[1] = 11;
+ btn_high[1] = 38;
+ btn_low[2] = 39;
+ btn_high[2] = 64;
+ btn_low[3] = 65;
+ btn_high[3] = 91;
+ btn_low[4] = 92;
+ btn_high[4] = 115;
+ btn_low[5] = 116;
+ btn_high[5] = 141;
+ btn_low[6] = 142;
+ btn_high[6] = 163;
+ btn_low[7] = 164;
+ btn_high[7] = 250;
+ n_ready = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_READY);
+ n_ready[0] = 48;
+ n_ready[1] = 38;
+ n_cic = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_CIC);
+ n_cic[0] = 60;
+ n_cic[1] = 47;
+ gain = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return sitar_cal;
+}
+
static int msm8930_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -447,7 +500,7 @@
ARRAY_SIZE(common_audio_map));
snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Neg");
snd_soc_dapm_sync(dapm);
@@ -466,7 +519,10 @@
return err;
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
- sitar_hs_detect(codec, &hs_jack, &button_jack, &sitar_calib);
+
+ sitar_hs_detect(codec, &hs_jack, &button_jack, sitar_mbhc_cal,
+ SITAR_MICBIAS2, msm8930_enable_codec_ext_clk, 0,
+ SITAR_EXT_CLK_RATE);
return 0;
}
@@ -596,76 +652,7 @@
return 0;
}
-static int msm8930_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
- channels->min = channels->max = 1;
-
- return 0;
-}
-static int msm8930_aux_pcm_get_gpios(void)
-{
- int ret = 0;
-
- pr_debug("%s\n", __func__);
-
- ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
- __func__, GPIO_AUX_PCM_DOUT);
- goto fail_dout;
- }
-
- ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
- __func__, GPIO_AUX_PCM_DIN);
- goto fail_din;
- }
-
- ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
- __func__, GPIO_AUX_PCM_SYNC);
- goto fail_sync;
- }
- ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
- __func__, GPIO_AUX_PCM_CLK);
- goto fail_clk;
- }
-
- return 0;
-
-fail_clk:
- gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
- gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
- gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
- return ret;
-}
-
-static int msm8930_aux_pcm_free_gpios(void)
-{
- gpio_free(GPIO_AUX_PCM_DIN);
- gpio_free(GPIO_AUX_PCM_DOUT);
- gpio_free(GPIO_AUX_PCM_SYNC);
- gpio_free(GPIO_AUX_PCM_CLK);
-
- return 0;
-}
static int msm8930_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -673,26 +660,6 @@
return 0;
}
-static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm8930_aux_pcm_get_gpios();
- if (ret < 0) {
- pr_err("%s: Aux PCM GPIO request failed\n", __func__);
- return -EINVAL;
- }
- return 0;
-}
-
-static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
-{
-
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm8930_aux_pcm_free_gpios();
-}
-
static void msm8930_shutdown(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -705,11 +672,6 @@
.shutdown = msm8930_shutdown,
};
-static struct snd_soc_ops msm8930_auxpcm_be_ops = {
- .startup = msm8930_auxpcm_startup,
- .shutdown = msm8930_auxpcm_shutdown,
-};
-
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8930_dai[] = {
/* FrontEnd DAI Links */
@@ -940,30 +902,6 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
- /* AUX PCM Backend DAI Links */
- {
- .name = LPASS_BE_AUXPCM_RX,
- .stream_name = "AUX PCM Playback",
- .cpu_dai_name = "msm-dai-q6.2",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
- .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
- .ops = &msm8930_auxpcm_be_ops,
- },
- {
- .name = LPASS_BE_AUXPCM_TX,
- .stream_name = "AUX PCM Capture",
- .cpu_dai_name = "msm-dai-q6.3",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
- .no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
- .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
- },
/* Incall Music BACK END DAI Link */
{
.name = LPASS_BE_VOICE_PLAYBACK_TX,
@@ -1043,10 +981,16 @@
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
+ sitar_mbhc_cal = def_sitar_mbhc_cal();
+ if (!sitar_mbhc_cal) {
+ pr_err("Calibration data allocation failed\n");
+ return -ENOMEM;
+ }
msm8930_snd_device = platform_device_alloc("soc-audio", 0);
if (!msm8930_snd_device) {
pr_err("Platform device allocation failed\n");
+ kfree(sitar_mbhc_cal);
return -ENOMEM;
}
@@ -1054,6 +998,7 @@
ret = platform_device_add(msm8930_snd_device);
if (ret) {
platform_device_put(msm8930_snd_device);
+ kfree(sitar_mbhc_cal);
return ret;
}
@@ -1076,6 +1021,7 @@
}
msm8930_free_headset_mic_gpios();
platform_device_unregister(msm8930_snd_device);
+ kfree(sitar_mbhc_cal);
}
module_exit(msm8930_audio_exit);