mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-15 17:34:43 +00:00
usb: musb-new: Add support for Analog Devices SC5xx SoCs
This adds support for the MUSB-based USB controller found in the Analog Devices SC57x and SC58x SoCs. Co-developed-by: Greg Malysa <malysagreg@gmail.com> Signed-off-by: Greg Malysa <malysagreg@gmail.com> Co-developed-by: Ian Roberts <ian.roberts@timesys.com> Signed-off-by: Ian Roberts <ian.roberts@timesys.com> Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com> Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com> Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com> Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com> Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
This commit is contained in:
parent
446179627f
commit
2f6a86a612
4 changed files with 211 additions and 0 deletions
|
@ -637,6 +637,7 @@ F: drivers/gpio/gpio-adi-adsp.c
|
|||
F: drivers/pinctrl/pinctrl-adi-adsp.c
|
||||
F: drivers/serial/serial_adi_uart4.c
|
||||
F: drivers/timer/adi_sc5xx_timer.c
|
||||
F: drivers/usb/musb-new/sc5xx.c
|
||||
F: include/configs/sc5*
|
||||
F: include/dt-bindings/pinctrl/adi-adsp.h
|
||||
F: include/env/adi/
|
||||
|
|
|
@ -22,6 +22,13 @@ config USB_MUSB_GADGET
|
|||
Enables the MUSB USB dual-role controller in gadget mode.
|
||||
|
||||
if USB_MUSB_HOST || USB_MUSB_GADGET
|
||||
config USB_MUSB_SC5XX
|
||||
bool "Analog Devices MUSB support"
|
||||
depends on (SC57X || SC58X)
|
||||
help
|
||||
Say y here to enable support for the USB controller on
|
||||
ADI SC57X/SC58X processors.
|
||||
|
||||
config USB_MUSB_DA8XX
|
||||
bool "Enable DA8xx MUSB Controller"
|
||||
depends on ARCH_DAVINCI
|
||||
|
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
|
|||
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
|
||||
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
|
||||
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
|
||||
obj-$(CONFIG_USB_MUSB_SC5XX) += sc5xx.o
|
||||
|
||||
ccflags-y := $(call cc-option,-Wno-unused-variable) \
|
||||
$(call cc-option,-Wno-unused-but-set-variable) \
|
||||
|
|
202
drivers/usb/musb-new/sc5xx.c
Normal file
202
drivers/usb/musb-new/sc5xx.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright 2022 - Analog Devices, Inc.
|
||||
*
|
||||
* ADI SC5XX MUSB "glue layer"
|
||||
*
|
||||
* Written and/or maintained by Timesys Corporation
|
||||
*
|
||||
* Loosely ported from Linux driver:
|
||||
* Author: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include "linux-compat.h"
|
||||
#include "musb_core.h"
|
||||
#include "musb_uboot.h"
|
||||
|
||||
#define MUSB_SOFTRST 0x7f
|
||||
#define MUSB_SOFTRST_NRST BIT(0)
|
||||
#define MUSB_SOFTRST_NRSTX BIT(1)
|
||||
|
||||
#define REG_USB_VBUS_CTL 0x380
|
||||
#define REG_USB_ID_CTL 0x382
|
||||
#define REG_USB_PHY_CTL 0x394
|
||||
#define REG_USB_PLL_OSC 0x398
|
||||
#define REG_USB_UTMI_CTL 0x39c
|
||||
|
||||
/* controller data */
|
||||
struct sc5xx_musb_data {
|
||||
struct musb_host_data mdata;
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
#define to_sc5xx_musb_data(d) \
|
||||
container_of(d, struct sc5xx_musb_data, dev)
|
||||
|
||||
static void sc5xx_musb_disable(struct musb *musb)
|
||||
{
|
||||
/* no way to shut the controller */
|
||||
}
|
||||
|
||||
static int sc5xx_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 sc5xx_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u8 devctl;
|
||||
|
||||
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
|
||||
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
|
||||
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
|
||||
|
||||
if (musb->int_usb & MUSB_INTR_VBUSERROR) {
|
||||
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
|
||||
devctl = musb_readw(musb->mregs, MUSB_DEVCTL);
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
}
|
||||
if (musb->int_usb || musb->int_tx || musb->int_rx) {
|
||||
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
|
||||
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
|
||||
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
|
||||
ret = musb_interrupt(musb);
|
||||
}
|
||||
|
||||
if (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))
|
||||
musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sc5xx_musb_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(dev);
|
||||
|
||||
switch (mode) {
|
||||
case MUSB_HOST:
|
||||
musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x1);
|
||||
break;
|
||||
case MUSB_PERIPHERAL:
|
||||
musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x3);
|
||||
break;
|
||||
case MUSB_OTG:
|
||||
musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x0);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported mode %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc5xx_musb_init(struct musb *musb)
|
||||
{
|
||||
struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(musb->controller);
|
||||
|
||||
musb->isr = sc5xx_interrupt;
|
||||
|
||||
musb_writel(musb->mregs, REG_USB_PLL_OSC, 20 << 1);
|
||||
musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
|
||||
musb_writeb(musb->mregs, REG_USB_PHY_CTL, 0x80);
|
||||
musb_writel(musb->mregs, REG_USB_UTMI_CTL,
|
||||
0x40 | musb_readl(musb->mregs, REG_USB_UTMI_CTL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct musb_platform_ops sc5xx_musb_ops = {
|
||||
.init = sc5xx_musb_init,
|
||||
.set_mode = sc5xx_musb_set_mode,
|
||||
.disable = sc5xx_musb_disable,
|
||||
.enable = sc5xx_musb_enable,
|
||||
};
|
||||
|
||||
static struct musb_hdrc_config sc5xx_musb_config = {
|
||||
.multipoint = 1,
|
||||
.dyn_fifo = 1,
|
||||
.num_eps = 16,
|
||||
.ram_bits = 12,
|
||||
};
|
||||
|
||||
/* has one MUSB controller which can be host or gadget */
|
||||
static struct musb_hdrc_platform_data sc5xx_musb_plat = {
|
||||
.mode = MUSB_HOST,
|
||||
.config = &sc5xx_musb_config,
|
||||
.power = 100,
|
||||
.platform_ops = &sc5xx_musb_ops,
|
||||
};
|
||||
|
||||
static int musb_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||
struct sc5xx_musb_data *pdata = dev_get_priv(dev);
|
||||
struct musb_host_data *mdata = &pdata->mdata;
|
||||
void __iomem *mregs;
|
||||
int ret;
|
||||
|
||||
priv->desc_before_addr = true;
|
||||
|
||||
mregs = dev_remap_addr(dev);
|
||||
if (!mregs)
|
||||
return -EINVAL;
|
||||
|
||||
/* init controller */
|
||||
if (IS_ENABLED(CONFIG_USB_MUSB_HOST)) {
|
||||
mdata->host = musb_init_controller(&sc5xx_musb_plat,
|
||||
&pdata->dev, mregs);
|
||||
if (!mdata->host)
|
||||
return -EIO;
|
||||
|
||||
ret = musb_lowlevel_init(mdata);
|
||||
} else {
|
||||
sc5xx_musb_plat.mode = MUSB_PERIPHERAL;
|
||||
mdata->host = musb_register(&sc5xx_musb_plat, &pdata->dev, mregs);
|
||||
if (!mdata->host)
|
||||
return -EIO;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int musb_usb_remove(struct udevice *dev)
|
||||
{
|
||||
struct sc5xx_musb_data *pdata = dev_get_priv(dev);
|
||||
|
||||
musb_stop(pdata->mdata.host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sc5xx_musb_ids[] = {
|
||||
{ .compatible = "adi,sc5xx-musb" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(usb_musb) = {
|
||||
.name = "sc5xx-musb",
|
||||
.id = UCLASS_USB,
|
||||
.of_match = sc5xx_musb_ids,
|
||||
.probe = musb_usb_probe,
|
||||
.remove = musb_usb_remove,
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
.ops = &musb_usb_ops,
|
||||
#endif
|
||||
.plat_auto = sizeof(struct usb_plat),
|
||||
.priv_auto = sizeof(struct sc5xx_musb_data),
|
||||
};
|
Loading…
Add table
Reference in a new issue