/******************************************************************************* | |
* (c) Copyright 2008-2015 Microsemi SoC Products Group. All rights reserved. | |
* | |
* CoreGPIO bare metal driver implementation. | |
* | |
* SVN $Revision: 7964 $ | |
* SVN $Date: 2015-10-09 18:26:53 +0530 (Fri, 09 Oct 2015) $ | |
*/ | |
#include "core_gpio.h" | |
#include "hal.h" | |
#include "hal_assert.h" | |
#include "coregpio_regs.h" | |
/*-------------------------------------------------------------------------*//** | |
* | |
*/ | |
#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL | |
#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL | |
#define NB_OF_GPIO 32 | |
#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF | |
#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF | |
#define CLEAR_ALL_IRQ8 (uint8_t)0xFF | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_init() | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_init | |
( | |
gpio_instance_t * this_gpio, | |
addr_t base_addr, | |
gpio_apb_width_t bus_width | |
) | |
{ | |
uint8_t i = 0; | |
addr_t cfg_reg_addr = base_addr; | |
this_gpio->base_addr = base_addr; | |
this_gpio->apb_bus_width = bus_width; | |
/* Clear configuration. */ | |
for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) | |
{ | |
HW_set_8bit_reg( cfg_reg_addr, 0 ); | |
cfg_reg_addr += 4; | |
} | |
/* Clear any pending interrupts */ | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); | |
HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_config | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_config | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id, | |
uint32_t config | |
) | |
{ | |
HAL_ASSERT( port_id < NB_OF_GPIO ); | |
if ( port_id < NB_OF_GPIO ) | |
{ | |
uint32_t cfg_reg_addr = this_gpio->base_addr; | |
cfg_reg_addr += (port_id * 4); | |
HW_set_32bit_reg( cfg_reg_addr, config ); | |
/* | |
* Verify that the configuration was correctly written. Failure to read | |
* back the expected value may indicate that the GPIO port was configured | |
* as part of the hardware flow and cannot be modified through software. | |
* It may also indicate that the base address passed as parameter to | |
* GPIO_init() was incorrect. | |
*/ | |
HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_set_outputs | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_set_outputs | |
( | |
gpio_instance_t * this_gpio, | |
uint32_t value | |
) | |
{ | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); | |
HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); | |
HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); | |
HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); | |
HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
/* | |
* Verify that the output register was correctly written. Failure to read back | |
* the expected value may indicate that some of the GPIOs may not exist due to | |
* the number of GPIOs selected in the CoreGPIO hardware flow configuration. | |
* It may also indicate that the base address or APB bus width passed as | |
* parameter to the GPIO_init() function do not match the hardware design. | |
*/ | |
HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_get_inputs | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
uint32_t GPIO_get_inputs | |
( | |
gpio_instance_t * this_gpio | |
) | |
{ | |
uint32_t gpio_in = 0; | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); | |
gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); | |
gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); | |
gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); | |
gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
return gpio_in; | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_get_outputs | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
uint32_t GPIO_get_outputs | |
( | |
gpio_instance_t * this_gpio | |
) | |
{ | |
uint32_t gpio_out = 0; | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); | |
gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); | |
gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); | |
gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); | |
gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
return gpio_out; | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_set_output | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_set_output | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id, | |
uint8_t value | |
) | |
{ | |
HAL_ASSERT( port_id < NB_OF_GPIO ); | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
{ | |
uint32_t outputs_state; | |
outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); | |
if ( 0 == value ) | |
{ | |
outputs_state &= ~(1 << port_id); | |
} | |
else | |
{ | |
outputs_state |= 1 << port_id; | |
} | |
HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); | |
/* | |
* Verify that the output register was correctly written. Failure to read back | |
* the expected value may indicate that some of the GPIOs may not exist due to | |
* the number of GPIOs selected in the CoreGPIO hardware flow configuration. | |
* It may also indicate that the base address or APB bus width passed as | |
* parameter to the GPIO_init() function do not match the hardware design. | |
*/ | |
HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); | |
} | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
{ | |
uint16_t outputs_state; | |
uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); | |
outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); | |
if ( 0 == value ) | |
{ | |
outputs_state &= ~(1 << (port_id & 0x0F)); | |
} | |
else | |
{ | |
outputs_state |= 1 << (port_id & 0x0F); | |
} | |
HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); | |
/* | |
* Verify that the output register was correctly written. Failure to read back | |
* the expected value may indicate that some of the GPIOs may not exist due to | |
* the number of GPIOs selected in the CoreGPIO hardware flow configuration. | |
* It may also indicate that the base address or APB bus width passed as | |
* parameter to the GPIO_init() function do not match the hardware design. | |
*/ | |
HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); | |
} | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
{ | |
uint8_t outputs_state; | |
uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); | |
outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); | |
if ( 0 == value ) | |
{ | |
outputs_state &= ~(1 << (port_id & 0x07)); | |
} | |
else | |
{ | |
outputs_state |= 1 << (port_id & 0x07); | |
} | |
HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); | |
/* | |
* Verify that the output register was correctly written. Failure to read back | |
* the expected value may indicate that some of the GPIOs may not exist due to | |
* the number of GPIOs selected in the CoreGPIO hardware flow configuration. | |
* It may also indicate that the base address or APB bus width passed as | |
* parameter to the GPIO_init() function do not match the hardware design. | |
*/ | |
HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); | |
} | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_drive_inout | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_drive_inout | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id, | |
gpio_inout_state_t inout_state | |
) | |
{ | |
uint32_t config; | |
uint32_t cfg_reg_addr = this_gpio->base_addr; | |
HAL_ASSERT( port_id < NB_OF_GPIO ); | |
switch( inout_state ) | |
{ | |
case GPIO_DRIVE_HIGH: | |
/* Set output high */ | |
GPIO_set_output( this_gpio, port_id, 1 ); | |
/* Enable output buffer */ | |
cfg_reg_addr = this_gpio->base_addr + (port_id * 4); | |
config = HW_get_8bit_reg( cfg_reg_addr ); | |
config |= OUTPUT_BUFFER_ENABLE_MASK; | |
HW_set_8bit_reg( cfg_reg_addr, config ); | |
break; | |
case GPIO_DRIVE_LOW: | |
/* Set output low */ | |
GPIO_set_output( this_gpio, port_id, 0 ); | |
/* Enable output buffer */ | |
cfg_reg_addr = this_gpio->base_addr + (port_id * 4); | |
config = HW_get_8bit_reg( cfg_reg_addr ); | |
config |= OUTPUT_BUFFER_ENABLE_MASK; | |
HW_set_8bit_reg( cfg_reg_addr, config ); | |
break; | |
case GPIO_HIGH_Z: | |
/* Disable output buffer */ | |
cfg_reg_addr = this_gpio->base_addr + (port_id * 4); | |
config = HW_get_8bit_reg( cfg_reg_addr ); | |
config &= ~OUTPUT_BUFFER_ENABLE_MASK; | |
HW_set_8bit_reg( cfg_reg_addr, config ); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_enable_irq | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_enable_irq | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id | |
) | |
{ | |
uint32_t cfg_value; | |
uint32_t cfg_reg_addr = this_gpio->base_addr; | |
HAL_ASSERT( port_id < NB_OF_GPIO ); | |
if ( port_id < NB_OF_GPIO ) | |
{ | |
cfg_reg_addr += (port_id * 4); | |
cfg_value = HW_get_8bit_reg( cfg_reg_addr ); | |
cfg_value |= GPIO_INT_ENABLE_MASK; | |
HW_set_8bit_reg( cfg_reg_addr, cfg_value ); | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_disable_irq | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_disable_irq | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id | |
) | |
{ | |
uint32_t cfg_value; | |
uint32_t cfg_reg_addr = this_gpio->base_addr; | |
HAL_ASSERT( port_id < NB_OF_GPIO ); | |
if ( port_id < NB_OF_GPIO ) | |
{ | |
cfg_reg_addr += (port_id * 4); | |
cfg_value = HW_get_8bit_reg( cfg_reg_addr ); | |
cfg_value &= ~GPIO_INT_ENABLE_MASK; | |
HW_set_8bit_reg( cfg_reg_addr, cfg_value ); | |
} | |
} | |
/*-------------------------------------------------------------------------*//** | |
* GPIO_clear_irq | |
* See "core_gpio.h" for details of how to use this function. | |
*/ | |
void GPIO_clear_irq | |
( | |
gpio_instance_t * this_gpio, | |
gpio_id_t port_id | |
) | |
{ | |
uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); | |
switch( this_gpio->apb_bus_width ) | |
{ | |
case GPIO_APB_32_BITS_BUS: | |
HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); | |
break; | |
case GPIO_APB_16_BITS_BUS: | |
HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); | |
HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); | |
break; | |
case GPIO_APB_8_BITS_BUS: | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); | |
HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); | |
break; | |
default: | |
HAL_ASSERT(0); | |
break; | |
} | |
} | |