1760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin/* 2760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * Copyright 2008 Cavium Networks 3760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * 4760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * This file is free software; you can redistribute it and/or modify 5760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * it under the terms of the GNU General Public License, Version 2, as 6760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * published by the Free Software Foundation. 7760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin */ 8760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 9760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#include <linux/platform_device.h> 10760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#include <linux/atomic.h> 11760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#include <mach/cns3xxx.h> 12760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#include <mach/pm.h> 13760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 14760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linstatic int __devinit 15760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lincns3xxx_ohci_start(struct usb_hcd *hcd) 16760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin{ 17760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin struct ohci_hcd *ohci = hcd_to_ohci(hcd); 18760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin int ret; 19760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 20760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin /* 21760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * EHCI and OHCI share the same clock and power, 22760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * resetting twice would cause the 1st controller been reset. 23760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * Therefore only do power up at the first up device, and 24760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * power down at the last down device. 25760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * 26760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * Set USB AHB INCR length to 16 27760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin */ 28760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (atomic_inc_return(&usb_pwr_ref) == 1) { 29760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); 30760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 31760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); 32760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), 33760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin MISC_CHIP_CONFIG_REG); 34760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 35760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 36760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin ret = ohci_init(ohci); 37760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (ret < 0) 38760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return ret; 39760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 40760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin ohci->num_ports = 1; 41760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 42760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin ret = ohci_run(ohci); 43760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (ret < 0) { 44760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin err("can't start %s", hcd->self.bus_name); 45760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin ohci_stop(hcd); 46760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return ret; 47760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 48760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return 0; 49760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin} 50760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 51760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linstatic const struct hc_driver cns3xxx_ohci_hc_driver = { 52760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .description = hcd_name, 53760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .product_desc = "CNS3XXX OHCI Host controller", 54760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .hcd_priv_size = sizeof(struct ohci_hcd), 55760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .irq = ohci_irq, 56760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .flags = HCD_USB11 | HCD_MEMORY, 57760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .start = cns3xxx_ohci_start, 58760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .stop = ohci_stop, 59760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .shutdown = ohci_shutdown, 60760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .urb_enqueue = ohci_urb_enqueue, 61760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .urb_dequeue = ohci_urb_dequeue, 62760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .endpoint_disable = ohci_endpoint_disable, 63760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .get_frame_number = ohci_get_frame, 64760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .hub_status_data = ohci_hub_status_data, 65760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .hub_control = ohci_hub_control, 66760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#ifdef CONFIG_PM 67760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .bus_suspend = ohci_bus_suspend, 68760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .bus_resume = ohci_bus_resume, 69760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin#endif 70760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .start_port_reset = ohci_start_port_reset, 71760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin}; 72760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 73760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linstatic int cns3xxx_ohci_probe(struct platform_device *pdev) 74760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin{ 75760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin struct device *dev = &pdev->dev; 76760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin struct usb_hcd *hcd; 77760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; 78760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin struct resource *res; 79760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin int irq; 80760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin int retval; 81760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 82760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (usb_disabled()) 83760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return -ENODEV; 84760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 85760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 86760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (!res) { 87760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin dev_err(dev, "Found HC with no IRQ.\n"); 88760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return -ENODEV; 89760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 90760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin irq = res->start; 91760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 92760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin hcd = usb_create_hcd(driver, dev, dev_name(dev)); 93760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (!hcd) 94760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return -ENOMEM; 95760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 96760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 97760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (!res) { 98760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin dev_err(dev, "Found HC with no register addr.\n"); 99760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin retval = -ENODEV; 100760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin goto err1; 101760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 102760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin hcd->rsrc_start = res->start; 10328f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches hcd->rsrc_len = resource_size(res); 104760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 105760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 106760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin driver->description)) { 107760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin dev_dbg(dev, "controller already in use\n"); 108760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin retval = -EBUSY; 109760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin goto err1; 110760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 111760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 112760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 113760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (!hcd->regs) { 114760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin dev_dbg(dev, "error mapping memory\n"); 115760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin retval = -EFAULT; 116760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin goto err2; 117760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin } 118760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 119760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin ohci_hcd_init(hcd_to_ohci(hcd)); 120760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 121760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 122760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (retval == 0) 123760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return retval; 124760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 125760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin iounmap(hcd->regs); 126760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linerr2: 127760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 128760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linerr1: 129760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin usb_put_hcd(hcd); 130760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return retval; 131760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin} 132760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 133760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linstatic int cns3xxx_ohci_remove(struct platform_device *pdev) 134760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin{ 135760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin struct usb_hcd *hcd = platform_get_drvdata(pdev); 136760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 137760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin usb_remove_hcd(hcd); 138760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin iounmap(hcd->regs); 139760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 140760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 141760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin /* 142760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * EHCI and OHCI share the same clock and power, 143760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * resetting twice would cause the 1st controller been reset. 144760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * Therefore only do power up at the first up device, and 145760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin * power down at the last down device. 146760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin */ 147760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin if (atomic_dec_return(&usb_pwr_ref) == 0) 148760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 149760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 150760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin usb_put_hcd(hcd); 151760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 152760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin platform_set_drvdata(pdev, NULL); 153760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 154760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin return 0; 155760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin} 156760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 157760efe6910d5743084b586d3d0a3b65aea96fb2fMac LinMODULE_ALIAS("platform:cns3xxx-ohci"); 158760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin 159760efe6910d5743084b586d3d0a3b65aea96fb2fMac Linstatic struct platform_driver ohci_hcd_cns3xxx_driver = { 160760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .probe = cns3xxx_ohci_probe, 161760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .remove = cns3xxx_ohci_remove, 162760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .driver = { 163760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin .name = "cns3xxx-ohci", 164760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin }, 165760efe6910d5743084b586d3d0a3b65aea96fb2fMac Lin}; 166