xref: /netbsd-src/sys/arch/hpcarm/dev/wzero3_usb.c (revision 9edf49b047b567f256fdc9669452ea6dc2188733)
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