From 3137301b6d970219706d887eb6bdcabbf54f1f3b Mon Sep 17 00:00:00 2001 From: Yauhen Kharuzhy Date: Sun, 3 Mar 2019 23:16:12 +0300 Subject: [PATCH 1/7] extcon: intel-cht-wc: Make charger detection co-existed with OTG host mode Whiskey Cove Cherry Trail PMIC requires disabling OTG host mode before of charger detection procedure. Do this by manipulationg of CHGRCTRL1 register. Source: APCI DSDT code of Lenovo Yoga Book YB1-X91L and open-sourced Intel's drivers. Signed-off-by: Yauhen Kharuzhy Reviewed-by: Andy Shevchenko Reviewed-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 5ef215297101..8d20e913536f 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -29,7 +29,15 @@ #define CHT_WC_CHGRCTRL0_DBPOFF BIT(6) #define CHT_WC_CHGRCTRL0_CHR_WDT_NOKICK BIT(7) -#define CHT_WC_CHGRCTRL1 0x5e17 +#define CHT_WC_CHGRCTRL1 0x5e17 +#define CHT_WC_CHGRCTRL1_FUSB_INLMT_100 BIT(0) +#define CHT_WC_CHGRCTRL1_FUSB_INLMT_150 BIT(1) +#define CHT_WC_CHGRCTRL1_FUSB_INLMT_500 BIT(2) +#define CHT_WC_CHGRCTRL1_FUSB_INLMT_900 BIT(3) +#define CHT_WC_CHGRCTRL1_FUSB_INLMT_1500 BIT(4) +#define CHT_WC_CHGRCTRL1_FTEMP_EVENT BIT(5) +#define CHT_WC_CHGRCTRL1_OTGMODE BIT(6) +#define CHT_WC_CHGRCTRL1_DBPEN BIT(7) #define CHT_WC_USBSRC 0x5e29 #define CHT_WC_USBSRC_STS_MASK GENMASK(1, 0) @@ -198,6 +206,18 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); } +static void cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext, + bool enable) +{ + unsigned int val = enable ? CHT_WC_CHGRCTRL1_OTGMODE : 0; + int ret; + + ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL1, + CHT_WC_CHGRCTRL1_OTGMODE, val); + if (ret) + dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret); +} + /* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */ static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext, unsigned int cable, bool state) @@ -222,10 +242,14 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) id = cht_wc_extcon_get_id(ext, pwrsrc_sts); if (id == USB_ID_GND) { + cht_wc_extcon_set_otgmode(ext, true); + /* The 5v boost causes a false VBUS / SDP detect, skip */ goto charger_det_done; } + cht_wc_extcon_set_otgmode(ext, false); + /* Plugged into a host/charger or not connected? */ if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) { /* Route D+ and D- to PMIC for future charger detection */ From a72a1be0de71b3bdab3d8b2e708267f32ea33ee2 Mon Sep 17 00:00:00 2001 From: Yauhen Kharuzhy Date: Sun, 3 Mar 2019 23:16:13 +0300 Subject: [PATCH 2/7] extcon: intel-cht-wc: Enable external charger In some configuration external charger "#charge enable" signal is connected to PMIC. Enable it at device probing to allow charging. Save CHGRCTRL0 and CHGDISCTR registers at driver probing and restore them at driver unbind to re-enable hardware charging control if it was enabled before. Tested at Lenovo Yoga Book (YB1-X91L). Signed-off-by: Yauhen Kharuzhy Reviewed-by: Andy Shevchenko Reviewed-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 8d20e913536f..53b28ecc4ad1 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -56,6 +56,13 @@ #define CHT_WC_USBSRC_TYPE_OTHER 8 #define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9 +#define CHT_WC_CHGDISCTRL 0x5e2f +#define CHT_WC_CHGDISCTRL_OUT BIT(0) +/* 0 - open drain, 1 - regular push-pull output */ +#define CHT_WC_CHGDISCTRL_DRV BIT(4) +/* 0 - pin is controlled by SW, 1 - by HW */ +#define CHT_WC_CHGDISCTRL_FN BIT(6) + #define CHT_WC_PWRSRC_IRQ 0x6e03 #define CHT_WC_PWRSRC_IRQ_MASK 0x6e0f #define CHT_WC_PWRSRC_STS 0x6e1e @@ -218,6 +225,18 @@ static void cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext, dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret); } +static void cht_wc_extcon_enable_charging(struct cht_wc_extcon_data *ext, + bool enable) +{ + unsigned int val = enable ? 0 : CHT_WC_CHGDISCTRL_OUT; + int ret; + + ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, + CHT_WC_CHGDISCTRL_OUT, val); + if (ret) + dev_err(ext->dev, "Error updating CHGDISCTRL reg: %d\n", ret); +} + /* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */ static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext, unsigned int cable, bool state) @@ -242,6 +261,7 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) id = cht_wc_extcon_get_id(ext, pwrsrc_sts); if (id == USB_ID_GND) { + cht_wc_extcon_enable_charging(ext, false); cht_wc_extcon_set_otgmode(ext, true); /* The 5v boost causes a false VBUS / SDP detect, skip */ @@ -249,6 +269,7 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) } cht_wc_extcon_set_otgmode(ext, false); + cht_wc_extcon_enable_charging(ext, true); /* Plugged into a host/charger or not connected? */ if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) { @@ -302,6 +323,14 @@ static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable) { int ret, mask, val; + val = enable ? 0 : CHT_WC_CHGDISCTRL_FN; + ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, + CHT_WC_CHGDISCTRL_FN, val); + if (ret) + dev_err(ext->dev, + "Error setting sw control for CHGDIS pin: %d\n", + ret); + mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF; val = enable ? mask : 0; ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); @@ -353,7 +382,10 @@ static int cht_wc_extcon_probe(struct platform_device *pdev) /* Enable sw control */ ret = cht_wc_extcon_sw_control(ext, true); if (ret) - return ret; + goto disable_sw_control; + + /* Disable charging by external battery charger */ + cht_wc_extcon_enable_charging(ext, false); /* Register extcon device */ ret = devm_extcon_dev_register(ext->dev, ext->edev); From db8b4aefd17b1ccf108d81a4fbb181c8e50abf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdis=20Kl=C4=93tnieks?= Date: Tue, 12 Mar 2019 06:42:31 -0400 Subject: [PATCH 3/7] extcon: Fix build warning for extcon_unregister_notifier comment Give the line the asterisk it wanted to fix the build warning. [Build warning message] Building with W=1 reports: CC drivers/extcon/devres.o drivers/extcon/devres.c:208: warning: bad line: - Resource-managed extcon_unregister_notifier() Signed-off-by: Valdis Kletnieks [cw00.choi: Edit the patch subject and description] Signed-off-by: Chanwoo Choi --- drivers/extcon/devres.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c index f599aeddf8e5..f487d877ab5d 100644 --- a/drivers/extcon/devres.c +++ b/drivers/extcon/devres.c @@ -205,7 +205,7 @@ EXPORT_SYMBOL(devm_extcon_register_notifier); /** * devm_extcon_unregister_notifier() - - Resource-managed extcon_unregister_notifier() + * - Resource-managed extcon_unregister_notifier() * @dev: the device owning the extcon device being created * @edev: the extcon device * @id: the unique id among the extcon enumeration From 098b7ae8ec431465b319e2157f848df50dc6b7e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Mar 2019 16:30:41 +0200 Subject: [PATCH 4/7] extcon: intel: Split out some definitions to a common header We are going to use some definitions in the other Intel extcon drivers, thus, split out them to a common header file. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 21 +++++++-------------- drivers/extcon/extcon-intel.h | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 drivers/extcon/extcon-intel.h diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 53b28ecc4ad1..9d32150e68db 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -17,6 +17,8 @@ #include #include +#include "extcon-intel.h" + #define CHT_WC_PHYCTRL 0x5e07 #define CHT_WC_CHGRCTRL0 0x5e16 @@ -80,15 +82,6 @@ #define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4) #define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5) -enum cht_wc_usb_id { - USB_ID_OTG, - USB_ID_GND, - USB_ID_FLOAT, - USB_RID_A, - USB_RID_B, - USB_RID_C, -}; - enum cht_wc_mux_select { MUX_SEL_PMIC = 0, MUX_SEL_SOC, @@ -116,9 +109,9 @@ static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts) { switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) { case CHT_WC_PWRSRC_RID_GND: - return USB_ID_GND; + return INTEL_USB_ID_GND; case CHT_WC_PWRSRC_RID_FLOAT: - return USB_ID_FLOAT; + return INTEL_USB_ID_FLOAT; case CHT_WC_PWRSRC_RID_ACA: default: /* @@ -126,7 +119,7 @@ static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts) * the USBID GPADC channel here and determine ACA role * based on that. */ - return USB_ID_FLOAT; + return INTEL_USB_ID_FLOAT; } } @@ -260,7 +253,7 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) } id = cht_wc_extcon_get_id(ext, pwrsrc_sts); - if (id == USB_ID_GND) { + if (id == INTEL_USB_ID_GND) { cht_wc_extcon_enable_charging(ext, false); cht_wc_extcon_set_otgmode(ext, true); @@ -293,7 +286,7 @@ set_state: ext->previous_cable = cable; } - ext->usb_host = ((id == USB_ID_GND) || (id == USB_RID_A)); + ext->usb_host = ((id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A)); extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host); } diff --git a/drivers/extcon/extcon-intel.h b/drivers/extcon/extcon-intel.h new file mode 100644 index 000000000000..0ad645ec7b33 --- /dev/null +++ b/drivers/extcon/extcon-intel.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for Intel extcon hardware + * + * Copyright (C) 2019 Intel Corporation. All rights reserved. + */ + +#ifndef __EXTCON_INTEL_H__ +#define __EXTCON_INTEL_H__ + +enum extcon_intel_usb_id { + INTEL_USB_ID_OTG, + INTEL_USB_ID_GND, + INTEL_USB_ID_FLOAT, + INTEL_USB_RID_A, + INTEL_USB_RID_B, + INTEL_USB_RID_C, +}; + +#endif /* __EXTCON_INTEL_H__ */ From 492929c547913f77460c20be994482d57bc74840 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Mar 2019 16:30:42 +0200 Subject: [PATCH 5/7] extcon: mrfld: Introduce extcon driver for Basin Cove PMIC On Intel Merrifield the Basin Cove PMIC provides a feature to detect the USB connection type. This driver utilizes the feature in order to support the USB dual role detection. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/Kconfig | 7 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-intel-mrfld.c | 284 ++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 drivers/extcon/extcon-intel-mrfld.c diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 540e8cd16ee6..1ed4b45536c7 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -60,6 +60,13 @@ config EXTCON_INTEL_CHT_WC Say Y here to enable extcon support for charger detection / control on the Intel Cherrytrail Whiskey Cove PMIC. +config EXTCON_INTEL_MRFLD + tristate "Intel Merrifield Basin Cove PMIC extcon driver" + depends on INTEL_SOC_PMIC_MRFLD + help + Say Y here to enable extcon support for charger detection / control + on the Intel Merrifield Basin Cove PMIC. + config EXTCON_MAX14577 tristate "Maxim MAX14577/77836 EXTCON Support" depends on MFD_MAX14577 diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 261ce4cfe209..d3941a735df3 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o obj-$(CONFIG_EXTCON_INTEL_CHT_WC) += extcon-intel-cht-wc.o +obj-$(CONFIG_EXTCON_INTEL_MRFLD) += extcon-intel-mrfld.o obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o diff --git a/drivers/extcon/extcon-intel-mrfld.c b/drivers/extcon/extcon-intel-mrfld.c new file mode 100644 index 000000000000..f47016fb28a8 --- /dev/null +++ b/drivers/extcon/extcon-intel-mrfld.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * extcon driver for Basin Cove PMIC + * + * Copyright (c) 2019, Intel Corporation. + * Author: Andy Shevchenko + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extcon-intel.h" + +#define BCOVE_USBIDCTRL 0x19 +#define BCOVE_USBIDCTRL_ID BIT(0) +#define BCOVE_USBIDCTRL_ACA BIT(1) +#define BCOVE_USBIDCTRL_ALL (BCOVE_USBIDCTRL_ID | BCOVE_USBIDCTRL_ACA) + +#define BCOVE_USBIDSTS 0x1a +#define BCOVE_USBIDSTS_GND BIT(0) +#define BCOVE_USBIDSTS_RARBRC_MASK GENMASK(2, 1) +#define BCOVE_USBIDSTS_RARBRC_SHIFT 1 +#define BCOVE_USBIDSTS_NO_ACA 0 +#define BCOVE_USBIDSTS_R_ID_A 1 +#define BCOVE_USBIDSTS_R_ID_B 2 +#define BCOVE_USBIDSTS_R_ID_C 3 +#define BCOVE_USBIDSTS_FLOAT BIT(3) +#define BCOVE_USBIDSTS_SHORT BIT(4) + +#define BCOVE_CHGRIRQ_ALL (BCOVE_CHGRIRQ_VBUSDET | BCOVE_CHGRIRQ_DCDET | \ + BCOVE_CHGRIRQ_BATTDET | BCOVE_CHGRIRQ_USBIDDET) + +#define BCOVE_CHGRCTRL0 0x4b +#define BCOVE_CHGRCTRL0_CHGRRESET BIT(0) +#define BCOVE_CHGRCTRL0_EMRGCHREN BIT(1) +#define BCOVE_CHGRCTRL0_EXTCHRDIS BIT(2) +#define BCOVE_CHGRCTRL0_SWCONTROL BIT(3) +#define BCOVE_CHGRCTRL0_TTLCK BIT(4) +#define BCOVE_CHGRCTRL0_BIT_5 BIT(5) +#define BCOVE_CHGRCTRL0_BIT_6 BIT(6) +#define BCOVE_CHGRCTRL0_CHR_WDT_NOKICK BIT(7) + +struct mrfld_extcon_data { + struct device *dev; + struct regmap *regmap; + struct extcon_dev *edev; + unsigned int status; + unsigned int id; +}; + +static const unsigned int mrfld_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_CHG_USB_SDP, + EXTCON_CHG_USB_CDP, + EXTCON_CHG_USB_DCP, + EXTCON_CHG_USB_ACA, + EXTCON_NONE, +}; + +static int mrfld_extcon_clear(struct mrfld_extcon_data *data, unsigned int reg, + unsigned int mask) +{ + return regmap_update_bits(data->regmap, reg, mask, 0x00); +} + +static int mrfld_extcon_set(struct mrfld_extcon_data *data, unsigned int reg, + unsigned int mask) +{ + return regmap_update_bits(data->regmap, reg, mask, 0xff); +} + +static int mrfld_extcon_sw_control(struct mrfld_extcon_data *data, bool enable) +{ + unsigned int mask = BCOVE_CHGRCTRL0_SWCONTROL; + struct device *dev = data->dev; + int ret; + + if (enable) + ret = mrfld_extcon_set(data, BCOVE_CHGRCTRL0, mask); + else + ret = mrfld_extcon_clear(data, BCOVE_CHGRCTRL0, mask); + if (ret) + dev_err(dev, "can't set SW control: %d\n", ret); + return ret; +} + +static int mrfld_extcon_get_id(struct mrfld_extcon_data *data) +{ + struct regmap *regmap = data->regmap; + unsigned int id; + bool ground; + int ret; + + ret = regmap_read(regmap, BCOVE_USBIDSTS, &id); + if (ret) + return ret; + + if (id & BCOVE_USBIDSTS_FLOAT) + return INTEL_USB_ID_FLOAT; + + switch ((id & BCOVE_USBIDSTS_RARBRC_MASK) >> BCOVE_USBIDSTS_RARBRC_SHIFT) { + case BCOVE_USBIDSTS_R_ID_A: + return INTEL_USB_RID_A; + case BCOVE_USBIDSTS_R_ID_B: + return INTEL_USB_RID_B; + case BCOVE_USBIDSTS_R_ID_C: + return INTEL_USB_RID_C; + } + + /* + * PMIC A0 reports USBIDSTS_GND = 1 for ID_GND, + * but PMIC B0 reports USBIDSTS_GND = 0 for ID_GND. + * Thus we must check this bit at last. + */ + ground = id & BCOVE_USBIDSTS_GND; + switch ('A' + BCOVE_MAJOR(data->id)) { + case 'A': + return ground ? INTEL_USB_ID_GND : INTEL_USB_ID_FLOAT; + case 'B': + return ground ? INTEL_USB_ID_FLOAT : INTEL_USB_ID_GND; + } + + /* Unknown or unsupported type */ + return INTEL_USB_ID_FLOAT; +} + +static int mrfld_extcon_role_detect(struct mrfld_extcon_data *data) +{ + unsigned int id; + bool usb_host; + int ret; + + ret = mrfld_extcon_get_id(data); + if (ret < 0) + return ret; + + id = ret; + + usb_host = (id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A); + extcon_set_state_sync(data->edev, EXTCON_USB_HOST, usb_host); + + return 0; +} + +static int mrfld_extcon_cable_detect(struct mrfld_extcon_data *data) +{ + struct regmap *regmap = data->regmap; + unsigned int status, change; + int ret; + + /* + * It seems SCU firmware clears the content of BCOVE_CHGRIRQ1 + * and makes it useless for OS. Instead we compare a previously + * stored status to the current one, provided by BCOVE_SCHGRIRQ1. + */ + ret = regmap_read(regmap, BCOVE_SCHGRIRQ1, &status); + if (ret) + return ret; + + change = status ^ data->status; + if (!change) + return -ENODATA; + + if (change & BCOVE_CHGRIRQ_USBIDDET) { + ret = mrfld_extcon_role_detect(data); + if (ret) + return ret; + } + + data->status = status; + + return 0; +} + +static irqreturn_t mrfld_extcon_interrupt(int irq, void *dev_id) +{ + struct mrfld_extcon_data *data = dev_id; + int ret; + + ret = mrfld_extcon_cable_detect(data); + + mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR); + + return ret ? IRQ_NONE: IRQ_HANDLED; +} + +static int mrfld_extcon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); + struct regmap *regmap = pmic->regmap; + struct mrfld_extcon_data *data; + unsigned int id; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + data->regmap = regmap; + + data->edev = devm_extcon_dev_allocate(dev, mrfld_extcon_cable); + if (IS_ERR(data->edev)) + return -ENOMEM; + + ret = devm_extcon_dev_register(dev, data->edev); + if (ret < 0) { + dev_err(dev, "can't register extcon device: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_extcon_interrupt, + IRQF_ONESHOT | IRQF_SHARED, pdev->name, + data); + if (ret) { + dev_err(dev, "can't register IRQ handler: %d\n", ret); + return ret; + } + + ret = regmap_read(regmap, BCOVE_ID, &id); + if (ret) { + dev_err(dev, "can't read PMIC ID: %d\n", ret); + return ret; + } + + data->id = id; + + ret = mrfld_extcon_sw_control(data, true); + if (ret) + return ret; + + /* Get initial state */ + mrfld_extcon_role_detect(data); + + mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR); + mrfld_extcon_clear(data, BCOVE_MCHGRIRQ1, BCOVE_CHGRIRQ_ALL); + + mrfld_extcon_set(data, BCOVE_USBIDCTRL, BCOVE_USBIDCTRL_ALL); + + platform_set_drvdata(pdev, data); + + return 0; +} + +static int mrfld_extcon_remove(struct platform_device *pdev) +{ + struct mrfld_extcon_data *data = platform_get_drvdata(pdev); + + mrfld_extcon_sw_control(data, false); + + return 0; +} + +static const struct platform_device_id mrfld_extcon_id_table[] = { + { .name = "mrfld_bcove_pwrsrc" }, + {} +}; +MODULE_DEVICE_TABLE(platform, mrfld_extcon_id_table); + +static struct platform_driver mrfld_extcon_driver = { + .driver = { + .name = "mrfld_bcove_pwrsrc", + }, + .probe = mrfld_extcon_probe, + .remove = mrfld_extcon_remove, + .id_table = mrfld_extcon_id_table, +}; +module_platform_driver(mrfld_extcon_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_DESCRIPTION("extcon driver for Intel Merrifield Basin Cove PMIC"); +MODULE_LICENSE("GPL v2"); From fa3c098c2d52a268f6372fa053932e11f50cecb1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 4 Apr 2019 22:17:48 +0800 Subject: [PATCH 6/7] extcon: axp288: Add a depends on ACPI to the Kconfig entry As Hans de Goede pointed, using this driver without ACPI makes little sense, so add ACPI dependency to Kconfig entry to fix a build error while CONFIG_ACPI is not set. drivers/extcon/extcon-axp288.c: In function 'axp288_extcon_probe': drivers/extcon/extcon-axp288.c:363:20: error: dereferencing pointer to incomplete type put_device(&adev->dev); Fixes: 0cf064db948a ("extcon: axp288: Convert to use acpi_dev_get_first_match_dev()") Reported-by: Hulk Robot Suggested-by: Hans de Goede Signed-off-by: YueHaibing Reviewed-by: Hans de Goede Reviewed-by: Mukesh Ojha Signed-off-by: Chanwoo Choi --- drivers/extcon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 1ed4b45536c7..de06fafb52ff 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -30,7 +30,7 @@ config EXTCON_ARIZONA config EXTCON_AXP288 tristate "X-Power AXP288 EXTCON support" - depends on MFD_AXP20X && USB_SUPPORT && X86 + depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI select USB_ROLE_SWITCH help Say Y here to enable support for USB peripheral detection From 00053de52231117ddc154042549f2256183ffb86 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Apr 2019 17:33:56 +0100 Subject: [PATCH 7/7] extcon: arizona: Disable mic detect if running when driver is removed Microphone detection provides the button detection features on the Arizona CODECs as such it will be running if the jack is currently inserted. If the driver is unbound whilst the jack is still inserted this will cause warnings from the regulator framework as the MICVDD regulator is put but was never disabled. Correct this by disabling microphone detection on driver removal and if the microphone detection was running disable the regulator and put the runtime reference that was currently held. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index da0e9bc4262f..9327479c719c 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1726,6 +1726,16 @@ static int arizona_extcon_remove(struct platform_device *pdev) struct arizona_extcon_info *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; int jack_irq_rise, jack_irq_fall; + bool change; + + regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, + ARIZONA_MICD_ENA, 0, + &change); + + if (change) { + regulator_disable(info->micvdd); + pm_runtime_put(info->dev); + } gpiod_put(info->micd_pol_gpio);