aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/pxa25x_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/pxa25x_udc.c')
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c279
1 files changed, 77 insertions, 202 deletions
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index b37f92cb71b..9984437d295 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -11,16 +11,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
/* #define VERBOSE_DEBUG */
@@ -31,26 +21,26 @@
#include <linux/ioport.h>
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
+#include <linux/platform_data/pxa2xx_udc.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/irq.h>
#include <linux/clk.h>
-#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/io.h>
+#include <linux/prefetch.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/gpio.h>
-#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
@@ -63,15 +53,13 @@
*/
#ifdef CONFIG_ARCH_PXA
#include <mach/pxa25x-udc.h>
+#include <mach/hardware.h>
#endif
#ifdef CONFIG_ARCH_LUBBOCK
#include <mach/lubbock.h>
#endif
-#include <asm/mach/udc_pxa2xx.h>
-
-
/*
* This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
* series processors. The UDC for the IXP 4xx series is very similar.
@@ -139,24 +127,6 @@ static const char ep0name [] = "ep0";
static void pxa25x_ep_fifo_flush (struct usb_ep *ep);
static void nuke (struct pxa25x_ep *, int status);
-/* one GPIO should be used to detect VBUS from the host */
-static int is_vbus_present(void)
-{
- struct pxa2xx_udc_mach_info *mach = the_controller->mach;
-
- if (gpio_is_valid(mach->gpio_vbus)) {
- int value = gpio_get_value(mach->gpio_vbus);
-
- if (mach->gpio_vbus_inverted)
- return !value;
- else
- return !!value;
- }
- if (mach->udc_is_connected)
- return mach->udc_is_connected();
- return 1;
-}
-
/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static void pullup_off(void)
{
@@ -246,11 +216,10 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
struct pxa25x_udc *dev;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ if (!_ep || !desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
- || ep->fifo_size < le16_to_cpu
- (desc->wMaxPacketSize)) {
+ || ep->fifo_size < usb_endpoint_maxp (desc)) {
DMSG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
@@ -265,7 +234,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
/* hardware _could_ do smaller, but driver doesn't */
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
- && le16_to_cpu (desc->wMaxPacketSize)
+ && usb_endpoint_maxp (desc)
!= BULK_FIFO_SIZE)
|| !desc->wMaxPacketSize) {
DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
@@ -278,10 +247,10 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
return -ESHUTDOWN;
}
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
ep->pio_irqs = 0;
- ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
+ ep->ep.maxpacket = usb_endpoint_maxp (desc);
/* flush fifo (mostly for OUT buffers) */
pxa25x_ep_fifo_flush (_ep);
@@ -298,7 +267,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
unsigned long flags;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
DMSG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
@@ -310,7 +279,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
/* flush fifo (mostly for IN buffers) */
pxa25x_ep_fifo_flush (_ep);
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
local_irq_restore(flags);
@@ -418,7 +387,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
{
unsigned max;
- max = le16_to_cpu(ep->desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(ep->ep.desc);
do {
unsigned count;
int is_last, is_short;
@@ -672,7 +641,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
ep = container_of(_ep, struct pxa25x_ep, ep);
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
}
@@ -688,8 +657,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- && req->req.length > le16_to_cpu
- (ep->desc->wMaxPacketSize)))
+ && req->req.length > usb_endpoint_maxp(ep->ep.desc)))
return -EMSGSIZE;
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -702,7 +670,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
- if (ep->desc == NULL/* ep0 */) {
+ if (ep->ep.desc == NULL/* ep0 */) {
unsigned length = _req->length;
switch (dev->ep0state) {
@@ -751,7 +719,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
- if (likely (req && ep->desc))
+ if (likely(req && ep->ep.desc))
pio_irq_enable(ep->bEndpointAddress);
}
@@ -778,7 +746,7 @@ static void nuke(struct pxa25x_ep *ep, int status)
queue);
done(ep, req, status);
}
- if (ep->desc)
+ if (ep->ep.desc)
pio_irq_disable (ep->bEndpointAddress);
}
@@ -821,7 +789,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct pxa25x_ep, ep);
if (unlikely (!_ep
- || (!ep->desc && ep->ep.name != ep0name))
+ || (!ep->ep.desc && ep->ep.name != ep0name))
|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
@@ -849,7 +817,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
*ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
/* ep0 needs special care */
- if (!ep->desc) {
+ if (!ep->ep.desc) {
start_watchdog(ep->dev);
ep->dev->req_pending = 0;
ep->dev->ep0state = EP0_STALL;
@@ -1023,17 +991,24 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
udc = container_of(_gadget, struct pxa25x_udc, gadget);
- if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ if (!IS_ERR_OR_NULL(udc->transceiver))
+ return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
+static int pxa25x_udc_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
+static int pxa25x_udc_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops pxa25x_udc_ops = {
.get_frame = pxa25x_udc_get_frame,
.wakeup = pxa25x_udc_wakeup,
.vbus_session = pxa25x_udc_vbus_session,
.pullup = pxa25x_udc_pullup,
.vbus_draw = pxa25x_udc_vbus_draw,
+ .udc_start = pxa25x_udc_start,
+ .udc_stop = pxa25x_udc_stop,
};
/*-------------------------------------------------------------------------*/
@@ -1055,7 +1030,7 @@ udc_seq_show(struct seq_file *m, void *_d)
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR "(pio)",
dev->driver ? dev->driver->driver.name : "(none)",
- is_vbus_present() ? "full speed" : "disconnected");
+ dev->gadget.speed == USB_SPEED_FULL ? "full speed" : "disconnected");
/* registers for device and ep0 */
seq_printf(m,
@@ -1094,7 +1069,7 @@ udc_seq_show(struct seq_file *m, void *_d)
(tmp & UDCCFR_ACM) ? " acm" : "");
}
- if (!is_vbus_present() || !dev->driver)
+ if (dev->gadget.speed != USB_SPEED_FULL || !dev->driver)
goto done;
seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
@@ -1110,13 +1085,13 @@ udc_seq_show(struct seq_file *m, void *_d)
if (i != 0) {
const struct usb_endpoint_descriptor *desc;
- desc = ep->desc;
+ desc = ep->ep.desc;
if (!desc)
continue;
tmp = *dev->ep [i].reg_udccs;
seq_printf(m,
"%s max %d %s udccs %02x irqs %lu\n",
- ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
+ ep->ep.name, usb_endpoint_maxp(desc),
"pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
@@ -1214,10 +1189,11 @@ static void udc_reinit(struct pxa25x_udc *dev)
if (i != 0)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
ep->pio_irqs = 0;
+ usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);
}
/* the rest was statically initialized, and is read-only */
@@ -1280,57 +1256,25 @@ static void udc_enable (struct pxa25x_udc *dev)
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int pxa25x_udc_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
{
- struct pxa25x_udc *dev = the_controller;
+ struct pxa25x_udc *dev = to_pxa25x(g);
int retval;
- if (!driver
- || driver->speed < USB_SPEED_FULL
- || !bind
- || !driver->disconnect
- || !driver->setup)
- return -EINVAL;
- if (!dev)
- return -ENODEV;
- if (dev->driver)
- return -EBUSY;
-
/* first hook up the driver ... */
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1;
- retval = device_add (&dev->gadget.dev);
- if (retval) {
-fail:
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- return retval;
- }
- retval = bind(&dev->gadget);
- if (retval) {
- DMSG("bind to driver %s --> error %d\n",
- driver->driver.name, retval);
- device_del (&dev->gadget.dev);
- goto fail;
- }
-
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
*/
- 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);
+ if (!IS_ERR_OR_NULL(dev->transceiver)) {
+ retval = otg_set_peripheral(dev->transceiver->otg,
+ &dev->gadget);
+ if (retval)
goto bind_fail;
- }
}
pullup(dev);
@@ -1339,7 +1283,6 @@ fail:
bind_fail:
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void
stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
@@ -1368,14 +1311,10 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
udc_reinit(dev);
}
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa25x_udc_stop(struct usb_gadget*g,
+ struct usb_gadget_driver *driver)
{
- struct pxa25x_udc *dev = the_controller;
-
- if (!dev)
- return -ENODEV;
- if (!driver || driver != dev->driver || !driver->unbind)
- return -EINVAL;
+ struct pxa25x_udc *dev = to_pxa25x(g);
local_irq_disable();
dev->pullup = 0;
@@ -1383,21 +1322,15 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
stop_activity(dev, driver);
local_irq_enable();
- if (dev->transceiver)
- (void) otg_set_peripheral(dev->transceiver, NULL);
+ if (!IS_ERR_OR_NULL(dev->transceiver))
+ (void) otg_set_peripheral(dev->transceiver->otg, NULL);
- driver->unbind(&dev->gadget);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
- device_del (&dev->gadget.dev);
-
- DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
dump_state(dev);
+
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -1435,14 +1368,6 @@ lubbock_vbus_irq(int irq, void *_dev)
#endif
-static irqreturn_t udc_vbus_irq(int irq, void *_dev)
-{
- struct pxa25x_udc *dev = _dev;
-
- pxa25x_udc_vbus_session(&dev->gadget, is_vbus_present());
- return IRQ_HANDLED;
-}
-
/*-------------------------------------------------------------------------*/
@@ -1766,12 +1691,9 @@ pxa25x_udc_irq(int irq, void *_dev)
if (unlikely(udccr & UDCCR_SUSIR)) {
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
- DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
- ? "" : "+disconnect");
+ DBG(DBG_VERBOSE, "USB suspend\n");
- if (!is_vbus_present())
- stop_activity(dev, dev->driver);
- else if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
@@ -1786,8 +1708,7 @@ pxa25x_udc_irq(int irq, void *_dev)
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
- && dev->driver->resume
- && is_vbus_present())
+ && dev->driver->resume)
dev->driver->resume(&dev->gadget);
}
@@ -2134,12 +2055,14 @@ static struct pxa25x_udc memory = {
/*
* probe - binds to the platform device
*/
-static int __init pxa25x_udc_probe(struct platform_device *pdev)
+static int pxa25x_udc_probe(struct platform_device *pdev)
{
struct pxa25x_udc *dev = &memory;
- int retval, vbus_irq, irq;
+ int retval, irq;
u32 chiprev;
+ pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
+
/* insist on Intel/ARM/XScale */
asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
@@ -2195,22 +2118,9 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
/* other non-static parts of init */
dev->dev = &pdev->dev;
- dev->mach = pdev->dev.platform_data;
-
- dev->transceiver = otg_get_transceiver();
+ dev->mach = dev_get_platdata(&pdev->dev);
- if (gpio_is_valid(dev->mach->gpio_vbus)) {
- if ((retval = gpio_request(dev->mach->gpio_vbus,
- "pxa25x_udc GPIO VBUS"))) {
- dev_dbg(&pdev->dev,
- "can't get vbus gpio %d, err: %d\n",
- dev->mach->gpio_vbus, retval);
- goto err_gpio_vbus;
- }
- gpio_direction_input(dev->mach->gpio_vbus);
- vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
- } else
- vbus_irq = 0;
+ dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (gpio_is_valid(dev->mach->gpio_pullup)) {
if ((retval = gpio_request(dev->mach->gpio_pullup,
@@ -2227,21 +2137,17 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->timer.function = udc_watchdog;
dev->timer.data = (unsigned long) dev;
- device_initialize(&dev->gadget.dev);
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
the_controller = dev;
platform_set_drvdata(pdev, dev);
udc_disable(dev);
udc_reinit(dev);
- dev->vbus = !!is_vbus_present();
+ dev->vbus = 0;
/* irq setup after old hardware state is cleaned up */
retval = request_irq(irq, pxa25x_udc_irq,
- IRQF_DISABLED, driver_name, dev);
+ 0, driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
@@ -2251,58 +2157,41 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
#ifdef CONFIG_ARCH_LUBBOCK
if (machine_is_lubbock()) {
- retval = request_irq(LUBBOCK_USB_DISC_IRQ,
- lubbock_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- driver_name, dev);
+ retval = request_irq(LUBBOCK_USB_DISC_IRQ, lubbock_vbus_irq,
+ 0, driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
-lubbock_fail0:
goto err_irq_lub;
}
- retval = request_irq(LUBBOCK_USB_IRQ,
- lubbock_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- driver_name, dev);
+ retval = request_irq(LUBBOCK_USB_IRQ, lubbock_vbus_irq,
+ 0, driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_IRQ, retval);
- free_irq(LUBBOCK_USB_DISC_IRQ, dev);
goto lubbock_fail0;
}
} else
#endif
- if (vbus_irq) {
- retval = request_irq(vbus_irq, udc_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- driver_name, dev);
- if (retval != 0) {
- pr_err("%s: can't get irq %i, err %d\n",
- driver_name, vbus_irq, retval);
- goto err_vbus_irq;
- }
- }
create_debug_files(dev);
- return 0;
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (!retval)
+ return retval;
- err_vbus_irq:
+ remove_debug_files(dev);
#ifdef CONFIG_ARCH_LUBBOCK
+lubbock_fail0:
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
err_irq_lub:
-#endif
free_irq(irq, dev);
+#endif
err_irq1:
if (gpio_is_valid(dev->mach->gpio_pullup))
gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup:
- if (gpio_is_valid(dev->mach->gpio_vbus))
- gpio_free(dev->mach->gpio_vbus);
- err_gpio_vbus:
- if (dev->transceiver) {
- otg_put_transceiver(dev->transceiver);
+ if (!IS_ERR_OR_NULL(dev->transceiver)) {
+ usb_put_phy(dev->transceiver);
dev->transceiver = NULL;
}
clk_put(dev->clk);
@@ -2315,13 +2204,14 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)
pullup_off();
}
-static int __exit pxa25x_udc_remove(struct platform_device *pdev)
+static int pxa25x_udc_remove(struct platform_device *pdev)
{
struct pxa25x_udc *dev = platform_get_drvdata(pdev);
if (dev->driver)
return -EBUSY;
+ usb_del_gadget_udc(&dev->gadget);
dev->pullup = 0;
pullup(dev);
@@ -2337,21 +2227,16 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
- if (gpio_is_valid(dev->mach->gpio_vbus)) {
- free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
- gpio_free(dev->mach->gpio_vbus);
- }
if (gpio_is_valid(dev->mach->gpio_pullup))
gpio_free(dev->mach->gpio_pullup);
clk_put(dev->clk);
- if (dev->transceiver) {
- otg_put_transceiver(dev->transceiver);
+ if (!IS_ERR_OR_NULL(dev->transceiver)) {
+ usb_put_phy(dev->transceiver);
dev->transceiver = NULL;
}
- platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
}
@@ -2410,7 +2295,8 @@ static int pxa25x_udc_resume(struct platform_device *dev)
static struct platform_driver udc_driver = {
.shutdown = pxa25x_udc_shutdown,
- .remove = __exit_p(pxa25x_udc_remove),
+ .probe = pxa25x_udc_probe,
+ .remove = pxa25x_udc_remove,
.suspend = pxa25x_udc_suspend,
.resume = pxa25x_udc_resume,
.driver = {
@@ -2419,18 +2305,7 @@ static struct platform_driver udc_driver = {
},
};
-static int __init udc_init(void)
-{
- pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
- return platform_driver_probe(&udc_driver, pxa25x_udc_probe);
-}
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
+module_platform_driver(udc_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");