ehci-spear.c revision c8c38de9d8002578599222296b90696745ac0fe3
1c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri/* 2c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* Driver for EHCI HCD on SPEAR SOC 3c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* 4c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* Copyright (C) 2010 ST Micro Electronics, 5c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* Deepak Sikri <deepak.sikri@st.com> 6c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* 7c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* Based on various ehci-*.c drivers 8c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* 9c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* This file is subject to the terms and conditions of the GNU General Public 10c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* License. See the file COPYING in the main directory of this archive for 11c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri* more details. 12c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri*/ 13c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 14c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri#include <linux/platform_device.h> 15c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri#include <linux/clk.h> 16c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 17c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristruct spear_ehci { 18c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct ehci_hcd ehci; 19c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct clk *clk; 20c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri}; 21c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 22c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd) 23c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 24c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic void spear_start_ehci(struct spear_ehci *ehci) 25c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 26c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri clk_enable(ehci->clk); 27c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 28c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 29c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic void spear_stop_ehci(struct spear_ehci *ehci) 30c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 31c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri clk_disable(ehci->clk); 32c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 33c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 34c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int ehci_spear_setup(struct usb_hcd *hcd) 35c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 36c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct ehci_hcd *ehci = hcd_to_ehci(hcd); 37c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri int retval = 0; 38c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 39c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* registers start at offset 0x0 */ 40c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci->caps = hcd->regs; 41c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, 42c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri &ehci->caps->hc_capbase)); 43c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* cache this readonly data; minimize chip reads */ 44c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 45c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = ehci_halt(ehci); 46c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (retval) 47c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 48c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 49c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = ehci_init(hcd); 50c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (retval) 51c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 52c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 53c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci_reset(ehci); 54c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci_port_power(ehci, 0); 55c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 56c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 57c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 58c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 59c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic const struct hc_driver ehci_spear_hc_driver = { 60c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .description = hcd_name, 61c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .product_desc = "SPEAr EHCI", 62c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .hcd_priv_size = sizeof(struct spear_ehci), 63c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 64c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* generic hardware linkage */ 65c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .irq = ehci_irq, 66c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .flags = HCD_MEMORY | HCD_USB2, 67c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 68c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* basic lifecycle operations */ 69c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .reset = ehci_spear_setup, 70c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .start = ehci_run, 71c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .stop = ehci_stop, 72c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .shutdown = ehci_shutdown, 73c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 74c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* managing i/o requests and associated device resources */ 75c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .urb_enqueue = ehci_urb_enqueue, 76c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .urb_dequeue = ehci_urb_dequeue, 77c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .endpoint_disable = ehci_endpoint_disable, 78c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .endpoint_reset = ehci_endpoint_reset, 79c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 80c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* scheduling support */ 81c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .get_frame_number = ehci_get_frame, 82c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 83c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri /* root hub support */ 84c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .hub_status_data = ehci_hub_status_data, 85c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .hub_control = ehci_hub_control, 86c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .bus_suspend = ehci_bus_suspend, 87c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .bus_resume = ehci_bus_resume, 88c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .relinquish_port = ehci_relinquish_port, 89c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .port_handed_over = ehci_port_handed_over, 90c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 91c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri}; 92c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 93c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int spear_ehci_hcd_drv_probe(struct platform_device *pdev) 94c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 95c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct usb_hcd *hcd ; 96c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct spear_ehci *ehci; 97c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct resource *res; 98c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct clk *usbh_clk; 99c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri const struct hc_driver *driver = &ehci_spear_hc_driver; 100c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri int *pdata = pdev->dev.platform_data; 101c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri int irq, retval; 102c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri char clk_name[20] = "usbh_clk"; 103c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 104c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (pdata == NULL) 105c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return -EFAULT; 106c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 107c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (usb_disabled()) 108c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return -ENODEV; 109c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 110c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri irq = platform_get_irq(pdev, 0); 111c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (irq < 0) { 112c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = irq; 113c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_irq_get; 114c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 115c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 116c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (*pdata >= 0) 117c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri sprintf(clk_name, "usbh.%01d_clk", *pdata); 118c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 119c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usbh_clk = clk_get(NULL, clk_name); 120c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (IS_ERR(usbh_clk)) { 121c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "Error getting interface clock\n"); 122c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = PTR_ERR(usbh_clk); 123c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_get_usbh_clk; 124c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 125c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 126c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 127c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!hcd) { 128c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENOMEM; 129c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_create_hcd; 130c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 131c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 132c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 133c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!res) { 134c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENODEV; 135c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_request_resource; 136c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 137c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 138c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_start = res->start; 139c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_len = resource_size(res); 140c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 141c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri driver->description)) { 142c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -EBUSY; 143c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_request_resource; 144c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 145c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 146c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 147c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (hcd->regs == NULL) { 148c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_dbg(&pdev->dev, "error mapping memory\n"); 149c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENOMEM; 150c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_ioremap; 151c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 152c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 153c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci = (struct spear_ehci *)hcd_to_ehci(hcd); 154c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri ehci->clk = usbh_clk; 155c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 156c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri spear_start_ehci(ehci); 157c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED); 158c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (retval) 159c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri goto fail_add_hcd; 160c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 161c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 162c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 163c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_add_hcd: 164c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri spear_stop_ehci(ehci); 165c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri iounmap(hcd->regs); 166c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_ioremap: 167c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 168c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_request_resource: 169c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 170c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_create_hcd: 171c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri clk_put(usbh_clk); 172c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_get_usbh_clk: 173c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikrifail_irq_get: 174c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "init fail, %d\n", retval); 175c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 176c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval ; 177c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 178c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 179c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int spear_ehci_hcd_drv_remove(struct platform_device *pdev) 180c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 181c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct usb_hcd *hcd = platform_get_drvdata(pdev); 182c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct spear_ehci *ehci_p = to_spear_ehci(hcd); 183c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 184c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!hcd) 185c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return 0; 186c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (in_interrupt()) 187c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri BUG(); 188c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_remove_hcd(hcd); 189c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 190c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (ehci_p->clk) 191c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri spear_stop_ehci(ehci_p); 192c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri iounmap(hcd->regs); 193c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 194c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 195c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 196c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (ehci_p->clk) 197c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri clk_put(ehci_p->clk); 198c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 199c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return 0; 200c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 201c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 202c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic struct platform_driver spear_ehci_hcd_driver = { 203c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .probe = spear_ehci_hcd_drv_probe, 204c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .remove = spear_ehci_hcd_drv_remove, 205c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .shutdown = usb_hcd_platform_shutdown, 206c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .driver = { 207c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .name = "spear-ehci", 208c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .bus = &platform_bus_type 209c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 210c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri}; 211c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 212c8c38de9d8002578599222296b90696745ac0fe3Deepak SikriMODULE_ALIAS("platform:spear-ehci"); 213