Skip to content

Commit 591fc11

Browse files
Ivan T. IvanovFelipe Balbi
Ivan T. Ivanov
authored and
Felipe Balbi
committed
usb: phy: msm: Use extcon framework for VBUS and ID detection
On recent Qualcomm platforms VBUS and ID lines are not routed to USB PHY LINK controller. Use extcon framework to receive connect and disconnect ID and VBUS notification. Signed-off-by: Ivan T. Ivanov <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent 5a294e5 commit 591fc11

File tree

4 files changed

+109
-0
lines changed

4 files changed

+109
-0
lines changed

Documentation/devicetree/bindings/usb/msm-hsusb.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ Optional properties:
6969
(no, min, max) where each value represents either a voltage
7070
in microvolts or a value corresponding to voltage corner.
7171

72+
- extcon: phandles to external connector devices. First phandle
73+
should point to external connector, which provide "USB"
74+
cable events, the second should point to external connector
75+
device, which provide "USB-HOST" cable events. If one of
76+
the external connector devices is not required empty <0>
77+
phandle should be specified.
78+
7279
Example HSUSB OTG controller device node:
7380

7481
usb@f9a55000 {

drivers/usb/phy/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ config USB_MSM_OTG
141141
tristate "Qualcomm on-chip USB OTG controller support"
142142
depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
143143
depends on RESET_CONTROLLER
144+
depends on EXTCON
144145
select USB_PHY
145146
help
146147
Enable this to support the USB OTG transceiver on Qualcomm chips. It

drivers/usb/phy/phy-msm-usb.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,9 +1436,42 @@ static const struct of_device_id msm_otg_dt_match[] = {
14361436
};
14371437
MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
14381438

1439+
static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
1440+
void *ptr)
1441+
{
1442+
struct msm_usb_cable *vbus = container_of(nb, struct msm_usb_cable, nb);
1443+
struct msm_otg *motg = container_of(vbus, struct msm_otg, vbus);
1444+
1445+
if (event)
1446+
set_bit(B_SESS_VLD, &motg->inputs);
1447+
else
1448+
clear_bit(B_SESS_VLD, &motg->inputs);
1449+
1450+
schedule_work(&motg->sm_work);
1451+
1452+
return NOTIFY_DONE;
1453+
}
1454+
1455+
static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
1456+
void *ptr)
1457+
{
1458+
struct msm_usb_cable *id = container_of(nb, struct msm_usb_cable, nb);
1459+
struct msm_otg *motg = container_of(id, struct msm_otg, id);
1460+
1461+
if (event)
1462+
clear_bit(ID, &motg->inputs);
1463+
else
1464+
set_bit(ID, &motg->inputs);
1465+
1466+
schedule_work(&motg->sm_work);
1467+
1468+
return NOTIFY_DONE;
1469+
}
1470+
14391471
static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
14401472
{
14411473
struct msm_otg_platform_data *pdata;
1474+
struct extcon_dev *ext_id, *ext_vbus;
14421475
const struct of_device_id *id;
14431476
struct device_node *node = pdev->dev.of_node;
14441477
struct property *prop;
@@ -1487,6 +1520,52 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
14871520
motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
14881521
}
14891522

1523+
ext_id = ERR_PTR(-ENODEV);
1524+
ext_vbus = ERR_PTR(-ENODEV);
1525+
if (of_property_read_bool(node, "extcon")) {
1526+
1527+
/* Each one of them is not mandatory */
1528+
ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0);
1529+
if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
1530+
return PTR_ERR(ext_vbus);
1531+
1532+
ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1);
1533+
if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
1534+
return PTR_ERR(ext_id);
1535+
}
1536+
1537+
if (!IS_ERR(ext_vbus)) {
1538+
motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
1539+
ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name,
1540+
"USB", &motg->vbus.nb);
1541+
if (ret < 0) {
1542+
dev_err(&pdev->dev, "register VBUS notifier failed\n");
1543+
return ret;
1544+
}
1545+
1546+
ret = extcon_get_cable_state(ext_vbus, "USB");
1547+
if (ret)
1548+
set_bit(B_SESS_VLD, &motg->inputs);
1549+
else
1550+
clear_bit(B_SESS_VLD, &motg->inputs);
1551+
}
1552+
1553+
if (!IS_ERR(ext_id)) {
1554+
motg->id.nb.notifier_call = msm_otg_id_notifier;
1555+
ret = extcon_register_interest(&motg->id.conn, ext_id->name,
1556+
"USB-HOST", &motg->id.nb);
1557+
if (ret < 0) {
1558+
dev_err(&pdev->dev, "register ID notifier failed\n");
1559+
return ret;
1560+
}
1561+
1562+
ret = extcon_get_cable_state(ext_id, "USB-HOST");
1563+
if (ret)
1564+
clear_bit(ID, &motg->inputs);
1565+
else
1566+
set_bit(ID, &motg->inputs);
1567+
}
1568+
14901569
prop = of_find_property(node, "qcom,phy-init-sequence", &len);
14911570
if (!prop || !len)
14921571
return 0;
@@ -1700,6 +1779,11 @@ static int msm_otg_remove(struct platform_device *pdev)
17001779
if (phy->otg->host || phy->otg->gadget)
17011780
return -EBUSY;
17021781

1782+
if (motg->id.conn.edev)
1783+
extcon_unregister_interest(&motg->id.conn);
1784+
if (motg->vbus.conn.edev)
1785+
extcon_unregister_interest(&motg->vbus.conn);
1786+
17031787
msm_otg_debugfs_cleanup();
17041788
cancel_delayed_work_sync(&motg->chg_work);
17051789
cancel_work_sync(&motg->sm_work);

include/linux/usb/msm_hsusb.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef __ASM_ARCH_MSM_HSUSB_H
1919
#define __ASM_ARCH_MSM_HSUSB_H
2020

21+
#include <linux/extcon.h>
2122
#include <linux/types.h>
2223
#include <linux/usb/otg.h>
2324
#include <linux/clk.h>
@@ -119,6 +120,17 @@ struct msm_otg_platform_data {
119120
void (*setup_gpio)(enum usb_otg_state state);
120121
};
121122

123+
/**
124+
* struct msm_usb_cable - structure for exteternal connector cable
125+
* state tracking
126+
* @nb: hold event notification callback
127+
* @conn: used for notification registration
128+
*/
129+
struct msm_usb_cable {
130+
struct notifier_block nb;
131+
struct extcon_specific_cable_nb conn;
132+
};
133+
122134
/**
123135
* struct msm_otg: OTG driver data. Shared by HCD and DCD.
124136
* @otg: USB OTG Transceiver structure.
@@ -138,6 +150,8 @@ struct msm_otg_platform_data {
138150
* @chg_type: The type of charger attached.
139151
* @dcd_retires: The retry count used to track Data contact
140152
* detection process.
153+
* @vbus: VBUS signal state trakining, using extcon framework
154+
* @id: ID signal state trakining, using extcon framework
141155
*/
142156
struct msm_otg {
143157
struct usb_phy phy;
@@ -166,6 +180,9 @@ struct msm_otg {
166180
struct reset_control *phy_rst;
167181
struct reset_control *link_rst;
168182
int vdd_levels[3];
183+
184+
struct msm_usb_cable vbus;
185+
struct msm_usb_cable id;
169186
};
170187

171188
#endif

0 commit comments

Comments
 (0)