ASoC: wcd934x: Add support for USB Type-C analog audio
Add playback and capture support when an analog wired accessory is inserted into USB Type-C receptacle through an USB type-c to 3.5mm analog audio adapter. CRs-Fixed: 1102048 Change-Id: I36126ecdb0d2683d27d78dea9256bee0be67c1a6 Signed-off-by: Phani Kumar Uppalapati <phaniu@codeaurora.org>
This commit is contained in:
parent
d9ac8efbd9
commit
f42b8d1625
4 changed files with 351 additions and 5 deletions
|
@ -2334,6 +2334,11 @@ Optional properties:
|
||||||
- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
|
- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target
|
||||||
- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
|
- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device
|
||||||
- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
|
- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
|
||||||
|
- qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is
|
||||||
|
enabled or not.
|
||||||
|
- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio
|
||||||
|
- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio
|
||||||
|
- qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -2407,6 +2412,10 @@ Example:
|
||||||
<&wsa881x_213>, <&wsa881x_214>;
|
<&wsa881x_213>, <&wsa881x_214>;
|
||||||
qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
|
qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
|
||||||
"SpkrRight", "SpkrLeft";
|
"SpkrRight", "SpkrLeft";
|
||||||
|
qcom,msm-mbhc-usbc-audio-supported = <1>;
|
||||||
|
qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
|
||||||
|
qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>;
|
||||||
|
qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>;
|
||||||
};
|
};
|
||||||
|
|
||||||
* MSMSTUB ASoC Machine driver
|
* MSMSTUB ASoC Machine driver
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
|
#include <linux/mfd/msm-cdc-pinctrl.h>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
#include "wcd-mbhc-v2.h"
|
#include "wcd-mbhc-v2.h"
|
||||||
|
@ -2132,6 +2133,22 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
|
||||||
if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
|
if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
|
||||||
mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
|
mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For USB analog we need to override the switch configuration.
|
||||||
|
* Also, disable hph_l pull-up current source as HS_DET_L is driven
|
||||||
|
* by an external source
|
||||||
|
*/
|
||||||
|
if (mbhc->mbhc_cfg->enable_usbc_analog) {
|
||||||
|
mbhc->hphl_swh = 1;
|
||||||
|
mbhc->gnd_swh = 1;
|
||||||
|
|
||||||
|
if (mbhc->mbhc_cb->hph_pull_up_control)
|
||||||
|
mbhc->mbhc_cb->hph_pull_up_control(codec, I_OFF);
|
||||||
|
else
|
||||||
|
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
|
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
|
||||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
|
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
|
||||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
|
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
|
||||||
|
@ -2304,15 +2321,263 @@ int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wcd_mbhc_start(struct wcd_mbhc *mbhc,
|
static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
|
||||||
struct wcd_mbhc_config *mbhc_cfg)
|
bool active)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
struct usbc_ana_audio_config *config =
|
||||||
|
&mbhc->mbhc_cfg->usbc_analog_cfg;
|
||||||
|
|
||||||
|
dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n",
|
||||||
|
__func__, active);
|
||||||
|
if (active) {
|
||||||
|
if (config->usbc_en1_gpio_p) {
|
||||||
|
rc = msm_cdc_pinctrl_select_active_state(
|
||||||
|
config->usbc_en1_gpio_p);
|
||||||
|
/* delay required to allow the hw to stabilize */
|
||||||
|
usleep_range(1000, 1200);
|
||||||
|
}
|
||||||
|
if (rc == 0 && config->usbc_en2n_gpio_p) {
|
||||||
|
rc = msm_cdc_pinctrl_select_active_state(
|
||||||
|
config->usbc_en2n_gpio_p);
|
||||||
|
/* delay required to allow the hw to stabilize */
|
||||||
|
usleep_range(1000, 1200);
|
||||||
|
}
|
||||||
|
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_en2n_gpio_p)
|
||||||
|
msm_cdc_pinctrl_select_sleep_state(
|
||||||
|
config->usbc_en2n_gpio_p);
|
||||||
|
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);
|
||||||
|
mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
if (!mbhc || !mbhc_cfg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
config = &mbhc_cfg->usbc_analog_cfg;
|
||||||
|
codec = mbhc->codec;
|
||||||
|
card = codec->component.card;
|
||||||
|
|
||||||
pr_debug("%s: enter\n", __func__);
|
|
||||||
/* update the mbhc config */
|
/* update the mbhc config */
|
||||||
mbhc->mbhc_cfg = mbhc_cfg;
|
mbhc->mbhc_cfg = mbhc_cfg;
|
||||||
|
|
||||||
|
dev_dbg(mbhc->codec->dev, "%s: enter\n", __func__);
|
||||||
|
|
||||||
|
/* check if USB C analog is defined on device tree */
|
||||||
|
mbhc_cfg->enable_usbc_analog = 0;
|
||||||
|
if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) {
|
||||||
|
rc = of_property_read_u32(card->dev->of_node, usb_c_dt,
|
||||||
|
&mbhc_cfg->enable_usbc_analog);
|
||||||
|
}
|
||||||
|
if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) {
|
||||||
|
dev_info(card->dev,
|
||||||
|
"%s: %s in dt node is missing or false\n",
|
||||||
|
__func__, usb_c_dt);
|
||||||
|
dev_info(card->dev,
|
||||||
|
"%s: skipping USB c analog configuration\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize GPIOs */
|
||||||
|
if (mbhc_cfg->enable_usbc_analog) {
|
||||||
|
dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n",
|
||||||
|
__func__);
|
||||||
|
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;
|
||||||
|
|
||||||
|
rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
|
||||||
|
"qcom,usbc-analog-en2_n_gpio",
|
||||||
|
&config->usbc_en2n_gpio,
|
||||||
|
&config->usbc_en2n_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;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set btn key code */
|
/* Set btn key code */
|
||||||
if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
|
if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
|
||||||
pr_err("Set btn key code error!!!\n");
|
pr_err("Set btn key code error!!!\n");
|
||||||
|
@ -2329,14 +2594,44 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc,
|
||||||
pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
|
pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
|
||||||
__func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
|
__func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
|
||||||
}
|
}
|
||||||
pr_debug("%s: leave %d\n", __func__, rc);
|
|
||||||
|
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_en2n_gpio > 0) {
|
||||||
|
dev_dbg(card->dev, "%s free usb_en2 gpio %d\n",
|
||||||
|
__func__, config->usbc_en2n_gpio);
|
||||||
|
gpio_free(config->usbc_en2n_gpio);
|
||||||
|
config->usbc_en2n_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_en2n_gpio_p)
|
||||||
|
of_node_put(config->usbc_en2n_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;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wcd_mbhc_start);
|
EXPORT_SYMBOL(wcd_mbhc_start);
|
||||||
|
|
||||||
void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
|
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__);
|
pr_debug("%s: enter\n", __func__);
|
||||||
|
|
||||||
if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
|
if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
|
||||||
if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
|
if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
|
||||||
mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
|
mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
|
||||||
|
@ -2358,6 +2653,25 @@ void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
|
||||||
mbhc->mbhc_fw = NULL;
|
mbhc->mbhc_fw = NULL;
|
||||||
mbhc->mbhc_cal = NULL;
|
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_en2n_gpio > 0)
|
||||||
|
gpio_free(config->usbc_en2n_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_en2n_gpio_p)
|
||||||
|
of_node_put(config->usbc_en2n_gpio_p);
|
||||||
|
if (config->usbc_force_gpio_p)
|
||||||
|
of_node_put(config->usbc_force_gpio_p);
|
||||||
|
}
|
||||||
|
|
||||||
pr_debug("%s: leave\n", __func__);
|
pr_debug("%s: leave\n", __func__);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wcd_mbhc_stop);
|
EXPORT_SYMBOL(wcd_mbhc_stop);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
#include <linux/power_supply.h>
|
||||||
#include "wcdcal-hwdep.h"
|
#include "wcdcal-hwdep.h"
|
||||||
|
|
||||||
#define TOMBAK_MBHC_NC 0
|
#define TOMBAK_MBHC_NC 0
|
||||||
|
@ -249,6 +250,15 @@ enum mbhc_moisture_rref {
|
||||||
R_184_KOHM,
|
R_184_KOHM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct usbc_ana_audio_config {
|
||||||
|
int usbc_en1_gpio;
|
||||||
|
int usbc_en2n_gpio;
|
||||||
|
int usbc_force_gpio;
|
||||||
|
struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */
|
||||||
|
struct device_node *usbc_en2n_gpio_p; /* used by pinctrl API */
|
||||||
|
struct device_node *usbc_force_gpio_p; /* used by pinctrl API */
|
||||||
|
};
|
||||||
|
|
||||||
struct wcd_mbhc_config {
|
struct wcd_mbhc_config {
|
||||||
bool read_fw_bin;
|
bool read_fw_bin;
|
||||||
void *calibration;
|
void *calibration;
|
||||||
|
@ -263,6 +273,8 @@ struct wcd_mbhc_config {
|
||||||
int mbhc_micbias;
|
int mbhc_micbias;
|
||||||
int anc_micbias;
|
int anc_micbias;
|
||||||
bool enable_anc_mic_detect;
|
bool enable_anc_mic_detect;
|
||||||
|
u32 enable_usbc_analog;
|
||||||
|
struct usbc_ana_audio_config usbc_analog_cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wcd_mbhc_intr {
|
struct wcd_mbhc_intr {
|
||||||
|
@ -443,6 +455,11 @@ struct wcd_mbhc {
|
||||||
|
|
||||||
unsigned long intr_status;
|
unsigned long intr_status;
|
||||||
bool is_hph_ocp_pending;
|
bool is_hph_ocp_pending;
|
||||||
|
|
||||||
|
int usbc_mode;
|
||||||
|
struct notifier_block psy_nb;
|
||||||
|
struct power_supply *usb_psy;
|
||||||
|
struct work_struct usbc_analog_work;
|
||||||
};
|
};
|
||||||
#define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
|
#define WCD_MBHC_CAL_SIZE(buttons, rload) ( \
|
||||||
sizeof(struct wcd_mbhc_general_cfg) + \
|
sizeof(struct wcd_mbhc_general_cfg) + \
|
||||||
|
|
|
@ -772,13 +772,19 @@ static void tavil_mbhc_moisture_config(struct wcd_mbhc *mbhc)
|
||||||
{
|
{
|
||||||
struct snd_soc_codec *codec = mbhc->codec;
|
struct snd_soc_codec *codec = mbhc->codec;
|
||||||
|
|
||||||
if (mbhc->moist_rref == R_OFF)
|
if ((mbhc->moist_rref == R_OFF) ||
|
||||||
|
(mbhc->mbhc_cfg->enable_usbc_analog)) {
|
||||||
|
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
|
||||||
|
0x0C, R_OFF << 2);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Donot enable moisture detection if jack type is NC */
|
/* Donot enable moisture detection if jack type is NC */
|
||||||
if (!mbhc->hphl_swh) {
|
if (!mbhc->hphl_swh) {
|
||||||
dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
|
dev_dbg(codec->dev, "%s: disable moisture detection for NC\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2,
|
||||||
|
0x0C, R_OFF << 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue