xref: /netbsd-src/sys/arch/arm/imx/imxgpio.c (revision 404ee5b9334f618040b6cdef96a0ff35a6fc4636)
1 /*	$NetBSD: imxgpio.c,v 1.6 2019/07/24 12:33:18 hkenken Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.6 2019/07/24 12:33:18 hkenken Exp $");
33 
34 #define	_INTR_PRIVATE
35 
36 #include "locators.h"
37 #include "gpio.h"
38 
39 #include <sys/param.h>
40 #include <sys/evcnt.h>
41 #include <sys/atomic.h>
42 #include <sys/bus.h>
43 
44 #include <machine/intr.h>
45 
46 #include <arm/cpu.h>
47 #include <arm/armreg.h>
48 #include <arm/cpufunc.h>
49 
50 #include <arm/imx/imxgpioreg.h>
51 #include <arm/imx/imxgpiovar.h>
52 
53 #if NGPIO > 0
54 /* GPIO access from userland */
55 #include <sys/gpio.h>
56 #include <dev/gpio/gpiovar.h>
57 #endif
58 
59 #define	MAX_NGROUP	8
60 
61 static void imxgpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
62 static void imxgpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
63 static int imxgpio_pic_find_pending_irqs(struct pic_softc *);
64 static void imxgpio_pic_establish_irq(struct pic_softc *, struct intrsource *);
65 
66 const struct pic_ops imxgpio_pic_ops = {
67 	.pic_unblock_irqs = imxgpio_pic_unblock_irqs,
68 	.pic_block_irqs = imxgpio_pic_block_irqs,
69 	.pic_find_pending_irqs = imxgpio_pic_find_pending_irqs,
70 	.pic_establish_irq = imxgpio_pic_establish_irq,
71 	.pic_source_name = NULL
72 };
73 
74 static struct imxgpio_softc *imxgpio_handles[MAX_NGROUP];
75 
76 CFATTACH_DECL_NEW(imxgpio, sizeof(struct imxgpio_softc),
77     imxgpio_match, imxgpio_attach, NULL, NULL);
78 
79 #define	PIC_TO_SOFTC(pic)						      \
80 	((struct imxgpio_softc *)((char *)(pic) -			      \
81 	    offsetof(struct imxgpio_softc, gpio_pic)))
82 
83 #define	GPIO_READ(gpio, reg)						      \
84 	bus_space_read_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg))
85 #define	GPIO_WRITE(gpio, reg, val)					      \
86 	bus_space_write_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg), (val))
87 
88 void
89 imxgpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
90 {
91 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
92 	KASSERT(irq_base == 0);
93 
94 	gpio->gpio_enable_mask |= irq_mask;
95 
96 	GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
97 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
98 }
99 
100 void
101 imxgpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
102 {
103 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
104 	KASSERT(irq_base == 0);
105 
106 	gpio->gpio_enable_mask &= ~irq_mask;
107 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
108 }
109 
110 int
111 imxgpio_pic_find_pending_irqs(struct pic_softc *pic)
112 {
113 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
114 	uint32_t v;
115 	uint32_t pending;
116 
117 	v = GPIO_READ(gpio, GPIO_ISR);
118 	pending = (v & gpio->gpio_enable_mask);
119 	if (pending == 0)
120 		return 0;
121 
122 	/*
123 	 * Disable the pending interrupts.
124 	 */
125 	gpio->gpio_enable_mask &= ~pending;
126 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
127 
128 	/*
129 	 * If any of the sources are edge triggered, ack them now so
130 	 * we won't lose them.
131 	 */
132 	if (v & gpio->gpio_edge_mask)
133 		GPIO_WRITE(gpio, GPIO_ISR, v & gpio->gpio_edge_mask);
134 
135 	/*
136 	 * Now find all the pending bits and mark them as pending.
137 	 */
138 	do {
139 		int irq;
140 		KASSERT(pending != 0);
141 		irq = 31 - __builtin_clz(pending);
142 		pending &= ~__BIT(irq);
143 
144 		const struct intrsource *is = pic->pic_sources[irq];
145 		if (is->is_type == IST_EDGE_BOTH) {
146 			/*
147 			 * for both edge
148 			 */
149 			uint32_t icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2);
150 			v = GPIO_READ(gpio, icr_reg);
151 			uint32_t icr_shift = (is->is_irq & 0x0f) << 1;
152 			uint32_t mask = (3 << icr_shift);
153 			int gtype = __SHIFTOUT(v, mask);
154 			if (gtype == GPIO_ICR_EDGE_RISING)
155 				gtype = GPIO_ICR_EDGE_FALLING;
156 			else if (gtype == GPIO_ICR_EDGE_FALLING)
157 				gtype = GPIO_ICR_EDGE_RISING;
158 			v &= ~mask;
159 			v |= __SHIFTIN(gtype, mask);
160 			GPIO_WRITE(gpio, icr_reg, v);
161 		}
162 		pic_mark_pending(&gpio->gpio_pic, irq);
163 	} while (pending != 0);
164 
165 	return 1;
166 }
167 
168 #define	GPIO_TYPEMAP \
169 	((GPIO_ICR_LEVEL_LOW << (2*IST_LEVEL_LOW)) | \
170 	 (GPIO_ICR_LEVEL_HIGH << (2*IST_LEVEL_HIGH)) | \
171 	 (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_RISING)) | \
172 	 (GPIO_ICR_EDGE_FALLING << (2*IST_EDGE_FALLING)) | \
173 	 (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_BOTH)))
174 
175 void
176 imxgpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
177 {
178 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
179 	KASSERT(is->is_irq < 32);
180 	uint32_t irq_mask = __BIT(is->is_irq);
181 	uint32_t v;
182 	unsigned int icr_shift, icr_reg;
183 	unsigned int gtype;
184 
185 	/*
186 	 * Make sure the irq isn't enabled and not asserting.
187 	 */
188 	gpio->gpio_enable_mask &= ~irq_mask;
189 	GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
190 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
191 	/*
192 	 * Convert the type to a gpio type and figure out which bits in what
193 	 * register we have to tweak.
194 	 */
195 	gtype = (GPIO_TYPEMAP >> (2 * is->is_type)) & 3;
196 	icr_shift = (is->is_irq & 0x0f) << 1;
197 	icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2);
198 
199 	/*
200 	 * Set the interrupt type.
201 	 */
202 	v = GPIO_READ(gpio, icr_reg);
203 	v &= ~(3 << icr_shift);
204 	v |= gtype << icr_shift;
205 	GPIO_WRITE(gpio, icr_reg, v);
206 
207 	/*
208 	 * Mark it as input.
209 	 */
210 	v = GPIO_READ(gpio, GPIO_DIR);
211 	v &= ~irq_mask;
212 	GPIO_WRITE(gpio, GPIO_DIR, v);
213 
214 	/*
215 	 * Now record the type of interrupt.
216 	 */
217 	if (gtype == GPIO_ICR_EDGE_RISING || gtype == GPIO_ICR_EDGE_FALLING) {
218 		gpio->gpio_edge_mask |= irq_mask;
219 		gpio->gpio_level_mask &= ~irq_mask;
220 	} else {
221 		gpio->gpio_edge_mask &= ~irq_mask;
222 		gpio->gpio_level_mask |= irq_mask;
223 	}
224 }
225 
226 #if NGPIO > 0
227 
228 int
229 imxgpio_pin_read(void *arg, int pin)
230 {
231 	struct imxgpio_softc * const gpio = arg;
232 	int val;
233 
234 	val = __SHIFTOUT(GPIO_READ(gpio, GPIO_DR), __BIT(pin));
235 
236 	return val;
237 }
238 
239 void
240 imxgpio_pin_write(void *arg, int pin, int value)
241 {
242 	struct imxgpio_softc * const gpio = arg;
243 	uint32_t mask = __BIT(pin);
244 	uint32_t old;
245 	uint32_t new;
246 
247 	mutex_enter(&gpio->gpio_lock);
248 
249 	old = GPIO_READ(gpio, GPIO_DR);
250 	if (value)
251 		new = old | mask;
252 	else
253 		new = old & ~mask;
254 
255 	if (old != new)
256 		GPIO_WRITE(gpio, GPIO_DR, new);
257 
258 	mutex_exit(&gpio->gpio_lock);
259 }
260 
261 void
262 imxgpio_pin_ctl(void *arg, int pin, int flags)
263 {
264 	struct imxgpio_softc * const gpio = arg;
265 	uint32_t mask = __BIT(pin);
266 	uint32_t old;
267 	uint32_t new;
268 
269 	mutex_enter(&gpio->gpio_lock);
270 
271 	old = GPIO_READ(gpio, GPIO_DIR);
272 	new = old;
273 	switch (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
274 	case GPIO_PIN_INPUT:
275 		new &= ~mask;
276 		break;
277 	case GPIO_PIN_OUTPUT:
278 		new |= mask;
279 		break;
280 	default:
281 		break;
282 	}
283 
284 	if (old != new)
285 		GPIO_WRITE(gpio, GPIO_DIR, new);
286 
287 	mutex_exit(&gpio->gpio_lock);
288 }
289 
290 static void
291 gpio_defer(device_t self)
292 {
293 	struct imxgpio_softc * const gpio = device_private(self);
294 	struct gpio_chipset_tag * const gp = &gpio->gpio_chipset;
295 	struct gpiobus_attach_args gba;
296 	gpio_pin_t *pins;
297 	uint32_t mask, dir, value;
298 	int pin;
299 
300 	gp->gp_cookie = gpio;
301 	gp->gp_pin_read = imxgpio_pin_read;
302 	gp->gp_pin_write = imxgpio_pin_write;
303 	gp->gp_pin_ctl = imxgpio_pin_ctl;
304 
305 	gba.gba_gc = gp;
306 	gba.gba_pins = gpio->gpio_pins;
307 	gba.gba_npins = __arraycount(gpio->gpio_pins);
308 
309 	dir = GPIO_READ(gpio, GPIO_DIR);
310 	value = GPIO_READ(gpio, GPIO_DR);
311 	for (pin = 0, mask = 1, pins = gpio->gpio_pins;
312 	     pin < 32; pin++, mask <<= 1, pins++) {
313 		pins->pin_num = pin;
314 		if ((gpio->gpio_edge_mask | gpio->gpio_level_mask) & mask)
315 			pins->pin_caps = GPIO_PIN_INPUT;
316 		else
317 			pins->pin_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
318 		pins->pin_flags =
319 		    (dir & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
320 		pins->pin_state =
321 		    (value & mask) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
322 	}
323 
324 	config_found_ia(self, "gpiobus", &gba, gpiobus_print);
325 }
326 #endif /* NGPIO > 0 */
327 
328 void
329 imxgpio_attach_common(device_t self)
330 {
331 	struct imxgpio_softc * const gpio = device_private(self);
332 
333 	KASSERT(gpio->gpio_unit < MAX_NGROUP);
334 
335 	gpio->gpio_dev = self;
336 
337 	if (gpio->gpio_irqbase > 0) {
338 		aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n",
339 		    gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1);
340 
341 		gpio->gpio_pic.pic_ops = &imxgpio_pic_ops;
342 		strlcpy(gpio->gpio_pic.pic_name, device_xname(self),
343 		    sizeof(gpio->gpio_pic.pic_name));
344 		gpio->gpio_pic.pic_maxsources = 32;
345 
346 		pic_add(&gpio->gpio_pic, gpio->gpio_irqbase);
347 	}
348 
349 	mutex_init(&gpio->gpio_lock, MUTEX_DEFAULT, IPL_VM);
350 
351 	imxgpio_handles[gpio->gpio_unit] = gpio;
352 
353 #if NGPIO > 0
354 	config_interrupts(self, gpio_defer);
355 #endif
356 }
357 
358 /* in-kernel GPIO access utility functions */
359 void
360 gpio_set_direction(u_int gpio, int dir)
361 {
362 	int index = gpio / GPIO_NPINS;
363 	int pin = gpio % GPIO_NPINS;
364 
365 	KDASSERT(index < imxgpio_ngroups);
366 	KASSERT(imxgpio_handles[index] != NULL);
367 
368 	imxgpio_pin_ctl(imxgpio_handles[index], pin, dir);
369 }
370 
371 void
372 gpio_data_write(u_int gpio, u_int value)
373 {
374 	int index = gpio / GPIO_NPINS;
375 	int pin = gpio % GPIO_NPINS;
376 
377 	KDASSERT(index < imxgpio_ngroups);
378 	KASSERT(imxgpio_handles[index] != NULL);
379 
380 	imxgpio_pin_write(imxgpio_handles[index], pin, value);
381 }
382 
383 bool
384 gpio_data_read(u_int gpio)
385 {
386 	int index = gpio / GPIO_NPINS;
387 	int pin = gpio % GPIO_NPINS;
388 
389 	KDASSERT(index < imxgpio_ngroups);
390 	KASSERT(imxgpio_handles[index] != NULL);
391 
392 	return imxgpio_pin_read(imxgpio_handles[index], pin) ? true : false;
393 }
394 
395