summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorFrank Li <Frank.li@freescale.com>2010-03-10 15:20:22 +0800
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2010-05-25 11:20:19 +0200
commit3f59fe0ee827aa12cecd8bcf1573a66945e5b02b (patch)
tree0de344d1b124446f040167a827aea90a9f222de9 /drivers
parent2631add3701e1de5d46da7ee5ec8b20ecf291395 (diff)
ENGR00121497-2 MX28 USB 100mA current draw
Add USB 100mA limitation feature for mx28 to mach usb 2.0 current requirment Signed-off-by: Frank Li <Frank.li@freescale.com> Signed-off-by: Alejandro Gonzalez <alex.gonzalez@digi.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/mxs/ddi_power_battery.c6
-rw-r--r--drivers/power/mxs/linux.c64
-rw-r--r--drivers/usb/gadget/arcotg_udc.c20
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c9
5 files changed, 91 insertions, 15 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8793ce6972a8..f90ffbf4c436 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -117,4 +117,11 @@ config BATTERY_MXS
Say Y to enable support for the battery charger state machine
for the Sigmatel MXS based SoC's.
+config MXS_VBUS_CURRENT_DRAW
+ tristate "MXS SoC USB2.0 VBUS Current Limitation"
+ depends on ARCH_MXS
+ help
+ Say Y to enable 100mA limitation when USB vbus power on system
+ before enumeration to match USB2.0 requirement.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/mxs/ddi_power_battery.c b/drivers/power/mxs/ddi_power_battery.c
index c17b2da86ffa..101e38e6b8d4 100644
--- a/drivers/power/mxs/ddi_power_battery.c
+++ b/drivers/power/mxs/ddi_power_battery.c
@@ -888,6 +888,12 @@ int ddi_power_init_battery(void)
power driver behavior may not be reliable \n");
ret = 1;
}
+ if ((__raw_readl(REGS_POWER_BASE + HW_POWER_BATTMONITOR) &
+ BM_POWER_BATTMONITOR_BATT_VAL) == 0) {
+ ret = 1;
+ printk(KERN_INFO "WARNING : No battery connected !\r\n");
+ return ret;
+ }
/* the following code to enable automatic battery measurement
* should have already been enabled in the boot prep files. Not
diff --git a/drivers/power/mxs/linux.c b/drivers/power/mxs/linux.c
index ce8b0e3ed75f..3cd173d640c9 100644
--- a/drivers/power/mxs/linux.c
+++ b/drivers/power/mxs/linux.c
@@ -18,6 +18,7 @@
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/sched.h>
+#include <linux/clk.h>
#include <mach/ddi_bc.h>
#include "ddi_bc_internal.h"
#include <linux/regulator/consumer.h>
@@ -26,6 +27,7 @@
#include <mach/regs-power.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
+#include <mach/clock.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
@@ -229,9 +231,25 @@ static void check_and_handle_5v_connection(struct mxs_info *info)
_5v_connected_verified;
dev_info(info->dev,
"5v connection verified\n");
+#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
+ #ifdef CONFIG_USB_GADGET
+ /* if there is USB 2.0 current limitation requirement,
+ * waiting for USB enum done.
+ */
+ if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
+ & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) ==
+ (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
+ dev_info(info->dev, "waiting USB enum done...\r\n");
+ }
+ while ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
+ & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT)
+ == (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
+ msleep(50);
+ }
+ #endif
+#endif
ddi_power_Enable4p2(450);
-
/* part of handling for errata. It is
* now "somewhat" safe to
* turn on vddio interrupts again
@@ -278,6 +296,12 @@ static void check_and_handle_5v_connection(struct mxs_info *info)
dev_info(info->dev,
"5v disconnection handled\n");
+ __raw_writel(__raw_readl(REGS_POWER_BASE +
+ HW_POWER_5VCTRL) &
+ (~BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT)
+ | (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT),
+ REGS_POWER_BASE + HW_POWER_5VCTRL);
+
}
}
@@ -494,8 +518,7 @@ static void state_machine_work(struct work_struct *work)
}
/* if we made it here, we have a verified 5v connection */
-
- if (is_ac_online()) {
+#ifndef CONFIG_MXS_VBUS_CURRENT_DRAW
if (info->is_ac_online)
goto done;
@@ -518,7 +541,7 @@ static void state_machine_work(struct work_struct *work)
}
ddi_bc_SetEnable();
goto done;
- }
+#else
if (!is_usb_online())
goto out;
@@ -557,7 +580,7 @@ static void state_machine_work(struct work_struct *work)
info->is_usb_online |= USB_REG_SET;
dev_info(info->dev, "changed power connection to usb/5v present\n");
-
+#endif
done:
ddi_bc_StateMachine();
@@ -1073,6 +1096,8 @@ static struct proc_dir_entry *power_fiq_proc;
static int __init mxs_bat_init(void)
{
+ struct clk *cpu, *pll0;
+
#ifdef POWER_FIQ
int ret;
ret = claim_fiq(&power_fiq);
@@ -1118,6 +1143,28 @@ static int __init mxs_bat_init(void)
}
#endif
+#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
+ if (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
+ BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000)
+ && ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
+ BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0)) {
+#ifdef CONFIG_USB_GADGET
+ printk(KERN_INFO "USB GADGET exist,wait USB enum done...\r\n");
+ while (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
+ & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) &&
+ ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
+ BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0))
+ ;
+#else
+ printk(KERN_INFO "USB GADGET not exist,\
+ release current limit and let CPU clock up...\r\n");
+#endif
+ }
+ cpu = clk_get(NULL, "cpu");
+ pll0 = clk_get(NULL, "ref_cpu");
+ if (cpu->set_parent)
+ cpu->set_parent(cpu, pll0);
+#endif
return platform_driver_register(&mxs_batdrv);
}
@@ -1125,8 +1172,11 @@ static void __exit mxs_bat_exit(void)
{
platform_driver_unregister(&mxs_batdrv);
}
-
-module_init(mxs_bat_init);
+#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
+ fs_initcall(mxs_bat_init);
+#else
+ module_init(mxs_bat_init);
+#endif
module_exit(mxs_bat_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 2f7612df6861..58bb833fd97e 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -1356,10 +1356,16 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
struct fsl_udc *udc;
+ struct fsl_usb2_platform_data *pdata;
udc = container_of(gadget, struct fsl_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
+ pdata = udc->pdata;
+ if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_draw) {
+ pdata->xcvr_ops->set_vbus_draw(pdata->xcvr_ops, pdata, mA);
+ return 0;
+ }
return -ENOTSUPP;
}
@@ -1515,7 +1521,8 @@ static void setup_received_irq(struct fsl_udc *udc,
u16 wValue = le16_to_cpu(setup->wValue);
u16 wIndex = le16_to_cpu(setup->wIndex);
u16 wLength = le16_to_cpu(setup->wLength);
-
+ struct usb_gadget *gadget = &(udc->gadget);
+ unsigned mA = 500;
udc_reset_ep_queue(udc, 0);
if (wLength) {
@@ -1544,7 +1551,8 @@ static void setup_received_irq(struct fsl_udc *udc,
break;
ch9setaddress(udc, wValue, wIndex, wLength);
return;
-
+ case USB_REQ_SET_CONFIGURATION:
+ fsl_vbus_draw(gadget, mA);
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
/* Status phase from udc */
@@ -3069,9 +3077,11 @@ static int __init udc_init(void)
printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
return platform_driver_register(&udc_driver);
}
-
-module_init(udc_init);
-
+#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
+ fs_initcall(udc_init);
+#else
+ module_init(udc_init);
+#endif
static void __exit udc_exit(void)
{
platform_driver_unregister(&udc_driver);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 42a74b8a0bb8..2b8c435db49e 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2004-2010 Freescale Semicondutor, Inc. All rights reserved.
*
* Author: Li Yang <leoli@freescale.com>
* Jiang Bo <tanya.jiang@freescale.com>
@@ -2475,8 +2475,11 @@ static int __init udc_init(void)
return platform_driver_probe(&udc_driver, fsl_udc_probe);
}
-module_init(udc_init);
-
+#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
+ fs_initcall(udc_init);
+#else
+ module_init(udc_init);
+#endif
static void __exit udc_exit(void)
{
platform_driver_unregister(&udc_driver);