diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-01-15 23:12:10 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:44:37 -0500 |
commit | 6a6c957eba20814456bc4bffbd4ec42406f9eb02 (patch) | |
tree | 21e215b745658c6ff49b833da59c84327c9793d2 /drivers/usb/host/ohci-ps3.c | |
parent | de44743b033942731f6b898c2d389f7ee5ac890b (diff) |
USB: ps3 ohci bus glue
USB OHCI driver bus glue for the PS3 game console.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-ps3.c')
-rw-r--r-- | drivers/usb/host/ohci-ps3.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c new file mode 100644 index 000000000000..69d948b4a701 --- /dev/null +++ b/drivers/usb/host/ohci-ps3.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * PS3 OHCI Host Controller driver | ||
3 | * | ||
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2006 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <asm/ps3.h> | ||
22 | |||
23 | static int ps3_ohci_hc_reset(struct usb_hcd *hcd) | ||
24 | { | ||
25 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
26 | |||
27 | ohci->flags |= OHCI_QUIRK_BE_MMIO; | ||
28 | ohci_hcd_init(ohci); | ||
29 | return ohci_init(ohci); | ||
30 | } | ||
31 | |||
32 | static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) | ||
33 | { | ||
34 | int result; | ||
35 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
36 | |||
37 | /* Handle root hub init quirk in spider south bridge. */ | ||
38 | /* Also set PwrOn2PwrGood to 0x7f (254ms). */ | ||
39 | |||
40 | ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, | ||
41 | &ohci->regs->roothub.a); | ||
42 | ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); | ||
43 | |||
44 | result = ohci_run(ohci); | ||
45 | |||
46 | if (result < 0) { | ||
47 | err("can't start %s", hcd->self.bus_name); | ||
48 | ohci_stop(hcd); | ||
49 | } | ||
50 | |||
51 | return result; | ||
52 | } | ||
53 | |||
54 | static const struct hc_driver ps3_ohci_hc_driver = { | ||
55 | .description = hcd_name, | ||
56 | .product_desc = "PS3 OHCI Host Controller", | ||
57 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
58 | .irq = ohci_irq, | ||
59 | .flags = HCD_MEMORY | HCD_USB11, | ||
60 | .reset = ps3_ohci_hc_reset, | ||
61 | .start = ps3_ohci_hc_start, | ||
62 | .stop = ohci_stop, | ||
63 | .shutdown = ohci_shutdown, | ||
64 | .urb_enqueue = ohci_urb_enqueue, | ||
65 | .urb_dequeue = ohci_urb_dequeue, | ||
66 | .endpoint_disable = ohci_endpoint_disable, | ||
67 | .get_frame_number = ohci_get_frame, | ||
68 | .hub_status_data = ohci_hub_status_data, | ||
69 | .hub_control = ohci_hub_control, | ||
70 | .hub_irq_enable = ohci_rhsc_enable, | ||
71 | .start_port_reset = ohci_start_port_reset, | ||
72 | #if defined(CONFIG_PM) | ||
73 | .bus_suspend = ohci_bus_suspend, | ||
74 | .bus_resume = ohci_bus_resume, | ||
75 | #endif | ||
76 | }; | ||
77 | |||
78 | /* redefine dev_dbg to do a syntax check */ | ||
79 | |||
80 | #if !defined(DEBUG) | ||
81 | #undef dev_dbg | ||
82 | static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( | ||
83 | const struct device *_dev, const char *fmt, ...) {return 0;} | ||
84 | #endif | ||
85 | |||
86 | static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) | ||
87 | { | ||
88 | int result; | ||
89 | struct usb_hcd *hcd; | ||
90 | unsigned int virq; | ||
91 | static u64 dummy_mask = DMA_32BIT_MASK; | ||
92 | |||
93 | if (usb_disabled()) { | ||
94 | result = -ENODEV; | ||
95 | goto fail_start; | ||
96 | } | ||
97 | |||
98 | result = ps3_mmio_region_create(dev->m_region); | ||
99 | |||
100 | if (result) { | ||
101 | dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", | ||
102 | __func__, __LINE__); | ||
103 | result = -EPERM; | ||
104 | goto fail_mmio; | ||
105 | } | ||
106 | |||
107 | dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, | ||
108 | __LINE__, dev->m_region->lpar_addr); | ||
109 | |||
110 | result = ps3_alloc_io_irq(dev->interrupt_id, &virq); | ||
111 | |||
112 | if (result) { | ||
113 | dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", | ||
114 | __func__, __LINE__, virq); | ||
115 | result = -EPERM; | ||
116 | goto fail_irq; | ||
117 | } | ||
118 | |||
119 | dev->core.power.power_state = PMSG_ON; | ||
120 | dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ | ||
121 | |||
122 | hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); | ||
123 | |||
124 | if (!hcd) { | ||
125 | dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, | ||
126 | __LINE__); | ||
127 | result = -ENOMEM; | ||
128 | goto fail_create_hcd; | ||
129 | } | ||
130 | |||
131 | hcd->rsrc_start = dev->m_region->lpar_addr; | ||
132 | hcd->rsrc_len = dev->m_region->len; | ||
133 | hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); | ||
134 | |||
135 | if (!hcd->regs) { | ||
136 | dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, | ||
137 | __LINE__); | ||
138 | result = -EPERM; | ||
139 | goto fail_ioremap; | ||
140 | } | ||
141 | |||
142 | dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, | ||
143 | (unsigned long)hcd->rsrc_start); | ||
144 | dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, | ||
145 | (unsigned long)hcd->rsrc_len); | ||
146 | dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, | ||
147 | (unsigned long)hcd->regs); | ||
148 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, | ||
149 | (unsigned long)virq); | ||
150 | |||
151 | ps3_system_bus_set_driver_data(dev, hcd); | ||
152 | |||
153 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); | ||
154 | |||
155 | if (result) { | ||
156 | dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", | ||
157 | __func__, __LINE__, result); | ||
158 | goto fail_add_hcd; | ||
159 | } | ||
160 | |||
161 | return result; | ||
162 | |||
163 | fail_add_hcd: | ||
164 | iounmap(hcd->regs); | ||
165 | fail_ioremap: | ||
166 | usb_put_hcd(hcd); | ||
167 | fail_create_hcd: | ||
168 | ps3_free_io_irq(virq); | ||
169 | fail_irq: | ||
170 | ps3_free_mmio_region(dev->m_region); | ||
171 | fail_mmio: | ||
172 | fail_start: | ||
173 | return result; | ||
174 | } | ||
175 | |||
176 | static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev) | ||
177 | { | ||
178 | struct usb_hcd *hcd = | ||
179 | (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); | ||
180 | |||
181 | usb_put_hcd(hcd); | ||
182 | ps3_system_bus_set_driver_data(dev, NULL); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | MODULE_ALIAS("ps3-ohci"); | ||
188 | |||
189 | static struct ps3_system_bus_driver ps3_ohci_sb_driver = { | ||
190 | .match_id = PS3_MATCH_ID_OHCI, | ||
191 | .core = { | ||
192 | .name = "ps3-ohci-driver", | ||
193 | }, | ||
194 | .probe = ps3_ohci_sb_probe, | ||
195 | .remove = ps3_ohci_sb_remove, | ||
196 | }; | ||