/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-07-29 zdzn first version */ #include "raspi.h" #include "drv_gpio.h" #ifdef BSP_USING_PIN /* * 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]; void gpio_set_pud(rt_uint8_t pin, rt_uint8_t pud) { 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; } 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; data = IRQ_DISABLE2; data |= (0x1 << (irq - 32)); IRQ_DISABLE2 = data; } void gpio_irq_disable(rt_uint8_t index, bcm_gpio_pin pin) { int irq = 0; rt_uint32_t reg_value; rt_uint8_t irq_type; irq = IRQ_GPIO0 + index; 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; switch (irq_type) { 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; } } void gpio_irq_enable(rt_uint8_t index, bcm_gpio_pin pin) { rt_uint32_t offset; rt_uint32_t data; offset = pin; if (index == 0) offset = IRQ_GPIO0 - 32; else if (index == 1) offset = IRQ_GPIO1 - 32; else offset = IRQ_GPIO2 - 32; data = IRQ_ENABLE2; data |= 0x1 << offset; IRQ_ENABLE2 = data; } static void raspi_pin_mode(struct rt_device *dev, rt_base_t pin, rt_uint8_t mode) { RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); RT_ASSERT(!(mode & 0x8)); switch (mode) { case PIN_MODE_OUTPUT: GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP); break; case PIN_MODE_INPUT: GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); break; case PIN_MODE_INPUT_PULLUP: gpio_set_pud(pin, BCM283X_GPIO_PUD_UP); GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); break; case PIN_MODE_INPUT_PULLDOWN: gpio_set_pud(pin, BCM283X_GPIO_PUD_DOWN); GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); break; case PIN_MODE_OUTPUT_OD: gpio_set_pud(pin, BCM283X_GPIO_PUD_OFF); GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP); break; } } static void raspi_pin_write(struct rt_device *dev, rt_base_t pin, rt_uint8_t value) { 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 BCM283X_GPIO_GPCLR(pin / 32) |= (1 << (pin %32)); } static rt_int8_t raspi_pin_read(struct rt_device *device, rt_base_t pin) { 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_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) { RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); rt_uint8_t index; rt_uint32_t reg_value; if (pin <= 27) index = 0; else if (pin <= 45) index = 1; else index = 2; _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; rt_uint8_t shift = pin % 32; rt_uint32_t mask = 1 << shift; switch (mode) { case PIN_IRQ_MODE_RISING: reg_value = BCM283X_GPIO_GPREN(pin /32); BCM283X_GPIO_GPREN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); break; case PIN_IRQ_MODE_FALLING: reg_value = BCM283X_GPIO_GPFEN(pin /32); BCM283X_GPIO_GPFEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); break; 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); break; case PIN_IRQ_MODE_HIGH_LEVEL: reg_value = BCM283X_GPIO_GPHEN(pin /32); BCM283X_GPIO_GPHEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); break; case PIN_IRQ_MODE_LOW_LEVEL: reg_value = BCM283X_GPIO_GPLEN(pin /32); BCM283X_GPIO_GPLEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); break; } return RT_EOK; } static rt_err_t raspi_pin_detach_irq(struct rt_device *device, rt_base_t pin) { RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); rt_uint8_t index; if (pin <= 27) index = 0; else if (pin <= 45) index = 1; else index = 2; gpio_irq_disable(index, pin); _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; return RT_EOK; } rt_err_t raspi_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) { RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); rt_uint8_t index; if (pin <= 27) index = 0; else if (pin <= 45) index = 1; else index = 2; if (enabled) gpio_irq_enable(index, pin); else gpio_irq_disable(index, pin); return RT_EOK; } 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 */ value = BCM283X_GPIO_GPEDS(0); value &= 0x0fffffff; pin = 0; BCM283X_GPIO_GPEDS(0) = 0; } else if (irq == IRQ_GPIO1) { /* 28-45 */ tmpvalue = BCM283X_GPIO_GPEDS(0); tmpvalue &= (~0x0fffffff); value = BCM283X_GPIO_GPEDS(1); value &= 0x3fff; value = (value<<4) | tmpvalue; pin = 28; BCM283X_GPIO_GPEDS(0) = 0; BCM283X_GPIO_GPEDS(1) = 0; } else if (irq == IRQ_GPIO2) { /* 46-53 */ value = BCM283X_GPIO_GPEDS(1); value &= (~0x3fff); value &= 0xff600000; pin = 46; BCM283X_GPIO_GPEDS(1) = 0; } 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 = { raspi_pin_mode, raspi_pin_write, raspi_pin_read, raspi_pin_attach_irq, raspi_pin_detach_irq, raspi_pin_irq_enable, RT_NULL, }; #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); #endif return 0; } INIT_DEVICE_EXPORT(rt_hw_gpio_init);