diff options
author | Peter Chen <peter.chen@freescale.com> | 2012-06-05 11:08:29 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-07-20 13:38:32 +0800 |
commit | ffd12c932f3d78ae18a1a3e14d50802dd7146cf3 (patch) | |
tree | 6c1845b6b926a032d7532684835a8850e4e3d60c /drivers/usb | |
parent | b918da295054ee8a96c1b586b2d7a63a583d210b (diff) |
ENGR00212322-1: usb: add usb charger support for i.mx6x
- 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>
Diffstat (limited to 'drivers/usb')
-rwxr-xr-x | drivers/usb/gadget/Kconfig | 7 | ||||
-rwxr-xr-x | drivers/usb/gadget/arcotg_udc.c | 45 | ||||
-rwxr-xr-x | drivers/usb/gadget/arcotg_udc.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/imx_usb_charger.c | 319 | ||||
-rw-r--r-- | drivers/usb/gadget/imx_usb_charger.h | 194 |
5 files changed, 562 insertions, 7 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2cd864d829d4..43006e49d903 100755 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -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 diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index ea81802a3ca6..8def72278d19 100755 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -38,10 +38,10 @@ #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; diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h index 8f4b88ebc283..35a2790828a9 100755 --- a/drivers/usb/gadget/arcotg_udc.h +++ b/drivers/usb/gadget/arcotg_udc.h @@ -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 index 000000000000..41043b432102 --- /dev/null +++ b/drivers/usb/gadget/imx_usb_charger.c @@ -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 index 000000000000..5417743a5118 --- /dev/null +++ b/drivers/usb/gadget/imx_usb_charger.h @@ -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 */ |