BACKPORT: FROMGIT: usb: common: usb-conn-gpio: Prevent bailing out if initial role is none
Currently if we bootup a device without cable connected, then
usb-conn-gpio won't call set_role() because last_role is same
as current role. This happens since last_role gets initialised
to zero during the probe.
To avoid this, add a new flag initial_detection into struct
usb_conn_info, which prevents bailing out during initial
detection.
Cc: <stable@vger.kernel.org> # 5.4
Fixes: 4602f3bff2 ("usb: common: add USB GPIO based connection detection driver")
Signed-off-by: Prashanth K <quic_prashk@quicinc.com>
Tested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/1690880632-12588-1-git-send-email-quic_prashk@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
In-order to comply with KMI, added new struct usb_conn_info_vendor
to avoid modifying existing struct usb_conn_info.
Bug: 287406049
(cherry picked from commit 8e21a620c7e6e00347ade1a6ed4967b359eada5a
https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/ usb-linus)
Signed-off-by: Prashanth K <quic_prashk@quicinc.com>
Change-Id: Iace5bc9fd6a9a77fb45e4336ce7bba2ab009f9a7
This commit is contained in:
@@ -44,6 +44,16 @@ struct usb_conn_info {
|
||||
struct power_supply *charger;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb_conn_info_vendor - contains parameters without modifying the format of usb_conn_info
|
||||
* @info: contains usb_conn_info structure reference
|
||||
* initial_detection: bool to check if it's initial detection after probe
|
||||
*/
|
||||
struct usb_conn_info_vendor {
|
||||
struct usb_conn_info info;
|
||||
bool initial_detection;
|
||||
};
|
||||
|
||||
/*
|
||||
* "DEVICE" = VBUS and "HOST" = !ID, so we have:
|
||||
* Both "DEVICE" and "HOST" can't be set as active at the same time
|
||||
@@ -64,12 +74,15 @@ struct usb_conn_info {
|
||||
static void usb_conn_detect_cable(struct work_struct *work)
|
||||
{
|
||||
struct usb_conn_info *info;
|
||||
struct usb_conn_info_vendor *v_info;
|
||||
enum usb_role role;
|
||||
int id, vbus, ret;
|
||||
|
||||
info = container_of(to_delayed_work(work),
|
||||
struct usb_conn_info, dw_det);
|
||||
|
||||
v_info = container_of(info, struct usb_conn_info_vendor, info);
|
||||
|
||||
/* check ID and VBUS */
|
||||
id = info->id_gpiod ?
|
||||
gpiod_get_value_cansleep(info->id_gpiod) : 1;
|
||||
@@ -86,11 +99,13 @@ static void usb_conn_detect_cable(struct work_struct *work)
|
||||
dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
|
||||
usb_role_string(info->last_role), usb_role_string(role), id, vbus);
|
||||
|
||||
if (info->last_role == role) {
|
||||
if (!v_info->initial_detection && info->last_role == role) {
|
||||
dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
|
||||
return;
|
||||
}
|
||||
|
||||
v_info->initial_detection = false;
|
||||
|
||||
if (info->last_role == USB_ROLE_HOST && info->vbus)
|
||||
regulator_disable(info->vbus);
|
||||
|
||||
@@ -175,13 +190,15 @@ static int usb_conn_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usb_conn_info *info;
|
||||
struct usb_conn_info_vendor *v_info;
|
||||
bool need_vbus = true;
|
||||
int ret = 0;
|
||||
|
||||
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
v_info = devm_kzalloc(dev, sizeof(*v_info), GFP_KERNEL);
|
||||
if (!v_info)
|
||||
return -ENOMEM;
|
||||
|
||||
info = &v_info->info;
|
||||
info->dev = dev;
|
||||
info->id_gpiod = devm_gpiod_get_optional(dev, "id", GPIOD_IN);
|
||||
if (IS_ERR(info->id_gpiod))
|
||||
@@ -274,6 +291,7 @@ static int usb_conn_probe(struct platform_device *pdev)
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
|
||||
/* Perform initial detection */
|
||||
v_info->initial_detection = true;
|
||||
usb_conn_queue_dwork(info, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user