xref: /netbsd-src/sys/dev/tc/tcu.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* $NetBSD: tcu.c,v 1.1 2016/08/11 09:05:42 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2016, Felix Deichmann
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * flxd TC-USB - TURBOchannel USB host option
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: tcu.c,v 1.1 2016/08/11 09:05:42 christos Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/gpio.h>
40 
41 #include <sys/bus.h>
42 
43 #include <dev/tc/tcvar.h>
44 
45 #include <dev/gpio/gpiovar.h>
46 
47 #include "gpio.h"
48 #include "slhci_tcu.h"
49 
50 #define TCU_GPIO_NPINS	8
51 #define TCU_GPIO_OFFS	0x80
52 #define TCU_GPIO_SIZE	(3 * 4)
53 #define TCU_GPIO_DIR	0x0
54 #define TCU_GPIO_IN	0x4
55 #define TCU_GPIO_OUT	0x8
56 
57 struct tcu_softc {
58 #if NGPIO > 0
59 	kmutex_t		sc_gpio_mtx;
60 	struct gpio_chipset_tag	sc_gpio_gc;
61 	gpio_pin_t		sc_gpio_pins[TCU_GPIO_NPINS];
62 	bus_space_tag_t		sc_gpio_iot;
63 	bus_space_handle_t	sc_gpio_ioh;
64 #endif /* NGPIO > 0 */
65 };
66 
67 static int  tcu_match(device_t, cfdata_t, void *);
68 static void tcu_attach(device_t, device_t, void *);
69 
70 #if NSLHCI_TCU > 0
71 static int  tcu_print(void *, const char *);
72 #endif /* NSLHCI_TCU > 0 */
73 #if NGPIO > 0
74 static void tcu_gpio_attach(device_t, device_t, void *);
75 static int  tcu_gpio_read(void *, int);
76 static void tcu_gpio_write(void *, int, int);
77 static void tcu_gpio_ctl(void *, int, int);
78 #endif /* NGPIO > 0 */
79 
80 CFATTACH_DECL_NEW(tcu, sizeof(struct tcu_softc),
81     tcu_match, tcu_attach, NULL, NULL);
82 
83 static int
84 tcu_match(device_t parent, cfdata_t cf, void *aux)
85 {
86 	struct tc_attach_args *ta = aux;
87 
88 	if (strncmp("TC-USB  ", ta->ta_modname, TC_ROM_LLEN))
89 		return 0;
90 
91 	return 1;
92 }
93 
94 static void
95 tcu_attach(device_t parent, device_t self, void *aux)
96 {
97 
98 	printf(": TC-USB\n");
99 #if NSLHCI_TCU > 0
100 	/* Attach slhci. */
101 	(void)config_found_ia(self, "tcu", aux, tcu_print);
102 #endif /* NSLHCI_TCU > 0 */
103 #if NGPIO > 0
104 	/* Attach gpio(bus). */
105 	tcu_gpio_attach(parent, self, aux);
106 #endif /* NGPIO > 0 */
107 }
108 
109 #if NSLHCI_TCU > 0
110 static int
111 tcu_print(void *aux, const char *pnp)
112 {
113 
114 	/* This function is only used for "slhci at tcu". */
115 	if (pnp)
116 		aprint_normal("slhci at %s", pnp);
117 
118 	return UNCONF;
119 }
120 #endif /* NSLHCI_TCU > 0 */
121 
122 #if NGPIO > 0
123 static void
124 tcu_gpio_attach(device_t parent, device_t self, void *aux)
125 {
126 	struct tcu_softc *sc = device_private(self);
127 	struct tc_attach_args *ta = aux;
128 	struct gpiobus_attach_args gba;
129 	bus_space_tag_t iot = ta->ta_memt;
130 	uint32_t v;
131 	int error;
132 
133 	sc->sc_gpio_iot = iot;
134 
135 	error = bus_space_map(iot, ta->ta_addr + TCU_GPIO_OFFS, TCU_GPIO_SIZE,
136 	    0, &sc->sc_gpio_ioh);
137 	if (error) {
138 		aprint_error_dev(self, "bus_space_map() failed (%d)\n", error);
139 		return;
140 	}
141 
142 	mutex_init(&sc->sc_gpio_mtx, MUTEX_DEFAULT, IPL_NONE);
143 
144 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
145 
146 	for (int pin = 0; pin < TCU_GPIO_NPINS; pin++) {
147 		sc->sc_gpio_pins[pin].pin_num = pin;
148 		sc->sc_gpio_pins[pin].pin_caps = GPIO_PIN_INPUT |
149 		    GPIO_PIN_OUTPUT;
150 		sc->sc_gpio_pins[pin].pin_flags = (v & (UINT32_C(1) << pin)) ?
151 		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
152 		sc->sc_gpio_pins[pin].pin_state = tcu_gpio_read(sc, pin);
153 	}
154 
155 	sc->sc_gpio_gc.gp_cookie = sc;
156 	sc->sc_gpio_gc.gp_pin_read = tcu_gpio_read;
157 	sc->sc_gpio_gc.gp_pin_write = tcu_gpio_write;
158 	sc->sc_gpio_gc.gp_pin_ctl = tcu_gpio_ctl;
159 
160 	memset(&gba, 0, sizeof(gba));
161 
162 	gba.gba_gc = &sc->sc_gpio_gc;
163 	gba.gba_pins = sc->sc_gpio_pins;
164 	gba.gba_npins = TCU_GPIO_NPINS;
165 
166 	(void)config_found_ia(self, "gpiobus", &gba, gpiobus_print);
167 }
168 
169 static int
170 tcu_gpio_read(void *arg, int pin)
171 {
172 	struct tcu_softc *sc = arg;
173 	uint32_t v;
174 
175 	mutex_enter(&sc->sc_gpio_mtx);
176 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_IN);
177 	mutex_exit(&sc->sc_gpio_mtx);
178 
179 	return (v & (UINT32_C(1) << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
180 }
181 
182 static void
183 tcu_gpio_write(void *arg, int pin, int val)
184 {
185 	struct tcu_softc *sc = arg;
186 	uint32_t v;
187 
188 	mutex_enter(&sc->sc_gpio_mtx);
189 
190 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT);
191 
192 	if (val == GPIO_PIN_LOW)
193 		v &= ~(UINT32_C(1) << pin);
194 	else if (val == GPIO_PIN_HIGH)
195 		v |= (UINT32_C(1) << pin);
196 
197 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_OUT, v);
198 
199 	mutex_exit(&sc->sc_gpio_mtx);
200 }
201 
202 static void
203 tcu_gpio_ctl(void *arg, int pin, int flags)
204 {
205 	struct tcu_softc *sc = arg;
206 	uint32_t v;
207 
208 	mutex_enter(&sc->sc_gpio_mtx);
209 
210 	v = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR);
211 
212 	if (flags & GPIO_PIN_INPUT)
213 		v &= ~(UINT32_C(1) << pin);
214 	if (flags & GPIO_PIN_OUTPUT)
215 		v |= (UINT32_C(1) << pin);
216 
217 	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, TCU_GPIO_DIR, v);
218 
219 	mutex_exit(&sc->sc_gpio_mtx);
220 }
221 #endif /* NGPIO > 0 */
222