USB: gadget: pxa25x: basic transceiver support
This adds very basic otg_transceiver support, with vbus_session and vbus_draw callbacks. Now VBUS sensing can be handled by an external driver which registers the otg_transceiver interface. It also allows gadget drivers to configure the current drawn from VBUS. The UDC driver just passes their requests along to the transceiver driver. Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
4c6e8971cb
commit
ab26d20f3e
@@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
|
#include <linux/usb/otg.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This driver is PXA25x only. Grab the right register definitions.
|
* This driver is PXA25x only. Grab the right register definitions.
|
||||||
@@ -1008,15 +1009,27 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* boards may consume current from VBUS, up to 100-500mA based on config.
|
||||||
|
* the 500uA suspend ceiling means that exclusively vbus-powered PXA designs
|
||||||
|
* violate USB specs.
|
||||||
|
*/
|
||||||
|
static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||||
|
{
|
||||||
|
struct pxa25x_udc *udc;
|
||||||
|
|
||||||
|
udc = container_of(_gadget, struct pxa25x_udc, gadget);
|
||||||
|
|
||||||
|
if (udc->transceiver)
|
||||||
|
return otg_set_power(udc->transceiver, mA);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct usb_gadget_ops pxa25x_udc_ops = {
|
static const struct usb_gadget_ops pxa25x_udc_ops = {
|
||||||
.get_frame = pxa25x_udc_get_frame,
|
.get_frame = pxa25x_udc_get_frame,
|
||||||
.wakeup = pxa25x_udc_wakeup,
|
.wakeup = pxa25x_udc_wakeup,
|
||||||
.vbus_session = pxa25x_udc_vbus_session,
|
.vbus_session = pxa25x_udc_vbus_session,
|
||||||
.pullup = pxa25x_udc_pullup,
|
.pullup = pxa25x_udc_pullup,
|
||||||
|
.vbus_draw = pxa25x_udc_vbus_draw,
|
||||||
// .vbus_draw ... boards may consume current from VBUS, up to
|
|
||||||
// 100-500mA based on config. the 500uA suspend ceiling means
|
|
||||||
// that exclusively vbus-powered PXA designs violate USB specs.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@@ -1303,9 +1316,23 @@ fail:
|
|||||||
* for set_configuration as well as eventual disconnect.
|
* for set_configuration as well as eventual disconnect.
|
||||||
*/
|
*/
|
||||||
DMSG("registered gadget driver '%s'\n", driver->driver.name);
|
DMSG("registered gadget driver '%s'\n", driver->driver.name);
|
||||||
|
|
||||||
|
/* connect to bus through transceiver */
|
||||||
|
if (dev->transceiver) {
|
||||||
|
retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
|
||||||
|
if (retval) {
|
||||||
|
DMSG("can't bind to transceiver\n");
|
||||||
|
if (driver->unbind)
|
||||||
|
driver->unbind(&dev->gadget);
|
||||||
|
goto bind_fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pullup(dev);
|
pullup(dev);
|
||||||
dump_state(dev);
|
dump_state(dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
bind_fail:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||||
|
|
||||||
@@ -1351,6 +1378,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||||||
stop_activity(dev, driver);
|
stop_activity(dev, driver);
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
|
|
||||||
|
if (dev->transceiver)
|
||||||
|
(void) otg_set_peripheral(dev->transceiver, NULL);
|
||||||
|
|
||||||
driver->unbind(&dev->gadget);
|
driver->unbind(&dev->gadget);
|
||||||
dev->gadget.dev.driver = NULL;
|
dev->gadget.dev.driver = NULL;
|
||||||
dev->driver = NULL;
|
dev->driver = NULL;
|
||||||
@@ -2162,6 +2192,8 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
|
|||||||
dev->dev = &pdev->dev;
|
dev->dev = &pdev->dev;
|
||||||
dev->mach = pdev->dev.platform_data;
|
dev->mach = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
dev->transceiver = otg_get_transceiver();
|
||||||
|
|
||||||
if (gpio_is_valid(dev->mach->gpio_vbus)) {
|
if (gpio_is_valid(dev->mach->gpio_vbus)) {
|
||||||
if ((retval = gpio_request(dev->mach->gpio_vbus,
|
if ((retval = gpio_request(dev->mach->gpio_vbus,
|
||||||
"pxa25x_udc GPIO VBUS"))) {
|
"pxa25x_udc GPIO VBUS"))) {
|
||||||
@@ -2264,6 +2296,10 @@ lubbock_fail0:
|
|||||||
if (gpio_is_valid(dev->mach->gpio_vbus))
|
if (gpio_is_valid(dev->mach->gpio_vbus))
|
||||||
gpio_free(dev->mach->gpio_vbus);
|
gpio_free(dev->mach->gpio_vbus);
|
||||||
err_gpio_vbus:
|
err_gpio_vbus:
|
||||||
|
if (dev->transceiver) {
|
||||||
|
otg_put_transceiver(dev->transceiver);
|
||||||
|
dev->transceiver = NULL;
|
||||||
|
}
|
||||||
clk_put(dev->clk);
|
clk_put(dev->clk);
|
||||||
err_clk:
|
err_clk:
|
||||||
return retval;
|
return retval;
|
||||||
@@ -2305,6 +2341,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
clk_put(dev->clk);
|
clk_put(dev->clk);
|
||||||
|
|
||||||
|
if (dev->transceiver) {
|
||||||
|
otg_put_transceiver(dev->transceiver);
|
||||||
|
dev->transceiver = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
platform_set_drvdata(pdev, NULL);
|
||||||
the_controller = NULL;
|
the_controller = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -128,6 +128,7 @@ struct pxa25x_udc {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct pxa2xx_udc_mach_info *mach;
|
struct pxa2xx_udc_mach_info *mach;
|
||||||
|
struct otg_transceiver *transceiver;
|
||||||
u64 dma_mask;
|
u64 dma_mask;
|
||||||
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
|
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user