File size: 3,507 Bytes
829b19c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * HAL — GPIO driver for OMAP3530
 */

#include "gpio.h"

static hw_reg32_t gpio_bank_base(uint8_t bank) {
    switch (bank) {
        case 1: return (hw_reg32_t)GPIO1_BASE;
        case 2: return (hw_reg32_t)GPIO2_BASE;
        case 3: return (hw_reg32_t)GPIO3_BASE;
        case 4: return (hw_reg32_t)GPIO4_BASE;
        case 5: return (hw_reg32_t)GPIO5_BASE;
        case 6: return (hw_reg32_t)GPIO6_BASE;
        default: return (hw_reg32_t)GPIO1_BASE;
    }
}

void gpio_init(gpio_dev_t *dev, uint8_t bank) {
    dev->bank = bank;
    dev->base = gpio_bank_base(bank);

    /* Enable GPIO module (auto-idle off for reliability) */
    reg_write32(dev->base + GPIO_SYSCONFIG, 0x04);  /* Smart idle */
    delay_cycles(50);

    /* Wait for reset to complete */
    while (!(reg_read32(dev->base + GPIO_SYSSTATUS) & 0x01))
        ;

    /* Disable all GPIO interrupts */
    reg_write32(dev->base + GPIO_IRQENABLE1, 0x00);
    reg_write32(dev->base + GPIO_LEVELDETECT0, 0x00);
    reg_write32(dev->base + GPIO_LEVELDETECT1, 0x00);
    reg_write32(dev->base + GPIO_RISINGDETECT, 0x00);
    reg_write32(dev->base + GPIO_FALLINGDETECT, 0x00);
}

void gpio_set_dir(gpio_dev_t *dev, uint8_t pin, gpio_dir_t dir) {
    reg32_t mask = (1UL << pin);
    if (dir == GPIO_DIR_INPUT)
        reg_set32(dev->base + GPIO_OE, mask);      /* 1 = input */
    else
        reg_clr32(dev->base + GPIO_OE, mask);      /* 0 = output */
}

void gpio_set_output(gpio_dev_t *dev, uint8_t pin) {
    gpio_set_dir(dev, pin, GPIO_DIR_OUTPUT);
}

void gpio_set_input(gpio_dev_t *dev, uint8_t pin) {
    gpio_set_dir(dev, pin, GPIO_DIR_INPUT);
}

void gpio_write(gpio_dev_t *dev, uint8_t pin, int value) {
    reg32_t mask = (1UL << pin);
    if (value)
        reg_write32(dev->base + GPIO_SETDATAOUT, mask);
    else
        reg_write32(dev->base + GPIO_CLEARDATAOUT, mask);
}

int gpio_read(gpio_dev_t *dev, uint8_t pin) {
    return (reg_read32(dev->base + GPIO_DATAIN) >> pin) & 1;
}

void gpio_toggle(gpio_dev_t *dev, uint8_t pin) {
    int val = gpio_read(dev, pin);
    gpio_write(dev, pin, !val);
}

void gpio_set_irq_edge(gpio_dev_t *dev, uint8_t pin, gpio_irq_edge_t edge) {
    reg32_t mask = (1UL << pin);

    /* Clear all edge/level detection for this pin first */
    reg_clr32(dev->base + GPIO_LEVELDETECT0, mask);
    reg_clr32(dev->base + GPIO_LEVELDETECT1, mask);
    reg_clr32(dev->base + GPIO_RISINGDETECT, mask);
    reg_clr32(dev->base + GPIO_FALLINGDETECT, mask);

    switch (edge) {
        case GPIO_IRQ_EDGE_RISING:
            reg_set32(dev->base + GPIO_RISINGDETECT, mask);
            break;
        case GPIO_IRQ_EDGE_FALLING:
            reg_set32(dev->base + GPIO_FALLINGDETECT, mask);
            break;
        case GPIO_IRQ_EDGE_BOTH:
            reg_set32(dev->base + GPIO_RISINGDETECT, mask);
            reg_set32(dev->base + GPIO_FALLINGDETECT, mask);
            break;
        case GPIO_IRQ_LEVEL_HIGH:
            reg_set32(dev->base + GPIO_LEVELDETECT0, mask);
            break;
        case GPIO_IRQ_LEVEL_LOW:
            reg_set32(dev->base + GPIO_LEVELDETECT1, mask);
            break;
        default:
            break;
    }

    /* Enable IRQ for this pin */
    if (edge != GPIO_IRQ_EDGE_NONE)
        reg_set32(dev->base + GPIO_IRQENABLE1, mask);
}

void gpio_clear_irq(gpio_dev_t *dev, uint8_t pin) {
    reg_write32(dev->base + GPIO_IRQSTATUS1, (1UL << pin));
}

uint32_t gpio_get_irq_status(gpio_dev_t *dev) {
    return reg_read32(dev->base + GPIO_IRQSTATUS1);
}