From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Vasut Date: Tue, 15 Mar 2016 19:19:37 +0100 Subject: [U-Boot] [PATCH v3 3/4] drivers: musb-new: Add USB DRC driver for Microchip PIC32 OTG controller. In-Reply-To: <1458045855-7726-3-git-send-email-purna.mandal@microchip.com> References: <1458045855-7726-1-git-send-email-purna.mandal@microchip.com> <1458045855-7726-3-git-send-email-purna.mandal@microchip.com> Message-ID: <56E85239.1040303@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 03/15/2016 01:44 PM, Purna Chandra Mandal wrote: > This driver adds support of PIC32 MUSB OTG controller as dual role device. > It implements platform specific glue to reuse musb core. > > Signed-off-by: Cristian Birsan > Signed-off-by: Purna Chandra Mandal [...] > diff --git a/drivers/usb/musb-new/pic32.c b/drivers/usb/musb-new/pic32.c > new file mode 100644 > index 0000000..980a971 > --- /dev/null > +++ b/drivers/usb/musb-new/pic32.c > @@ -0,0 +1,294 @@ > +/* > + * Microchip PIC32 MUSB "glue layer" > + * > + * Copyright (C) 2015, Microchip Technology Inc. > + * Cristian Birsan > + * Purna Chandra Mandal > + * > + * SPDX-License-Identifier: GPL-2.0+ > + * > + * Based on the dsps "glue layer" code. > + */ > + > +#include > +#include > +#include "linux-compat.h" > +#include "musb_core.h" > +#include "musb_uboot.h" > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#define PIC32_TX_EP_MASK 0x0f /* EP0 + 7 Tx EPs */ > +#define PIC32_RX_EP_MASK 0x0e /* 7 Rx EPs */ > + > +#define MUSB_SOFTRST 0x7f > +#define MUSB_SOFTRST_NRST BIT(0) > +#define MUSB_SOFTRST_NRSTX BIT(1) > + > +#define USBCRCON 0 > +#define USBCRCON_USBWKUPEN BIT(0) /* Enable Wakeup Interrupt */ > +#define USBCRCON_USBRIE BIT(1) /* Enable Remote resume Interrupt */ > +#define USBCRCON_USBIE BIT(2) /* Enable USB General interrupt */ > +#define USBCRCON_SENDMONEN BIT(3) /* Enable Session End VBUS monitoring */ > +#define USBCRCON_BSVALMONEN BIT(4) /* Enable B-Device VBUS monitoring */ > +#define USBCRCON_ASVALMONEN BIT(5) /* Enable A-Device VBUS monitoring */ > +#define USBCRCON_VBUSMONEN BIT(6) /* Enable VBUS monitoring */ > +#define USBCRCON_PHYIDEN BIT(7) /* PHY ID monitoring enable */ > +#define USBCRCON_USBIDVAL BIT(8) /* USB ID value */ > +#define USBCRCON_USBIDOVEN BIT(9) /* USB ID override enable */ > +#define USBCRCON_USBWK BIT(24) /* USB Wakeup Status */ > +#define USBCRCON_USBRF BIT(25) /* USB Resume Status */ > +#define USBCRCON_USBIF BIT(26) /* USB General Interrupt Status */ > + > +static void __iomem *musb_glue; What would happen once you make a chip with two MUSB controllers ? > +/* pic32_musb_disable - disable HDRC */ > +static void pic32_musb_disable(struct musb *musb) > +{ Is there no way to shut down the MUSB on the PIC32 ? > +} > + > +/* pic32_musb_enable - enable HDRC */ > +static int pic32_musb_enable(struct musb *musb) > +{ > + /* soft reset by NRSTx */ > + musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX); > + /* set mode */ > + musb_platform_set_mode(musb, musb->board_mode); > + > + return 0; > +} > + > +static irqreturn_t pic32_interrupt(int irq, void *hci) > +{ > + struct musb *musb = hci; > + irqreturn_t ret = IRQ_NONE; > + u32 epintr, usbintr; > + > + /* Get usb core interrupts */ You mean "get" or "ack" here ? > + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); > + if (musb->int_usb) > + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); > + > + /* Get endpoint interrupts */ DTTO > + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX) & PIC32_RX_EP_MASK; > + if (musb->int_rx) > + musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); Same here > + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX) & PIC32_TX_EP_MASK; > + if (musb->int_tx) > + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); > + > + /* Drop spurious RX and TX if device is disconnected */ > + if (musb->int_usb & MUSB_INTR_DISCONNECT) { > + musb->int_tx = 0; > + musb->int_rx = 0; > + } > + > + if (musb->int_tx || musb->int_rx || musb->int_usb) > + ret |= musb_interrupt(musb); > + > + return ret; > +} > + > +static int pic32_musb_set_mode(struct musb *musb, u8 mode) > +{ > + struct device *dev = musb->controller; > + > + switch (mode) { > + case MUSB_HOST: > + clrsetbits_le32(musb_glue + USBCRCON, > + USBCRCON_USBIDVAL, USBCRCON_USBIDOVEN); > + break; > + case MUSB_PERIPHERAL: > + setbits_le32(musb_glue + USBCRCON, > + USBCRCON_USBIDVAL | USBCRCON_USBIDOVEN); > + break; > + case MUSB_OTG: > + dev_err(dev, "MUSB OTG mode enabled\n"); So having the core in OTG mode is an error ? Why ? > + break; > + default: > + dev_err(dev, "unsupported mode %d\n", mode); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int pic32_musb_init(struct musb *musb) > +{ > + u32 ctrl, hwvers; > + u8 power; > + > + /* Returns zero if not clocked */ > + hwvers = musb_read_hwvers(musb->mregs); > + if (!hwvers) > + return -ENODEV; > + > + /* Reset the musb */ > + power = musb_readb(musb->mregs, MUSB_POWER); > + power = power | MUSB_POWER_RESET; > + musb_writeb(musb->mregs, MUSB_POWER, power); > + mdelay(100); > + > + /* Start the on-chip PHY and its PLL. */ > + power = power & ~MUSB_POWER_RESET; > + musb_writeb(musb->mregs, MUSB_POWER, power); > + > + musb->isr = pic32_interrupt; > + > + ctrl = USBCRCON_USBIF | USBCRCON_USBRF | > + USBCRCON_USBWK | USBCRCON_USBIDOVEN | > + USBCRCON_PHYIDEN | USBCRCON_USBIE | > + USBCRCON_USBRIE | USBCRCON_USBWKUPEN | > + USBCRCON_VBUSMONEN; > + writel(ctrl, musb_glue + USBCRCON); > + > + return 0; > +} > + > +/* PIC32 supports only 32bit read operation */ > +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) > +{ > + void __iomem *fifo = hw_ep->fifo; > + u32 val; > + int i; This could become: bulk_len = len / 4; bulk_rem = len % 4; readsl(fifo, dst, bulk_len); if (rem) { dst += len & ~0x3; tmp = readl(fifo); copy the remaining bytes according to endianness } This is 10 LoC , not 50 ;-) > + /* Read for 32bit-aligned destination address */ > + if (likely((0x03 & (unsigned long)dst) == 0) && len >= 4) { > + readsl(fifo, dst, len / 4); > + dst += len & ~0x03; > + len &= 0x03; > + } > + > + /* > + * Now read the remaining 1 to 3 byte or complete length if > + * unaligned address. > + */ > + if (len > 4) { > + for (i = 0; i < (len / 4); i++) { > + *(u32 *)dst = musb_readl(fifo, 0); > + dst += 4; > + } > + len &= 0x03; > + } > + > + if (len > 0) { > + val = musb_readl(fifo, 0); > + memcpy(dst, &val, len); > + } > +} [...] -- Best regards, Marek Vasut