diff options
author | Suresh Mangipudi <smangipudi@nvidia.com> | 2011-08-14 18:27:30 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:17 -0800 |
commit | 9d6b71c8e8bf85c350951e4f8c3a1cb5ba54bac0 (patch) | |
tree | 81c2ae38cbb2595baa0fad85b95820e9b3ce870d | |
parent | d540f7650771617c58cee51d1223888dd37d1ad0 (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.c | 48 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 1 | ||||
-rw-r--r-- | include/linux/fsl_devices.h | 1 |
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 */ |