/*******************************************************************************
 * (c) Copyright 2008-2018 Microsemi SoC Products Group. All rights reserved.
 * 
 *  CoreGPIO bare metal driver public API.
 *
 * SVN $Revision: 9743 $
 * SVN $Date: 2018-02-12 15:45:09 +0530 (Mon, 12 Feb 2018) $
 */

/*=========================================================================*//**
  @mainpage CoreGPIO Bare Metal Driver.

  @section intro_sec Introduction
  The CoreGPIO hardware IP includes up to 32 general purpose input output GPIOs.
  This driver provides a set of functions for controlling the GPIOs as part of a
  bare metal system where no operating system is available. These drivers
  can be adapted for use as part of an operating system but the implementation
  of the adaptation layer between this driver and the operating system's driver
  model is outside the scope of this driver.
  
  @section driver_configuration Driver Configuration
  The CoreGPIO individual IOs can be configured either in the hardware flow or
  as part of the software application through calls to the GPIO_config() function.
  GPIOs configured as as part of the hardware is fixed and cannot be modified
  using a call to the GPI_config() function.
  
  @section theory_op Theory of Operation
  The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access
  hardware registers. You must ensure that the Actel HAL is included as part of
  your software project. The Actel HAL is available through the Actel Firmware
  Catalog.
  
  The CoreGPIO driver functions are logically grouped into the following groups:
    - Initialization
    - Configuration
    - Reading and writing GPIO state
    - Interrupt control
  
  The CoreGPIO driver is initialized through a call to the GPIO_init() function.
  The GPIO_init() function must be called before any other GPIO driver functions
  can be called.
  
  Each GPIO port is individually configured through a call to the
  GPIO_config() function. Configuration includes deciding if a GPIO port
  will be used as input, output or both. GPIO ports configured as inputs can be
  further configured to generate interrupts based on the input's state.
  Interrupts can be level or edge sensitive.
  Please note that a CoreGPIO hardware instance can be generated, as part of the
  hardware flow, with a fixed configuration for some or all of its IOs. Attempting
  to modify the configuration of such a hardware configured IO using the
  GPIO_config() function has no effect.
  
  The state of the GPIO ports can be read and written using the following
  functions:
    - GPIO_get_inputs()
    - GPIO_get_outputs()
    - GPIO_set_outputs()
    - GPIO_drive_inout()
    
  Interrupts generated by GPIO ports configured as inputs are controlled using
  the following functions:
    - GPIO_enable_irq()
    - GPIO_disable_irq()
    - GPIO_clear_irq()
    - GPIO_get_irq_sources()
    - GPIO_clear_all_irq_sources()
  
 *//*=========================================================================*/
#ifndef CORE_GPIO_H_
#define CORE_GPIO_H_

#include <stdint.h>
#include "cpu_types.h"

/*-------------------------------------------------------------------------*//**
  The gpio_id_t enumeration is used to identify GPIOs as part of the
  parameter to functions:
    - GPIO_config(),
    - GPIO_drive_inout(),
    - GPIO_enable_int(),
    - GPIO_disable_int(),
    - GPIO_clear_int()
 */
typedef enum __gpio_id_t
{
    GPIO_0 = 0,
    GPIO_1 = 1,
    GPIO_2 = 2,
    GPIO_3 = 3,
    GPIO_4 = 4,
    GPIO_5 = 5,
    GPIO_6 = 6,
    GPIO_7 = 7,
    GPIO_8 = 8,
    GPIO_9 = 9,
    GPIO_10 = 10,
    GPIO_11 = 11,
    GPIO_12 = 12,
    GPIO_13 = 13,
    GPIO_14 = 14,
    GPIO_15 = 15,
    GPIO_16 = 16,
    GPIO_17 = 17,
    GPIO_18 = 18,
    GPIO_19 = 19,
    GPIO_20 = 20,
    GPIO_21 = 21,
    GPIO_22 = 22,
    GPIO_23 = 23,
    GPIO_24 = 24,
    GPIO_25 = 25,
    GPIO_26 = 26,
    GPIO_27 = 27,
    GPIO_28 = 28,
    GPIO_29 = 29,
    GPIO_30 = 30,
    GPIO_31 = 31
} gpio_id_t;

typedef enum __gpio_apb_width_t
{
    GPIO_APB_8_BITS_BUS = 0,
    GPIO_APB_16_BITS_BUS = 1,
    GPIO_APB_32_BITS_BUS = 2,
    GPIO_APB_UNKNOWN_BUS_WIDTH = 3
} gpio_apb_width_t;

/*-------------------------------------------------------------------------*//**
 */
typedef struct __gpio_instance_t
{
    addr_t              base_addr;
    gpio_apb_width_t    apb_bus_width;
} gpio_instance_t;

/*-------------------------------------------------------------------------*//**
  GPIO ports definitions used to identify GPIOs as part of the parameter to
  function GPIO_set_outputs().
  These definitions can also be used to identity GPIO through logical
  operations on the return value of function GPIO_get_inputs().
 */
#define GPIO_0_MASK         0x00000001UL
#define GPIO_1_MASK         0x00000002UL
#define GPIO_2_MASK         0x00000004UL
#define GPIO_3_MASK         0x00000008UL
#define GPIO_4_MASK         0x00000010UL
#define GPIO_5_MASK         0x00000020UL
#define GPIO_6_MASK         0x00000040UL
#define GPIO_7_MASK         0x00000080UL
#define GPIO_8_MASK         0x00000100UL
#define GPIO_9_MASK         0x00000200UL
#define GPIO_10_MASK        0x00000400UL
#define GPIO_11_MASK        0x00000800UL
#define GPIO_12_MASK        0x00001000UL
#define GPIO_13_MASK        0x00002000UL
#define GPIO_14_MASK        0x00004000UL
#define GPIO_15_MASK        0x00008000UL
#define GPIO_16_MASK        0x00010000UL
#define GPIO_17_MASK        0x00020000UL
#define GPIO_18_MASK        0x00040000UL
#define GPIO_19_MASK        0x00080000UL
#define GPIO_20_MASK        0x00100000UL
#define GPIO_21_MASK        0x00200000UL
#define GPIO_22_MASK        0x00400000UL
#define GPIO_23_MASK        0x00800000UL
#define GPIO_24_MASK        0x01000000UL
#define GPIO_25_MASK        0x02000000UL
#define GPIO_26_MASK        0x04000000UL
#define GPIO_27_MASK        0x08000000UL
#define GPIO_28_MASK        0x10000000UL
#define GPIO_29_MASK        0x20000000UL
#define GPIO_30_MASK        0x40000000UL
#define GPIO_31_MASK        0x80000000UL

/*-------------------------------------------------------------------------*//**
 * GPIO modes
 */
#define GPIO_INPUT_MODE              0x0000000002UL
#define GPIO_OUTPUT_MODE             0x0000000005UL
#define GPIO_INOUT_MODE              0x0000000003UL

/*-------------------------------------------------------------------------*//**
 * Possible GPIO inputs interrupt configurations.
 */
#define GPIO_IRQ_LEVEL_HIGH           0x0000000000UL
#define GPIO_IRQ_LEVEL_LOW            0x0000000020UL
#define GPIO_IRQ_EDGE_POSITIVE        0x0000000040UL
#define GPIO_IRQ_EDGE_NEGATIVE        0x0000000060UL
#define GPIO_IRQ_EDGE_BOTH            0x0000000080UL

/*-------------------------------------------------------------------------*//**
 * Possible states for GPIO configured as INOUT.
 */
typedef enum gpio_inout_state
{
    GPIO_DRIVE_LOW = 0,
    GPIO_DRIVE_HIGH,
    GPIO_HIGH_Z
} gpio_inout_state_t;

/*-------------------------------------------------------------------------*//**
  The GPIO_init() function initialises a CoreGPIO hardware instance and the data
  structure associated with the CoreGPIO hardware instance.
  Please note that a CoreGPIO hardware instance can be generated with a fixed
  configuration for some or all of its IOs as part of the hardware flow. Attempting
  to modify the configuration of such a hardware configured IO using the
  GPIO_config() function has no effect.

  @param this_gpio
    Pointer to the gpio_instance_t data structure instance holding all data
    regarding the CoreGPIO hardware instance being initialized. A pointer to the
    same data structure will be used in subsequent calls to the CoreGPIO driver
    functions in order to identify the CoreGPIO instance that should perform the
    operation implemented by the called driver function.

  @param base_addr
    The base_addr parameter is the base address in the processor's memory map for
    the registers of the GPIO instance being initialized.
    
  @param bus_width
    The bus_width parameter informs the driver of the APB bus width selected during
    the hardware flow configuration of the CoreGPIO hardware instance. It indicates
    to the driver whether the CoreGPIO hardware registers will be visible as 8, 16
    or 32 bits registers. Allowed value are:
        - GPIO_APB_8_BITS_BUS
        - GPIO_APB_16_BITS_BUS
        - GPIO_APB_32_BITS_BUS
  
  @return
    none.
    
  Example:
  @code
    #define COREGPIO_BASE_ADDR  0xC2000000
    
    gpio_instance_t g_gpio;
    
    void system_init( void )
    {
        GPIO_init( &g_gpio,    COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS );
    }
  @endcode
  */
void GPIO_init
(
    gpio_instance_t *   this_gpio,
    addr_t              base_addr,
    gpio_apb_width_t    bus_width
);

/*-------------------------------------------------------------------------*//**
  The GPIO_config() function is used to configure an individual GPIO port.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter identifies the GPIO port to be configured.
    An enumeration item of the form GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example GPIO_0 identifies the
    first GPIO port and GPIO_31 the last one.
    
  @param config
    The config parameter specifies the configuration to be applied to the GPIO
    port identified by the first parameter. It is a logical OR of GPIO mode and
    the interrupt mode. The interrupt mode is only relevant if the GPIO is
    configured as input.
       Possible modes are:
           - GPIO_INPUT_MODE,
           - GPIO_OUTPUT_MODE,
           - GPIO_INOUT_MODE.
       Possible interrupt modes are:
           - GPIO_IRQ_LEVEL_HIGH,
           - GPIO_IRQ_LEVEL_LOW,
           - GPIO_IRQ_EDGE_POSITIVE,
           - GPIO_IRQ_EDGE_NEGATIVE,
           - GPIO_IRQ_EDGE_BOTH
 
  @return
    none.
    
  For example the following call will configure GPIO 4 as an input generating
  interrupts on a low to high transition of the input:
  @code
  GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE );
  @endcode
 */
void GPIO_config
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id,
    uint32_t            config
);

/*-------------------------------------------------------------------------*//**
  The GPIO_set_outputs() function is used to set the state of the GPIO ports
  configured as outputs.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param value
    The value parameter specifies the state of the GPIO ports configured as
    outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK) where n
    and m are numbers identifying GPIOs.
    For example (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the
    first, second and third GPIOs' must be set high and all other outputs set
    low.

  @return
    none.
    
  Example 1:
    Set GPIOs outputs 0 and 8 high and all other GPIO outputs low.
    @code
        GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK );
    @endcode

  Example 2:
    Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs.
    @code
        uint32_t gpio_outputs;
        gpio_outputs = GPIO_get_outputs( &g_gpio );
        gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK );
        GPIO_set_outputs( &g_gpio, gpio_outputs );
    @endcode

  @see GPIO_get_outputs()
 */
void GPIO_set_outputs
(
    gpio_instance_t *   this_gpio,
    uint32_t            value
);

/*-------------------------------------------------------------------------*//**
  The GPIO_set_output() function is used to set the state of a single GPIO
  port configured as output.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter specifies the GPIO port that will have its output set
    by a call to this function.
  
  @param value
    The value parameter specifies the desired state for the GPIO output. A value
    of 0 will set the output low and a value of 1 will set the port high.
  
  @return
    none.
 */
void GPIO_set_output
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id,
    uint8_t             value
);

/*-------------------------------------------------------------------------*//**
  The GPIO_get_inputs() function is used to read the state of all GPIOs
  configured as inputs.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @return
    This function returns a 32 bit unsigned integer where each bit represents
    the state of an input. The least significant bit representing the state of
    GPIO 0 and the most significant bit the state of GPIO 31.
 */
uint32_t GPIO_get_inputs
(
    gpio_instance_t *   this_gpio
);

/*-------------------------------------------------------------------------*//**
  The GPIO_get_outputs() function is used to read the current state of all
  GPIO outputs.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @return
     This function returns a 32 bit unsigned integer where each bit represents
     the state of an output. The least significant bit representing the state
     of GPIO 0 and the most significant bit the state of GPIO 31.
 */
uint32_t GPIO_get_outputs
(
    gpio_instance_t *   this_gpio
);

/*-------------------------------------------------------------------------*//**
  The GPIO_drive_inout() function is used to set the output state of a
  GPIO configured as INOUT. An INOUT GPIO can be in one of three states:
    - high
    - low
    - high impedance
  An INOUT output would typically be used where several devices can drive the
  state of a signal. The high and low states are equivalent to the high and low
  states of a GPIO configured as output. The high impedance state is used to
  prevent the GPIO from driving the state of the output and therefore allow
  reading the state of the GPIO as an input.
  Please note that the GPIO port you wish to use as INOUT through this function
  must be configurable through software. Therefore the GPIO ports used as INOUT
  must not have a fixed configuration selected as part of the hardware flow.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter identifies the GPIO for which this function will
    change the output state.
    An enumeration item of the form GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example GPIO_0 identifies the
    first GPIO port and GPIO_31 the last one.
    
  @param inout_state
    The inout_state parameter specifies the state of the I/O identified by the
    first parameter. Possible states are:
                           - GPIO_DRIVE_HIGH,
                           - GPIO_DRIVE_LOW,
                           - GPIO_HIGH_Z (high impedance)

  @return
    none.
    
  Example:
    The call to GPIO_drive_inout() below will set the GPIO 7 output to
    high impedance state.
    @code
    GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z );
    @endcode
 */
void GPIO_drive_inout
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id,
    gpio_inout_state_t  inout_state
);

/*-------------------------------------------------------------------------*//**
  The GPIO_enable_irq() function is used to enable an interrupt to be
  generated based on the state of the input identified as parameter.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter identifies the GPIO input the call to
    GPIO_enable_irq() will enable to generate interrupts.
    An enumeration item of the form GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example GPIO_0 identifies the
    first GPIO port and GPIO_31 the last one.
    
  @return
    none.
    
  Example:
    The call to GPIO_enable_irq() below will allow GPIO 8 to generate
    interrupts.
    @code
    GPIO_enable_irq( &g_gpio, GPIO_8 );
    @endcode
 */
void GPIO_enable_irq
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id
);

/*-------------------------------------------------------------------------*//**
  The GPIO_disable_irq() function is used to disable interrupt from being
  generated based on the state of the input specified as parameter.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter identifies the GPIO input the call to
    GPIO_disable_irq() will disable from generating interrupts.
    An enumeration item of the form GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example GPIO_0 identifies the
    first GPIO port and GPIO_31 the last one.
 
  @return
    none.
    
  Example:
    The call to GPIO_disable_irq() below will prevent GPIO 8 from generating
    interrupts.
    @code
    GPIO_disable_irq( &g_gpio, GPIO_8 );
    @endcode
 */
void GPIO_disable_irq
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id
);

/*-------------------------------------------------------------------------*//**
  The GPIO_clear_irq() function is used to clear the interrupt generated by
  the GPIO specified as parameter. The GPIO_clear_irq() function  must be
  called as part of a GPIO interrupt service routine (ISR) in order to prevent
  the same interrupt event re-triggering a call to the GPIO ISR.
  Please note that interrupts may also need to be cleared in the processor's
  interrupt controller.
 
  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param port_id
    The port_id parameter identifies the GPIO input for which to clear the
    interrupt.
    An enumeration item of the form GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example GPIO_0 identifies the
    first GPIO port and GPIO_31 the last one.
    
  @return
    none.
    
  Example:
    The example below demonstrates the use of the GPIO_clear_irq() function as
    part of the GPIO 9 interrupt service routine.  
    @code
    void GPIO9_IRQHandler( void )
    {
        do_interrupt_processing();
        
        GPIO_clear_irq( &g_gpio, GPIO_9 );
        
        NVIC_ClearPendingIRQ( GPIO9_IRQn );
    }
    @endcode
 */
void GPIO_clear_irq
(
    gpio_instance_t *   this_gpio,
    gpio_id_t           port_id
);

/*-------------------------------------------------------------------------*//**
  The GPIO_get_irq_sources() function is used to identify the source of
  interrupt. i.e. the GPIO input line whose state change triggered the interrupt.
  The GPIO_get_irq_sources() function  must be called as part of a GPIO
  interrupt service routine (ISR) in order to determine the interrupt source.

  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @return
     This function returns a 32 bit unsigned integer where each bit represents
     the pin number of GPIO.

  Example:
    The example below demonstrates the use of the GPIO_get_irq_sources() function
    as part of the GPIO 9 interrupt service routine.
    @code
    void GPIO9_IRQHandler( void )
    {
        do_interrupt_processing();

        GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio));

        NVIC_ClearPendingIRQ( GPIO9_IRQn );
    }
    @endcode
 */
uint32_t GPIO_get_irq_sources
(
    gpio_instance_t *   this_gpio
);

/*-------------------------------------------------------------------------*//**
  The GPIO_clear_all_irq_sources() function is used to clear the all the active
  interrupt generated by the GPIO specified as parameter. The
  GPIO_clear_all_irq_sources() function  must be called as part of a GPIO interrupt
  service routine (ISR) in order to prevent the same interrupt event
  re-triggering a call to the GPIO ISR.
  Please note that interrupts may also need to be cleared in the processor's
  interrupt controller.

  @param this_gpio
    The this_gpio parameter is a pointer to the gpio_instance_t structure holding
    all data regarding the CoreGPIO instance controlled through this function call.

  @param bitmask
     This bitmask parameter is a 32 bit unsigned integer where each bit represents
     the GPIO pin used to clears the interrupt bit register of the corresponding
     GPIO bit. The least significant bit representing the status of GPIO 0 and
     the most significant bit the status of GPIO 31.

  @return
    none.

  Example:
    The example below demonstrates the use of the GPIO_clear_all_irq_sources() function as
    part of the GPIO 9 interrupt service routine.
    @code
    void GPIO9_IRQHandler( void )
    {
        do_interrupt_processing();

        do_interrupt_processing();

        GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio));

        NVIC_ClearPendingIRQ( GPIO9_IRQn );
    }
    @endcode
 */
void GPIO_clear_all_irq_sources
(
    gpio_instance_t *   this_gpio,
    uint32_t            bitmask
);
#endif /* CORE_GPIO_H_ */
