summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jun <b47624@freescale.com>2015-01-09 15:35:07 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:56:29 +0800
commit5037438220f6b5ebfc4f127ba3bdfd4ce431f165 (patch)
tree52f1b204ced749e26272d614978ddaa2e518f007
parent219d54332a09e8d8741c1e1982f5eae56099de85 (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.c8
-rw-r--r--drivers/usb/chipidea/otg.c16
-rw-r--r--drivers/usb/chipidea/otg.h3
-rw-r--r--drivers/usb/chipidea/otg_fsm.c6
-rw-r--r--drivers/usb/chipidea/udc.c77
-rw-r--r--drivers/usb/chipidea/udc.h13
-rw-r--r--include/linux/usb/chipidea.h3
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;