1 /* 2 * SAMSUNG EXYNOS USB HOST OHCI Controller 3 * 4 * Copyright (C) 2011 Samsung Electronics Co.Ltd 5 * Author: Jingoo Han <jg1.han@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 * 12 */ 13 14 #include <linux/clk.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 #include <linux/platform_data/usb-exynos.h> 18 #include <plat/usb-phy.h> 19 20 struct exynos_ohci_hcd { 21 struct device *dev; 22 struct usb_hcd *hcd; 23 struct clk *clk; 24 }; 25 26 static int ohci_exynos_reset(struct usb_hcd *hcd) 27 { 28 return ohci_init(hcd_to_ohci(hcd)); 29 } 30 31 static int ohci_exynos_start(struct usb_hcd *hcd) 32 { 33 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 34 int ret; 35 36 ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); 37 38 ret = ohci_run(ohci); 39 if (ret < 0) { 40 dev_err(hcd->self.controller, "can't start %s\n", 41 hcd->self.bus_name); 42 ohci_stop(hcd); 43 return ret; 44 } 45 46 return 0; 47 } 48 49 static const struct hc_driver exynos_ohci_hc_driver = { 50 .description = hcd_name, 51 .product_desc = "EXYNOS OHCI Host Controller", 52 .hcd_priv_size = sizeof(struct ohci_hcd), 53 54 .irq = ohci_irq, 55 .flags = HCD_MEMORY|HCD_USB11, 56 57 .reset = ohci_exynos_reset, 58 .start = ohci_exynos_start, 59 .stop = ohci_stop, 60 .shutdown = ohci_shutdown, 61 62 .get_frame_number = ohci_get_frame, 63 64 .urb_enqueue = ohci_urb_enqueue, 65 .urb_dequeue = ohci_urb_dequeue, 66 .endpoint_disable = ohci_endpoint_disable, 67 68 .hub_status_data = ohci_hub_status_data, 69 .hub_control = ohci_hub_control, 70 #ifdef CONFIG_PM 71 .bus_suspend = ohci_bus_suspend, 72 .bus_resume = ohci_bus_resume, 73 #endif 74 .start_port_reset = ohci_start_port_reset, 75 }; 76 77 static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32); 78 79 static int exynos_ohci_probe(struct platform_device *pdev) 80 { 81 struct exynos4_ohci_platdata *pdata; 82 struct exynos_ohci_hcd *exynos_ohci; 83 struct usb_hcd *hcd; 84 struct ohci_hcd *ohci; 85 struct resource *res; 86 int irq; 87 int err; 88 89 pdata = pdev->dev.platform_data; 90 if (!pdata) { 91 dev_err(&pdev->dev, "No platform data defined\n"); 92 return -EINVAL; 93 } 94 95 /* 96 * Right now device-tree probed devices don't get dma_mask set. 97 * Since shared usb code relies on it, set it here for now. 98 * Once we move to full device tree support this will vanish off. 99 */ 100 if (!pdev->dev.dma_mask) 101 pdev->dev.dma_mask = &ohci_exynos_dma_mask; 102 if (!pdev->dev.coherent_dma_mask) 103 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 104 105 exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd), 106 GFP_KERNEL); 107 if (!exynos_ohci) 108 return -ENOMEM; 109 110 exynos_ohci->dev = &pdev->dev; 111 112 hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, 113 dev_name(&pdev->dev)); 114 if (!hcd) { 115 dev_err(&pdev->dev, "Unable to create HCD\n"); 116 return -ENOMEM; 117 } 118 119 exynos_ohci->hcd = hcd; 120 exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); 121 122 if (IS_ERR(exynos_ohci->clk)) { 123 dev_err(&pdev->dev, "Failed to get usbhost clock\n"); 124 err = PTR_ERR(exynos_ohci->clk); 125 goto fail_clk; 126 } 127 128 err = clk_prepare_enable(exynos_ohci->clk); 129 if (err) 130 goto fail_clk; 131 132 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 133 if (!res) { 134 dev_err(&pdev->dev, "Failed to get I/O memory\n"); 135 err = -ENXIO; 136 goto fail_io; 137 } 138 139 hcd->rsrc_start = res->start; 140 hcd->rsrc_len = resource_size(res); 141 hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); 142 if (!hcd->regs) { 143 dev_err(&pdev->dev, "Failed to remap I/O memory\n"); 144 err = -ENOMEM; 145 goto fail_io; 146 } 147 148 irq = platform_get_irq(pdev, 0); 149 if (!irq) { 150 dev_err(&pdev->dev, "Failed to get IRQ\n"); 151 err = -ENODEV; 152 goto fail_io; 153 } 154 155 if (pdata->phy_init) 156 pdata->phy_init(pdev, S5P_USB_PHY_HOST); 157 158 ohci = hcd_to_ohci(hcd); 159 ohci_hcd_init(ohci); 160 161 err = usb_add_hcd(hcd, irq, IRQF_SHARED); 162 if (err) { 163 dev_err(&pdev->dev, "Failed to add USB HCD\n"); 164 goto fail_io; 165 } 166 167 platform_set_drvdata(pdev, exynos_ohci); 168 169 return 0; 170 171 fail_io: 172 clk_disable_unprepare(exynos_ohci->clk); 173 fail_clk: 174 usb_put_hcd(hcd); 175 return err; 176 } 177 178 static int exynos_ohci_remove(struct platform_device *pdev) 179 { 180 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; 181 struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); 182 struct usb_hcd *hcd = exynos_ohci->hcd; 183 184 usb_remove_hcd(hcd); 185 186 if (pdata && pdata->phy_exit) 187 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 188 189 clk_disable_unprepare(exynos_ohci->clk); 190 191 usb_put_hcd(hcd); 192 193 return 0; 194 } 195 196 static void exynos_ohci_shutdown(struct platform_device *pdev) 197 { 198 struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); 199 struct usb_hcd *hcd = exynos_ohci->hcd; 200 201 if (hcd->driver->shutdown) 202 hcd->driver->shutdown(hcd); 203 } 204 205 #ifdef CONFIG_PM 206 static int exynos_ohci_suspend(struct device *dev) 207 { 208 struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); 209 struct usb_hcd *hcd = exynos_ohci->hcd; 210 struct ohci_hcd *ohci = hcd_to_ohci(hcd); 211 struct platform_device *pdev = to_platform_device(dev); 212 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; 213 unsigned long flags; 214 int rc = 0; 215 216 /* 217 * Root hub was already suspended. Disable irq emission and 218 * mark HW unaccessible, bail out if RH has been resumed. Use 219 * the spinlock to properly synchronize with possible pending 220 * RH suspend or resume activity. 221 */ 222 spin_lock_irqsave(&ohci->lock, flags); 223 if (ohci->rh_state != OHCI_RH_SUSPENDED && 224 ohci->rh_state != OHCI_RH_HALTED) { 225 rc = -EINVAL; 226 goto fail; 227 } 228 229 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 230 231 if (pdata && pdata->phy_exit) 232 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 233 234 clk_disable_unprepare(exynos_ohci->clk); 235 236 fail: 237 spin_unlock_irqrestore(&ohci->lock, flags); 238 239 return rc; 240 } 241 242 static int exynos_ohci_resume(struct device *dev) 243 { 244 struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); 245 struct usb_hcd *hcd = exynos_ohci->hcd; 246 struct platform_device *pdev = to_platform_device(dev); 247 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; 248 249 clk_prepare_enable(exynos_ohci->clk); 250 251 if (pdata && pdata->phy_init) 252 pdata->phy_init(pdev, S5P_USB_PHY_HOST); 253 254 ohci_resume(hcd, false); 255 256 return 0; 257 } 258 #else 259 #define exynos_ohci_suspend NULL 260 #define exynos_ohci_resume NULL 261 #endif 262 263 static const struct dev_pm_ops exynos_ohci_pm_ops = { 264 .suspend = exynos_ohci_suspend, 265 .resume = exynos_ohci_resume, 266 }; 267 268 #ifdef CONFIG_OF 269 static const struct of_device_id exynos_ohci_match[] = { 270 { .compatible = "samsung,exynos-ohci" }, 271 {}, 272 }; 273 MODULE_DEVICE_TABLE(of, exynos_ohci_match); 274 #endif 275 276 static struct platform_driver exynos_ohci_driver = { 277 .probe = exynos_ohci_probe, 278 .remove = exynos_ohci_remove, 279 .shutdown = exynos_ohci_shutdown, 280 .driver = { 281 .name = "exynos-ohci", 282 .owner = THIS_MODULE, 283 .pm = &exynos_ohci_pm_ops, 284 .of_match_table = of_match_ptr(exynos_ohci_match), 285 } 286 }; 287 288 MODULE_ALIAS("platform:exynos-ohci"); 289 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); 290