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 */ 84e1fd7341837238c6c5380c5073887d238f706cf0Russell King retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 8522d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King if (retval) 8622d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King goto fail; 8756fafb94f64efaca625206a3876432b96558dcb0Stefan Roese 8898515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar usbh_clk = devm_clk_get(&pdev->dev, NULL); 89c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (IS_ERR(usbh_clk)) { 90c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "Error getting interface clock\n"); 91c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = PTR_ERR(usbh_clk); 9298515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto fail; 93c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 94c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 95c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 96c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!hcd) { 97c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENOMEM; 9898515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto fail; 99c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 100c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 101c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 102c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (!res) { 103c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri retval = -ENODEV; 10498515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_put_hcd; 105c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 106c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 107c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_start = res->start; 108c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri hcd->rsrc_len = resource_size(res); 109e0f77a91ee30ed785c107ed48fb2171d063df42bVivek Gautam hcd->regs = devm_ioremap_resource(&pdev->dev, res); 110e0f77a91ee30ed785c107ed48fb2171d063df42bVivek Gautam if (IS_ERR(hcd->regs)) { 111e0f77a91ee30ed785c107ed48fb2171d063df42bVivek Gautam retval = PTR_ERR(hcd->regs); 11298515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_put_hcd; 113c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 114c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1157675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar sehci = to_spear_ehci(hcd); 1167675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar sehci->clk = usbh_clk; 1177675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1187675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar /* registers start at offset 0x0 */ 1197675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar hcd_to_ehci(hcd)->caps = hcd->regs; 120c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1217675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_prepare_enable(sehci->clk); 122b5dd18d8747010e3f3eb1cc76a49f94291938559Yong Zhang retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 123c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri if (retval) 12498515e5923b1c8f982511eeec9d27014b05efebfViresh Kumar goto err_stop_ehci; 125c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1263c9740a117d40a74412775b5d3fe2b88a7635a0ePeter Chen device_wakeup_enable(hcd->self.controller); 127c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval; 128c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 12998515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarerr_stop_ehci: 1307675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_disable_unprepare(sehci->clk); 13198515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarerr_put_hcd: 132c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 13398515e5923b1c8f982511eeec9d27014b05efebfViresh Kumarfail: 134c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri dev_err(&pdev->dev, "init fail, %d\n", retval); 135c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 136c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return retval ; 137c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 138c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 139c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic int spear_ehci_hcd_drv_remove(struct platform_device *pdev) 140c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri{ 141c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri struct usb_hcd *hcd = platform_get_drvdata(pdev); 1427675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar struct spear_ehci *sehci = to_spear_ehci(hcd); 143c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 144c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_remove_hcd(hcd); 145c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1467675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar if (sehci->clk) 1477675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar clk_disable_unprepare(sehci->clk); 148c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri usb_put_hcd(hcd); 149c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 150c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri return 0; 151c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri} 152c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1533632eba532fce0651f69d605177b53ff8d91d91eJingoo Hanstatic const struct of_device_id spear_ehci_id_table[] = { 15456fafb94f64efaca625206a3876432b96558dcb0Stefan Roese { .compatible = "st,spear600-ehci", }, 15556fafb94f64efaca625206a3876432b96558dcb0Stefan Roese { }, 15656fafb94f64efaca625206a3876432b96558dcb0Stefan Roese}; 15756fafb94f64efaca625206a3876432b96558dcb0Stefan Roese 158c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikristatic struct platform_driver spear_ehci_hcd_driver = { 159c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .probe = spear_ehci_hcd_drv_probe, 160c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .remove = spear_ehci_hcd_drv_remove, 161c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .shutdown = usb_hcd_platform_shutdown, 162c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .driver = { 163c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri .name = "spear-ehci", 1648c1b369394d188afb954ef470d90ac887438530cDeepak Sikri .bus = &platform_bus_type, 1658c1b369394d188afb954ef470d90ac887438530cDeepak Sikri .pm = &ehci_spear_pm_ops, 1662c398f3e4a5f791ac7ce0d7a5fc963a7e067aa66Sachin Kamat .of_match_table = spear_ehci_id_table, 167c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri } 168c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri}; 169c8c38de9d8002578599222296b90696745ac0fe3Deepak Sikri 1707675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic const struct ehci_driver_overrides spear_overrides __initdata = { 1717675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar .extra_priv_size = sizeof(struct spear_ehci), 1727675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar}; 1737675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1747675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic int __init ehci_spear_init(void) 1757675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar{ 1767675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar if (usb_disabled()) 1777675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar return -ENODEV; 1787675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1797675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar pr_info("%s: " DRIVER_DESC "\n", hcd_name); 1807675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1817675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides); 1827675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar return platform_driver_register(&spear_ehci_hcd_driver); 1837675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar} 1847675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarmodule_init(ehci_spear_init); 1857675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1867675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarstatic void __exit ehci_spear_cleanup(void) 1877675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar{ 1887675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar platform_driver_unregister(&spear_ehci_hcd_driver); 1897675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar} 1907675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudarmodule_exit(ehci_spear_cleanup); 1917675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath Goudar 1927675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_DESCRIPTION(DRIVER_DESC); 193c8c38de9d8002578599222296b90696745ac0fe3Deepak SikriMODULE_ALIAS("platform:spear-ehci"); 1947675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_AUTHOR("Deepak Sikri"); 1957675d6ba436f8439fc524ee0b42dc562cb1bc74eManjunath GoudarMODULE_LICENSE("GPL"); 196