diff options
-rw-r--r-- | drivers/usb/chipidea/otg.c | 18 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg.h | 1 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.c | 30 | ||||
-rw-r--r-- | include/linux/usb/chipidea.h | 5 |
4 files changed, 51 insertions, 3 deletions
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 49b4e2513445..bdf3f41b6cc2 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c | |||
@@ -39,6 +39,24 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) | |||
39 | return role; | 39 | return role; |
40 | } | 40 | } |
41 | 41 | ||
42 | void ci_handle_vbus_connected(struct ci_hdrc *ci) | ||
43 | { | ||
44 | u32 otgsc; | ||
45 | |||
46 | /* | ||
47 | * TODO: if the platform does not supply 5v to udc, or use other way | ||
48 | * to supply 5v, it needs to use other conditions to call | ||
49 | * usb_gadget_vbus_connect. | ||
50 | */ | ||
51 | if (!ci->is_otg) | ||
52 | return; | ||
53 | |||
54 | otgsc = hw_read(ci, OP_OTGSC, ~0); | ||
55 | |||
56 | if (otgsc & OTGSC_BSV) | ||
57 | usb_gadget_vbus_connect(&ci->gadget); | ||
58 | } | ||
59 | |||
42 | void ci_handle_vbus_change(struct ci_hdrc *ci) | 60 | void ci_handle_vbus_change(struct ci_hdrc *ci) |
43 | { | 61 | { |
44 | u32 otgsc; | 62 | u32 otgsc; |
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 2d9f090733bc..f171e6b9b6ba 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h | |||
@@ -31,5 +31,6 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci); | |||
31 | void ci_hdrc_otg_destroy(struct ci_hdrc *ci); | 31 | void ci_hdrc_otg_destroy(struct ci_hdrc *ci); |
32 | enum ci_role ci_otg_role(struct ci_hdrc *ci); | 32 | enum ci_role ci_otg_role(struct ci_hdrc *ci); |
33 | void ci_handle_vbus_change(struct ci_hdrc *ci); | 33 | void ci_handle_vbus_change(struct ci_hdrc *ci); |
34 | void ci_handle_vbus_connected(struct ci_hdrc *ci); | ||
34 | 35 | ||
35 | #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ | 36 | #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ |
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b34c81969cba..2359ce526ef0 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
@@ -1448,6 +1448,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) | |||
1448 | struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); | 1448 | struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); |
1449 | unsigned long flags; | 1449 | unsigned long flags; |
1450 | int gadget_ready = 0; | 1450 | int gadget_ready = 0; |
1451 | int ret; | ||
1451 | 1452 | ||
1452 | spin_lock_irqsave(&ci->lock, flags); | 1453 | spin_lock_irqsave(&ci->lock, flags); |
1453 | ci->vbus_active = is_active; | 1454 | ci->vbus_active = is_active; |
@@ -1455,6 +1456,31 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) | |||
1455 | gadget_ready = 1; | 1456 | gadget_ready = 1; |
1456 | spin_unlock_irqrestore(&ci->lock, flags); | 1457 | spin_unlock_irqrestore(&ci->lock, flags); |
1457 | 1458 | ||
1459 | /* Charger Detection */ | ||
1460 | if (ci->platdata->notify_event) { | ||
1461 | /* | ||
1462 | * Keep controller active when the cable is connected, | ||
1463 | * It can make disconnect interrupt (BSV 1->0) occur when | ||
1464 | * the cable is disconnected. | ||
1465 | */ | ||
1466 | if (is_active) | ||
1467 | pm_runtime_get_sync(&_gadget->dev); | ||
1468 | else | ||
1469 | pm_runtime_put_sync(&_gadget->dev); | ||
1470 | |||
1471 | ret = ci->platdata->notify_event | ||
1472 | (ci, CI_HDRC_CONTROLLER_CHARGER_EVENT); | ||
1473 | if (ret == CI_HDRC_NOTIFY_RET_DEFER_EVENT) { | ||
1474 | hw_device_reset(ci, USBMODE_CM_DC); | ||
1475 | /* Pull up dp */ | ||
1476 | hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); | ||
1477 | ci->platdata->notify_event | ||
1478 | (ci, CI_HDRC_CONTROLLER_CHARGER_POST_EVENT); | ||
1479 | /* Pull down dp */ | ||
1480 | hw_write(ci, OP_USBCMD, USBCMD_RS, 0); | ||
1481 | } | ||
1482 | } | ||
1483 | |||
1458 | if (gadget_ready) { | 1484 | if (gadget_ready) { |
1459 | if (is_active) { | 1485 | if (is_active) { |
1460 | pm_runtime_get_sync(&_gadget->dev); | 1486 | pm_runtime_get_sync(&_gadget->dev); |
@@ -1795,8 +1821,8 @@ static int udc_start(struct ci_hdrc *ci) | |||
1795 | pm_runtime_no_callbacks(&ci->gadget.dev); | 1821 | pm_runtime_no_callbacks(&ci->gadget.dev); |
1796 | pm_runtime_enable(&ci->gadget.dev); | 1822 | pm_runtime_enable(&ci->gadget.dev); |
1797 | 1823 | ||
1798 | /* Update ci->vbus_active */ | 1824 | /* Notify vbus connected event if it is existed */ |
1799 | ci_handle_vbus_change(ci); | 1825 | ci_handle_vbus_connected(ci); |
1800 | 1826 | ||
1801 | return retval; | 1827 | return retval; |
1802 | 1828 | ||
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 8c3b7e2ec5a1..c75433e763e7 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h | |||
@@ -30,7 +30,10 @@ struct ci_hdrc_platform_data { | |||
30 | enum usb_dr_mode dr_mode; | 30 | enum usb_dr_mode dr_mode; |
31 | #define CI_HDRC_CONTROLLER_RESET_EVENT 0 | 31 | #define CI_HDRC_CONTROLLER_RESET_EVENT 0 |
32 | #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 | 32 | #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 |
33 | void (*notify_event) (struct ci_hdrc *ci, unsigned event); | 33 | #define CI_HDRC_CONTROLLER_CHARGER_EVENT 2 |
34 | #define CI_HDRC_CONTROLLER_CHARGER_POST_EVENT 3 | ||
35 | int (*notify_event) (struct ci_hdrc *ci, unsigned event); | ||
36 | #define CI_HDRC_NOTIFY_RET_DEFER_EVENT 1 | ||
34 | struct regulator *reg_vbus; | 37 | struct regulator *reg_vbus; |
35 | }; | 38 | }; |
36 | 39 | ||