ehci-spear.c revision 22d9d8e8316d7f69046c8805ce9aa8d9c43d4e5b
1c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri/* 27675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar* 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/clk.h> 157675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/dma-mapping.h> 167675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/io.h> 178c1b369394d188afb954ef470d90ac887438530cDeepak Sikri#include <linux/jiffies.h> 187675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/kernel.h> 197675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/module.h> 2056fafb94f64efaca625206a3876432b96558dcb0Stefan Roese#include <linux/of.h> 218c1b369394d188afb954ef470d90ac887438530cDeepak Sikri#include <linux/platform_device.h> 228c1b369394d188afb954ef470d90ac887438530cDeepak Sikri#include <linux/pm.h> 237675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/usb.h> 247675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include <linux/usb/hcd.h> 25c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 267675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#include "ehci.h" 27c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 287675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#define DRIVER_DESC "EHCI SPEAr driver" 29c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 307675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic const char hcd_name[] = "SPEAr-ehci"; 31c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 327675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstruct spear_ehci { 337675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar struct clk *clk; 347675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar}; 35c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 367675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar#define to_spear_ehci(hcd) (struct spear_ehci *)(hcd_to_ehci(hcd)->priv) 37c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 387675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic struct hc_driver __read_mostly ehci_spear_hc_driver; 39c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 40ab1f046a1908d60d2bad20c3ac0f9e71db72318fJingoo Han#ifdef CONFIG_PM_SLEEP 418c1b369394d188afb954ef470d90ac887438530cDeepak Sikristatic int ehci_spear_drv_suspend(struct device *dev) 428c1b369394d188afb954ef470d90ac887438530cDeepak Sikri{ 438c1b369394d188afb954ef470d90ac887438530cDeepak Sikri struct usb_hcd *hcd = dev_get_drvdata(dev); 44c5cf9212a368d88fe1e25797699b167f6daa64a5Alan Stern bool do_wakeup = device_may_wakeup(dev); 45c5cf9212a368d88fe1e25797699b167f6daa64a5Alan Stern 46c5cf9212a368d88fe1e25797699b167f6daa64a5Alan Stern return ehci_suspend(hcd, do_wakeup); 478c1b369394d188afb954ef470d90ac887438530cDeepak Sikri} 488c1b369394d188afb954ef470d90ac887438530cDeepak Sikri 498c1b369394d188afb954ef470d90ac887438530cDeepak Sikristatic int ehci_spear_drv_resume(struct device *dev) 508c1b369394d188afb954ef470d90ac887438530cDeepak Sikri{ 518c1b369394d188afb954ef470d90ac887438530cDeepak Sikri struct usb_hcd *hcd = dev_get_drvdata(dev); 528c1b369394d188afb954ef470d90ac887438530cDeepak Sikri 53c5cf9212a368d88fe1e25797699b167f6daa64a5Alan Stern ehci_resume(hcd, false); 548c1b369394d188afb954ef470d90ac887438530cDeepak Sikri return 0; 558c1b369394d188afb954ef470d90ac887438530cDeepak Sikri} 56ab1f046a1908d60d2bad20c3ac0f9e71db72318fJingoo Han#endif /* CONFIG_PM_SLEEP */ 578c1b369394d188afb954ef470d90ac887438530cDeepak Sikri 588c1b369394d188afb954ef470d90ac887438530cDeepak Sikristatic SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, 598c1b369394d188afb954ef470d90ac887438530cDeepak Sikri ehci_spear_drv_resume); 608c1b369394d188afb954ef470d90ac887438530cDeepak Sikri 61c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int spear_ehci_hcd_drv_probe(struct platform_device *pdev) 62c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 63c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct usb_hcd *hcd ; 647675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar struct spear_ehci *sehci; 65c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct resource *res; 66c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct clk *usbh_clk; 67c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri const struct hc_driver *driver = &ehci_spear_hc_driver; 68c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri int irq, retval; 69c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 70c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (usb_disabled()) 71c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return -ENODEV; 72c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 73c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri irq = platform_get_irq(pdev, 0); 74c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (irq < 0) { 75c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = irq; 7698515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto fail; 77c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 78c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 7956fafb94f64efaca625206a3876432b96558dcb0Stefan Roese /* 8056fafb94f64efaca625206a3876432b96558dcb0Stefan Roese * Right now device-tree probed devices don't get dma_mask set. 8156fafb94f64efaca625206a3876432b96558dcb0Stefan Roese * Since shared usb code relies on it, set it here for now. 8256fafb94f64efaca625206a3876432b96558dcb0Stefan Roese * Once we have dma capability bindings this can go away. 8356fafb94f64efaca625206a3876432b96558dcb0Stefan Roese */ 8456fafb94f64efaca625206a3876432b96558dcb0Stefan Roese if (!pdev->dev.dma_mask) 853b9561e9d9b88eca9d4ed6aab025dec2eeeed501Stephen Warren pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; 8622d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 8722d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King if (retval) 8822d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King goto fail; 8956fafb94f64efaca625206a3876432b96558dcb0Stefan Roese 9098515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar usbh_clk = devm_clk_get(&pdev->dev, NULL); 91c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (IS_ERR(usbh_clk)) { 92c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "Error getting interface clock\n"); 93c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = PTR_ERR(usbh_clk); 9498515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto fail; 95c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 96c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 97c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 98c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!hcd) { 99c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENOMEM; 10098515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto fail; 101c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 102c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 103c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 104c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!res) { 105c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENODEV; 10698515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_put_hcd; 107c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 108c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 109c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_start = res->start; 110c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_len = resource_size(res); 11198515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar if (!devm_request_mem_region(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len, 112c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri driver->description)) { 113c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -EBUSY; 11498515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_put_hcd; 115c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 116c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 11798515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); 118c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (hcd->regs == NULL) { 119c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_dbg(&pdev->dev, "error mapping memory\n"); 120c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENOMEM; 12198515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_put_hcd; 122c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 123c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1247675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar sehci = to_spear_ehci(hcd); 1257675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar sehci->clk = usbh_clk; 1267675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1277675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar /* registers start at offset 0x0 */ 1287675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar hcd_to_ehci(hcd)->caps = hcd->regs; 129c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1307675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_prepare_enable(sehci->clk); 131b5dd18d8747010e3f3eb1cc76a49f94291938559Yong Zhang retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 132c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (retval) 13398515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_stop_ehci; 134c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 135c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 136c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 13798515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarerr_stop_ehci: 1387675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_disable_unprepare(sehci->clk); 13998515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarerr_put_hcd: 140c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 14198515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarfail: 142c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "init fail, %d\n", retval); 143c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 144c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval ; 145c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 146c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 147c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int spear_ehci_hcd_drv_remove(struct platform_device *pdev) 148c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 149c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct usb_hcd *hcd = platform_get_drvdata(pdev); 1507675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar struct spear_ehci *sehci = to_spear_ehci(hcd); 151c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 152c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_remove_hcd(hcd); 153c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1547675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar if (sehci->clk) 1557675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_disable_unprepare(sehci->clk); 156c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 157c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 158c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return 0; 159c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 160c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 161d3608b6dafc570bb671c3338288eb2523f8cd52aBill Pembertonstatic struct of_device_id spear_ehci_id_table[] = { 16256fafb94f64efaca625206a3876432b96558dcb0Stefan Roese { .compatible = "st,spear600-ehci", }, 16356fafb94f64efaca625206a3876432b96558dcb0Stefan Roese { }, 16456fafb94f64efaca625206a3876432b96558dcb0Stefan Roese}; 16556fafb94f64efaca625206a3876432b96558dcb0Stefan Roese 166c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic struct platform_driver spear_ehci_hcd_driver = { 167c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .probe = spear_ehci_hcd_drv_probe, 168c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .remove = spear_ehci_hcd_drv_remove, 169c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .shutdown = usb_hcd_platform_shutdown, 170c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .driver = { 171c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .name = "spear-ehci", 1728c1b369394d188afb954ef470d90ac887438530cDeepak Sikri .bus = &platform_bus_type, 1738c1b369394d188afb954ef470d90ac887438530cDeepak Sikri .pm = &ehci_spear_pm_ops, 1742c398f3e4a5f791ac7ce0d7a5fc963a7e067aa66Sachin Kamat .of_match_table = spear_ehci_id_table, 175c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 176c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri}; 177c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1787675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic const struct ehci_driver_overrides spear_overrides __initdata = { 1797675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar .extra_priv_size = sizeof(struct spear_ehci), 1807675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar}; 1817675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1827675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic int __init ehci_spear_init(void) 1837675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar{ 1847675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar if (usb_disabled()) 1857675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar return -ENODEV; 1867675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1877675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar pr_info("%s: " DRIVER_DESC "\n", hcd_name); 1887675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1897675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides); 1907675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar return platform_driver_register(&spear_ehci_hcd_driver); 1917675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar} 1927675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarmodule_init(ehci_spear_init); 1937675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1947675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic void __exit ehci_spear_cleanup(void) 1957675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar{ 1967675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar platform_driver_unregister(&spear_ehci_hcd_driver); 1977675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar} 1987675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarmodule_exit(ehci_spear_cleanup); 1997675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 2007675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_DESCRIPTION(DRIVER_DESC); 201c8c38de9d8002578599222296b90696745ac0fe3Deepak SikriMODULE_ALIAS("platform:spear-ehci"); 2027675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_AUTHOR("Deepak Sikri"); 2037675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_LICENSE("GPL"); 204