drv_gpio.c 8.4 KB
Newer Older
B
bigmagic 已提交
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
B
bigmagic 已提交
3 4 5 6 7 8 9 10 11 12 13
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author         Notes
 * 2019-07-29     zdzn           first version
 */
#include "raspi.h"
#include "drv_gpio.h"


B
bigmagic 已提交
14
#ifdef BSP_USING_PIN
B
bigmagic 已提交
15 16 17 18 19 20 21
/*
 * gpio_int[0] for BANK0 (pins 0-27)
 * gpio_int[1] for BANK1 (pins 28-45)
 * gpio_int[2] for BANK2 (pins 46-53)
 */
static struct gpio_irq_def _g_gpio_irq_tbl[GPIO_IRQ_NUM];

B
bigmagic 已提交
22
void gpio_set_pud(rt_uint8_t pin, rt_uint8_t pud)
B
bigmagic 已提交
23
{
B
bigmagic 已提交
24 25 26 27 28 29 30 31 32
    rt_uint8_t num = pin / 32;
    rt_uint8_t shift = pin % 32;
    BCM283X_GPIO_GPPUD = pud;
    DELAY_MICROS(10);
    BCM283X_GPIO_GPPUDCLK(num) = 1 << shift;
    DELAY_MICROS(10);
    BCM283X_GPIO_GPPUD = BCM283X_GPIO_PUD_OFF;
    BCM283X_GPIO_GPPUDCLK(num) = 0 << shift;
}
B
bigmagic 已提交
33

B
bigmagic 已提交
34 35 36 37 38 39
static void gpio_ack_irq(int irq, bcm_gpio_pin pin)
{
    rt_uint32_t data;
    data = IRQ_PEND2;
    data &= (0x0 << (irq - 32));
    IRQ_PEND2 = data;
B
bigmagic 已提交
40

B
bigmagic 已提交
41 42 43
    data = IRQ_DISABLE2;
    data |= (0x1 << (irq - 32));
    IRQ_DISABLE2 = data;
B
bigmagic 已提交
44 45
}

B
bigmagic 已提交
46
void gpio_irq_disable(rt_uint8_t index, bcm_gpio_pin pin)
B
bigmagic 已提交
47
{
B
bigmagic 已提交
48 49 50 51
    int irq = 0;
    rt_uint32_t  reg_value;
    rt_uint8_t irq_type;
    irq = IRQ_GPIO0 + index;
B
bigmagic 已提交
52

B
bigmagic 已提交
53 54 55 56 57
    gpio_ack_irq(irq, pin);

    irq_type = _g_gpio_irq_tbl[index].irq_type[pin];
    rt_uint8_t shift = pin % 32;
    rt_uint32_t mask = 1 << shift;
B
bigmagic 已提交
58

B
bigmagic 已提交
59
    switch (irq_type)
B
bigmagic 已提交
60
    {
B
bigmagic 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    case PIN_IRQ_MODE_RISING:
        reg_value = BCM283X_GPIO_GPREN(pin /32);
        BCM283X_GPIO_GPREN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        break;
    case PIN_IRQ_MODE_FALLING:
        reg_value = BCM283X_GPIO_GPFEN(pin /32);
        BCM283X_GPIO_GPFEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        break;
    case PIN_IRQ_MODE_RISING_FALLING:
        reg_value = BCM283X_GPIO_GPAREN(pin /32);
        BCM283X_GPIO_GPAREN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        reg_value = BCM283X_GPIO_GPAFEN(pin /32);
        BCM283X_GPIO_GPAFEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        break;
    case PIN_IRQ_MODE_HIGH_LEVEL:
        reg_value = BCM283X_GPIO_GPHEN(pin /32);
        BCM283X_GPIO_GPHEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        break;
    case PIN_IRQ_MODE_LOW_LEVEL:
        reg_value = BCM283X_GPIO_GPLEN(pin /32);
        BCM283X_GPIO_GPLEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask);
        break;
B
bigmagic 已提交
83 84 85
    }
}

B
bigmagic 已提交
86
void gpio_irq_enable(rt_uint8_t index, bcm_gpio_pin pin)
B
bigmagic 已提交
87
{
B
bigmagic 已提交
88 89
    rt_uint32_t offset;
    rt_uint32_t data;
B
bigmagic 已提交
90

B
bigmagic 已提交
91 92 93 94 95 96 97
    offset = pin;
    if (index == 0)
        offset = IRQ_GPIO0 - 32;
    else if (index == 1)
        offset = IRQ_GPIO1 - 32;
    else
        offset = IRQ_GPIO2 - 32;
B
bigmagic 已提交
98

B
bigmagic 已提交
99 100 101
    data = IRQ_ENABLE2;
    data |= 0x1 << offset;
    IRQ_ENABLE2 = data;
B
bigmagic 已提交
102 103 104

}

B
bigmagic 已提交
105
static void raspi_pin_mode(struct rt_device *dev, rt_base_t pin, rt_base_t mode)
B
bigmagic 已提交
106
{
B
bigmagic 已提交
107 108
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
    RT_ASSERT(!(mode & 0x8));
B
bigmagic 已提交
109

B
bigmagic 已提交
110
    switch (mode)
B
bigmagic 已提交
111
    {
B
bigmagic 已提交
112 113
    case PIN_MODE_OUTPUT:
        GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP);
B
bigmagic 已提交
114
        break;
B
bigmagic 已提交
115 116
    case PIN_MODE_INPUT:
        GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT);
B
bigmagic 已提交
117
        break;
B
bigmagic 已提交
118 119 120
    case PIN_MODE_INPUT_PULLUP:
        gpio_set_pud(pin, BCM283X_GPIO_PUD_UP);
        GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT);
B
bigmagic 已提交
121
        break;
B
bigmagic 已提交
122 123 124
    case PIN_MODE_INPUT_PULLDOWN:
        gpio_set_pud(pin, BCM283X_GPIO_PUD_DOWN);
        GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT);
B
bigmagic 已提交
125
        break;
B
bigmagic 已提交
126 127 128
    case PIN_MODE_OUTPUT_OD:
        gpio_set_pud(pin, BCM283X_GPIO_PUD_OFF);
        GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP);
B
bigmagic 已提交
129 130 131 132
        break;
    }
}

B
bigmagic 已提交
133
static void raspi_pin_write(struct rt_device *dev, rt_base_t pin, rt_base_t value)
B
bigmagic 已提交
134
{
B
bigmagic 已提交
135 136 137 138 139 140
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
    RT_ASSERT(!(value & 0xE));

    if (value)
        BCM283X_GPIO_GPSET(pin / 32) |= (1 << (pin %32));
    else
F
fanhuanji 已提交
141
        BCM283X_GPIO_GPCLR(pin / 32) |= (1 << (pin %32));
B
bigmagic 已提交
142 143 144

}

B
bigmagic 已提交
145
static int raspi_pin_read(struct rt_device *device, rt_base_t pin)
B
bigmagic 已提交
146
{
B
bigmagic 已提交
147 148 149 150 151 152 153
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
    return (BCM2835_GPIO_GPLEV(pin / 32) & (1 << (pin % 32)))? PIN_HIGH : PIN_LOW;
}

static rt_err_t raspi_pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
{
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
B
bigmagic 已提交
154

B
bigmagic 已提交
155 156
    rt_uint8_t index;
    rt_uint32_t  reg_value;
B
bigmagic 已提交
157 158
    if (pin <= 27)
        index = 0;
B
bigmagic 已提交
159
    else if (pin <= 45)
B
bigmagic 已提交
160
        index = 1;
B
bigmagic 已提交
161
    else
B
bigmagic 已提交
162
        index = 2;
B
bigmagic 已提交
163 164 165
    _g_gpio_irq_tbl[index].irq_cb[pin]    = hdr;
    _g_gpio_irq_tbl[index].irq_arg[pin]   = args;
    _g_gpio_irq_tbl[index].irq_type[pin]  = mode;
B
bigmagic 已提交
166

B
bigmagic 已提交
167 168
    rt_uint8_t shift = pin % 32;
    rt_uint32_t mask = 1 << shift;
B
bigmagic 已提交
169

B
bigmagic 已提交
170
    switch (mode)
B
bigmagic 已提交
171
    {
B
bigmagic 已提交
172 173 174
    case PIN_IRQ_MODE_RISING:
        reg_value = BCM283X_GPIO_GPREN(pin /32);
        BCM283X_GPIO_GPREN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
B
bigmagic 已提交
175
        break;
B
bigmagic 已提交
176 177 178
    case PIN_IRQ_MODE_FALLING:
        reg_value = BCM283X_GPIO_GPFEN(pin /32);
        BCM283X_GPIO_GPFEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
B
bigmagic 已提交
179
        break;
B
bigmagic 已提交
180 181 182 183 184
    case PIN_IRQ_MODE_RISING_FALLING:
        reg_value = BCM283X_GPIO_GPAREN(pin /32);
        BCM283X_GPIO_GPAREN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
        reg_value = BCM283X_GPIO_GPAFEN(pin /32);
        BCM283X_GPIO_GPAFEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
B
bigmagic 已提交
185
        break;
B
bigmagic 已提交
186 187 188
    case PIN_IRQ_MODE_HIGH_LEVEL:
        reg_value = BCM283X_GPIO_GPHEN(pin /32);
        BCM283X_GPIO_GPHEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
B
bigmagic 已提交
189
        break;
B
bigmagic 已提交
190 191 192
    case PIN_IRQ_MODE_LOW_LEVEL:
        reg_value = BCM283X_GPIO_GPLEN(pin /32);
        BCM283X_GPIO_GPLEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask);
B
bigmagic 已提交
193 194
        break;
    }
B
bigmagic 已提交
195
    return RT_EOK;
B
bigmagic 已提交
196 197
}

B
bigmagic 已提交
198
static rt_err_t raspi_pin_detach_irq(struct rt_device *device, rt_int32_t pin)
B
bigmagic 已提交
199
{
B
bigmagic 已提交
200
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
B
bigmagic 已提交
201

B
bigmagic 已提交
202
    rt_uint8_t index;
B
bigmagic 已提交
203 204 205 206 207 208
    if (pin <= 27)
        index = 0;
    else if (pin <= 45)
        index = 1;
    else
        index = 2;
B
bigmagic 已提交
209 210

    gpio_irq_disable(index, pin);
B
bigmagic 已提交
211 212 213 214 215

    _g_gpio_irq_tbl[index].irq_cb[pin]    = RT_NULL;
    _g_gpio_irq_tbl[index].irq_arg[pin]   = RT_NULL;
    _g_gpio_irq_tbl[index].irq_type[pin]  = RT_NULL;

B
bigmagic 已提交
216
    return RT_EOK;
B
bigmagic 已提交
217 218
}

B
bigmagic 已提交
219
rt_err_t raspi_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled)
B
bigmagic 已提交
220
{
B
bigmagic 已提交
221
    RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL));
B
bigmagic 已提交
222

B
bigmagic 已提交
223
    rt_uint8_t index;
B
bigmagic 已提交
224
    if (pin <= 27)
B
bigmagic 已提交
225
        index = 0;
B
bigmagic 已提交
226
    else if (pin <= 45)
B
bigmagic 已提交
227
        index = 1;
B
bigmagic 已提交
228
    else
B
bigmagic 已提交
229
        index = 2;
B
bigmagic 已提交
230

B
bigmagic 已提交
231 232 233 234
    if (enabled)
        gpio_irq_enable(index, pin);
    else
        gpio_irq_disable(index, pin);
B
bigmagic 已提交
235

B
bigmagic 已提交
236
    return RT_EOK;
B
bigmagic 已提交
237 238 239 240 241 242 243 244 245 246 247 248
}

static void gpio_irq_handler(int irq, void *param)
{
    struct gpio_irq_def *irq_def = (struct gpio_irq_def *)param;
    rt_uint32_t pin;
    rt_uint32_t value;
    rt_uint32_t tmpvalue;

    if (irq == IRQ_GPIO0)
    {
        /* 0~27 */
B
bigmagic 已提交
249 250

        value = BCM283X_GPIO_GPEDS(0);
B
bigmagic 已提交
251 252
        value &= 0x0fffffff;
        pin = 0;
B
bigmagic 已提交
253
        BCM283X_GPIO_GPEDS(0) = 0;
B
bigmagic 已提交
254 255 256 257
    }
    else if (irq == IRQ_GPIO1)
    {
        /* 28-45 */
B
bigmagic 已提交
258
        tmpvalue = BCM283X_GPIO_GPEDS(0);
B
bigmagic 已提交
259 260
        tmpvalue &= (~0x0fffffff);

B
bigmagic 已提交
261
        value = BCM283X_GPIO_GPEDS(1);
B
bigmagic 已提交
262 263 264
        value &= 0x3fff;
        value = (value<<4) | tmpvalue;
        pin = 28;
B
bigmagic 已提交
265 266
        BCM283X_GPIO_GPEDS(0) = 0;
        BCM283X_GPIO_GPEDS(1) = 0;
B
bigmagic 已提交
267 268 269 270
    }
    else if (irq == IRQ_GPIO2)
    {
        /* 46-53 */
B
bigmagic 已提交
271
        value = BCM283X_GPIO_GPEDS(1);
B
bigmagic 已提交
272 273 274
        value &= (~0x3fff);
        value &= 0xff600000;
        pin = 46;
B
bigmagic 已提交
275
        BCM283X_GPIO_GPEDS(1) = 0;
B
bigmagic 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    }

    while (value)
    {
        if ((value & 0x1) && (irq_def->irq_cb[pin] != RT_NULL))
        {
            irq_def->irq_cb[pin](irq_def->irq_arg[pin]);
            gpio_ack_irq(irq,pin);
        }
        pin++;
        value = value >> 1;
    }
}

static const struct rt_pin_ops ops =
{
B
bigmagic 已提交
292 293 294 295 296 297
    raspi_pin_mode,
    raspi_pin_write,
    raspi_pin_read,
    raspi_pin_attach_irq,
    raspi_pin_detach_irq,
    raspi_pin_irq_enable,
298
    RT_NULL,
B
bigmagic 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
};
#endif

int rt_hw_gpio_init(void)
{
#ifdef BSP_USING_PIN
    rt_device_pin_register("gpio", &ops, RT_NULL);

    /* install ISR */
    rt_hw_interrupt_install(IRQ_GPIO0, gpio_irq_handler, &_g_gpio_irq_tbl[0], "gpio0_irq");
    rt_hw_interrupt_umask(IRQ_GPIO0);

    rt_hw_interrupt_install(IRQ_GPIO1, gpio_irq_handler, &_g_gpio_irq_tbl[1], "gpio1_irq");
    rt_hw_interrupt_umask(IRQ_GPIO1);

    rt_hw_interrupt_install(IRQ_GPIO2, gpio_irq_handler, &_g_gpio_irq_tbl[2], "gpio2_irq");
    rt_hw_interrupt_umask(IRQ_GPIO2);
B
bigmagic 已提交
316
#endif
B
bigmagic 已提交
317 318 319 320

    return 0;
}
INIT_DEVICE_EXPORT(rt_hw_gpio_init);