1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * SuperH EHCI host controller driver 4 * 5 * Copyright (C) 2010 Paul Mundt 6 * 7 * Based on ohci-sh.c and ehci-atmel.c. 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file "COPYING" in the main directory of this archive 11 * for more details. 12 */ 13 #include <linux/platform_device.h> 14 #include <linux/clk.h> 15 #include <linux/platform_data/ehci-sh.h> 16 17 struct ehci_sh_priv { 18 struct clk *iclk, *fclk; 19 struct usb_hcd *hcd; 20 }; 21 22 static int ehci_sh_reset(struct usb_hcd *hcd) 23 { 24 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 25 26 ehci->caps = hcd->regs; 27 28 return ehci_setup(hcd); 29 } 30 31 static const struct hc_driver ehci_sh_hc_driver = { 32 .description = hcd_name, 33 .product_desc = "SuperH EHCI", 34 .hcd_priv_size = sizeof(struct ehci_hcd), 35 36 /* 37 * generic hardware linkage 38 */ 39 .irq = ehci_irq, 40 .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, 41 42 /* 43 * basic lifecycle operations 44 */ 45 .reset = ehci_sh_reset, 46 .start = ehci_run, 47 .stop = ehci_stop, 48 .shutdown = ehci_shutdown, 49 50 /* 51 * managing i/o requests and associated device resources 52 */ 53 .urb_enqueue = ehci_urb_enqueue, 54 .urb_dequeue = ehci_urb_dequeue, 55 .endpoint_disable = ehci_endpoint_disable, 56 .endpoint_reset = ehci_endpoint_reset, 57 58 /* 59 * scheduling support 60 */ 61 .get_frame_number = ehci_get_frame, 62 63 /* 64 * root hub support 65 */ 66 .hub_status_data = ehci_hub_status_data, 67 .hub_control = ehci_hub_control, 68 69 #ifdef CONFIG_PM 70 .bus_suspend = ehci_bus_suspend, 71 .bus_resume = ehci_bus_resume, 72 #endif 73 74 .relinquish_port = ehci_relinquish_port, 75 .port_handed_over = ehci_port_handed_over, 76 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 77 }; 78 79 static int ehci_hcd_sh_probe(struct platform_device *pdev) 80 { 81 struct resource *res; 82 struct ehci_sh_priv *priv; 83 struct ehci_sh_platdata *pdata; 84 struct usb_hcd *hcd; 85 int irq, ret; 86 87 if (usb_disabled()) 88 return -ENODEV; 89 90 irq = platform_get_irq(pdev, 0); 91 if (irq <= 0) { 92 dev_err(&pdev->dev, 93 "Found HC with no IRQ. Check %s setup!\n", 94 dev_name(&pdev->dev)); 95 ret = -ENODEV; 96 goto fail_create_hcd; 97 } 98 99 pdata = dev_get_platdata(&pdev->dev); 100 101 /* initialize hcd */ 102 hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, 103 dev_name(&pdev->dev)); 104 if (!hcd) { 105 ret = -ENOMEM; 106 goto fail_create_hcd; 107 } 108 109 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 110 hcd->regs = devm_ioremap_resource(&pdev->dev, res); 111 if (IS_ERR(hcd->regs)) { 112 ret = PTR_ERR(hcd->regs); 113 goto fail_request_resource; 114 } 115 hcd->rsrc_start = res->start; 116 hcd->rsrc_len = resource_size(res); 117 118 priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv), 119 GFP_KERNEL); 120 if (!priv) { 121 ret = -ENOMEM; 122 goto fail_request_resource; 123 } 124 125 /* These are optional, we don't care if they fail */ 126 priv->fclk = devm_clk_get(&pdev->dev, "usb_fck"); 127 if (IS_ERR(priv->fclk)) 128 priv->fclk = NULL; 129 130 priv->iclk = devm_clk_get(&pdev->dev, "usb_ick"); 131 if (IS_ERR(priv->iclk)) 132 priv->iclk = NULL; 133 134 clk_enable(priv->fclk); 135 clk_enable(priv->iclk); 136 137 if (pdata && pdata->phy_init) 138 pdata->phy_init(); 139 140 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 141 if (ret != 0) { 142 dev_err(&pdev->dev, "Failed to add hcd"); 143 goto fail_add_hcd; 144 } 145 device_wakeup_enable(hcd->self.controller); 146 147 priv->hcd = hcd; 148 platform_set_drvdata(pdev, priv); 149 150 return ret; 151 152 fail_add_hcd: 153 clk_disable(priv->iclk); 154 clk_disable(priv->fclk); 155 156 fail_request_resource: 157 usb_put_hcd(hcd); 158 fail_create_hcd: 159 dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret); 160 161 return ret; 162 } 163 164 static int ehci_hcd_sh_remove(struct platform_device *pdev) 165 { 166 struct ehci_sh_priv *priv = platform_get_drvdata(pdev); 167 struct usb_hcd *hcd = priv->hcd; 168 169 usb_remove_hcd(hcd); 170 usb_put_hcd(hcd); 171 172 clk_disable(priv->fclk); 173 clk_disable(priv->iclk); 174 175 return 0; 176 } 177 178 static void ehci_hcd_sh_shutdown(struct platform_device *pdev) 179 { 180 struct ehci_sh_priv *priv = platform_get_drvdata(pdev); 181 struct usb_hcd *hcd = priv->hcd; 182 183 if (hcd->driver->shutdown) 184 hcd->driver->shutdown(hcd); 185 } 186 187 static struct platform_driver ehci_hcd_sh_driver = { 188 .probe = ehci_hcd_sh_probe, 189 .remove = ehci_hcd_sh_remove, 190 .shutdown = ehci_hcd_sh_shutdown, 191 .driver = { 192 .name = "sh_ehci", 193 }, 194 }; 195 196 MODULE_ALIAS("platform:sh_ehci"); 197