summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2011-07-21 10:17:26 +0530
committerManish Tuteja <mtuteja@nvidia.com>2011-07-25 02:31:40 -0700
commit06bdd7fc427abd7a6e907af52441dec07f92e2f6 (patch)
treef785d3ea25632ee58dad2ae34768ab33a5cb7d06 /drivers
parent69c083d495e1f187654c5a1bcd58569e54bf985b (diff)
usb: gadget: udc: USB charger detection support
Adding the USB charger detection support for device controller. Bug 819334 Change-Id: I9350c6abaa2be38ecb40db6bc9bc5e84c5303998 Reviewed-on: http://git-master/r/42299 Reviewed-by: Rakesh Bodla <rbodla@nvidia.com> Tested-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c5
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c28
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h6
3 files changed, 39 insertions, 0 deletions
diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c
index 712636d8ee8e..3e44aea98eeb 100644
--- a/drivers/usb/gadget/fsl_tegra_udc.c
+++ b/drivers/usb/gadget/fsl_tegra_udc.c
@@ -132,3 +132,8 @@ void fsl_udc_clk_resume(bool is_dpd)
clk_enable(udc_clk);
tegra_usb_phy_power_on(phy, is_dpd);
}
+
+bool fsl_udc_charger_detect(void)
+{
+ return tegra_usb_phy_charger_detect(phy);
+}
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 82118cd1cbf7..1dba4dfcacfd 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -39,6 +39,7 @@
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -71,6 +72,9 @@ static struct usb_dr_device *dr_regs;
static struct usb_sys_interface *usb_sys_regs;
#endif
+/* 1 sec wait time for charger detection after vbus is detected */
+#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
+
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
@@ -1207,6 +1211,8 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
if (udc->transceiver) {
if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
spin_lock_irqsave(&udc->lock, flags);
/* reset all internal Queues and inform client driver */
reset_queues(udc);
@@ -1230,6 +1236,9 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc->vbus_active = 1;
/* start the controller */
dr_controller_run(udc);
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work, USB_CHARGER_DETECTION_WAIT_TIME_MS);
}
return 0;
}
@@ -1999,6 +2008,18 @@ static void reset_irq(struct fsl_udc *udc)
#endif
}
+/*
+ * If VBUS is detected and setup packet is not received in 100ms then
+ * work thread starts and checks for the USB charger detection.
+ */
+static void fsl_udc_charger_detect_work(struct work_struct* work)
+{
+ /* check for the platform charger detection */
+ if (fsl_udc_charger_detect()) {
+ printk(KERN_INFO "USB compliant charger detected\n");
+ }
+}
+
#if defined(CONFIG_ARCH_TEGRA)
/*
* Restart device controller in the OTG mode on VBUS detection
@@ -2053,6 +2074,9 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
VDBG("Packet int");
/* Setup package, we only support ep0 as control ep */
if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
+ /* Setup packet received, we are connected to host and
+ * not charger. Cancel any delayed work */
+ cancel_delayed_work(&udc->work);
tripwire_handler(udc, 0,
(u8 *) (&udc->local_setup_buff));
setup_received_irq(udc, &udc->local_setup_buff);
@@ -2751,6 +2775,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
}
create_proc_file();
+ /* create a delayed work for detecting the USB charger */
+ INIT_DELAYED_WORK(&udc_controller->work, fsl_udc_charger_detect_work);
+
#ifdef CONFIG_USB_OTG_UTILS
udc_controller->transceiver = otg_get_transceiver();
if (udc_controller->transceiver) {
@@ -2800,6 +2827,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
return -ENODEV;
udc_controller->done = &done;
+ cancel_delayed_work(&udc_controller->work);
if (udc_controller->transceiver)
otg_set_peripheral(udc_controller->transceiver, NULL);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 415b7c088962..599327d16634 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -512,6 +512,7 @@ struct fsl_udc {
u32 ep0_dir; /* Endpoint zero direction: can be
USB_DIR_IN or USB_DIR_OUT */
u8 device_address; /* Device USB address */
+ struct delayed_work work; /* delayed work for charger detection */
};
/*-------------------------------------------------------------------------*/
@@ -593,6 +594,7 @@ void fsl_udc_clk_finalize(struct platform_device *pdev);
void fsl_udc_clk_release(void);
void fsl_udc_clk_suspend(bool is_dpd);
void fsl_udc_clk_resume(bool is_dpd);
+bool fsl_udc_charger_detect(void);
#else
static inline int fsl_udc_clk_init(struct platform_device *pdev)
{
@@ -610,6 +612,10 @@ static inline void fsl_udc_clk_suspend(bool is_dpd)
static inline void fsl_udc_clk_resume(bool is_dpd)
{
}
+static inline bool fsl_udc_charger_detect(void)
+{
+ return false;
+}
#endif
#endif