Remove building with NOCRYPTO option
[minix3.git] / minix / lib / libgpio / gpio_omap.c
bloba5c99334f2df6c86bbccc591dfa82ba754693ed7
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>
11 /* system headers */
12 #include <sys/mman.h>
13 #include <sys/types.h>
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>
23 /* local headers */
24 #include "gpio_omap.h"
26 /* used for logging */
27 static struct log log = {
28 .name = "gpio_omap",
29 .log_level = LEVEL_INFO,
30 .log_func = default_log
33 struct gpio_driver
35 /* request access to a gpio */
36 int (*claim) (char *owner, int nr, struct gpio ** gpio);
38 /* Configure the GPIO for a certain purpose */
39 int (*pin_mode) (struct gpio * gpio, int mode);
41 /* Set the value for a GPIO */
42 int (*set) (struct gpio * gpio, int value);
44 /* Read the current value of the GPIO */
45 int (*read) (struct gpio * gpio, int *value);
47 /* Read and clear the value interrupt value of the GPIO */
48 int (*intr_read) (struct gpio * gpio, int *value);
50 /* Interrupt hook */
51 int (*message_hook) (message * m);
54 static struct gpio_driver drv;
56 struct omap_gpio_bank
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 */
68 static struct omap_gpio_bank *omap_gpio_banks;
70 static struct omap_gpio_bank am335x_gpio_banks[] = {
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,
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,
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,
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,
111 {NULL, 0, 0, 0, 0, 0, 0, 0 }
114 static struct omap_gpio_bank dm37xx_gpio_banks[] = {
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,
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,
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,
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,
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,
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,
169 {NULL, 0, 0, 0, 0, 0, 0, 0 }
172 static int nbanks; /* number of banks */
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.
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;
192 /* Define the registers for each chip */
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
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
220 static gpio_omap_regs_t *regs;
223 static struct omap_gpio_bank *
224 omap_gpio_bank_get(int gpio_nr)
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;
232 static int
233 omap_gpio_claim(char *owner, int nr, struct gpio **gpio)
235 log_trace(&log, "%s s claiming %d\n", owner, nr);
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;
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;
249 struct gpio *tmp = malloc(sizeof(struct gpio));
250 memset(tmp, 0, sizeof(*tmp));
252 tmp->nr = nr;
253 *gpio = tmp;
254 return OK;
257 static int
258 omap_gpio_pin_mode(struct gpio *gpio, int mode)
260 struct omap_gpio_bank *bank;
261 assert(gpio != NULL);
262 gpio->mode = mode;
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);
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);
280 return 0;
283 static int
284 omap_gpio_set(struct gpio *gpio, int value)
286 struct omap_gpio_bank *bank;
287 assert(gpio != NULL);
288 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
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));
298 return OK;
301 static int
302 omap_gpio_read(struct gpio *gpio, int *value)
304 struct omap_gpio_bank *bank;
305 assert(gpio != NULL);
306 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
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));
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;
323 return OK;
326 static int
327 omap_gpio_intr_read(struct gpio *gpio, int *value)
329 struct omap_gpio_bank *bank;
330 assert(gpio != NULL);
331 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
333 bank = omap_gpio_bank_get(gpio->nr);
334 /* TODO: check if interrupt where enabled?? */
336 *value = (bank->inter_values >> (gpio->nr % 32)) & 0x1;
337 /* clear the data */
338 bank->inter_values &= ~(1 << (gpio->nr % 32));
340 return OK;
343 static int
344 omap_message_hook(message * m)
346 unsigned long irq_set, i;
347 struct omap_gpio_bank *bank;
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];
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);
374 return OK;
375 default:
376 log_debug(&log, "Unknown message\n");
377 break;
379 return OK;
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)){
387 DM37XX_GPIO_REVISION_MAJOR(rev) != 2
388 || DM37XX_GPIO_REVISION_MINOR(rev) != 5
390 return 0;
392 } else if (BOARD_IS_BB(board_id)){
393 if (
394 AM335X_GPIO_REVISION_MAJOR(rev) != 0
395 || AM335X_GPIO_REVISION_MINOR(rev) != 1
397 return 0;
400 return 1;
403 static int
404 omap_gpio_init(struct gpio_driver *gpdrv)
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);
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;
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;
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 */
436 /* Set the base address to use */
437 bank->base_address =
438 (uint32_t) vm_map_phys(SELF,
439 (void *) bank->register_address, 0x400);
441 if (bank->base_address == (uint32_t) MAP_FAILED) {
442 log_warn(&log, "Unable to map GPIO memory\n");
443 return EPERM; /* fixme */
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;
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;
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);
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);
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);
479 clkconf_init();
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);
487 clkconf_release();
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;
500 gpio_init()
502 return omap_gpio_init(&drv);
505 /* request access to a gpio */
507 gpio_claim(char *owner, int nr, struct gpio **gpio)
509 return drv.claim(owner, nr, gpio);
512 /* Configure the GPIO for a certain purpose */
514 gpio_pin_mode(struct gpio *gpio, int mode)
516 return drv.pin_mode(gpio, mode);
519 /* Set the value for a GPIO */
521 gpio_set(struct gpio *gpio, int value)
523 return drv.set(gpio, value);
526 /* Read the current value of the GPIO */
528 gpio_read(struct gpio *gpio, int *value)
530 return drv.read(gpio, value);
533 /* Read and clear the value interrupt value of the GPIO */
535 gpio_intr_read(struct gpio *gpio, int *value)
537 return drv.intr_read(gpio, value);
540 /* Interrupt hook */
542 gpio_intr_message(message * m)
544 return drv.message_hook(m);
548 gpio_release(void)
550 return OK;