diff options
Diffstat (limited to 'drivers/usb/gadget/pxa25x_udc.c')
| -rw-r--r-- | drivers/usb/gadget/pxa25x_udc.c | 279 | 
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");  | 
