diff options
author | Tom Rini <trini@konsulko.com> | 2024-08-20 08:08:52 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-08-20 08:08:52 -0600 |
commit | d2067c3ea54199ac7c09232cd5551901c75af511 (patch) | |
tree | e114c54764db936f5fd44e4b85f5ca42aab3ba3e | |
parent | 158cf0270cb6691bc7f58fbeb4c6b8b603957bfe (diff) | |
parent | 73f5b54a589cb6ff97aaca55e7c97d68b43997ee (diff) |
Merge tag 'u-boot-dfu-next-20240820' of https://source.denx.de/u-boot/custodians/u-boot-dfu into next
u-boot-dfu-next-20240820
- Migrate Atmel usb gadget to DM_USB_GADGET
- More small cleanups/improvements on the atmel UDC driver
- Change udc uclass name from "usb" -> "usb_gadget"
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.c | 256 | ||||
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.h | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/udc-uclass.c | 2 | ||||
-rw-r--r-- | include/linux/usb/atmel_usba_udc.h | 2 |
4 files changed, 215 insertions, 48 deletions
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f99553df8d4..a77037a7094 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -7,16 +7,28 @@ * Bo Shen <voice.shen@atmel.com> */ -#include <linux/bitops.h> -#include <linux/errno.h> +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <malloc.h> #include <asm/gpio.h> #include <asm/hardware.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <linux/bitops.h> +#include <linux/errno.h> #include <linux/list.h> -#include <linux/printk.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/atmel_usba_udc.h> -#include <malloc.h> + +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +#include <mach/atmel_usba_udc.h> + +static int usba_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int usba_udc_stop(struct usb_gadget *gadget); +#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ #include "atmel_usba_udc.h" @@ -506,10 +518,32 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) return 0; } +static int usba_udc_pullup(struct usb_gadget *gadget, int is_on) +{ + struct usba_udc *udc = to_usba_udc(gadget); + u32 ctrl; + + ctrl = usba_readl(udc, CTRL); + + if (is_on) + ctrl &= ~USBA_DETACH; + else + ctrl |= USBA_DETACH; + + usba_writel(udc, CTRL, ctrl); + + return 0; +} + 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, + .pullup = usba_udc_pullup, +#if CONFIG_IS_ENABLED(DM_USB_GADGET) + .udc_start = usba_udc_start, + .udc_stop = usba_udc_stop, +#endif }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1153,7 +1187,7 @@ static int usba_udc_irq(struct usba_udc *udc) return 0; } -static int atmel_usba_start(struct usba_udc *udc) +static int usba_udc_enable(struct usba_udc *udc) { udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; @@ -1168,7 +1202,7 @@ static int atmel_usba_start(struct usba_udc *udc) return 0; } -static int atmel_usba_stop(struct usba_udc *udc) +static int usba_udc_disable(struct usba_udc *udc) { udc->gadget.speed = USB_SPEED_UNKNOWN; reset_all_endpoints(udc); @@ -1179,6 +1213,47 @@ static int atmel_usba_stop(struct usba_udc *udc) return 0; } +static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, + struct usba_udc *udc) +{ + struct usba_ep *eps; + int i; + + eps = malloc(sizeof(struct usba_ep) * pdata->num_ep); + if (!eps) { + log_err("failed to alloc eps\n"); + return NULL; + } + + udc->gadget.ep0 = &eps[0].ep; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + 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->ep.maxpacket = pdata->ep[i].fifo_size; + ep->fifo_size = ep->ep.maxpacket; + 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; +} + +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) static struct usba_udc controller = { .regs = (unsigned *)ATMEL_BASE_UDPHS, .fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO, @@ -1204,22 +1279,22 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) int ret; if (!driver || !driver->bind || !driver->setup) { - printf("bad paramter\n"); + log_err("bad parameter\n"); return -EINVAL; } if (udc->driver) { - printf("UDC already has a gadget driver\n"); + log_err("UDC already has a gadget driver\n"); return -EBUSY; } - atmel_usba_start(udc); + usba_udc_enable(udc); udc->driver = driver; ret = driver->bind(&udc->gadget); if (ret) { - pr_err("driver->bind() returned %d\n", ret); + log_err("driver->bind() returned %d\n", ret); udc->driver = NULL; } @@ -1231,7 +1306,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) struct usba_udc *udc = &controller; if (!driver || !driver->unbind || !driver->disconnect) { - pr_err("bad paramter\n"); + log_err("bad parameter\n"); return -EINVAL; } @@ -1239,58 +1314,145 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) driver->unbind(&udc->gadget); udc->driver = NULL; - atmel_usba_stop(udc); + usba_udc_disable(udc); return 0; } -static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, - struct usba_udc *udc) +int usba_udc_probe(struct usba_platform_data *pdata) { - struct usba_ep *eps; - int i; + struct usba_udc *udc; - eps = malloc(sizeof(struct usba_ep) * pdata->num_ep); - if (!eps) { - pr_err("failed to alloc eps\n"); - return NULL; - } + udc = &controller; - udc->gadget.ep0 = &eps[0].ep; + udc->usba_ep = usba_udc_pdata(pdata, udc); - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&eps[0].ep.ep_list); + return 0; +} - for (i = 0; i < pdata->num_ep; i++) { - struct usba_ep *ep = &eps[i]; +#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ +struct usba_priv_data { + struct clk_bulk clks; + struct usba_udc udc; +}; - 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->fifo_size = ep->ep.maxpacket; - 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); - }; +static int usba_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = to_usba_udc(gadget); - return eps; + usba_udc_enable(udc); + + udc->driver = driver; + return 0; } -int usba_udc_probe(struct usba_platform_data *pdata) +static int usba_udc_stop(struct usb_gadget *gadget) { - struct usba_udc *udc; + struct usba_udc *udc = to_usba_udc(gadget); - udc = &controller; + udc->driver = NULL; - udc->usba_ep = usba_udc_pdata(pdata, udc); + usba_udc_disable(udc); + return 0; +} + +static int usba_udc_clk_init(struct udevice *dev, struct clk_bulk *clks) +{ + int ret; + + ret = clk_get_bulk(dev, clks); + if (ret == -ENOSYS) + return 0; + + if (ret) + return ret; + + ret = clk_enable_bulk(clks); + if (ret) { + clk_release_bulk(clks); + return ret; + } return 0; } + +static int usba_udc_probe(struct udevice *dev) +{ + struct usba_priv_data *priv = dev_get_priv(dev); + struct usba_udc *udc = &priv->udc; + int ret; + + udc->fifo = (void __iomem *)dev_remap_addr_index(dev, FIFO_IOMEM_ID); + if (!udc->fifo) + return -EINVAL; + + udc->regs = (void __iomem *)dev_remap_addr_index(dev, CTRL_IOMEM_ID); + if (!udc->regs) + return -EINVAL; + + ret = usba_udc_clk_init(dev, &priv->clks); + if (ret) + return ret; + + udc->usba_ep = usba_udc_pdata(&pdata, udc); + + udc->gadget.ops = &usba_udc_ops; + udc->gadget.speed = USB_SPEED_HIGH, + udc->gadget.is_dualspeed = 1, + udc->gadget.name = "atmel_usba_udc", + + ret = usb_add_gadget_udc((struct device *)dev, &udc->gadget); + if (ret) + goto err; + + return 0; +err: + free(udc->usba_ep); + + clk_release_bulk(&priv->clks); + + return ret; +} + +static int usba_udc_remove(struct udevice *dev) +{ + struct usba_priv_data *priv = dev_get_priv(dev); + + usb_del_gadget_udc(&priv->udc.gadget); + + free(priv->udc.usba_ep); + + clk_release_bulk(&priv->clks); + + return dm_scan_fdt_dev(dev); +} + +static int usba_udc_handle_interrupts(struct udevice *dev) +{ + struct usba_priv_data *priv = dev_get_priv(dev); + + return usba_udc_irq(&priv->udc); +} + +static const struct usb_gadget_generic_ops usba_udc_gadget_ops = { + .handle_interrupts = usba_udc_handle_interrupts, +}; + +static const struct udevice_id usba_udc_ids[] = { + { .compatible = "atmel,at91sam9rl-udc" }, + { .compatible = "atmel,at91sam9g45-udc" }, + { .compatible = "atmel,sama5d3-udc" }, + {} +}; + +U_BOOT_DRIVER(atmel_usba_udc) = { + .name = "atmel_usba_udc", + .id = UCLASS_USB_GADGET_GENERIC, + .of_match = usba_udc_ids, + .ops = &usba_udc_gadget_ops, + .probe = usba_udc_probe, + .remove = usba_udc_remove, + .priv_auto = sizeof(struct usba_priv_data), +}; +#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index f6cb48c1cff..7f5e98f6c4c 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -211,6 +211,9 @@ #define EP0_EPT_SIZE USBA_EPT_SIZE_64 #define EP0_NR_BANKS 1 +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + #define DBG_ERR 0x0001 /* report all error returns */ #define DBG_HW 0x0002 /* debug hardware initialization */ #define DBG_GADGET 0x0004 /* calls to/from gadget driver */ diff --git a/drivers/usb/gadget/udc/udc-uclass.c b/drivers/usb/gadget/udc/udc-uclass.c index fbe62bbce47..723d1cdfd78 100644 --- a/drivers/usb/gadget/udc/udc-uclass.c +++ b/drivers/usb/gadget/udc/udc-uclass.c @@ -83,7 +83,7 @@ __weak int dm_usb_gadget_handle_interrupts(struct udevice *dev) #if CONFIG_IS_ENABLED(DM) UCLASS_DRIVER(usb_gadget_generic) = { .id = UCLASS_USB_GADGET_GENERIC, - .name = "usb", + .name = "usb_gadget", .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif diff --git a/include/linux/usb/atmel_usba_udc.h b/include/linux/usb/atmel_usba_udc.h index c1c810759c3..37c4f218493 100644 --- a/include/linux/usb/atmel_usba_udc.h +++ b/include/linux/usb/atmel_usba_udc.h @@ -20,6 +20,8 @@ struct usba_platform_data { struct usba_ep_data *ep; }; +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) extern int usba_udc_probe(struct usba_platform_data *pdata); +#endif #endif /* __LINUX_USB_USBA_H */ |