[PATCH] Add GPIO, I2C and SPI support for the RPi BSP

Joel Sherrill joel.sherrill at oarcorp.com
Fri Oct 31 15:35:13 UTC 2014


On 10/31/2014 9:25 AM, Gedare Bloom wrote:
> Thanks, I'll leave detailed comments to the experts but noticed a few things.
I'm going to pile on Gedare's comment and add that this should
not introduce any warnings.

The Pi already has warnings about an abort handler (shared by two
other ARM BSPs) which Sebastian pointed out indicates something
that is out of date relative to other ARM BSPs.

> On Fri, Oct 31, 2014 at 7:56 AM, Andre Marques
> <andre.lousa.marques at gmail.com> wrote:
>> Aditional documentation can be found in the RTEMS wiki
>>
>> http://www.rtems.org/wiki/index.php/Raspberry_Pi_BSP_Peripherals
>>
>> and on my GSOC development blog
>>
>> http://asuolgsoc2014.wordpress.com/2014/08/18/testing-the-project/
>>
>> Device drivers and test cases used to test this work were moved to a github repository
>>
>> https://github.com/asuol/RTEMS_rpi_testing
>> ---
>>  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       | 745 +++++++++++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c         | 427 ++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c    |  78 +++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c         | 564 ++++++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c    |  83 +++
>>  c/src/lib/libbsp/arm/raspberrypi/include/gpio.h    | 198 ++++++
>>  c/src/lib/libbsp/arm/raspberrypi/include/i2c.h     | 166 +++++
>>  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, 2475 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 839c8de..81dc196 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
>> @@ -119,11 +120,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..ef83c9d 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],[*],[1])
>> +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..d245339
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>> @@ -0,0 +1,745 @@
>> +/**
>> + * @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 <stdlib.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;
>> +
>> +/**
>> + * @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");
> We prefer to see nested scopes within a function (even with just one
> line) have explicit braces { }.
>
>> +}
>> +
>> +/**
>> + * @brief Initializes the GPIO API.
>> + *        Allocates space to the gpio_pin array 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;
>> +
>> +  gpio_pin = (rpi_gpio_pin *) malloc(GPIO_PIN_COUNT * sizeof(rpi_gpio_pin));
>> +
>> +  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;
>> +  }
> This entire function can be eliminated, dynamic allocation and
> initialization are unnecessary since you know the size and initial
> values to use.
>
>> +}
>> +
>> +/**
>> + * @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 0 Pin was set successfully.
>> + * @retval -1 The received pin is not configured as an digital output.
>> + */
>> +int gpio_set(int pin)
>> +{
> I'd add some asserts here and in other places that use 'pin', like..
> assert(pin > 0);
> assert(pin < =PIN_COUNT);
> Or whatever is sensible.
>
>
>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>> +    return -1;
>> +
>> +  BCM2835_REG(BCM2835_GPIO_GPSET0) = (1 << pin);
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pin was cleared successfully.
>> + * @retval -1 The received pin is not configured as an digital output.
>> + */
>> +int gpio_clear(int pin)
>> +{
>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>> +    return -1;
>> +
>> +  BCM2835_REG(BCM2835_GPIO_GPCLR0) = (1 << pin);
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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_val(int pin)
> avoid abbreviations
>
>> +{
>> +  return BCM2835_REG(BCM2835_GPIO_GPLEV0) &= (1 << (pin));
> Do you intend for the assignment as a side-effect? If so, it should be
> documented.
>
>> +}
>> +
>> +/**
>> + * @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 0 Pin was configured successfully.
>> + * @retval -1 The received pin is already being used, or unknown function.
>> + */
>> +int gpio_select_pin(int pin, rpi_pin type)
>> +{
>> +  /* 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 -1;
>> +
> You could simplify the following by defining the enum rpi_pin like...
> DIGITAL_OUTPUT = 1,
> ALT_FUNC_5,
> ALT_FUNC_4,
> ALT_FUNC_0,
> ...
>
> Then use
>  *(pin_addr) |= SELECT_PIN_FUNCTION(type, pin);
>
>
> Also, is ALT_FUNC_3 identical to DIGITAL_INPUT?
>
>
>> +  /* Sets pin function select bits as zero (DIGITAL_INPUT).*/
>> +  *(pin_addr) &= ~SELECT_PIN_FUNCTION(7, pin);
>> +
>> +  switch ( type ) {
>> +    case DIGITAL_INPUT:
>> +
>> +      /* Digital input is set by default before this switch. */
>> +
>> +      break;
>> +
>> +    case DIGITAL_OUTPUT:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(1, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_0:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(4, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_1:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(5, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_2:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(6, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_3:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(7, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_4:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(3, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_5:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(2, pin);
>> +
>> +      break;
>> +
>> +    default:
>> +      return -1;
>> +  }
>> +
>> +  /* 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 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pull resistor successfully configured.
>> + * @retval -1 Unknown pull resistor mode.
>> + */
>> +static int
>> +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 -1;
>> +  }
>> +
>> +  /* 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 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pull resistor successfully configured.
>> + * @retval -1 @see set_input_mode().
>> + */
>> +int gpio_input_mode(int pin, rpi_gpio_input_mode mode)
>> +{
>> +  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 0;
>> +
>> +  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 0 Pull resistor successfully configured.
>> + * @retval -1 Unknown pull resistor mode.
>> + */
>> +int 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 > 32 )
> Use the max macro instead of literal 32
>
>> +    return -1;
> Consider using more informative error codes.
>
>> +
>> +  /* 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++ ) {
>> +    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 0;
>> +
>> +  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 0 Pin successfully disabled on the API.
>> + * @retval -1 Could not disable an ative interrupt on this pin.
>> + */
>> +int gpio_disable_pin(int dev_pin)
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *pin;
>> +
>> +  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);
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL )
>> +      return -1;
>> +  }
>> +
>> +  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 0 JTAG interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_jtag(void)
>> +{
>> +  /* Setup gpio 4 alt5 ARM_TDI. */
>> +  if ( gpio_select_pin(4, ALT_FUNC_5) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 22 alt4 ARM_TRST. */
>> +  if ( gpio_select_pin(22, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 24 alt4 ARM_TDO. */
>> +  if ( gpio_select_pin(24, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 25 alt4 ARM_TCK. */
>> +  if ( gpio_select_pin(25, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 27 alt4 ARM_TMS. */
>> +  if ( gpio_select_pin(27, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 SPI interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_spi_p1(void)
>> +{
>> +  /* SPI master 0 MISO data line. */
>> +  if ( gpio_select_pin(9, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 MOSI data line. */
>> +  if ( gpio_select_pin(10, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 SCLK clock line. */
>> +  if ( gpio_select_pin(11, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 CE_0 chip enable line. */
>> +  if ( gpio_select_pin(8, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 CE_1 chip enable line. */
>> +  if ( gpio_select_pin(7, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 JTAG interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_i2c_p1_rev2(void)
>> +{
>> +  int pins[] = {2,3};
>> +
>> +  /* I2C BSC1 SDA data line. */
>> +  if ( gpio_select_pin(2, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* I2C BSC1 SCL clock line. */
>> +  if ( gpio_select_pin(3, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
> Does it make sense to have gpio_select_pins(int[], type[])?
>
>> +  /* Enable pins 2 and 3 pull-up resistors. */
>> +  if ( gpio_setup_input_mode(pins, 2, PULL_UP) < 0 )
>> +    return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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. Probable switch bounce.
>> + */
>> +static int debounce_switch(int dev_pin)
>> +{
>> +  rtems_interval time;
>> +  rpi_gpio_pin *pin;
>> +
>> +  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 clears 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) ();
> Probably should pass the handler_args to the 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 0 De-bounce function successfully attached to the pin.
>> + * @retval -1 The current pin is not configured as a digital input, hence
>> + *            it can not be connected to a switch.
>> + */
>> +int gpio_debounce_switch(int dev_pin, int ticks)
>> +{
>> +  if ( gpio_pin[dev_pin-1].pin_type != DIGITAL_INPUT )
>> +    return -1;
>> +
>> +  gpio_pin[dev_pin-1].h_args.debouncing_tick_count = ticks;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Interrupt successfully enabled for this pin.
>> + * @retval -1 Could not replace the currently active interrupt on this pin, or
>> + *            unknown @var interrupt.
>> + */
>> +int gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler)(void))
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *pin;
>> +
>> +  /* Only consider GPIO pins up to 31. */
>> +  if ( dev_pin > 31 )
> Use macro,
>
>> +    return -1;
>> +
>> +  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 -1;
>> +  }
>> +
>> +  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 -1;
>> +
>> +  switch ( interrupt ) {
>> +    case FALLING_EDGE:
>> +
>> +      /* Enables asynchronous falling edge detection. */
>> +      BCM2835_REG(BCM2835_GPIO_GPAFEN0) |= (1 << dev_pin);
>> +
>> +      break;
> Remove the blank lines in each case to group the cases together more compactly.
>> +
>> +    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 0;
> Does this mean disabled line? I think you should let it fall through
> to assign pin->enabled_interrupt.
>
>> +
>> +    default:
>> +      return -1;
> This error case should be detected sooner?
>
>> +  }
>> +
>> +  pin->enabled_interrupt = interrupt;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Interrupt successfully disabled for this pin.
>> + * @retval -1 Could not remove the current interrupt handler or could not
>> + *            recognise the current active interrupt on this pin.
>> + */
>> +int gpio_disable_interrupt(int dev_pin)
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *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 0;
> Probably still want to remove the handler?
>
>> +
>> +    default:
>> +      return -1;
>> +  }
>> +
>> +  /* 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 -1;
>> +
>> +  pin->enabled_interrupt = NONE;
>> +
>> +  return 0;
>> +}
>> 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..838add4
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
>> @@ -0,0 +1,427 @@
>> +/**
>> + * @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>
>> +
>> +/**
>> + * @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;
>> +
>> +  /* Calculates an initial clock divider. */
>> +  divider = BSC_CORE_CLK_HZ / clock_hz;
>> +
>> +  if ( divider < 0 || divider > 0xFFFF )
>> +    return RTEMS_INVALID_NUMBER;
> This check is superfluous -- always false.
>
>> +
>> +  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 / 0xFFFF;
>> +  uint16_t dlen_buffer_size;
>> +
>> +  /* If the buffer size is a multiple of the max size per transfer,
>> +   * round up the transfer count. */
>> +  if ( buffer_size % 0xFFFF != 0 )
>> +    transfer_count++;
>> +
> You can calculate transfer_count more efficiently with
> transfer_count = (buffer_size + 0xFFFE) / 0xFFFF;
>
> In general, ceil(x/n) = (x + (n-1))/n
>
>> +  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 )
> Is the semaphore accounted for in confdefs?
>
>> +            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--;
> Is this right? It seems like transfer_count--; should go after the next }.
>
>> +    }
>> +  } 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);
> Break lines > 80 characters
>
> I have to stop reviewing here. Skimming the rest, there are some more
> issues repeating what I pointed out above.
>
>> +  }
>> +
>> +  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..f231537
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
>> @@ -0,0 +1,78 @@
>> +/**
>> + * @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>
>> +
>> +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;
>> +
>> +  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..c260f19
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
>> @@ -0,0 +1,564 @@
>> +/**
>> + * @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>
>> +
>> +/**
>> + * @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;
>> +
>> +  /* Calculates an initial clock divider. */
>> +  divider = GPU_CORE_CLOCK_RATE / clock_hz;
>> +
>> +  if ( divider < 0 || divider > 65536 )
>> +    return RTEMS_INVALID_NUMBER;
>> +
>> +  /* 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;
>> +
>> +  /* FIXME: 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..cde59f1
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
>> @@ -0,0 +1,83 @@
>> +/**
>> + * @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..3b4e178
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
>> @@ -0,0 +1,198 @@
>> +/**
>> + * @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 the internal ones.
>> + */
>> +#define GPIO_PIN_COUNT 54
>> +
>> +/**
>> + * @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,
>> +  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,
>> +  DIGITAL_OUTPUT,
>> +  ALT_FUNC_0,
>> +  ALT_FUNC_1,
>> +  ALT_FUNC_2,
>> +  ALT_FUNC_3,
>> +  ALT_FUNC_4,
>> +  ALT_FUNC_5,
>> +  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 int gpio_set(int pin);
>> +
>> +/**
>> + * @brief Turns off the given pin.
>> + */
>> +extern int gpio_clear(int pin);
>> +
>> +/**
>> + * @brief Returns the current value of a GPIO pin.
>> + */
>> +extern int gpio_get_val(int pin);
>> +
>> +/**
>> + * @brief Selects a GPIO pin for a specific function.
>> + */
>> +extern int gpio_select_pin(int pin, rpi_pin type);
>> +
>> +/**
>> + * @brief Setups a JTAG pin configuration.
>> + */
>> +extern int gpio_select_jtag(void);
>> +
>> +/**
>> + * @brief Setups the SPI interface on the RPI P1 GPIO header.
>> + */
>> +extern int gpio_select_spi_p1(void);
>> +
>> +/**
>> + * @brief Setups the I2C interface on the main (P1) GPIO pin header (rev2).
>> + */
>> +extern int gpio_select_i2c_p1_rev2(void);
>> +
>> +/**
>> + * @brief Configures a input GPIO pin pull-up resistor.
>> + */
>> +extern int gpio_input_mode(int pin, rpi_gpio_input_mode mode);
>> +
>> +/**
>> + * @brief Configures several input GPIO pins to the same pull-up resistor setup.
>> + */
>> +extern int gpio_setup_input_mode(int *pin, int pin_count, rpi_gpio_input_mode mode);
>> +
>> +/**
>> + * @brief Discards any configuration made on this pin.
>> + */
>> +extern int gpio_disable_pin(int dev_pin);
>> +
>> +/**
>> + * @brief Debouces a switch by requiring a number of clock ticks to pass between interruts.
>> + */
>> +extern int gpio_debounce_switch(int pin, int ticks);
>> +
>> +/**
>> + * @brief Enables interrupts on the given GPIO pin.
>> + */
>> +extern int gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler) (void));
>> +
>> +/**
>> + * @brief Disables any interrupt enabled on the given GPIO pin.
>> + */
>> +extern int 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..bdc53ef
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
>> @@ -0,0 +1,166 @@
>> +/**
>> + * @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();
>>  }
>> --
>> 1.8.5.5
>>
>> _______________________________________________
>> devel mailing list
>> devel at rtems.org
>> http://lists.rtems.org/mailman/listinfo/devel
> On Fri, Oct 31, 2014 at 7:56 AM, Andre Marques
> <andre.lousa.marques at gmail.com> wrote:
>> Aditional documentation can be found in the RTEMS wiki
>>
>> http://www.rtems.org/wiki/index.php/Raspberry_Pi_BSP_Peripherals
>>
>> and on my GSOC development blog
>>
>> http://asuolgsoc2014.wordpress.com/2014/08/18/testing-the-project/
>>
>> Device drivers and test cases used to test this work were moved to a github repository
>>
>> https://github.com/asuol/RTEMS_rpi_testing
>> ---
>>  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       | 745 +++++++++++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c         | 427 ++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c    |  78 +++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c         | 564 ++++++++++++++++
>>  c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c    |  83 +++
>>  c/src/lib/libbsp/arm/raspberrypi/include/gpio.h    | 198 ++++++
>>  c/src/lib/libbsp/arm/raspberrypi/include/i2c.h     | 166 +++++
>>  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, 2475 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 839c8de..81dc196 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
>> @@ -119,11 +120,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..ef83c9d 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],[*],[1])
>> +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..d245339
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/gpio/gpio.c
>> @@ -0,0 +1,745 @@
>> +/**
>> + * @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 <stdlib.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;
>> +
>> +/**
>> + * @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.
>> + *        Allocates space to the gpio_pin array 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;
>> +
>> +  gpio_pin = (rpi_gpio_pin *) malloc(GPIO_PIN_COUNT * sizeof(rpi_gpio_pin));
>> +
>> +  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 0 Pin was set successfully.
>> + * @retval -1 The received pin is not configured as an digital output.
>> + */
>> +int gpio_set(int pin)
>> +{
>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>> +    return -1;
>> +
>> +  BCM2835_REG(BCM2835_GPIO_GPSET0) = (1 << pin);
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pin was cleared successfully.
>> + * @retval -1 The received pin is not configured as an digital output.
>> + */
>> +int gpio_clear(int pin)
>> +{
>> +  if (gpio_pin[pin-1].pin_type != DIGITAL_OUTPUT)
>> +    return -1;
>> +
>> +  BCM2835_REG(BCM2835_GPIO_GPCLR0) = (1 << pin);
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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_val(int pin)
>> +{
>> +  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 0 Pin was configured successfully.
>> + * @retval -1 The received pin is already being used, or unknown function.
>> + */
>> +int gpio_select_pin(int pin, rpi_pin type)
>> +{
>> +  /* 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 -1;
>> +
>> +  /* Sets pin function select bits as zero (DIGITAL_INPUT).*/
>> +  *(pin_addr) &= ~SELECT_PIN_FUNCTION(7, pin);
>> +
>> +  switch ( type ) {
>> +    case DIGITAL_INPUT:
>> +
>> +      /* Digital input is set by default before this switch. */
>> +
>> +      break;
>> +
>> +    case DIGITAL_OUTPUT:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(1, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_0:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(4, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_1:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(5, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_2:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(6, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_3:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(7, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_4:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(3, pin);
>> +
>> +      break;
>> +
>> +    case ALT_FUNC_5:
>> +
>> +      *(pin_addr) |= SELECT_PIN_FUNCTION(2, pin);
>> +
>> +      break;
>> +
>> +    default:
>> +      return -1;
>> +  }
>> +
>> +  /* 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 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pull resistor successfully configured.
>> + * @retval -1 Unknown pull resistor mode.
>> + */
>> +static int
>> +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 -1;
>> +  }
>> +
>> +  /* 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 0;
>> +}
>> +
>> +/**
>> + * @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 0 Pull resistor successfully configured.
>> + * @retval -1 @see set_input_mode().
>> + */
>> +int gpio_input_mode(int pin, rpi_gpio_input_mode mode)
>> +{
>> +  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 0;
>> +
>> +  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 0 Pull resistor successfully configured.
>> + * @retval -1 Unknown pull resistor mode.
>> + */
>> +int 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 > 32 )
>> +    return -1;
>> +
>> +  /* 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++ ) {
>> +    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 0;
>> +
>> +  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 0 Pin successfully disabled on the API.
>> + * @retval -1 Could not disable an ative interrupt on this pin.
>> + */
>> +int gpio_disable_pin(int dev_pin)
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *pin;
>> +
>> +  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);
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL )
>> +      return -1;
>> +  }
>> +
>> +  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 0 JTAG interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_jtag(void)
>> +{
>> +  /* Setup gpio 4 alt5 ARM_TDI. */
>> +  if ( gpio_select_pin(4, ALT_FUNC_5) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 22 alt4 ARM_TRST. */
>> +  if ( gpio_select_pin(22, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 24 alt4 ARM_TDO. */
>> +  if ( gpio_select_pin(24, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 25 alt4 ARM_TCK. */
>> +  if ( gpio_select_pin(25, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  /* Setup gpio 27 alt4 ARM_TMS. */
>> +  if ( gpio_select_pin(27, ALT_FUNC_4) < 0 )
>> +      return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 SPI interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_spi_p1(void)
>> +{
>> +  /* SPI master 0 MISO data line. */
>> +  if ( gpio_select_pin(9, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 MOSI data line. */
>> +  if ( gpio_select_pin(10, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 SCLK clock line. */
>> +  if ( gpio_select_pin(11, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 CE_0 chip enable line. */
>> +  if ( gpio_select_pin(8, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* SPI master 0 CE_1 chip enable line. */
>> +  if ( gpio_select_pin(7, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 JTAG interface successfully configured.
>> + * @retval -1 At least one of the required pins is currently occupied.
>> + */
>> +int gpio_select_i2c_p1_rev2(void)
>> +{
>> +  int pins[] = {2,3};
>> +
>> +  /* I2C BSC1 SDA data line. */
>> +  if ( gpio_select_pin(2, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* I2C BSC1 SCL clock line. */
>> +  if ( gpio_select_pin(3, ALT_FUNC_0) < 0 )
>> +      return -1;
>> +
>> +  /* Enable pins 2 and 3 pull-up resistors. */
>> +  if ( gpio_setup_input_mode(pins, 2, PULL_UP) < 0 )
>> +    return -1;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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. Probable switch bounce.
>> + */
>> +static int debounce_switch(int dev_pin)
>> +{
>> +  rtems_interval time;
>> +  rpi_gpio_pin *pin;
>> +
>> +  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 clears 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 0 De-bounce function successfully attached to the pin.
>> + * @retval -1 The current pin is not configured as a digital input, hence
>> + *            it can not be connected to a switch.
>> + */
>> +int gpio_debounce_switch(int dev_pin, int ticks)
>> +{
>> +  if ( gpio_pin[dev_pin-1].pin_type != DIGITAL_INPUT )
>> +    return -1;
>> +
>> +  gpio_pin[dev_pin-1].h_args.debouncing_tick_count = ticks;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Interrupt successfully enabled for this pin.
>> + * @retval -1 Could not replace the currently active interrupt on this pin, or
>> + *            unknown @var interrupt.
>> + */
>> +int gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler)(void))
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *pin;
>> +
>> +  /* Only consider GPIO pins up to 31. */
>> +  if ( dev_pin > 31 )
>> +    return -1;
>> +
>> +  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 -1;
>> +  }
>> +
>> +  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 -1;
>> +
>> +  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 0;
>> +
>> +    default:
>> +      return -1;
>> +  }
>> +
>> +  pin->enabled_interrupt = interrupt;
>> +
>> +  return 0;
>> +}
>> +
>> +/**
>> + * @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 0 Interrupt successfully disabled for this pin.
>> + * @retval -1 Could not remove the current interrupt handler or could not
>> + *            recognise the current active interrupt on this pin.
>> + */
>> +int gpio_disable_interrupt(int dev_pin)
>> +{
>> +  rtems_status_code sc;
>> +  rpi_gpio_pin *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 0;
>> +
>> +    default:
>> +      return -1;
>> +  }
>> +
>> +  /* 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 -1;
>> +
>> +  pin->enabled_interrupt = NONE;
>> +
>> +  return 0;
>> +}
>> 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..838add4
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c
>> @@ -0,0 +1,427 @@
>> +/**
>> + * @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>
>> +
>> +/**
>> + * @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;
>> +
>> +  /* Calculates an initial clock divider. */
>> +  divider = BSC_CORE_CLK_HZ / clock_hz;
>> +
>> +  if ( divider < 0 || divider > 0xFFFF )
>> +    return RTEMS_INVALID_NUMBER;
>> +
>> +  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 / 0xFFFF;
>> +  uint16_t dlen_buffer_size;
>> +
>> +  /* If the buffer size is a multiple of the max size per transfer,
>> +   * round up the transfer count. */
>> +  if ( buffer_size % 0xFFFF != 0 )
>> +    transfer_count++;
>> +
>> +  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..f231537
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c_init.c
>> @@ -0,0 +1,78 @@
>> +/**
>> + * @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>
>> +
>> +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;
>> +
>> +  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..c260f19
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi.c
>> @@ -0,0 +1,564 @@
>> +/**
>> + * @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>
>> +
>> +/**
>> + * @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;
>> +
>> +  /* Calculates an initial clock divider. */
>> +  divider = GPU_CORE_CLOCK_RATE / clock_hz;
>> +
>> +  if ( divider < 0 || divider > 65536 )
>> +    return RTEMS_INVALID_NUMBER;
>> +
>> +  /* 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;
>> +
>> +  /* FIXME: 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..cde59f1
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/i2c/spi_init.c
>> @@ -0,0 +1,83 @@
>> +/**
>> + * @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..3b4e178
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/include/gpio.h
>> @@ -0,0 +1,198 @@
>> +/**
>> + * @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 the internal ones.
>> + */
>> +#define GPIO_PIN_COUNT 54
>> +
>> +/**
>> + * @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,
>> +  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,
>> +  DIGITAL_OUTPUT,
>> +  ALT_FUNC_0,
>> +  ALT_FUNC_1,
>> +  ALT_FUNC_2,
>> +  ALT_FUNC_3,
>> +  ALT_FUNC_4,
>> +  ALT_FUNC_5,
>> +  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 int gpio_set(int pin);
>> +
>> +/**
>> + * @brief Turns off the given pin.
>> + */
>> +extern int gpio_clear(int pin);
>> +
>> +/**
>> + * @brief Returns the current value of a GPIO pin.
>> + */
>> +extern int gpio_get_val(int pin);
>> +
>> +/**
>> + * @brief Selects a GPIO pin for a specific function.
>> + */
>> +extern int gpio_select_pin(int pin, rpi_pin type);
>> +
>> +/**
>> + * @brief Setups a JTAG pin configuration.
>> + */
>> +extern int gpio_select_jtag(void);
>> +
>> +/**
>> + * @brief Setups the SPI interface on the RPI P1 GPIO header.
>> + */
>> +extern int gpio_select_spi_p1(void);
>> +
>> +/**
>> + * @brief Setups the I2C interface on the main (P1) GPIO pin header (rev2).
>> + */
>> +extern int gpio_select_i2c_p1_rev2(void);
>> +
>> +/**
>> + * @brief Configures a input GPIO pin pull-up resistor.
>> + */
>> +extern int gpio_input_mode(int pin, rpi_gpio_input_mode mode);
>> +
>> +/**
>> + * @brief Configures several input GPIO pins to the same pull-up resistor setup.
>> + */
>> +extern int gpio_setup_input_mode(int *pin, int pin_count, rpi_gpio_input_mode mode);
>> +
>> +/**
>> + * @brief Discards any configuration made on this pin.
>> + */
>> +extern int gpio_disable_pin(int dev_pin);
>> +
>> +/**
>> + * @brief Debouces a switch by requiring a number of clock ticks to pass between interruts.
>> + */
>> +extern int gpio_debounce_switch(int pin, int ticks);
>> +
>> +/**
>> + * @brief Enables interrupts on the given GPIO pin.
>> + */
>> +extern int gpio_enable_interrupt(int dev_pin, gpio_interrupt interrupt, void (*handler) (void));
>> +
>> +/**
>> + * @brief Disables any interrupt enabled on the given GPIO pin.
>> + */
>> +extern int 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..bdc53ef
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/arm/raspberrypi/include/i2c.h
>> @@ -0,0 +1,166 @@
>> +/**
>> + * @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();
>>  }
>> --
>> 1.8.5.5
>>
>> _______________________________________________
>> devel mailing list
>> devel at rtems.org
>> http://lists.rtems.org/mailman/listinfo/devel
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel

-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel.sherrill at OARcorp.com        On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
Support Available                (256) 722-9985




More information about the devel mailing list