ASoC: wcd: enable regulator when micbias is needed

When vdd micbias is connected to regulator, need enable
regulator when micbias is needed.
To detect special headset, micbias need to be set to 2.7v.
Regulator need get enabled before special headset detection.

Change-Id: Iae361cabf7b5194e12f5ddc8e32d60cf94bf28c3
Signed-off-by: Meng Wang <mwang@codeaurora.org>
This commit is contained in:
Meng Wang 2015-12-17 14:01:44 +08:00 committed by David Keitel
parent 6c13525e1b
commit e066a36f41
2 changed files with 156 additions and 34 deletions

View file

@ -142,6 +142,12 @@ MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode");
#define TASHA_DIG_CORE_COLLAPSE_TIMER_MS (5 * 1000)
#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
"cdc-vdd-mic-bias",
};
enum {
POWER_COLLAPSE,
POWER_RESUME,
@ -774,6 +780,8 @@ struct tasha_priv {
struct snd_info_entry *version_entry;
int power_active_ref;
struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
enum wcd9335_codec_event);
int spkr_gain_offset;
@ -1283,6 +1291,55 @@ static void tasha_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec,
0xC0, 0x40);
}
static int tasha_enable_ext_mb_source(struct snd_soc_codec *codec,
bool turn_on)
{
struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
int ret = 0;
struct on_demand_supply *supply;
if (!tasha)
return -EINVAL;
supply = &tasha->on_demand_list[ON_DEMAND_MICBIAS];
if (!supply->supply) {
dev_dbg(codec->dev, "%s: warning supply not present ond for %s\n",
__func__, "onDemand Micbias");
return ret;
}
dev_dbg(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
supply->ondemand_supply_count);
if (turn_on) {
if (!(supply->ondemand_supply_count)) {
ret = snd_soc_dapm_force_enable_pin(
snd_soc_codec_get_dapm(codec),
"MICBIAS_REGULATOR");
snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
}
supply->ondemand_supply_count++;
} else {
if (supply->ondemand_supply_count > 0)
supply->ondemand_supply_count--;
if (!(supply->ondemand_supply_count)) {
ret = snd_soc_dapm_disable_pin(
snd_soc_codec_get_dapm(codec),
"MICBIAS_REGULATOR");
snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
}
}
if (ret)
dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
__func__, turn_on ? "enable" : "disabled");
else
dev_dbg(codec->dev, "%s: %s external micbias source\n",
__func__, turn_on ? "Enabled" : "Disabled");
return ret;
}
static int tasha_micbias_control(struct snd_soc_codec *codec,
int micb_num,
int req, bool is_dapm)
@ -1910,6 +1967,7 @@ static const struct wcd_mbhc_cb mbhc_cb = {
.free_irq = tasha_mbhc_free_irq,
.clk_setup = tasha_mbhc_clk_setup,
.map_btn_code_to_num = tasha_mbhc_btn_to_num,
.enable_mb_source = tasha_enable_ext_mb_source,
.mbhc_bias = tasha_mbhc_mbhc_bias_control,
.set_btn_thr = tasha_mbhc_program_btn_thr,
.lock_sleep = tasha_mbhc_lock_sleep,
@ -5001,6 +5059,57 @@ static int tasha_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
return 0;
}
static int tasha_codec_enable_on_demand_supply(
struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
int ret = 0;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
struct on_demand_supply *supply;
if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
dev_err(codec->dev, "%s: error index > MAX Demand supplies",
__func__);
ret = -EINVAL;
goto out;
}
dev_dbg(codec->dev, "%s: supply: %s event: %d\n",
__func__, on_demand_supply_name[w->shift], event);
supply = &tasha->on_demand_list[w->shift];
WARN_ONCE(!supply->supply, "%s isn't defined\n",
on_demand_supply_name[w->shift]);
if (!supply->supply) {
dev_err(codec->dev, "%s: err supply not present ond for %d",
__func__, w->shift);
goto out;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = regulator_enable(supply->supply);
if (ret)
dev_err(codec->dev, "%s: Failed to enable %s\n",
__func__,
on_demand_supply_name[w->shift]);
break;
case SND_SOC_DAPM_POST_PMD:
ret = regulator_disable(supply->supply);
if (ret)
dev_err(codec->dev, "%s: Failed to disable %s\n",
__func__,
on_demand_supply_name[w->shift]);
break;
default:
break;
};
out:
return ret;
}
static int tasha_codec_find_amic_input(struct snd_soc_codec *codec,
int adc_mux_n)
{
@ -10117,6 +10226,10 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LINEOUT4"),
SND_SOC_DAPM_OUTPUT("ANC LINEOUT1"),
SND_SOC_DAPM_OUTPUT("ANC LINEOUT2"),
SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
ON_DEMAND_MICBIAS, 0,
tasha_codec_enable_on_demand_supply,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD9335_CDC_TX0_TX_PATH_192_CTL, 0,
0, &adc_us_mux0_switch),
@ -12163,40 +12276,6 @@ static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
bw_ops, true);
}
static int tasha_dapm_pre_powerup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
dev_dbg(codec->dev, "%s: w->name %s event %d\n",
__func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
tasha_codec_vote_max_bw(codec, true);
break;
}
return 0;
}
static int tasha_dapm_post_powerup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
dev_dbg(codec->dev, "%s: w->name %s event %d\n",
__func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
tasha_codec_vote_max_bw(codec, false);
break;
}
return 0;
}
static int tasha_cpe_err_irq_control(struct snd_soc_codec *codec,
enum cpe_err_irq_cntl_type cntl_type, u8 *status)
{
@ -12410,6 +12489,26 @@ err:
return ret;
}
static struct regulator *tasha_codec_find_ondemand_regulator(
struct snd_soc_codec *codec, const char *name)
{
int i;
struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
struct wcd9xxx *wcd9xxx = tasha->wcd9xxx;
struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent);
for (i = 0; i < wcd9xxx->num_of_supplies; ++i) {
if (pdata->regulator[i].ondemand &&
wcd9xxx->supplies[i].supply &&
!strcmp(wcd9xxx->supplies[i].supply, name))
return wcd9xxx->supplies[i].consumer;
}
dev_dbg(tasha->dev, "Warning: regulator not found:%s\n",
name);
return NULL;
}
static int tasha_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@ -12418,6 +12517,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int i, ret;
void *ptr = NULL;
struct regulator *supply;
control = dev_get_drvdata(codec->dev->parent);
@ -12468,6 +12568,14 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
goto err;
}
supply = tasha_codec_find_ondemand_regulator(codec,
on_demand_supply_name[ON_DEMAND_MICBIAS]);
if (supply) {
tasha->on_demand_list[ON_DEMAND_MICBIAS].supply = supply;
tasha->on_demand_list[ON_DEMAND_MICBIAS].ondemand_supply_count =
0;
}
tasha->fw_data = devm_kzalloc(codec->dev,
sizeof(*(tasha->fw_data)), GFP_KERNEL);
if (!tasha->fw_data) {

View file

@ -87,6 +87,20 @@ enum wcd9335_codec_event {
WCD9335_CODEC_EVENT_CODEC_UP = 0,
};
enum tasha_on_demand_supply {
ON_DEMAND_MICBIAS = 0,
ON_DEMAND_SUPPLIES_MAX,
};
/* structure used to put the defined
* ondemand supply for codec
* and count being used.
*/
struct on_demand_supply {
struct regulator *supply;
int ondemand_supply_count;
};
/* Dai data structure holds the
* dai specific info like rate,
* channel number etc.