[PATCH] Add GPIO, I2C and SPI support for the RPi BSP
Andre Marques
andre.lousa.marques at gmail.com
Wed Dec 10 10:14:28 UTC 2014
This patch addresses gedare's comments regardig coding conventions and a few other issues.
As to Pavel's concerns on the interrupt handling I currently lack the time to address them properly, but when possible I and possibly Alan will have a look at that and on the new I2C framework.
---
c/src/lib/libbsp/arm/raspberrypi/Makefile.am | 11 +-
c/src/lib/libbsp/arm/raspberrypi/configure.ac | 12 +
c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c | 727 +++++++++++++++++++++
c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c | 480 ++++++++++++++
c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c | 84 +++
c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c | 608 +++++++++++++++++
c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c | 85 +++
c/src/lib/libbsp/arm/raspberrypi/include/gpio.h | 210 ++++++
c/src/lib/libbsp/arm/raspberrypi/include/i2c.h | 183 ++++++
c/src/lib/libbsp/arm/raspberrypi/include/irq.h | 6 +-
.../libbsp/arm/raspberrypi/include/raspberrypi.h | 79 ++-
c/src/lib/libbsp/arm/raspberrypi/irq/irq.c | 103 ++-
c/src/lib/libbsp/arm/raspberrypi/preinstall.am | 8 +
.../lib/libbsp/arm/raspberrypi/startup/bspstart.c | 17 +-
14 files changed, 2591 insertions(+), 22 deletions(-)
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
create mode 100644 c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
diff --git a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
index ed134fa..9363bc4 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
+++ b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am
@@ -44,6 +44,8 @@ include_bsp_HEADERS += include/irq.h
include_bsp_HEADERS += include/mmu.h
include_bsp_HEADERS += include/usart.h
include_bsp_HEADERS += include/raspberrypi.h
+include_bsp_HEADERS += include/gpio.h
+include_bsp_HEADERS += include/i2c.h
include_libcpu_HEADERS = ../../../libcpu/arm/shared/include/cache_.h \
../../../libcpu/arm/shared/include/arm-cp15.h
@@ -79,7 +81,6 @@ libbsp_a_SOURCES += ../../shared/bspclean.c
libbsp_a_SOURCES += ../../shared/bspgetworkarea.c
libbsp_a_SOURCES += ../../shared/bsplibc.c
libbsp_a_SOURCES += ../../shared/bsppost.c
-libbsp_a_SOURCES += ../../shared/bsppredriverhook.c
libbsp_a_SOURCES += ../../shared/bsppretaskinghook.c
libbsp_a_SOURCES += ../../shared/cpucounterread.c
libbsp_a_SOURCES += ../../shared/cpucounterdiff.c
@@ -118,11 +119,19 @@ libbsp_a_SOURCES += clock/clockdrv.c ../../../shared/clockdrv_shell.h
# Timer
libbsp_a_SOURCES += misc/timer.c
+# GPIO
+
+libbsp_a_SOURCES += gpio/gpio.c
+
# RTC
# SSP
# I2C
+libbsp_a_SOURCES += i2c/i2c.c
+libbsp_a_SOURCES += i2c/i2c_init.c
+libbsp_a_SOURCES += i2c/spi.c
+libbsp_a_SOURCES += i2c/spi_init.c
# Cache
libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
diff --git a/c/src/lib/libbsp/arm/raspberrypi/configure.ac b/c/src/lib/libbsp/arm/raspberrypi/configure.ac
index 9bd6883..92fa903 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/configure.ac
+++ b/c/src/lib/libbsp/arm/raspberrypi/configure.ac
@@ -24,6 +24,18 @@ AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
RTEMS_BSPOPTS_SET([BSP_START_RESET_VECTOR],[*],[])
RTEMS_BSPOPTS_HELP([BSP_START_RESET_VECTOR],[reset vector address for BSP start])
+RTEMS_BSPOPTS_SET([I2C_IO_MODE],[*],[1])
+RTEMS_BSPOPTS_HELP([I2C_IO_MODE],[Define to 1 to use interrupt-driven I/O with the Raspberry Pi I2C bus. If defined to other value the access will be polled-driven.])
+
+RTEMS_BSPOPTS_SET([SPI_IO_MODE],[*],[1])
+RTEMS_BSPOPTS_HELP([SPI_IO_MODE],[Define to 1 to use interrupt-driven I/O with the Raspberry Pi SPI bus. If defined to other value the access will be polled-driven.])
+
+RTEMS_BSPOPTS_SET([BSP_ENABLE_SPI],[*],[0])
+RTEMS_BSPOPTS_HELP([BSP_ENABLE_SPI],[Define to 1 to use the SPI bus. This will register the bus in /dev/spi and also any device driver mentioned in i2c/spi_init.c .])
+
+RTEMS_BSPOPTS_SET([BSP_ENABLE_I2C],[*],[0])
+RTEMS_BSPOPTS_HELP([BSP_ENABLE_I2C],[Define to 1 to use the I2C bus. This will register the bus in /dev/i2c and also any device driver mentioned in i2c/i2c_init.c .])
+
RTEMS_BSP_CLEANUP_OPTIONS(0, 0)
RTEMS_BSP_LINKCMDS
diff --git a/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
new file mode 100644
index 0000000..40ac3b0
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
@@ -0,0 +1,727 @@
+/**
+ * @file gpio.c
+ *
+ * @ingroup raspberrypi_gpio
+ *
+ * @brief Support for the Raspberry PI GPIO.
+ */
+
+/*
+ * Copyright (c) 2014 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.h>
+#include <bsp/gpio.h>
+#include <assert.h>
+
+/* Calculates a bitmask to assign an alternate function to a given pin. */
+#define SELECT_PIN_FUNCTION(fn, pn) (fn << ((pn % 10) * 3))
+
+static bool is_initialized = false;
+
+rpi_gpio_pin gpio_pin[GPIO_PIN_COUNT];
+
+/**
+ * @brief Waits a number of CPU cycles.
+ *
+ * @param[in] cycles The number of CPU cycles to wait.
+ *
+ */
+static void arm_delay (int cycles)
+{
+ int i;
+
+ for ( i = 0; i < cycles; i++ ) {
+ asm volatile ("nop");
+ }
+}
+
+/**
+ * @brief Initializes the GPIO API and sets every pin as NOT_USED.
+ * If the API has already been initialized silently exits.
+ */
+void gpio_initialize(void)
+{
+ int i;
+
+ if ( is_initialized ) {
+ return;
+ }
+
+ is_initialized = true;
+
+ for ( i = 0; i < GPIO_PIN_COUNT; i++ ) {
+ gpio_pin[i].pin_type = NOT_USED;
+ gpio_pin[i].enabled_interrupt = NONE;
+
+ gpio_pin[i].h_args.debouncing_tick_count = 0;
+ }
+}
+
+/**
+ * @brief Gives an output GPIO pin the logical value of 1.
+ *
+ * @param[in] pin The Raspberry Pi GPIO pin label number (not is position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL Pin was set successfully.
+ * @retval RTEMS_NOT_CONFIGURED The received pin is not configured
+ * as an digital output.
+ */
+rtems_status_code gpio_set(int pin)
+{
+ assert( pin >= 0 && pin < GPIO_PIN_COUNT );
+
+ if ( gpio_pin[pin - 1].pin_type != DIGITAL_OUTPUT ) {
+ return RTEMS_NOT_CONFIGURED;
+ }
+
+ BCM2835_REG(BCM2835_GPIO_GPSET0) = (1 << pin);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Gives an output GPIO pin the logical value of 0.
+ *
+ * @param[in] pin The Raspberry Pi GPIO pin label number (not is position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL Pin was cleared successfully.
+ * @retval RTEMS_NOT_CONFIGURED The received pin is not configured
+ * as an digital output.
+ */
+rtems_status_code gpio_clear(int pin)
+{
+ assert( pin >= 0 && pin < GPIO_PIN_COUNT );
+
+ if ( gpio_pin[pin - 1].pin_type != DIGITAL_OUTPUT ) {
+ return RTEMS_NOT_CONFIGURED;
+ }
+
+ BCM2835_REG(BCM2835_GPIO_GPCLR0) = (1 << pin);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Gets the value (level) of a GPIO input pin.
+ *
+ * @param[in] pin The Raspberry Pi GPIO pin label number (not is position
+ * on the header).
+ *
+ * @retval The function returns 0 or 1 depending on the pin current
+ * logical value.
+ */
+int gpio_get_value(int pin)
+{
+ assert( pin >= 0 && pin < GPIO_PIN_COUNT );
+
+ return (BCM2835_REG(BCM2835_GPIO_GPLEV0) & (1 << pin));
+}
+
+/**
+ * @brief Configures a GPIO pin to perform a certain function.
+ *
+ * @param[in] pin The Raspberry Pi GPIO pin label number (not is position
+ * on the header).
+ * @param[in] type The new function of the pin.
+ *
+ * @retval RTEMS_SUCCESSFUL Pin was configured successfully.
+ * @retval RTEMS_RESOURCE_IN_USE The received pin is already being used.
+ */
+rtems_status_code gpio_select_pin(int pin, rpi_pin type)
+{
+ assert( pin >= 0 && pin < GPIO_PIN_COUNT );
+
+ /* Calculate the pin function select register address. */
+ volatile unsigned int *pin_addr = (unsigned int *)BCM2835_GPIO_REGS_BASE +
+ (pin / 10);
+
+ /* If the pin is already being used returns with an error. */
+ if ( gpio_pin[pin - 1].pin_type != NOT_USED ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Sets pin function select bits.*/
+ if ( type == DIGITAL_INPUT ) {
+ *(pin_addr) &= ~SELECT_PIN_FUNCTION(7, pin);
+ }
+ else {
+ *(pin_addr) |= SELECT_PIN_FUNCTION(type, pin);
+ }
+
+ /* If the alternate function was successfuly assigned to the pin,
+ * record that information on the gpio_pin structure. */
+ gpio_pin[pin - 1].pin_type = type;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Configures the pull resistor setting of an array of GPIO pins.
+ *
+ * @param[in] pins Array of Raspberry Pi GPIO pin label numbers (not their
+ * position on the header).
+ * @param[in] pin_count Number of pins on the @var pins array.
+ * @param[in] mode The pull resistor mode.
+ *
+ * @retval RTEMS_SUCCESSFUL Pull resistor successfully configured.
+ * @retval RTEMS_NOT_DEFINED Unknown pull resistor mode.
+ */
+static rtems_status_code
+set_input_mode(int *pins, int pin_count, int pin_mask, rpi_gpio_input_mode mode)
+{
+ int i;
+
+ /* 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_NOT_DEFINED;
+ }
+
+ /* Wait 150 cyles, as per BCM2835 documentation. */
+ arm_delay(150);
+
+ /* Setup clock for the control signal. */
+ BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = pin_mask;
+
+ arm_delay(150);
+
+ /* Remove the control signal. */
+ BCM2835_REG(BCM2835_GPIO_GPPUD) = 0;
+
+ /* Remove the clock. */
+ BCM2835_REG(BCM2835_GPIO_GPPUDCLK0) = 0;
+
+ /* If the operation was successful, record that information
+ * on the gpio_pin structure so it can be recalled later. */
+ for ( i = 0; i < pin_count; i++ ) {
+ gpio_pin[pins[i] - 1].input_mode = mode;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Configures a single GPIO pin pull resistor.
+ *
+ * @param[in] pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ * @param[in] mode The pull resistor mode.
+ *
+ * @retval RTEMS_SUCCESSFUL Pull resistor successfully configured.
+ * @retval RTEMS_NOT_DEFINED @see set_input_mode().
+ */
+rtems_status_code gpio_input_mode(int pin, rpi_gpio_input_mode mode)
+{
+ assert( pin >= 0 && pin < GPIO_PIN_COUNT );
+
+ int pin_mask = (1 << pin);
+ int pins[1];
+
+ /* If the desired actuation mode is already set, silently exits. */
+ if ( gpio_pin[pin - 1].input_mode == mode ) {
+ return RTEMS_SUCCESSFUL;
+ }
+
+ pins[0] = pin;
+
+ return set_input_mode(pins, 1, pin_mask, mode);
+}
+
+/**
+ * @brief Sets the same pull-up/down resistors actuation mode to multiple GPIO
+ * input pins. There is a maximum number of 32 pins per call,
+ * which is enough for Raspberry Pi models A and B (17 GPIOs on
+ * P1 GPIO header) and also model B+ (28 GPIOs on J8 GPIO header).
+ *
+ * @param[in] pins Array of Raspberry Pi GPIO pin label numbers
+ * (not their position on the header).
+ * @param[in] pin_count Number of pins on the @var pins array.
+ * @param[in] mode The pull resistor mode.
+ *
+ * @retval RTEMS_SUCCESSFUL Pull resistor successfully configured.
+ * @retval RTEMS_INVALID_ID Unknown pull resistor mode.
+ */
+rtems_status_code
+gpio_setup_input_mode(int *pins, int pin_count, rpi_gpio_input_mode mode)
+{
+ uint32_t pin_mask = 0;
+ int diff_mode_counter = 0;
+ int i;
+
+ if ( pin_count > GPIO_EXTERNAL_TOP_PIN ) {
+ return RTEMS_INVALID_ID;
+ }
+
+ /* Cycle through the given pins to check if this operation will have an effect
+ * on the resistor actuation mode of any one of the pins.
+ * Every pin that currently uses a different pull resistor mode sets a bit
+ * in its corresponding place on a bitmask. If the mode for a pin will not
+ * change then the diff_mode_counter variable is increased. */
+ for ( i = 0; i < pin_count; i++ ) {
+ assert( pins[i] >= 0 && pins[i] < GPIO_PIN_COUNT );
+
+ if ( gpio_pin[pins[i] - 1].input_mode != mode ) {
+ pin_mask |= (1 << pins[i]);
+ }
+ else {
+ ++diff_mode_counter;
+ }
+ }
+
+ /* If no pin will have its resistor mode changed silently exits, avoiding an
+ * unnecessary access to the Rasberry Pi memory registers. */
+ if ( diff_mode_counter == 0 ) {
+ return RTEMS_SUCCESSFUL;
+ }
+
+ return set_input_mode(pins, pin_count, pin_mask, mode);
+}
+
+/**
+ * @brief Disables a GPIO pin on the APiI, making it available to be used
+ * by anyone on the system.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL Pin successfully disabled on the API.
+ * @retval RTEMS_UNSATISFIED Could not disable an ative interrupt on this pin,
+ * @see gpio_disable_interrupt(),
+ */
+rtems_status_code gpio_disable_pin(int dev_pin)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rpi_gpio_pin *pin;
+
+ assert( dev_pin >= 1 && dev_pin <= GPIO_PIN_COUNT );
+
+ pin = &gpio_pin[dev_pin - 1];
+
+ pin->pin_type = NOT_USED;
+
+ /* If the pin has an enabled interrupt then remove the handler. */
+ if ( pin->enabled_interrupt != NONE ) {
+ sc = gpio_disable_interrupt(dev_pin);
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Setups a JTAG interface using the P1 GPIO pin header
+ * for the models A/B and J8 header on the B+.
+ * The following pins should be unused before calling this function:
+ * GPIO 4, 22, 24, 25 and 27.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL JTAG interface successfully configured.
+ * @retval RTEMS_RESOURCE_IN_USE At least one of the required pins is currently
+ * occupied, @see gpio_select_pin().
+ */
+rtems_status_code gpio_select_jtag(void)
+{
+ rtems_status_code sc;
+
+ /* Setup gpio 4 alt5 ARM_TDI. */
+ if ( (sc = gpio_select_pin(4, ALT_FUNC_5)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Setup gpio 22 alt4 ARM_TRST. */
+ if ( (sc = gpio_select_pin(22, ALT_FUNC_4)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Setup gpio 24 alt4 ARM_TDO. */
+ if ( (sc = gpio_select_pin(24, ALT_FUNC_4)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Setup gpio 25 alt4 ARM_TCK. */
+ if ( (sc = gpio_select_pin(25, ALT_FUNC_4)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Setup gpio 27 alt4 ARM_TMS. */
+ if ( (sc = gpio_select_pin(27, ALT_FUNC_4)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Setups a SPI interface using the P1 GPIO pin header
+ * for the models A/B and J8 header on the B+.
+ * The following pins should be unused before calling this function:
+ * GPIO 7, 8, 9, 10 and 11.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL SPI interface successfully configured.
+ * @retval RTEMS_RESOURCE_IN_USE At least one of the required pins is currently
+ * occupied, @see gpio_select_pin().
+ */
+rtems_status_code gpio_select_spi_p1(void)
+{
+ rtems_status_code sc;
+
+ /* SPI master 0 MISO data line. */
+ if ( (sc = gpio_select_pin(9, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* SPI master 0 MOSI data line. */
+ if ( (sc = gpio_select_pin(10, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* SPI master 0 SCLK clock line. */
+ if ( (sc = gpio_select_pin(11, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* SPI master 0 CE_0 chip enable line. */
+ if ( (sc = gpio_select_pin(8, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* SPI master 0 CE_1 chip enable line. */
+ if ( (sc = gpio_select_pin(7, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Setups a I2C interface using the P1 GPIO pin header
+ * for the models A/B and J8 header on the B+.
+ * The following pins should be unused before calling this function:
+ * GPIO 2 and 3.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL JTAG interface successfully configured.
+ * @retval RTEMS_RESOURCE_IN_USE At least one of the required pins is currently
+ * occupied, @see gpio_select_pin().
+ */
+rtems_status_code gpio_select_i2c_p1_rev2(void)
+{
+ rtems_status_code sc;
+ int pins[] = {2,3};
+
+ /* I2C BSC1 SDA data line. */
+ if ( (sc = gpio_select_pin(2, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* I2C BSC1 SCL clock line. */
+ if ( (sc = gpio_select_pin(3, ALT_FUNC_0)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Enable pins 2 and 3 pull-up resistors. */
+ if ( (sc = gpio_setup_input_mode(pins, 2, PULL_UP)) != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief De-bounces a switch by requiring a certain time to pass between
+ * interrupts. Any interrupt fired too close to the last will be
+ * ignored as it is probably the result of a involuntary switch/button
+ * bounce after being released.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval 0 Interrupt is likely provoked by a user press on the switch.
+ * @retval -1 Interrupt was generated too close to the last one.
+ * Probably a switch bounce.
+ */
+static int debounce_switch(int dev_pin)
+{
+ rtems_interval time;
+ rpi_gpio_pin *pin;
+
+ assert( dev_pin >= 1 && dev_pin <= GPIO_PIN_COUNT );
+
+ pin = &gpio_pin[dev_pin - 1];
+
+ time = rtems_clock_get_ticks_since_boot();
+
+ if ( (time - pin->h_args.last_isr_tick) < pin->h_args.debouncing_tick_count ) {
+ return -1;
+ }
+
+ pin->h_args.last_isr_tick = time;
+
+ return 0;
+}
+
+/**
+ * @brief Generic ISR that clears the event register on the Raspberry Pi and
+ * calls an user defined ISR.
+ *
+ * @param[in] arg Void pointer to a handler_arguments structure.
+ */
+static void generic_handler(void* arg)
+{
+ handler_arguments* handler_args;
+ int rv = 0;
+ int pin = 0;
+
+ handler_args = (handler_arguments*) arg;
+
+ pin = handler_args->pin_number;
+
+ /* If the interrupt was generated by the pin attached to this ISR clear it. */
+ if ( BCM2835_REG(BCM2835_GPIO_GPEDS0) & (1 << pin) ) {
+ BCM2835_REG(BCM2835_GPIO_GPEDS0) &= (1 << pin);
+ }
+ /* If not lets the next ISR process the interrupt. */
+ else {
+ return;
+ }
+
+ /* If this pin has the deboucing function attached, call it. */
+ if ( handler_args->debouncing_tick_count > 0 ) {
+ rv = debounce_switch(pin);
+
+ if ( rv < 0 ) {
+ return;
+ }
+ }
+
+ /* Call the user's ISR. */
+ (handler_args->handler) ();
+}
+
+/**
+ * @brief Defines for a GPIO input pin the number of clock ticks that must pass
+ * before an generated interrupt is garanteed to be generated by the user
+ * and not by a bouncing switch/button.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL De-bounce function successfully attached to the pin.
+ * @retval RTEMS_NOT_CONFIGURED The current pin is not configured as a digital
+ * input, hence it can not be connected to a switch.
+ */
+rtems_status_code gpio_debounce_switch(int dev_pin, int ticks)
+{
+ assert( dev_pin >= 1 && dev_pin <= GPIO_PIN_COUNT );
+
+ if ( gpio_pin[dev_pin - 1].pin_type != DIGITAL_INPUT ) {
+ return RTEMS_NOT_CONFIGURED;
+ }
+
+ gpio_pin[dev_pin - 1].h_args.debouncing_tick_count = ticks;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Enables interrupts to be generated on a given GPIO pin.
+ * When fired that interrupt will call the given handler.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ * @param[in] interrupt Type of interrupt to enable for the pin.
+ * @param[in] handler Pointer to a function that will be called every time
+ * @var interrupt is generated. This function must have
+ * no receiving parameters and return void.
+ *
+ * @retval RTEMS_SUCCESSFUL Interrupt successfully enabled for this pin.
+ * @retval RTEMS_UNSATISFIED Could not replace the currently active
+ * interrupt on this pin.
+ */
+rtems_status_code gpio_enable_interrupt(
+int dev_pin,
+gpio_interrupt interrupt,
+void (*handler)(void)
+)
+{
+ rtems_status_code sc;
+ rpi_gpio_pin *pin;
+
+ assert( dev_pin >= 1 && dev_pin <= GPIO_EXTERNAL_TOP_PIN );
+
+ pin = &gpio_pin[dev_pin - 1];
+
+ /* If the pin already has an enabled interrupt removes it first,
+ * as well as its handler. */
+ if ( pin->enabled_interrupt != NONE ) {
+ sc = gpio_disable_interrupt(dev_pin);
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return RTEMS_UNSATISFIED;
+ }
+ }
+
+ pin->h_args.pin_number = dev_pin;
+ pin->h_args.handler = handler;
+
+ pin->h_args.last_isr_tick = rtems_clock_get_ticks_since_boot();
+
+ /* Installs the generic_handler, which will call the user handler received
+ * a parameter. */
+ sc = rtems_interrupt_handler_install(BCM2835_IRQ_ID_GPIO_0,
+ NULL,
+ RTEMS_INTERRUPT_SHARED,
+ (rtems_interrupt_handler) generic_handler,
+ &(pin->h_args));
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ switch ( interrupt ) {
+ case FALLING_EDGE:
+ /* Enables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) |= (1 << dev_pin);
+ break;
+
+ case RISING_EDGE:
+ /* Enables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) |= (1 << dev_pin);
+ break;
+
+ case BOTH_EDGES:
+ /* Enables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) |= (1 << dev_pin);
+
+ /* Enables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) |= (1 << dev_pin);
+ break;
+
+ case LOW_LEVEL:
+ /* Enables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) |= (1 << dev_pin);
+ break;
+
+ case HIGH_LEVEL:
+ /* Enables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) |= (1 << dev_pin);
+ break;
+
+ case BOTH_LEVELS:
+ /* Enables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) |= (1 << dev_pin);
+
+ /* Enables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) |= (1 << dev_pin);
+ break;
+
+ case NONE:
+ return RTEMS_SUCCESSFUL;
+ }
+
+ pin->enabled_interrupt = interrupt;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Stops interrupts from being generated from a given GPIO pin
+ * and removes the corresponding handler.
+ *
+ * @param[in] dev_pin Raspberry Pi GPIO pin label number (not its position
+ * on the header).
+ *
+ * @retval RTEMS_SUCCESSFUL Interrupt successfully disabled for this pin.
+ * @retval RTEMS_UNSATISFIED Could not remove the current interrupt handler or
+ * could not recognise the current active interrupt
+ * on this pin.
+ */
+rtems_status_code gpio_disable_interrupt(int dev_pin)
+{
+ rtems_status_code sc;
+ rpi_gpio_pin *pin;
+
+ assert( dev_pin >= 1 && dev_pin <= GPIO_EXTERNAL_TOP_PIN );
+
+ pin = &gpio_pin[dev_pin - 1];
+
+ switch ( pin->enabled_interrupt ) {
+ case FALLING_EDGE:
+ /* Disables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) &= ~(1 << dev_pin);
+ break;
+
+ case RISING_EDGE:
+ /* Disables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) &= ~(1 << dev_pin);
+ break;
+
+ case BOTH_EDGES:
+ /* Disables asynchronous falling edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAFEN0) &= ~(1 << dev_pin);
+
+ /* Disables asynchronous rising edge detection. */
+ BCM2835_REG(BCM2835_GPIO_GPAREN0) &= ~(1 << dev_pin);
+ break;
+
+ case LOW_LEVEL:
+ /* Disables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) &= ~(1 << dev_pin);
+ break;
+
+ case HIGH_LEVEL:
+ /* Disables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) &= ~(1 << dev_pin);
+ break;
+
+ case BOTH_LEVELS:
+ /* Disables pin low level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPLEN0) &= ~(1 << dev_pin);
+
+ /* Disables pin high level detection. */
+ BCM2835_REG(BCM2835_GPIO_GPHEN0) &= ~(1 << dev_pin);
+ break;
+
+ case NONE:
+ return RTEMS_SUCCESSFUL;
+ }
+
+ /* Removes the handler. */
+ sc = rtems_interrupt_handler_remove(BCM2835_IRQ_ID_GPIO_0,
+ (rtems_interrupt_handler) generic_handler,
+ &(pin->h_args));
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ pin->enabled_interrupt = NONE;
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
new file mode 100644
index 0000000..13c33ad
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
@@ -0,0 +1,480 @@
+/**
+ * @file i2c.c
+ *
+ * @ingroup raspberrypi_i2c
+ *
+ * @brief Support for the I2C bus on the Raspberry Pi GPIO P1 header (model A/B)
+ * and GPIO J8 header on model B+.
+ */
+
+/*
+ * Copyright (c) 2014 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.
+ */
+
+/*
+ * TODO:
+ * - Clock stretching (currently using default values)
+ * - 10-bit addressing
+ * - Falling/Rising edge delays (currently using default values)
+ */
+
+#include <bsp.h>
+#include <bsp/raspberrypi.h>
+#include <bsp/gpio.h>
+#include <bsp/irq.h>
+#include <bsp/i2c.h>
+#include <assert.h>
+
+/**
+ * @brief Calculates a clock divider to be used with the BSC core clock rate
+ * to set a I2C clock rate the closest (<=) to a desired frequency.
+ *
+ * @param[in] clock_hz The desired clock frequency for the I2C bus operation.
+ * @param[out] clock_divider Pointer to a variable where the calculated
+ * clock divider will be stored.
+ *
+ * @retval RTEMS_SUCCESSFUL Successfully calculated a valid clock divider.
+ * @retval RTEMS_INVALID_NUMBER The resulting clock divider is invalid, due to
+ * an invalid BSC_CORE_CLOCK_HZ
+ * or clock_hz value.
+ */
+static rtems_status_code
+bcm2835_i2c_calculate_clock_divider(uint32_t clock_hz, uint16_t *clock_divider)
+{
+ uint16_t divider;
+ uint32_t clock_rate;
+
+ assert( clock_hz > 0 );
+
+ /* Calculates an initial clock divider. */
+ divider = BSC_CORE_CLK_HZ / clock_hz;
+
+ clock_rate = BSC_CORE_CLK_HZ / divider;
+
+ /* If the resulting clock rate is greater than desired, try the next greater
+ * divider. */
+ while ( clock_rate > clock_hz ) {
+ ++divider;
+
+ clock_rate = BSC_CORE_CLK_HZ / divider;
+ }
+
+ *clock_divider = divider;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Set the I2C bus clock divider.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] tfr_mode Pointer to a libi2c API transfer mode data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL Successfully setup the bus transfer mode as desired.
+ * @retval RTEMS_INVALID_NUMBER @see bcm2835_i2c_calculate_clock_divider().
+ */
+static rtems_status_code bcm2835_i2c_set_tfr_mode(
+rtems_libi2c_bus_t *bushdl,
+const rtems_libi2c_tfr_mode_t *tfr_mode
+)
+{
+ rtems_status_code sc;
+ uint16_t clock_divider;
+
+ /* Calculate the most appropriate clock divider. */
+ sc = bcm2835_i2c_calculate_clock_divider(tfr_mode->baudrate, &clock_divider);
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Set clock divider. */
+ BCM2835_REG(BCM2835_I2C_DIV) = clock_divider;
+
+ return sc;
+}
+
+/**
+ * @brief Reads/writes to/from the I2C bus.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] rd_buf Read buffer. If not NULL the function will read from
+ * the bus and store the read on this buffer.
+ * @param[in] wr_buf Write buffer. If not NULL the function will write the
+ * contents of this buffer to the bus.
+ * @param[in] buffer_size Size of the non-NULL buffer.
+ *
+ * @retval -1 Could not send/receive data to/from the bus.
+ * @retval >=0 The number of bytes read/written.
+ */
+static int bcm2835_i2c_read_write(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *rd_buf,
+const unsigned char *wr_buf,
+int buffer_size
+)
+{
+ bcm2835_i2c_softc_t *softc_ptr = &(((bcm2835_i2c_desc_t *)(bushdl))->softc);
+
+ uint32_t bytes_sent = buffer_size;
+
+ /* Since there is a maximum of 0xFFFF packets per transfer
+ * (size of the DLEN register), count how many transfers will be
+ * needed and adjust each transfer size accordingly. */
+ int transfer_count = (buffer_size + 0xFFFE) / 0xFFFF;
+ uint16_t dlen_buffer_size;
+
+ do {
+ if ( transfer_count > 1 ) {
+ dlen_buffer_size = 0xFFFF;
+ }
+ else {
+ dlen_buffer_size = (buffer_size & 0xFFFF);
+ }
+
+ /* Set the DLEN register, which specifies how many data packets
+ * will be transferred. */
+ BCM2835_REG(BCM2835_I2C_DLEN) = dlen_buffer_size;
+
+ /* Clear the acknowledgment and clock stretching error status. */
+ BCM2835_REG(BCM2835_I2C_S) |= (3 << 8);
+
+ /* While there is data to transfer. */
+ while ( dlen_buffer_size >= 1 ) {
+ /* If writing. */
+ if ( rd_buf == NULL ) {
+
+ /* If transfer is not active, send start bit. */
+ if( (BCM2835_REG(BCM2835_I2C_S) & (1 << 0)) == 0 )
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 7);
+
+ /* If using the I2C bus in interrupt-driven mode. */
+ if ( I2C_IO_MODE == 1 ) {
+
+ /* Generate interrupts on the TXW bit condition. */
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 9);
+
+ if (
+ rtems_semaphore_obtain(softc_ptr->irq_sema_id, RTEMS_WAIT, 50) !=
+ RTEMS_SUCCESSFUL
+ ) {
+ return -1;
+ }
+ }
+
+ /* If using the bus in polling mode. */
+ else {
+ /* Poll TXW bit until there is space available to write. */
+ while ( (BCM2835_REG(BCM2835_I2C_S) & (1 << 2)) == 0 ) {
+ ;
+ }
+ }
+
+ /* Write data to the TX FIFO. */
+ BCM2835_REG(BCM2835_I2C_FIFO) = (*(uint8_t *)wr_buf);
+
+ ++wr_buf;
+
+ /* Check for acknowledgment or clock stretching errors. */
+ if (
+ (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) ||
+ (BCM2835_REG(BCM2835_I2C_S) & (1 << 9))
+ ) {
+ return -1;
+ }
+ }
+ /* If reading. */
+ else {
+ /* Send start bit. Before any read a libi2c_send_addr call should be
+ * made signaling a read operation. */
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 7);
+
+ /* Check for an acknowledgment error. */
+ if ( (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) != 0 ) {
+ return -1;
+ }
+
+ /* Poll RXD bit until there is data on the RX FIFO to read. */
+ while ( (BCM2835_REG(BCM2835_I2C_S) & (1 << 5)) == 0 ) {
+ ;
+ }
+
+ /* Read data from the RX FIFO. */
+ (*(uint8_t *)rd_buf) = BCM2835_REG(BCM2835_I2C_FIFO) & 0xFF;
+
+ ++rd_buf;
+
+ /* Check for acknowledgment or clock stretching errors. */
+ if (
+ (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) ||
+ (BCM2835_REG(BCM2835_I2C_S) & (1 << 9))
+ ) {
+ return -1;
+ }
+ }
+
+ --dlen_buffer_size;
+ --transfer_count;
+ --buffer_size;
+ }
+ } while ( transfer_count > 0 );
+
+ /* If using the I2C bus in interrupt-driven mode. */
+ if ( I2C_IO_MODE == 1 ) {
+ /* Generate interrupts on the DONE bit condition. */
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 8);
+
+ if (
+ rtems_semaphore_obtain(softc_ptr->irq_sema_id, RTEMS_WAIT, 50) !=
+ RTEMS_SUCCESSFUL
+ ) {
+ return -1;
+ }
+ }
+ /* If using the bus in polling mode. */
+ else {
+ /* Poll DONE bit until data has been sent. */
+ while ( (BCM2835_REG(BCM2835_I2C_S) & (1 << 1)) == 0 ) {
+ ;
+ }
+ }
+
+ bytes_sent -= buffer_size;
+
+ return bytes_sent;
+}
+
+/**
+ * @brief Handler function that is called on any I2C interrupt.
+ *
+ * There are 3 situations that can generate an interrupt:
+ *
+ * 1. Transfer (read/write) complete;
+ * 2. The TX FIFO has space for more data (during a write transfer);
+ * 3. The RX FIFO is full.
+ *
+ * Because the I2C FIFO has a 16 byte size, the 3. situation is not
+ * as useful to many applications as knowing that at least 1 byte can
+ * be read from the RX FIFO. For that reason this information is
+ * got through polling the RXD bit even in interrupt-driven mode.
+ *
+ * This leaves only 2 interrupts to be caught. At any given time
+ * when no I2C bus transfer is taking place no I2C interrupts are
+ * generated, and they do they are only enabled one at a time:
+ *
+ * - When trying to write, the 2. interrupt is enabled to signal that
+ * data can be written on the TX FIFO, avoiding data loss in case
+ * it is full. When caught the handler disables that interrupt from
+ * being generated and releases the irq semaphore, which will allow
+ * the transfer process to continue (by writing to the TX FIFO);
+ *
+ * - When the transfer is done on Raspberry side, the 1. interrupt is
+ * enabled for the device to signal it has finished the transfer as
+ * well. When caught the handler disables that interrupt from being
+ * generated and releases the irq semaphore, marking the end of the
+ * transfer.
+ *
+ * @param[in] arg Void pointer to the bus data structure.
+ */
+static void i2c_handler(void* arg)
+{
+ bcm2835_i2c_softc_t *softc_ptr = (bcm2835_i2c_softc_t *) arg;
+
+ /* If the current enabled interrupt is on the TXW condition, disable it. */
+ if ( (BCM2835_REG(BCM2835_I2C_C) & (1 << 9)) ) {
+ BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 9);
+ }
+ /* If the current enabled interrupt is on the DONE condition, disable it. */
+ else if ( (BCM2835_REG(BCM2835_I2C_C) & (1 << 8)) ) {
+ BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 8);
+
+ /* Release the irq semaphore. */
+ rtems_semaphore_release(softc_ptr->irq_sema_id);
+ }
+}
+
+/**
+ * @brief Low level function to initialize the I2C bus.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL SPI bus successfully initialized.
+ * @retval Any other status code @see rtems_semaphore_create() and
+ * @see rtems_interrupt_handler_install().
+ */
+rtems_status_code bcm2835_i2c_init(rtems_libi2c_bus_t * bushdl)
+{
+ bcm2835_i2c_softc_t *softc_ptr = &(((bcm2835_i2c_desc_t *)(bushdl))->softc);
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if ( softc_ptr->initialized == 1 ) {
+ return sc;
+ }
+
+ softc_ptr->initialized = 1;
+
+ /* Enable the I2C BSC interface. */
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 15);
+
+ /* If the access to the bus is configured to be interrupt-driven. */
+ if ( I2C_IO_MODE == 1 ) {
+ sc = rtems_semaphore_create(rtems_build_name('i','2','c','s'),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &softc_ptr->irq_sema_id
+ );
+
+ sc = rtems_interrupt_handler_install(BCM2835_IRQ_ID_I2C,
+ NULL,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) i2c_handler,
+ softc_ptr
+ );
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Low level function that would send a start condition over the I2C bus.
+ * Because of the way the BSC controller implements the I2C protocol, the
+ * start sequence is sent whenever appropriate in bcm2835_i2c_read_write.
+ * Instead this function clears the bus FIFOS before each new data
+ * transfer.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL
+ */
+rtems_status_code bcm2835_i2c_send_start(rtems_libi2c_bus_t * bushdl)
+{
+ /* Clear FIFOs. */
+ BCM2835_REG(BCM2835_I2C_C) |= (3 << 4);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function that would send a stop condition over the I2C bus,
+ * however the BSC controller send this condition automatically when the
+ * DLEN (data length - the number of bytes to be transferred) register
+ * value reaches 0.
+ * For that reason, it is here just to satisfy, the libi2c API,
+ * which requires this function.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL
+ */
+rtems_status_code bcm2835_i2c_stop(rtems_libi2c_bus_t * bushdl)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function which addresses a I2C device.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] addr Address of a connected I2C device
+ * @param[in] rw Defines the nature of the transfer which will take place with
+ * the addressed device - 0 to write and 1 to read.
+ *
+ * @retval RTEMS_SUCCESSFUL The device has been successfully addressed.
+ */
+rtems_status_code
+bcm2835_i2c_send_addr(rtems_libi2c_bus_t * bushdl, uint32_t addr, int rw)
+{
+ /* Address slave device. */
+ BCM2835_REG(BCM2835_I2C_A) = addr;
+
+ /* Set read/write bit.
+ * If writing. */
+ if ( rw == 0 ) {
+ BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 0);
+ }
+ /* If reading. */
+ else {
+ BCM2835_REG(BCM2835_I2C_C) |= (1 << 0);
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function that reads a number of bytes from the I2C bus
+ * on to a buffer.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] bytes Buffer where the data read from the bus will be stored.
+ * @param[in] nbytes Number of bytes to be read from the bus
+ * to the bytes buffer.
+ *
+ * @retval @see bcm2835_i2c_read_write().
+ */
+int bcm2835_i2c_read_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+)
+{
+ return bcm2835_i2c_read_write(bushdl, bytes, NULL, nbytes);
+}
+
+/**
+ * @brief Low level function that writes a number of bytes from a buffer
+ * to the I2C bus.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] bytes Buffer with data to send through the bus.
+ * @param[in] nbytes Number of bytes to be written from the bytes buffer
+ to the bus.
+ *
+ * @retval @see bcm2835_i2c_read_write().
+ */
+int bcm2835_i2c_write_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+)
+{
+ return bcm2835_i2c_read_write(bushdl, NULL, bytes, nbytes);
+}
+
+/**
+ * @brief Low level function that is used to perform ioctl
+ * operations on the bus. Currently only setups
+ * the bus transfer mode, namely the bus clock divider.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] cmd IOCTL request command.
+ * @param[in] arg Arguments needed to fulfill the requested IOCTL command.
+ *
+ * @retval -1 Unknown request command.
+ * @retval >=0 @see bcm2835_i2c_set_tfr_mode().
+ */
+int bcm2835_i2c_ioctl(rtems_libi2c_bus_t * bushdl, int cmd, void *arg)
+{
+ switch ( cmd ) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+
+ return bcm2835_i2c_set_tfr_mode(bushdl,
+ (const rtems_libi2c_tfr_mode_t *)arg
+ );
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
new file mode 100644
index 0000000..3a68407
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
@@ -0,0 +1,84 @@
+/**
+ * @file i2c_init.c
+ *
+ * @ingroup raspberrypi_i2c
+ *
+ * @brief Raspberry Pi I2C bus initialization.
+ */
+
+/*
+ * Copyright (c) 2014 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/gpio.h>
+#include <bsp/i2c.h>
+
+#include <libchip/mcp23008.h>
+
+static rtems_libi2c_bus_ops_t bcm2835_i2c_ops = {
+ init: bcm2835_i2c_init,
+ send_start: bcm2835_i2c_send_start,
+ send_stop: bcm2835_i2c_stop,
+ send_addr: bcm2835_i2c_send_addr,
+ read_bytes: bcm2835_i2c_read_bytes,
+ write_bytes: bcm2835_i2c_write_bytes,
+ ioctl: bcm2835_i2c_ioctl
+};
+
+static bcm2835_i2c_desc_t bcm2835_i2c_bus_desc = {
+ {
+ ops: &bcm2835_i2c_ops,
+ size: sizeof(bcm2835_i2c_bus_desc)
+ },
+ {
+ initialized: 0
+ }
+};
+
+/* Register drivers here for all the devices
+ * which require access to the I2C bus.
+ *
+ * The libi2c function "rtems_libi2c_register_drv" must be used to
+ * register each device driver, using the received i2c bus number.
+ *
+ * This function returns 0 on success. */
+int BSP_i2c_register_drivers(int i2c_bus_number)
+{
+ int rv = 0;
+
+ rv = rtems_libi2c_register_drv("mcp23008", &i2c_mcp23008_drv_t, i2c_bus_number, MCP23008_ADDR);
+
+ return rv;
+}
+
+int BSP_i2c_init(void)
+{
+ int rv;
+
+ /* Initialize the libi2c API. */
+ rtems_libi2c_initialize ();
+
+ /* Enable the I2C interface on the Raspberry Pi P1 GPIO header. */
+ gpio_initialize ();
+
+ if ( gpio_select_i2c_p1_rev2() < 0 ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Register the I2C bus. */
+ rv = rtems_libi2c_register_bus("/dev/i2c", &(bcm2835_i2c_bus_desc.bus_desc));
+
+ if ( rv < 0 ) {
+ return -rv;
+ }
+
+ /* Register SPI device drivers. */
+ rv = BSP_i2c_register_drivers(rv);
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
new file mode 100644
index 0000000..96b6db0
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
@@ -0,0 +1,608 @@
+/**
+ * @file spi.c
+ *
+ * @ingroup raspberrypi_i2c
+ *
+ * @brief Support for the SPI bus on the Raspberry Pi GPIO P1 header (model A/B)
+ * and GPIO J8 header on model B+.
+ */
+
+/*
+ * Copyright (c) 2014 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.
+ */
+
+/*
+ * STATUS:
+ * - Bi-directional mode untested
+ * - Write-only devices not supported
+ */
+
+#include <bsp.h>
+#include <bsp/raspberrypi.h>
+#include <bsp/gpio.h>
+#include <bsp/irq.h>
+#include <bsp/i2c.h>
+#include <assert.h>
+
+/**
+ * @brief Calculates a clock divider to be used with the GPU core clock rate
+ * to set a SPI clock rate the closest (<=) to a desired frequency.
+ *
+ * @param[in] clock_hz The desired clock frequency for the SPI bus operation.
+ * @param[out] clock_divider Pointer to a variable where the calculated
+ * clock divider will be stored.
+ *
+ * @retval RTEMS_SUCCESSFUL Successfully calculated a valid clock divider.
+ * @retval RTEMS_INVALID_NUMBER The resulting clock divider is invalid, due to
+ * an invalid GPU_CORE_CLOCK_RATE
+ * or clock_hz value.
+ */
+static rtems_status_code
+bcm2835_spi_calculate_clock_divider(uint32_t clock_hz, uint16_t *clock_divider)
+{
+ uint16_t divider;
+ uint32_t clock_rate;
+
+ assert( clock_hz > 0 );
+
+ /* Calculates an initial clock divider. */
+ divider = GPU_CORE_CLOCK_RATE / clock_hz;
+
+ /* Because the divider must be a power of two (as per the BCM2835 datasheet),
+ * calculate the next greater power of two. */
+ --divider;
+
+ divider |= (divider >> 1);
+ divider |= (divider >> 2);
+ divider |= (divider >> 4);
+ divider |= (divider >> 8);
+
+ ++divider;
+
+ clock_rate = GPU_CORE_CLOCK_RATE / divider;
+
+ /* If the resulting clock rate is greater than the desired frequency,
+ * try the next greater power of two divider. */
+ while ( clock_rate > clock_hz ) {
+ divider = (divider << 1);
+
+ clock_rate = GPU_CORE_CLOCK_RATE / divider;
+ }
+
+ *clock_divider = divider;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Set the SPI bus transfer mode.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] tfr_mode Pointer to a libi2c API transfer mode data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL Successfully setup the bus transfer mode as desired.
+ * @retval RTEMS_INVALID_NUMBER This can have two meanings:
+ * 1. The specified number of bytes per char is not
+ * 8, 16, 24 or 32;
+ * 2. @see bcm2835_spi_calculate_clock_divider()
+ */
+static rtems_status_code bcm2835_spi_set_tfr_mode(
+rtems_libi2c_bus_t *bushdl,
+const rtems_libi2c_tfr_mode_t *tfr_mode
+)
+{
+ bcm2835_spi_softc_t *softc_ptr = &(((bcm2835_spi_desc_t *)(bushdl))->softc);
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint16_t clock_divider;
+
+ /* Set the dummy character. */
+ softc_ptr->dummy_char = tfr_mode->idle_char;
+
+ /* Calculate the most appropriate clock divider. */
+ sc = bcm2835_spi_calculate_clock_divider(tfr_mode->baudrate, &clock_divider);
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ /* Set the bus clock divider. */
+ BCM2835_REG(BCM2835_SPI_CLK) = clock_divider;
+
+ /* Calculate how many bytes each character has.
+ * Only multiples of 8 bits are accepted for the transaction. */
+ switch ( tfr_mode->bits_per_char ) {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ softc_ptr->bytes_per_char = tfr_mode->bits_per_char / 8;
+ break;
+
+ default:
+ return RTEMS_INVALID_NUMBER;
+ }
+
+ /* Check the data mode (most or least significant bit first) and calculate
+ * the correcting bit shift value to apply on the data before sending. */
+ if ( tfr_mode->lsb_first ) {
+ softc_ptr->bit_shift = 32 - tfr_mode->bits_per_char;
+ }
+ /* If MSB first. */
+ else {
+ softc_ptr->bit_shift = 0;
+ }
+
+ /* Set SPI clock polarity.
+ * If clock_inv is TRUE, the clock is active high.*/
+ if ( tfr_mode->clock_inv ) {
+ /* Rest state of clock is low. */
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 3);
+ }
+ else {
+ /* Rest state of clock is high. */
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 3);
+ }
+
+ /* Set SPI clock phase.
+ * If clock_phs is true, clock starts toggling
+ * at the start of the data transfer. */
+ if ( tfr_mode->clock_phs ) {
+ /* First SCLK transition at beginning of data bit. */
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 2);
+ }
+ else {
+ /* First SCLK transition at middle of data bit. */
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 2);
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Reads/writes to/from the SPI bus.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] rd_buf Read buffer. If not NULL the function will read from
+ * the bus and store the read on this buffer.
+ * @param[in] wr_buf Write buffer. If not NULL the function will write the
+ * contents of this buffer to the bus.
+ * @param[in] buffer_size Size of the non-NULL buffer.
+ *
+ * @retval -1 Could not send/receive data to/from the bus.
+ * @retval >=0 The number of bytes read/written.
+ */
+static int bcm2835_spi_read_write(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *rd_buf,
+const unsigned char *wr_buf,
+int buffer_size
+)
+{
+ bcm2835_spi_softc_t *softc_ptr = &(((bcm2835_spi_desc_t *)(bushdl))->softc);
+
+ uint8_t bytes_per_char = softc_ptr->bytes_per_char;
+ uint8_t bit_shift = softc_ptr->bit_shift;
+ uint32_t dummy_char = softc_ptr->dummy_char;
+
+ uint32_t bytes_sent = buffer_size;
+ uint32_t fifo_data;
+
+ /* Clear SPI bus FIFOs. */
+ BCM2835_REG(BCM2835_SPI_CS) |= (3 << 4);
+
+ /* Set SPI transfer active. */
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 7);
+
+ /* If using the SPI bus in interrupt-driven mode. */
+ if ( SPI_IO_MODE == 1 ) {
+ softc_ptr->irq_write = 1;
+
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
+
+ if (
+ rtems_semaphore_obtain(softc_ptr->irq_sema_id, RTEMS_WAIT, 50) !=
+ RTEMS_SUCCESSFUL
+ ) {
+ return -1;
+ }
+ }
+ /* If using the bus in polling mode. */
+ else {
+ /* Poll TXD bit until there is space to write at least one byte
+ * on the TX FIFO. */
+ while ( (BCM2835_REG(BCM2835_SPI_CS) & (1 << 18)) == 0 ) {
+ ;
+ }
+ }
+
+ /* While there is data to be transferred. */
+ while ( buffer_size >= bytes_per_char ) {
+ /* If reading from the bus, send a dummy character to the device. */
+ if ( rd_buf != NULL ) {
+ BCM2835_REG(BCM2835_SPI_FIFO) = dummy_char;
+ }
+ /* If writing to the bus, move the buffer data to the TX FIFO. */
+ else {
+ switch ( bytes_per_char ) {
+ case 1:
+ BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFF) << bit_shift);
+ break;
+
+ case 2:
+ BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFFFF) << bit_shift);
+ break;
+
+ case 3:
+ BCM2835_REG(BCM2835_SPI_FIFO) = (((*wr_buf) & 0xFFFFFF) << bit_shift);
+ break;
+
+ case 4:
+ BCM2835_REG(BCM2835_SPI_FIFO) = ((*wr_buf) << bit_shift);
+ break;
+
+ default:
+ return -1;
+ }
+
+ wr_buf += bytes_per_char;
+
+ buffer_size -= bytes_per_char;
+ }
+
+ /* If using bi-directional SPI. */
+ if ( softc_ptr->bidirectional == 1 ) {
+ /* Change bus direction to read from the slave device. */
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 12);
+ }
+
+ /* If using the SPI bus in interrupt-driven mode. */
+ if ( SPI_IO_MODE == 1 ) {
+ softc_ptr->irq_write = 0;
+
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
+
+ if (
+ rtems_semaphore_obtain(softc_ptr->irq_sema_id, RTEMS_WAIT, 50) !=
+ RTEMS_SUCCESSFUL
+ ) {
+ return -1;
+ }
+ }
+ /* If using the bus in polling mode. */
+ else {
+ /* Poll the Done bit until the data transfer is complete. */
+ while ( (BCM2835_REG(BCM2835_SPI_CS) & (1 << 16)) == 0 ) {
+ ;
+ }
+
+ /* Poll the RXD bit until there is at least one byte
+ * on the RX FIFO to be read. */
+ while ( (BCM2835_REG(BCM2835_SPI_CS) & (1 << 17)) == 0 ) {
+ ;
+ }
+ }
+
+ /* If writing to the bus, read the dummy char sent by the slave device. */
+ if ( rd_buf == NULL ) {
+ fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFF;
+ }
+
+ /* If reading from the bus, retrieve data from the RX FIFO and
+ * store it on the buffer. */
+ if ( rd_buf != NULL ) {
+ switch ( bytes_per_char ) {
+ case 1:
+ fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFF;
+ (*rd_buf) = (fifo_data >> bit_shift);
+ break;
+
+ case 2:
+ fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFFFF;
+ (*rd_buf) = (fifo_data >> bit_shift);
+ break;
+
+ case 3:
+ fifo_data = BCM2835_REG(BCM2835_SPI_FIFO) & 0xFFFFFF;
+ (*rd_buf) = (fifo_data >> bit_shift);
+ break;
+
+ case 4:
+ fifo_data = BCM2835_REG(BCM2835_SPI_FIFO);
+ (*rd_buf) = (fifo_data >> bit_shift);
+ break;
+
+ default:
+ return -1;
+ }
+
+ rd_buf += bytes_per_char;
+
+ buffer_size -= bytes_per_char;
+ }
+
+ /* If using bi-directional SPI. */
+ if ( softc_ptr->bidirectional == 1 ) {
+ /* Restore bus direction to write to the slave. */
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 12);
+ }
+ }
+
+ /* If using the SPI bus in interrupt-driven mode. */
+ if ( SPI_IO_MODE == 1 ) {
+ softc_ptr->irq_write = 1;
+
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << 9);
+
+ if (
+ rtems_semaphore_obtain(softc_ptr->irq_sema_id, RTEMS_WAIT, 50) !=
+ RTEMS_SUCCESSFUL
+ ) {
+ return -1;
+ }
+ }
+ /* If using the bus in polling mode. */
+ else {
+ /* Poll the Done bit until the data transfer is complete. */
+ while ( (BCM2835_REG(BCM2835_SPI_CS) & (1 << 16)) == 0 ) {
+ ;
+ }
+ }
+
+ bytes_sent -= buffer_size;
+
+ return bytes_sent;
+}
+
+/**
+ * @brief Handler function that is called on any SPI interrupt.
+ *
+ * There are 2 situations that can generate an interrupt:
+ *
+ * 1. Transfer (read/write) complete;
+ * 2. RX FIFO full.
+ *
+ * Because the 2. situation is not useful to many applications,
+ * the only interrupt that is generated and handled is the
+ * transfer complete interrupt.
+ *
+ * The objective of the handler is then, depending on the transfer
+ * context (reading or writing on the bus), to check if there is enough
+ * space available on the TX FIFO to send data over the bus (if writing)
+ * or if the slave device has sent enough data to be fetched from the
+ * RX FIFO (if reading).
+ *
+ * When any of these two conditions occur, disables further interrupts
+ * to be generated and releases a irq semaphore which will allow the
+ * following transfer to proceed.
+ *
+ * @param[in] arg Void pointer to the bus data structure.
+ */
+static void spi_handler(void* arg)
+{
+ bcm2835_spi_softc_t *softc_ptr = (bcm2835_spi_softc_t *) arg;
+
+ /* If waiting to write to the bus, expect the TXD bit to be set, or
+ * if waiting to read from the bus, expect the RXD bit to be set
+ * before releasing the irq semaphore. */
+ if (
+ ( softc_ptr->irq_write == 1 && (BCM2835_REG(BCM2835_SPI_CS) & (1 << 18)) != 0 ) ||
+ ( softc_ptr->irq_write == 0 && (BCM2835_REG(BCM2835_SPI_CS) & (1 << 17)) != 0 )
+ ) {
+ /* Disable the SPI interrupt generation when a transfer is complete. */
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 9);
+
+ /* Release the irq semaphore. */
+ rtems_semaphore_release(softc_ptr->irq_sema_id);
+ }
+}
+
+/**
+ * @brief Low level function to initialize the SPI bus.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL SPI bus successfully initialized.
+ * @retval Any other status code @see rtems_semaphore_create() and
+ * @see rtems_interrupt_handler_install().
+ */
+rtems_status_code bcm2835_spi_init(rtems_libi2c_bus_t * bushdl)
+{
+ bcm2835_spi_softc_t *softc_ptr = &(((bcm2835_spi_desc_t *)(bushdl))->softc);
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if ( softc_ptr->initialized == 1 ) {
+ return sc;
+ }
+
+ softc_ptr->initialized = 1;
+
+ /* TODO: This should be set on the device driver itself and configured
+ * during the bus transfer mode setup or another ioctl request. */
+ softc_ptr->bidirectional = 0;
+
+ /* If using the SPI bus in interrupt-driven mode. */
+ if ( SPI_IO_MODE == 1 ) {
+ sc = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &softc_ptr->irq_sema_id
+ );
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return sc;
+ }
+
+ sc = rtems_interrupt_handler_install(BCM2835_IRQ_ID_SPI,
+ NULL,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) spi_handler,
+ softc_ptr
+ );
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Low level function that would send a start condition over an I2C bus.
+ * As it is not required to access a SPI bus it is here just to satisfy
+ * the libi2c API, which requires this function.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL
+ */
+rtems_status_code bcm2835_spi_send_start(rtems_libi2c_bus_t * bushdl)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function that terminates a SPI transfer.
+ * It stops the SPI transfer and unselects the current SPI slave device.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ *
+ * @retval RTEMS_SUCCESSFUL The slave device has been successfully unselected.
+ * @retval RTEMS_INVALID_ADDRESS The stored slave address is neither 0 or 1.
+ */
+rtems_status_code bcm2835_spi_stop(rtems_libi2c_bus_t * bushdl)
+{
+ bcm2835_spi_softc_t *softc_ptr = &(((bcm2835_spi_desc_t *)(bushdl))->softc);
+
+ uint32_t addr = softc_ptr->current_slave_addr;
+ uint32_t chip_select_bit = 21 + addr;
+
+ /* Set SPI transfer as not active. */
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << 7);
+
+ /* Unselect the active SPI slave. */
+ switch ( addr ) {
+ case 0:
+ case 1:
+ BCM2835_REG(BCM2835_SPI_CS) |= (1 << chip_select_bit);
+
+ break;
+
+ default:
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function which addresses a SPI slave device.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] addr SPI slave select line address (0 for CE0 or 1 for CE1).
+ * @param[in] rw This values is unnecessary to address a SPI device and its
+ * presence here is only to fulfill a libi2c requirement.
+ *
+ * @retval RTEMS_SUCCESSFUL The slave device has been successfully addressed.
+ * @retval RTEMS_INVALID_ADDRESS The received address is neither 0 or 1.
+ */
+rtems_status_code
+bcm2835_spi_send_addr(rtems_libi2c_bus_t * bushdl, uint32_t addr, int rw)
+{
+ bcm2835_spi_softc_t *softc_ptr = &(((bcm2835_spi_desc_t *)(bushdl))->softc);
+
+ /* Calculates the bit corresponding to the received address
+ * on the SPI control register. */
+ uint32_t chip_select_bit = 21 + addr;
+
+ /* Save which slave will be currently addressed,
+ * so it can be unselected later. */
+ softc_ptr->current_slave_addr = addr;
+
+ /* Select one of the two available SPI slave address lines. */
+ switch ( addr ) {
+ case 0:
+ case 1:
+ BCM2835_REG(BCM2835_SPI_CS) &= ~(1 << chip_select_bit);
+ break;
+
+ default:
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Low level function that reads a number of bytes from the SPI bus
+ * on to a buffer.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] bytes Buffer where the data read from the bus will be stored.
+ * @param[in] nbytes Number of bytes to be read from the bus to the bytes buffer.
+ *
+ * @retval @see bcm2835_spi_read_write().
+ */
+int bcm2835_spi_read_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+)
+{
+ return bcm2835_spi_read_write(bushdl, bytes, NULL, nbytes);
+}
+
+/**
+ * @brief Low level function that writes a number of bytes from a buffer
+ * to the SPI bus.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] bytes Buffer with data to send over the SPI bus.
+ * @param[in] nbytes Number of bytes to be written from the bytes buffer
+ to the bus.
+ *
+ * @retval @see bcm2835_spi_read_write().
+ */
+int bcm2835_spi_write_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+)
+{
+ return bcm2835_spi_read_write(bushdl, NULL, bytes, nbytes);
+}
+
+/**
+ * @brief Low level function that is used to perform ioctl
+ * operations on the bus. Currently only setups
+ * the bus transfer mode.
+ * This function is used by the libi2c API.
+ *
+ * @param[in] bushdl Pointer to the libi2c API bus driver data structure.
+ * @param[in] cmd IOCTL request command.
+ * @param[in] arg Arguments needed to fulfill the requested IOCTL command.
+ *
+ * @retval -1 Unknown request command.
+ * @retval >=0 @see bcm2835_spi_set_tfr_mode().
+ */
+int bcm2835_spi_ioctl(rtems_libi2c_bus_t * bushdl, int cmd, void *arg)
+{
+ switch ( cmd ) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+
+ return bcm2835_spi_set_tfr_mode(bushdl,
+ (const rtems_libi2c_tfr_mode_t *)arg
+ );
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
new file mode 100644
index 0000000..1e1a6cc
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
@@ -0,0 +1,85 @@
+/**
+ * @file spi_init.c
+ *
+ * @ingroup raspberrypi_i2c
+ *
+ * @brief Raspberry Pi SPI bus initialization.
+ */
+
+/*
+ * Copyright (c) 2014 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/gpio.h>
+#include <bsp/i2c.h>
+
+static rtems_libi2c_bus_ops_t bcm2835_spi_ops = {
+ init: bcm2835_spi_init,
+ send_start: bcm2835_spi_send_start,
+ send_stop: bcm2835_spi_stop,
+ send_addr: bcm2835_spi_send_addr,
+ read_bytes: bcm2835_spi_read_bytes,
+ write_bytes: bcm2835_spi_write_bytes,
+ ioctl: bcm2835_spi_ioctl
+};
+
+static bcm2835_spi_desc_t bcm2835_spi_bus_desc = {
+ {
+ ops: &bcm2835_spi_ops,
+ size: sizeof(bcm2835_spi_bus_desc)
+ },
+ {
+ initialized: 0
+ }
+};
+
+/* Register drivers here for all the devices
+ * which require access to the SPI bus.
+ *
+ * The libi2c function "rtems_libi2c_register_drv" must be used to
+ * register each device driver, using the received spi bus number.
+ *
+ * This function returns 0 on success. */
+int BSP_spi_register_drivers(int spi_bus_number)
+{
+ int rv = 0;
+
+ return rv;
+}
+
+int BSP_spi_init(void)
+{
+ int rv;
+
+ /* Initialize the libi2c API. */
+ rtems_libi2c_initialize ();
+
+ /* Enable the SPI interface on the Raspberry Pi P1 GPIO header. */
+ gpio_initialize ();
+
+ if ( gpio_select_spi_p1() < 0 ) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ /* Clear SPI control register and clear SPI FIFOs. */
+ BCM2835_REG(BCM2835_SPI_CS) = 0x0000030;
+
+ /* Register the SPI bus. */
+ rv = rtems_libi2c_register_bus("/dev/spi", &(bcm2835_spi_bus_desc.bus_desc));
+
+ if ( rv < 0 ) {
+ return rv;
+ }
+
+ /* Register SPI device drivers. */
+ rv = BSP_spi_register_drivers(rv);
+
+ return rv;
+}
+
+
diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h b/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
new file mode 100644
index 0000000..d8c8b08
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
@@ -0,0 +1,210 @@
+/**
+ * @file gpio.h
+ *
+ * @ingroup raspberrypi_gpio
+ *
+ * @brief Raspberry Pi specific GPIO definitions.
+ */
+
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef LIBBSP_ARM_RASPBERRYPI_GPIO_H
+#define LIBBSP_ARM_RASPBERRYPI_GPIO_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Number of total GPIOS on the Raspberry Pi,
+ * including inaccessible ones.
+ */
+#define GPIO_PIN_COUNT 54
+
+/**
+ * @brief Highest GPIO index directly accessible on the Raspberry Pi board.
+ */
+#define GPIO_EXTERNAL_TOP_PIN 32
+
+/**
+ * @brief The set of possible configurations for a GPIO pull-up resistor.
+ *
+ * Enumerated type to define the possible pull-up resistor configuratons
+ * for an input pin.
+ */
+typedef enum
+{
+ PULL_UP=1,
+ PULL_DOWN,
+ NO_PULL_RESISTOR
+} rpi_gpio_input_mode;
+
+/**
+ * @brief The set of possible functions a pin can have.
+ *
+ * Enumerated type to define a pin function.
+ */
+typedef enum
+{
+ DIGITAL_INPUT=0,
+ DIGITAL_OUTPUT,
+ ALT_FUNC_5,
+ ALT_FUNC_4,
+ ALT_FUNC_0,
+ ALT_FUNC_1,
+ ALT_FUNC_2,
+ ALT_FUNC_3,
+
+ NOT_USED
+} rpi_pin;
+
+/**
+ * @brief The set of possible interrupts an input pin can generate.
+ *
+ * Enumerated type to define an input pin interrupt.
+ */
+typedef enum
+{
+ FALLING_EDGE,
+ RISING_EDGE,
+ BOTH_EDGES,
+ LOW_LEVEL,
+ HIGH_LEVEL,
+ BOTH_LEVELS,
+ NONE
+} gpio_interrupt;
+
+/**
+ * @brief Object containing relevant information to a interrupt handler.
+ *
+ * Encapsulates relevant data for a GPIO interrupt handler.
+ */
+typedef struct
+{
+ int pin_number;
+
+ void (*handler) (void);
+
+ int debouncing_tick_count;
+
+ rtems_interval last_isr_tick;
+
+} handler_arguments;
+
+/**
+ * @brief Object containing information on a GPIO pin.
+ *
+ * Encapsulates relevant data about a GPIO pin.
+ */
+typedef struct
+{
+ /* The pin type */
+ rpi_pin pin_type;
+
+ /* Interrupt handler arguments*/
+ handler_arguments h_args;
+
+ gpio_interrupt enabled_interrupt;
+
+ /* GPIO input pin mode. */
+ rpi_gpio_input_mode input_mode;
+
+} rpi_gpio_pin;
+
+/** @} */
+
+/**
+ * @name gpio Usage
+ *
+ * @{
+ */
+
+/**
+ * @brief Initializes the GPIO API.
+ */
+extern void gpio_initialize(void);
+
+/**
+ * @brief Turns on the given pin.
+ */
+extern rtems_status_code gpio_set(int pin);
+
+/**
+ * @brief Turns off the given pin.
+ */
+extern rtems_status_code gpio_clear(int pin);
+
+/**
+ * @brief Returns the current value of a GPIO pin.
+ */
+extern int gpio_get_value(int pin);
+
+/**
+ * @brief Selects a GPIO pin for a specific function.
+ */
+extern rtems_status_code gpio_select_pin(int pin, rpi_pin type);
+
+/**
+ * @brief Setups a JTAG pin configuration.
+ */
+extern rtems_status_code gpio_select_jtag(void);
+
+/**
+ * @brief Setups the SPI interface on the RPI P1 GPIO header.
+ */
+extern rtems_status_code gpio_select_spi_p1(void);
+
+/**
+ * @brief Setups the I2C interface on the main (P1) GPIO pin header (rev2).
+ */
+extern rtems_status_code gpio_select_i2c_p1_rev2(void);
+
+/**
+ * @brief Configures a input GPIO pin pull-up resistor.
+ */
+extern rtems_status_code gpio_input_mode(int pin, rpi_gpio_input_mode mode);
+
+/**
+ * @brief Configures several input GPIO pins to the same pull-up resistor setup.
+ */
+extern rtems_status_code
+gpio_setup_input_mode(int *pin, int pin_count, rpi_gpio_input_mode mode);
+
+/**
+ * @brief Discards any configuration made on this pin.
+ */
+extern rtems_status_code gpio_disable_pin(int dev_pin);
+
+/**
+ * @brief Debouces a switch by requiring a number of clock ticks to
+ * pass between interruts.
+ */
+extern rtems_status_code gpio_debounce_switch(int pin, int ticks);
+
+/**
+ * @brief Enables interrupts on the given GPIO pin.
+ */
+extern rtems_status_code gpio_enable_interrupt(
+int dev_pin,
+gpio_interrupt interrupt,
+void (*handler) (void)
+);
+
+/**
+ * @brief Disables any interrupt enabled on the given GPIO pin.
+ */
+extern rtems_status_code gpio_disable_interrupt(int dev_pin);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_RASPBERRYPI_GPIO_H */
diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/i2c.h b/c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
new file mode 100644
index 0000000..3224048
--- /dev/null
+++ b/c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
@@ -0,0 +1,183 @@
+/**
+ * @file i2c.h
+ *
+ * @ingroup raspberrypi_i2c
+ *
+ * @brief Raspberry Pi specific I2C and SPI definitions.
+ */
+
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef LIBBSP_ARM_RASPBERRYPI_I2C_H
+#define LIBBSP_ARM_RASPBERRYPI_I2C_H
+
+#include <rtems/libi2c.h>
+
+/**
+ * @name SPI constants.
+ *
+ * @{
+ */
+
+/**
+ * @brief GPU processor core clock rate in Hz.
+ *
+ * Unless configured otherwise on a "config.txt" file present on the SD card
+ * the GPU defaults to 250 MHz. Currently only 250 MHz is supported.
+ */
+
+/* TODO: It would be nice if this value could be probed at startup, probably
+ * using the Mailbox interface since the usual way of setting this on
+ * the hardware is through a "config.txt" text file on the SD card.
+ * Having this setup on the configure.ac script would require changing
+ * the same setting on two different places. */
+#define GPU_CORE_CLOCK_RATE 250000000
+
+/** @} */
+
+/**
+ * @name SPI data structures.
+ *
+ * @{
+ */
+
+/**
+ * @brief Object containing the SPI bus configuration settings.
+ *
+ * Encapsulates the current SPI bus configuration.
+ */
+typedef struct {
+ int initialized;
+ uint8_t bytes_per_char;
+
+ /* Shift to be applied on data transfers with
+ * least significative bit first (LSB) devices. */
+ uint8_t bit_shift;
+ uint32_t dummy_char;
+
+ /* If set to 0 uses 3-wire SPI, with 2 separate data lines (MOSI and MISO),
+ * if set to 1 uses 2-wire SPI, where the MOSI data line doubles as the
+ * slave out (SO) and slave in (SI) data lines. */
+ int bidirectional;
+ uint32_t current_slave_addr;
+ rtems_id irq_sema_id;
+ int irq_write;
+} bcm2835_spi_softc_t;
+
+typedef struct {
+ rtems_libi2c_bus_t bus_desc;
+ bcm2835_spi_softc_t softc;
+} bcm2835_spi_desc_t;
+
+/** @} */
+
+/**
+ * @name SPI directives.
+ *
+ * @{
+ */
+
+rtems_status_code bcm2835_spi_init(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code bcm2835_spi_send_start(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code bcm2835_spi_stop(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code
+bcm2835_spi_send_addr(rtems_libi2c_bus_t * bushdl, uint32_t addr, int rw);
+
+int bcm2835_spi_read_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+);
+
+int bcm2835_spi_write_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes);
+
+int bcm2835_spi_ioctl(rtems_libi2c_bus_t * bushdl, int cmd, void *arg);
+
+int BSP_spi_register_drivers(int spi_bus_number);
+
+int BSP_spi_init(void);
+
+/** @} */
+
+/**
+ * @name I2C constants.
+ *
+ * @{
+ */
+
+
+/**
+ * @brief BSC controller core clock rate in Hz.
+ *
+ * This is set to 150 MHz as per the BCM2835 datasheet.
+ */
+#define BSC_CORE_CLK_HZ 150000000
+
+/** @} */
+
+/**
+ * @name I2C data structures.
+ *
+ * @{
+ */
+
+typedef struct {
+ int initialized;
+ rtems_id irq_sema_id;
+} bcm2835_i2c_softc_t;
+
+typedef struct {
+ rtems_libi2c_bus_t bus_desc;
+ bcm2835_i2c_softc_t softc;
+} bcm2835_i2c_desc_t;
+
+/** @} */
+
+/**
+ * @name I2C directives.
+ *
+ * @{
+ */
+
+rtems_status_code bcm2835_i2c_init(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code bcm2835_i2c_send_start(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code bcm2835_i2c_stop(rtems_libi2c_bus_t * bushdl);
+
+rtems_status_code
+bcm2835_i2c_send_addr(rtems_libi2c_bus_t * bushdl, uint32_t addr, int rw);
+
+int bcm2835_i2c_read_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+);
+
+int bcm2835_i2c_write_bytes(
+rtems_libi2c_bus_t * bushdl,
+unsigned char *bytes,
+int nbytes
+);
+
+int bcm2835_i2c_ioctl(rtems_libi2c_bus_t * bushdl, int cmd, void *arg);
+
+int BSP_i2c_register_drivers(int i2c_bus_number);
+
+int BSP_i2c_init(void);
+
+/** @} */
+
+#endif /* LIBBSP_ARM_RASPBERRYPI_I2C_H */
diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/irq.h b/c/src/lib/libbsp/arm/raspberrypi/include/irq.h
index 8436c2d..fb5f90e 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/include/irq.h
+++ b/c/src/lib/libbsp/arm/raspberrypi/include/irq.h
@@ -1,5 +1,5 @@
/**
- * @file
+ * @file irq.h
*
* @ingroup raspberrypi_interrupt
*
@@ -7,7 +7,8 @@
*/
/**
- * Copyright (c) 2013 Alan Cudmore
+ * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com>
+ * Copyright (c) 2013 Alan Cudmore
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -62,6 +63,7 @@
#define BSP_IRQ_COUNT (BCM2835_INTC_TOTAL_IRQ)
+rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector);
void raspberrypi_set_exception_handler(Arm_symbolic_exception_name exception,
void (*handler)(void));
diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/raspberrypi.h b/c/src/lib/libbsp/arm/raspberrypi/include/raspberrypi.h
index 4cc7eec..2e902c6 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/include/raspberrypi.h
+++ b/c/src/lib/libbsp/arm/raspberrypi/include/raspberrypi.h
@@ -1,6 +1,5 @@
-
/**
- * @file
+ * @file raspberrypi.h
*
* @ingroup raspberrypi_reg
*
@@ -8,7 +7,8 @@
*/
/*
- * Copyright (c) 2013 Alan Cudmore.
+ * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com>
+ * Copyright (c) 2013 Alan Cudmore.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -79,8 +79,16 @@
#define BCM2835_GPIO_GPFSEL1 (BCM2835_GPIO_REGS_BASE+0x04)
#define BCM2835_GPIO_GPSET0 (BCM2835_GPIO_REGS_BASE+0x1C)
#define BCM2835_GPIO_GPCLR0 (BCM2835_GPIO_REGS_BASE+0x28)
+#define BCM2835_GPIO_GPLEV0 (BCM2835_GPIO_REGS_BASE+0x34)
+#define BCM2835_GPIO_GPEDS0 (BCM2835_GPIO_REGS_BASE+0x40)
+#define BCM2835_GPIO_GPREN0 (BCM2835_GPIO_REGS_BASE+0x4C)
+#define BCM2835_GPIO_GPFEN0 (BCM2835_GPIO_REGS_BASE+0x58)
+#define BCM2835_GPIO_GPHEN0 (BCM2835_GPIO_REGS_BASE+0x64)
+#define BCM2835_GPIO_GPLEN0 (BCM2835_GPIO_REGS_BASE+0x70)
+#define BCM2835_GPIO_GPAREN0 (BCM2835_GPIO_REGS_BASE+0x7C)
+#define BCM2835_GPIO_GPAFEN0 (BCM2835_GPIO_REGS_BASE+0x88)
#define BCM2835_GPIO_GPPUD (BCM2835_GPIO_REGS_BASE+0x94)
-#define BCM2835_GPIO_GPPUDCLK0 (BCM2835_GPIO_REGS_BASE+0x98)
+#define BCM2835_GPIO_GPPUDCLK0 (BCM2835_GPIO_REGS_BASE+0x98)
/** @} */
@@ -107,14 +115,12 @@
/** @} */
-
/**
* @name UART 0 (PL011) Registers
*
* @{
*/
-
#define BCM2835_UART0_BASE (0x20201000)
#define BCM2835_UART0_DR (BCM2835_UART0_BASE+0x00)
@@ -145,9 +151,68 @@
#define BCM2835_UART0_ICR_RX 0x10
#define BCM2835_UART0_ICR_TX 0x20
+/** @} */
+
+/**
+ * @name I2C (BSC) Registers
+ *
+ * @{
+ */
+
+#define BCM2835_I2C_BASE (0x20804000)
+
+#define BCM2835_I2C_C (BCM2835_I2C_BASE+0x00)
+#define BCM2835_I2C_S (BCM2835_I2C_BASE+0x04)
+#define BCM2835_I2C_DLEN (BCM2835_I2C_BASE+0x08)
+#define BCM2835_I2C_A (BCM2835_I2C_BASE+0x0C)
+#define BCM2835_I2C_FIFO (BCM2835_I2C_BASE+0x10)
+#define BCM2835_I2C_DIV (BCM2835_I2C_BASE+0x14)
+#define BCM2835_I2C_DEL (BCM2835_I2C_BASE+0x18)
+#define BCM2835_I2C_CLKT (BCM2835_I2C_BASE+0x1C)
/** @} */
+/**
+ * @name SPI Registers
+ *
+ * @{
+ */
+
+#define BCM2835_SPI_BASE (0x20204000)
+
+#define BCM2835_SPI_CS (BCM2835_SPI_BASE+0x00)
+#define BCM2835_SPI_FIFO (BCM2835_SPI_BASE+0x04)
+#define BCM2835_SPI_CLK (BCM2835_SPI_BASE+0x08)
+#define BCM2835_SPI_DLEN (BCM2835_SPI_BASE+0x0C)
+#define BCM2835_SPI_LTOH (BCM2835_SPI_BASE+0x10)
+#define BCM2835_SPI_DC (BCM2835_SPI_BASE+0x14)
+
+/** @} */
+
+/**
+ * @name I2C/SPI slave BSC Registers
+ *
+ * @{
+ */
+
+#define BCM2835_I2C_SPI_BASE (0x20214000)
+
+#define BCM2835_I2C_SPI_DR (BCM2835_I2C_SPI_BASE+0x00)
+#define BCM2835_I2C_SPI_RSR (BCM2835_I2C_SPI_BASE+0x04)
+#define BCM2835_I2C_SPI_SLV (BCM2835_I2C_SPI_BASE+0x08)
+#define BCM2835_I2C_SPI_CR (BCM2835_I2C_SPI_BASE+0x0C)
+#define BCM2835_I2C_SPI_FR (BCM2835_I2C_SPI_BASE+0x10)
+#define BCM2835_I2C_SPI_IFLS (BCM2835_I2C_SPI_BASE+0x14)
+#define BCM2835_I2C_SPI_IMSC (BCM2835_I2C_SPI_BASE+0x18)
+#define BCM2835_I2C_SPI_RIS (BCM2835_I2C_SPI_BASE+0x1C)
+#define BCM2835_I2C_SPI_MIS (BCM2835_I2C_SPI_BASE+0x20)
+#define BCM2835_I2C_SPI_ICR (BCM2835_I2C_SPI_BASE+0x24)
+#define BCM2835_I2C_SPI_DMACR (BCM2835_I2C_SPI_BASE+0x28)
+#define BCM2835_I2C_SPI_TDR (BCM2835_I2C_SPI_BASE+0x2C)
+#define BCM2835_I2C_SPI_GPUSTAT (BCM2835_I2C_SPI_BASE+0x30)
+#define BCM2835_I2C_SPI_HCTRL (BCM2835_I2C_SPI_BASE+0x34)
+
+/** @} */
/**
* @name IRQ Registers
@@ -170,7 +235,6 @@
/** @} */
-
/**
* @name GPU Timer Registers
*
@@ -194,7 +258,6 @@
/** @} */
-
/** @} */
#endif /* LIBBSP_ARM_RASPBERRYPI_RASPBERRYPI_H */
diff --git a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
index 4132ef9..c2c7d89 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
+++ b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
@@ -1,5 +1,5 @@
/**
- * @file
+ * @file irq.c
*
* @ingroup raspberrypi_interrupt
*
@@ -7,6 +7,8 @@
*/
/*
+ * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com>
+ *
* Copyright (c) 2009
* embedded brains GmbH
* Obere Lagerstr. 30
@@ -52,22 +54,47 @@ void bsp_interrupt_dispatch(void)
rtems_vector_number vector = 255;
/* ARM timer */
- if (BCM2835_REG(BCM2835_IRQ_BASIC) && 0x1)
+ if ( BCM2835_REG(BCM2835_IRQ_BASIC) & 0x1 )
{
vector = BCM2835_IRQ_ID_TIMER_0;
-
}
/* UART 0 */
- else if ( BCM2835_REG(BCM2835_IRQ_BASIC) && BCM2835_BIT(19))
+ else if ( BCM2835_REG(BCM2835_IRQ_BASIC) & BCM2835_BIT(19) )
{
vector = BCM2835_IRQ_ID_UART;
}
+ /* GPIO 0*/
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(17) )
+ {
+ vector = BCM2835_IRQ_ID_GPIO_0;
+ }
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(18) )
+ {
+ vector = BCM2835_IRQ_ID_GPIO_1;
+ }
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(19) )
+ {
+ vector = BCM2835_IRQ_ID_GPIO_2;
+ }
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(20) )
+ {
+ vector = BCM2835_IRQ_ID_GPIO_3;
+ }
+ /* I2C */
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(21) )
+ {
+ vector = BCM2835_IRQ_ID_I2C;
+ }
+ /* SPI */
+ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(22) )
+ {
+ vector = BCM2835_IRQ_ID_SPI;
+ }
if ( vector < 255 )
{
bsp_interrupt_handler_dispatch(vector);
}
-
}
rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
@@ -76,7 +103,7 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
rtems_interrupt_disable(level);
- /* ARM Timer */
+ /* ARM Timer */
if ( vector == BCM2835_IRQ_ID_TIMER_0 )
{
BCM2835_REG(BCM2835_IRQ_ENABLE_BASIC) = 0x1;
@@ -85,8 +112,38 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
else if ( vector == BCM2835_IRQ_ID_UART )
{
BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(25);
-
}
+ /* GPIO 0 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_0 )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(17);
+ }
+ /* GPIO 1 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_1 )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(18);
+ }
+ /* GPIO 2 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_2 )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(19);
+ }
+ /* GPIO 3 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_3 )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(20);
+ }
+ /* I2C */
+ else if ( vector == BCM2835_IRQ_ID_I2C )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(21);
+ }
+ /* SPI */
+ else if ( vector == BCM2835_IRQ_ID_SPI )
+ {
+ BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(22);
+ }
+
rtems_interrupt_enable(level);
return RTEMS_SUCCESSFUL;
@@ -106,12 +163,42 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
{
BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(25);
}
+ /* GPIO 0 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_0 )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(17);
+ }
+ /* GPIO 1 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_1 )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(18);
+ }
+ /* GPIO 2 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_2 )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(19);
+ }
+ /* GPIO 3 */
+ else if ( vector == BCM2835_IRQ_ID_GPIO_3 )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(20);
+ }
+ /* I2C */
+ else if ( vector == BCM2835_IRQ_ID_I2C )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(21);
+ }
+ /* SPI */
+ else if ( vector == BCM2835_IRQ_ID_SPI )
+ {
+ BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(22);
+ }
+
rtems_interrupt_enable(level);
return RTEMS_SUCCESSFUL;
}
-
void bsp_interrupt_handler_default(rtems_vector_number vector)
{
printk("spurious interrupt: %u\n", vector);
diff --git a/c/src/lib/libbsp/arm/raspberrypi/preinstall.am b/c/src/lib/libbsp/arm/raspberrypi/preinstall.am
index 70259e2..f9a87e0 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/preinstall.am
+++ b/c/src/lib/libbsp/arm/raspberrypi/preinstall.am
@@ -130,6 +130,14 @@ $(PROJECT_INCLUDE)/bsp/raspberrypi.h: include/raspberrypi.h $(PROJECT_INCLUDE)/b
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/raspberrypi.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/raspberrypi.h
+$(PROJECT_INCLUDE)/bsp/gpio.h: include/gpio.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gpio.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gpio.h
+
+$(PROJECT_INCLUDE)/bsp/i2c.h: include/i2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/i2c.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/i2c.h
+
$(PROJECT_INCLUDE)/libcpu/cache_.h: ../../../libcpu/arm/shared/include/cache_.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache_.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache_.h
diff --git a/c/src/lib/libbsp/arm/raspberrypi/startup/bspstart.c b/c/src/lib/libbsp/arm/raspberrypi/startup/bspstart.c
index c5786bf..5ca6612 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/startup/bspstart.c
+++ b/c/src/lib/libbsp/arm/raspberrypi/startup/bspstart.c
@@ -1,5 +1,5 @@
/**
- * @file
+ * @file bspstart.c
*
* @ingroup arm_start
*
@@ -7,7 +7,8 @@
*/
/*
- * Copyright (c) 2013 by Alan Cudmore
+ * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com>
+ * Copyright (c) 2013 by Alan Cudmore
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -22,8 +23,18 @@
#include <bsp/linker-symbols.h>
#include <bsp/stackalloc.h>
#include <bsp/raspberrypi.h>
+#include <bsp/i2c.h>
+
+void bsp_predriver_hook(void)
+{
+ if ( BSP_ENABLE_SPI == 1 )
+ BSP_spi_init();
+
+ if ( BSP_ENABLE_I2C == 1 )
+ BSP_i2c_init();
+}
void bsp_start(void)
{
- bsp_interrupt_initialize();
+ bsp_interrupt_initialize();
}
--
2.0.4
More information about the devel
mailing list