summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuresh Mangipudi <smangipudi@nvidia.com>2011-08-14 18:27:30 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:17 -0800
commit9d6b71c8e8bf85c350951e4f8c3a1cb5ba54bac0 (patch)
tree81c2ae38cbb2595baa0fad85b95820e9b3ce870d
parentd540f7650771617c58cee51d1223888dd37d1ad0 (diff)
usb: fsl_udc: setting usb charging current
Setting the charging current limit through the regulator for drawing the vbus current. Bug 854993 Original-Change-Id: I4e1d3578de7f234f7fc9cd1af09fdd1d9dc227d9 Reviewed-on: http://git-master/r/46704 Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com> Tested-by: Suresh Mangipudi <smangipudi@nvidia.com> Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com> Rebase-Id: R2a322c109bfc6f08455bf02069d6fb3828f3534e
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c48
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h1
-rw-r--r--include/linux/fsl_devices.h1
3 files changed, 49 insertions, 1 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 9cfc9c665e4e..c46f7419e5cd 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -42,6 +42,7 @@
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <asm/byteorder.h>
@@ -74,6 +75,8 @@ static struct usb_dr_device *dr_regs;
static struct usb_sys_interface *usb_sys_regs;
#endif
+/* Charger current limit=1800mA, as per the USB charger spec */
+#define USB_CHARGING_CURRENT_LIMIT_MA 1800
/* 1 sec wait time for charger detection after vbus is detected */
#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
@@ -1384,6 +1387,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc->usb_state = USB_STATE_DEFAULT;
spin_unlock_irqrestore(&udc->lock, flags);
fsl_udc_clk_suspend(false);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 0);
+ }
} else if (!udc->vbus_active && is_active) {
fsl_udc_clk_resume(false);
/* setup the controller in the device mode */
@@ -1397,9 +1405,15 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc->vbus_active = 1;
/* start the controller */
dr_controller_run(udc);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 100);
+ }
/* 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);
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
}
return 0;
}
@@ -1428,6 +1442,13 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
+ /* check udc regulator is available for drawing the vbus current */
+ if (udc->vbus_regulator) {
+ /* set the current limit in uA and return */
+ return regulator_set_current_limit(
+ udc->vbus_regulator, 0, mA*1000);
+ }
+
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return -ENOTSUPP;
@@ -2213,9 +2234,18 @@ static void reset_irq(struct fsl_udc *udc)
*/
static void fsl_udc_charger_detect_work(struct work_struct* work)
{
+ struct fsl_udc *udc = container_of (work, struct fsl_udc, work.work);
+
/* check for the platform charger detection */
if (fsl_udc_charger_detect()) {
printk(KERN_INFO "USB compliant charger detected\n");
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_regulator) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0,
+ USB_CHARGING_CURRENT_LIMIT_MA*1000);
+ }
}
}
@@ -2850,6 +2880,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
u32 dccparams;
#if defined(CONFIG_ARCH_TEGRA)
struct resource *res_sys = NULL;
+ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
#endif
if (strcmp(pdev->name, driver_name)) {
@@ -3059,6 +3090,18 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#endif
#endif
+ /* Get the regulator for drawing the vbus current in udc driver */
+ if (pdata->charge_regulator) {
+ udc_controller->vbus_regulator = regulator_get(NULL,
+ pdata->charge_regulator);
+ if (IS_ERR(udc_controller->vbus_regulator)) {
+ dev_err(&pdev->dev,
+ "can't get charge regulator,err:%ld\n",
+ PTR_ERR(udc_controller->vbus_regulator));
+ udc_controller->vbus_regulator = NULL;
+ }
+ }
+
return 0;
err_del_udc:
@@ -3099,6 +3142,9 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
udc_controller->done = &done;
cancel_delayed_work(&udc_controller->work);
+ if (udc_controller->vbus_regulator)
+ regulator_put(udc_controller->vbus_regulator);
+
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 7ea4a2fbbec0..2f1038b4e5e0 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -639,6 +639,7 @@ struct fsl_udc {
USB_DIR_IN or USB_DIR_OUT */
u8 device_address; /* Device USB address */
struct delayed_work work; /* delayed work for charger detection */
+ struct regulator *vbus_regulator; /* regulator for drawing VBUS */
};
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index a8a4ead84332..0050fc784394 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -105,6 +105,7 @@ struct fsl_usb2_platform_data {
void *phy_config;
enum fsl_usb2_phy_types usb_phy_type;
+ const char *charge_regulator;
};
/* Flags in fsl_usb2_mph_platform_data */