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

ohci: Add support for OHCI controller on the of_platform bus

PPC embedded systems can have a ohci controller builtin. In the
new model, it will end up as a driver on the of_platform bus,
this patches takes care of them.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Sylvain Munaut and committed by
Greg Kroah-Hartman
495a678f 5e16fabe

+274 -1
+22 -1
drivers/usb/host/Kconfig
··· 112 112 Enables support for the USB controller on the MPC52xx or 113 113 STB03xxx processor chip. If unsure, say Y. 114 114 115 + config USB_OHCI_HCD_PPC_OF 116 + bool "OHCI support for PPC USB controller on OF platform bus" 117 + depends on USB_OHCI_HCD && PPC_OF 118 + default y 119 + ---help--- 120 + Enables support for the USB controller PowerPC present on the 121 + OpenFirmware platform bus. 122 + 123 + config USB_OHCI_HCD_PPC_OF_BE 124 + bool "Support big endian HC" 125 + depends on USB_OHCI_HCD_PPC_OF 126 + default y 127 + select USB_OHCI_BIG_ENDIAN_DESC 128 + select USB_OHCI_BIG_ENDIAN_MMIO 129 + 130 + config USB_OHCI_HCD_PPC_OF_LE 131 + bool "Support little endian HC" 132 + depends on USB_OHCI_HCD_PPC_OF 133 + default n 134 + select USB_OHCI_LITTLE_ENDIAN 135 + 115 136 config USB_OHCI_HCD_PCI 116 137 bool "OHCI support for PCI-bus USB controllers" 117 - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) 138 + depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) 118 139 default y 119 140 select USB_OHCI_LITTLE_ENDIAN 120 141 ---help---
+20
drivers/usb/host/ohci-hcd.c
··· 914 914 #endif 915 915 916 916 917 + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF 918 + #include "ohci-ppc-of.c" 919 + #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver 920 + #endif 921 + 917 922 #if !defined(PCI_DRIVER) && \ 918 923 !defined(PLATFORM_DRIVER) && \ 924 + !defined(OF_PLATFORM_DRIVER) && \ 919 925 !defined(SA1111_DRIVER) 920 926 #error "missing bus glue for ohci-hcd" 921 927 #endif ··· 942 936 retval = platform_driver_register(&PLATFORM_DRIVER); 943 937 if (retval < 0) 944 938 return retval; 939 + ls++; 940 + #endif 941 + 942 + #ifdef OF_PLATFORM_DRIVER 943 + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); 944 + if (retval < 0) 945 + goto error; 945 946 ls++; 946 947 #endif 947 948 ··· 974 961 if (ls--) 975 962 platform_driver_unregister(&PLATFORM_DRIVER); 976 963 #endif 964 + #ifdef OF_PLATFORM_DRIVER 965 + if (ls--) 966 + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); 967 + #endif 977 968 #ifdef SA1111_DRIVER 978 969 if (ls--) 979 970 sa1111_driver_unregister(&SA1111_DRIVER); ··· 993 976 #endif 994 977 #ifdef SA1111_DRIVER 995 978 sa1111_driver_unregister(&SA1111_DRIVER); 979 + #endif 980 + #ifdef OF_PLATFORM_DRIVER 981 + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); 996 982 #endif 997 983 #ifdef PLATFORM_DRIVER 998 984 platform_driver_unregister(&PLATFORM_DRIVER);
+232
drivers/usb/host/ohci-ppc-of.c
··· 1 + /* 2 + * OHCI HCD (Host Controller Driver) for USB. 3 + * 4 + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> 5 + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> 6 + * (C) Copyright 2002 Hewlett-Packard Company 7 + * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com> 8 + * 9 + * Bus glue for OHCI HC on the of_platform bus 10 + * 11 + * Modified for of_platform bus from ohci-sa1111.c 12 + * 13 + * This file is licenced under the GPL. 14 + */ 15 + 16 + #include <linux/signal.h> 17 + 18 + #include <asm/of_platform.h> 19 + #include <asm/prom.h> 20 + 21 + 22 + static int __devinit 23 + ohci_ppc_of_start(struct usb_hcd *hcd) 24 + { 25 + struct ohci_hcd *ohci = hcd_to_ohci(hcd); 26 + int ret; 27 + 28 + if ((ret = ohci_init(ohci)) < 0) 29 + return ret; 30 + 31 + if ((ret = ohci_run(ohci)) < 0) { 32 + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); 33 + ohci_stop(hcd); 34 + return ret; 35 + } 36 + 37 + return 0; 38 + } 39 + 40 + static const struct hc_driver ohci_ppc_of_hc_driver = { 41 + .description = hcd_name, 42 + .product_desc = "OF OHCI", 43 + .hcd_priv_size = sizeof(struct ohci_hcd), 44 + 45 + /* 46 + * generic hardware linkage 47 + */ 48 + .irq = ohci_irq, 49 + .flags = HCD_USB11 | HCD_MEMORY, 50 + 51 + /* 52 + * basic lifecycle operations 53 + */ 54 + .start = ohci_ppc_of_start, 55 + .stop = ohci_stop, 56 + .shutdown = ohci_shutdown, 57 + 58 + /* 59 + * managing i/o requests and associated device resources 60 + */ 61 + .urb_enqueue = ohci_urb_enqueue, 62 + .urb_dequeue = ohci_urb_dequeue, 63 + .endpoint_disable = ohci_endpoint_disable, 64 + 65 + /* 66 + * scheduling support 67 + */ 68 + .get_frame_number = ohci_get_frame, 69 + 70 + /* 71 + * root hub support 72 + */ 73 + .hub_status_data = ohci_hub_status_data, 74 + .hub_control = ohci_hub_control, 75 + .hub_irq_enable = ohci_rhsc_enable, 76 + #ifdef CONFIG_PM 77 + .bus_suspend = ohci_bus_suspend, 78 + .bus_resume = ohci_bus_resume, 79 + #endif 80 + .start_port_reset = ohci_start_port_reset, 81 + }; 82 + 83 + 84 + static int __devinit 85 + ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) 86 + { 87 + struct device_node *dn = op->node; 88 + struct usb_hcd *hcd; 89 + struct ohci_hcd *ohci; 90 + struct resource res; 91 + int irq; 92 + 93 + int rv; 94 + int is_bigendian; 95 + 96 + if (usb_disabled()) 97 + return -ENODEV; 98 + 99 + is_bigendian = 100 + device_is_compatible(dn, "ohci-bigendian") || 101 + device_is_compatible(dn, "ohci-be"); 102 + 103 + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); 104 + 105 + rv = of_address_to_resource(dn, 0, &res); 106 + if (rv) 107 + return rv; 108 + 109 + hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); 110 + if (!hcd) 111 + return -ENOMEM; 112 + 113 + hcd->rsrc_start = res.start; 114 + hcd->rsrc_len = res.end - res.start + 1; 115 + 116 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 117 + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); 118 + rv = -EBUSY; 119 + goto err_rmr; 120 + } 121 + 122 + irq = irq_of_parse_and_map(dn, 0); 123 + if (irq == NO_IRQ) { 124 + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); 125 + rv = -EBUSY; 126 + goto err_irq; 127 + } 128 + 129 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 130 + if (!hcd->regs) { 131 + printk(KERN_ERR __FILE__ ": ioremap failed\n"); 132 + rv = -ENOMEM; 133 + goto err_ioremap; 134 + } 135 + 136 + ohci = hcd_to_ohci(hcd); 137 + if (is_bigendian) 138 + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; 139 + 140 + ohci_hcd_init(ohci); 141 + 142 + rv = usb_add_hcd(hcd, irq, 0); 143 + if (rv == 0) 144 + return 0; 145 + 146 + iounmap(hcd->regs); 147 + err_ioremap: 148 + irq_dispose_mapping(irq); 149 + err_irq: 150 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 151 + err_rmr: 152 + usb_put_hcd(hcd); 153 + 154 + return rv; 155 + } 156 + 157 + static int ohci_hcd_ppc_of_remove(struct of_device *op) 158 + { 159 + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); 160 + dev_set_drvdata(&op->dev, NULL); 161 + 162 + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); 163 + 164 + usb_remove_hcd(hcd); 165 + 166 + iounmap(hcd->regs); 167 + irq_dispose_mapping(hcd->irq); 168 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 169 + 170 + usb_put_hcd(hcd); 171 + 172 + return 0; 173 + } 174 + 175 + static int ohci_hcd_ppc_of_shutdown(struct of_device *op) 176 + { 177 + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); 178 + 179 + if (hcd->driver->shutdown) 180 + hcd->driver->shutdown(hcd); 181 + 182 + return 0; 183 + } 184 + 185 + 186 + static struct of_device_id ohci_hcd_ppc_of_match[] = { 187 + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE 188 + { 189 + .name = "usb", 190 + .compatible = "ohci-bigendian", 191 + }, 192 + { 193 + .name = "usb", 194 + .compatible = "ohci-be", 195 + }, 196 + #endif 197 + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE 198 + { 199 + .name = "usb", 200 + .compatible = "ohci-littledian", 201 + }, 202 + { 203 + .name = "usb", 204 + .compatible = "ohci-le", 205 + }, 206 + #endif 207 + {}, 208 + }; 209 + MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); 210 + 211 + #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ 212 + !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) 213 + #error "No endianess selected for ppc-of-ohci" 214 + #endif 215 + 216 + 217 + static struct of_platform_driver ohci_hcd_ppc_of_driver = { 218 + .name = "ppc-of-ohci", 219 + .match_table = ohci_hcd_ppc_of_match, 220 + .probe = ohci_hcd_ppc_of_probe, 221 + .remove = ohci_hcd_ppc_of_remove, 222 + .shutdown = ohci_hcd_ppc_of_shutdown, 223 + #ifdef CONFIG_PM 224 + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ 225 + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ 226 + #endif 227 + .driver = { 228 + .name = "ppc-of-ohci", 229 + .owner = THIS_MODULE, 230 + }, 231 + }; 232 +