diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-23 11:28:21 +0900 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-23 11:28:21 +0900 |
commit | f8712528ae0bfef50f30b1da3d58e22f4f007889 (patch) | |
tree | 77dffd5ac91fd75f5e87595adb31176fd2bf3f11 /drivers/usb/musb | |
parent | c311e391a7efd101250c0e123286709b7e736249 (diff) | |
parent | 7751b6fb05869bcb318e74420148c06577adf894 (diff) |
Merge tag 'usb-for-v3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v3.16 merge window
Not a lot here during this merge window. Mostly we just have
the usual miscellaneous patches (removal of unnecessary prints,
proper dependencies being added to Kconfig, build warning fixes,
new device ID, etc.
Other than those, the only important new features are the
new support for OS Strings which should help Linux Gadget
Drivers behave better under MS Windows. Also Babble Recovery
implementation for MUSB on AM335x. Lastly, we also have
ARCH_QCOM PHY support though phy-msm.
Signed-of-by: Felipe Balbi <balbi@ti.com>
Conflicts:
drivers/usb/phy/phy-mv-u3d-usb.c
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/Kconfig | 5 | ||||
-rw-r--r-- | drivers/usb/musb/am35x.c | 14 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin.c | 14 | ||||
-rw-r--r-- | drivers/usb/musb/da8xx.c | 16 | ||||
-rw-r--r-- | drivers/usb/musb/davinci.c | 8 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 35 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 9 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 29 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010.c | 28 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010.h | 8 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010_omap.c | 2 |
11 files changed, 123 insertions, 45 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 8b789792f6fa..06cc5d6ea681 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -76,7 +76,7 @@ config USB_MUSB_TUSB6010 config USB_MUSB_OMAP2PLUS tristate "OMAP2430 and onwards" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS && USB select GENERIC_PHY config USB_MUSB_AM35X @@ -141,10 +141,11 @@ config USB_TI_CPPI_DMA config USB_TI_CPPI41_DMA bool 'TI CPPI 4.1 (AM335x)' depends on ARCH_OMAP + select TI_CPPI41 config USB_TUSB_OMAP_DMA bool 'TUSB 6010' - depends on USB_MUSB_TUSB6010 + depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules depends on ARCH_OMAP help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index b3aa0184af9a..0a34dd859555 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -32,7 +32,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <linux/platform_data/usb-omap.h> #include "musb_core.h" @@ -85,6 +85,7 @@ struct am35x_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *phy_clk; struct clk *clk; }; @@ -360,7 +361,6 @@ static int am35x_musb_init(struct musb *musb) if (!rev) return -ENODEV; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -402,7 +402,6 @@ static int am35x_musb_exit(struct musb *musb) data->set_phy_power(0); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -505,6 +504,9 @@ static int am35x_probe(struct platform_device *pdev) pdata->platform_ops = &am35x_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err7; platform_set_drvdata(pdev, glue); pinfo = am35x_dev_info; @@ -518,11 +520,14 @@ static int am35x_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err7; + goto err8; } return 0; +err8: + usb_phy_generic_unregister(glue->phy); + err7: clk_disable(clk); @@ -547,6 +552,7 @@ static int am35x_remove(struct platform_device *pdev) struct am35x_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_disable(glue->phy_clk); clk_put(glue->clk); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 796677fa9a15..d40d5f0b5528 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -18,7 +18,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/prefetch.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <asm/cacheflush.h> @@ -29,6 +29,7 @@ struct bfin_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -401,7 +402,6 @@ static int bfin_musb_init(struct musb *musb) } gpio_direction_output(musb->config->gpio_vrsel, 0); - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { gpio_free(musb->config->gpio_vrsel); @@ -424,9 +424,8 @@ static int bfin_musb_init(struct musb *musb) static int bfin_musb_exit(struct musb *musb) { gpio_free(musb->config->gpio_vrsel); - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + return 0; } @@ -477,6 +476,9 @@ static int bfin_probe(struct platform_device *pdev) pdata->platform_ops = &bfin_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err2; platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -514,6 +516,9 @@ static int bfin_probe(struct platform_device *pdev) return 0; err3: + usb_phy_generic_unregister(glue->phy); + +err2: platform_device_put(musb); err1: @@ -528,6 +533,7 @@ static int bfin_remove(struct platform_device *pdev) struct bfin_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index e3486de71995..058775e647ad 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -32,7 +32,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <mach/da8xx.h> #include <linux/platform_data/usb-davinci.h> @@ -85,6 +85,7 @@ struct da8xx_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *clk; }; @@ -418,7 +419,6 @@ static int da8xx_musb_init(struct musb *musb) if (!rev) goto fail; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -453,7 +453,6 @@ static int da8xx_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -512,6 +511,11 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) { + ret = PTR_ERR(glue->phy); + goto err5; + } platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -538,11 +542,14 @@ static int da8xx_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err5; + goto err6; } return 0; +err6: + usb_phy_generic_unregister(glue->phy); + err5: clk_disable(clk); @@ -561,6 +568,7 @@ static int da8xx_remove(struct platform_device *pdev) struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index c259dac9d056..de8492b06e46 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -32,7 +32,7 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <mach/cputype.h> #include <mach/hardware.h> @@ -381,7 +381,6 @@ static int davinci_musb_init(struct musb *musb) u32 revision; int ret = -ENODEV; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -439,7 +438,7 @@ static int davinci_musb_init(struct musb *musb) fail: usb_put_phy(musb->xceiv); unregister: - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return ret; } @@ -487,7 +486,6 @@ static int davinci_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -545,6 +543,7 @@ static int davinci_probe(struct platform_device *pdev) pdata->platform_ops = &davinci_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -603,6 +602,7 @@ static int davinci_remove(struct platform_device *pdev) struct davinci_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 07576907e2c6..61da471b7aed 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -848,6 +848,10 @@ b_host: } } + /* handle babble condition */ + if (int_usb & MUSB_INTR_BABBLE) + schedule_work(&musb->recover_work); + #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -1746,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data) } } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, recover_work); + int status; + + musb_platform_reset(musb); + + usb_phy_vbus_off(musb->xceiv); + udelay(100); + + usb_phy_vbus_on(musb->xceiv); + udelay(100); + + /* + * When a babble condition occurs, the musb controller removes the + * session bit and the endpoint config is lost. + */ + if (musb->dyn_fifo) + status = ep_config_from_table(musb); + else + status = ep_config_from_hw(musb); + + /* start the session again */ + if (status == 0) + musb_start(musb); +} + /* -------------------------------------------------------------------------- * Init support */ @@ -1913,6 +1945,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_WORK(&musb->recover_work, musb_recover_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); @@ -2008,6 +2041,7 @@ fail4: fail3: cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); if (musb->dma_controller) @@ -2073,6 +2107,7 @@ static int musb_remove(struct platform_device *pdev) dma_controller_destroy(musb->dma_controller); cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 7083e82776ff..d155a156f240 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -192,6 +192,7 @@ struct musb_platform_ops { int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); + void (*reset)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); @@ -296,6 +297,7 @@ struct musb { irqreturn_t (*isr)(int, void *); struct work_struct irq_work; + struct work_struct recover_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; u16 hwvers; @@ -337,6 +339,7 @@ struct musb { dma_addr_t async; dma_addr_t sync; void __iomem *sync_va; + u8 tusb_revision; #endif /* passed down from chip/board specific irq handlers */ @@ -552,6 +555,12 @@ static inline void musb_platform_try_idle(struct musb *musb, musb->ops->try_idle(musb, timeout); } +static inline void musb_platform_reset(struct musb *musb) +{ + if (musb->ops->reset) + musb->ops->reset(musb); +} + static inline int musb_platform_get_vbus_status(struct musb *musb) { if (!musb->ops->vbus_status) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e2fd263585de..51beb13c7e1a 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -35,7 +35,7 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/module.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include <linux/platform_data/usb-omap.h> #include <linux/sizes.h> @@ -329,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) + if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); + /* + * When a babble condition occurs, the musb controller removes + * the session and is no longer in host mode. Hence, all + * devices connected to its root hub get disconnected. + * + * Hand this error down to the musb core isr, so it can + * recover. + */ + musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; + musb->int_tx = musb->int_rx = 0; + } + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; @@ -524,6 +536,16 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static void dsps_musb_reset(struct musb *musb) +{ + struct device *dev = musb->controller; + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); + udelay(100); +} + static struct musb_platform_ops dsps_ops = { .init = dsps_musb_init, .exit = dsps_musb_exit, @@ -533,6 +555,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, + .reset = dsps_musb_reset, }; static u64 musb_dmamask = DMA_BIT_MASK(32); @@ -750,7 +773,7 @@ static const struct of_device_id musb_dsps_of_match[] = { }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dsps_suspend(struct device *dev) { struct dsps_glue *glue = dev_get_drvdata(dev); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4e9fb1d08698..159ef4be1ef2 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -24,13 +24,14 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h> #include "musb_core.h" struct tusb6010_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; static void tusb_musb_set_vbus(struct musb *musb, int is_on); @@ -42,7 +43,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on); * Checks the revision. We need to use the DMA register as 3.0 does not * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV. */ -u8 tusb_get_revision(struct musb *musb) +static u8 tusb_get_revision(struct musb *musb) { void __iomem *tbase = musb->ctrl_base; u32 die_id; @@ -58,14 +59,13 @@ u8 tusb_get_revision(struct musb *musb) return rev; } -EXPORT_SYMBOL_GPL(tusb_get_revision); -static int tusb_print_revision(struct musb *musb) +static void tusb_print_revision(struct musb *musb) { void __iomem *tbase = musb->ctrl_base; u8 rev; - rev = tusb_get_revision(musb); + rev = musb->tusb_revision; pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n", "prcm", @@ -84,8 +84,6 @@ static int tusb_print_revision(struct musb *musb) TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)), "rev", TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - - return tusb_get_revision(musb); } #define WBUS_QUIRK_MASK (TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ @@ -349,7 +347,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables) u32 reg; if ((wakeup_enables & TUSB_PRCM_WBUS) - && (tusb_get_revision(musb) == TUSB_REV_30)) + && (musb->tusb_revision == TUSB_REV_30)) tusb_wbus_quirk(musb, 1); tusb_set_clock_source(musb, 0); @@ -797,7 +795,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci) u32 reg; u32 i; - if (tusb_get_revision(musb) == TUSB_REV_30) + if (musb->tusb_revision == TUSB_REV_30) tusb_wbus_quirk(musb, 0); /* there are issues re-locking the PLL on wakeup ... */ @@ -1011,10 +1009,11 @@ static int tusb_musb_start(struct musb *musb) goto err; } - ret = tusb_print_revision(musb); - if (ret < 2) { + musb->tusb_revision = tusb_get_revision(musb); + tusb_print_revision(musb); + if (musb->tusb_revision < 2) { printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", - ret); + musb->tusb_revision); goto err; } @@ -1065,7 +1064,6 @@ static int tusb_musb_init(struct musb *musb) void __iomem *sync = NULL; int ret; - usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -1117,7 +1115,6 @@ done: iounmap(sync); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); } return ret; } @@ -1133,7 +1130,6 @@ static int tusb_musb_exit(struct musb *musb) iounmap(musb->sync_va); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return 0; } @@ -1176,6 +1172,7 @@ static int tusb_probe(struct platform_device *pdev) pdata->platform_ops = &tusb_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -1224,6 +1221,7 @@ static int tusb_remove(struct platform_device *pdev) struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 35c933a5d991..aec86c86ce32 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -12,14 +12,6 @@ #ifndef __TUSB6010_H__ #define __TUSB6010_H__ -extern u8 tusb_get_revision(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb() 1 -#else -#define musb_in_tusb() 0 -#endif - #ifdef CONFIG_USB_TUSB_OMAP_DMA #define tusb_dma_omap() 1 #else diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index e33b6b2c44c2..3ce152c0408e 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -677,7 +677,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba tusb_dma->controller.channel_program = tusb_omap_dma_program; tusb_dma->controller.channel_abort = tusb_omap_dma_abort; - if (tusb_get_revision(musb) >= TUSB_REV_30) + if (musb->tusb_revision >= TUSB_REV_30) tusb_dma->multichannel = 1; for (i = 0; i < MAX_DMAREQ; i++) { |