1// SPDX-License-Identifier: GPL-2.0+ 2/* Copyright (C) 2019 Stephan Gerhold */ 3 4#include <common.h> 5#include <dm.h> 6#include <generic-phy.h> 7#include <dm/device_compat.h> 8#include "musb_uboot.h" 9 10static struct musb_hdrc_config ux500_musb_hdrc_config = { 11 .multipoint = true, 12 .dyn_fifo = true, 13 .num_eps = 16, 14 .ram_bits = 16, 15}; 16 17struct ux500_glue { 18 struct musb_host_data mdata; 19 struct device dev; 20 struct phy phy; 21 bool enabled; 22}; 23#define to_ux500_glue(d) container_of(d, struct ux500_glue, dev) 24 25static int ux500_musb_enable(struct musb *musb) 26{ 27 struct ux500_glue *glue = to_ux500_glue(musb->controller); 28 int ret; 29 30 if (glue->enabled) 31 return 0; 32 33 ret = generic_phy_power_on(&glue->phy); 34 if (ret) { 35 printf("%s: failed to power on USB PHY\n", __func__); 36 return ret; 37 } 38 39 glue->enabled = true; 40 return 0; 41} 42 43static void ux500_musb_disable(struct musb *musb) 44{ 45 struct ux500_glue *glue = to_ux500_glue(musb->controller); 46 int ret; 47 48 if (!glue->enabled) 49 return; 50 51 ret = generic_phy_power_off(&glue->phy); 52 if (ret) { 53 printf("%s: failed to power off USB PHY\n", __func__); 54 return; 55 } 56 57 glue->enabled = false; 58} 59 60static int ux500_musb_init(struct musb *musb) 61{ 62 struct ux500_glue *glue = to_ux500_glue(musb->controller); 63 int ret; 64 65 ret = generic_phy_init(&glue->phy); 66 if (ret) { 67 printf("%s: failed to init USB PHY\n", __func__); 68 return ret; 69 } 70 71 return 0; 72} 73 74static int ux500_musb_exit(struct musb *musb) 75{ 76 struct ux500_glue *glue = to_ux500_glue(musb->controller); 77 int ret; 78 79 ret = generic_phy_exit(&glue->phy); 80 if (ret) { 81 printf("%s: failed to exit USB PHY\n", __func__); 82 return ret; 83 } 84 85 return 0; 86} 87 88static const struct musb_platform_ops ux500_musb_ops = { 89 .init = ux500_musb_init, 90 .exit = ux500_musb_exit, 91 .enable = ux500_musb_enable, 92 .disable = ux500_musb_disable, 93}; 94 95int dm_usb_gadget_handle_interrupts(struct udevice *dev) 96{ 97 struct ux500_glue *glue = dev_get_priv(dev); 98 99 glue->mdata.host->isr(0, glue->mdata.host); 100 return 0; 101} 102 103static int ux500_musb_probe(struct udevice *dev) 104{ 105#ifdef CONFIG_USB_MUSB_HOST 106 struct usb_bus_priv *priv = dev_get_uclass_priv(dev); 107#endif 108 struct ux500_glue *glue = dev_get_priv(dev); 109 struct musb_host_data *host = &glue->mdata; 110 struct musb_hdrc_platform_data pdata; 111 void *base = dev_read_addr_ptr(dev); 112 int ret; 113 114 if (!base) 115 return -EINVAL; 116 117 ret = generic_phy_get_by_name(dev, "usb", &glue->phy); 118 if (ret) { 119 dev_err(dev, "failed to get USB PHY: %d\n", ret); 120 return ret; 121 } 122 123 memset(&pdata, 0, sizeof(pdata)); 124 pdata.platform_ops = &ux500_musb_ops; 125 pdata.config = &ux500_musb_hdrc_config; 126 127#ifdef CONFIG_USB_MUSB_HOST 128 priv->desc_before_addr = true; 129 pdata.mode = MUSB_HOST; 130 131 host->host = musb_init_controller(&pdata, &glue->dev, base); 132 if (!host->host) 133 return -EIO; 134 135 return musb_lowlevel_init(host); 136#else 137 pdata.mode = MUSB_PERIPHERAL; 138 host->host = musb_init_controller(&pdata, &glue->dev, base); 139 if (!host->host) 140 return -EIO; 141 142 return usb_add_gadget_udc(&glue->dev, &host->host->g); 143#endif 144} 145 146static int ux500_musb_remove(struct udevice *dev) 147{ 148 struct ux500_glue *glue = dev_get_priv(dev); 149 struct musb_host_data *host = &glue->mdata; 150 151 usb_del_gadget_udc(&host->host->g); 152 musb_stop(host->host); 153 free(host->host); 154 host->host = NULL; 155 156 return 0; 157} 158 159static const struct udevice_id ux500_musb_ids[] = { 160 { .compatible = "stericsson,db8500-musb" }, 161 { } 162}; 163 164U_BOOT_DRIVER(ux500_musb) = { 165 .name = "ux500-musb", 166#ifdef CONFIG_USB_MUSB_HOST 167 .id = UCLASS_USB, 168#else 169 .id = UCLASS_USB_GADGET_GENERIC, 170#endif 171 .of_match = ux500_musb_ids, 172 .probe = ux500_musb_probe, 173 .remove = ux500_musb_remove, 174#ifdef CONFIG_USB_MUSB_HOST 175 .ops = &musb_usb_ops, 176#endif 177 .plat_auto = sizeof(struct usb_plat), 178 .priv_auto = sizeof(struct ux500_glue), 179}; 180