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

USB: cns3xxx: Add EHCI and OHCI bus glue for cns3xxx SOCs

The CNS3XXX SOC has include USB EHCI and OHCI compatible controllers.
This patch adds the necessary glue logic to allow ehci-hcd and ohci-hcd
drivers to work on CNS3XXX

The EHCI and OHCI controllers share a common clock control and reset
bit, therefore additional check for the timming of enabling and disabling
is required. The USB bit of PLL Power Down Control is also shared by OTG,
24MHzUART clock, Crypto clock, PCIe reference clock, and Clock Scale
Generator. Therefore we only ensure it is enabled, while not disabling it.

Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

authored by

Mac Lin and committed by
Anton Vorontsov
760efe69 cf36797f

+363
+2
drivers/usb/Kconfig
··· 41 41 default y if MFD_TC6393XB 42 42 default y if ARCH_W90X900 43 43 default y if ARCH_DAVINCI_DA8XX 44 + default y if ARCH_CNS3XXX 44 45 # PPC: 45 46 default y if STB03xxx 46 47 default y if PPC_MPC52xx ··· 67 66 default y if ARCH_AT91SAM9G45 68 67 default y if ARCH_MXC 69 68 default y if ARCH_OMAP3 69 + default y if ARCH_CNS3XXX 70 70 default PCI 71 71 72 72 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+15
drivers/usb/host/Kconfig
··· 147 147 ---help--- 148 148 Enables support for the W90X900 USB controller 149 149 150 + config USB_CNS3XXX_EHCI 151 + bool "Cavium CNS3XXX EHCI Module" 152 + depends on USB_EHCI_HCD && ARCH_CNS3XXX 153 + ---help--- 154 + Enable support for the CNS3XXX SOC's on-chip EHCI controller. 155 + It is needed for high-speed (480Mbit/sec) USB 2.0 device 156 + support. 157 + 150 158 config USB_OXU210HP_HCD 151 159 tristate "OXU210HP HCD support" 152 160 depends on USB ··· 293 285 Broadcom based SSB bus. 294 286 295 287 If unsure, say N. 288 + 289 + config USB_CNS3XXX_OHCI 290 + bool "Cavium CNS3XXX OHCI Module" 291 + depends on USB_OHCI_HCD && ARCH_CNS3XXX 292 + ---help--- 293 + Enable support for the CNS3XXX SOC's on-chip OHCI controller. 294 + It is needed for low-speed USB 1.0 device support. 296 295 297 296 config USB_OHCI_BIG_ENDIAN_DESC 298 297 bool
+171
drivers/usb/host/ehci-cns3xxx.c
··· 1 + /* 2 + * Copyright 2008 Cavium Networks 3 + * 4 + * This file is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License, Version 2, as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/platform_device.h> 10 + #include <linux/atomic.h> 11 + #include <mach/cns3xxx.h> 12 + #include <mach/pm.h> 13 + 14 + static int cns3xxx_ehci_init(struct usb_hcd *hcd) 15 + { 16 + struct ehci_hcd *ehci = hcd_to_ehci(hcd); 17 + int retval; 18 + 19 + /* 20 + * EHCI and OHCI share the same clock and power, 21 + * resetting twice would cause the 1st controller been reset. 22 + * Therefore only do power up at the first up device, and 23 + * power down at the last down device. 24 + * 25 + * Set USB AHB INCR length to 16 26 + */ 27 + if (atomic_inc_return(&usb_pwr_ref) == 1) { 28 + cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); 29 + cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 30 + cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); 31 + __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), 32 + MISC_CHIP_CONFIG_REG); 33 + } 34 + 35 + ehci->caps = hcd->regs; 36 + ehci->regs = hcd->regs 37 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); 38 + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 39 + 40 + hcd->has_tt = 0; 41 + ehci_reset(ehci); 42 + 43 + retval = ehci_init(hcd); 44 + if (retval) 45 + return retval; 46 + 47 + ehci_port_power(ehci, 0); 48 + 49 + return retval; 50 + } 51 + 52 + static const struct hc_driver cns3xxx_ehci_hc_driver = { 53 + .description = hcd_name, 54 + .product_desc = "CNS3XXX EHCI Host Controller", 55 + .hcd_priv_size = sizeof(struct ehci_hcd), 56 + .irq = ehci_irq, 57 + .flags = HCD_MEMORY | HCD_USB2, 58 + .reset = cns3xxx_ehci_init, 59 + .start = ehci_run, 60 + .stop = ehci_stop, 61 + .shutdown = ehci_shutdown, 62 + .urb_enqueue = ehci_urb_enqueue, 63 + .urb_dequeue = ehci_urb_dequeue, 64 + .endpoint_disable = ehci_endpoint_disable, 65 + .endpoint_reset = ehci_endpoint_reset, 66 + .get_frame_number = ehci_get_frame, 67 + .hub_status_data = ehci_hub_status_data, 68 + .hub_control = ehci_hub_control, 69 + #ifdef CONFIG_PM 70 + .bus_suspend = ehci_bus_suspend, 71 + .bus_resume = ehci_bus_resume, 72 + #endif 73 + .relinquish_port = ehci_relinquish_port, 74 + .port_handed_over = ehci_port_handed_over, 75 + 76 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 77 + }; 78 + 79 + static int cns3xxx_ehci_probe(struct platform_device *pdev) 80 + { 81 + struct device *dev = &pdev->dev; 82 + struct usb_hcd *hcd; 83 + const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; 84 + struct resource *res; 85 + int irq; 86 + int retval; 87 + 88 + if (usb_disabled()) 89 + return -ENODEV; 90 + 91 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 92 + if (!res) { 93 + dev_err(dev, "Found HC with no IRQ.\n"); 94 + return -ENODEV; 95 + } 96 + irq = res->start; 97 + 98 + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 99 + if (!hcd) 100 + return -ENOMEM; 101 + 102 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 103 + if (!res) { 104 + dev_err(dev, "Found HC with no register addr.\n"); 105 + retval = -ENODEV; 106 + goto err1; 107 + } 108 + 109 + hcd->rsrc_start = res->start; 110 + hcd->rsrc_len = res->end - res->start + 1; 111 + 112 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 113 + driver->description)) { 114 + dev_dbg(dev, "controller already in use\n"); 115 + retval = -EBUSY; 116 + goto err1; 117 + } 118 + 119 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 120 + if (hcd->regs == NULL) { 121 + dev_dbg(dev, "error mapping memory\n"); 122 + retval = -EFAULT; 123 + goto err2; 124 + } 125 + 126 + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 127 + if (retval == 0) 128 + return retval; 129 + 130 + iounmap(hcd->regs); 131 + err2: 132 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 133 + err1: 134 + usb_put_hcd(hcd); 135 + 136 + return retval; 137 + } 138 + 139 + static int cns3xxx_ehci_remove(struct platform_device *pdev) 140 + { 141 + struct usb_hcd *hcd = platform_get_drvdata(pdev); 142 + 143 + usb_remove_hcd(hcd); 144 + iounmap(hcd->regs); 145 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 146 + 147 + /* 148 + * EHCI and OHCI share the same clock and power, 149 + * resetting twice would cause the 1st controller been reset. 150 + * Therefore only do power up at the first up device, and 151 + * power down at the last down device. 152 + */ 153 + if (atomic_dec_return(&usb_pwr_ref) == 0) 154 + cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 155 + 156 + usb_put_hcd(hcd); 157 + 158 + platform_set_drvdata(pdev, NULL); 159 + 160 + return 0; 161 + } 162 + 163 + MODULE_ALIAS("platform:cns3xxx-ehci"); 164 + 165 + static struct platform_driver cns3xxx_ehci_driver = { 166 + .probe = cns3xxx_ehci_probe, 167 + .remove = cns3xxx_ehci_remove, 168 + .driver = { 169 + .name = "cns3xxx-ehci", 170 + }, 171 + };
+5
drivers/usb/host/ehci-hcd.c
··· 1216 1216 #define PLATFORM_DRIVER ehci_octeon_driver 1217 1217 #endif 1218 1218 1219 + #ifdef CONFIG_USB_CNS3XXX_EHCI 1220 + #include "ehci-cns3xxx.c" 1221 + #define PLATFORM_DRIVER cns3xxx_ehci_driver 1222 + #endif 1223 + 1219 1224 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1220 1225 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1221 1226 !defined(XILINX_OF_PLATFORM_DRIVER)
+165
drivers/usb/host/ohci-cns3xxx.c
··· 1 + /* 2 + * Copyright 2008 Cavium Networks 3 + * 4 + * This file is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License, Version 2, as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <linux/platform_device.h> 10 + #include <linux/atomic.h> 11 + #include <mach/cns3xxx.h> 12 + #include <mach/pm.h> 13 + 14 + static int __devinit 15 + cns3xxx_ohci_start(struct usb_hcd *hcd) 16 + { 17 + struct ohci_hcd *ohci = hcd_to_ohci(hcd); 18 + int ret; 19 + 20 + /* 21 + * EHCI and OHCI share the same clock and power, 22 + * resetting twice would cause the 1st controller been reset. 23 + * Therefore only do power up at the first up device, and 24 + * power down at the last down device. 25 + * 26 + * Set USB AHB INCR length to 16 27 + */ 28 + if (atomic_inc_return(&usb_pwr_ref) == 1) { 29 + cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); 30 + cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 31 + cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); 32 + __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), 33 + MISC_CHIP_CONFIG_REG); 34 + } 35 + 36 + ret = ohci_init(ohci); 37 + if (ret < 0) 38 + return ret; 39 + 40 + ohci->num_ports = 1; 41 + 42 + ret = ohci_run(ohci); 43 + if (ret < 0) { 44 + err("can't start %s", hcd->self.bus_name); 45 + ohci_stop(hcd); 46 + return ret; 47 + } 48 + return 0; 49 + } 50 + 51 + static const struct hc_driver cns3xxx_ohci_hc_driver = { 52 + .description = hcd_name, 53 + .product_desc = "CNS3XXX OHCI Host controller", 54 + .hcd_priv_size = sizeof(struct ohci_hcd), 55 + .irq = ohci_irq, 56 + .flags = HCD_USB11 | HCD_MEMORY, 57 + .start = cns3xxx_ohci_start, 58 + .stop = ohci_stop, 59 + .shutdown = ohci_shutdown, 60 + .urb_enqueue = ohci_urb_enqueue, 61 + .urb_dequeue = ohci_urb_dequeue, 62 + .endpoint_disable = ohci_endpoint_disable, 63 + .get_frame_number = ohci_get_frame, 64 + .hub_status_data = ohci_hub_status_data, 65 + .hub_control = ohci_hub_control, 66 + #ifdef CONFIG_PM 67 + .bus_suspend = ohci_bus_suspend, 68 + .bus_resume = ohci_bus_resume, 69 + #endif 70 + .start_port_reset = ohci_start_port_reset, 71 + }; 72 + 73 + static int cns3xxx_ohci_probe(struct platform_device *pdev) 74 + { 75 + struct device *dev = &pdev->dev; 76 + struct usb_hcd *hcd; 77 + const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; 78 + struct resource *res; 79 + int irq; 80 + int retval; 81 + 82 + if (usb_disabled()) 83 + return -ENODEV; 84 + 85 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 86 + if (!res) { 87 + dev_err(dev, "Found HC with no IRQ.\n"); 88 + return -ENODEV; 89 + } 90 + irq = res->start; 91 + 92 + hcd = usb_create_hcd(driver, dev, dev_name(dev)); 93 + if (!hcd) 94 + return -ENOMEM; 95 + 96 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 97 + if (!res) { 98 + dev_err(dev, "Found HC with no register addr.\n"); 99 + retval = -ENODEV; 100 + goto err1; 101 + } 102 + hcd->rsrc_start = res->start; 103 + hcd->rsrc_len = res->end - res->start + 1; 104 + 105 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 106 + driver->description)) { 107 + dev_dbg(dev, "controller already in use\n"); 108 + retval = -EBUSY; 109 + goto err1; 110 + } 111 + 112 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 113 + if (!hcd->regs) { 114 + dev_dbg(dev, "error mapping memory\n"); 115 + retval = -EFAULT; 116 + goto err2; 117 + } 118 + 119 + ohci_hcd_init(hcd_to_ohci(hcd)); 120 + 121 + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 122 + if (retval == 0) 123 + return retval; 124 + 125 + iounmap(hcd->regs); 126 + err2: 127 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 128 + err1: 129 + usb_put_hcd(hcd); 130 + return retval; 131 + } 132 + 133 + static int cns3xxx_ohci_remove(struct platform_device *pdev) 134 + { 135 + struct usb_hcd *hcd = platform_get_drvdata(pdev); 136 + 137 + usb_remove_hcd(hcd); 138 + iounmap(hcd->regs); 139 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 140 + 141 + /* 142 + * EHCI and OHCI share the same clock and power, 143 + * resetting twice would cause the 1st controller been reset. 144 + * Therefore only do power up at the first up device, and 145 + * power down at the last down device. 146 + */ 147 + if (atomic_dec_return(&usb_pwr_ref) == 0) 148 + cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); 149 + 150 + usb_put_hcd(hcd); 151 + 152 + platform_set_drvdata(pdev, NULL); 153 + 154 + return 0; 155 + } 156 + 157 + MODULE_ALIAS("platform:cns3xxx-ohci"); 158 + 159 + static struct platform_driver ohci_hcd_cns3xxx_driver = { 160 + .probe = cns3xxx_ohci_probe, 161 + .remove = cns3xxx_ohci_remove, 162 + .driver = { 163 + .name = "cns3xxx-ohci", 164 + }, 165 + };
+5
drivers/usb/host/ohci-hcd.c
··· 1111 1111 #define PLATFORM_DRIVER ohci_octeon_driver 1112 1112 #endif 1113 1113 1114 + #ifdef CONFIG_USB_CNS3XXX_OHCI 1115 + #include "ohci-cns3xxx.c" 1116 + #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver 1117 + #endif 1118 + 1114 1119 #if !defined(PCI_DRIVER) && \ 1115 1120 !defined(PLATFORM_DRIVER) && \ 1116 1121 !defined(OMAP1_PLATFORM_DRIVER) && \