diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 471edcb93a8b..82540aa647fa 100755 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -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) { diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h index aefb4ed72cb2..40cb70f05280 100644 --- a/sound/soc/codecs/wcd9335.h +++ b/sound/soc/codecs/wcd9335.h @@ -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.