[PATCH] Add GPIO, I2C and SPI support for the RPi BSP
Andre Marques
andre.lousa.marques at gmail.com
Tue Nov 4 23:27:51 UTC 2014
On 11/04/14 23:16, Joel Sherrill wrote:
> On 11/4/2014 5:01 PM, Andre Marques wrote:
>> Hi gedare,
>>
>> will send a new version of this patch in the next few days.
>>
>> Replies to your comments below.
>>
> I am too overwhelmed to remember but are there example
> and/or test programs for the IO pins?
Yes I have put the test cases and the device drivers I used during
development in github:
https://github.com/asuol/RTEMS_rpi_testing
>
> FWIW I have a Pinewood Derby application that uses 3 discrete
> inputs to time two wooden cars on a race track. I need to move
> it to my personal git repo. It was developed to use a parallel
> port on a PC as input but moving to a Raspberry Pi for it would
> be cool!
>
> --joel
>> --André Marques.
>>
>> On 10/31/14 14:25, Gedare Bloom wrote:
>>> Thanks, I'll leave detailed comments to the experts but noticed a few things.
>>>
>>> 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 { }.
>> Will review the code against the coding conventions. On a side note the
>> explicit braces convention does not seem to be in the wiki page (I am
>> looking it through the google cache since the wiki is down).
>>
>>>> +}
>>>> +
>>>> +/**
>>>> + * @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.
>>>
>> The allocation can indeed become static. As for the initialization of
>> the array this function is to be called by any application that intends
>> to use digital I/O capabilities. The alternative is to have this
>> initialization on startup/bspstart.c (as I2C/SPI which are activated
>> through configure.ac).
>>
>> When changing the alocation from dynamic to static I found that some
>> pins were not getting the pull-up resistors to work, which I traced to
>> the rpi_gpio_input_mode enumerator in include/gpio.h (for some reason if
>> PULL_UP is 0 the resistor is not activated when the gpio_pin array is
>> staticly-allocated):
>>
>> typedef enum
>> {
>> PULL_UP,
>> PULL_DOWN,
>> NO_PULL_RESISTOR
>> } rpi_gpio_input_mode;
>>
>> Will initialize every first value on the enumerators there to 1.
>>
>>>> +}
>>>> +
>>>> +/**
>>>> + * @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.
>> Will do.
>>
>>>> + 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
>> This one should become gpio_get_value or gpio_read.
>>
>>>> +{
>>>> + return BCM2835_REG(BCM2835_GPIO_GPLEV0) &= (1 << (pin));
>>> Do you intend for the assignment as a side-effect? If so, it should be
>>> documented.
>> Actually the assignment is not needed. There is also too many parenthesis.
>>
>>>> +}
>>>> +
>>>> +/**
>>>> + * @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?
>> DIGITAL_INPUT uses the &~ operators instead of |, but the switch may be
>> simplified through the enumerator.
>>
>>>> + /* 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
>> Will create a macro for it.
>>
>>>> + return -1;
>>> Consider using more informative error codes.
>> Should I print something before the return?
>>
>>>> +
>>>> + /* 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[])?
>> It may make sense in some scenarios, but probably is easier to read if
>> each call assigns a type to all pins on a given array instead of having
>> to visually match each pin with a 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.
>> The handler args are processed in this generic handler, as it avoids
>> calling the handler when the interrupt was generated by a switch bounce.
>> The called handler (given by an application) receives no arguments.
>>
>>>> +}
>>>> +
>>>> +/**
>>>> + * @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.
>> I agree.
>>
>>>> +
>>>> + default:
>>>> + return -1;
>>> This error case should be detected sooner?
>> Yes, I was just being overzealous.
>>
>>>> + }
>>>> +
>>>> + 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?
>> If the pin has no recorded active interrupt it should not have any
>> handler to remove.
>>
>>>> +
>>>> + 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?
>> I account for it in my test cases but I am not sure if I mentioned this
>> in the documentation. Will check that.
>>
>>>> + 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 }.
>> The transfer_count is the total number of byte transfers -1, because
>> each of these transfers use the full 32 bits of the DLEN register. The
>> -1 part is because the last transfer may not need the full register to
>> hold the remaining data. A full while loop will send 4 bytes of
>> information, so if the transfer_count-- goes after the next } it must
>> become transfer_count -=4.
>>
>>>> + }
>>>> + } 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
More information about the devel
mailing list