Home | History | Annotate | Line # | Download | only in dev
augpio.c revision 1.1
      1 /* $NetBSD: augpio.c,v 1.1 2006/02/12 20:49:34 gdamore Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Itronix Inc.
      5  * All rights reserved.
      6  *
      7  * Written by Garrett D'Amore for Itronix Inc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of Itronix Inc. may not be used to endorse
     18  *    or promote products derived from this software without specific
     19  *    prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     28  * ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: augpio.c,v 1.1 2006/02/12 20:49:34 gdamore Exp $");
     36 
     37 #include <sys/types.h>
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/errno.h>
     41 #include <sys/device.h>
     42 #include <sys/gpio.h>
     43 #include <sys/kernel.h>
     44 
     45 #include <dev/gpio/gpiovar.h>
     46 
     47 #include <machine/bus.h>
     48 #include <machine/cpu.h>
     49 
     50 #include <mips/alchemy/include/aubusvar.h>
     51 #include <mips/alchemy/include/aureg.h>
     52 #include <mips/alchemy/dev/augpioreg.h>
     53 #include <mips/alchemy/dev/augpiovar.h>
     54 
     55 struct augpio_softc {
     56 	struct device			sc_dev;
     57 	struct gpio_chipset_tag		sc_gc;
     58 	gpio_pin_t			sc_pins[AUGPIO_NPINS];
     59 	int				sc_npins;
     60 	int				sc_isgpio2;
     61 };
     62 
     63 static int augpio_pin_read(void *, int);
     64 static void augpio_pin_write(void *, int, int);
     65 static void augpio_pin_ctl(void *, int, int);
     66 static int augpio_match(struct device *, struct cfdata *, void *);
     67 static void augpio_attach(struct device *, struct device *, void *);
     68 
     69 CFATTACH_DECL(augpio, sizeof(struct augpio_softc),
     70     augpio_match, augpio_attach, NULL, NULL);
     71 
     72 #define	GETREG(x)	\
     73 	(*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x))
     74 #define	PUTREG(x, v)	\
     75 	((*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) = (v))
     76 
     77 static int augpio_found = 0;
     78 
     79 int
     80 augpio_match(struct device *parent, struct cfdata *match, void *aux)
     81 {
     82 	struct aubus_attach_args *aa = (struct aubus_attach_args *)aux;
     83 
     84 	if (strcmp(aa->aa_name, "augpio") != 0)
     85 		return 0;
     86 
     87 	if (augpio_found)
     88 		return 0;
     89 
     90 	return 1;
     91 }
     92 
     93 void
     94 augpio_attach(struct device *parent, struct device *self, void *aux)
     95 {
     96 	int	pin;
     97 
     98 	struct augpio_softc *sc = (struct augpio_softc *)self;
     99 	struct aubus_attach_args *aa = aux;
    100 	struct gpiobus_attach_args gba;
    101 
    102 	sc->sc_npins = 0;
    103 
    104 	printf(": Alchemy GPIO");
    105 	if (aa->aa_addrs[0] == SYS_BASE) {
    106 		for (pin = 0; pin < aa->aa_addrs[1]; pin++) {
    107 
    108 			sc->sc_pins[sc->sc_npins].pin_num = pin;
    109 			sc->sc_pins[sc->sc_npins].pin_caps =
    110 			    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
    111 			    GPIO_PIN_TRISTATE;
    112 			sc->sc_pins[sc->sc_npins].pin_flags =
    113 			    au_gpio_ctl(pin, 0);
    114 			sc->sc_pins[sc->sc_npins].pin_state =
    115 			    au_gpio_read(pin);
    116 			sc->sc_npins++;
    117 		}
    118 		sc->sc_isgpio2 = 0;
    119 		printf(", primary block");
    120 
    121 	} else if (aa->aa_addrs[0] == GPIO2_BASE) {
    122 
    123 		/* initialize GPIO2 block */
    124 		uint32_t	val;
    125 		val = AUGPIO_GPIO2_ENABLE_MR | AUGPIO_GPIO2_ENABLE_CE;
    126 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_ENABLE, val);
    127 		delay(10);
    128 		val &= ~AUGPIO_GPIO2_ENABLE_MR;
    129 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_ENABLE, val);
    130 
    131 		for (pin = 0; pin < aa->aa_addrs[1]; pin++) {
    132 			sc->sc_pins[sc->sc_npins].pin_num = pin;
    133 			sc->sc_pins[sc->sc_npins].pin_caps =
    134 			    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
    135 			sc->sc_pins[sc->sc_npins].pin_flags =
    136 			    au_gpio2_ctl(pin, 0);
    137 			sc->sc_pins[sc->sc_npins].pin_state =
    138 			    au_gpio2_read(pin);
    139 			sc->sc_npins++;
    140 		}
    141 
    142 		printf(", secondary block");
    143 		sc->sc_isgpio2 = 1;
    144 
    145 	} else {
    146 		printf(", unidentified block");
    147 	}
    148 	printf("\n");
    149 
    150 	sc->sc_gc.gp_cookie = sc;
    151 	sc->sc_gc.gp_pin_read = augpio_pin_read;
    152 	sc->sc_gc.gp_pin_write = augpio_pin_write;
    153 	sc->sc_gc.gp_pin_ctl = augpio_pin_ctl;
    154 
    155 	gba.gba_gc = &sc->sc_gc;
    156 	gba.gba_pins = sc->sc_pins;
    157 	gba.gba_npins = sc->sc_npins;
    158 
    159 	config_found_ia(&sc->sc_dev, "gpiobus", &gba, gpiobus_print);
    160 }
    161 
    162 int
    163 augpio_pin_read(void *arg, int pin)
    164 {
    165 	struct augpio_softc *sc = arg;
    166 
    167 	return (sc->sc_isgpio2 ? au_gpio2_read(pin) : au_gpio_read(pin));
    168 }
    169 
    170 void
    171 augpio_pin_write(void *arg, int pin, int value)
    172 {
    173 	struct augpio_softc *sc = arg;
    174 
    175 	if (sc->sc_isgpio2)
    176 		au_gpio2_write(pin, value);
    177 	else
    178 		au_gpio_write(pin, value);
    179 }
    180 
    181 void
    182 augpio_pin_ctl(void *arg, int pin, int flags)
    183 {
    184 	struct augpio_softc *sc = arg;
    185 
    186 	if (sc->sc_isgpio2)
    187 		(void) au_gpio2_ctl(pin, flags);
    188 	else
    189 		(void) au_gpio_ctl(pin, flags);
    190 }
    191 
    192 int
    193 au_gpio_read(int pin)
    194 {
    195 
    196 	pin = 1 << pin;
    197 	return ((GETREG(SYS_BASE + AUGPIO_SYS_PINSTATERD) & pin) ?
    198 	    GPIO_PIN_HIGH : GPIO_PIN_LOW);
    199 }
    200 
    201 void
    202 au_gpio_write(int pin, int value)
    203 {
    204 
    205 	pin = 1 << pin;
    206 	if (value) {
    207 		PUTREG(SYS_BASE + AUGPIO_SYS_OUTPUTSET, pin);
    208 	} else {
    209 		PUTREG(SYS_BASE + AUGPIO_SYS_OUTPUTCLR, pin);
    210 	}
    211 }
    212 
    213 int
    214 au_gpio_ctl(int pin, int flags)
    215 {
    216 	uint32_t		tri, out;
    217 	int			old;
    218 
    219 	old = 0;
    220 
    221 	pin = 1 << pin;
    222 	tri = GETREG(SYS_BASE + AUGPIO_SYS_TRIOUTRD);
    223 	out = GETREG(SYS_BASE + AUGPIO_SYS_OUTPUTRD);
    224 	old = 0;
    225 
    226 	if (tri & pin) {
    227 		old |= GPIO_PIN_INPUT;
    228 	} else {
    229 		old |= GPIO_PIN_OUTPUT;
    230 	}
    231 
    232 	if (flags & (GPIO_PIN_TRISTATE|GPIO_PIN_INPUT)) {
    233 		PUTREG(SYS_BASE + AUGPIO_SYS_TRIOUTCLR, pin);
    234 	} else if (flags & GPIO_PIN_OUTPUT) {
    235 		if (pin & out) {
    236 			PUTREG(SYS_BASE + AUGPIO_SYS_OUTPUTSET, pin);
    237 		} else {
    238 			PUTREG(SYS_BASE + AUGPIO_SYS_OUTPUTCLR, pin);
    239 		}
    240 	}
    241 
    242 	return old;
    243 }
    244 
    245 int
    246 au_gpio2_read(int pin)
    247 {
    248 
    249 	pin = 1 << pin;
    250 
    251 	return ((GETREG(GPIO2_BASE + AUGPIO_GPIO2_PINSTATE) & pin) ?
    252 	    GPIO_PIN_HIGH : GPIO_PIN_LOW);
    253 }
    254 
    255 void
    256 au_gpio2_write(int pin, int value)
    257 {
    258 
    259 	pin = 1 << pin;
    260 
    261 	if (value) {
    262 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_OUTPUT, (pin | (pin << 16)));
    263 	} else {
    264 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_OUTPUT, (pin << 16));
    265 	}
    266 }
    267 
    268 int
    269 au_gpio2_ctl(int pin, int flags)
    270 {
    271 	uint32_t		dir;
    272 	int			old;
    273 
    274 	pin = 1 << pin;
    275 
    276 	dir = GETREG(GPIO2_BASE + AUGPIO_GPIO2_DIR);
    277 	old = dir;
    278 
    279 	if (dir & pin) {
    280 		old |= GPIO_PIN_OUTPUT;
    281 	} else {
    282 		old |= GPIO_PIN_INPUT;
    283 	}
    284 
    285 	if (flags & GPIO_PIN_INPUT) {
    286 		dir |= pin;
    287 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_DIR, pin);
    288 	} else if (flags & GPIO_PIN_OUTPUT) {
    289 		dir &= ~pin;
    290 		PUTREG(GPIO2_BASE + AUGPIO_GPIO2_DIR, pin);
    291 	}
    292 
    293 	return old;
    294 }
    295