blob: 964913e581785d805dc3ded8d1a3a173486c881f [file] [log] [blame]
/*****************************************************************************
* © 2014 Microchip Technology Inc. and its subsidiaries.
* You may use this software and any derivatives exclusively with
* Microchip products.
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS".
* NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP
* PRODUCTS, COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.
* TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
* CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF
* FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE
* OF THESE TERMS.
*****************************************************************************/
/** @file mec14xx_gpio.c
*MEC14xx GPIO hardware access
*/
/** @defgroup MEC14xx Peripherals GPIO
* @{
*/
#include "appcfg.h"
#include "platform.h"
#include "MEC14xx/mec14xx.h"
#include "MEC14xx/mec14xx_gpio.h"
static uint32_t gpio_has_drv_str ( enum gpio_id_t gpio_id );
#ifdef ENABLE_GPIO_PIN_VALIDATION
static const uint32_t gpio_port_bitmaps[NUM_GPIO_PORTS] =
{
(GPIO_PORT_A_BITMAP),
(GPIO_PORT_B_BITMAP),
(GPIO_PORT_C_BITMAP),
(GPIO_PORT_D_BITMAP)
};
#endif
//
// Drive Strength Register bitmap
//
static const uint32_t gpio_drv_str_bitmap[NUM_GPIO_PORTS] =
{
(GPIO_PORT_A_DRVSTR_BITMAP),
(GPIO_PORT_B_DRVSTR_BITMAP),
(GPIO_PORT_C_DRVSTR_BITMAP),
(GPIO_PORT_D_DRVSTR_BITMAP)
};
struct gpio_cfg
{
uint16_t bit_mask;
uint8_t bit_pos;
};
static const struct gpio_cfg gpio_cfg_tbl[GPIO_PROP_MAX] =
{
{ 0x0003u, 0x00u },
{ 0x000Cu, 0x02u },
{ 0x00F0u, 0x04u },
{ 0x0100u, 0x08u },
{ 0x0200u, 0x09u },
{ 0x0400u, 0x0Au },
{ 0x0800u, 0x0Bu },
{ 0x3000u, 0x0Cu },
{ 0x3FFFu, 0x00u }
};
static uint32_t gpio_pin_ctrl_addr(enum gpio_id_t gpio_id)
{
return ((uint32_t)(GPIO_BASE) + (uint32_t)(gpio_id << 2));
}
#ifdef ENABLE_GPIO_PIN_VALIDATION
/**
* gpio_is_valid - local helper checks if GPIO pin is
* implemented in this hardware.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
*
* @return uint8_t Non-zero(GPIO Pin implemented), 0(not
* implemented).
*/
static uint8_t gpio_is_valid ( enum gpio_id_t gpio_id )
{
uint16_t gp_bank;
gp_bank = 0;
if ( (uint16_t)gpio_id < (uint16_t)(MAX_GPIO_ID) )
{
gp_bank = (uint16_t)gpio_id >> 5;
if ( gpio_port_bitmaps[gp_bank] & (1 << (gpio_id & 0x001Fu)) )
{
return true;
}
}
return false;
}
#else
static uint32_t gpio_is_valid(enum gpio_id_t gpio_id) { return true; }
#endif
static uint8_t gpio_bank_num(enum gpio_id_t gpio_id)
{
return (uint8_t)(gpio_id) >> 5;
}
static uint8_t gpio_pin_num(enum gpio_id_t gpio_id)
{
return (uint8_t)(gpio_id) & 0x1Fu;
}
/**
* gpio_has_drv_str - Local helper to check if GPIO pin has
* associated drive strength register.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
*
* @return uint32_t 0(No Drive Strength), Non-zero(Physical
* address of Drive Strength Register).
*/
static uint32_t gpio_has_drv_str ( enum gpio_id_t gpio_id )
{
uint32_t bank, bitpos, addr;
addr = 0ul;
if ( gpio_id < MAX_GPIO_ID )
{
bank = gpio_bank_num(gpio_id);
bitpos = gpio_pin_num(gpio_id);
if ( gpio_drv_str_bitmap[bank] & (1ul << bitpos) )
{
addr = (GPIO_PCTRL2_BASE) + ((uint32_t)(gpio_id) << 2);
if ( gpio_id > GPIO_0077_ID )
{
addr -= 0x20ul;
}
}
}
return addr;
}
uint16_t GPIOGetConfig(enum gpio_id_t gpio_id)
{
if (gpio_is_valid(gpio_id)) {
return *((volatile uint16_t *)gpio_pin_ctrl_addr(gpio_id));
} else {
return 0u;
}
}
void GPIOSetConfig(enum gpio_id_t gpio_id, uint16_t config)
{
volatile uint16_t * p;
if (gpio_is_valid(gpio_id)) {
p = (volatile uint16_t *)gpio_pin_ctrl_addr(gpio_id);
*p = config;
}
}
void GPIOConfigAndOr(enum gpio_id_t gpio_id, uint16_t and_mask, uint16_t or_mask)
{
volatile uint16_t * p;
if (gpio_is_valid(gpio_id)) {
p = (volatile uint16_t *)gpio_pin_ctrl_addr(gpio_id);
*p = (*p & and_mask) | or_mask;
}
}
uint32_t GPIOGetControl(enum gpio_id_t gpio_id)
{
if (gpio_is_valid(gpio_id)) {
return *((volatile uint32_t *)gpio_pin_ctrl_addr(gpio_id));
} else {
return 0xFFFFFFFFul;
}
}
void GPIOSetControl(enum gpio_id_t gpio_id, uint32_t ctrl_val)
{
volatile uint32_t * p;
if (gpio_is_valid(gpio_id)) {
p = (volatile uint32_t *)gpio_pin_ctrl_addr(gpio_id);
*p = ctrl_val;
}
}
void GPIOControlAndOr(enum gpio_id_t gpio_id, uint32_t and_mask, uint32_t or_mask)
{
volatile uint32_t * p;
if (gpio_is_valid(gpio_id)) {
p = (volatile uint32_t *)gpio_pin_ctrl_addr(gpio_id);
*p = (*p & and_mask) | or_mask;
}
}
/**
* GPIOPropertySet - Program specified GPIO Pin configuration
* item.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
* @param gpio_prop enumerated GPIO Property(configuration item)
* @param prop_val new property value
*/
void GPIOPropertySet ( enum gpio_id_t gpio_id,
enum gpio_prop_t gpio_prop,
uint16_t prop_val
)
{
volatile uint16_t * p;
uint16_t gp_cfg;
gp_cfg = 0u;
if ( gpio_is_valid(gpio_id) && ((uint16_t)gpio_prop < (uint16_t)GPIO_PROP_MAX) )
{
p = (volatile uint16_t *)gpio_pin_ctrl_addr(gpio_id);
gp_cfg = *p;
gp_cfg &= ~(gpio_cfg_tbl[gpio_prop].bit_mask);
gp_cfg |= (prop_val << gpio_cfg_tbl[gpio_prop].bit_pos) &
gpio_cfg_tbl[gpio_prop].bit_mask;
*p = gp_cfg;
}
}
/**
* GPIOGetSlewRate - Return GPIO Pin Slew Rate
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
*
* @return uint8_t GPIO Pin Slew Rate: 0(Slow) or 1(Fast)
*/
uint8_t GPIOGetSlewRate( enum gpio_id_t gpio_id )
{
uint32_t addr;
uint8_t slew;
addr = gpio_has_drv_str(gpio_id);
if ( 0ul != addr )
{
slew = ((*(volatile uint8_t *)addr) >> GPIO_DRV_SLEW_BITPOS) & 0x01u;
}
else
{
slew = 0u;
}
return slew;
}
/**
* GPIOSetSlewRate - Program GPIO Pin's Slew Rate
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
* @param slew_rate new slew rate: 0(Slow), Non-zero(Fast)
*/
void GPIOSetSlewRate ( enum gpio_id_t gpio_id,
enum gpio_slew_rate_t slew_rate )
{
uint32_t addr;
addr = gpio_has_drv_str(gpio_id );
if ( addr )
{
*(volatile uint8_t *)addr = (*(volatile uint8_t *)addr &
~(GPIO_DRV_SLEW_MASK)) |
((slew_rate << (GPIO_DRV_SLEW_BITPOS)) & (GPIO_DRV_SLEW_MASK));
}
}
/**
* GPIOGetDriveStr - Get GPIO Pin's Drive Strength
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
*
* @return uint8_t Pin Drive Strength: 0=2mA, 1=4mA, 2=8mA,
* 3=12mA.
*/
uint8_t GPIOGetDriveStr ( enum gpio_id_t gpio_id )
{
uint32_t addr;
addr = gpio_has_drv_str(gpio_id );
if ( addr )
{
return ((*(volatile uint8_t *)addr) >> GPIO_DRV_STR_BITPOS) & (GPIO_DRV_STR_MASK);
}
else
{
return 0u;
}
}
/**
* GPIOSetDriveStr - Program GPIO Pin's Drive Strength
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
* @param drv_str enumerated drive strength: 0=2mA, 1=4mA,
* 2=8mA, 3=12mA
*/
void GPIOSetDriveStr ( enum gpio_id_t gpio_id,
enum gpio_drv_str_t drv_str )
{
uint32_t addr;
uint8_t r8;
addr = gpio_has_drv_str(gpio_id);
if ( addr )
{
r8 = *(volatile uint8_t *)addr & ~(GPIO_DRV_STR_MASK);
r8 += ((drv_str << GPIO_DRV_STR_BITPOS) & GPIO_DRV_STR_MASK);
*(volatile uint8_t *)addr = r8;
}
}
/**
* GPIOGetDriveStrAndSlew - Return combined value representing
* Drive Strength and Slew Rate.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
*
* @return uint8_t bit[0] = Slew Rate, bits[3:1]=0(Reserved),
* bits[5:4]=Drive Strength, bits[7:6]=0(Reserved)
*/
uint8_t GPIOGetDriveStrAndSlew ( enum gpio_id_t gpio_id )
{
uint32_t addr;
addr = gpio_has_drv_str(gpio_id );
if ( addr )
{
return (*(volatile uint8_t *)addr);
}
else
{
return 0u;
}
}
/**
* GPIOSetDriveStrAndSlew - Program GPIO Pin's drive strength
* and slew rate.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
* @param drv_and_slew bit[0] = Slew Rate, bits[3:1]=0(Reserved),
* bits[5:4]=Drive Strength, bits[7:6]=0(Reserved)
*/
void GPIOSetDriveStrAndSlew ( enum gpio_id_t gpio_id,
uint8_t drv_and_slew )
{
uint32_t addr;
uint8_t r8;
addr = gpio_has_drv_str(gpio_id);
if ( addr )
{
r8 = *(volatile uint8_t *)addr & ~(GPIO_DRV_SLEW_MASK + GPIO_DRV_STR_MASK);
r8 |= (drv_and_slew & (GPIO_DRV_SLEW_MASK + GPIO_DRV_STR_MASK));
*(volatile uint8_t *)addr = r8;
}
}
/**
* GPIOSetOutput - Program GPIO Pin's output state using Pin
* configuration register (not parallel output register).
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID
* @param gpio_state pin state: actual pin state at pad will
* depend upon GPIO Output invert
* configuration.
* @note peforms a byte wide write to byte offset 2 of the GPIO
* Pin's 32-bit configuration register. No
* read-modify-write.
*/
void GPIOSetOutput ( enum gpio_id_t gpio_id,
uint8_t gpio_state
)
{
volatile uint8_t * p;
if ( gpio_is_valid(gpio_id) )
{
p = (volatile uint8_t *)(gpio_pin_ctrl_addr(gpio_id) + 2ul);
if (gpio_state) {
*p = 0x01u;
} else {
*p = 0u;
}
}
}
void GPIOToggleOutput ( enum gpio_id_t gpio_id )
{
volatile uint8_t * p;
if ( gpio_is_valid(gpio_id) )
{
p = (volatile uint8_t *)(gpio_pin_ctrl_addr(gpio_id) + 2ul);
*p ^= 0x01u;
}
}
/**
* GPIOReadPin - Read GPIO Pin's Pad Input from configuration
* register.
*
* @author sworley
*
* @param gpio_id 0-based GPIO ID.
*
* @return uint8_t 0 or 1 depending upon the state of the GPIO
* pad.
* @note performs a byte read of offset 3 of the GPIO Pin's
* 32-bit configuration register.
*/
uint8_t GPIOReadPin( enum gpio_id_t gpio_id )
{
if ( gpio_is_valid(gpio_id) )
{
return *((volatile uint8_t *)(gpio_pin_ctrl_addr(gpio_id) + 3ul));
}
else
{
return 0u;
}
}
/** GPIOPinLock - Lock specified GPIO's control register.
* @param enum gpio_id_t zero based GPIO ID
* @note Lock bit is only cleared on POR. Lock registers
* are in reverse order, first register is at top address.
* GPIO_LOCK_BASE defined to top(first) register address.
* */
void GPIOPinLock(enum gpio_id_t gpio_id)
{
uint32_t addr;
uint8_t bank, bitpos;
if (gpio_is_valid(gpio_id)) {
bank = gpio_bank_num(gpio_id); // 0 - 4
bitpos = gpio_pin_num(gpio_id); // 0 - 31
addr = (uint32_t)(GPIO_LOCK_BASE) - (bank << 2);
*(volatile uint32_t *)addr |= (1ul << bitpos);
}
}
/* end mec14xx_gpio.c */
/** @}
*/