diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c index 93ff975e83..97989dee18 100644 --- a/asoc/codecs/wcd-mbhc-v2.c +++ b/asoc/codecs/wcd-mbhc-v2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "msm-cdc-pinctrl.h" @@ -958,6 +959,9 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) mbhc->extn_cable_hph_rem = false; wcd_mbhc_report_plug(mbhc, 0, jack_type); + if (mbhc->mbhc_cfg->enable_usbc_analog) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + } else if (!detection_type) { /* Disable external voltage source to micbias if present */ if (mbhc->mbhc_cb->enable_mb_source) @@ -1291,8 +1295,8 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) * by an external source */ if (mbhc->mbhc_cfg->enable_usbc_analog) { - mbhc->hphl_swh = 1; - mbhc->gnd_swh = 1; + mbhc->hphl_swh = 0; + mbhc->gnd_swh = 0; if (mbhc->mbhc_cb->hph_pull_up_control_v2) mbhc->mbhc_cb->hph_pull_up_control_v2(codec, @@ -1310,7 +1314,16 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) if (mbhc->mbhc_cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl) mbhc->mbhc_cb->mbhc_gnd_det_ctrl(codec, true); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + + /* + * Disable L_DET for USB-C analog audio to avoid spurious interrupts + * when a non-audio accessory is inserted. L_DET_EN sets to 1 when FSA + * I2C driver notifies that ANALOG_AUDIO_ADAPTER is inserted + */ + if (mbhc->mbhc_cfg->enable_usbc_analog) + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); if (mbhc->mbhc_cfg->enable_usbc_analog) { /* Insertion debounce set to 48ms */ @@ -1481,207 +1494,26 @@ static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc) return result; } -static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc, - bool active) +static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, + unsigned long mode, void *ptr) { - int rc = 0; - struct usbc_ana_audio_config *config = - &mbhc->mbhc_cfg->usbc_analog_cfg; - union power_supply_propval pval; + struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, fsa_nb); - dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n", - __func__, active); + if (!mbhc) + return -EINVAL; - memset(&pval, 0, sizeof(pval)); + dev_dbg(mbhc->codec->dev, "%s: mode = %lu\n", __func__, mode); - if (active) { - pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; - if (power_supply_set_property(mbhc->usb_psy, - POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval)) - dev_info(mbhc->codec->dev, "%s: force PR_SOURCE mode unsuccessful\n", - __func__); - else - mbhc->usbc_force_pr_mode = true; - - if (config->usbc_en1_gpio_p) - rc = msm_cdc_pinctrl_select_active_state( - config->usbc_en1_gpio_p); - if (rc == 0 && config->usbc_force_gpio_p) - rc = msm_cdc_pinctrl_select_active_state( - config->usbc_force_gpio_p); - mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; - } else { - /* no delay is required when disabling GPIOs */ - if (config->usbc_en1_gpio_p) - msm_cdc_pinctrl_select_sleep_state( - config->usbc_en1_gpio_p); - if (config->usbc_force_gpio_p) - msm_cdc_pinctrl_select_sleep_state( - config->usbc_force_gpio_p); - - if (mbhc->usbc_force_pr_mode) { - pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; - if (power_supply_set_property(mbhc->usb_psy, - POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval)) - dev_info(mbhc->codec->dev, "%s: force PR_DUAL mode unsuccessful\n", - __func__); - - mbhc->usbc_force_pr_mode = false; - } - - mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE; - if (mbhc->mbhc_cfg->swap_gnd_mic) - mbhc->mbhc_cfg->swap_gnd_mic(mbhc->codec, false); + if (mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + /* insertion detected, enable L_DET_EN */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); } - - return rc; -} - -/* workqueue */ -static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work) -{ - struct wcd_mbhc *mbhc = - container_of(work, struct wcd_mbhc, usbc_analog_work); - - wcd_mbhc_usb_c_analog_setup_gpios(mbhc, - mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE); -} - -/* this callback function is used to process PMI notification */ -static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb, - unsigned long evt, void *ptr) -{ - int ret; - union power_supply_propval mode; - struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb); - struct snd_soc_codec *codec = mbhc->codec; - - if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED) - return 0; - - ret = power_supply_get_property(mbhc->usb_psy, - POWER_SUPPLY_PROP_TYPEC_MODE, &mode); - if (ret) { - dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n", - __func__, ret); - return ret; - } - - dev_dbg(codec->dev, "%s: USB change event received\n", - __func__); - dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__, - mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); - - switch (mode.intval) { - case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: - case POWER_SUPPLY_TYPEC_NONE: - dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n", - __func__, mbhc->usbc_mode, mode.intval); - - if (mbhc->usbc_mode == mode.intval) - break; /* filter notifications received before */ - mbhc->usbc_mode = mode.intval; - - dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n", - __func__); - schedule_work(&mbhc->usbc_analog_work); - break; - default: - break; - } - return ret; -} - -/* PMI registration code */ -static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc) -{ - int ret = 0; - struct snd_soc_codec *codec = mbhc->codec; - - dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__); - INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn); - - mbhc->usb_psy = power_supply_get_by_name("usb"); - if (IS_ERR_OR_NULL(mbhc->usb_psy)) { - dev_err(codec->dev, "%s: could not get USB psy info\n", - __func__); - ret = -EPROBE_DEFER; - if (IS_ERR(mbhc->usb_psy)) - ret = PTR_ERR(mbhc->usb_psy); - mbhc->usb_psy = NULL; - goto err; - } - - ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); - if (ret) { - dev_err(codec->dev, "%s: error while setting USBC ana gpios\n", - __func__); - goto err; - } - - mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed; - mbhc->psy_nb.priority = 0; - ret = power_supply_reg_notifier(&mbhc->psy_nb); - if (ret) { - dev_err(codec->dev, "%s: power supply registration failed\n", - __func__); - goto err; - } - - /* - * as part of the init sequence check if there is a connected - * USB C analog adapter - */ - dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n", - __func__); - ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb, - PSY_EVENT_PROP_CHANGED, - mbhc->usb_psy); - -err: - return ret; -} - -static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc) -{ - wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); - - /* deregister from PMI */ - power_supply_unreg_notifier(&mbhc->psy_nb); - return 0; } -static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc, - struct wcd_mbhc_config *mbhc_cfg, - const char *gpio_dt_str, - int *gpio, struct device_node **gpio_dn) -{ - int rc = 0; - struct snd_soc_codec *codec = mbhc->codec; - struct snd_soc_card *card = codec->component.card; - - dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str); - - *gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0); - - if (!(*gpio_dn)) { - *gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0); - if (!gpio_is_valid(*gpio)) { - dev_err(card->dev, "%s, property %s not in node %s", - __func__, gpio_dt_str, - card->dev->of_node->full_name); - rc = -EINVAL; - } - } - - return rc; -} - int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) { int rc = 0; - struct usbc_ana_audio_config *config; struct snd_soc_codec *codec; struct snd_soc_card *card; const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; @@ -1689,7 +1521,6 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) if (!mbhc || !mbhc_cfg) return -EINVAL; - config = &mbhc_cfg->usbc_analog_cfg; codec = mbhc->codec; card = codec->component.card; @@ -1705,42 +1536,24 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) &mbhc_cfg->enable_usbc_analog); } if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) { - dev_info(card->dev, + dev_dbg(card->dev, "%s: %s in dt node is missing or false\n", __func__, usb_c_dt); - dev_info(card->dev, + dev_dbg(card->dev, "%s: skipping USB c analog configuration\n", __func__); } - /* initialize GPIOs */ + /* Parse fsa switch handle */ if (mbhc_cfg->enable_usbc_analog) { dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n", __func__); mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; - rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, - "qcom,usbc-analog-en1-gpio", - &config->usbc_en1_gpio, - &config->usbc_en1_gpio_p); - if (rc) - goto err; - - if (of_find_property(card->dev->of_node, - "qcom,usbc-analog-force_detect_gpio", - NULL)) { - rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, - "qcom,usbc-analog-force_detect_gpio", - &config->usbc_force_gpio, - &config->usbc_force_gpio_p); - if (rc) - goto err; - } - - dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n", - __func__); - /* init PMI notifier */ - rc = wcd_mbhc_usb_c_analog_init(mbhc); - if (rc) { - rc = EPROBE_DEFER; + mbhc->fsa_np = of_parse_phandle(card->dev->of_node, + "fsa4480-i2c-handle", 0); + if (!mbhc->fsa_np) { + dev_err(card->dev, "%s: fsa4480 i2c node not found\n", + __func__); + rc = -EINVAL; goto err; } } @@ -1753,6 +1566,11 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) || (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) { rc = wcd_mbhc_initialise(mbhc); + if (rc) { + dev_err(card->dev, "%s: wcd mbhc initialize failed\n", + __func__); + goto err; + } } else { if (!mbhc->mbhc_fw || !mbhc->mbhc_cal) schedule_delayed_work(&mbhc->mbhc_firmware_dwork, @@ -1762,24 +1580,14 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); } + if (mbhc_cfg->enable_usbc_analog) { + mbhc->fsa_nb.notifier_call = wcd_mbhc_usbc_ana_event_handler; + mbhc->fsa_nb.priority = 0; + rc = fsa4480_reg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + } + return rc; err: - if (config->usbc_en1_gpio > 0) { - dev_dbg(card->dev, "%s free usb en1 gpio %d\n", - __func__, config->usbc_en1_gpio); - gpio_free(config->usbc_en1_gpio); - config->usbc_en1_gpio = 0; - } - if (config->usbc_force_gpio > 0) { - dev_dbg(card->dev, "%s free usb_force gpio %d\n", - __func__, config->usbc_force_gpio); - gpio_free(config->usbc_force_gpio); - config->usbc_force_gpio = 0; - } - if (config->usbc_en1_gpio_p) - of_node_put(config->usbc_en1_gpio_p); - if (config->usbc_force_gpio_p) - of_node_put(config->usbc_force_gpio_p); dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc); return rc; } @@ -1787,8 +1595,6 @@ EXPORT_SYMBOL(wcd_mbhc_start); void wcd_mbhc_stop(struct wcd_mbhc *mbhc) { - struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg; - pr_debug("%s: enter\n", __func__); if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) { @@ -1813,19 +1619,8 @@ void wcd_mbhc_stop(struct wcd_mbhc *mbhc) mbhc->mbhc_cal = NULL; } - if (mbhc->mbhc_cfg->enable_usbc_analog) { - wcd_mbhc_usb_c_analog_deinit(mbhc); - /* free GPIOs */ - if (config->usbc_en1_gpio > 0) - gpio_free(config->usbc_en1_gpio); - if (config->usbc_force_gpio) - gpio_free(config->usbc_force_gpio); - - if (config->usbc_en1_gpio_p) - of_node_put(config->usbc_en1_gpio_p); - if (config->usbc_force_gpio_p) - of_node_put(config->usbc_force_gpio_p); - } + if (mbhc->mbhc_cfg->enable_usbc_analog) + fsa4480_unreg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); pr_debug("%s: leave\n", __func__); } diff --git a/asoc/codecs/wcd-mbhc-v2.h b/asoc/codecs/wcd-mbhc-v2.h index fc8b3f8f48..2fb09ff5be 100644 --- a/asoc/codecs/wcd-mbhc-v2.h +++ b/asoc/codecs/wcd-mbhc-v2.h @@ -422,15 +422,6 @@ enum mbhc_moisture_rref { R_184_KOHM, }; -struct usbc_ana_audio_config { - int usbc_en1_gpio; - int usbc_en2_gpio; - int usbc_force_gpio; - struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */ - struct device_node *usbc_en2_gpio_p; /* used by pinctrl API */ - struct device_node *usbc_force_gpio_p; /* used by pinctrl API */ -}; - struct wcd_mbhc_config { bool read_fw_bin; void *calibration; @@ -446,7 +437,6 @@ struct wcd_mbhc_config { int anc_micbias; bool enable_anc_mic_detect; u32 enable_usbc_analog; - struct usbc_ana_audio_config usbc_analog_cfg; }; struct wcd_mbhc_intr { @@ -599,14 +589,10 @@ struct wcd_mbhc { unsigned long intr_status; bool is_hph_ocp_pending; - bool usbc_force_pr_mode; - int usbc_mode; - struct notifier_block psy_nb; - struct power_supply *usb_psy; - struct work_struct usbc_analog_work; - struct wcd_mbhc_fn *mbhc_fn; bool force_linein; + struct device_node *fsa_np; + struct notifier_block fsa_nb; }; void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,