xref: /netbsd-src/sys/arch/arm/imx/imxgpio.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1 /*	$NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2007, 2020 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.11 2021/08/07 16:18:44 thorpej 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 #include <sys/cpu.h>
44 #include <sys/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
imxgpio_pic_unblock_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)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
imxgpio_pic_block_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)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
imxgpio_pic_find_pending_irqs(struct pic_softc * pic)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
imxgpio_pic_establish_irq(struct pic_softc * pic,struct intrsource * is)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
imxgpio_pin_read(void * arg,int pin)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
imxgpio_pin_write(void * arg,int pin,int value)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
imxgpio_pin_ctl(void * arg,int pin,int flags)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
imxgpio_attach_ports(struct imxgpio_softc * gpio)291 imxgpio_attach_ports(struct imxgpio_softc *gpio)
292 {
293 	struct gpio_chipset_tag * const gp = &gpio->gpio_chipset;
294 	struct gpiobus_attach_args gba;
295 	uint32_t dir;
296 	u_int pin;
297 
298 	gp->gp_cookie = gpio;
299 	gp->gp_pin_read = imxgpio_pin_read;
300 	gp->gp_pin_write = imxgpio_pin_write;
301 	gp->gp_pin_ctl = imxgpio_pin_ctl;
302 
303 	dir = GPIO_READ(gpio, GPIO_DIR);
304 	for (pin = 0; pin < __arraycount(gpio->gpio_pins); pin++) {
305 		uint32_t mask = __BIT(pin);
306 		gpio_pin_t *pins = &gpio->gpio_pins[pin];
307 		pins->pin_num = pin;
308 		if ((gpio->gpio_edge_mask | gpio->gpio_level_mask) & mask)
309 			pins->pin_caps = GPIO_PIN_INPUT;
310 		else
311 			pins->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
312 		pins->pin_flags =
313 		    (dir & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
314 		pins->pin_state = imxgpio_pin_read(gpio, pin);
315 	}
316 
317 	memset(&gba, 0, sizeof(gba));
318 	gba.gba_gc = gp;
319 	gba.gba_pins = gpio->gpio_pins;
320 	gba.gba_npins = __arraycount(gpio->gpio_pins);
321 	config_found(gpio->gpio_dev, &gba, gpiobus_print, CFARGS_NONE);
322 }
323 #endif /* NGPIO > 0 */
324 
325 void
imxgpio_attach_common(device_t self)326 imxgpio_attach_common(device_t self)
327 {
328 	struct imxgpio_softc * const gpio = device_private(self);
329 
330 	gpio->gpio_dev = self;
331 
332 	if (gpio->gpio_irqbase == PIC_IRQBASE_ALLOC || gpio->gpio_irqbase > 0) {
333 		gpio->gpio_pic.pic_ops = &imxgpio_pic_ops;
334 		strlcpy(gpio->gpio_pic.pic_name, device_xname(self),
335 		    sizeof(gpio->gpio_pic.pic_name));
336 		gpio->gpio_pic.pic_maxsources = GPIO_NPINS;
337 
338 		gpio->gpio_irqbase = pic_add(&gpio->gpio_pic, gpio->gpio_irqbase);
339 
340 		aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n",
341 		    gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1);
342 	}
343 
344 	mutex_init(&gpio->gpio_lock, MUTEX_DEFAULT, IPL_VM);
345 
346 	if (gpio->gpio_unit != -1) {
347 		KASSERT(gpio->gpio_unit < MAX_NGROUP);
348 		imxgpio_handles[gpio->gpio_unit] = gpio;
349 	}
350 
351 #if NGPIO > 0
352 	imxgpio_attach_ports(gpio);
353 #endif
354 }
355 
356 /* in-kernel GPIO access utility functions */
357 void
imxgpio_set_direction(u_int gpio,int dir)358 imxgpio_set_direction(u_int gpio, int dir)
359 {
360 	int index = gpio / GPIO_NPINS;
361 	int pin = gpio % GPIO_NPINS;
362 
363 	KDASSERT(index < imxgpio_ngroups);
364 	KASSERT(imxgpio_handles[index] != NULL);
365 
366 	imxgpio_pin_ctl(imxgpio_handles[index], pin, dir);
367 }
368 
369 void
imxgpio_data_write(u_int gpio,u_int value)370 imxgpio_data_write(u_int gpio, u_int value)
371 {
372 	int index = gpio / GPIO_NPINS;
373 	int pin = gpio % GPIO_NPINS;
374 
375 	KDASSERT(index < imxgpio_ngroups);
376 	KASSERT(imxgpio_handles[index] != NULL);
377 
378 	imxgpio_pin_write(imxgpio_handles[index], pin, value);
379 }
380 
381 bool
imxgpio_data_read(u_int gpio)382 imxgpio_data_read(u_int gpio)
383 {
384 	int index = gpio / GPIO_NPINS;
385 	int pin = gpio % GPIO_NPINS;
386 
387 	KDASSERT(index < imxgpio_ngroups);
388 	KASSERT(imxgpio_handles[index] != NULL);
389 
390 	return imxgpio_pin_read(imxgpio_handles[index], pin) ? true : false;
391 }
392 
393