From 8d6705374629fbcb39b2f5d272235618db9c6e7a Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 9 Jan 2015 15:35:07 +0800 Subject: [PATCH] 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 Signed-off-by: Li Jun --- drivers/usb/chipidea/ci_hdrc_msm.c | 4 +- drivers/usb/chipidea/core.c | 8 ++-- drivers/usb/chipidea/otg.c | 16 ++++++- drivers/usb/chipidea/otg.h | 3 +- drivers/usb/chipidea/otg_fsm.c | 6 +-- drivers/usb/chipidea/udc.c | 77 ++++++++++++++++++++++-------- drivers/usb/chipidea/udc.h | 13 +++++ include/linux/usb/chipidea.h | 5 +- 8 files changed, 100 insertions(+), 32 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 37591a4b1346..6d5cf973dba6 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -17,7 +17,7 @@ #define MSM_USB_BASE (ci->hw_bank.abs) -static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) +static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) { struct device *dev = ci->gadget.dev.parent; @@ -40,6 +40,8 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) dev_dbg(dev, "unknown ci_hdrc event\n"); break; } + + return 0; } static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 6e0d614a8075..fd19dc4373f2 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -982,11 +982,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 f36a1ac3bfbd..dad2a07de015 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -1,7 +1,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 * @@ -129,6 +129,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 9ecb598e48f0..1c9ad1af082b 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. * * Author: Peter Chen * @@ -17,6 +17,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 7f9e80061cba..2a2fe132bc1d 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -28,6 +28,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 */ @@ -563,10 +564,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 2baa017fd322..caf2a733a335 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1539,26 +1539,11 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) gadget_ready = 1; spin_unlock_irqrestore(&ci->lock, flags); - 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; } @@ -1970,6 +1955,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->is_otg) diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h index e66df0020bd4..7c3af66aa8f4 100644 --- a/drivers/usb/chipidea/udc.h +++ b/drivers/usb/chipidea/udc.h @@ -85,6 +85,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 @@ -98,6 +100,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 f9be467d6695..3fcb7b34a168 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -60,7 +60,10 @@ struct ci_hdrc_platform_data { enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 - void (*notify_event) (struct ci_hdrc *ci, unsigned event); +#define CI_HDRC_CONTROLLER_VBUS_EVENT 2 +#define CI_HDRC_NOTIFY_RET_DEFER_EVENT 3 +#define CI_HDRC_CONTROLLER_CHARGER_POST_EVENT 4 + int (*notify_event)(struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; bool tpl_support; -- 2.17.1