From 0916d26393562a776aa8b1c99ddcc60e4ba12fea Mon Sep 17 00:00:00 2001 From: juhosg Date: Fri, 16 Apr 2010 18:40:06 +0000 Subject: [PATCH] ppc40x: make isp116x-hcd driver usable on the OpenRB board Cc: backfire@openwrt.org git-svn-id: svn://svn.openwrt.org/openwrt/trunk@20931 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../120-usb-isp116x-hcd-add-of-binding.patch | 306 ++++++++++++++++++ ...b-isp116x-hcd-ppc405-register-access.patch | 111 +++++++ 2 files changed, 417 insertions(+) create mode 100644 target/linux/ppc40x/patches/120-usb-isp116x-hcd-add-of-binding.patch create mode 100644 target/linux/ppc40x/patches/121-usb-isp116x-hcd-ppc405-register-access.patch diff --git a/target/linux/ppc40x/patches/120-usb-isp116x-hcd-add-of-binding.patch b/target/linux/ppc40x/patches/120-usb-isp116x-hcd-add-of-binding.patch new file mode 100644 index 000000000..6de6e9b84 --- /dev/null +++ b/target/linux/ppc40x/patches/120-usb-isp116x-hcd-add-of-binding.patch @@ -0,0 +1,306 @@ +--- a/drivers/usb/host/isp116x-hcd.c ++++ b/drivers/usb/host/isp116x-hcd.c +@@ -1531,8 +1531,11 @@ static struct hc_driver isp116x_hc_drive + .bus_resume = isp116x_bus_resume, + }; + ++#define resource_len(r) (((r)->end - (r)->start) + 1) ++ + /*----------------------------------------------------------------*/ + ++#ifdef CONFIG_USB_ISP116X_HCD_PLATFORM + static int isp116x_remove(struct platform_device *pdev) + { + struct usb_hcd *hcd = platform_get_drvdata(pdev); +@@ -1556,8 +1559,6 @@ static int isp116x_remove(struct platfor + return 0; + } + +-#define resource_len(r) (((r)->end - (r)->start) + 1) +- + static int __devinit isp116x_probe(struct platform_device *pdev) + { + struct usb_hcd *hcd; +@@ -1708,22 +1709,253 @@ static struct platform_driver isp116x_dr + }, + }; + ++static inline int isp116x_platform_register(void) ++{ ++ return platform_driver_register(&isp116x_driver); ++} ++ ++static inline void isp116x_platform_unregister(void) ++{ ++ platform_driver_unregister(&isp116x_driver); ++} ++#else ++static inline int isp116x_platform_register(void) { return 0; }; ++static void isp116x_platform_unregister(void) {}; ++#endif /* CONFIG_USB_ISP116X_PLATFORM */ ++ ++/*-----------------------------------------------------------------*/ ++ ++#ifdef CONFIG_USB_ISP116X_HCD_OF ++ ++#include ++#include ++#include ++ ++#ifdef USE_PLATFORM_DELAY ++static void isp116x_of_delay(struct device *ddev, int delay) ++{ ++ ndelay(delay); ++} ++#else ++#define isp116x_of_delay NULL ++#endif ++ ++static int __devinit isp116x_of_probe(struct of_device *op, ++ const struct of_device_id *match) ++{ ++ struct device_node *dn = op->node; ++ struct usb_hcd *hcd; ++ struct isp116x *isp116x; ++ struct resource addr, data, ires; ++ struct isp116x_platform_data *board; ++ void __iomem *addr_reg; ++ void __iomem *data_reg; ++ int irq; ++ int ret = 0; ++ unsigned long irqflags; ++ ++ ret = of_address_to_resource(dn, 0, &data); ++ if (ret) ++ return ret; ++ ++ ret = of_address_to_resource(dn, 1, &addr); ++ if (ret) ++ return ret; ++ ++ ret = of_irq_to_resource(dn, 1, &ires); ++ if (ret) ++ return ret; ++ ++ irqflags = ires.flags & IRQF_TRIGGER_MASK; ++ ++ board = kzalloc(sizeof(struct isp116x_platform_data), GFP_KERNEL); ++ if (board == NULL) ++ return -ENOMEM; ++ ++ if (!request_mem_region(addr.start, resource_len(&addr), hcd_name)) { ++ ret = -EBUSY; ++ goto err_free_board; ++ } ++ ++ addr_reg = ioremap_nocache(addr.start, resource_len(&addr)); ++ if (addr_reg == NULL) { ++ ret = -ENOMEM; ++ goto err_release_addr; ++ } ++ ++ if (!request_mem_region(data.start, resource_len(&data), hcd_name)) { ++ ret = -EBUSY; ++ goto err_unmap_addr; ++ } ++ ++ data_reg = ioremap_nocache(data.start, resource_len(&data)); ++ if (data_reg == NULL) { ++ ret = -ENOMEM; ++ goto err_release_data; ++ } ++ ++ irq = irq_of_parse_and_map(op->node, 0); ++ if (irq == NO_IRQ) { ++ ret = -EINVAL; ++ goto err_unmap_data; ++ } ++ ++ /* allocate and initialize hcd */ ++ hcd = usb_create_hcd(&isp116x_hc_driver, &op->dev, dev_name(&op->dev)); ++ if (!hcd) { ++ ret = -ENOMEM; ++ goto err_irq_dispose; ++ } ++ ++ /* this rsrc_start is bogus */ ++ hcd->rsrc_start = addr.start; ++ isp116x = hcd_to_isp116x(hcd); ++ isp116x->data_reg = data_reg; ++ isp116x->addr_reg = addr_reg; ++ isp116x->board = board; ++ spin_lock_init(&isp116x->lock); ++ INIT_LIST_HEAD(&isp116x->async); ++ ++ board->delay = isp116x_of_delay; ++ if (of_get_property(dn, "sel15Kres", NULL)) ++ board->sel15Kres = 1; ++ if (of_get_property(dn, "oc_enable", NULL)) ++ board->oc_enable = 1; ++ if (of_get_property(dn, "remote_wakeup_enable", NULL)) ++ board->remote_wakeup_enable = 1; ++ ++ if (of_get_property(dn, "int_act_high", NULL)) ++ board->int_act_high = 1; ++ if (of_get_property(dn, "int_edge_triggered", NULL)) ++ board->int_edge_triggered = 1; ++ ++ ret = usb_add_hcd(hcd, irq, irqflags | IRQF_DISABLED); ++ if (ret) ++ goto err_put_hcd; ++ ++ ret = create_debug_file(isp116x); ++ if (ret) { ++ ERR("Couldn't create debugfs entry\n"); ++ goto err_remove_hcd; ++ } ++ ++ return 0; ++ ++ err_remove_hcd: ++ usb_remove_hcd(hcd); ++ err_put_hcd: ++ usb_put_hcd(hcd); ++ err_irq_dispose: ++ irq_dispose_mapping(irq); ++ err_unmap_data: ++ iounmap(data_reg); ++ err_release_data: ++ release_mem_region(data.start, resource_len(&data)); ++ err_unmap_addr: ++ iounmap(addr_reg); ++ err_release_addr: ++ release_mem_region(addr.start, resource_len(&addr)); ++ err_free_board: ++ kfree(board); ++ return ret; ++} ++ ++static __devexit int isp116x_of_remove(struct of_device *op) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(&op->dev); ++ struct isp116x *isp116x; ++ struct resource res; ++ ++ if (!hcd) ++ return 0; ++ ++ dev_set_drvdata(&op->dev, NULL); ++ ++ isp116x = hcd_to_isp116x(hcd); ++ remove_debug_file(isp116x); ++ usb_remove_hcd(hcd); ++ ++ irq_dispose_mapping(hcd->irq); ++ ++ iounmap(isp116x->data_reg); ++ (void) of_address_to_resource(op->node, 0, &res); ++ release_mem_region(res.start, resource_len(&res)); ++ ++ iounmap(isp116x->addr_reg); ++ (void) of_address_to_resource(op->node, 1, &res); ++ release_mem_region(res.start, resource_len(&res)); ++ ++ kfree(isp116x->board); ++ usb_put_hcd(hcd); ++ ++ return 0; ++} ++ ++static struct of_device_id isp116x_of_match[] = { ++ { .compatible = "isp116x-hcd", }, ++ {}, ++}; ++ ++static struct of_platform_driver isp116x_of_platform_driver = { ++ .owner = THIS_MODULE, ++ .name = "isp116x-hcd-of", ++ .match_table = isp116x_of_match, ++ .probe = isp116x_of_probe, ++ .remove = __devexit_p(isp116x_of_remove), ++ .driver = { ++ .name = "isp116x-hcd-of", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init isp116x_of_register(void) ++{ ++ return of_register_platform_driver(&isp116x_of_platform_driver); ++} ++ ++static void __exit isp116x_of_unregister(void) ++{ ++ of_unregister_platform_driver(&isp116x_of_platform_driver); ++} ++ ++MODULE_DEVICE_TABLE(of, isp116x_of_match); ++ ++#else ++static inline int isp116x_of_register(void) { return 0; }; ++static void isp116x_of_unregister(void) {}; ++#endif /* CONFIG_USB_ISP116X_HCD_OF */ ++ + /*-----------------------------------------------------------------*/ + + static int __init isp116x_init(void) + { ++ int ret; ++ + if (usb_disabled()) + return -ENODEV; + + INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); +- return platform_driver_register(&isp116x_driver); ++ ret = isp116x_platform_register(); ++ if (ret) ++ return ret; ++ ++ ret = isp116x_of_register(); ++ if (ret) ++ goto err_platform_unregister; ++ ++ return 0; ++ ++ err_platform_unregister: ++ isp116x_platform_unregister(); ++ return ret; + } + + module_init(isp116x_init); + + static void __exit isp116x_cleanup(void) + { +- platform_driver_unregister(&isp116x_driver); ++ isp116x_of_unregister(); ++ isp116x_platform_unregister(); + } + + module_exit(isp116x_cleanup); +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -144,6 +144,24 @@ config USB_ISP116X_HCD + To compile this driver as a module, choose M here: the + module will be called isp116x-hcd. + ++config USB_ISP116X_HCD_PLATFORM ++ bool "ISP116X support for controllers on platform bus" ++ depends on USB_ISP116X_HCD ++ default n if PPC_OF ++ default y ++ ---help--- ++ Enables support for the ISP116x USB controller present on the ++ platform bus. ++ ++config USB_ISP116X_HCD_OF ++ bool "ISP116X support for controllers on OF platform bus" ++ depends on USB_ISP116X_HCD && PPC_OF ++ default y if PPC_OF ++ default n ++ ---help--- ++ Enables support for the ISP116x USB controller present on the ++ OpenFirmware platform bus. ++ + config USB_ISP1760_HCD + tristate "ISP 1760 HCD support" + depends on USB && EXPERIMENTAL diff --git a/target/linux/ppc40x/patches/121-usb-isp116x-hcd-ppc405-register-access.patch b/target/linux/ppc40x/patches/121-usb-isp116x-hcd-ppc405-register-access.patch new file mode 100644 index 000000000..c81d18a44 --- /dev/null +++ b/target/linux/ppc40x/patches/121-usb-isp116x-hcd-ppc405-register-access.patch @@ -0,0 +1,111 @@ +--- a/drivers/usb/host/isp116x.h ++++ b/drivers/usb/host/isp116x.h +@@ -364,22 +364,64 @@ struct isp116x_ep { + #define IRQ_TEST() do{}while(0) + #endif + ++#ifdef CONFIG_405EP ++static inline void isp116x_writew(u16 val, void __iomem *addr) ++{ ++ writew(cpu_to_le16(val), addr); ++} ++ ++static inline u16 isp116x_readw(void __iomem *addr) ++{ ++ return le16_to_cpu(readw(addr)); ++} ++ ++static inline void isp116x_raw_writew(u16 val, void __iomem *addr) ++{ ++ writew(cpu_to_le16(val), addr); ++} ++ ++static inline u16 isp116x_raw_readw(void __iomem *addr) ++{ ++ return le16_to_cpu(readw(addr)); ++} ++#else ++static inline void isp116x_writew(u16 val, void __iomem *addr) ++{ ++ writew(val, addr); ++} ++ ++static inline u16 isp116x_readw(void __iomem *addr) ++{ ++ return readw(addr); ++} ++ ++static inline void isp116x_raw_writew(u16 val, void __iomem *addr) ++{ ++ __raw_writew(val, addr); ++} ++ ++static inline u16 isp116x_raw_readw(void __iomem *addr) ++{ ++ return __raw_readw(addr); ++} ++#endif ++ + static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) + { + IRQ_TEST(); +- writew(reg & 0xff, isp116x->addr_reg); ++ isp116x_writew(reg & 0xff, isp116x->addr_reg); + isp116x_delay(isp116x, 300); + } + + static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val) + { +- writew(val, isp116x->data_reg); ++ isp116x_writew(val, isp116x->data_reg); + isp116x_delay(isp116x, 150); + } + + static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val) + { +- __raw_writew(val, isp116x->data_reg); ++ isp116x_raw_writew(val, isp116x->data_reg); + isp116x_delay(isp116x, 150); + } + +@@ -387,7 +429,7 @@ static inline u16 isp116x_read_data16(st + { + u16 val; + +- val = readw(isp116x->data_reg); ++ val = isp116x_readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); + return val; + } +@@ -396,16 +438,16 @@ static inline u16 isp116x_raw_read_data1 + { + u16 val; + +- val = __raw_readw(isp116x->data_reg); ++ val = isp116x_raw_readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); + return val; + } + + static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val) + { +- writew(val & 0xffff, isp116x->data_reg); ++ isp116x_writew(val & 0xffff, isp116x->data_reg); + isp116x_delay(isp116x, 150); +- writew(val >> 16, isp116x->data_reg); ++ isp116x_writew(val >> 16, isp116x->data_reg); + isp116x_delay(isp116x, 150); + } + +@@ -413,9 +455,9 @@ static inline u32 isp116x_read_data32(st + { + u32 val; + +- val = (u32) readw(isp116x->data_reg); ++ val = (u32) isp116x_readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); +- val |= ((u32) readw(isp116x->data_reg)) << 16; ++ val |= ((u32) isp116x_readw(isp116x->data_reg)) << 16; + isp116x_delay(isp116x, 150); + return val; + }