usb: gadget: udc: USB charger detection support
Rakesh Bodla [Tue, 9 Aug 2011 10:49:08 +0000 (15:49 +0530)]
Adding the USB charger detection support for
device controller.

Bug 819334

Reviewed-on: http://git-master/r/42299
(cherry picked from commit 06bdd7fc427abd7a6e907af52441dec07f92e2f6)

Original-Change-Id: I3559b00f171c3d4111c1a9c1ecfb89f4d6a57fd1
Reviewed-on: http://git-master/r/43519
Reviewed-by: Rakesh Bodla <rbodla@nvidia.com>
Tested-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>

Rebase-Id: Rb088810caf6946a123094851d6da1c17940a83ba

drivers/usb/gadget/fsl_tegra_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fsl_usb2_udc.h

index 01375d3..ece468e 100644 (file)
@@ -139,12 +139,17 @@ void fsl_udc_clk_resume(bool is_dpd)
        tegra_usb_phy_power_on(phy,  is_dpd);
 }
 
-void fsl_udc_clk_enable()
+void fsl_udc_clk_enable(void)
 {
        clk_enable(udc_clk);
 }
 
-void fsl_udc_clk_disable()
+void fsl_udc_clk_disable(void)
 {
        clk_disable(udc_clk);
 }
+
+bool fsl_udc_charger_detect(void)
+{
+       return tegra_usb_phy_charger_detect(phy);
+}
index 8830c91..9cfc9c6 100644 (file)
@@ -42,6 +42,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>
@@ -73,6 +74,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;
 
@@ -1368,6 +1372,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);
@@ -1391,6 +1397,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;
        }
@@ -2198,6 +2207,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
@@ -2259,6 +2280,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);
@@ -3015,6 +3039,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
        if (udc_controller->transceiver) {
                dr_controller_stop(udc_controller);
@@ -3071,6 +3098,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
        usb_del_gadget_udc(&udc_controller->gadget);
        udc_controller->done = &done;
 
+       cancel_delayed_work(&udc_controller->work);
        if (udc_controller->transceiver)
                otg_set_peripheral(udc_controller->transceiver, NULL);
 
index b74c8cf..7ea4a2f 100644 (file)
@@ -638,6 +638,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 */
 };
 
 /*-------------------------------------------------------------------------*/
@@ -721,6 +722,7 @@ void fsl_udc_clk_suspend(bool is_dpd);
 void fsl_udc_clk_resume(bool is_dpd);
 void fsl_udc_clk_enable(void);
 void fsl_udc_clk_disable(void);
+bool fsl_udc_charger_detect(void);
 #else
 static inline int fsl_udc_clk_init(struct platform_device *pdev)
 {
@@ -744,6 +746,10 @@ void fsl_udc_clk_enable(void)
 void fsl_udc_clk_disable(void)
 {
 }
+static inline bool fsl_udc_charger_detect(void)
+{
+       return false;
+}
 #endif
 
 #endif