Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.0-rc4 202 lines 4.6 kB view raw
1/* 2 * SAMSUNG S5P USB HOST EHCI Controller 3 * 4 * Copyright (C) 2011 Samsung Electronics Co.Ltd 5 * Author: Jingoo Han <jg1.han@samsung.com> 6 * Author: Joonyoung Shim <jy0922.shim@samsung.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 */ 14 15#include <linux/clk.h> 16#include <linux/platform_device.h> 17#include <mach/regs-pmu.h> 18#include <plat/cpu.h> 19#include <plat/ehci.h> 20#include <plat/usb-phy.h> 21 22struct s5p_ehci_hcd { 23 struct device *dev; 24 struct usb_hcd *hcd; 25 struct clk *clk; 26}; 27 28static const struct hc_driver s5p_ehci_hc_driver = { 29 .description = hcd_name, 30 .product_desc = "S5P EHCI Host Controller", 31 .hcd_priv_size = sizeof(struct ehci_hcd), 32 33 .irq = ehci_irq, 34 .flags = HCD_MEMORY | HCD_USB2, 35 36 .reset = ehci_init, 37 .start = ehci_run, 38 .stop = ehci_stop, 39 .shutdown = ehci_shutdown, 40 41 .get_frame_number = ehci_get_frame, 42 43 .urb_enqueue = ehci_urb_enqueue, 44 .urb_dequeue = ehci_urb_dequeue, 45 .endpoint_disable = ehci_endpoint_disable, 46 .endpoint_reset = ehci_endpoint_reset, 47 48 .hub_status_data = ehci_hub_status_data, 49 .hub_control = ehci_hub_control, 50 .bus_suspend = ehci_bus_suspend, 51 .bus_resume = ehci_bus_resume, 52 53 .relinquish_port = ehci_relinquish_port, 54 .port_handed_over = ehci_port_handed_over, 55 56 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 57}; 58 59static int __devinit s5p_ehci_probe(struct platform_device *pdev) 60{ 61 struct s5p_ehci_platdata *pdata; 62 struct s5p_ehci_hcd *s5p_ehci; 63 struct usb_hcd *hcd; 64 struct ehci_hcd *ehci; 65 struct resource *res; 66 int irq; 67 int err; 68 69 pdata = pdev->dev.platform_data; 70 if (!pdata) { 71 dev_err(&pdev->dev, "No platform data defined\n"); 72 return -EINVAL; 73 } 74 75 s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL); 76 if (!s5p_ehci) 77 return -ENOMEM; 78 79 s5p_ehci->dev = &pdev->dev; 80 81 hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, 82 dev_name(&pdev->dev)); 83 if (!hcd) { 84 dev_err(&pdev->dev, "Unable to create HCD\n"); 85 err = -ENOMEM; 86 goto fail_hcd; 87 } 88 89 s5p_ehci->clk = clk_get(&pdev->dev, "usbhost"); 90 91 if (IS_ERR(s5p_ehci->clk)) { 92 dev_err(&pdev->dev, "Failed to get usbhost clock\n"); 93 err = PTR_ERR(s5p_ehci->clk); 94 goto fail_clk; 95 } 96 97 err = clk_enable(s5p_ehci->clk); 98 if (err) 99 goto fail_clken; 100 101 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 102 if (!res) { 103 dev_err(&pdev->dev, "Failed to get I/O memory\n"); 104 err = -ENXIO; 105 goto fail_io; 106 } 107 108 hcd->rsrc_start = res->start; 109 hcd->rsrc_len = resource_size(res); 110 hcd->regs = ioremap(res->start, resource_size(res)); 111 if (!hcd->regs) { 112 dev_err(&pdev->dev, "Failed to remap I/O memory\n"); 113 err = -ENOMEM; 114 goto fail_io; 115 } 116 117 irq = platform_get_irq(pdev, 0); 118 if (!irq) { 119 dev_err(&pdev->dev, "Failed to get IRQ\n"); 120 err = -ENODEV; 121 goto fail; 122 } 123 124 if (pdata->phy_init) 125 pdata->phy_init(pdev, S5P_USB_PHY_HOST); 126 127 ehci = hcd_to_ehci(hcd); 128 ehci->caps = hcd->regs; 129 ehci->regs = hcd->regs + 130 HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); 131 132 dbg_hcs_params(ehci, "reset"); 133 dbg_hcc_params(ehci, "reset"); 134 135 /* cache this readonly data; minimize chip reads */ 136 ehci->hcs_params = readl(&ehci->caps->hcs_params); 137 138 err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); 139 if (err) { 140 dev_err(&pdev->dev, "Failed to add USB HCD\n"); 141 goto fail; 142 } 143 144 platform_set_drvdata(pdev, s5p_ehci); 145 146 return 0; 147 148fail: 149 iounmap(hcd->regs); 150fail_io: 151 clk_disable(s5p_ehci->clk); 152fail_clken: 153 clk_put(s5p_ehci->clk); 154fail_clk: 155 usb_put_hcd(hcd); 156fail_hcd: 157 kfree(s5p_ehci); 158 return err; 159} 160 161static int __devexit s5p_ehci_remove(struct platform_device *pdev) 162{ 163 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; 164 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); 165 struct usb_hcd *hcd = s5p_ehci->hcd; 166 167 usb_remove_hcd(hcd); 168 169 if (pdata && pdata->phy_exit) 170 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 171 172 iounmap(hcd->regs); 173 174 clk_disable(s5p_ehci->clk); 175 clk_put(s5p_ehci->clk); 176 177 usb_put_hcd(hcd); 178 kfree(s5p_ehci); 179 180 return 0; 181} 182 183static void s5p_ehci_shutdown(struct platform_device *pdev) 184{ 185 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); 186 struct usb_hcd *hcd = s5p_ehci->hcd; 187 188 if (hcd->driver->shutdown) 189 hcd->driver->shutdown(hcd); 190} 191 192static struct platform_driver s5p_ehci_driver = { 193 .probe = s5p_ehci_probe, 194 .remove = __devexit_p(s5p_ehci_remove), 195 .shutdown = s5p_ehci_shutdown, 196 .driver = { 197 .name = "s5p-ehci", 198 .owner = THIS_MODULE, 199 } 200}; 201 202MODULE_ALIAS("platform:s5p-ehci");