0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/ssb/ssb.h>
0021 #include <linux/delay.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/module.h>
0024 #include <linux/slab.h>
0025 #include <linux/usb/ehci_pdriver.h>
0026 #include <linux/usb/ohci_pdriver.h>
0027
0028 MODULE_AUTHOR("Hauke Mehrtens");
0029 MODULE_DESCRIPTION("Common USB driver for SSB Bus");
0030 MODULE_LICENSE("GPL");
0031
0032 #define SSB_HCD_TMSLOW_HOSTMODE (1 << 29)
0033
0034 struct ssb_hcd_device {
0035 struct platform_device *ehci_dev;
0036 struct platform_device *ohci_dev;
0037
0038 u32 enable_flags;
0039 };
0040
0041 static void ssb_hcd_5354wa(struct ssb_device *dev)
0042 {
0043 #ifdef CONFIG_SSB_DRIVER_MIPS
0044
0045 if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
0046
0047 ssb_write32(dev, 0x894, 0x00fe00fe);
0048
0049
0050 ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1);
0051 }
0052 #endif
0053 }
0054
0055 static void ssb_hcd_usb20wa(struct ssb_device *dev)
0056 {
0057 if (dev->id.coreid == SSB_DEV_USB20_HOST) {
0058
0059
0060
0061
0062
0063
0064
0065 ssb_write32(dev, 0x200, 0x7ff);
0066
0067
0068 ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8);
0069 ssb_read32(dev, 0x400);
0070
0071
0072 ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100);
0073 ssb_read32(dev, 0x304);
0074
0075 udelay(1);
0076
0077 ssb_hcd_5354wa(dev);
0078 }
0079 }
0080
0081
0082 static u32 ssb_hcd_init_chip(struct ssb_device *dev)
0083 {
0084 u32 flags = 0;
0085
0086 if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
0087
0088 flags |= SSB_HCD_TMSLOW_HOSTMODE;
0089
0090 ssb_device_enable(dev, flags);
0091
0092 ssb_hcd_usb20wa(dev);
0093
0094 return flags;
0095 }
0096
0097 static const struct usb_ehci_pdata ehci_pdata = {
0098 };
0099
0100 static const struct usb_ohci_pdata ohci_pdata = {
0101 };
0102
0103 static struct platform_device *ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len)
0104 {
0105 struct platform_device *hci_dev;
0106 struct resource hci_res[2];
0107 int ret;
0108
0109 memset(hci_res, 0, sizeof(hci_res));
0110
0111 hci_res[0].start = addr;
0112 hci_res[0].end = hci_res[0].start + len - 1;
0113 hci_res[0].flags = IORESOURCE_MEM;
0114
0115 hci_res[1].start = dev->irq;
0116 hci_res[1].flags = IORESOURCE_IRQ;
0117
0118 hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
0119 "ehci-platform" , 0);
0120 if (!hci_dev)
0121 return ERR_PTR(-ENOMEM);
0122
0123 hci_dev->dev.parent = dev->dev;
0124 hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
0125
0126 ret = platform_device_add_resources(hci_dev, hci_res,
0127 ARRAY_SIZE(hci_res));
0128 if (ret)
0129 goto err_alloc;
0130 if (ohci)
0131 ret = platform_device_add_data(hci_dev, &ohci_pdata,
0132 sizeof(ohci_pdata));
0133 else
0134 ret = platform_device_add_data(hci_dev, &ehci_pdata,
0135 sizeof(ehci_pdata));
0136 if (ret)
0137 goto err_alloc;
0138 ret = platform_device_add(hci_dev);
0139 if (ret)
0140 goto err_alloc;
0141
0142 return hci_dev;
0143
0144 err_alloc:
0145 platform_device_put(hci_dev);
0146 return ERR_PTR(ret);
0147 }
0148
0149 static int ssb_hcd_probe(struct ssb_device *dev,
0150 const struct ssb_device_id *id)
0151 {
0152 int err, tmp;
0153 int start, len;
0154 u16 chipid_top;
0155 u16 coreid = dev->id.coreid;
0156 struct ssb_hcd_device *usb_dev;
0157
0158
0159 chipid_top = (dev->bus->chip_id & 0xFF00);
0160 if (chipid_top != 0x4700 && chipid_top != 0x5300)
0161 return -ENODEV;
0162
0163
0164
0165 if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
0166 return -EOPNOTSUPP;
0167
0168 usb_dev = devm_kzalloc(dev->dev, sizeof(struct ssb_hcd_device),
0169 GFP_KERNEL);
0170 if (!usb_dev)
0171 return -ENOMEM;
0172
0173
0174
0175
0176
0177 usb_dev->enable_flags = ssb_hcd_init_chip(dev);
0178
0179 tmp = ssb_read32(dev, SSB_ADMATCH0);
0180
0181 start = ssb_admatch_base(tmp);
0182 len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
0183 usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
0184 if (IS_ERR(usb_dev->ohci_dev))
0185 return PTR_ERR(usb_dev->ohci_dev);
0186
0187 if (coreid == SSB_DEV_USB20_HOST) {
0188 start = ssb_admatch_base(tmp) + 0x800;
0189 usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len);
0190 if (IS_ERR(usb_dev->ehci_dev)) {
0191 err = PTR_ERR(usb_dev->ehci_dev);
0192 goto err_unregister_ohci_dev;
0193 }
0194 }
0195
0196 ssb_set_drvdata(dev, usb_dev);
0197 return 0;
0198
0199 err_unregister_ohci_dev:
0200 platform_device_unregister(usb_dev->ohci_dev);
0201 return err;
0202 }
0203
0204 static void ssb_hcd_remove(struct ssb_device *dev)
0205 {
0206 struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
0207 struct platform_device *ohci_dev = usb_dev->ohci_dev;
0208 struct platform_device *ehci_dev = usb_dev->ehci_dev;
0209
0210 if (ohci_dev)
0211 platform_device_unregister(ohci_dev);
0212 if (ehci_dev)
0213 platform_device_unregister(ehci_dev);
0214
0215 ssb_device_disable(dev, 0);
0216 }
0217
0218 static void ssb_hcd_shutdown(struct ssb_device *dev)
0219 {
0220 ssb_device_disable(dev, 0);
0221 }
0222
0223 #ifdef CONFIG_PM
0224
0225 static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
0226 {
0227 ssb_device_disable(dev, 0);
0228
0229 return 0;
0230 }
0231
0232 static int ssb_hcd_resume(struct ssb_device *dev)
0233 {
0234 struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
0235
0236 ssb_device_enable(dev, usb_dev->enable_flags);
0237
0238 return 0;
0239 }
0240
0241 #else
0242 #define ssb_hcd_suspend NULL
0243 #define ssb_hcd_resume NULL
0244 #endif
0245
0246 static const struct ssb_device_id ssb_hcd_table[] = {
0247 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
0248 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
0249 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
0250 {},
0251 };
0252 MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
0253
0254 static struct ssb_driver ssb_hcd_driver = {
0255 .name = KBUILD_MODNAME,
0256 .id_table = ssb_hcd_table,
0257 .probe = ssb_hcd_probe,
0258 .remove = ssb_hcd_remove,
0259 .shutdown = ssb_hcd_shutdown,
0260 .suspend = ssb_hcd_suspend,
0261 .resume = ssb_hcd_resume,
0262 };
0263
0264 static int __init ssb_hcd_init(void)
0265 {
0266 return ssb_driver_register(&ssb_hcd_driver);
0267 }
0268 module_init(ssb_hcd_init);
0269
0270 static void __exit ssb_hcd_exit(void)
0271 {
0272 ssb_driver_unregister(&ssb_hcd_driver);
0273 }
0274 module_exit(ssb_hcd_exit);