Home | History | Annotate | Line # | Download | only in dev
      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 (at) 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 *
    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
    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
    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
    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
    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
    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