2 #include <minix/syslib.h>
3 #include <minix/drvlib.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>
13 #include <sys/types.h>
24 #include "gpio_omap.h"
26 /* used for logging */
27 static struct log log
= {
29 .log_level
= LEVEL_INFO
,
30 .log_func
= default_log
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
);
51 int (*message_hook
) (message
* m
);
54 static struct gpio_driver drv
;
59 uint32_t register_address
;
60 uint32_t irq_nr
; /* irq number */
61 uint32_t base_address
;
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
[] = {
73 .register_address
= AM335X_GPIO0_BASE
,
74 .irq_nr
= AM335X_GPIO0A_IRQ
,
77 .irq_id
= AM335X_GPIO0A_IRQ_HOOK_ID
,
78 .irq_hook_id
= AM335X_GPIO0A_IRQ_HOOK_ID
,
83 .register_address
= AM335X_GPIO1_BASE
,
84 .irq_nr
= AM335X_GPIO1A_IRQ
,
87 .irq_id
= AM335X_GPIO1A_IRQ_HOOK_ID
,
88 .irq_hook_id
= AM335X_GPIO1A_IRQ_HOOK_ID
,
93 .register_address
= AM335X_GPIO2_BASE
,
94 .irq_nr
= AM335X_GPIO2A_IRQ
,
97 .irq_id
= AM335X_GPIO2A_IRQ_HOOK_ID
,
98 .irq_hook_id
= AM335X_GPIO2A_IRQ_HOOK_ID
,
103 .register_address
= AM335X_GPIO3_BASE
,
104 .irq_nr
= AM335X_GPIO3A_IRQ
,
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
[] = {
117 .register_address
= DM37XX_GPIO1_BASE
,
118 .irq_nr
= DM37XX_GPIO1_IRQ
,
121 .irq_id
= DM37XX_GPIO1_IRQ_HOOK_ID
,
122 .irq_hook_id
= DM37XX_GPIO1_IRQ_HOOK_ID
,
126 .register_address
= DM37XX_GPIO2_BASE
,
127 .irq_nr
= DM37XX_GPIO2_IRQ
,
130 .irq_id
= DM37XX_GPIO2_IRQ_HOOK_ID
,
131 .irq_hook_id
= DM37XX_GPIO2_IRQ_HOOK_ID
,
135 .register_address
= DM37XX_GPIO3_BASE
,
136 .irq_nr
= DM37XX_GPIO3_IRQ
,
139 .irq_id
= DM37XX_GPIO3_IRQ_HOOK_ID
,
140 .irq_hook_id
= DM37XX_GPIO3_IRQ_HOOK_ID
,
144 .register_address
= DM37XX_GPIO4_BASE
,
145 .irq_nr
= DM37XX_GPIO4_IRQ
,
148 .irq_id
= DM37XX_GPIO4_IRQ_HOOK_ID
,
149 .irq_hook_id
= DM37XX_GPIO4_IRQ_HOOK_ID
,
153 .register_address
= DM37XX_GPIO5_BASE
,
154 .irq_nr
= DM37XX_GPIO5_IRQ
,
157 .irq_id
= DM37XX_GPIO5_IRQ_HOOK_ID
,
158 .irq_hook_id
= DM37XX_GPIO5_IRQ_HOOK_ID
,
162 .register_address
= DM37XX_GPIO6_BASE
,
163 .irq_nr
= DM37XX_GPIO6_IRQ
,
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
{
186 vir_bytes RISINGDETECT
;
187 vir_bytes FALLINGDETECT
;
188 vir_bytes CLEARDATAOUT
;
189 vir_bytes SETDATAOUT
;
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];
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",
243 if (omap_gpio_bank_get(nr
)->disabled
== 1) {
244 log_warn(&log
, "%s is claiming GPIO %d from disabled bank\n",
249 struct gpio
*tmp
= malloc(sizeof(struct gpio
));
250 memset(tmp
, 0, sizeof(*tmp
));
258 omap_gpio_pin_mode(struct gpio
*gpio
, int mode
)
260 struct omap_gpio_bank
*bank
;
261 assert(gpio
!= NULL
);
264 bank
= omap_gpio_bank_get(gpio
->nr
);
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);
273 set32(bank
->base_address
+ regs
->FALLINGDETECT
,
274 BIT(gpio
->nr
% 32), 0xffffffff);
275 set32(bank
->base_address
+ regs
->IRQENABLE
, BIT(gpio
->nr
% 32),
277 set32(bank
->base_address
+ regs
->OE
, BIT(gpio
->nr
% 32),
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
);
292 write32(bank
->base_address
+ regs
->SETDATAOUT
,
295 write32(bank
->base_address
+ regs
->CLEARDATAOUT
,
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
) {
315 (read32(bank
->base_address
+
316 regs
->DATAIN
) >> (gpio
->nr
% 32)) & 0x1;
319 (read32(bank
->base_address
+
320 regs
->DATAOUT
) >> (gpio
->nr
% 32)) & 0x1;
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;
338 bank
->inter_values
&= ~(1 << (gpio
->nr
% 32));
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
)) {
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",
361 bank
->inter_values
|=
362 read32(bank
->base_address
+
364 /* clear the interrupts */
365 write32(bank
->base_address
+ regs
->IRQSTATUS
,
367 if (sys_irqenable(&bank
->irq_hook_id
) != OK
) {
369 "Failed to enable irq for bank %s\n",
376 log_debug(&log
, "Unknown message\n");
382 static int revision_matches(u32_t board_id
,u32_t rev
) {
383 /* figures out if the collected resition matches the one expected
385 if (BOARD_IS_BBXM(board_id
)){
387 DM37XX_GPIO_REVISION_MAJOR(rev
) != 2
388 || DM37XX_GPIO_REVISION_MINOR(rev
) != 5
392 } else if (BOARD_IS_BB(board_id
)){
394 AM335X_GPIO_REVISION_MAJOR(rev
) != 0
395 || AM335X_GPIO_REVISION_MINOR(rev
) != 1
404 omap_gpio_init(struct gpio_driver
*gpdrv
)
408 struct minix_mem_range mr
;
409 struct omap_gpio_bank
*bank
;
410 struct machine machine
;
411 sys_getmachine(&machine
);
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
++) {
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) {
432 "Unable to request permission to map memory\n");
433 return EPERM
; /* fixme */
436 /* Set the base address to use */
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
)) {
450 "Failed to read the revision of GPIO bank %s.. disabling\n",
452 log_warn(&log
, "Got 0x%x\n", revision
);
458 if (sys_irqsetpolicy(bank
->irq_nr
, 0,
459 &bank
->irq_hook_id
) != OK
) {
461 "GPIO: couldn't set IRQ policy for bank %s\n",
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
) {
471 "GPIO: couldn't enable interrupt for %s\n",
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
);
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);
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
;
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
);
542 gpio_intr_message(message
* m
)
544 return drv
.message_hook(m
);