aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/phy/phy-msm-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/phy/phy-msm-usb.c')
-rw-r--r--drivers/usb/phy/phy-msm-usb.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index c9156beeadef..00c49bb1bd29 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -240,8 +240,14 @@ static void ulpi_init(struct msm_otg *motg)
240static int msm_phy_notify_disconnect(struct usb_phy *phy, 240static int msm_phy_notify_disconnect(struct usb_phy *phy,
241 enum usb_device_speed speed) 241 enum usb_device_speed speed)
242{ 242{
243 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
243 int val; 244 int val;
244 245
246 if (motg->manual_pullup) {
247 val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
248 usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
249 }
250
245 /* 251 /*
246 * Put the transceiver in non-driving mode. Otherwise host 252 * Put the transceiver in non-driving mode. Otherwise host
247 * may not detect soft-disconnection. 253 * may not detect soft-disconnection.
@@ -422,6 +428,24 @@ static int msm_phy_init(struct usb_phy *phy)
422 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL); 428 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
423 } 429 }
424 430
431 if (motg->manual_pullup) {
432 val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
433 ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
434
435 val = readl(USB_GENCONFIG_2);
436 val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
437 writel(val, USB_GENCONFIG_2);
438
439 val = readl(USB_USBCMD);
440 val |= USBCMD_SESS_VLD_CTRL;
441 writel(val, USB_USBCMD);
442
443 val = ulpi_read(phy, ULPI_FUNC_CTRL);
444 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
445 val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
446 ulpi_write(phy, val, ULPI_FUNC_CTRL);
447 }
448
425 if (motg->phy_number) 449 if (motg->phy_number)
426 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); 450 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
427 451
@@ -1436,9 +1460,42 @@ static const struct of_device_id msm_otg_dt_match[] = {
1436}; 1460};
1437MODULE_DEVICE_TABLE(of, msm_otg_dt_match); 1461MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1438 1462
1463static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
1464 void *ptr)
1465{
1466 struct msm_usb_cable *vbus = container_of(nb, struct msm_usb_cable, nb);
1467 struct msm_otg *motg = container_of(vbus, struct msm_otg, vbus);
1468
1469 if (event)
1470 set_bit(B_SESS_VLD, &motg->inputs);
1471 else
1472 clear_bit(B_SESS_VLD, &motg->inputs);
1473
1474 schedule_work(&motg->sm_work);
1475
1476 return NOTIFY_DONE;
1477}
1478
1479static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
1480 void *ptr)
1481{
1482 struct msm_usb_cable *id = container_of(nb, struct msm_usb_cable, nb);
1483 struct msm_otg *motg = container_of(id, struct msm_otg, id);
1484
1485 if (event)
1486 clear_bit(ID, &motg->inputs);
1487 else
1488 set_bit(ID, &motg->inputs);
1489
1490 schedule_work(&motg->sm_work);
1491
1492 return NOTIFY_DONE;
1493}
1494
1439static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) 1495static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1440{ 1496{
1441 struct msm_otg_platform_data *pdata; 1497 struct msm_otg_platform_data *pdata;
1498 struct extcon_dev *ext_id, *ext_vbus;
1442 const struct of_device_id *id; 1499 const struct of_device_id *id;
1443 struct device_node *node = pdev->dev.of_node; 1500 struct device_node *node = pdev->dev.of_node;
1444 struct property *prop; 1501 struct property *prop;
@@ -1487,6 +1544,54 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1487 motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX]; 1544 motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
1488 } 1545 }
1489 1546
1547 motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
1548
1549 ext_id = ERR_PTR(-ENODEV);
1550 ext_vbus = ERR_PTR(-ENODEV);
1551 if (of_property_read_bool(node, "extcon")) {
1552
1553 /* Each one of them is not mandatory */
1554 ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0);
1555 if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
1556 return PTR_ERR(ext_vbus);
1557
1558 ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1);
1559 if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
1560 return PTR_ERR(ext_id);
1561 }
1562
1563 if (!IS_ERR(ext_vbus)) {
1564 motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
1565 ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name,
1566 "USB", &motg->vbus.nb);
1567 if (ret < 0) {
1568 dev_err(&pdev->dev, "register VBUS notifier failed\n");
1569 return ret;
1570 }
1571
1572 ret = extcon_get_cable_state(ext_vbus, "USB");
1573 if (ret)
1574 set_bit(B_SESS_VLD, &motg->inputs);
1575 else
1576 clear_bit(B_SESS_VLD, &motg->inputs);
1577 }
1578
1579 if (!IS_ERR(ext_id)) {
1580 motg->id.nb.notifier_call = msm_otg_id_notifier;
1581 ret = extcon_register_interest(&motg->id.conn, ext_id->name,
1582 "USB-HOST", &motg->id.nb);
1583 if (ret < 0) {
1584 dev_err(&pdev->dev, "register ID notifier failed\n");
1585 return ret;
1586 }
1587
1588 ret = extcon_get_cable_state(ext_id, "USB-HOST");
1589 if (ret)
1590 clear_bit(ID, &motg->inputs);
1591 else
1592 set_bit(ID, &motg->inputs);
1593 }
1594
1490 prop = of_find_property(node, "qcom,phy-init-sequence", &len); 1595 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1491 if (!prop || !len) 1596 if (!prop || !len)
1492 return 0; 1597 return 0;
@@ -1700,6 +1805,11 @@ static int msm_otg_remove(struct platform_device *pdev)
1700 if (phy->otg->host || phy->otg->gadget) 1805 if (phy->otg->host || phy->otg->gadget)
1701 return -EBUSY; 1806 return -EBUSY;
1702 1807
1808 if (motg->id.conn.edev)
1809 extcon_unregister_interest(&motg->id.conn);
1810 if (motg->vbus.conn.edev)
1811 extcon_unregister_interest(&motg->vbus.conn);
1812
1703 msm_otg_debugfs_cleanup(); 1813 msm_otg_debugfs_cleanup();
1704 cancel_delayed_work_sync(&motg->chg_work); 1814 cancel_delayed_work_sync(&motg->chg_work);
1705 cancel_work_sync(&motg->sm_work); 1815 cancel_work_sync(&motg->sm_work);