]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00212322-1: usb: add usb charger support for i.mx6x
authorPeter Chen <peter.chen@freescale.com>
Tue, 5 Jun 2012 03:08:29 +0000 (11:08 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:47 +0000 (08:34 +0200)
- USB charger function is embedded in usb device driver, and only for i.mx6x
- SDP and DCP charger are tested
- Need to enable usb device function (insmod one gadget driver)
to use usb charger detect function
- The power supply interface for usb charger is:
/sys/class/power_supply/imx_usb_charger/
Some useful entries for power supply interface:
- present: whether usb charger is present or not
- type: usb charger type
- current_max: the max charger current for this charger
- online: whether vbus is on or not

Signed-off-by: Peter Chen <peter.chen@freescale.com>
drivers/usb/gadget/Kconfig
drivers/usb/gadget/arcotg_udc.c
drivers/usb/gadget/arcotg_udc.h
drivers/usb/gadget/imx_usb_charger.c [new file with mode: 0644]
drivers/usb/gadget/imx_usb_charger.h [new file with mode: 0644]

index 2cd864d829d49de897ef4c29a92ef7e587816da0..43006e49d903cb88f42bc474373dd6de0c0d2308 100755 (executable)
@@ -173,6 +173,13 @@ config USB_STATIC_IRAM_PPH
        help
           Apply static IRAM patch to peripheral driver.
 
+config IMX_USB_CHARGER
+       bool "Use i.MX SoC USB charger detect function"
+       depends on USB_GADGET_ARC && ARCH_MX6
+       help
+         Say "y" will enable i.mx usb charger detect function
+         (only for i.mx6x currently).
+
 config USB_ARC
        tristate
        depends on USB_GADGET_ARC
index ea81802a3ca6a9d282505317a8db799cc0d51d75..8def72278d19df8d731f90955f7bbfec99a21fb5 100755 (executable)
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 #include <linux/dmapool.h>
+#include <linux/io.h>
 
 #include <asm/processor.h>
 #include <asm/byteorder.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
@@ -78,6 +78,8 @@ static const char driver_desc[] = DRIVER_DESC;
 volatile static struct usb_dr_device *dr_regs;
 volatile static struct usb_sys_interface *usb_sys_regs;
 
+#include "imx_usb_charger.c" /* support for usb charger detect */
+
 /* it is initialized in probe()  */
 static struct fsl_udc *udc_controller;
 
@@ -488,6 +490,8 @@ static void dr_controller_run(struct fsl_udc *udc)
        /* If vbus not on and used low power mode */
        if (!(temp & OTGSC_B_SESSION_VALID)) {
                /* Set stopped before low power mode */
+               udc->vbus_active = false;
+               imx_usb_vbus_disconnect(&udc->charger); /* charger disconnect */
                udc->stopped = 1;
                /* enable wake up */
                dr_wake_up_enable(udc, true);
@@ -508,10 +512,8 @@ static void dr_controller_run(struct fsl_udc *udc)
 
                /* disable pulldown dp and dm */
                dr_discharge_line(udc->pdata, false);
-               /* The usb line has already been connected to pc */
-               temp = fsl_readl(&dr_regs->usbcmd);
-               temp |= USB_CMD_RUN_STOP;
-               fsl_writel(temp, &dr_regs->usbcmd);
+               udc->vbus_active = true;
+               imx_usb_vbus_connect(&udc->charger); /* charger detect */
                printk(KERN_DEBUG "%s: udc out low power mode\n", __func__);
        }
 
@@ -1467,6 +1469,15 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
+/*
+ * The USB PHY/Charger driver can't visit usb_gadget directly, so
+ * supply a wrapped function for usb charger visiting.
+ */
+static void usb_charger_pullup_dp(bool enable)
+{
+       fsl_pullup(&udc_controller->gadget, (int)enable);
+}
+
 /* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
        .get_frame = fsl_get_frame,
@@ -2227,13 +2238,15 @@ bool try_wake_up_udc(struct fsl_udc *udc)
                if (irq_src & OTGSC_B_SESSION_VALID) {
                        if (udc->suspended) /*let the system pm resume the udc */
                                return true;
+                       udc->vbus_active = true;
                        udc->stopped = 0;
                        /* disable pulldown dp and dm */
                        dr_discharge_line(pdata, false);
-                       fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd);
+                       imx_usb_vbus_connect(&udc->charger); /* charger detect */
                        printk(KERN_DEBUG "%s: udc out low power mode\n", __func__);
                } else {
-                       fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd);
+                       udc->vbus_active = false;
+                       imx_usb_vbus_disconnect(&udc->charger); /* charger disconnect */
                        /* here we need disable B_SESSION_IRQ, after
                         * schedule_work finished, it need to be enabled again.
                         * Doing like this can avoid conflicting between rapid
@@ -3178,6 +3191,20 @@ static int __devinit fsl_udc_probe(struct platform_device *pdev)
 
        create_proc_file();
 
+       /* create usb charger */
+#ifdef CONFIG_IMX_USB_CHARGER
+       udc_controller->charger.dev = &pdev->dev;
+       udc_controller->charger.dp_pullup = usb_charger_pullup_dp;
+       udc_controller->charger.enable = true;
+       if (pdata->charger_base_addr)
+               udc_controller->charger.charger_base_addr = pdata->charger_base_addr;
+       if (imx_usb_create_charger(&udc_controller->charger, "imx_usb_charger"))
+               dev_err(&pdev->dev, "Can't create usb charger\n");
+#else
+       udc_controller->charger.dp_pullup = usb_charger_pullup_dp;
+       udc_controller->charger.enable = false;
+#endif
+
        return 0;
 
 err4:
@@ -3234,6 +3261,10 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
        free_irq(udc_controller->irq, udc_controller);
        iounmap((u8 __iomem *)dr_regs);
 
+#ifdef CONFIG_IMX_USB_CHARGER
+       imx_usb_remove_charger(&udc_controller->charger);
+#endif
+
 #ifndef CONFIG_USB_OTG
 {
        struct resource *res;
index 8f4b88ebc283113f9cacf615d47d34fe0539b4fa..35a2790828a9cd0c775addd1b37f38a9facd63d3 100755 (executable)
@@ -25,6 +25,9 @@
 #ifndef __ARCOTG_UDC_H
 #define __ARCOTG_UDC_H
 
+/* delete below include when charger code moves to phy driver */
+#include "imx_usb_charger.h"
+
 #define TRUE 1
 #define FALSE 0
 
@@ -621,6 +624,7 @@ struct fsl_udc {
        u32 iram_buffer[IRAM_PPH_NTD];
        void *iram_buffer_v[IRAM_PPH_NTD];
        struct work_struct gadget_disconnect_schedule;
+       struct usb_charger charger; /* usb charger for this udc */
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/imx_usb_charger.c b/drivers/usb/gadget/imx_usb_charger.c
new file mode 100644 (file)
index 0000000..41043b4
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * NOTICE: Currently, it only supports i.mx6q usb charger detect
+ */
+
+static int usb_charger_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct usb_charger *charger =
+               container_of(psy, struct usb_charger, psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = charger->present;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = charger->online;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               val->intval = charger->max_current;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void usb_charger_work(struct work_struct *data)
+{
+       int                     ret;
+       struct usb_charger      *charger =
+                       container_of(data, struct usb_charger, work);
+
+       if (!charger->online)
+               return;
+
+       mutex_lock(&charger->lock);
+
+       /* Start the primary charger detection. */
+       if (charger->detect) {
+               ret = charger->detect(charger);
+               if (ret <= 0)
+                       dev_err(charger->dev, "Error occurs during usb charger \
+                                       detection\n");
+               else
+                       charger->present = ret;
+       }
+
+       switch (charger->psy.type) {
+       case POWER_SUPPLY_TYPE_USB_DCP:
+               charger->max_current = 1500;
+               break;
+       case POWER_SUPPLY_TYPE_USB_CDP:
+               charger->max_current = 900;
+               break;
+       case POWER_SUPPLY_TYPE_USB: /* SDP */
+               charger->max_current = 500;
+       default:
+               if (charger->dp_pullup)
+                       charger->dp_pullup(true);
+               break;
+       }
+
+       power_supply_changed(&charger->psy);
+
+       mutex_unlock(&charger->lock);
+}
+
+/* Return value if the charger is present */
+static int usb_charger_detect(struct usb_charger *charger)
+{
+       void __iomem *addr = charger->charger_base_addr;
+       int i;
+
+       BUG_ON(!addr);
+
+       /* Enable the vdd3p0 curret limiter */
+       writel(BM_ANADIG_REG_3P0_ENABLE_LINREG |
+                       BM_ANADIG_REG_3P0_ENABLE_ILIMIT,
+                       addr + HW_ANADIG_REG_3P0_SET);
+
+       /* check if vbus is valid */
+       if (!(readl(addr + HW_ANADIG_USB1_VBUS_DET_STAT) &
+                       BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
+               dev_err(charger->dev, "vbus is error\n");
+               return 0;
+       }
+
+       /* Enable charger detector */
+       writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B,
+                       addr + HW_ANADIG_USB1_CHRG_DETECT_CLR);
+       /*
+        * - Do not check whether a charger is connected to the USB port
+        * - Check whether the USB plug has been in contact with each other
+        */
+       writel(BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT
+                       | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B,
+                       addr + HW_ANADIG_USB1_CHRG_DETECT_SET);
+
+       /* Check if plug is connected */
+       for (i = 0; i < 1000; i = i + 1) {
+               if (readl(addr + HW_ANADIG_USB1_CHRG_DET_STAT) &
+                       BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
+                       dev_dbg(charger->dev, "Plug Contact = 1\n");
+                       break;
+               } else if (i > 800) {
+                       dev_err(charger->dev, "VBUS is coming from a dedicated power supply.\n");
+                       return 0;
+               } else
+                       msleep(1);
+       }
+
+       /*
+        * - Do check whether a charger is connected to the USB port
+        * - Do not Check whether the USB plug has been in contact with each other
+        */
+       writel(BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT
+                       | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B,
+                       addr + HW_ANADIG_USB1_CHRG_DETECT_CLR);
+
+       msleep(40);
+
+       /* Check if it is a charger */
+       if (!(readl(addr + HW_ANADIG_USB1_CHRG_DET_STAT) &
+                       BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
+               dev_info(charger->dev, "It is a stardard downstream port\n");
+               charger->psy.type = POWER_SUPPLY_TYPE_USB;
+
+               /* Disable Charger detector */
+               writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B
+                       | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B,
+                       addr + HW_ANADIG_USB1_CHRG_DETECT);
+
+               /* Disable the vdd3p0 curret limiter */
+               writel(BM_ANADIG_REG_3P0_ENABLE_ILIMIT,
+                               addr + HW_ANADIG_REG_3P0_CLR);
+               return 1;
+       }
+
+       /* Begin to detect CDP and DCP */
+
+       /* Disable Charger detector */
+       writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B
+               | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B,
+               addr + HW_ANADIG_USB1_CHRG_DETECT);
+
+       msleep(40);
+
+       /* Disable the vdd3p0 curret limiter */
+       writel(BM_ANADIG_REG_3P0_ENABLE_ILIMIT,
+                       addr + HW_ANADIG_REG_3P0_CLR);
+
+       /* pull up dp */
+       if (charger->dp_pullup)
+               charger->dp_pullup(true);
+
+       msleep(40);
+
+       if ((readl(&dr_regs->portsc1) & PORTSCX_LINE_STATUS_KSTATE)) {
+               dev_info(charger->dev, "It is a dedicate charging port\n");
+               charger->psy.type = POWER_SUPPLY_TYPE_USB_DCP;
+       } else {
+               dev_info(charger->dev, "It is a charging downstream port\n");
+               charger->psy.type = POWER_SUPPLY_TYPE_USB_CDP;
+       }
+
+       return 1;
+}
+
+void usb_charger_init(struct usb_charger *charger)
+{
+       charger->bc = BATTERY_CHARGING_SPEC_1_2;
+       charger->detect = usb_charger_detect;
+}
+
+/*
+ * imx_usb_create_charger - create a USB charger
+ * @charger: the charger to be initialized
+ * @name: name for the power supply
+
+ * Registers a power supply for the charger. The PHY/UDC driver will
+ * call this after filling struct usb_charger. All the users are
+ * expected to be in the supplied_to parameter.
+ */
+int imx_usb_create_charger(struct usb_charger *charger,
+               const char *name)
+{
+       int                     ret = 0;
+       struct power_supply     *psy = &charger->psy;
+
+       if (!charger->dev)
+               return -EINVAL;
+
+       if (name)
+               psy->name = name;
+       else
+               psy->name = "usb_charger";
+
+       usb_charger_init(charger);
+
+       psy->type               = POWER_SUPPLY_TYPE_USB;
+       psy->properties         = power_props;
+       psy->num_properties     = ARRAY_SIZE(power_props);
+       psy->get_property       = usb_charger_get_property;
+
+       psy->supplied_to        = usb_charger_supplied_to;
+       psy->num_supplicants    = sizeof(usb_charger_supplied_to)/sizeof(char *);
+
+       ret = power_supply_register(charger->dev, psy);
+       if (ret)
+               goto fail;
+
+       mutex_init(&charger->lock);
+       INIT_WORK(&charger->work, usb_charger_work);
+
+fail:
+       return ret;
+}
+EXPORT_SYMBOL(imx_usb_create_charger);
+
+/*
+ * imx_usb_remove_charger - remove a USB charger
+ * @charger: the charger to be removed
+ *
+ * Unregister the chargers power supply.
+ */
+void imx_usb_remove_charger(struct usb_charger *charger)
+{
+       power_supply_unregister(&charger->psy);
+}
+EXPORT_SYMBOL(imx_usb_remove_charger);
+
+/*
+ * imx_usb_set_power - Set the maximum power allowed to draw
+ * @charger: the usb charger
+ * @mA: maximum current in milliamps
+ *
+ * Called from the controller after enumeration to inform the maximum
+ * power from the configuration, and after bus suspend and resume.
+ */
+int imx_usb_set_power(struct usb_charger *charger, unsigned mA)
+{
+       if (!charger->online)
+               return 0;
+
+       if (charger->max_current == mA)
+               return 0;
+
+       charger->max_current = mA;
+
+       power_supply_changed(&charger->psy);
+
+       return 0;
+}
+EXPORT_SYMBOL(imx_usb_set_power);
+
+/*
+ * imx_usb_vbus_connect - inform about VBUS connection
+ * @charger: the usb charger
+ *
+ * Inform the charger VBUS is connected. The USB device controller is
+ * expected to keep the dataline pullups disabled until dp_pullup()
+ * is called.
+ */
+int imx_usb_vbus_connect(struct usb_charger *charger)
+{
+       /* if charger is disabled, set usbcmd.rs=1 and return directly */
+       if (!charger->enable) {
+               if (charger->dp_pullup)
+                       charger->dp_pullup(true);
+               return 0;
+       }
+
+       charger->online = 1;
+       schedule_work(&charger->work);
+
+       return 0;
+}
+EXPORT_SYMBOL(imx_usb_vbus_connect);
+
+/*
+ * imx_usb_vbus_disconnect - inform about VBUS disconnection
+ * @charger: the usb charger
+ *
+ * Inform the charger that VBUS is disconnected. The charging will be
+ * stopped and the charger properties cleared.
+ */
+int imx_usb_vbus_disconnect(struct usb_charger *charger)
+{
+       if (charger->dp_pullup)
+               charger->dp_pullup(false); /* usbcmd.rs = 0 */
+
+       if (!charger->enable)
+               return 0;
+
+       charger->online = 0;
+       charger->present = 0;
+       charger->max_current = 0;
+       charger->psy.type = POWER_SUPPLY_TYPE_USB;
+
+       if (charger->disconnect)
+               charger->disconnect(charger);
+
+       power_supply_changed(&charger->psy);
+
+       return 0;
+}
+EXPORT_SYMBOL(imx_usb_vbus_disconnect);
diff --git a/drivers/usb/gadget/imx_usb_charger.h b/drivers/usb/gadget/imx_usb_charger.h
new file mode 100644 (file)
index 0000000..5417743
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * NOTICE: Currently, it only supports i.mx6q usb charger detect
+ */
+
+#ifndef __IMXUSB_CHARGER_H
+#define __IMXUSB_CHARGER_H
+
+#define HW_ANADIG_REG_3P0      (0x00000120)
+#define HW_ANADIG_REG_3P0_SET  (0x00000124)
+#define HW_ANADIG_REG_3P0_CLR  (0x00000128)
+#define HW_ANADIG_REG_3P0_TOG  (0x0000012c)
+#define BM_ANADIG_REG_3P0_ENABLE_ILIMIT 0x00000004
+#define BM_ANADIG_REG_3P0_ENABLE_LINREG 0x00000001
+
+#define HW_ANADIG_USB1_VBUS_DETECT     (0x000001a0)
+#define HW_ANADIG_USB1_VBUS_DETECT_SET (0x000001a4)
+#define HW_ANADIG_USB1_VBUS_DETECT_CLR (0x000001a8)
+#define HW_ANADIG_USB1_VBUS_DETECT_TOG (0x000001ac)
+
+#define BM_ANADIG_USB1_VBUS_DETECT_EN_CHARGER_RESISTOR 0x80000000
+#define BP_ANADIG_USB1_VBUS_DETECT_RSVD2      28
+#define BM_ANADIG_USB1_VBUS_DETECT_RSVD2 0x70000000
+#define BF_ANADIG_USB1_VBUS_DETECT_RSVD2(v)  \
+       (((v) << 28) & BM_ANADIG_USB1_VBUS_DETECT_RSVD2)
+#define BM_ANADIG_USB1_VBUS_DETECT_CHARGE_VBUS 0x08000000
+#define BM_ANADIG_USB1_VBUS_DETECT_DISCHARGE_VBUS 0x04000000
+#define BP_ANADIG_USB1_VBUS_DETECT_RSVD1      21
+#define BM_ANADIG_USB1_VBUS_DETECT_RSVD1 0x03E00000
+#define BF_ANADIG_USB1_VBUS_DETECT_RSVD1(v)  \
+       (((v) << 21) & BM_ANADIG_USB1_VBUS_DETECT_RSVD1)
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_PWRUP_CMPS 0x00100000
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_5VDETECT 0x00080000
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_TO_B 0x00040000
+#define BP_ANADIG_USB1_VBUS_DETECT_RSVD0      8
+#define BM_ANADIG_USB1_VBUS_DETECT_RSVD0 0x0003FF00
+#define BF_ANADIG_USB1_VBUS_DETECT_RSVD0(v)  \
+       (((v) << 8) & BM_ANADIG_USB1_VBUS_DETECT_RSVD0)
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_OVERRIDE 0x00000080
+#define BM_ANADIG_USB1_VBUS_DETECT_AVALID_OVERRIDE 0x00000040
+#define BM_ANADIG_USB1_VBUS_DETECT_BVALID_OVERRIDE 0x00000020
+#define BM_ANADIG_USB1_VBUS_DETECT_SESSEND_OVERRIDE 0x00000010
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUS_OVERRIDE_EN 0x00000008
+#define BP_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH      0
+#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH 0x00000007
+#define BF_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH(v)  \
+       (((v) << 0) & BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH)
+
+#define HW_ANADIG_USB1_CHRG_DETECT     (0x000001b0)
+#define HW_ANADIG_USB1_CHRG_DETECT_SET (0x000001b4)
+#define HW_ANADIG_USB1_CHRG_DETECT_CLR (0x000001b8)
+#define HW_ANADIG_USB1_CHRG_DETECT_TOG (0x000001bc)
+
+#define BP_ANADIG_USB1_CHRG_DETECT_RSVD2      24
+#define BM_ANADIG_USB1_CHRG_DETECT_RSVD2 0xFF000000
+#define BF_ANADIG_USB1_CHRG_DETECT_RSVD2(v) \
+       (((v) << 24) & BM_ANADIG_USB1_CHRG_DETECT_RSVD2)
+#define BM_ANADIG_USB1_CHRG_DETECT_BGR_BIAS 0x00800000
+#define BP_ANADIG_USB1_CHRG_DETECT_RSVD1      21
+#define BM_ANADIG_USB1_CHRG_DETECT_RSVD1 0x00600000
+#define BF_ANADIG_USB1_CHRG_DETECT_RSVD1(v)  \
+       (((v) << 21) & BM_ANADIG_USB1_CHRG_DETECT_RSVD1)
+#define BM_ANADIG_USB1_CHRG_DETECT_EN_B 0x00100000
+#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B 0x00080000
+#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT 0x00040000
+#define BP_ANADIG_USB1_CHRG_DETECT_RSVD0      1
+#define BM_ANADIG_USB1_CHRG_DETECT_RSVD0 0x0003FFFE
+#define BF_ANADIG_USB1_CHRG_DETECT_RSVD0(v)  \
+       (((v) << 1) & BM_ANADIG_USB1_CHRG_DETECT_RSVD0)
+#define BM_ANADIG_USB1_CHRG_DETECT_FORCE_DETECT 0x00000001
+
+#define HW_ANADIG_USB1_VBUS_DET_STAT   (0x000001c0)
+#define HW_ANADIG_USB1_VBUS_DET_STAT_SET       (0x000001c4)
+#define HW_ANADIG_USB1_VBUS_DET_STAT_CLR       (0x000001c8)
+#define HW_ANADIG_USB1_VBUS_DET_STAT_TOG       (0x000001cc)
+
+#define BP_ANADIG_USB1_VBUS_DET_STAT_RSVD0      4
+#define BM_ANADIG_USB1_VBUS_DET_STAT_RSVD0 0xFFFFFFF0
+#define BF_ANADIG_USB1_VBUS_DET_STAT_RSVD0(v) \
+       (((v) << 4) & BM_ANADIG_USB1_VBUS_DET_STAT_RSVD0)
+#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID 0x00000008
+#define BM_ANADIG_USB1_VBUS_DET_STAT_AVALID 0x00000004
+#define BM_ANADIG_USB1_VBUS_DET_STAT_BVALID 0x00000002
+#define BM_ANADIG_USB1_VBUS_DET_STAT_SESSEND 0x00000001
+
+#define HW_ANADIG_USB1_CHRG_DET_STAT   (0x000001d0)
+#define HW_ANADIG_USB1_CHRG_DET_STAT_SET       (0x000001d4)
+#define HW_ANADIG_USB1_CHRG_DET_STAT_CLR       (0x000001d8)
+#define HW_ANADIG_USB1_CHRG_DET_STAT_TOG       (0x000001dc)
+
+#define BP_ANADIG_USB1_CHRG_DET_STAT_RSVD0      4
+#define BM_ANADIG_USB1_CHRG_DET_STAT_RSVD0 0xFFFFFFF0
+#define BF_ANADIG_USB1_CHRG_DET_STAT_RSVD0(v) \
+       (((v) << 4) & BM_ANADIG_USB1_CHRG_DET_STAT_RSVD0)
+#define BM_ANADIG_USB1_CHRG_DET_STAT_DP_STATE 0x00000008
+#define BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE 0x00000004
+#define BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED 0x00000002
+#define BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT 0x00000001
+
+#define HW_ANADIG_USB1_LOOPBACK        (0x000001e0)
+#define HW_ANADIG_USB1_LOOPBACK_SET    (0x000001e4)
+#define HW_ANADIG_USB1_LOOPBACK_CLR    (0x000001e8)
+#define HW_ANADIG_USB1_LOOPBACK_TOG    (0x000001ec)
+
+#define BP_ANADIG_USB1_LOOPBACK_RSVD0      9
+#define BM_ANADIG_USB1_LOOPBACK_RSVD0 0xFFFFFE00
+#define BF_ANADIG_USB1_LOOPBACK_RSVD0(v) \
+       (((v) << 9) & BM_ANADIG_USB1_LOOPBACK_RSVD0)
+#define BM_ANADIG_USB1_LOOPBACK_UTMO_DIG_TST1 0x00000100
+#define BM_ANADIG_USB1_LOOPBACK_UTMO_DIG_TST0 0x00000080
+#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_HIZ 0x00000040
+#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN 0x00000020
+#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_LS_MODE 0x00000010
+#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_HS_MODE 0x00000008
+#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 0x00000004
+#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST0 0x00000002
+#define BM_ANADIG_USB1_LOOPBACK_UTMI_TESTSTART 0x00000001
+
+#define HW_ANADIG_USB1_MISC    (0x000001f0)
+#define HW_ANADIG_USB1_MISC_SET        (0x000001f4)
+#define HW_ANADIG_USB1_MISC_CLR        (0x000001f8)
+#define HW_ANADIG_USB1_MISC_TOG        (0x000001fc)
+
+#define BM_ANADIG_USB1_MISC_RSVD1 0x80000000
+#define BM_ANADIG_USB1_MISC_EN_CLK_UTMI 0x40000000
+#define BM_ANADIG_USB1_MISC_RX_VPIN_FS 0x20000000
+#define BM_ANADIG_USB1_MISC_RX_VMIN_FS 0x10000000
+#define BM_ANADIG_USB1_MISC_RX_RXD_FS 0x08000000
+#define BM_ANADIG_USB1_MISC_RX_SQUELCH 0x04000000
+#define BM_ANADIG_USB1_MISC_RX_DISCON_DET 0x02000000
+#define BM_ANADIG_USB1_MISC_RX_HS_DATA 0x01000000
+#define BP_ANADIG_USB1_MISC_RSVD0      2
+#define BM_ANADIG_USB1_MISC_RSVD0 0x00FFFFFC
+#define BF_ANADIG_USB1_MISC_RSVD0(v)  \
+       (((v) << 2) & BM_ANADIG_USB1_MISC_RSVD0)
+#define BM_ANADIG_USB1_MISC_EN_DEGLITCH 0x00000002
+#define BM_ANADIG_USB1_MISC_HS_USE_EXTERNAL_R 0x00000001
+
+#include <linux/power_supply.h>
+enum battery_charging_spec {
+       BATTERY_CHARGING_SPEC_NONE = 0,
+       BATTERY_CHARGING_SPEC_UNKNOWN,
+       BATTERY_CHARGING_SPEC_1_0,
+       BATTERY_CHARGING_SPEC_1_1,
+       BATTERY_CHARGING_SPEC_1_2,
+};
+
+struct usb_charger {
+       void __iomem            *charger_base_addr; /* Get from MSL if exists */
+       struct device           *dev; /* udc supplies */
+       /* charger detect can be enabled/disabled by kernel config */
+       bool                    enable;
+
+       struct power_supply     psy;
+       struct work_struct      work;
+       struct mutex            lock;
+
+       /* Compliant with Battery Charging Specification version (if any) */
+       enum battery_charging_spec      bc;
+
+       /* properties */
+       unsigned                present:1;
+       unsigned                online:1;
+       unsigned                max_current;
+       /* pull up/down dp during the charger detect, udc supplies */
+       void    (*dp_pullup)(bool);
+       int     (*connect)(struct usb_charger *charger);
+       int     (*disconnect)(struct usb_charger *charger);
+       int     (*set_power)(struct usb_charger *charger, unsigned mA);
+
+       int     (*detect)(struct usb_charger *charger);
+};
+
+static char *usb_charger_supplied_to[] = {
+       "main-battery",
+};
+
+static enum power_supply_property power_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,      /* Charger detected */
+       POWER_SUPPLY_PROP_ONLINE,       /* VBUS online */
+       POWER_SUPPLY_PROP_CURRENT_MAX,  /* Maximum current in mA */
+};
+
+#endif /* __IMXUSB_CHARGER_H */