From 20efdbc3105a97b7e487dcd48c4863b86c026ba9 Mon Sep 17 00:00:00 2001 From: Ravi Vembu Date: Fri, 13 Jul 2018 16:25:14 -0500 Subject: [PATCH] extcon-madera: Handle USBC Audio Connections Add support for detecting USBC Audio adapters Change-Id: Iaf632b4171b98f7c014a7c11e22720929a1a1216 Signed-off-by: Ravi Vembu Mot-CRs-Fixed: (CR) Change-Id: Iaf632b4171b98f7c014a7c11e22720929a1a1216 Reviewed-on: https://gerrit.mot.com/1209639 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Rav(CR) Vembu Submit-Approved: Jira Key --- drivers/extcon/extcon-madera.c | 77 ++++++++++++++++++++++++++++ include/linux/extcon/extcon-madera.h | 5 ++ 2 files changed, 82 insertions(+) diff --git a/drivers/extcon/extcon-madera.c b/drivers/extcon/extcon-madera.c index 90c4339c2ba8..f123c4bda479 100644 --- a/drivers/extcon/extcon-madera.c +++ b/drivers/extcon/extcon-madera.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2365,6 +2366,51 @@ static void madera_extcon_get_hpd_pins(struct madera_extcon *info, pdata->hpd_pins[i] = madera_default_hpd_pins[i]; } +static bool madera_extcon_usbc_audio_connected(struct madera_extcon *info) +{ + union power_supply_propval prop = {0,}; + int ret; + + if (!info->usb_psy) + return false; + + ret = power_supply_get_property(info->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &prop); + if (ret < 0) + dev_err(info->dev, "Unable to get USB Type\n"); + return (prop.intval == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); +} + +static void madera_handle_usbc_audio(struct madera_extcon *info, bool connected) +{ + dev_err(info->dev, "Type-C Audio Adapter %sconnected\n", + connected ? "" : "dis"); + if (info->usbc_det_gpio[0] > 0 && info->usbc_det_gpio[1] > 0) { + gpiod_set_value(info->usbc_det_gpio[0], connected); + gpiod_set_value(info->usbc_det_gpio[1], connected); + } + + info->usbc_connected = connected; +} + +static int madera_psy_notifier(struct notifier_block *nb, unsigned long evt, void *ptr) +{ + struct madera_extcon *info = container_of(nb, struct madera_extcon, psy_nb); + struct power_supply *psy = ptr; + bool usbc_audio_connected = false; + + if (evt != PSY_EVENT_PROP_CHANGED || strcmp(psy->desc->name, "usb") || + (psy->desc->type != POWER_SUPPLY_TYPE_USB && + psy->desc->type != POWER_SUPPLY_TYPE_USB_PD)) + return 0; + + usbc_audio_connected = madera_extcon_usbc_audio_connected(info); + if (info->usbc_connected == usbc_audio_connected) + return NOTIFY_OK; + madera_handle_usbc_audio(info, usbc_audio_connected); + return NOTIFY_OK; +} + static void madera_extcon_process_accdet_node(struct madera_extcon *info, struct fwnode_handle *node) { @@ -2472,6 +2518,24 @@ static void madera_extcon_process_accdet_node(struct madera_extcon *info, node); if (IS_ERR(info->micd_pol_gpio[1])) info->micd_pol_gpio[1] = 0; + + info->usbc_headset_support = fwnode_property_present(node, + "cirrus,usbc-headset"); + if (info->usbc_headset_support) { + info->usbc_connected = false; + info->usbc_det_gpio[0] = devm_get_gpiod_from_child(madera->dev, + "cirrus,usbsel", + node); + if (IS_ERR(info->usbc_det_gpio[0])) + info->usbc_det_gpio[0] = 0; + + info->usbc_det_gpio[1] = devm_get_gpiod_from_child(madera->dev, + "cirrus,hsdet", + node); + if (IS_ERR(info->usbc_det_gpio[1])) + info->usbc_det_gpio[1] = 0; + + } } static int madera_extcon_get_device_pdata(struct madera_extcon *info) @@ -3145,6 +3209,13 @@ static int madera_extcon_probe(struct platform_device *pdev) madera_extcon_dump_config(info); + if (info->usbc_headset_support) { + info->psy_nb.notifier_call = madera_psy_notifier; + power_supply_reg_notifier(&info->psy_nb); + info->usb_psy = power_supply_get_by_name("usb"); + madera_handle_usbc_audio(info, madera_extcon_usbc_audio_connected(info)); + } + return 0; err_fall_wake: @@ -3177,6 +3248,12 @@ static int madera_extcon_remove(struct platform_device *pdev) regmap_update_bits(madera->regmap, MADERA_MICD_CLAMP_CONTROL, MADERA_MICD_CLAMP_MODE_MASK, 0); + if (info->usbc_headset_support) { + power_supply_unreg_notifier(&info->psy_nb); + if (info->usb_psy) + power_supply_put(info->usb_psy); + } + if (info->pdata->jd_use_jd2) { jack_irq_rise = MADERA_IRQ_MICD_CLAMP_RISE; jack_irq_fall = MADERA_IRQ_MICD_CLAMP_FALL; diff --git a/include/linux/extcon/extcon-madera.h b/include/linux/extcon/extcon-madera.h index ecf07bca8c76..2e892ca7cc87 100644 --- a/include/linux/extcon/extcon-madera.h +++ b/include/linux/extcon/extcon-madera.h @@ -71,6 +71,7 @@ struct madera_extcon { struct input_dev *input; struct extcon_dev *edev; struct gpio_desc *micd_pol_gpio[2]; + struct gpio_desc *usbc_det_gpio[2]; u16 last_jackdet; int hp_tuning_level; @@ -104,6 +105,10 @@ struct madera_extcon { struct delayed_work state_timeout_work; struct madera_micd_bias micd_bias; + bool usbc_headset_support; + bool usbc_connected; + struct notifier_block psy_nb; + struct power_supply *usb_psy; }; enum madera_accdet_mode {