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