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