1 /* $NetBSD: wzero3_usb.c,v 1.2 2011/07/19 15:37:39 dyoung 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.2 2011/07/19 15:37:39 dyoung 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
51 struct 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
65 static int wzero3usb_match(device_t, cfdata_t, void *);
66 static void wzero3usb_attach(device_t, device_t, void *);
67
68 CFATTACH_DECL_NEW(wzero3usb, sizeof(struct wzero3usb_softc),
69 wzero3usb_match, wzero3usb_attach, NULL, NULL);
70
71 static int wzero3usb_client_intr(void *);
72 static int wzero3usb_host_intr(void *);
73 static void wzero3usb_host_power(struct wzero3usb_softc *);
74
75 static 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
114 static const struct wzero3usb_model *
wzero3usb_lookup(void)115 wzero3usb_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
127 static int
wzero3usb_match(device_t parent,cfdata_t cf,void * aux)128 wzero3usb_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
138 static void
wzero3usb_attach(device_t parent,device_t self,void * aux)139 wzero3usb_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
182 static int
wzero3usb_host_intr(void * v)183 wzero3usb_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
196 static int
wzero3usb_client_intr(void * v)197 wzero3usb_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
210 static void
wzero3usb_host_power(struct wzero3usb_softc * sc)211 wzero3usb_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