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