summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorYeleswarapu Nagaradhesh <nagaradh@codeaurora.org>2014-07-08 22:11:49 +0530
committerYeleswarapu Nagaradhesh <nagaradh@codeaurora.org>2014-07-10 23:56:47 +0530
commit0c2ec08f192fb6202ce43b952d876f48cde2399f (patch)
treee9f35948921a8f2a379931d68ddc2d89b338ddf4 /sound/soc
parent219497d6f8c7ddd93475d3b4a7abbe704eac7fc8 (diff)
ASoC: wcd: add notifier between codec and mbhc
Refractor special headset detection logic. For button's to work on special headset in MICBIAS mode, we need to enable AutoZeroing. Add notification between codec and mbhc to enable AutoZeroing when MICBIAS is enabled. CRs-Fixed: 676586 Change-Id: I3430c029b22b2b5f80a8b267ea2e334b4ccae0a8 Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/msm8x16-wcd.c57
-rw-r--r--sound/soc/codecs/msm8x16-wcd.h53
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c199
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.h1
4 files changed, 209 insertions, 101 deletions
diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c
index 349a9d10ca90..aa54ed7220f7 100644
--- a/sound/soc/codecs/msm8x16-wcd.c
+++ b/sound/soc/codecs/msm8x16-wcd.c
@@ -114,11 +114,6 @@ enum {
BAND_MAX,
};
-enum {
- ON_DEMAND_MICBIAS = 0,
- ON_DEMAND_SUPPLIES_MAX,
-};
-
struct hpf_work {
struct msm8x16_wcd_priv *msm8x16_wcd;
u32 decimator;
@@ -128,33 +123,10 @@ struct hpf_work {
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
-struct on_demand_supply {
- struct regulator *supply;
- atomic_t ref;
-};
-
static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
"cdc-vdd-mic-bias",
};
-struct msm8x16_wcd_priv {
- struct snd_soc_codec *codec;
- u16 pmic_rev;
- u32 adc_count;
- u32 rx_bias_count;
- s32 dmic_1_2_clk_cnt;
- u32 mute_mask;
- bool mclk_enabled;
- bool clock_active;
- bool config_mode_active;
- bool spk_boost_set;
- bool ear_pa_boost_set;
- bool dec_active[NUM_DECIMATORS];
- struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
- /* mbhc module */
- struct wcd_mbhc mbhc;
-};
-
static unsigned long rx_digital_gain_reg[] = {
MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -204,6 +176,31 @@ static const struct wcd_mbhc_cb mbhc_cb = {
.enable_mb_source = msm8x16_wcd_enable_ext_mb_source,
};
+int msm8x16_unregister_notifier(struct snd_soc_codec *codec,
+ struct notifier_block *nblock)
+{
+ struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
+
+ return blocking_notifier_chain_unregister(&msm8x16_wcd->notifier,
+ nblock);
+}
+
+int msm8x16_register_notifier(struct snd_soc_codec *codec,
+ struct notifier_block *nblock)
+{
+ struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
+
+ return blocking_notifier_chain_register(&msm8x16_wcd->notifier, nblock);
+}
+
+void msm8x16_notifier_call(struct snd_soc_codec *codec,
+ const enum wcd_notify_event event)
+{
+ struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: notifier call event %d\n", __func__, event);
+ blocking_notifier_call_chain(&msm8x16_wcd->notifier, event, codec);
+}
static int get_spmi_msm8x16_wcd_device_info(u16 *reg,
struct msm8x16_wcd_spmi **msm8x16_wcd)
@@ -1838,6 +1835,7 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
} else if (strnstr(w->name, internal3_text, 30)) {
snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01);
}
+ msm8x16_notifier_call(codec, WCD_EVENT_PRE_MICBIAS_2_ON);
break;
case SND_SOC_DAPM_POST_PMD:
if (strnstr(w->name, internal1_text, 30)) {
@@ -1851,6 +1849,7 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
}
snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN,
0x45, 0x01);
+ msm8x16_notifier_call(codec, WCD_EVENT_PRE_MICBIAS_2_OFF);
break;
}
return 0;
@@ -3235,6 +3234,8 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
on_demand_supply_name[ON_DEMAND_MICBIAS]);
atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+ BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier);
+
wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
false);
diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h
index 7d497299264e..a5cfee9a7fa4 100644
--- a/sound/soc/codecs/msm8x16-wcd.h
+++ b/sound/soc/codecs/msm8x16-wcd.h
@@ -46,6 +46,8 @@
#define MCLK_SUS_RSC 2
#define MCLK_SUS_NO_ACT 3
+#define NUM_DECIMATORS 2
+
extern const u8 msm8x16_wcd_reg_readable[MSM8X16_WCD_CACHE_SIZE];
extern const u8 msm8x16_wcd_reg_readonly[MSM8X16_WCD_CACHE_SIZE];
extern const u8 msm8x16_wcd_reset_reg_defaults[MSM8X16_WCD_CACHE_SIZE];
@@ -105,6 +107,26 @@ enum {
MSM8X16_WCD_NUM_IRQS,
};
+enum wcd_notify_event {
+ WCD_EVENT_INVALID,
+ /* events for micbias ON and OFF */
+ WCD_EVENT_PRE_MICBIAS_2_OFF,
+ WCD_EVENT_POST_MICBIAS_2_OFF,
+ WCD_EVENT_PRE_MICBIAS_2_ON,
+ WCD_EVENT_POST_MICBIAS_2_ON,
+ /* events for PA ON and OFF */
+ WCD_EVENT_PRE_HPHL_PA_ON,
+ WCD_EVENT_POST_HPHL_PA_OFF,
+ WCD_EVENT_PRE_HPHR_PA_ON,
+ WCD_EVENT_POST_HPHR_PA_OFF,
+ WCD_EVENT_LAST,
+};
+
+enum {
+ ON_DEMAND_MICBIAS = 0,
+ ON_DEMAND_SUPPLIES_MAX,
+};
+
/*
* The delay list is per codec HW specification.
* Please add delay in the list in the future instead
@@ -173,6 +195,31 @@ struct msm8x16_wcd {
char __iomem *dig_base;
};
+struct on_demand_supply {
+ struct regulator *supply;
+ atomic_t ref;
+};
+
+struct msm8x16_wcd_priv {
+ struct snd_soc_codec *codec;
+ u16 pmic_rev;
+ u32 adc_count;
+ u32 rx_bias_count;
+ s32 dmic_1_2_clk_cnt;
+ u32 mute_mask;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool spk_boost_set;
+ bool ear_pa_boost_set;
+ bool dec_active[NUM_DECIMATORS];
+ struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
+ /* mbhc module */
+ struct wcd_mbhc mbhc;
+ struct blocking_notifier_head notifier;
+
+};
+
extern int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
bool dapm);
@@ -181,5 +228,11 @@ extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec);
+extern int msm8x16_register_notifier(struct snd_soc_codec *codec,
+ struct notifier_block *nblock);
+
+extern int msm8x16_unregister_notifier(struct snd_soc_codec *codec,
+ struct notifier_block *nblock);
+
#endif
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index d287b2403ced..657c50fe1ec6 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -34,6 +34,7 @@
#include "wcd9xxx-mbhc.h"
#include "msm8x16_wcd_registers.h"
#include "msm8916-wcd-irq.h"
+#include "msm8x16-wcd.h"
#define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
@@ -43,6 +44,7 @@
SND_JACK_BTN_4)
#define OCP_ATTEMPT 1
#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
+#define SPECIAL_HS_DETECT_TIME_MS (2 * 1000)
#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
#define GND_MIC_SWAP_THRESHOLD 4
@@ -65,6 +67,49 @@
"%s: BCL should have acquired\n", __func__); \
}
+static int wcd_event_notify(struct notifier_block *self, unsigned long val,
+ void *data)
+{
+ struct snd_soc_codec *codec = (struct snd_soc_codec *)data;
+ struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
+ struct wcd_mbhc *mbhc = &msm8x16_wcd->mbhc;
+ enum wcd_notify_event event = (enum wcd_notify_event)val;
+
+ pr_debug("%s: event %d\n", __func__, event);
+ switch (event) {
+ /* MICBIAS usage change */
+ case WCD_EVENT_PRE_MICBIAS_2_ON:
+ if (mbhc->micbias_enable) {
+ snd_soc_write(codec,
+ MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
+ 0xC0);
+ snd_soc_update_bits(codec,
+ MSM8X16_WCD_A_ANALOG_MICB_2_EN,
+ 0x18, 0x10);
+ }
+ /* Disable current source if micbias enabled */
+ snd_soc_update_bits(codec,
+ MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
+ 0xB0, 0x80);
+ break;
+ /* MICBIAS usage change */
+ case WCD_EVENT_PRE_MICBIAS_2_OFF:
+ snd_soc_update_bits(codec,
+ MSM8X16_WCD_A_ANALOG_MICB_2_EN,
+ 0x18, 0x00);
+ snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
+ 0x20);
+ /* Enable current source again for polling */
+ snd_soc_update_bits(codec,
+ MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
+ 0xB0, 0xB0);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc)
{
struct wcd_mbhc_btn_detect_cfg *btn_det;
@@ -426,13 +471,8 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
~WCD_MBHC_JACK_BUTTON_MASK;
}
- /*
- * Set micbias back to 1.8V if accessory was special
- * headset and thus micbias was increased to 2.8V
- */
if (mbhc->micbias_enable)
- snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
- 0x20);
+ mbhc->micbias_enable = false;
mbhc->zl = mbhc->zr = 0;
mbhc->is_hs_inserted = false;
@@ -462,11 +502,8 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
jack_type == SND_JACK_LINEOUT) &&
(mbhc->hph_status && mbhc->hph_status != jack_type)) {
- if (mbhc->micbias_enable &&
- mbhc->hph_status == SND_JACK_HEADSET)
- snd_soc_write(codec,
- MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
- 0x20);
+ if (mbhc->micbias_enable)
+ mbhc->micbias_enable = false;
mbhc->zl = mbhc->zr = 0;
mbhc->is_hs_inserted = false;
@@ -609,6 +646,69 @@ static bool wcd_check_cross_conn(struct wcd_mbhc *mbhc)
return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
}
+static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
+{
+ u16 result2;
+ struct snd_soc_codec *codec = mbhc->codec;
+ int delay = 0;
+ bool ret = false;
+ s16 reg;
+
+ /*
+ * Enable micbias if not already enabled
+ * and disable current source if using micbias
+ */
+ reg = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL);
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
+ 0xB0, 0x80);
+ /* Enable micbias if not already enabled */
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN,
+ 0x80, 0x80);
+ pr_debug("%s: special headset, start register writes\n", __func__);
+ result2 = snd_soc_read(codec,
+ MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
+ while (result2 & 0x01) {
+ if (wcd_swch_level_remove(mbhc)) {
+ pr_debug("%s: Switch level is low\n", __func__);
+ break;
+ }
+ delay = delay + 50;
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_CTL,
+ 0x60, 0x60);
+ snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
+ 0xC0);
+ /* Wait for 50msec for MICBIAS to settle down */
+ msleep(50);
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN,
+ 0x18, 0x10);
+ /* Wait for 50msec for FSM to update result values */
+ msleep(50);
+ result2 = snd_soc_read(codec,
+ MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
+ if (!(result2 & 0x01))
+ pr_debug("%s: Special headset detected in %d msecs\n",
+ __func__, (delay * 2));
+ if (delay == SPECIAL_HS_DETECT_TIME_MS) {
+ pr_debug("%s: Spl headset didnt get detect in 4 sec\n",
+ __func__);
+ break;
+ }
+ }
+ if (!(result2 & 0x01)) {
+ pr_debug("%s: Headset with threshold found\n", __func__);
+ mbhc->micbias_enable = true;
+ ret = true;
+ }
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_CTL, 0x60, 0x00);
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN, 0x80, 0x00);
+ snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL, reg);
+ snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL, 0x20);
+ snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN, 0x18, 0x00);
+
+ pr_debug("%s: leave\n", __func__);
+ return ret;
+}
+
static void wcd_correct_swch_plug(struct work_struct *work)
{
struct wcd_mbhc *mbhc;
@@ -618,7 +718,6 @@ static void wcd_correct_swch_plug(struct work_struct *work)
u16 result1, result2;
bool wrk_complete = false;
int pt_gnd_mic_swap_cnt = 0;
- int delay = 0;
bool is_pa_on;
pr_debug("%s: enter\n", __func__);
@@ -729,69 +828,12 @@ static void wcd_correct_swch_plug(struct work_struct *work)
}
if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
- /* Enable external voltage source to micbias if present */
- if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
- mbhc->mbhc_cb->enable_mb_source(codec, true);
-
- /* Enable micbias if not already enabled*/
- snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN,
- 0x80, 0x80);
- pr_debug("DEBUG special headset, start register writes");
-
- result2 = snd_soc_read(codec,
- MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
- while (result2 & 0x01) {
- if (wcd_swch_level_remove(mbhc)) {
- pr_debug("%s: Switch level is low ", __func__);
- break;
- }
- delay = delay + 50;
- snd_soc_update_bits(codec,
- MSM8X16_WCD_A_ANALOG_MICB_1_CTL,
- 0x60, 0x60);
- snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
- 0xC0);
- /*
- * Special headset needs micbias voltage above 2.4,
- * it is taking time for micbias to rampup and
- * for result2 to change.This delay is also dependent
- * on type of headset.
- */
- msleep(delay);
- snd_soc_update_bits(codec,
- MSM8X16_WCD_A_ANALOG_MICB_2_EN,
- 0x18, 0x10);
- msleep(50);
- result2 = snd_soc_read(codec,
- MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT);
- if (!(result2 & 0x01))
- pr_debug("spl headset detected in %d msecs",
- delay);
- if (delay == 2000) {
- pr_debug("spl headset not detected in 2 sec");
- break;
- }
- }
- if (!result1 && !(result2 & 0x01)) {
- pr_debug("%s: Headset with threshold found\n",
- __func__);
+ if (wcd_is_special_headset(mbhc)) {
+ pr_debug("%s: Special headset found %d\n",
+ __func__, plug_type);
plug_type = MBHC_PLUG_TYPE_HEADSET;
- mbhc->micbias_enable = true;
+ goto report;
}
- /* Disable autozero and put micbias back to 1.8V */
- snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN,
- 0x18, 0x00);
- snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_CTL,
- 0x60, 0x00);
- snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN,
- 0x80, 0x00);
- if (!mbhc->micbias_enable)
- snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
- 0x20);
-
- /* Disable external voltage source to micbias if present */
- if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
- mbhc->mbhc_cb->enable_mb_source(codec, false);
}
report:
@@ -1385,6 +1427,14 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
}
+ /* Register event notifier */
+ mbhc->nblock.notifier_call = wcd_event_notify;
+ ret = msm8x16_register_notifier(codec, &mbhc->nblock);
+ if (ret) {
+ pr_err("%s: Failed to register notifier %d\n", __func__, ret);
+ return ret;
+ }
+
init_waitqueue_head(&mbhc->wait_btn_press);
mutex_init(&mbhc->codec_resource_lock);
@@ -1457,6 +1507,7 @@ err_btn_release_irq:
err_btn_press_irq:
wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
err_mbhc_sw_irq:
+ msm8x16_unregister_notifier(codec, &mbhc->nblock);
mutex_destroy(&mbhc->codec_resource_lock);
err:
pr_debug("%s: leave ret %d\n", __func__, ret);
@@ -1466,6 +1517,7 @@ EXPORT_SYMBOL(wcd_mbhc_init);
void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
{
+ struct snd_soc_codec *codec = mbhc->codec;
wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
@@ -1473,6 +1525,7 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_hs_ins_rem_intr, mbhc);
wcd9xxx_spmi_free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
wcd9xxx_spmi_free_irq(mbhc->intr_ids->hph_right_ocp, mbhc);
+ msm8x16_unregister_notifier(codec, &mbhc->nblock);
mutex_destroy(&mbhc->codec_resource_lock);
}
EXPORT_SYMBOL(wcd_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index abb4e6ca159e..e847f8960c0a 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -103,6 +103,7 @@ struct wcd_mbhc {
const struct wcd_mbhc_intr *intr_ids;
/* Work to correct accessory type */
struct work_struct correct_plug_swch;
+ struct notifier_block nblock;
};
#define WCD_MBHC_CAL_BTN_DET_PTR(cali) ( \