xref: /minix3/minix/lib/libgpio/gpio_omap.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /* kernel headers */
2 #include <minix/syslib.h>
3 #include <minix/drvlib.h>
4 #include <minix/log.h>
5 #include <minix/mmio.h>
6 #include <minix/gpio.h>
7 #include <minix/clkconf.h>
8 #include <minix/type.h>
9 #include <minix/board.h>
10 
11 /* system headers */
12 #include <sys/mman.h>
13 #include <sys/types.h>
14 
15 /* usr headers */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <assert.h>
22 
23 /* local headers */
24 #include "gpio_omap.h"
25 
26 /* used for logging */
27 static struct log log = {
28 	.name = "gpio_omap",
29 	.log_level = LEVEL_INFO,
30 	.log_func = default_log
31 };
32 
33 struct gpio_driver
34 {
35 	/* request access to a gpio */
36 	int (*claim) (char *owner, int nr, struct gpio ** gpio);
37 
38 	/* Configure the GPIO for a certain purpose */
39 	int (*pin_mode) (struct gpio * gpio, int mode);
40 
41 	/* Set the value for a GPIO */
42 	int (*set) (struct gpio * gpio, int value);
43 
44 	/* Read the current value of the GPIO */
45 	int (*read) (struct gpio * gpio, int *value);
46 
47 	/* Read and clear the value interrupt value of the GPIO */
48 	int (*intr_read) (struct gpio * gpio, int *value);
49 
50 	/* Interrupt hook */
51 	int (*message_hook) (message * m);
52 };
53 
54 static struct gpio_driver drv;
55 
56 struct omap_gpio_bank
57 {
58 	const char *name;
59 	uint32_t register_address;
60 	uint32_t irq_nr;	/* irq number */
61 	uint32_t base_address;
62 	int32_t disabled;
63 	int irq_id;		/* original hook id??? */
64 	int irq_hook_id;	/* hook id */
65 	uint32_t inter_values;	/* values when the interrupt was called */
66 };
67 
68 static struct omap_gpio_bank *omap_gpio_banks;
69 
70 static struct omap_gpio_bank am335x_gpio_banks[] = {
71 	{
72 		    .name = "GPIO0",
73 		    .register_address = AM335X_GPIO0_BASE,
74 		    .irq_nr = AM335X_GPIO0A_IRQ,
75 		    .base_address = 0,
76 		    .disabled = 0,
77 		    .irq_id = AM335X_GPIO0A_IRQ_HOOK_ID,
78 		    .irq_hook_id = AM335X_GPIO0A_IRQ_HOOK_ID,
79 
80 	    },
81 	{
82 		    .name = "GPIO1",
83 		    .register_address = AM335X_GPIO1_BASE,
84 		    .irq_nr = AM335X_GPIO1A_IRQ,
85 		    .base_address = 0,
86 		    .disabled = 0,
87 		    .irq_id = AM335X_GPIO1A_IRQ_HOOK_ID,
88 		    .irq_hook_id = AM335X_GPIO1A_IRQ_HOOK_ID,
89 
90 	    },
91 	{
92 		    .name = "GPIO2",
93 		    .register_address = AM335X_GPIO2_BASE,
94 		    .irq_nr = AM335X_GPIO2A_IRQ,
95 		    .base_address = 0,
96 		    .disabled = 0,
97 		    .irq_id = AM335X_GPIO2A_IRQ_HOOK_ID,
98 		    .irq_hook_id = AM335X_GPIO2A_IRQ_HOOK_ID,
99 
100 	    },
101 	{
102 		    .name = "GPIO3",
103 		    .register_address = AM335X_GPIO3_BASE,
104 		    .irq_nr = AM335X_GPIO3A_IRQ,
105 		    .base_address = 0,
106 		    .disabled = 0,
107 		    .irq_id = AM335X_GPIO3A_IRQ_HOOK_ID,
108 		    .irq_hook_id = AM335X_GPIO3A_IRQ_HOOK_ID,
109 
110 	    },
111 	{NULL, 0, 0, 0, 0, 0, 0, 0 }
112 };
113 
114 static struct omap_gpio_bank dm37xx_gpio_banks[] = {
115 	{
116 		    .name = "GPIO1",
117 		    .register_address = DM37XX_GPIO1_BASE,
118 		    .irq_nr = DM37XX_GPIO1_IRQ,
119 		    .base_address = 0,
120 		    .disabled = 0,
121 		    .irq_id = DM37XX_GPIO1_IRQ_HOOK_ID,
122 		    .irq_hook_id = DM37XX_GPIO1_IRQ_HOOK_ID,
123 	    },
124 	{
125 		    .name = "GPIO2",
126 		    .register_address = DM37XX_GPIO2_BASE,
127 		    .irq_nr = DM37XX_GPIO2_IRQ,
128 		    .base_address = 0,
129 		    .disabled = 0,
130 		    .irq_id = DM37XX_GPIO2_IRQ_HOOK_ID,
131 		    .irq_hook_id = DM37XX_GPIO2_IRQ_HOOK_ID,
132 	    },
133 	{
134 		    .name = "GPIO3",
135 		    .register_address = DM37XX_GPIO3_BASE,
136 		    .irq_nr = DM37XX_GPIO3_IRQ,
137 		    .base_address = 0,
138 		    .disabled = 0,
139 		    .irq_id = DM37XX_GPIO3_IRQ_HOOK_ID,
140 		    .irq_hook_id = DM37XX_GPIO3_IRQ_HOOK_ID,
141 	    },
142 	{
143 		    .name = "GPIO4",
144 		    .register_address = DM37XX_GPIO4_BASE,
145 		    .irq_nr = DM37XX_GPIO4_IRQ,
146 		    .base_address = 0,
147 		    .disabled = 0,
148 		    .irq_id = DM37XX_GPIO4_IRQ_HOOK_ID,
149 		    .irq_hook_id = DM37XX_GPIO4_IRQ_HOOK_ID,
150 	    },
151 	{
152 		    .name = "GPIO5",
153 		    .register_address = DM37XX_GPIO5_BASE,
154 		    .irq_nr = DM37XX_GPIO5_IRQ,
155 		    .base_address = 0,
156 		    .disabled = 0,
157 		    .irq_id = DM37XX_GPIO5_IRQ_HOOK_ID,
158 		    .irq_hook_id = DM37XX_GPIO5_IRQ_HOOK_ID,
159 	    },
160 	{
161 		    .name = "GPIO6",
162 		    .register_address = DM37XX_GPIO6_BASE,
163 		    .irq_nr = DM37XX_GPIO6_IRQ,
164 		    .base_address = 0,
165 		    .disabled = 0,
166 		    .irq_id = DM37XX_GPIO6_IRQ_HOOK_ID,
167 		    .irq_hook_id = DM37XX_GPIO6_IRQ_HOOK_ID,
168 	    },
169 	{NULL, 0, 0, 0, 0, 0, 0, 0 }
170 };
171 
172 static int nbanks; /* number of banks */
173 
174 /*
175  * Defines the set of registers. There is a lot of commonality between the
176  * AM335X and DM37XX gpio registers. To avoid ifdefs everywhere, we define
177  * a central register set and only use ifdefs where they differ.
178  */
179 typedef struct gpio_omap_registers {
180 	vir_bytes REVISION;
181 	vir_bytes IRQENABLE;
182 	vir_bytes IRQSTATUS;
183 	vir_bytes DATAOUT;
184 	vir_bytes DATAIN;
185 	vir_bytes OE;
186 	vir_bytes RISINGDETECT;
187 	vir_bytes FALLINGDETECT;
188 	vir_bytes CLEARDATAOUT;
189 	vir_bytes SETDATAOUT;
190 } gpio_omap_regs_t;
191 
192 /* Define the registers for each chip */
193 
194 gpio_omap_regs_t gpio_omap_dm37xx = {
195 	.REVISION = DM37XX_GPIO_REVISION,
196 	.IRQENABLE = DM37XX_GPIO_IRQENABLE1,
197 	.IRQSTATUS = DM37XX_GPIO_IRQSTATUS1,
198 	.DATAOUT = DM37XX_GPIO_DATAOUT,
199 	.DATAIN = DM37XX_GPIO_DATAIN,
200 	.OE = DM37XX_GPIO_OE,
201 	.RISINGDETECT = DM37XX_GPIO_RISINGDETECT1,
202 	.FALLINGDETECT = DM37XX_GPIO_FALLINGDETECT1,
203 	.CLEARDATAOUT = DM37XX_GPIO_CLEARDATAOUT,
204 	.SETDATAOUT = DM37XX_GPIO_SETDATAOUT
205 };
206 
207 gpio_omap_regs_t gpio_omap_am335x = {
208 	.REVISION = AM335X_GPIO_REVISION,
209 	.IRQENABLE = AM335X_GPIO_IRQSTATUS_SET_0,
210 	.IRQSTATUS = AM335X_GPIO_IRQSTATUS_0,
211 	.DATAOUT = AM335X_GPIO_DATAOUT,
212 	.DATAIN = AM335X_GPIO_DATAIN,
213 	.OE = AM335X_GPIO_OE,
214 	.RISINGDETECT = AM335X_GPIO_RISINGDETECT,
215 	.FALLINGDETECT = AM335X_GPIO_FALLINGDETECT,
216 	.CLEARDATAOUT = AM335X_GPIO_CLEARDATAOUT,
217 	.SETDATAOUT = AM335X_GPIO_SETDATAOUT
218 };
219 
220 static gpio_omap_regs_t *regs;
221 
222 
223 static struct omap_gpio_bank *
omap_gpio_bank_get(int gpio_nr)224 omap_gpio_bank_get(int gpio_nr)
225 {
226 	struct omap_gpio_bank *bank;
227 	assert(gpio_nr >= 0 && gpio_nr <= 32 * nbanks);
228 	bank = &omap_gpio_banks[gpio_nr / 32];
229 	return bank;
230 }
231 
232 static int
omap_gpio_claim(char * owner,int nr,struct gpio ** gpio)233 omap_gpio_claim(char *owner, int nr, struct gpio **gpio)
234 {
235 	log_trace(&log, "%s s claiming %d\n", owner, nr);
236 
237 	if (nr < 0 && nr >= 32 * nbanks) {
238 		log_warn(&log, "%s is claiming unknown GPIO number %d\n",
239 		    owner, nr);
240 		return EINVAL;
241 	}
242 
243 	if (omap_gpio_bank_get(nr)->disabled == 1) {
244 		log_warn(&log, "%s is claiming GPIO %d from disabled bank\n",
245 		    owner, nr);
246 		return EINVAL;
247 	}
248 
249 	struct gpio *tmp = malloc(sizeof(struct gpio));
250 	memset(tmp, 0, sizeof(*tmp));
251 
252 	tmp->nr = nr;
253 	*gpio = tmp;
254 	return OK;
255 }
256 
257 static int
omap_gpio_pin_mode(struct gpio * gpio,int mode)258 omap_gpio_pin_mode(struct gpio *gpio, int mode)
259 {
260 	struct omap_gpio_bank *bank;
261 	assert(gpio != NULL);
262 	gpio->mode = mode;
263 
264 	bank = omap_gpio_bank_get(gpio->nr);
265 	log_debug(&log,
266 	    "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n",
267 	    bank->name, bank->base_address, bank->register_address, regs->OE,
268 	    bank->register_address + regs->OE);
269 
270 	if (mode == GPIO_MODE_OUTPUT) {
271 		set32(bank->base_address + regs->OE, BIT(gpio->nr % 32), 0);
272 	} else {
273 		set32(bank->base_address + regs->FALLINGDETECT,
274 		    BIT(gpio->nr % 32), 0xffffffff);
275 		set32(bank->base_address + regs->IRQENABLE, BIT(gpio->nr % 32),
276 		    0xffffffff);
277 		set32(bank->base_address + regs->OE, BIT(gpio->nr % 32),
278 		    0xffffffff);
279 	}
280 	return 0;
281 }
282 
283 static int
omap_gpio_set(struct gpio * gpio,int value)284 omap_gpio_set(struct gpio *gpio, int value)
285 {
286 	struct omap_gpio_bank *bank;
287 	assert(gpio != NULL);
288 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
289 
290 	bank = omap_gpio_bank_get(gpio->nr);
291 	if (value == 1) {
292 		write32(bank->base_address + regs->SETDATAOUT,
293 		    BIT(gpio->nr % 32));
294 	} else {
295 		write32(bank->base_address + regs->CLEARDATAOUT,
296 		    BIT(gpio->nr % 32));
297 	}
298 	return OK;
299 }
300 
301 static int
omap_gpio_read(struct gpio * gpio,int * value)302 omap_gpio_read(struct gpio *gpio, int *value)
303 {
304 	struct omap_gpio_bank *bank;
305 	assert(gpio != NULL);
306 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
307 
308 	bank = omap_gpio_bank_get(gpio->nr);
309 	log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode,
310 	    read32(bank->base_address + regs->DATAIN),
311 	    read32(bank->base_address + regs->DATAOUT));
312 
313 	if (gpio->mode == GPIO_MODE_INPUT) {
314 		*value =
315 		    (read32(bank->base_address +
316 			regs->DATAIN) >> (gpio->nr % 32)) & 0x1;
317 	} else {
318 		*value =
319 		    (read32(bank->base_address +
320 			regs->DATAOUT) >> (gpio->nr % 32)) & 0x1;
321 	}
322 
323 	return OK;
324 }
325 
326 static int
omap_gpio_intr_read(struct gpio * gpio,int * value)327 omap_gpio_intr_read(struct gpio *gpio, int *value)
328 {
329 	struct omap_gpio_bank *bank;
330 	assert(gpio != NULL);
331 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
332 
333 	bank = omap_gpio_bank_get(gpio->nr);
334 	/* TODO: check if interrupt where enabled?? */
335 
336 	*value = (bank->inter_values >> (gpio->nr % 32)) & 0x1;
337 	/* clear the data */
338 	bank->inter_values &= ~(1 << (gpio->nr % 32));
339 
340 	return OK;
341 }
342 
343 static int
omap_message_hook(message * m)344 omap_message_hook(message * m)
345 {
346 	unsigned long irq_set, i;
347 	struct omap_gpio_bank *bank;
348 
349 	switch (_ENDPOINT_P(m->m_source)) {
350 	case HARDWARE:
351 		/* Hardware interrupt return a "set" if pending interrupts */
352 		irq_set = m->m_notify.interrupts;
353 		log_debug(&log, "HW message 0X%08llx\n", m->m_notify.interrupts);
354 		bank = &omap_gpio_banks[0];
355 		for (i = 0; omap_gpio_banks[i].name != NULL; i++) {
356 			bank = &omap_gpio_banks[i];
357 
358 			if (irq_set & (1 << (bank->irq_id))) {
359 				log_trace(&log, "Interrupt for bank %s\n",
360 				    bank->name);
361 				bank->inter_values |=
362 				    read32(bank->base_address +
363 				    regs->IRQSTATUS);
364 				/* clear the interrupts */
365 				write32(bank->base_address + regs->IRQSTATUS,
366 				    0xffffffff);
367 				if (sys_irqenable(&bank->irq_hook_id) != OK) {
368 					log_warn(&log,
369 					    "Failed to enable irq for bank %s\n",
370 					    bank->name);
371 				}
372 			}
373 		}
374 		return OK;
375 	default:
376 		log_debug(&log, "Unknown message\n");
377 		break;
378 	}
379 	return OK;
380 }
381 
revision_matches(u32_t board_id,u32_t rev)382 static int revision_matches(u32_t board_id,u32_t rev) {
383 	/* figures out if the collected resition matches the one expected
384 	 * from the board */
385 	if (BOARD_IS_BBXM(board_id)){
386 		if(
387 		   DM37XX_GPIO_REVISION_MAJOR(rev) != 2
388 		   || DM37XX_GPIO_REVISION_MINOR(rev) !=  5
389 		   ) {
390 			return 0;
391 		}
392 	} else if (BOARD_IS_BB(board_id)){
393 		if (
394 		    AM335X_GPIO_REVISION_MAJOR(rev) != 0
395 		    || AM335X_GPIO_REVISION_MINOR(rev) != 1
396 		    ) {
397 			return 0;
398 		}
399 	}
400 	return 1;
401 }
402 
403 static int
omap_gpio_init(struct gpio_driver * gpdrv)404 omap_gpio_init(struct gpio_driver *gpdrv)
405 {
406 	u32_t revision;
407 	int i;
408 	struct minix_mem_range mr;
409 	struct omap_gpio_bank *bank;
410 	struct machine machine;
411 	sys_getmachine(&machine);
412 
413 	nbanks =0;
414 	omap_gpio_banks = NULL;
415 	if (BOARD_IS_BBXM(machine.board_id)){
416 		omap_gpio_banks = dm37xx_gpio_banks;
417 		regs = &gpio_omap_dm37xx;
418 	} else if (BOARD_IS_BB(machine.board_id)){
419 		omap_gpio_banks = am335x_gpio_banks;
420 		regs = &gpio_omap_am335x;
421 	}
422 
423 	bank = &omap_gpio_banks[0];
424 	for (i = 0; omap_gpio_banks[i].name != NULL; i++) {
425 		nbanks++;
426 		bank = &omap_gpio_banks[i];
427 		mr.mr_base = bank->register_address;
428 		mr.mr_limit = bank->register_address + 0x400;
429 
430 		if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
431 			log_warn(&log,
432 			    "Unable to request permission to map memory\n");
433 			return EPERM;	/* fixme */
434 		}
435 
436 		/* Set the base address to use */
437 		bank->base_address =
438 		    (uint32_t) vm_map_phys(SELF,
439 		    (void *) bank->register_address, 0x400);
440 
441 		if (bank->base_address == (uint32_t) MAP_FAILED) {
442 			log_warn(&log, "Unable to map GPIO memory\n");
443 			return EPERM;	/* fixme */
444 		}
445 
446 		revision = read32(bank->base_address + regs->REVISION);
447 		/* test if we can access it */
448 		if (! revision_matches(machine.board_id,revision)) {
449 			log_warn(&log,
450 			    "Failed to read the revision of GPIO bank %s.. disabling\n",
451 			    bank->name);
452 			log_warn(&log, "Got 0x%x\n", revision);
453 			bank->disabled = 1;
454 		} else {
455 			bank->disabled = 0;
456 		}
457 
458 		if (sys_irqsetpolicy(bank->irq_nr, 0,
459 			&bank->irq_hook_id) != OK) {
460 			log_warn(&log,
461 			    "GPIO: couldn't set IRQ policy for bank %s\n",
462 			    bank->name);
463 			continue;
464 		};
465 		if (bank->irq_id != bank->irq_hook_id) {
466 			log_debug(&log, "requested id %d but got id %d\n",
467 			    bank->irq_id, bank->irq_hook_id);
468 		}
469 		if (sys_irqenable(&bank->irq_hook_id) != OK) {
470 			log_warn(&log,
471 			    "GPIO: couldn't enable interrupt for %s\n",
472 			    bank->name);
473 		};
474 		log_trace(&log, "bank %s mapped on 0x%x with irq hook id %d\n",
475 		    bank->name, bank->base_address, bank->irq_hook_id);
476 
477 	};
478 
479 	clkconf_init();
480 
481 	if (BOARD_IS_BBXM(machine.board_id)){
482 		/* enable the interface and functional clock on GPIO bank 1 , this only
483 		   applies to the Beagelboard XM */
484 		clkconf_set(CM_FCLKEN_WKUP, BIT(3), 0xffffffff);
485 		clkconf_set(CM_ICLKEN_WKUP, BIT(3), 0xffffffff);
486 	}
487 	clkconf_release();
488 
489 
490 	gpdrv->claim = omap_gpio_claim;
491 	gpdrv->pin_mode = omap_gpio_pin_mode;
492 	gpdrv->set = omap_gpio_set;
493 	gpdrv->read = omap_gpio_read;
494 	gpdrv->intr_read = omap_gpio_intr_read;
495 	gpdrv->message_hook = omap_message_hook;
496 	return 0;
497 }
498 
499 int
gpio_init()500 gpio_init()
501 {
502 	return omap_gpio_init(&drv);
503 }
504 
505 /* request access to a gpio */
506 int
gpio_claim(char * owner,int nr,struct gpio ** gpio)507 gpio_claim(char *owner, int nr, struct gpio **gpio)
508 {
509 	return drv.claim(owner, nr, gpio);
510 }
511 
512 /* Configure the GPIO for a certain purpose */
513 int
gpio_pin_mode(struct gpio * gpio,int mode)514 gpio_pin_mode(struct gpio *gpio, int mode)
515 {
516 	return drv.pin_mode(gpio, mode);
517 }
518 
519 /* Set the value for a GPIO */
520 int
gpio_set(struct gpio * gpio,int value)521 gpio_set(struct gpio *gpio, int value)
522 {
523 	return drv.set(gpio, value);
524 }
525 
526 /* Read the current value of the GPIO */
527 int
gpio_read(struct gpio * gpio,int * value)528 gpio_read(struct gpio *gpio, int *value)
529 {
530 	return drv.read(gpio, value);
531 }
532 
533 /* Read and clear the value interrupt value of the GPIO */
534 int
gpio_intr_read(struct gpio * gpio,int * value)535 gpio_intr_read(struct gpio *gpio, int *value)
536 {
537 	return drv.intr_read(gpio, value);
538 }
539 
540 /* Interrupt hook */
541 int
gpio_intr_message(message * m)542 gpio_intr_message(message * m)
543 {
544 	return drv.message_hook(m);
545 }
546 
547 int
gpio_release(void)548 gpio_release(void)
549 {
550 	return OK;
551 }
552