1*9edf49b0Sdyoung /* $NetBSD: wzero3_usb.c,v 1.2 2011/07/19 15:37:39 dyoung Exp $ */
2b62fc9e2Snonaka
3b62fc9e2Snonaka /*
4b62fc9e2Snonaka * Copyright (c) 2009 NONAKA Kimihiro <nonaka@netbsd.org>
5b62fc9e2Snonaka * All rights reserved.
6b62fc9e2Snonaka *
7b62fc9e2Snonaka * 1. Redistributions of source code must retain the above copyright
8b62fc9e2Snonaka * notice, this list of conditions and the following disclaimer.
9b62fc9e2Snonaka * 2. Redistributions in binary form must reproduce the above copyright
10b62fc9e2Snonaka * notice, this list of conditions and the following disclaimer in the
11b62fc9e2Snonaka * documentation and/or other materials provided with the distribution.
12b62fc9e2Snonaka *
13b62fc9e2Snonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
14b62fc9e2Snonaka * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15b62fc9e2Snonaka * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16b62fc9e2Snonaka * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17b62fc9e2Snonaka * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18b62fc9e2Snonaka * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19b62fc9e2Snonaka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20b62fc9e2Snonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21b62fc9e2Snonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22b62fc9e2Snonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23b62fc9e2Snonaka * SUCH DAMAGE.
24b62fc9e2Snonaka */
25b62fc9e2Snonaka
26b62fc9e2Snonaka #include <sys/cdefs.h>
27*9edf49b0Sdyoung __KERNEL_RCSID(0, "$NetBSD: wzero3_usb.c,v 1.2 2011/07/19 15:37:39 dyoung Exp $");
28b62fc9e2Snonaka
29b62fc9e2Snonaka #include <sys/param.h>
30b62fc9e2Snonaka #include <sys/device.h>
31b62fc9e2Snonaka #include <sys/kernel.h>
32*9edf49b0Sdyoung #include <sys/bus.h>
33b62fc9e2Snonaka
34b62fc9e2Snonaka #include <arm/xscale/pxa2x0reg.h>
35b62fc9e2Snonaka #include <arm/xscale/pxa2x0var.h>
36b62fc9e2Snonaka #include <arm/xscale/pxa2x0_gpio.h>
37b62fc9e2Snonaka
38b62fc9e2Snonaka #include <machine/bootinfo.h>
39b62fc9e2Snonaka #include <machine/config_hook.h>
40b62fc9e2Snonaka #include <machine/platid.h>
41b62fc9e2Snonaka #include <machine/platid_mask.h>
42b62fc9e2Snonaka
43b62fc9e2Snonaka #include <hpcarm/dev/wzero3_reg.h>
44b62fc9e2Snonaka
45b62fc9e2Snonaka #if defined(WZERO3USB_DEBUG)
46b62fc9e2Snonaka #define DPRINTF(s) printf s
47b62fc9e2Snonaka #else
48b62fc9e2Snonaka #define DPRINTF(s)
49b62fc9e2Snonaka #endif
50b62fc9e2Snonaka
51b62fc9e2Snonaka struct wzero3usb_softc {
52b62fc9e2Snonaka device_t sc_dev;
53b62fc9e2Snonaka
54b62fc9e2Snonaka bus_space_tag_t sc_iot;
55b62fc9e2Snonaka bus_space_handle_t sc_ioh;
56b62fc9e2Snonaka
57b62fc9e2Snonaka int sc_client_pin;
58b62fc9e2Snonaka int sc_host_pin;
59b62fc9e2Snonaka int sc_host_power_pin;
60b62fc9e2Snonaka
61b62fc9e2Snonaka void *sc_client_ih;
62b62fc9e2Snonaka void *sc_host_ih;
63b62fc9e2Snonaka };
64b62fc9e2Snonaka
65b62fc9e2Snonaka static int wzero3usb_match(device_t, cfdata_t, void *);
66b62fc9e2Snonaka static void wzero3usb_attach(device_t, device_t, void *);
67b62fc9e2Snonaka
68b62fc9e2Snonaka CFATTACH_DECL_NEW(wzero3usb, sizeof(struct wzero3usb_softc),
69b62fc9e2Snonaka wzero3usb_match, wzero3usb_attach, NULL, NULL);
70b62fc9e2Snonaka
71b62fc9e2Snonaka static int wzero3usb_client_intr(void *);
72b62fc9e2Snonaka static int wzero3usb_host_intr(void *);
73b62fc9e2Snonaka static void wzero3usb_host_power(struct wzero3usb_softc *);
74b62fc9e2Snonaka
75b62fc9e2Snonaka static const struct wzero3usb_model {
76b62fc9e2Snonaka platid_mask_t *platid;
77b62fc9e2Snonaka int client_pin;
78b62fc9e2Snonaka int host_pin;
79b62fc9e2Snonaka int host_power_pin;
80b62fc9e2Snonaka } wzero3usb_table[] = {
81b62fc9e2Snonaka /* WS003SH */
82b62fc9e2Snonaka {
83b62fc9e2Snonaka &platid_mask_MACH_SHARP_WZERO3_WS003SH,
84b62fc9e2Snonaka GPIO_WS003SH_USB_CLIENT_DETECT,
85b62fc9e2Snonaka -1, /* None */
86b62fc9e2Snonaka -1, /* None */
87b62fc9e2Snonaka },
88b62fc9e2Snonaka /* WS004SH */
89b62fc9e2Snonaka {
90b62fc9e2Snonaka &platid_mask_MACH_SHARP_WZERO3_WS004SH,
91b62fc9e2Snonaka GPIO_WS003SH_USB_CLIENT_DETECT,
92b62fc9e2Snonaka -1, /* None */
93b62fc9e2Snonaka -1, /* None */
94b62fc9e2Snonaka },
95b62fc9e2Snonaka /* WS007SH */
96b62fc9e2Snonaka {
97b62fc9e2Snonaka &platid_mask_MACH_SHARP_WZERO3_WS007SH,
98b62fc9e2Snonaka GPIO_WS007SH_USB_CLIENT_DETECT,
99b62fc9e2Snonaka GPIO_WS007SH_USB_HOST_DETECT,
100b62fc9e2Snonaka GPIO_WS007SH_USB_HOST_POWER,
101b62fc9e2Snonaka },
102b62fc9e2Snonaka /* WS011SH */
103b62fc9e2Snonaka {
104b62fc9e2Snonaka &platid_mask_MACH_SHARP_WZERO3_WS011SH,
105b62fc9e2Snonaka GPIO_WS011SH_USB_CLIENT_DETECT,
106b62fc9e2Snonaka GPIO_WS011SH_USB_HOST_DETECT,
107b62fc9e2Snonaka GPIO_WS011SH_USB_HOST_POWER,
108b62fc9e2Snonaka },
109b62fc9e2Snonaka /* XXX: WS020SH */
110b62fc9e2Snonaka
111b62fc9e2Snonaka { NULL, -1, -1, -1, }
112b62fc9e2Snonaka };
113b62fc9e2Snonaka
114b62fc9e2Snonaka static const struct wzero3usb_model *
wzero3usb_lookup(void)115b62fc9e2Snonaka wzero3usb_lookup(void)
116b62fc9e2Snonaka {
117b62fc9e2Snonaka const struct wzero3usb_model *model;
118b62fc9e2Snonaka
119b62fc9e2Snonaka for (model = wzero3usb_table; model->platid != NULL; model++) {
120b62fc9e2Snonaka if (platid_match(&platid, model->platid)) {
121b62fc9e2Snonaka return model;
122b62fc9e2Snonaka }
123b62fc9e2Snonaka }
124b62fc9e2Snonaka return NULL;
125b62fc9e2Snonaka }
126b62fc9e2Snonaka
127b62fc9e2Snonaka static int
wzero3usb_match(device_t parent,cfdata_t cf,void * aux)128b62fc9e2Snonaka wzero3usb_match(device_t parent, cfdata_t cf, void *aux)
129b62fc9e2Snonaka {
130b62fc9e2Snonaka
131b62fc9e2Snonaka if (strcmp(cf->cf_name, "wzero3usb") != 0)
132b62fc9e2Snonaka return 0;
133b62fc9e2Snonaka if (wzero3usb_lookup() == NULL)
134b62fc9e2Snonaka return 0;
135b62fc9e2Snonaka return 1;
136b62fc9e2Snonaka }
137b62fc9e2Snonaka
138b62fc9e2Snonaka static void
wzero3usb_attach(device_t parent,device_t self,void * aux)139b62fc9e2Snonaka wzero3usb_attach(device_t parent, device_t self, void *aux)
140b62fc9e2Snonaka {
141b62fc9e2Snonaka struct wzero3usb_softc *sc = device_private(self);
142b62fc9e2Snonaka struct pxaip_attach_args *pxa = aux;
143b62fc9e2Snonaka const struct wzero3usb_model *model;
144b62fc9e2Snonaka
145b62fc9e2Snonaka sc->sc_dev = self;
146b62fc9e2Snonaka sc->sc_iot = pxa->pxa_iot;
147b62fc9e2Snonaka
148b62fc9e2Snonaka aprint_normal(": USB Mode detection\n");
149b62fc9e2Snonaka
150b62fc9e2Snonaka model = wzero3usb_lookup();
151b62fc9e2Snonaka if (model == NULL) {
152b62fc9e2Snonaka aprint_error_dev(self, "unknown model\n");
153b62fc9e2Snonaka return;
154b62fc9e2Snonaka }
155b62fc9e2Snonaka sc->sc_client_pin = model->client_pin;
156b62fc9e2Snonaka sc->sc_host_pin = model->host_pin;
157b62fc9e2Snonaka sc->sc_host_power_pin = model->host_power_pin;
158b62fc9e2Snonaka
159b62fc9e2Snonaka if (bus_space_map(sc->sc_iot, PXA2X0_USBDC_BASE, PXA270_USBDC_SIZE, 0,
160b62fc9e2Snonaka &sc->sc_ioh)) {
161b62fc9e2Snonaka aprint_error_dev(self, "couldn't map memory space\n");
162b62fc9e2Snonaka return;
163b62fc9e2Snonaka }
164b62fc9e2Snonaka
165b62fc9e2Snonaka if (sc->sc_client_pin >= 0) {
166b62fc9e2Snonaka sc->sc_client_ih = pxa2x0_gpio_intr_establish(sc->sc_client_pin,
167b62fc9e2Snonaka IST_EDGE_BOTH, IPL_BIO, wzero3usb_client_intr, sc);
168b62fc9e2Snonaka }
169b62fc9e2Snonaka if (sc->sc_host_pin >= 0) {
170b62fc9e2Snonaka sc->sc_host_ih = pxa2x0_gpio_intr_establish(sc->sc_host_pin,
171b62fc9e2Snonaka IST_EDGE_BOTH, IPL_BIO, wzero3usb_host_intr, sc);
172b62fc9e2Snonaka }
173b62fc9e2Snonaka
174b62fc9e2Snonaka /* configure port 2 for input */
175b62fc9e2Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR,
176b62fc9e2Snonaka USBDC_UP2OCR_HXS | USBDC_UP2OCR_HXOE |
177b62fc9e2Snonaka USBDC_UP2OCR_DPPDE | USBDC_UP2OCR_DMPDE);
178b62fc9e2Snonaka
179b62fc9e2Snonaka wzero3usb_host_power(sc);
180b62fc9e2Snonaka }
181b62fc9e2Snonaka
182b62fc9e2Snonaka static int
wzero3usb_host_intr(void * v)183b62fc9e2Snonaka wzero3usb_host_intr(void *v)
184b62fc9e2Snonaka {
185b62fc9e2Snonaka struct wzero3usb_softc *sc = (struct wzero3usb_softc *)v;
186b62fc9e2Snonaka
187b62fc9e2Snonaka DPRINTF(("%s: USB host cable changed: level = %s\n",
188b62fc9e2Snonaka device_xname(sc->sc_dev),
189b62fc9e2Snonaka pxa2x0_gpio_get_bit(sc->sc_host_pin) ? "H" : "L"));
190b62fc9e2Snonaka
191b62fc9e2Snonaka wzero3usb_host_power(sc);
192b62fc9e2Snonaka
193b62fc9e2Snonaka return 1;
194b62fc9e2Snonaka }
195b62fc9e2Snonaka
196b62fc9e2Snonaka static int
wzero3usb_client_intr(void * v)197b62fc9e2Snonaka wzero3usb_client_intr(void *v)
198b62fc9e2Snonaka {
199b62fc9e2Snonaka struct wzero3usb_softc *sc = (struct wzero3usb_softc *)v;
200b62fc9e2Snonaka
201b62fc9e2Snonaka DPRINTF(("%s: USB client cable changed: level = %s\n",
202b62fc9e2Snonaka device_xname(sc->sc_dev),
203b62fc9e2Snonaka pxa2x0_gpio_get_bit(sc->sc_client_pin) ? "H" : "L"));
204b62fc9e2Snonaka
205b62fc9e2Snonaka (void)sc; /*XXX*/
206b62fc9e2Snonaka
207b62fc9e2Snonaka return 1;
208b62fc9e2Snonaka }
209b62fc9e2Snonaka
210b62fc9e2Snonaka static void
wzero3usb_host_power(struct wzero3usb_softc * sc)211b62fc9e2Snonaka wzero3usb_host_power(struct wzero3usb_softc *sc)
212b62fc9e2Snonaka {
213b62fc9e2Snonaka int host_cable;
214b62fc9e2Snonaka
215b62fc9e2Snonaka if (sc->sc_host_pin >= 0 && sc->sc_host_power_pin >= 0) {
216b62fc9e2Snonaka host_cable = pxa2x0_gpio_get_bit(sc->sc_host_pin);
217b62fc9e2Snonaka
218b62fc9e2Snonaka if (!host_cable) {
219b62fc9e2Snonaka DPRINTF(("%s: enable USB host power\n",
220b62fc9e2Snonaka device_xname(sc->sc_dev)));
221b62fc9e2Snonaka pxa2x0_gpio_set_bit(sc->sc_host_power_pin);
222b62fc9e2Snonaka } else {
223b62fc9e2Snonaka DPRINTF(("%s: disable USB host power\n",
224b62fc9e2Snonaka device_xname(sc->sc_dev)));
225b62fc9e2Snonaka pxa2x0_gpio_clear_bit(sc->sc_host_power_pin);
226b62fc9e2Snonaka }
227b62fc9e2Snonaka }
228b62fc9e2Snonaka }
229