diff options
-rw-r--r-- | drivers/usb/dwc3/Makefile | 13 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.c | 108 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 198 | ||||
-rw-r--r-- | drivers/usb/dwc3/debugfs.c | 214 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-exynos.c | 151 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 116 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-pci.c | 52 | ||||
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 82 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 371 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.h | 3 | ||||
-rw-r--r-- | drivers/usb/dwc3/host.c | 2 | ||||
-rw-r--r-- | include/linux/platform_data/dwc3-exynos.h | 24 |
12 files changed, 921 insertions, 413 deletions
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 900ae74357f..d441fe4c180 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -28,6 +28,19 @@ endif obj-$(CONFIG_USB_DWC3) += dwc3-omap.o +## +# REVISIT Samsung Exynos platform needs the clk API which isn't +# defined on all architectures. If we allow dwc3-exynos.c compile +# always we will fail the linking phase on those architectures +# which don't provide clk api implementation and that's unnaceptable. +# +# When Samsung's platform start supporting pm_runtime, this check +# for HAVE_CLK should be removed. +## +ifneq ($(CONFIG_HAVE_CLK),) + obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o +endif + ifneq ($(CONFIG_PCI),) obj-$(CONFIG_USB_DWC3) += dwc3-pci.o endif diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7c9df630dbe..fd6917b8d0d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -48,10 +48,10 @@ #include <linux/list.h> #include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/of.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <linux/module.h> #include "core.h" #include "gadget.h" @@ -86,7 +86,7 @@ again: id = -ENOMEM; } - return 0; + return id; } EXPORT_SYMBOL_GPL(dwc3_get_device_id); @@ -167,11 +167,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, } /** - * dwc3_alloc_one_event_buffer - Allocated one event buffer structure + * dwc3_alloc_one_event_buffer - Allocates one event buffer structure * @dwc: Pointer to our controller context structure * @length: size of the event buffer * - * Returns a pointer to the allocated event buffer structure on succes + * Returns a pointer to the allocated event buffer structure on success * otherwise ERR_PTR(errno). */ static struct dwc3_event_buffer *__devinit @@ -215,10 +215,10 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) /** * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length - * @dwc: Pointer to out controller context structure + * @dwc: pointer to our controller context structure * @length: size of event buffer * - * Returns 0 on success otherwise negative errno. In error the case, dwc + * Returns 0 on success otherwise negative errno. In the error case, dwc * may contain some buffers allocated but not all which were requested. */ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) @@ -251,7 +251,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) /** * dwc3_event_buffers_setup - setup our allocated event buffers - * @dwc: Pointer to out controller context structure + * @dwc: pointer to our controller context structure * * Returns 0 on success otherwise negative errno. */ @@ -350,7 +350,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) dwc3_cache_hwparams(dwc); reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_SCALEDOWN(3); + reg &= ~DWC3_GCTL_SCALEDOWN_MASK; reg &= ~DWC3_GCTL_DISSCRAMBLE; switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { @@ -363,9 +363,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) /* * WORKAROUND: DWC3 revisions <1.90a have a bug - * when The device fails to connect at SuperSpeed + * where the device can fail to connect at SuperSpeed * and falls back to high-speed mode which causes - * the device to enter in a Connect/Disconnect loop + * the device to enter a Connect/Disconnect loop */ if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; @@ -404,8 +404,10 @@ static void dwc3_core_exit(struct dwc3 *dwc) static int __devinit dwc3_probe(struct platform_device *pdev) { + struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; + struct device *dev = &pdev->dev; int ret = -ENOMEM; int irq; @@ -415,39 +417,39 @@ static int __devinit dwc3_probe(struct platform_device *pdev) u8 mode; - mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { - dev_err(&pdev->dev, "not enough memory\n"); - goto err0; + dev_err(dev, "not enough memory\n"); + return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - dev_err(&pdev->dev, "missing resource\n"); - goto err1; + dev_err(dev, "missing resource\n"); + return -ENODEV; } dwc->res = res; - res = request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev)); + res = devm_request_mem_region(dev, res->start, resource_size(res), + dev_name(dev)); if (!res) { - dev_err(&pdev->dev, "can't request mem region\n"); - goto err1; + dev_err(dev, "can't request mem region\n"); + return -ENOMEM; } - regs = ioremap(res->start, resource_size(res)); + regs = devm_ioremap(dev, res->start, resource_size(res)); if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - goto err2; + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; } irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "missing IRQ\n"); - goto err3; + dev_err(dev, "missing IRQ\n"); + return -ENODEV; } spin_lock_init(&dwc->lock); @@ -455,7 +457,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) dwc->regs = regs; dwc->regs_size = resource_size(res); - dwc->dev = &pdev->dev; + dwc->dev = dev; dwc->irq = irq; if (!strncmp("super", maximum_speed, 5)) @@ -469,14 +471,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev) else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); - pm_runtime_forbid(&pdev->dev); + if (of_get_property(node, "tx-fifo-resize", NULL)) + dwc->needs_fifo_resize = true; + + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + pm_runtime_forbid(dev); ret = dwc3_core_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize core\n"); - goto err3; + dev_err(dev, "failed to initialize core\n"); + return ret; } mode = DWC3_MODE(dwc->hwparams.hwparams0); @@ -486,49 +491,49 @@ static int __devinit dwc3_probe(struct platform_device *pdev) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize gadget\n"); - goto err4; + dev_err(dev, "failed to initialize gadget\n"); + goto err1; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); - goto err4; + dev_err(dev, "failed to initialize host\n"); + goto err1; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); - goto err4; + dev_err(dev, "failed to initialize host\n"); + goto err1; } ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize gadget\n"); - goto err4; + dev_err(dev, "failed to initialize gadget\n"); + goto err1; } break; default: - dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); - goto err4; + dev_err(dev, "Unsupported mode of operation %d\n", mode); + goto err1; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize debugfs\n"); - goto err5; + dev_err(dev, "failed to initialize debugfs\n"); + goto err2; } - pm_runtime_allow(&pdev->dev); + pm_runtime_allow(dev); return 0; -err5: +err2: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); @@ -545,19 +550,9 @@ err5: break; } -err4: - dwc3_core_exit(dwc); - -err3: - iounmap(regs); - -err2: - release_mem_region(res->start, resource_size(res)); - err1: - kfree(dwc->mem); + dwc3_core_exit(dwc); -err0: return ret; } @@ -590,9 +585,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev) } dwc3_core_exit(dwc); - release_mem_region(res->start, resource_size(res)); - iounmap(dwc->regs); - kfree(dwc->mem); return 0; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a72f42ffbbe..6c7945b4cad 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -145,22 +145,23 @@ /* Bit fields */ /* Global Configuration Register */ -#define DWC3_GCTL_PWRDNSCALE(n) (n << 19) +#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_U2RSTECN (1 << 16) -#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6) +#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) #define DWC3_GCTL_CLK_PIPE (1) #define DWC3_GCTL_CLK_PIPEHALF (2) #define DWC3_GCTL_CLK_MASK (3) #define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12) -#define DWC3_GCTL_PRTCAPDIR(n) (n << 12) +#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12) #define DWC3_GCTL_PRTCAP_HOST 1 #define DWC3_GCTL_PRTCAP_DEVICE 2 #define DWC3_GCTL_PRTCAP_OTG 3 #define DWC3_GCTL_CORESOFTRESET (1 << 11) -#define DWC3_GCTL_SCALEDOWN(n) (n << 4) +#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) +#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) #define DWC3_GCTL_DISSCRAMBLE (1 << 3) #define DWC3_GCTL_DSBLCLKGTNG (1 << 0) @@ -172,8 +173,12 @@ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +/* Global TX Fifo Size Register */ +#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) +#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) + /* Global HWPARAMS1 Register */ -#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24) +#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 @@ -198,6 +203,15 @@ #define DWC3_DCTL_APPL1RES (1 << 23) +#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17) +#define DWC3_DCTL_TRGTULST(n) ((n) << 17) + +#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2)) +#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3)) +#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4)) +#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5)) +#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) + #define DWC3_DCTL_INITU2ENA (1 << 12) #define DWC3_DCTL_ACCEPTU2ENA (1 << 11) #define DWC3_DCTL_INITU1ENA (1 << 10) @@ -260,10 +274,10 @@ /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 -#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT) -#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) +#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT) +#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) #define DWC3_DEPCMD_STATUS_MASK (0x0f << 12) -#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12) +#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12) #define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) #define DWC3_DEPCMD_CMDACT (1 << 10) #define DWC3_DEPCMD_CMDIOC (1 << 8) @@ -288,7 +302,7 @@ /* Structures */ -struct dwc3_trb_hw; +struct dwc3_trb; /** * struct dwc3_event_buffer - Software event buffer representation @@ -343,7 +357,7 @@ struct dwc3_ep { struct list_head request_list; struct list_head req_queued; - struct dwc3_trb_hw *trb_pool; + struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; u32 free_slot; u32 busy_slot; @@ -418,102 +432,49 @@ enum dwc3_device_state { DWC3_CONFIGURED_STATE, }; -/** - * struct dwc3_trb - transfer request block - * @bpl: lower 32bit of the buffer - * @bph: higher 32bit of the buffer - * @length: buffer size (up to 16mb - 1) - * @pcm1: packet count m1 - * @trbsts: trb status - * 0 = ok - * 1 = missed isoc - * 2 = setup pending - * @hwo: hardware owner of descriptor - * @lst: last trb - * @chn: chain buffers - * @csp: continue on short packets (only supported on isoc eps) - * @trbctl: trb control - * 1 = normal - * 2 = control-setup - * 3 = control-status-2 - * 4 = control-status-3 - * 5 = control-data (first trb of data stage) - * 6 = isochronous-first (first trb of service interval) - * 7 = isochronous - * 8 = link trb - * others = reserved - * @isp_imi: interrupt on short packet / interrupt on missed isoc - * @ioc: interrupt on complete - * @sid_sofn: Stream ID / SOF Number - */ -struct dwc3_trb { - u64 bplh; - - union { - struct { - u32 length:24; - u32 pcm1:2; - u32 reserved27_26:2; - u32 trbsts:4; -#define DWC3_TRB_STS_OKAY 0 -#define DWC3_TRB_STS_MISSED_ISOC 1 -#define DWC3_TRB_STS_SETUP_PENDING 2 - }; - u32 len_pcm; - }; - - union { - struct { - u32 hwo:1; - u32 lst:1; - u32 chn:1; - u32 csp:1; - u32 trbctl:6; - u32 isp_imi:1; - u32 ioc:1; - u32 reserved13_12:2; - u32 sid_sofn:16; - u32 reserved31_30:2; - }; - u32 control; - }; -} __packed; +/* TRB Length, PCM and Status */ +#define DWC3_TRB_SIZE_MASK (0x00ffffff) +#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) +#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24) +#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28)) + +#define DWC3_TRBSTS_OK 0 +#define DWC3_TRBSTS_MISSED_ISOC 1 +#define DWC3_TRBSTS_SETUP_PENDING 2 + +/* TRB Control */ +#define DWC3_TRB_CTRL_HWO (1 << 0) +#define DWC3_TRB_CTRL_LST (1 << 1) +#define DWC3_TRB_CTRL_CHN (1 << 2) +#define DWC3_TRB_CTRL_CSP (1 << 3) +#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4) +#define DWC3_TRB_CTRL_ISP_IMI (1 << 10) +#define DWC3_TRB_CTRL_IOC (1 << 11) +#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) + +#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) +#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2) +#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3) +#define DWC3_TRBCTL_CONTROL_STATUS3 DWC3_TRB_CTRL_TRBCTL(4) +#define DWC3_TRBCTL_CONTROL_DATA DWC3_TRB_CTRL_TRBCTL(5) +#define DWC3_TRBCTL_ISOCHRONOUS_FIRST DWC3_TRB_CTRL_TRBCTL(6) +#define DWC3_TRBCTL_ISOCHRONOUS DWC3_TRB_CTRL_TRBCTL(7) +#define DWC3_TRBCTL_LINK_TRB DWC3_TRB_CTRL_TRBCTL(8) /** - * struct dwc3_trb_hw - transfer request block (hw format) + * struct dwc3_trb - transfer request block (hw format) * @bpl: DW0-3 * @bph: DW4-7 * @size: DW8-B * @trl: DWC-F */ -struct dwc3_trb_hw { - __le32 bpl; - __le32 bph; - __le32 size; - __le32 ctrl; +struct dwc3_trb { + u32 bpl; + u32 bph; + u32 size; + u32 ctrl; } __packed; -static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw) -{ - hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh)); - hw->bph = cpu_to_le32(upper_32_bits(nat->bplh)); - hw->size = cpu_to_le32p(&nat->len_pcm); - /* HWO is written last */ - hw->ctrl = cpu_to_le32p(&nat->control); -} - -static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) -{ - u64 bplh; - - bplh = le32_to_cpup(&hw->bpl); - bplh |= (u64) le32_to_cpup(&hw->bph) << 32; - nat->bplh = bplh; - - nat->len_pcm = le32_to_cpup(&hw->size); - nat->control = le32_to_cpup(&hw->ctrl); -} - /** * dwc3_hwparams - copy of HWPARAMS registers * @hwparams0 - GHWPARAMS0 @@ -546,8 +507,13 @@ struct dwc3_hwparams { #define DWC3_MODE_DRD 2 #define DWC3_MODE_HUB 3 +#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) + /* HWPARAMS1 */ -#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) +#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) + +/* HWPARAMS7 */ +#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) struct dwc3_request { struct usb_request request; @@ -555,7 +521,7 @@ struct dwc3_request { struct dwc3_ep *dep; u8 epnum; - struct dwc3_trb_hw *trb; + struct dwc3_trb *trb; dma_addr_t trb_dma; unsigned direction:1; @@ -593,6 +559,8 @@ struct dwc3_request { * @ep0_expect_in: true when we expect a DATA IN transfer * @start_config_issued: true when StartConfig command has been issued * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround + * @needs_fifo_resize: not all users might want fifo resizing, flag it + * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state @@ -603,7 +571,7 @@ struct dwc3_request { */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; - struct dwc3_trb_hw *ep0_trb; + struct dwc3_trb *ep0_trb; void *ep0_bounce; u8 *setup_buf; dma_addr_t ctrl_req_addr; @@ -649,6 +617,8 @@ struct dwc3 { unsigned start_config_issued:1; unsigned setup_packet_pending:1; unsigned delayed_status:1; + unsigned needs_fifo_resize:1; + unsigned resize_fifos:1; enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; @@ -660,23 +630,13 @@ struct dwc3 { struct dwc3_hwparams hwparams; struct dentry *root; + + u8 test_mode; + u8 test_mode_nr; }; /* -------------------------------------------------------------------------- */ -#define DWC3_TRBSTS_OK 0 -#define DWC3_TRBSTS_MISSED_ISOC 1 -#define DWC3_TRBSTS_SETUP_PENDING 2 - -#define DWC3_TRBCTL_NORMAL 1 -#define DWC3_TRBCTL_CONTROL_SETUP 2 -#define DWC3_TRBCTL_CONTROL_STATUS2 3 -#define DWC3_TRBCTL_CONTROL_STATUS3 4 -#define DWC3_TRBCTL_CONTROL_DATA 5 -#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6 -#define DWC3_TRBCTL_ISOCHRONOUS 7 -#define DWC3_TRBCTL_LINK_TRB 8 - /* -------------------------------------------------------------------------- */ struct dwc3_event_type { @@ -717,9 +677,14 @@ struct dwc3_event_depevt { u32 endpoint_event:4; u32 reserved11_10:2; u32 status:4; -#define DEPEVT_STATUS_BUSERR (1 << 0) -#define DEPEVT_STATUS_SHORT (1 << 1) -#define DEPEVT_STATUS_IOC (1 << 2) + +/* Within XferNotReady */ +#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3) + +/* Within XferComplete */ +#define DEPEVT_STATUS_BUSERR (1 << 0) +#define DEPEVT_STATUS_SHORT (1 << 1) +#define DEPEVT_STATUS_IOC (1 << 2) #define DEPEVT_STATUS_LST (1 << 3) /* Stream event only */ @@ -805,6 +770,7 @@ union dwc3_event { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); +int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 433c97c15fc..d4a30f11872 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -46,6 +46,8 @@ #include <linux/delay.h> #include <linux/uaccess.h> +#include <linux/usb/ch9.h> + #include "core.h" #include "gadget.h" #include "io.h" @@ -464,6 +466,192 @@ static const struct file_operations dwc3_mode_fops = { .release = single_release, }; +static int dwc3_testmode_show(struct seq_file *s, void *unused) +{ + struct dwc3 *dwc = s->private; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg &= DWC3_DCTL_TSTCTRL_MASK; + reg >>= 1; + spin_unlock_irqrestore(&dwc->lock, flags); + + switch (reg) { + case 0: + seq_printf(s, "no test\n"); + break; + case TEST_J: + seq_printf(s, "test_j\n"); + break; + case TEST_K: + seq_printf(s, "test_k\n"); + break; + case TEST_SE0_NAK: + seq_printf(s, "test_se0_nak\n"); + break; + case TEST_PACKET: + seq_printf(s, "test_packet\n"); + break; + case TEST_FORCE_EN: + seq_printf(s, "test_force_enable\n"); + break; + default: + seq_printf(s, "UNKNOWN %d\n", reg); + } + + return 0; +} + +static int dwc3_testmode_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_testmode_show, inode->i_private); +} + +static ssize_t dwc3_testmode_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct dwc3 *dwc = s->private; + unsigned long flags; + u32 testmode = 0; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "test_j", 6)) + testmode = TEST_J; + else if (!strncmp(buf, "test_k", 6)) + testmode = TEST_K; + else if (!strncmp(buf, "test_se0_nak", 12)) + testmode = TEST_SE0_NAK; + else if (!strncmp(buf, "test_packet", 11)) + testmode = TEST_PACKET; + else if (!strncmp(buf, "test_force_enable", 17)) + testmode = TEST_FORCE_EN; + else + testmode = 0; + + spin_lock_irqsave(&dwc->lock, flags); + dwc3_gadget_set_test_mode(dwc, testmode); + spin_unlock_irqrestore(&dwc->lock, flags); + + return count; +} + +static const struct file_operations dwc3_testmode_fops = { + .open = dwc3_testmode_open, + .write = dwc3_testmode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dwc3_link_state_show(struct seq_file *s, void *unused) +{ + struct dwc3 *dwc = s->private; + unsigned long flags; + enum dwc3_link_state state; + u32 reg; + + spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + state = DWC3_DSTS_USBLNKST(reg); + spin_unlock_irqrestore(&dwc->lock, flags); + + switch (state) { + case DWC3_LINK_STATE_U0: + seq_printf(s, "U0\n"); + break; + case DWC3_LINK_STATE_U1: + seq_printf(s, "U1\n"); + break; + case DWC3_LINK_STATE_U2: + seq_printf(s, "U2\n"); + break; + case DWC3_LINK_STATE_U3: + seq_printf(s, "U3\n"); + break; + case DWC3_LINK_STATE_SS_DIS: + seq_printf(s, "SS.Disabled\n"); + break; + case DWC3_LINK_STATE_RX_DET: + seq_printf(s, "Rx.Detect\n"); + break; + case DWC3_LINK_STATE_SS_INACT: + seq_printf(s, "SS.Inactive\n"); + break; + case DWC3_LINK_STATE_POLL: + seq_printf(s, "Poll\n"); + break; + case DWC3_LINK_STATE_RECOV: + seq_printf(s, "Recovery\n"); + break; + case DWC3_LINK_STATE_HRESET: + seq_printf(s, "HRESET\n"); + break; + case DWC3_LINK_STATE_CMPLY: + seq_printf(s, "Compliance\n"); + break; + case DWC3_LINK_STATE_LPBK: + seq_printf(s, "Loopback\n"); + break; + default: + seq_printf(s, "UNKNOWN %d\n", reg); + } + + return 0; +} + +static int dwc3_link_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_link_state_show, inode->i_private); +} + +static ssize_t dwc3_link_state_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct dwc3 *dwc = s->private; + unsigned long flags; + enum dwc3_link_state state = 0; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "SS.Disabled", 11)) + state = DWC3_LINK_STATE_SS_DIS; + else if (!strncmp(buf, "Rx.Detect", 9)) + state = DWC3_LINK_STATE_RX_DET; + else if (!strncmp(buf, "SS.Inactive", 11)) + state = DWC3_LINK_STATE_SS_INACT; + else if (!strncmp(buf, "Recovery", 8)) + state = DWC3_LINK_STATE_RECOV; + else if (!strncmp(buf, "Compliance", 10)) + state = DWC3_LINK_STATE_CMPLY; + else if (!strncmp(buf, "Loopback", 8)) + state = DWC3_LINK_STATE_LPBK; + else + return -EINVAL; + + spin_lock_irqsave(&dwc->lock, flags); + dwc3_gadget_set_link_state(dwc, state); + spin_unlock_irqrestore(&dwc->lock, flags); + + return count; +} + +static const struct file_operations dwc3_link_state_fops = { + .open = dwc3_link_state_open, + .write = dwc3_link_state_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int __devinit dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; @@ -471,8 +659,8 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) int ret; root = debugfs_create_dir(dev_name(dwc->dev), NULL); - if (IS_ERR(root)) { - ret = PTR_ERR(root); + if (!root) { + ret = -ENOMEM; goto err0; } @@ -480,15 +668,29 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) file = debugfs_create_file("regdump", S_IRUGO, root, dwc, &dwc3_regdump_fops); - if (IS_ERR(file)) { - ret = PTR_ERR(file); + if (!file) { + ret = -ENOMEM; goto err1; } file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_mode_fops); - if (IS_ERR(file)) { - ret = PTR_ERR(file); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_testmode_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_link_state_fops); + if (!file) { + ret = -ENOMEM; goto err1; } diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c new file mode 100644 index 00000000000..d1903019808 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -0,0 +1,151 @@ +/** + * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Anton Tikhomirov <av.tikhomirov@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * 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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/platform_data/dwc3-exynos.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/clk.h> + +#include "core.h" + +struct dwc3_exynos { + struct platform_device *dwc3; + struct device *dev; + + struct clk *clk; +}; + +static int __devinit dwc3_exynos_probe(struct platform_device *pdev) +{ + struct dwc3_exynos_data *pdata = pdev->dev.platform_data; + struct platform_device *dwc3; + struct dwc3_exynos *exynos; + struct clk *clk; + + int devid; + int ret = -ENOMEM; + + exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); + if (!exynos) { + dev_err(&pdev->dev, "not enough memory\n"); + goto err0; + } + + platform_set_drvdata(pdev, exynos); + + devid = dwc3_get_device_id(); + if (devid < 0) + goto err1; + + dwc3 = platform_device_alloc("dwc3", devid); + if (!dwc3) { + dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); + goto err2; + } + + clk = clk_get(&pdev->dev, "usbdrd30"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "couldn't get clock\n"); + ret = -EINVAL; + goto err3; + } + + dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask); + + dwc3->dev.parent = &pdev->dev; + dwc3->dev.dma_mask = pdev->dev.dma_mask; + dwc3->dev.dma_parms = pdev->dev.dma_parms; + exynos->dwc3 = dwc3; + exynos->dev = &pdev->dev; + exynos->clk = clk; + + clk_enable(exynos->clk); + + /* PHY initialization */ + if (!pdata) { + dev_dbg(&pdev->dev, "missing platform data\n"); + } else { + if (pdata->phy_init) + pdata->phy_init(pdev, pdata->phy_type); + } + + ret = platform_device_add_resources(dwc3, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); + goto err4; + } + + ret = platform_device_add(dwc3); + if (ret) { + dev_err(&pdev->dev, "failed to register dwc3 device\n"); + goto err4; + } + + return 0; + +err4: + if (pdata && pdata->phy_exit) + pdata->phy_exit(pdev, pdata->phy_type); + + clk_disable(clk); + clk_put(clk); +err3: + platform_device_put(dwc3); +err2: + dwc3_put_device_id(devid); +err1: + kfree(exynos); +err0: + return ret; +} + +static int __devexit dwc3_exynos_remove(struct platform_device *pdev) +{ + struct dwc3_exynos *exynos = platform_get_drvdata(pdev); + struct dwc3_exynos_data *pdata = pdev->dev.platform_data; + + platform_device_unregister(exynos->dwc3); + + dwc3_put_device_id(exynos->dwc3->id); + + if (pdata && pdata->phy_exit) + pdata->phy_exit(pdev, pdata->phy_type); + + clk_disable(exynos->clk); + clk_put(exynos->clk); + + kfree(exynos); + + return 0; +} + +static struct platform_driver dwc3_exynos_driver = { + .probe = dwc3_exynos_probe, + .remove = __devexit_p(dwc3_exynos_remove), + .driver = { + .name = "exynos-dwc3", + }, +}; + +module_platform_driver(dwc3_exynos_driver); + +MODULE_ALIAS("platform:exynos-dwc3"); +MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 3274ac8f120..d7d9c0ec951 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -46,7 +46,7 @@ #include <linux/dma-mapping.h> #include <linux/ioport.h> #include <linux/io.h> -#include <linux/module.h> +#include <linux/of.h> #include "core.h" #include "io.h" @@ -197,91 +197,99 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) static int __devinit dwc3_omap_probe(struct platform_device *pdev) { struct dwc3_omap_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; + struct platform_device *dwc3; struct dwc3_omap *omap; struct resource *res; + struct device *dev = &pdev->dev; int devid; + int size; int ret = -ENOMEM; int irq; + const u32 *utmi_mode; u32 reg; void __iomem *base; void *context; - omap = kzalloc(sizeof(*omap), GFP_KERNEL); + omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); if (!omap) { - dev_err(&pdev->dev, "not enough memory\n"); - goto err0; + dev_err(dev, "not enough memory\n"); + return -ENOMEM; } platform_set_drvdata(pdev, omap); irq = platform_get_irq(pdev, 1); if (irq < 0) { - dev_err(&pdev->dev, "missing IRQ resource\n"); - ret = -EIN |