diff options
Diffstat (limited to 'drivers/usb/musb-new/ti-musb.c')
-rw-r--r-- | drivers/usb/musb-new/ti-musb.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index cf0e296..1c15aa2 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -14,10 +14,195 @@ #include <dm/device-internal.h> #include <dm/lists.h> +#include <asm/io.h> +#include <asm/omap_musb.h> +#include "musb_uboot.h" + DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_DM_USB +/* USB 2.0 PHY Control */ +#define CM_PHY_PWRDN (1 << 0) +#define CM_PHY_OTG_PWRDN (1 << 1) +#define OTGVDET_EN (1 << 19) +#define OTGSESSENDEN (1 << 20) + +#define AM335X_USB1_CTRL 0x8 + +struct ti_musb_platdata { + void *base; + void *ctrl_mod_base; + struct musb_hdrc_platform_data plat; + struct musb_hdrc_config musb_config; + struct omap_musb_board_data otg_board_data; +}; + +static int ti_musb_get_usb_index(int node) +{ + const void *fdt = gd->fdt_blob; + int i = 0; + char path[64]; + const char *alias_path; + char alias[16]; + + fdt_get_path(fdt, node, path, sizeof(path)); + + do { + snprintf(alias, sizeof(alias), "usb%d", i); + alias_path = fdt_get_alias(fdt, alias); + if (alias_path == NULL) { + debug("USB index not found\n"); + return -ENOENT; + } + + if (!strcmp(path, alias_path)) + return i; + + i++; + } while (alias_path); + + return -ENOENT; +} + +static void ti_musb_set_phy_power(struct udevice *dev, u8 on) +{ + struct ti_musb_platdata *platdata = dev_get_platdata(dev); + + if (on) { + clrsetbits_le32(platdata->ctrl_mod_base, + CM_PHY_PWRDN | CM_PHY_OTG_PWRDN, + OTGVDET_EN | OTGSESSENDEN); + } else { + clrsetbits_le32(platdata->ctrl_mod_base, 0, + CM_PHY_PWRDN | CM_PHY_OTG_PWRDN); + } +} + +static int ti_musb_ofdata_to_platdata(struct udevice *dev) +{ + struct ti_musb_platdata *platdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int node = dev->of_offset; + int phys; + int ctrl_mod; + int usb_index; + + platdata->base = (void *)dev_get_addr_index(dev, 1); + + phys = fdtdec_lookup_phandle(fdt, node, "phys"); + ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod"); + platdata->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg"); + usb_index = ti_musb_get_usb_index(node); + switch (usb_index) { + case 1: + platdata->ctrl_mod_base += AM335X_USB1_CTRL; + case 0: + default: + break; + } + + platdata->musb_config.multipoint = fdtdec_get_int(fdt, node, + "mentor,multipoint", + -1); + if (platdata->musb_config.multipoint < 0) { + error("MUSB multipoint DT entry missing\n"); + return -ENOENT; + } + + platdata->musb_config.dyn_fifo = 1; + + platdata->musb_config.num_eps = fdtdec_get_int(fdt, node, + "mentor,num-eps", -1); + if (platdata->musb_config.num_eps < 0) { + error("MUSB num-eps DT entry missing\n"); + return -ENOENT; + } + + platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node, + "mentor,ram-bits", -1); + if (platdata->musb_config.ram_bits < 0) { + error("MUSB ram-bits DT entry missing\n"); + return -ENOENT; + } + + platdata->otg_board_data.set_phy_power = ti_musb_set_phy_power; + platdata->otg_board_data.dev = dev; + platdata->plat.config = &platdata->musb_config; + + platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); + if (platdata->plat.power < 0) { + error("MUSB mentor,power DT entry missing\n"); + return -ENOENT; + } + + platdata->plat.platform_ops = &musb_dsps_ops; + platdata->plat.board_data = &platdata->otg_board_data; + + return 0; +} + +static int ti_musb_host_probe(struct udevice *dev) +{ + struct musb_host_data *host = dev_get_priv(dev); + struct ti_musb_platdata *platdata = dev_get_platdata(dev); + struct usb_bus_priv *priv = dev_get_uclass_priv(dev); + struct omap_musb_board_data *otg_board_data; + int ret; + + priv->desc_before_addr = true; + + otg_board_data = &platdata->otg_board_data; + + host->host = musb_init_controller(&platdata->plat, + (struct device *)otg_board_data, + platdata->base); + if (!host->host) + return -EIO; + + ret = musb_lowlevel_init(host); + + return ret; +} + +static int ti_musb_host_remove(struct udevice *dev) +{ + struct musb_host_data *host = dev_get_priv(dev); + + musb_stop(host->host); + + return 0; +} + +static int ti_musb_host_ofdata_to_platdata(struct udevice *dev) +{ + struct ti_musb_platdata *platdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int node = dev->of_offset; + int ret; + + ret = ti_musb_ofdata_to_platdata(dev); + if (ret) { + error("platdata dt parse error\n"); + return ret; + } + + platdata->plat.mode = MUSB_HOST; + + return 0; +} + +U_BOOT_DRIVER(ti_musb_host) = { + .name = "ti-musb-host", + .id = UCLASS_USB, + .ofdata_to_platdata = ti_musb_host_ofdata_to_platdata, + .probe = ti_musb_host_probe, + .remove = ti_musb_host_remove, + .ops = &musb_usb_ops, + .platdata_auto_alloc_size = sizeof(struct ti_musb_platdata), + .priv_auto_alloc_size = sizeof(struct musb_host_data), +}; + static int ti_musb_wrapper_bind(struct udevice *parent) { const void *fdt = gd->fdt_blob; @@ -41,6 +226,12 @@ static int ti_musb_wrapper_bind(struct udevice *parent) break; case USB_DR_MODE_HOST: /* Bind MUSB host */ + ret = device_bind_driver_to_node(parent, "ti-musb-host", + name, node, &dev); + if (ret) { + error("musb - not able to bind usb host node\n"); + return ret; + } break; default: break; |