/* sysGpio.c - TIAM335X GPIO module support library */
/*
* Copyright (c) 2012 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01b,12dec12,sye updated to be a generic library.
01a,09may12,my_ written.
*/
/*
DESCRIPTION
This library provides support routines for the ti_am335x_evm GPIO.
A GPIO is a software controlled digital signal which represents a bit
connected to a particular pin. Logically, GPIOs are identified by unsigned
integers from 0 to GPIO_MAX_NUMBER, and the number of a specified board may
vary. GPIOs are commonly grouped in banks and each bank have several GPIO
pins together. On OMAP AM335X, there are 4 banks of GPIOs, and each bank have
32 GPIO pins which makes a total number of 128 GPIOs.
\h Features
This library provides generic GPIO features includes:
- Allocation and free
A GPIO must be allocated before use. Allocation means the GPIO is used as a
specified function and can not be used by other functions until it is freed.
A terminated string describing the GPIO usage can be provided by the caller
to track its function.
- Direction selection and value getting/setting
A GPIO can be used as input or output. Input is readable and output is writable,
and the gpio value can be level high (GPIO_VALUE_HIGH) or level low
(GPIO_VALUE_LOW). The GPIO direction must be selected before further operations.
Example: value getting and setting, interrupt connection, etc.
- Interrupt handling
When a GPIO is selected as input, it can also be used as an IRQ signal. All
GPIOs within a bank share the interrupt of the bank and check the IRQ status of
the bank can identify which one triggered it. A generic ISR is connected to the
GPIO bank interrupt if any GPIO within the bank want to use the interrupt
function. A user ISR can be chained to the generic ISR and be called by it when
the interrupt source is identified.
Before interrupt can be used, the GPIO interrupt trigger mode must be set. The
supported modes are: GPIO_IRQ_LOW_LEVEL_SENSITIVE, GPIO_IRQ_HIGH_LEVEL_SENSITIVE
, GPIO_IRQ_RISING_EDGE_SENSITIVE, GPIO_IRQ_FALLING_EDGE_SENSITIVE and
GPIO_IRQ_BOTH_EDGE_SENSITIVE.
The interrupt must be connected then enabled and vice versa, it must be disabled
then disconnected.
- Hardware debounce
The GPIO has inner glitch issues, if no debounce handling, the GPIO value may
not be right. This library supports hardware debounce features to be enabled or
disabled. The debounce time is global for one GPIO bank and steps in
GPIO_DEBOUNCE_STEPS microseconds, it can be set from GPIO_DEBOUNCE_STEPS to
256 * GPIO_DEBOUNCE_STEPS microseconds. If hardware debounce is not enabled on
the board (Example: hardware debounce capacitors are not installed), software
debounce must be used to remove the glitch issues.
\h Calling sequences
Typical calling sequences include:
/@ used as input @/
sysGpioAlloc (...)
sysGpioSelectInput (...)
sysGpioGetValue (...)
sysGpioFree (...)
/@ used as input and interrupt @/
sysGpioAlloc (...)
sysGpioSelectInput (...)
sysGpioSetDebounceTime (...)
sysGpioEnableDebounce (...)
sysGpioIntConnect (...)
sysGpioIntEnable (...)
sysGpioGetValue (...)
sysGpioIntDisable (...)
sysGpioIntDisconnect (...)
sysGpioDisableDebounce (...)
sysGpioFree (...)
/@ used as output @/
sysGpioAlloc (...)
sysGpioSelectOutput (...)
sysGpioSetValue (...)
sysGpioFree (...)
\h Notes
Normally, the GPIO pin is multiplexed, the user of this library should ensure
the right multiplexing.
To add this library to the vxWorks image, add the following component to the
kernel configuration, or define the following macro in config.h.
\cs
vxprj component add INCLUDE_SYS_GPIO
\ce
\cs
#define INCLUDE_SYS_GPIO
\ce
INCLUDE FILES: sysGpio.h
*/
#include <stdio.h>
#include <vxWorks.h>
#include <intLib.h>
#include <spinLockLib.h>
#include "ti_am335x_evm.h"
#include "sysGpio.h"
/* defines */
#define GPIO_MAX_NUMBER (0x100)
#define GPIO_USER_DATA_WIDTH (32)
#define GPIO_MAX_DEBOUNCE (0xff)
#define GPIO_DEBOUNCE_STEPS (31)
#define GPIO_VEC_NUM (2)
#define GPIO_SYS_CONFIG_SOFTRESET (1 << 1)
#define AM335X_GPIO_BANK_NUM (4)
#define AM335X_GPIO_BANK_WIDTH (32)
#define SYS_GPIO_WRITE32(reg, value) (*(volatile unsigned int *)(reg) = (value))
#define SYS_GPIO_READ32(reg) (*(volatile unsigned int *)(reg))
#define SYS_GPIO_TO_BANK(gpio) ((gpio) / AM335X_GPIO_BANK_WIDTH)
#define SYS_GPIO_TO_PIN(gpio) ((gpio) % AM335X_GPIO_BANK_WIDTH)
#define SYS_GPIO_BIT(gpio) (1 << SYS_GPIO_TO_PIN(gpio))
#define SYS_GPIO_NUM (AM335X_GPIO_BANK_NUM * \
AM335X_GPIO_BANK_WIDTH)
/* typdefs */
struct gpioVectorItem
{
UINT32 v0;
UINT32 v1;
};
typedef struct gpioReg
{
UINT32 revision;
UINT32 sysConfig;
UINT32 irqStatus[GPIO_VEC_NUM];
UINT32 irqStatusSet[GPIO_VEC_NUM];
UINT32 irqStatusClr[GPIO_VEC_NUM];
UINT32 sysStatus;
UINT32 ctrl;
UINT32 oe;
UINT32 dataIn;
UINT32 dataOut;
UINT32 levelDetect0;
UINT32 levelDetect1;
UINT32 risingDetect;
UINT32 fallingDetect;
UINT32 debounceEnable;
UINT32 debounceTime;
UINT32 clearDataOut;
UINT32 setDataOut;
} GPIO_REG;
struct gpioIsrData
{
FUNCPTR func;
void * arg;
};
typedef struct gpioBank
{
UINT32 base;
atomicVal_t pinUsed;
atomicVal_t isrInstalled[GPIO_VEC_NUM];
spinlockIsr_t lock;
UINT32 vec[GPIO_VEC_NUM];
UINT16 trigger[AM335X_GPIO_BANK_WIDTH];
GPIO_REG reg;
char * usage[GPIO_USER_DATA_WIDTH];
struct gpioIsrData isr[GPIO_USER_DATA_WIDTH];
} GPIO_BANK;
typedef struct gpioIntParam
{
GPIO_BANK * pGpioBank;
UINT32 vecIndex;
} GPIO_INT_PARAM;
/* locals */
LOCAL struct gpioVectorItem gpioVector[AM335X_GPIO_BANK_NUM] =
{
{AM335X_GPIOINT0A, AM335X_GPIOINT0B},
{AM335X_GPIOINT1A, AM335X_GPIOINT1B},
{AM335X_GPIOINT2A, AM335X_GPIOINT2B},
{AM335X_GPIOINT3A, AM335X_GPIOINT3B},
};
LOCAL GPIO_BANK gpioBank[AM335X_GPIO_BANK_NUM];
LOCAL GPIO_INT_PARAM gpioParam[AM335X_GPIO_BANK_NUM * 2] =
{
{&gpioBank[0], 0},
{&gpioBank[0], 1},
{&gpioBank[1], 0},
{&gpioBank[1], 1},
{&gpioBank[2], 0},
{&gpioBank[2], 1},
{&gpioBank[3], 0},
{&gpioBank[3], 1},
};
/* forward declarations */
_WRS_INLINE void sysGpioBankSetData (GPIO_BANK * pGpioBank, UINT32 val);
_WRS_INLINE void sysGpioSetIrqAck (GPIO_BANK * pGpioBank, UINT32 bit,
UINT32 vecIndex);
_WRS_INLINE void sysGpioSetDebounceEn (GPIO_BANK * pGpioBank,
UINT32 bit, BOOL isEnable);
_WRS_INLINE void sysGpioSetDir (GPIO_BANK * pGpioBank, UINT32 bit,
BOOL isInput);
_WRS_INLINE void sysGpioSetDataOut (GPIO_BANK * pGpioBank, UINT32 val);
_WRS_INLINE void sysGpioClearDataOut (GPIO_BANK * pGpioBank, UINT32 val);
_WRS_INLINE void sysGpioSetDebounceEn (GPIO_BANK * pGpioBank,
UINT32 bit, BOOL isEnable);
_WRS_INLINE void sysGpioSetIrqAck (GPIO_BANK * pGpioBank, UINT32 bit,
UINT32 vecIndex);
LOCAL void sysGpioSetIrqEnable (GPIO_BANK * pGpioBank, BOOL isEnable,
UINT32 bit, UINT32 vecIndex);
LOCAL void sysGpioSetIrqTrigger (GPIO_BANK * pGpioBank, UINT32 bit,
UINT32 trigger);
LOCAL GPIO_BANK * sysGpioCheckValid (UINT32 gpio);
LOCAL void sysGpio