summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c')
-rw-r--r--c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c b/c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c
new file mode 100644
index 0000000000..bd37e67765
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/gpio/rpi-gpio.c
@@ -0,0 +1,329 @@
+/**
+ * @file rpi-gpio.c
+ *
+ * @ingroup raspberrypi_gpio
+ *
+ * @brief Support for the Raspberry PI GPIO.
+ */
+
+/*
+ * Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at gmail.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp/raspberrypi.h>
+#include <bsp/irq-generic.h>
+#include <bsp/gpio.h>
+#include <bsp/rpi-gpio.h>
+
+#include <stdlib.h>
+
+/* Calculates a bitmask to assign an alternate function to a given pin. */
+#define SELECT_PIN_FUNCTION(fn, pn) (fn << ((pn % 10) * 3))
+
+rtems_gpio_specific_data alt_func_def[] = {
+ {.io_function = RPI_ALT_FUNC_0, .pin_data = NULL},
+ {.io_function = RPI_ALT_FUNC_1, .pin_data = NULL},
+ {.io_function = RPI_ALT_FUNC_2, .pin_data = NULL},
+ {.io_function = RPI_ALT_FUNC_3, .pin_data = NULL},
+ {.io_function = RPI_ALT_FUNC_4, .pin_data = NULL},
+ {.io_function = RPI_ALT_FUNC_5, .pin_data = NULL}
+};
+
+/* Raspberry Pi 1 Revision 2 gpio interface definitions. */
+#include "gpio-interfaces-pi1-rev2.c"
+
+/* Waits a number of CPU cycles. */
+static void arm_delay(uint8_t cycles)
+{
+ uint8_t i;
+
+ for ( i = 0; i < cycles; ++i ) {
+ asm volatile("nop");
+ }
+}
+
+static rtems_status_code rpi_select_pin_function(
+ uint32_t bank,
+ uint32_t pin,
+ uint32_t type
+) {
+ /* Calculate the pin function select register address. */
+ volatile unsigned int *pin_addr = (unsigned int *) BCM2835_GPIO_REGS_BASE +
+ (pin / 10);
+
+ if ( type == RPI_DIGITAL_IN ) {
+ *(pin_addr) &= ~SELECT_PIN_FUNCTION(RPI_DIGITAL_IN, pin);
+ }
+ else {
+ *(pin_addr) |= SELECT_PIN_FUNCTION(type, pin);
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rtems_gpio_bsp_multi_set(uint32_t bank, uint32_t bitmask)
+{
+ BCM2835_REG(BCM2835_GPIO_GPSET0) = bitmask;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rtems_gpio_bsp_multi_clear(uint32_t bank, uint32_t bitmask)
+{
+ BCM2835_REG(BCM2835_GPIO_GPCLR0) = bitmask;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+uint32_t rtems_gpio_bsp_multi_read(uint32_t bank, uint32_t bitmask)
+{
+ return (BCM2835_REG(BCM2835_GPIO_GPLEV0) & bitmask);
+}
+
+rtems_status_code rtems_gpio_bsp_set(uint32_t bank, uint32_t pin)
+{
+ BCM2835_REG(BCM2835_GPIO_GPSET0) = (1 << pin);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rtems_gpio_bsp_clear(uint32_t bank, uint32_t pin)
+{
+ BCM2835_REG(BCM2835_GPIO_GPCLR0) = (1 << pin);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+uint8_t rtems_gpio_bsp_get_value(uint32_t bank, uint32_t pin)
+{
+ return (BCM2835_REG(BCM2835_GPIO_GPLEV0) & (1 << pin));
+}
+
+rtems_status_code rtems_gpio_bsp_select_input(
+ uint32_t bank,
+ uint32_t pin,
+ void *bsp_specific
+) {
+ return rpi_select_pin_function(bank, pin, RPI_DIGITAL_IN);
+}
+
+rtems_status_code rtems_gpio_bsp_select_output(
+ uint32_t bank,
+ uint32_t pin,
+ void *bsp_specific
+) {
+ return rpi_select_pin_function(bank, pin, RPI_DIGITAL_OUT);
+}
+
+rtems_status_code rtems_bsp_select_specific_io(
+ uint32_t bank,
+ uint32_t pin,
+ uint32_t function,
+ void *pin_data
+) {
+ return rpi_select_pin_function(bank, pin, function);
+}
+
+rtems_status_code rtems_gpio_bsp_set_resistor_mode(
+ uint32_t bank,
+ uint32_t pin,
+ rtems_gpio_pull_mode mode
+) {
+ /* Set control signal. */
+ switch ( mode ) {
+ case PULL_UP:
+ BCM2835_REG(BCM2835_GPIO_GPPUD) = (1 << 1);
+ break;
+ case PULL_DOWN:
+ BCM2835_REG(BCM2835_GPIO_GPPUD) = (1 << 0);
+ break;
+ case NO_PULL_RESISTOR:
+ BCM2835_REG(BCM2835_GPIO_GPPUD) = 0;
+ break;
+ default:
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* Wait 150 cyles, as per BCM2835 documentation. */
+ arm_delay(150);
+
+ /* Setup clock for the control signal. */
+ BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = (1 << pin);
+
+ arm_delay(150);
+
+ /* Remove the control signal. */
+ BCM2835_REG(BCM2835_GPIO_GPPUD) = 0;
+
+ /* Remove the clock. */
+ BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_vector_number rtems_gpio_bsp_get_vector(uint32_t bank)
+{
+ return BCM2835_IRQ_ID_GPIO_0;
+}
+
+uint32_t rtems_gpio_bsp_interrupt_line(rtems_vector_number vector)
+{
+ uint32_t event_status;
+
+ /* Retrieve the interrupt event status. */
+ event_status = BCM2835_REG(BCM2835_GPIO_GPEDS0);
+
+ /* Clear the interrupt line. */
+ BCM2835_REG(BCM2835_GPIO_GPEDS0) = event_status;
+
+ return event_status;
+}
+
+rtems_status_code rtems_bsp_enable_interrupt(
+ uint32_t bank,
+ uint32_t pin,
+ rtems_gpio_interrupt interrupt
+) {
+ switch ( interrupt ) {
+ case FALLING_EDGE:
+ /* Enables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) |= (1 << pin);
+ break;
+ case RISING_EDGE:
+ /* Enables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) |= (1 << pin);
+ break;
+ case BOTH_EDGES:
+ /* Enables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) |= (1 << pin);
+
+ /* Enables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) |= (1 << pin);
+ break;
+ case LOW_LEVEL:
+ /* Enables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) |= (1 << pin);
+ break;
+ case HIGH_LEVEL:
+ /* Enables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) |= (1 << pin);
+ break;
+ case BOTH_LEVELS:
+ /* Enables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) |= (1 << pin);
+
+ /* Enables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) |= (1 << pin);
+ break;
+ case NONE:
+ default:
+ return RTEMS_UNSATISFIED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rtems_bsp_disable_interrupt(
+ uint32_t bank,
+ uint32_t pin,
+ rtems_gpio_interrupt interrupt
+) {
+ switch ( interrupt ) {
+ case FALLING_EDGE:
+ /* Disables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) &= ~(1 << pin);
+ break;
+ case RISING_EDGE:
+ /* Disables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) &= ~(1 << pin);
+ break;
+ case BOTH_EDGES:
+ /* Disables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) &= ~(1 << pin);
+
+ /* Disables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) &= ~(1 << pin);
+ break;
+ case LOW_LEVEL:
+ /* Disables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) &= ~(1 << pin);
+ break;
+ case HIGH_LEVEL:
+ /* Disables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) &= ~(1 << pin);
+ break;
+ case BOTH_LEVELS:
+ /* Disables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) &= ~(1 << pin);
+
+ /* Disables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) &= ~(1 << pin);
+ break;
+ case NONE:
+ default:
+ return RTEMS_UNSATISFIED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rpi_gpio_select_jtag(void)
+{
+ return rtems_gpio_multi_select(jtag_config, JTAG_PIN_COUNT);
+}
+
+rtems_status_code rpi_gpio_select_spi(void)
+{
+ return rtems_gpio_multi_select(spi_config, SPI_PIN_COUNT);
+}
+
+rtems_status_code rpi_gpio_select_i2c(void)
+{
+ return rtems_gpio_multi_select(i2c_config, I2C_PIN_COUNT);
+}
+
+rtems_status_code rtems_gpio_bsp_multi_select(
+ rtems_gpio_multiple_pin_select *pins,
+ uint32_t pin_count,
+ uint32_t select_bank
+) {
+ uint32_t register_address;
+ uint32_t select_register;
+ uint8_t i;
+
+ register_address = BCM2835_GPIO_REGS_BASE + (select_bank * 0x04);
+
+ select_register = BCM2835_REG(register_address);
+
+ for ( i = 0; i < pin_count; ++i ) {
+ if ( pins[i].function == DIGITAL_INPUT ) {
+ select_register &=
+ ~SELECT_PIN_FUNCTION(RPI_DIGITAL_IN, pins[i].pin_number);
+ }
+ else if ( pins[i].function == DIGITAL_OUTPUT ) {
+ select_register |=
+ SELECT_PIN_FUNCTION(RPI_DIGITAL_OUT, pins[i].pin_number);
+ }
+ else { /* BSP_SPECIFIC function. */
+ select_register |=
+ SELECT_PIN_FUNCTION(pins[i].io_function, pins[i].pin_number);
+ }
+ }
+
+ BCM2835_REG(register_address) = select_register;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code rtems_gpio_bsp_specific_group_operation(
+ uint32_t bank,
+ uint32_t *pins,
+ uint32_t pin_count,
+ void *arg
+) {
+ return RTEMS_NOT_DEFINED;
+}