mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-09-23 06:41:36 +02:00
usb: musb-new: Add glue driver for ST-Ericsson Ux500
The ST-Ericsson DB8500 SoC contains a MUSB OTG controller which supports both host and gadget mode. For some reason there is nothing special about it - add a simple glue driver for Ux500 that literally just sets up MUSB together with a generic PHY. There are no SoC-specific registers etc needed to make USB work. The new Ux500 glue driver is only tested to work with DM_USB and DM_USB_GADGET. Both host and gadget mode work fine on the u8500 "stemmy" board that is already present in U-Boot. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
This commit is contained in:
parent
4559df9e81
commit
845d9cf61c
@ -72,6 +72,15 @@ config USB_MUSB_SUNXI
|
|||||||
Say y here to enable support for the sunxi OTG / DRC USB controller
|
Say y here to enable support for the sunxi OTG / DRC USB controller
|
||||||
used on almost all sunxi boards.
|
used on almost all sunxi boards.
|
||||||
|
|
||||||
|
config USB_MUSB_UX500
|
||||||
|
bool "Enable ST-Ericsson Ux500 USB controller"
|
||||||
|
depends on DM_USB && DM_USB_GADGET && ARCH_U8500
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Say y to enable support for the MUSB OTG USB controller used in
|
||||||
|
ST-Ericsson Ux500. The driver supports either gadget or host mode
|
||||||
|
based on the selection of CONFIG_USB_MUSB_HOST.
|
||||||
|
|
||||||
config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
|
config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
|
||||||
bool "Disable MUSB bulk split/combine"
|
bool "Disable MUSB bulk split/combine"
|
||||||
default y
|
default y
|
||||||
@ -85,7 +94,7 @@ endif
|
|||||||
|
|
||||||
config USB_MUSB_PIO_ONLY
|
config USB_MUSB_PIO_ONLY
|
||||||
bool "Disable DMA (always use PIO)"
|
bool "Disable DMA (always use PIO)"
|
||||||
default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
|
default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX || USB_MUSB_UX500
|
||||||
help
|
help
|
||||||
All data is copied between memory and FIFO by the CPU.
|
All data is copied between memory and FIFO by the CPU.
|
||||||
DMA controllers are ignored.
|
DMA controllers are ignored.
|
||||||
|
@ -13,6 +13,7 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
|
|||||||
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
|
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
|
||||||
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
|
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
|
||||||
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
|
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
|
||||||
|
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
|
||||||
|
|
||||||
ccflags-y := $(call cc-option,-Wno-unused-variable) \
|
ccflags-y := $(call cc-option,-Wno-unused-variable) \
|
||||||
$(call cc-option,-Wno-unused-but-set-variable) \
|
$(call cc-option,-Wno-unused-but-set-variable) \
|
||||||
|
@ -1526,7 +1526,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
|
|||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
|
#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
|
||||||
defined(CONFIG_ARCH_OMAP4)
|
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
|
||||||
|
|
||||||
static irqreturn_t generic_interrupt(int irq, void *__hci)
|
static irqreturn_t generic_interrupt(int irq, void *__hci)
|
||||||
{
|
{
|
||||||
|
179
drivers/usb/musb-new/ux500.c
Normal file
179
drivers/usb/musb-new/ux500.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/* Copyright (C) 2019 Stephan Gerhold */
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <generic-phy.h>
|
||||||
|
#include <dm/device_compat.h>
|
||||||
|
#include "musb_uboot.h"
|
||||||
|
|
||||||
|
static struct musb_hdrc_config ux500_musb_hdrc_config = {
|
||||||
|
.multipoint = true,
|
||||||
|
.dyn_fifo = true,
|
||||||
|
.num_eps = 16,
|
||||||
|
.ram_bits = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ux500_glue {
|
||||||
|
struct musb_host_data mdata;
|
||||||
|
struct device dev;
|
||||||
|
struct phy phy;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
#define to_ux500_glue(d) container_of(d, struct ux500_glue, dev)
|
||||||
|
|
||||||
|
static int ux500_musb_enable(struct musb *musb)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = to_ux500_glue(musb->controller);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (glue->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = generic_phy_power_on(&glue->phy);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to power on USB PHY\n", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
glue->enabled = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ux500_musb_disable(struct musb *musb)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = to_ux500_glue(musb->controller);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!glue->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = generic_phy_power_off(&glue->phy);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to power off USB PHY\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glue->enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ux500_musb_init(struct musb *musb)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = to_ux500_glue(musb->controller);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = generic_phy_init(&glue->phy);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to init USB PHY\n", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ux500_musb_exit(struct musb *musb)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = to_ux500_glue(musb->controller);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = generic_phy_exit(&glue->phy);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to exit USB PHY\n", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct musb_platform_ops ux500_musb_ops = {
|
||||||
|
.init = ux500_musb_init,
|
||||||
|
.exit = ux500_musb_exit,
|
||||||
|
.enable = ux500_musb_enable,
|
||||||
|
.disable = ux500_musb_disable,
|
||||||
|
};
|
||||||
|
|
||||||
|
int dm_usb_gadget_handle_interrupts(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = dev_get_priv(dev);
|
||||||
|
|
||||||
|
glue->mdata.host->isr(0, glue->mdata.host);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ux500_musb_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_USB_MUSB_HOST
|
||||||
|
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||||
|
#endif
|
||||||
|
struct ux500_glue *glue = dev_get_priv(dev);
|
||||||
|
struct musb_host_data *host = &glue->mdata;
|
||||||
|
struct musb_hdrc_platform_data pdata;
|
||||||
|
void *base = dev_read_addr_ptr(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!base)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to get USB PHY: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&pdata, 0, sizeof(pdata));
|
||||||
|
pdata.platform_ops = &ux500_musb_ops;
|
||||||
|
pdata.config = &ux500_musb_hdrc_config;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_MUSB_HOST
|
||||||
|
priv->desc_before_addr = true;
|
||||||
|
pdata.mode = MUSB_HOST;
|
||||||
|
|
||||||
|
host->host = musb_init_controller(&pdata, &glue->dev, base);
|
||||||
|
if (!host->host)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return musb_lowlevel_init(host);
|
||||||
|
#else
|
||||||
|
pdata.mode = MUSB_PERIPHERAL;
|
||||||
|
host->host = musb_init_controller(&pdata, &glue->dev, base);
|
||||||
|
if (!host->host)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return usb_add_gadget_udc(&glue->dev, &host->host->g);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ux500_musb_remove(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct ux500_glue *glue = dev_get_priv(dev);
|
||||||
|
struct musb_host_data *host = &glue->mdata;
|
||||||
|
|
||||||
|
usb_del_gadget_udc(&host->host->g);
|
||||||
|
musb_stop(host->host);
|
||||||
|
free(host->host);
|
||||||
|
host->host = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id ux500_musb_ids[] = {
|
||||||
|
{ .compatible = "stericsson,db8500-musb" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(ux500_musb) = {
|
||||||
|
.name = "ux500-musb",
|
||||||
|
#ifdef CONFIG_USB_MUSB_HOST
|
||||||
|
.id = UCLASS_USB,
|
||||||
|
#else
|
||||||
|
.id = UCLASS_USB_GADGET_GENERIC,
|
||||||
|
#endif
|
||||||
|
.of_match = ux500_musb_ids,
|
||||||
|
.probe = ux500_musb_probe,
|
||||||
|
.remove = ux500_musb_remove,
|
||||||
|
#ifdef CONFIG_USB_MUSB_HOST
|
||||||
|
.ops = &musb_usb_ops,
|
||||||
|
#endif
|
||||||
|
.plat_auto = sizeof(struct usb_plat),
|
||||||
|
.priv_auto = sizeof(struct ux500_glue),
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user