forked from rubenslte/android_kernel_samsung_msm8226
Merge changes I9b4acae8,Ic0e2a529,Ib37f8545 into msm-3.0
* changes: ASoC: wcd9310: Use calibrated threshold ASoC: wcd9310: Introduce MBHC multi button support ALSA: Define more sound jack types
This commit is contained in:
committed by
QuIC Gerrit Code Review
commit
1484f46cd1
@@ -51,6 +51,8 @@ enum snd_jack_types {
|
||||
SND_JACK_BTN_3 = 0x0800,
|
||||
SND_JACK_BTN_4 = 0x0400,
|
||||
SND_JACK_BTN_5 = 0x0200,
|
||||
SND_JACK_BTN_6 = 0x0100,
|
||||
SND_JACK_BTN_7 = 0x0080,
|
||||
};
|
||||
|
||||
struct snd_jack {
|
||||
@@ -59,7 +61,7 @@ struct snd_jack {
|
||||
int type;
|
||||
const char *id;
|
||||
char name[100];
|
||||
unsigned int key[6]; /* Keep in sync with definitions above */
|
||||
unsigned int key[8]; /* Keep in sync with definitions above */
|
||||
void *private_data;
|
||||
void (*private_free)(struct snd_jack *);
|
||||
};
|
||||
|
||||
+159
-39
@@ -23,7 +23,6 @@
|
||||
#include <linux/mfd/wcd9310/pdata.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
@@ -54,6 +53,7 @@
|
||||
#define TABLA_MCLK_RATE_9600KHZ 9600000
|
||||
|
||||
#define TABLA_FAKE_INS_THRESHOLD_MS 2500
|
||||
#define TABLA_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);
|
||||
@@ -2756,7 +2756,6 @@ static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
|
||||
tabla->mbhc_data.npoll);
|
||||
snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
|
||||
tabla->mbhc_data.nbounce_wait);
|
||||
|
||||
n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
|
||||
snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
|
||||
n_cic[tabla_codec_mclk_index(tabla)]);
|
||||
@@ -3119,7 +3118,6 @@ static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
|
||||
/* Turn off the override after measuring mic voltage */
|
||||
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
|
||||
|
||||
pr_debug("read microphone bias value %04x\n", bias_value);
|
||||
return bias_value;
|
||||
}
|
||||
|
||||
@@ -3762,39 +3760,139 @@ int tabla_hs_detect(struct snd_soc_codec *codec,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tabla_hs_detect);
|
||||
|
||||
static int tabla_determine_button(const struct tabla_priv *priv,
|
||||
const s32 bias_mv)
|
||||
{
|
||||
s16 *v_btn_low, *v_btn_high;
|
||||
struct tabla_mbhc_btn_detect_cfg *btn_det;
|
||||
int i, btn = -1;
|
||||
|
||||
btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
|
||||
v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
|
||||
v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
|
||||
TABLA_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 tabla_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 tabla_dce_handler(int irq, void *data)
|
||||
{
|
||||
int i, mask;
|
||||
short bias_value_dce;
|
||||
s32 bias_mv_dce;
|
||||
int btn = -1, meas = 0;
|
||||
struct tabla_priv *priv = data;
|
||||
const struct tabla_mbhc_btn_detect_cfg *d =
|
||||
TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
|
||||
short btnmeas[d->n_btn_meas + 1];
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
short bias_value;
|
||||
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
bias_value = tabla_codec_read_dce_result(codec);
|
||||
pr_debug("%s: button press interrupt, DCE: %d,%d\n",
|
||||
__func__, bias_value,
|
||||
tabla_codec_sta_dce_v(codec, 1, bias_value));
|
||||
bias_value_dce = tabla_codec_read_dce_result(codec);
|
||||
bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
|
||||
|
||||
bias_value = tabla_codec_read_sta_result(codec);
|
||||
pr_debug("%s: button press interrupt, STA: %d,%d\n",
|
||||
__func__, bias_value,
|
||||
tabla_codec_sta_dce_v(codec, 0, bias_value));
|
||||
/*
|
||||
* TODO: If button pressed is not button 0,
|
||||
* report the button press event immediately.
|
||||
*/
|
||||
priv->buttons_pressed |= SND_JACK_BTN_0;
|
||||
|
||||
msleep(100);
|
||||
|
||||
if (schedule_delayed_work(&priv->btn0_dwork,
|
||||
msecs_to_jiffies(400)) == 0) {
|
||||
WARN(1, "Button pressed twice without release event\n");
|
||||
tabla_unlock_sleep(priv);
|
||||
/* determine pressed button */
|
||||
btnmeas[meas++] = tabla_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 = tabla_codec_sta_dce(codec, 1);
|
||||
bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
|
||||
btnmeas[meas] = tabla_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;
|
||||
}
|
||||
|
||||
if (btn >= 0) {
|
||||
mask = tabla_get_button_mask(btn);
|
||||
priv->buttons_pressed |= mask;
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* XXX: assuming button 0 has the lowest micbias voltage */
|
||||
if (btn == 0) {
|
||||
if (schedule_delayed_work(&priv->btn0_dwork,
|
||||
msecs_to_jiffies(400)) == 0) {
|
||||
WARN(1, "Button pressed twice without release"
|
||||
"event\n");
|
||||
tabla_unlock_sleep(priv);
|
||||
}
|
||||
} else {
|
||||
pr_debug("%s: Reporting short button %d(0x%x) press\n",
|
||||
__func__, btn, mask);
|
||||
tabla_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;
|
||||
}
|
||||
|
||||
@@ -3802,18 +3900,18 @@ static irqreturn_t tabla_release_handler(int irq, void *data)
|
||||
{
|
||||
struct tabla_priv *priv = data;
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
int ret, mb_v;
|
||||
int ret;
|
||||
short mb_v;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
if (priv->buttons_pressed & SND_JACK_BTN_0) {
|
||||
ret = cancel_delayed_work(&priv->btn0_dwork);
|
||||
|
||||
if (ret == 0) {
|
||||
pr_debug("%s: Reporting long button release event\n",
|
||||
__func__);
|
||||
pr_debug("%s: Reporting long button 0 release event\n",
|
||||
__func__);
|
||||
if (priv->button_jack)
|
||||
tabla_snd_soc_jack_report(priv,
|
||||
priv->button_jack, 0,
|
||||
@@ -3827,25 +3925,37 @@ static irqreturn_t tabla_release_handler(int irq, void *data)
|
||||
__func__, mb_v,
|
||||
tabla_codec_sta_dce_v(codec, 0, mb_v));
|
||||
|
||||
if (mb_v < -2000 || mb_v > -670)
|
||||
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__);
|
||||
__func__);
|
||||
else if (priv->button_jack) {
|
||||
pr_debug("%s:reporting short button "
|
||||
pr_debug("%s: Reporting short button 0 "
|
||||
"press and release\n", __func__);
|
||||
tabla_snd_soc_jack_report(priv,
|
||||
priv->button_jack,
|
||||
SND_JACK_BTN_0,
|
||||
SND_JACK_BTN_0);
|
||||
tabla_snd_soc_jack_report(priv,
|
||||
priv->button_jack,
|
||||
0, SND_JACK_BTN_0);
|
||||
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);
|
||||
tabla_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 &= ~TABLA_JACK_BUTTON_MASK;
|
||||
}
|
||||
|
||||
tabla_codec_start_hs_polling(codec);
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
@@ -4155,12 +4265,15 @@ static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
|
||||
|
||||
static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
|
||||
{
|
||||
short bias_value;
|
||||
struct tabla_priv *priv = data;
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
const struct tabla_mbhc_general_cfg *generic =
|
||||
TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
|
||||
short bias_value;
|
||||
int fake_removal = 0;
|
||||
int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
|
||||
|
||||
pr_debug("%s: enter, removal interrupt\n", __func__);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
|
||||
@@ -4169,11 +4282,18 @@ static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
|
||||
usleep_range(generic->t_shutdown_plug_rem,
|
||||
generic->t_shutdown_plug_rem);
|
||||
|
||||
bias_value = tabla_codec_sta_dce(codec, 1);
|
||||
pr_debug("removal interrupt, DCE: %d,%d\n",
|
||||
bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
|
||||
do {
|
||||
bias_value = tabla_codec_sta_dce(codec, 1);
|
||||
pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
|
||||
tabla_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 < (short) priv->mbhc_data.v_ins_h) {
|
||||
if (fake_removal) {
|
||||
pr_debug("False alarm, headset not actually removed\n");
|
||||
tabla_codec_start_hs_polling(codec);
|
||||
} else {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#define TABLA_VERSION_1_0 0
|
||||
#define TABLA_VERSION_1_1 1
|
||||
@@ -28,6 +29,11 @@
|
||||
#define STA 0
|
||||
#define DCE 1
|
||||
|
||||
#define TABLA_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 tabla_reg_readable[TABLA_CACHE_SIZE];
|
||||
extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
|
||||
|
||||
|
||||
+30
-23
@@ -55,7 +55,7 @@
|
||||
|
||||
#define TABLA_EXT_CLK_RATE 12288000
|
||||
|
||||
#define TABLA_MBHC_DEF_BUTTONS 3
|
||||
#define TABLA_MBHC_DEF_BUTTONS 8
|
||||
#define TABLA_MBHC_DEF_RLOADS 5
|
||||
|
||||
static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
|
||||
@@ -597,20 +597,16 @@ static void *def_tabla_mbhc_cal(void)
|
||||
#undef S
|
||||
#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
|
||||
S(v_no_mic, 30);
|
||||
S(v_hs_max, 1450);
|
||||
S(v_hs_max, 1550);
|
||||
#undef S
|
||||
#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
|
||||
S(c[0], 6);
|
||||
S(c[1], 10);
|
||||
S(c[2], 10);
|
||||
S(c[3], 14);
|
||||
S(c[4], 14);
|
||||
S(c[5], 16);
|
||||
S(c[6], 0);
|
||||
S(c[7], 0);
|
||||
S(nc, 5);
|
||||
S(n_meas, 11);
|
||||
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, TABLA_MBHC_DEF_BUTTONS);
|
||||
S(v_btn_press_delta_sta, 100);
|
||||
S(v_btn_press_delta_cic, 50);
|
||||
@@ -618,18 +614,28 @@ static void *def_tabla_mbhc_cal(void)
|
||||
btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
|
||||
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
|
||||
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
|
||||
btn_low[0] = 0;
|
||||
btn_high[0] = 40;
|
||||
btn_low[1] = 60;
|
||||
btn_high[1] = 140;
|
||||
btn_low[2] = 160;
|
||||
btn_high[2] = 240;
|
||||
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 = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
|
||||
n_ready[0] = 48;
|
||||
n_ready[1] = 38;
|
||||
n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
|
||||
n_cic[0] = 120;
|
||||
n_cic[1] = 94;
|
||||
n_cic[0] = 60;
|
||||
n_cic[1] = 47;
|
||||
gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
|
||||
gain[0] = 11;
|
||||
gain[1] = 9;
|
||||
@@ -671,15 +677,16 @@ static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
||||
err = snd_soc_jack_new(codec, "Headset Jack",
|
||||
(SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
|
||||
&hs_jack);
|
||||
(SND_JACK_HEADSET | SND_JACK_OC_HPHL |
|
||||
SND_JACK_OC_HPHR),
|
||||
&hs_jack);
|
||||
if (err) {
|
||||
pr_err("failed to create new jack\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_soc_jack_new(codec, "Button Jack",
|
||||
SND_JACK_BTN_0, &button_jack);
|
||||
TABLA_JACK_BUTTON_MASK, &button_jack);
|
||||
if (err) {
|
||||
pr_err("failed to create new jack\n");
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user