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:
Linux Build Service Account
2012-01-27 02:51:38 -08:00
committed by QuIC Gerrit Code Review
4 changed files with 198 additions and 63 deletions
+3 -1
View File
@@ -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
View File
@@ -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 {
+6
View File
@@ -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
View File
@@ -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;