1 /* $Id: obio_ohci.c,v 1.4 2008/12/12 17:36:14 matt Exp $ */
4 /* $NetBSD: obio_ohci.c,v 1.3 2008/10/24 05:39:00 matt Exp $ */
5 /* $OpenBSD: pxa2x0_ohci.c,v 1.19 2005/04/08 02:32:54 dlg Exp $ */
8 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include <sys/cdefs.h>
26 __KERNEL_RCSID(0, "$NetBSD: obio_ohci.c,v 1.3 2008/10/24 05:39:00 matt Exp $");
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/device.h>
31 #include <sys/kernel.h>
33 #include <machine/intr.h>
34 #include <machine/bus.h>
36 #include <dev/usb/usb.h>
37 #include <dev/usb/usbdi.h>
38 #include <dev/usb/usbdivar.h>
39 #include <dev/usb/usb_mem.h>
41 #include <dev/usb/ohcireg.h>
42 #include <dev/usb/ohcivar.h>
44 #include <arm/omap/omap2_obiovar.h>
45 #include <arm/omap/omap2_obioreg.h>
48 struct obioohci_softc
{
56 static int obioohci_match(struct device
*, struct cfdata
*, void *);
57 static void obioohci_attach(struct device
*, struct device
*, void *);
58 static int obioohci_detach(struct device
*, int);
59 void * obioohci_fake_intr_establish(int (*)(void *), void *);
60 void obioohci_fake_intr(void);
62 CFATTACH_DECL_NEW(obioohci
, sizeof(struct obioohci_softc
),
63 obioohci_match
, obioohci_attach
, obioohci_detach
, ohci_activate
);
65 static void obioohci_clkinit(struct obio_attach_args
*);
66 static void obioohci_power(int, void *);
67 static void obioohci_enable(struct obioohci_softc
*);
68 static void obioohci_disable(struct obioohci_softc
*);
70 #define HREAD4(sc,r) bus_space_read_4((sc)->sc.iot, (sc)->sc.ioh, (r))
71 #define HWRITE4(sc,r,v) bus_space_write_4((sc)->sc.iot, (sc)->sc.ioh, (r), (v))
74 obioohci_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
77 struct obio_attach_args
*obio
= aux
;
79 if ((obio
->obio_addr
== -1)
80 || (obio
->obio_size
== 0)
81 || (obio
->obio_intr
== -1))
82 panic("obioohci must have addr, size and intr"
83 " specified in config.");
85 obioohci_clkinit(obio
);
91 obioohci_attach(struct device
*parent
, struct device
*self
, void *aux
)
93 struct obioohci_softc
*sc
= (struct obioohci_softc
*)self
;
94 struct obio_attach_args
*obio
= aux
;
99 sc
->sc
.sc_bus
.dmatag
= 0;
102 if (bus_space_map(obio
->obio_iot
, obio
->obio_addr
, obio
->obio_size
, 0,
104 aprint_error(": couldn't map memory space\n");
107 sc
->sc
.iot
= obio
->obio_iot
;
108 sc
->sc_addr
= obio
->obio_addr
;
109 sc
->sc
.sc_size
= obio
->obio_size
;
110 sc
->sc
.sc_bus
.dmatag
= obio
->obio_dmac
;
112 /* XXX copied from ohci_pci.c. needed? */
113 bus_space_barrier(sc
->sc
.iot
, sc
->sc
.ioh
, 0, sc
->sc
.sc_size
,
114 BUS_SPACE_BARRIER_READ
|BUS_SPACE_BARRIER_WRITE
);
116 /* start the usb clock */
118 pxa2x0_clkman_config(CKEN_USBHC
, 1);
122 /* Disable interrupts, so we don't get any spurious ones. */
123 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, OHCI_INTERRUPT_DISABLE
,
127 sc
->sc_ih
= obio_intr_establish(obio
->obio_intr
, IPL_USB
,
128 sc
->sc
.sc_bus
.bdev
.dv_xname
, ohci_intr
, &sc
->sc
);
129 if (sc
->sc_ih
== NULL
) {
130 aprint_error(": unable to establish interrupt\n");
134 sc
->sc_ih
= obioohci_fake_intr_establish(ohci_intr
, &sc
->sc
);
137 strlcpy(sc
->sc
.sc_vendor
, "OMAP2", sizeof(sc
->sc
.sc_vendor
));
138 r
= ohci_init(&sc
->sc
);
139 if (r
!= USBD_NORMAL_COMPLETION
) {
140 aprint_error("%s: init failed, error=%d\n",
141 sc
->sc
.sc_bus
.bdev
.dv_xname
, r
);
145 sc
->sc
.sc_powerhook
= powerhook_establish(sc
->sc
.sc_bus
.bdev
.dv_xname
,
147 if (sc
->sc
.sc_powerhook
== NULL
) {
148 aprint_error("%s: cannot establish powerhook\n",
149 sc
->sc
.sc_bus
.bdev
.dv_xname
);
152 sc
->sc
.sc_child
= config_found((void *)sc
, &sc
->sc
.sc_bus
, usbctlprint
);
158 obio_gpio_intr_disestablish(sc
->sc_ih
);
164 obioohci_disable(sc
);
166 pxa2x0_clkman_config(CKEN_USBHC
, 0);
168 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
173 obioohci_detach(struct device
*self
, int flags
)
175 struct obioohci_softc
*sc
= (struct obioohci_softc
*)self
;
178 error
= ohci_detach(&sc
->sc
, flags
);
182 if (sc
->sc
.sc_powerhook
) {
183 powerhook_disestablish(sc
->sc
.sc_powerhook
);
184 sc
->sc
.sc_powerhook
= NULL
;
189 obio_gpio_intr_disestablish(sc
->sc_ih
);
194 obioohci_disable(sc
);
199 pxa2x0_clkman_config(CKEN_USBHC
, 0);
203 if (sc
->sc
.sc_size
) {
204 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
212 obioohci_power(int why
, void *arg
)
214 struct obioohci_softc
*sc
= (struct obioohci_softc
*)arg
;
218 sc
->sc
.sc_bus
.use_polling
++;
223 ohci_power(why
, &sc
->sc
);
226 pxa2x0_clkman_config(CKEN_USBHC
, 0);
232 pxa2x0_clkman_config(CKEN_USBHC
, 1);
236 ohci_power(why
, &sc
->sc
);
240 sc
->sc
.sc_bus
.use_polling
--;
245 obioohci_enable(struct obioohci_softc
*sc
)
247 printf("%s: TBD\n", __func__
);
251 obioohci_disable(struct obioohci_softc
*sc
)
256 /* Full host reset */
257 hr
= HREAD4(sc
, USBHC_HR
);
258 HWRITE4(sc
, USBHC_HR
, (hr
& USBHC_HR_MASK
) | USBHC_HR_FHR
);
260 DELAY(USBHC_RST_WAIT
);
262 hr
= HREAD4(sc
, USBHC_HR
);
263 HWRITE4(sc
, USBHC_HR
, (hr
& USBHC_HR_MASK
) & ~(USBHC_HR_FHR
));
268 obioohci_clkinit(struct obio_attach_args
*obio
)
271 bus_space_handle_t ioh
;
275 err
= bus_space_map(obio
->obio_iot
, OMAP2430_CM_BASE
,
276 OMAP2430_CM_SIZE
, 0, &ioh
);
278 panic("%s: cannot map OMAP2430_CM_BASE at %#x, error %d\n",
279 __func__
, OMAP2430_CM_BASE
, err
);
281 r
= bus_space_read_4(obio
->obio_iot
, ioh
, OMAP2430_CM_FCLKEN2_CORE
);
282 r
|= OMAP2430_CM_FCLKEN2_CORE_EN_USB
;
283 bus_space_write_4(obio
->obio_iot
, ioh
, OMAP2430_CM_FCLKEN2_CORE
, r
);
285 r
= bus_space_read_4(obio
->obio_iot
, ioh
, OMAP2430_CM_ICLKEN2_CORE
);
286 r
|= OMAP2430_CM_ICLKEN2_CORE_EN_USB
;
287 r
&= ~OMAP2430_CM_ICLKEN2_CORE_EN_USBHS
; /* force FS for ohci */
288 bus_space_write_4(obio
->obio_iot
, ioh
, OMAP2430_CM_ICLKEN2_CORE
, r
);
290 bus_space_unmap(obio
->obio_iot
, ioh
, OMAP2430_CM_SIZE
);
294 int (*obioohci_fake_intr_func
)(void *);
295 void *obioohci_fake_intr_arg
;
298 obioohci_fake_intr_establish(int (*func
)(void *), void *arg
)
300 obioohci_fake_intr_func
= func
;
301 obioohci_fake_intr_arg
= arg
;
306 obioohci_fake_intr(void)
308 (void)(*obioohci_fake_intr_func
)(obioohci_fake_intr_arg
);