diff options
author | Philipp Zabel <philipp.zabel@gmail.com> | 2009-07-01 06:46:25 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:23 -0400 |
commit | ab26d20f3ef1105d889f702cd01fba8c6fb32f73 (patch) | |
tree | afe07b1938e05f83b5824feaa3a4d8e6d8bdce64 | |
parent | 4c6e8971cbe0148085fcf6fd30eaa3c39f8a8cce (diff) |
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>
-rw-r--r-- | drivers/usb/gadget/pxa25x_udc.c | 49 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa25x_udc.h | 1 |
2 files changed, 46 insertions, 4 deletions
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index ed21e263f832..e6fedbd5a654 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c | |||
@@ -56,6 +56,7 @@ | |||
56 | 56 | ||
57 | #include <linux/usb/ch9.h> | 57 | #include <linux/usb/ch9.h> |
58 | #include <linux/usb/gadget.h> | 58 | #include <linux/usb/gadget.h> |
59 | #include <linux/usb/otg.h> | ||
59 | 60 | ||
60 | /* | 61 | /* |
61 | * This driver is PXA25x only. Grab the right register definitions. | 62 | * 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) | |||
1008 | return 0; | 1009 | return 0; |
1009 | } | 1010 | } |
1010 | 1011 | ||
1012 | /* boards may consume current from VBUS, up to 100-500mA based on config. | ||
1013 | * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs | ||
1014 | * violate USB specs. | ||
1015 | */ | ||
1016 | static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) | ||
1017 | { | ||
1018 | struct pxa25x_udc *udc; | ||
1019 | |||
1020 | udc = container_of(_gadget, struct pxa25x_udc, gadget); | ||
1021 | |||
1022 | if (udc->transceiver) | ||
1023 | return otg_set_power(udc->transceiver, mA); | ||
1024 | return -EOPNOTSUPP; | ||
1025 | } | ||
1026 | |||
1011 | static const struct usb_gadget_ops pxa25x_udc_ops = { | 1027 | static const struct usb_gadget_ops pxa25x_udc_ops = { |
1012 | .get_frame = pxa25x_udc_get_frame, | 1028 | .get_frame = pxa25x_udc_get_frame, |
1013 | .wakeup = pxa25x_udc_wakeup, | 1029 | .wakeup = pxa25x_udc_wakeup, |
1014 | .vbus_session = pxa25x_udc_vbus_session, | 1030 | .vbus_session = pxa25x_udc_vbus_session, |
1015 | .pullup = pxa25x_udc_pullup, | 1031 | .pullup = pxa25x_udc_pullup, |
1016 | 1032 | .vbus_draw = pxa25x_udc_vbus_draw, | |
1017 | // .vbus_draw ... boards may consume current from VBUS, up to | ||
1018 | // 100-500mA based on config. the 500uA suspend ceiling means | ||
1019 | // that exclusively vbus-powered PXA designs violate USB specs. | ||
1020 | }; | 1033 | }; |
1021 | 1034 | ||
1022 | /*-------------------------------------------------------------------------*/ | 1035 | /*-------------------------------------------------------------------------*/ |
@@ -1303,9 +1316,23 @@ fail: | |||
1303 | * for set_configuration as well as eventual disconnect. | 1316 | * for set_configuration as well as eventual disconnect. |
1304 | */ | 1317 | */ |
1305 | DMSG("registered gadget driver '%s'\n", driver->driver.name); | 1318 | DMSG("registered gadget driver '%s'\n", driver->driver.name); |
1319 | |||
1320 | /* connect to bus through transceiver */ | ||
1321 | if (dev->transceiver) { | ||
1322 | retval = otg_set_peripheral(dev->transceiver, &dev->gadget); | ||
1323 | if (retval) { | ||
1324 | DMSG("can't bind to transceiver\n"); | ||
1325 | if (driver->unbind) | ||
1326 | driver->unbind(&dev->gadget); | ||
1327 | goto bind_fail; | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1306 | pullup(dev); | 1331 | pullup(dev); |
1307 | dump_state(dev); | 1332 | dump_state(dev); |
1308 | return 0; | 1333 | return 0; |
1334 | bind_fail: | ||
1335 | return retval; | ||
1309 | } | 1336 | } |
1310 | EXPORT_SYMBOL(usb_gadget_register_driver); | 1337 | EXPORT_SYMBOL(usb_gadget_register_driver); |
1311 | 1338 | ||
@@ -1351,6 +1378,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | |||
1351 | stop_activity(dev, driver); | 1378 | stop_activity(dev, driver); |
1352 | local_irq_enable(); | 1379 | local_irq_enable(); |
1353 | 1380 | ||
1381 | if (dev->transceiver) | ||
1382 | (void) otg_set_peripheral(dev->transceiver, NULL); | ||
1383 | |||
1354 | driver->unbind(&dev->gadget); | 1384 | driver->unbind(&dev->gadget); |
1355 | dev->gadget.dev.driver = NULL; | 1385 | dev->gadget.dev.driver = NULL; |
1356 | dev->driver = NULL; | 1386 | dev->driver = NULL; |
@@ -2162,6 +2192,8 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) | |||
2162 | dev->dev = &pdev->dev; | 2192 | dev->dev = &pdev->dev; |
2163 | dev->mach = pdev->dev.platform_data; | 2193 | dev->mach = pdev->dev.platform_data; |
2164 | 2194 | ||
2195 | dev->transceiver = otg_get_transceiver(); | ||
2196 | |||
2165 | if (gpio_is_valid(dev->mach->gpio_vbus)) { | 2197 | if (gpio_is_valid(dev->mach->gpio_vbus)) { |
2166 | if ((retval = gpio_request(dev->mach->gpio_vbus, | 2198 | if ((retval = gpio_request(dev->mach->gpio_vbus, |
2167 | "pxa25x_udc GPIO VBUS"))) { | 2199 | "pxa25x_udc GPIO VBUS"))) { |
@@ -2264,6 +2296,10 @@ lubbock_fail0: | |||
2264 | if (gpio_is_valid(dev->mach->gpio_vbus)) | 2296 | if (gpio_is_valid(dev->mach->gpio_vbus)) |
2265 | gpio_free(dev->mach->gpio_vbus); | 2297 | gpio_free(dev->mach->gpio_vbus); |
2266 | err_gpio_vbus: | 2298 | err_gpio_vbus: |
2299 | if (dev->transceiver) { | ||
2300 | otg_put_transceiver(dev->transceiver); | ||
2301 | dev->transceiver = NULL; | ||
2302 | } | ||
2267 | clk_put(dev->clk); | 2303 | clk_put(dev->clk); |
2268 | err_clk: | 2304 | err_clk: |
2269 | return retval; | 2305 | return retval; |
@@ -2305,6 +2341,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) | |||
2305 | 2341 | ||
2306 | clk_put(dev->clk); | 2342 | clk_put(dev->clk); |
2307 | 2343 | ||
2344 | if (dev->transceiver) { | ||
2345 | otg_put_transceiver(dev->transceiver); | ||
2346 | dev->transceiver = NULL; | ||
2347 | } | ||
2348 | |||
2308 | platform_set_drvdata(pdev, NULL); | 2349 | platform_set_drvdata(pdev, NULL); |
2309 | the_controller = NULL; | 2350 | the_controller = NULL; |
2310 | return 0; | 2351 | return 0; |
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 1d51aa21e6eb..f572c5617462 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h | |||
@@ -128,6 +128,7 @@ struct pxa25x_udc { | |||
128 | struct device *dev; | 128 | struct device *dev; |
129 | struct clk *clk; | 129 | struct clk *clk; |
130 | struct pxa2xx_udc_mach_info *mach; | 130 | struct pxa2xx_udc_mach_info *mach; |
131 | struct otg_transceiver *transceiver; | ||
131 | u64 dma_mask; | 132 | u64 dma_mask; |
132 | struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS]; | 133 | struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS]; |
133 | 134 | ||