diff options
author | Li Jun <b47624@freescale.com> | 2015-01-09 15:35:07 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-11-25 15:56:29 +0800 |
commit | 5037438220f6b5ebfc4f127ba3bdfd4ce431f165 (patch) | |
tree | 52f1b204ced749e26272d614978ddaa2e518f007 | |
parent | 219d54332a09e8d8741c1e1982f5eae56099de85 (diff) |
MLK-10085-5 usb: chipidea: Add usb charger detect notify
- Change .notify's return value from void to int, update msm notify_event
return value accordingly.
- Add CI_HDRC_CONTROLLER_VBUS_EVENT and
CI_HDRC_CONTROLLER_CHARGER_POST_EVENT to finish the USB charger
detection flow.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Li Jun <jun.li@freescale.com>
(cherry picked from commit 681ca18061e334beb8a907d05e4405014f47dc07)
-rw-r--r-- | drivers/usb/chipidea/core.c | 8 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg.c | 16 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg.h | 3 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg_fsm.c | 6 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.c | 77 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.h | 13 | ||||
-rw-r--r-- | include/linux/usb/chipidea.h | 3 |
7 files changed, 96 insertions, 30 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 98ee575ee500..907c8daeadd6 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1143,11 +1143,11 @@ static int ci_hdrc_probe(struct platform_device *pdev) : CI_ROLE_GADGET; } - if (!ci_otg_is_fsm_mode(ci)) { - /* only update vbus status for peripheral */ - if (ci->role == CI_ROLE_GADGET) - ci_handle_vbus_change(ci); + /* only update vbus status for peripheral */ + if (ci->role == CI_ROLE_GADGET) + ci_handle_vbus_connected(ci); + if (!ci_otg_is_fsm_mode(ci)) { ret = ci_role_start(ci, ci->role); if (ret) { dev_err(dev, "can't start %s role\n", diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index fbfb02e05c97..3219cb8eead5 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -2,7 +2,7 @@ /* * otg.c - ChipIdea USB IP core OTG driver * - * Copyright (C) 2013 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. * * Author: Peter Chen */ @@ -126,6 +126,20 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } +void ci_handle_vbus_connected(struct ci_hdrc *ci) +{ + /* + * TODO: if the platform does not supply 5v to udc, or use other way + * to supply 5v, it needs to use other conditions to call + * usb_gadget_vbus_connect. + */ + if (!ci->is_otg) + return; + + if (hw_read_otgsc(ci, OTGSC_BSV)) + usb_gadget_vbus_connect(&ci->gadget); +} + void ci_handle_vbus_change(struct ci_hdrc *ci) { if (!ci->is_otg) diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 4f8b8179ec96..66f7b9a9bc5a 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. * * Author: Peter Chen */ @@ -14,6 +14,7 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci); void ci_hdrc_otg_destroy(struct ci_hdrc *ci); enum ci_role ci_otg_role(struct ci_hdrc *ci); void ci_handle_vbus_change(struct ci_hdrc *ci); +void ci_handle_vbus_connected(struct ci_hdrc *ci); static inline void ci_otg_queue_work(struct ci_hdrc *ci) { disable_irq_nosync(ci->irq); diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 6ed4b00dba96..3559915de710 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -25,6 +25,7 @@ #include "ci.h" #include "bits.h" #include "otg.h" +#include "udc.h" #include "otg_fsm.h" /* Add for otg: interact with user space app */ @@ -559,10 +560,7 @@ static int ci_otg_start_gadget(struct otg_fsm *fsm, int on) { struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); - if (on) - usb_gadget_vbus_connect(&ci->gadget); - else - usb_gadget_vbus_disconnect(&ci->gadget); + ci_hdrc_gadget_connect(&ci->gadget, on); return 0; } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 8f18e7b6cadf..735627d7cb6c 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1540,26 +1540,11 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) usb_phy_set_charger_state(ci->usb_phy, is_active ? USB_CHARGER_PRESENT : USB_CHARGER_ABSENT); - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(ci); - hw_device_state(ci, ci->ep0out->qh.dma); - usb_gadget_set_state(_gadget, USB_STATE_POWERED); - usb_udc_vbus_handler(_gadget, true); - } else { - usb_udc_vbus_handler(_gadget, false); - if (ci->driver) - ci->driver->disconnect(&ci->gadget); - hw_device_state(ci, 0); - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, - CI_HDRC_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&ci->gadget); - pm_runtime_put_sync(&_gadget->dev); - usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); - } - } + /* Charger Detection */ + ci_usb_charger_connect(ci, is_active); + + if (gadget_ready) + ci_hdrc_gadget_connect(_gadget, is_active); return 0; } @@ -1999,6 +1984,58 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) dma_pool_destroy(ci->qh_pool); } +int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active) +{ + int ret = 0; + + if (ci->platdata->notify_event) { + pm_runtime_get_sync(&ci->gadget.dev); + if (is_active) + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); + + ret = ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_VBUS_EVENT); + if (ret == CI_HDRC_NOTIFY_RET_DEFER_EVENT) { + hw_device_reset(ci); + /* Pull up dp */ + hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_CHARGER_POST_EVENT); + /* Pull down dp */ + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); + } + pm_runtime_put_sync(&ci->gadget.dev); + } + return ret; +} + +/** + * ci_hdrc_gadget_connect: caller make sure gadget driver is binded + */ +void ci_hdrc_gadget_connect(struct usb_gadget *gadget, int is_active) +{ + struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); + + if (is_active) { + pm_runtime_get_sync(&gadget->dev); + hw_device_reset(ci); + hw_device_state(ci, ci->ep0out->qh.dma); + usb_gadget_set_state(gadget, USB_STATE_POWERED); + usb_udc_vbus_handler(gadget, true); + } else { + usb_udc_vbus_handler(gadget, false); + if (ci->driver) + ci->driver->disconnect(gadget); + hw_device_state(ci, 0); + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(gadget); + pm_runtime_put_sync(&gadget->dev); + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + } +} + static int udc_id_switch_for_device(struct ci_hdrc *ci) { if (ci->platdata->pins_device) diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h index e023735d94b7..da8529c2684f 100644 --- a/drivers/usb/chipidea/udc.h +++ b/drivers/usb/chipidea/udc.h @@ -82,6 +82,8 @@ struct ci_hw_req { int ci_hdrc_gadget_init(struct ci_hdrc *ci); void ci_hdrc_gadget_destroy(struct ci_hdrc *ci); +int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active); +void ci_hdrc_gadget_connect(struct usb_gadget *gadget, int is_active); #else @@ -95,6 +97,17 @@ static inline void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) } +static inline int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active) +{ + return 0; +} + +static inline void ci_hdrc_gadget_connect(struct usb_gadget *gadget, + int is_active) +{ + +} + #endif #endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */ diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index edd89b7c8f18..8be9dce640bd 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -67,6 +67,9 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 #define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 2 #define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 3 +#define CI_HDRC_CONTROLLER_VBUS_EVENT 4 +#define CI_HDRC_NOTIFY_RET_DEFER_EVENT 5 +#define CI_HDRC_CONTROLLER_CHARGER_POST_EVENT 6 int (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; |