diff options
Diffstat (limited to 'drivers/usb/gadget/atmel_usba_udc.c')
| -rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.c | 517 | 
1 files changed, 276 insertions, 241 deletions
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index b5e20e873cb..76023ce449a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -21,16 +21,14 @@  #include <linux/usb/gadget.h>  #include <linux/usb/atmel_usba_udc.h>  #include <linux/delay.h> +#include <linux/platform_data/atmel.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include <asm/gpio.h> -#include <mach/board.h>  #include "atmel_usba_udc.h" - -static struct usba_udc the_udc; -static struct usba_ep *usba_ep; -  #ifdef CONFIG_USB_GADGET_DEBUG_FS  #include <linux/debugfs.h>  #include <linux/uaccess.h> @@ -93,7 +91,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,  	if (!access_ok(VERIFY_WRITE, buf, nbytes))  		return -EFAULT; -	mutex_lock(&file->f_dentry->d_inode->i_mutex); +	mutex_lock(&file_inode(file)->i_mutex);  	list_for_each_entry_safe(req, tmp_req, queue, queue) {  		len = snprintf(tmpbuf, sizeof(tmpbuf),  				"%8p %08x %c%c%c %5d %c%c%c\n", @@ -120,7 +118,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,  		nbytes -= len;  		buf += len;  	} -	mutex_unlock(&file->f_dentry->d_inode->i_mutex); +	mutex_unlock(&file_inode(file)->i_mutex);  	return actual;  } @@ -168,13 +166,13 @@ out:  static ssize_t regs_dbg_read(struct file *file, char __user *buf,  		size_t nbytes, loff_t *ppos)  { -	struct inode *inode = file->f_dentry->d_inode; +	struct inode *inode = file_inode(file);  	int ret;  	mutex_lock(&inode->i_mutex);  	ret = simple_read_from_buffer(buf, nbytes, ppos,  			file->private_data, -			file->f_dentry->d_inode->i_size); +			file_inode(file)->i_size);  	mutex_unlock(&inode->i_mutex);  	return ret; @@ -272,7 +270,7 @@ static void usba_init_debugfs(struct usba_udc *udc)  	regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,  				CTRL_IOMEM_ID); -	regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; +	regs->d_inode->i_size = resource_size(regs_resource);  	udc->debugfs_regs = regs;  	usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); @@ -328,16 +326,16 @@ static int vbus_is_present(struct usba_udc *udc)  #if defined(CONFIG_ARCH_AT91SAM9RL) -#include <mach/at91_pmc.h> +#include <linux/clk/at91_pmc.h>  static void toggle_bias(int is_on)  { -	unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); +	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);  	if (is_on) -		at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); +		at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);  	else -		at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); +		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));  }  #else @@ -489,13 +487,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)  	if (req->req.status == -EINPROGRESS)  		req->req.status = status; -	if (req->mapped) { -		dma_unmap_single( -			&udc->pdev->dev, req->req.dma, req->req.length, -			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -		req->req.dma = DMA_ADDR_INVALID; -		req->mapped = 0; -	} +	if (req->using_dma) +		usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);  	DBG(DBG_GADGET | DBG_REQ,  		"%s: req %p complete: status %d, actual %u\n", @@ -527,7 +520,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); -	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; +	maxpacket = usb_endpoint_maxp(desc) & 0x7ff;  	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)  			|| ep->index == 0 @@ -571,7 +564,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  		 * Bits 11:12 specify number of _additional_  		 * transactions per microframe.  		 */ -		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; +		nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;  		if (nr_trans > 3)  			return -EINVAL; @@ -599,13 +592,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  	spin_lock_irqsave(&ep->udc->lock, flags); -	if (ep->desc) { -		spin_unlock_irqrestore(&ep->udc->lock, flags); -		DBG(DBG_ERR, "ep%d already enabled\n", ep->index); -		return -EBUSY; -	} - -	ep->desc = desc; +	ep->ep.desc = desc;  	ep->ep.maxpacket = maxpacket;  	usba_ep_writel(ep, CFG, ept_cfg); @@ -647,7 +634,7 @@ static int usba_ep_disable(struct usb_ep *_ep)  	spin_lock_irqsave(&udc->lock, flags); -	if (!ep->desc) { +	if (!ep->ep.desc) {  		spin_unlock_irqrestore(&udc->lock, flags);  		/* REVISIT because this driver disables endpoints in  		 * reset_all_endpoints() before calling disconnect(), @@ -658,7 +645,7 @@ static int usba_ep_disable(struct usb_ep *_ep)  					ep->ep.name);  		return -EINVAL;  	} -	ep->desc = NULL; +	ep->ep.desc = NULL;  	list_splice_init(&ep->queue, &req_list);  	if (ep->can_dma) { @@ -690,7 +677,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)  		return NULL;  	INIT_LIST_HEAD(&req->queue); -	req->req.dma = DMA_ADDR_INVALID;  	return &req->req;  } @@ -723,20 +709,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,  		return -EINVAL;  	} -	req->using_dma = 1; - -	if (req->req.dma == DMA_ADDR_INVALID) { -		req->req.dma = dma_map_single( -			&udc->pdev->dev, req->req.buf, req->req.length, -			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -		req->mapped = 1; -	} else { -		dma_sync_single_for_device( -			&udc->pdev->dev, req->req.dma, req->req.length, -			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -		req->mapped = 0; -	} +	ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in); +	if (ret) +		return ret; +	req->using_dma = 1;  	req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)  			| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE  			| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; @@ -751,7 +728,7 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,  	 */  	ret = -ESHUTDOWN;  	spin_lock_irqsave(&udc->lock, flags); -	if (ep->desc) { +	if (ep->ep.desc) {  		if (list_empty(&ep->queue))  			submit_request(ep, req); @@ -775,7 +752,8 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)  	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",  			ep->ep.name, req, _req->length); -	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) +	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || +	    !ep->ep.desc)  		return -ESHUTDOWN;  	req->submitted = 0; @@ -791,7 +769,7 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)  	/* May have received a reset since last time we checked */  	ret = -ESHUTDOWN;  	spin_lock_irqsave(&udc->lock, flags); -	if (ep->desc) { +	if (ep->ep.desc) {  		list_add_tail(&req->queue, &ep->queue);  		if ((!ep_is_control(ep) && ep->is_in) || @@ -904,7 +882,7 @@ static int usba_ep_set_halt(struct usb_ep *_ep, int value)  	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,  			value ? "set" : "clear"); -	if (!ep->desc) { +	if (!ep->ep.desc) {  		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",  				ep->ep.name);  		return -ENODEV; @@ -1007,10 +985,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)  	return 0;  } +static int atmel_usba_start(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver); +static int atmel_usba_stop(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver);  static const struct usb_gadget_ops usba_udc_ops = {  	.get_frame		= usba_udc_get_frame,  	.wakeup			= usba_udc_wakeup,  	.set_selfpowered	= usba_udc_set_selfpowered, +	.udc_start		= atmel_usba_start, +	.udc_stop		= atmel_usba_stop,  };  static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1028,16 +1012,13 @@ static void nop_release(struct device *dev)  } -static struct usba_udc the_udc = { -	.gadget	= { -		.ops		= &usba_udc_ops, -		.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list), -		.is_dualspeed	= 1, -		.name		= "atmel_usba_udc", -		.dev	= { -			.init_name	= "gadget", -			.release	= nop_release, -		}, +static struct usb_gadget usba_gadget_template = { +	.ops		= &usba_udc_ops, +	.max_speed	= USB_SPEED_HIGH, +	.name		= "atmel_usba_udc", +	.dev	= { +		.init_name	= "gadget", +		.release	= nop_release,  	},  }; @@ -1064,7 +1045,7 @@ static void reset_all_endpoints(struct usba_udc *udc)  	 * FIXME remove this code ... and retest thoroughly.  	 */  	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { -		if (ep->desc) { +		if (ep->ep.desc) {  			spin_unlock(&udc->lock);  			usba_ep_disable(&ep->ep);  			spin_lock(&udc->lock); @@ -1082,9 +1063,9 @@ static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)  	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {  		u8 bEndpointAddress; -		if (!ep->desc) +		if (!ep->ep.desc)  			continue; -		bEndpointAddress = ep->desc->bEndpointAddress; +		bEndpointAddress = ep->ep.desc->bEndpointAddress;  		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)  			continue;  		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) @@ -1161,7 +1142,7 @@ static int do_test_mode(struct usba_udc *udc)  		 * Test_SE0_NAK: Force high-speed mode and set up ep0  		 * for Bulk IN transfers  		 */ -		ep = &usba_ep[0]; +		ep = &udc->usba_ep[0];  		usba_writel(udc, TST,  				USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));  		usba_ep_writel(ep, CFG, @@ -1179,7 +1160,7 @@ static int do_test_mode(struct usba_udc *udc)  		break;  	case 0x0400:  		/* Test_Packet */ -		ep = &usba_ep[0]; +		ep = &udc->usba_ep[0];  		usba_ep_writel(ep, CFG,  				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)  				| USBA_EPT_DIR_IN @@ -1680,21 +1661,21 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  	if (dma_status) {  		int i; -		for (i = 1; i < USBA_NR_ENDPOINTS; i++) +		for (i = 1; i < USBA_NR_DMAS; i++)  			if (dma_status & (1 << i)) -				usba_dma_irq(udc, &usba_ep[i]); +				usba_dma_irq(udc, &udc->usba_ep[i]);  	}  	ep_status = USBA_BFEXT(EPT_INT, status);  	if (ep_status) {  		int i; -		for (i = 0; i < USBA_NR_ENDPOINTS; i++) +		for (i = 0; i < udc->num_ep; i++)  			if (ep_status & (1 << i)) { -				if (ep_is_control(&usba_ep[i])) -					usba_control_irq(udc, &usba_ep[i]); +				if (ep_is_control(&udc->usba_ep[i])) +					usba_control_irq(udc, &udc->usba_ep[i]);  				else -					usba_ep_irq(udc, &usba_ep[i]); +					usba_ep_irq(udc, &udc->usba_ep[i]);  			}  	} @@ -1705,23 +1686,22 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  		reset_all_endpoints(udc);  		if (udc->gadget.speed != USB_SPEED_UNKNOWN -				&& udc->driver->disconnect) { +				&& udc->driver && udc->driver->disconnect) {  			udc->gadget.speed = USB_SPEED_UNKNOWN;  			spin_unlock(&udc->lock);  			udc->driver->disconnect(&udc->gadget);  			spin_lock(&udc->lock);  		} -		if (status & USBA_HIGH_SPEED) { -			DBG(DBG_BUS, "High-speed bus reset detected\n"); +		if (status & USBA_HIGH_SPEED)  			udc->gadget.speed = USB_SPEED_HIGH; -		} else { -			DBG(DBG_BUS, "Full-speed bus reset detected\n"); +		else  			udc->gadget.speed = USB_SPEED_FULL; -		} +		DBG(DBG_BUS, "%s bus reset detected\n", +		    usb_speed_string(udc->gadget.speed)); -		ep0 = &usba_ep[0]; -		ep0->desc = &usba_ep0_desc; +		ep0 = &udc->usba_ep[0]; +		ep0->ep.desc = &usba_ep0_desc;  		ep0->state = WAIT_FOR_SETUP;  		usba_ep_writel(ep0, CFG,  				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE) @@ -1789,35 +1769,26 @@ out:  	return IRQ_HANDLED;  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, -		int (*bind)(struct usb_gadget *)) +static int atmel_usba_start(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver)  { -	struct usba_udc *udc = &the_udc; -	unsigned long flags;  	int ret; - -	if (!udc->pdev) -		return -ENODEV; +	struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); +	unsigned long flags;  	spin_lock_irqsave(&udc->lock, flags); -	if (udc->driver) { -		spin_unlock_irqrestore(&udc->lock, flags); -		return -EBUSY; -	}  	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;  	udc->driver = driver; -	udc->gadget.dev.driver = &driver->driver;  	spin_unlock_irqrestore(&udc->lock, flags); -	clk_enable(udc->pclk); -	clk_enable(udc->hclk); - -	ret = bind(&udc->gadget); +	ret = clk_prepare_enable(udc->pclk); +	if (ret) +		return ret; +	ret = clk_prepare_enable(udc->hclk);  	if (ret) { -		DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", -			driver->driver.name, ret); -		goto err_driver_bind; +		clk_disable_unprepare(udc->pclk); +		return ret;  	}  	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); @@ -1836,24 +1807,14 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	spin_unlock_irqrestore(&udc->lock, flags);  	return 0; - -err_driver_bind: -	udc->driver = NULL; -	udc->gadget.dev.driver = NULL; -	return ret;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver)  { -	struct usba_udc *udc = &the_udc; +	struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);  	unsigned long flags; -	if (!udc->pdev) -		return -ENODEV; -	if (driver != udc->driver || !driver->unbind) -		return -EINVAL; -  	if (gpio_is_valid(udc->vbus_pin))  		disable_irq(gpio_to_irq(udc->vbus_pin)); @@ -1866,47 +1827,187 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); -	if (udc->driver->disconnect) -		udc->driver->disconnect(&udc->gadget); +	clk_disable_unprepare(udc->hclk); +	clk_disable_unprepare(udc->pclk); + +	DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name); -	driver->unbind(&udc->gadget); -	udc->gadget.dev.driver = NULL;  	udc->driver = NULL; -	clk_disable(udc->hclk); -	clk_disable(udc->pclk); +	return 0; +} -	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); +#ifdef CONFIG_OF +static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, +						    struct usba_udc *udc) +{ +	u32 val; +	const char *name; +	enum of_gpio_flags flags; +	struct device_node *np = pdev->dev.of_node; +	struct device_node *pp; +	int i, ret; +	struct usba_ep *eps, *ep; + +	udc->num_ep = 0; + +	udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0, +						&flags); +	udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; + +	pp = NULL; +	while ((pp = of_get_next_child(np, pp))) +		udc->num_ep++; + +	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep, +			   GFP_KERNEL); +	if (!eps) +		return ERR_PTR(-ENOMEM); + +	udc->gadget.ep0 = &eps[0].ep; + +	INIT_LIST_HEAD(&eps[0].ep.ep_list); + +	pp = NULL; +	i = 0; +	while ((pp = of_get_next_child(np, pp))) { +		ep = &eps[i]; + +		ret = of_property_read_u32(pp, "reg", &val); +		if (ret) { +			dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret); +			goto err; +		} +		ep->index = val; -	return 0; +		ret = of_property_read_u32(pp, "atmel,fifo-size", &val); +		if (ret) { +			dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret); +			goto err; +		} +		ep->fifo_size = val; + +		ret = of_property_read_u32(pp, "atmel,nb-banks", &val); +		if (ret) { +			dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret); +			goto err; +		} +		ep->nr_banks = val; + +		ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); +		ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); + +		ret = of_property_read_string(pp, "name", &name); +		ep->ep.name = name; + +		ep->ep_regs = udc->regs + USBA_EPT_BASE(i); +		ep->dma_regs = udc->regs + USBA_DMA_BASE(i); +		ep->fifo = udc->fifo + USBA_FIFO_BASE(i); +		ep->ep.ops = &usba_ep_ops; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); +		ep->udc = udc; +		INIT_LIST_HEAD(&ep->queue); + +		if (i) +			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + +		i++; +	} + +	if (i == 0) { +		dev_err(&pdev->dev, "of_probe: no endpoint specified\n"); +		ret = -EINVAL; +		goto err; +	} + +	return eps; +err: +	return ERR_PTR(ret); +} +#else +static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, +						    struct usba_udc *udc) +{ +	return ERR_PTR(-ENOSYS); +} +#endif + +static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, +						 struct usba_udc *udc) +{ +	struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev); +	struct usba_ep *eps; +	int i; + +	if (!pdata) +		return ERR_PTR(-ENXIO); + +	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * pdata->num_ep, +			   GFP_KERNEL); +	if (!eps) +		return ERR_PTR(-ENOMEM); + +	udc->gadget.ep0 = &eps[0].ep; + +	udc->vbus_pin = pdata->vbus_pin; +	udc->vbus_pin_inverted = pdata->vbus_pin_inverted; +	udc->num_ep = pdata->num_ep; + +	INIT_LIST_HEAD(&eps[0].ep.ep_list); + +	for (i = 0; i < pdata->num_ep; i++) { +		struct usba_ep *ep = &eps[i]; + +		ep->ep_regs = udc->regs + USBA_EPT_BASE(i); +		ep->dma_regs = udc->regs + USBA_DMA_BASE(i); +		ep->fifo = udc->fifo + USBA_FIFO_BASE(i); +		ep->ep.ops = &usba_ep_ops; +		ep->ep.name = pdata->ep[i].name; +		ep->fifo_size = pdata->ep[i].fifo_size; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); +		ep->udc = udc; +		INIT_LIST_HEAD(&ep->queue); +		ep->nr_banks = pdata->ep[i].nr_banks; +		ep->index = pdata->ep[i].index; +		ep->can_dma = pdata->ep[i].can_dma; +		ep->can_isoc = pdata->ep[i].can_isoc; + +		if (i) +			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); +	} + +	return eps;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static int __init usba_udc_probe(struct platform_device *pdev)  { -	struct usba_platform_data *pdata = pdev->dev.platform_data;  	struct resource *regs, *fifo;  	struct clk *pclk, *hclk; -	struct usba_udc *udc = &the_udc; +	struct usba_udc *udc;  	int irq, ret, i; +	udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); +	if (!udc) +		return -ENOMEM; + +	udc->gadget = usba_gadget_template; +	INIT_LIST_HEAD(&udc->gadget.ep_list); +  	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);  	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); -	if (!regs || !fifo || !pdata) +	if (!regs || !fifo)  		return -ENXIO;  	irq = platform_get_irq(pdev, 0);  	if (irq < 0)  		return irq; -	pclk = clk_get(&pdev->dev, "pclk"); +	pclk = devm_clk_get(&pdev->dev, "pclk");  	if (IS_ERR(pclk))  		return PTR_ERR(pclk); -	hclk = clk_get(&pdev->dev, "hclk"); -	if (IS_ERR(hclk)) { -		ret = PTR_ERR(hclk); -		goto err_get_hclk; -	} +	hclk = devm_clk_get(&pdev->dev, "hclk"); +	if (IS_ERR(hclk)) +		return PTR_ERR(hclk);  	spin_lock_init(&udc->lock);  	udc->pdev = pdev; @@ -1915,99 +2016,57 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	udc->vbus_pin = -ENODEV;  	ret = -ENOMEM; -	udc->regs = ioremap(regs->start, resource_size(regs)); +	udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));  	if (!udc->regs) {  		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); -		goto err_map_regs; +		return ret;  	}  	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",  		 (unsigned long)regs->start, udc->regs); -	udc->fifo = ioremap(fifo->start, resource_size(fifo)); +	udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo));  	if (!udc->fifo) {  		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); -		goto err_map_fifo; +		return ret;  	}  	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",  		 (unsigned long)fifo->start, udc->fifo); -	device_initialize(&udc->gadget.dev); -	udc->gadget.dev.parent = &pdev->dev; -	udc->gadget.dev.dma_mask = pdev->dev.dma_mask; -  	platform_set_drvdata(pdev, udc);  	/* Make sure we start from a clean slate */ -	clk_enable(pclk); +	ret = clk_prepare_enable(pclk); +	if (ret) { +		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n"); +		return ret; +	}  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); -	clk_disable(pclk); - -	usba_ep = kzalloc(sizeof(struct usba_ep) * pdata->num_ep, -			  GFP_KERNEL); -	if (!usba_ep) -		goto err_alloc_ep; - -	the_udc.gadget.ep0 = &usba_ep[0].ep; - -	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); -	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); -	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); -	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); -	usba_ep[0].ep.ops = &usba_ep_ops; -	usba_ep[0].ep.name = pdata->ep[0].name; -	usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size; -	usba_ep[0].udc = &the_udc; -	INIT_LIST_HEAD(&usba_ep[0].queue); -	usba_ep[0].fifo_size = pdata->ep[0].fifo_size; -	usba_ep[0].nr_banks = pdata->ep[0].nr_banks; -	usba_ep[0].index = pdata->ep[0].index; -	usba_ep[0].can_dma = pdata->ep[0].can_dma; -	usba_ep[0].can_isoc = pdata->ep[0].can_isoc; - -	for (i = 1; i < pdata->num_ep; i++) { -		struct usba_ep *ep = &usba_ep[i]; +	clk_disable_unprepare(pclk); -		ep->ep_regs = udc->regs + USBA_EPT_BASE(i); -		ep->dma_regs = udc->regs + USBA_DMA_BASE(i); -		ep->fifo = udc->fifo + USBA_FIFO_BASE(i); -		ep->ep.ops = &usba_ep_ops; -		ep->ep.name = pdata->ep[i].name; -		ep->ep.maxpacket = pdata->ep[i].fifo_size; -		ep->udc = &the_udc; -		INIT_LIST_HEAD(&ep->queue); -		ep->fifo_size = pdata->ep[i].fifo_size; -		ep->nr_banks = pdata->ep[i].nr_banks; -		ep->index = pdata->ep[i].index; -		ep->can_dma = pdata->ep[i].can_dma; -		ep->can_isoc = pdata->ep[i].can_isoc; +	if (pdev->dev.of_node) +		udc->usba_ep = atmel_udc_of_init(pdev, udc); +	else +		udc->usba_ep = usba_udc_pdata(pdev, udc); -		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); -	} +	if (IS_ERR(udc->usba_ep)) +		return PTR_ERR(udc->usba_ep); -	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); +	ret = devm_request_irq(&pdev->dev, irq, usba_udc_irq, 0, +				"atmel_usba_udc", udc);  	if (ret) {  		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",  			irq, ret); -		goto err_request_irq; +		return ret;  	}  	udc->irq = irq; -	ret = device_add(&udc->gadget.dev); -	if (ret) { -		dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); -		goto err_device_add; -	} - -	if (gpio_is_valid(pdata->vbus_pin)) { -		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { -			udc->vbus_pin = pdata->vbus_pin; -			udc->vbus_pin_inverted = pdata->vbus_pin_inverted; - -			ret = request_irq(gpio_to_irq(udc->vbus_pin), +	if (gpio_is_valid(udc->vbus_pin)) { +		if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) { +			ret = devm_request_irq(&pdev->dev, +					gpio_to_irq(udc->vbus_pin),  					usba_vbus_irq, 0,  					"atmel_usba_udc", udc);  			if (ret) { -				gpio_free(udc->vbus_pin);  				udc->vbus_pin = -ENODEV;  				dev_warn(&udc->pdev->dev,  					 "failed to request vbus irq; " @@ -2017,82 +2076,58 @@ static int __init usba_udc_probe(struct platform_device *pdev)  			}  		} else {  			/* gpio_request fail so use -EINVAL for gpio_is_valid */ -			ubc->vbus_pin = -EINVAL; +			udc->vbus_pin = -EINVAL;  		}  	} +	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); +	if (ret) +		return ret; +  	usba_init_debugfs(udc); -	for (i = 1; i < pdata->num_ep; i++) -		usba_ep_init_debugfs(udc, &usba_ep[i]); +	for (i = 1; i < udc->num_ep; i++) +		usba_ep_init_debugfs(udc, &udc->usba_ep[i]);  	return 0; - -err_device_add: -	free_irq(irq, udc); -err_request_irq: -	kfree(usba_ep); -err_alloc_ep: -	iounmap(udc->fifo); -err_map_fifo: -	iounmap(udc->regs); -err_map_regs: -	clk_put(hclk); -err_get_hclk: -	clk_put(pclk); - -	platform_set_drvdata(pdev, NULL); - -	return ret;  }  static int __exit usba_udc_remove(struct platform_device *pdev)  {  	struct usba_udc *udc;  	int i; -	struct usba_platform_data *pdata = pdev->dev.platform_data;  	udc = platform_get_drvdata(pdev); -	for (i = 1; i < pdata->num_ep; i++) -		usba_ep_cleanup_debugfs(&usba_ep[i]); -	usba_cleanup_debugfs(udc); - -	if (gpio_is_valid(udc->vbus_pin)) -		gpio_free(udc->vbus_pin); - -	free_irq(udc->irq, udc); -	kfree(usba_ep); -	iounmap(udc->fifo); -	iounmap(udc->regs); -	clk_put(udc->hclk); -	clk_put(udc->pclk); +	usb_del_gadget_udc(&udc->gadget); -	device_unregister(&udc->gadget.dev); +	for (i = 1; i < udc->num_ep; i++) +		usba_ep_cleanup_debugfs(&udc->usba_ep[i]); +	usba_cleanup_debugfs(udc);  	return 0;  } +#if defined(CONFIG_OF) +static const struct of_device_id atmel_udc_dt_ids[] = { +	{ .compatible = "atmel,at91sam9rl-udc" }, +	{ /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids); +#endif +  static struct platform_driver udc_driver = {  	.remove		= __exit_p(usba_udc_remove),  	.driver		= {  		.name		= "atmel_usba_udc",  		.owner		= THIS_MODULE, +		.of_match_table	= of_match_ptr(atmel_udc_dt_ids),  	},  }; -static int __init udc_init(void) -{ -	return platform_driver_probe(&udc_driver, usba_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ -	platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); +module_platform_driver_probe(udc_driver, usba_udc_probe);  MODULE_DESCRIPTION("Atmel USBA UDC driver"); -MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:atmel_usba_udc");  | 
