mirror of https://github.com/ARMmbed/mbed-os.git
202 lines
6.2 KiB
C
202 lines
6.2 KiB
C
/**
|
|
******************************************************************************
|
|
* @file gpio_api.c
|
|
* @brief Implementation of a GPIO driver
|
|
* @internal
|
|
* @author ON Semiconductor
|
|
* $Rev:
|
|
* $Date: 2015-11-04 $
|
|
******************************************************************************
|
|
* Copyright 2016 Semiconductor Components Industries LLC (d/b/a “ON Semiconductor”).
|
|
* All rights reserved. This software and/or documentation is licensed by ON Semiconductor
|
|
* under limited terms and conditions. The terms and conditions pertaining to the software
|
|
* and/or documentation are available at http://www.onsemi.com/site/pdf/ONSEMI_T&C.pdf
|
|
* (“ON Semiconductor Standard Terms and Conditions of Sale, Section 8 Software”) and
|
|
* if applicable the software license agreement. Do not use this software and/or
|
|
* documentation unless you have carefully read and you agree to the limited terms and
|
|
* conditions. By using this software and/or documentation, you agree to the limited
|
|
* terms and conditions.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
|
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
|
* ON SEMICONDUCTOR SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL,
|
|
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
|
* @endinternal
|
|
*
|
|
* @ingroup gpio
|
|
*
|
|
* @details
|
|
*
|
|
* @internal
|
|
* <h1> Reference document(s) </h1>
|
|
* <p>
|
|
* Reference document: IPC7203 APB GPIO Design Specification v1.2</a>
|
|
* </p>
|
|
* @endinternal
|
|
*
|
|
* <h1> Functional description (internal) </h1>
|
|
* <p>
|
|
* Each GPIO line can be independently programmed as an input or an output. Separate Set
|
|
* and Clear registers are provided since it is likely that different software tasks may be
|
|
* servicing different I/O signals. Inputs are synchronized to the system clock
|
|
* through a pair of flip-flops. Each input can be programmed
|
|
* to cause an interrupt to be generated. The interrupt can be programmed to be level-sensitive
|
|
* or edge-sensitive and the level (high or low) or edge (rising, falling or either) that causes
|
|
* the interrupt can be selected. Interrupts can be individually enabled or disabled.
|
|
* Level-sensitive interrupts stay asserted until the interrupting condition is cleared.
|
|
* Edge-triggered interrupts are cleared by writing to the GPIO interrupt clear register.
|
|
* </p>
|
|
*
|
|
* <h1> Use of GPIO driver in SW </h1>
|
|
* <p>
|
|
* The user of the GPIO driver should set the pin as GPIO, using crossbar.
|
|
* Init the GPIO and configure the mode and direction.This will return a device pointer. One device controls all GPIO's. It is not
|
|
* needed nor supported to create a device per GPIO.
|
|
* Next, the user should call the fGpioOpen function with the device and options as paramter.
|
|
* </p>
|
|
* <p>
|
|
* Use the device driver fGpioIoctl function to change the behavior of the GPIO's and to register an
|
|
* interrupt handler for each IO that has an interrupt enabled. There is one interrupt for all GPIO's.
|
|
* The GPIO driver will look up what IO caused the interrupt and call the respective interrupt handler.
|
|
* </p>
|
|
*/
|
|
|
|
#include "gpio.h"
|
|
|
|
/* Include from the mbed-hal layer */
|
|
#include "gpio_api.h"
|
|
#include "pinmap.h"
|
|
|
|
|
|
/** Set the given pin as GPIO
|
|
*
|
|
* @param pin The pin to be set as GPIO
|
|
* @return The GPIO port mask for this pin
|
|
**/
|
|
uint32_t gpio_set(PinName pin)
|
|
{
|
|
if (pin != NC) {
|
|
/* Configure to GPIO using pin function API*/
|
|
pin_function(pin, CONFIGURE_AS_GPIO);
|
|
|
|
return ((uint32_t) 0x1 << pin);
|
|
|
|
}
|
|
|
|
return(0x00000000);
|
|
|
|
}
|
|
|
|
/** Initialize the GPIO pin
|
|
*
|
|
* @param obj The GPIO object to initialize
|
|
* @param pin The GPIO pin to initialize
|
|
*/
|
|
void gpio_init(gpio_t *obj, PinName pin)
|
|
{
|
|
/* Initialize the GPIO membase */
|
|
obj->GPIOMEMBASE = GPIOREG;
|
|
|
|
/* Initialize the pin to be GPIO */
|
|
obj->gpioPin = pin;
|
|
obj->gpioMask = gpio_set(pin);
|
|
|
|
/* Enable the GPIO clock */
|
|
CLOCK_ENABLE(CLOCK_GPIO);
|
|
|
|
/* Set the drive strength of the pin to 1 by default */
|
|
/** - Get PAD IO register address for the PAD number */
|
|
PadReg_t *PadRegOffset = (PadReg_t*)(PADREG_BASE + (pin * PAD_REG_ADRS_BYTE_SIZE));
|
|
|
|
/** - Enable the clock for PAD peripheral device */
|
|
CLOCK_ENABLE(CLOCK_PAD);
|
|
|
|
/** - Set drive type, pulltype & drive strength */
|
|
PadRegOffset->PADIO0.BITS.POWER = 1;
|
|
|
|
/** - Disable the clock for PAD peripheral device */
|
|
CLOCK_DISABLE(CLOCK_PAD);
|
|
}
|
|
|
|
/** Set the input pin mode
|
|
*
|
|
* @param obj The GPIO object
|
|
* @param mode The pin mode to be set
|
|
*/
|
|
void gpio_mode(gpio_t *obj, PinMode mode)
|
|
{
|
|
uint32_t pin = obj->gpioPin;
|
|
|
|
/* Set the mode for the pin */
|
|
pin_mode((PinName)pin, mode);
|
|
}
|
|
|
|
/** Set the pin direction
|
|
*
|
|
* @param obj The GPIO object
|
|
* @param direction The pin direction to be set
|
|
*/
|
|
void gpio_dir(gpio_t *obj, PinDirection direction)
|
|
{
|
|
/* Enable the GPIO clock which may have been switched off by other drivers */
|
|
CLOCK_ENABLE(CLOCK_GPIO);
|
|
|
|
if (direction == PIN_INPUT) {
|
|
obj->GPIOMEMBASE->W_IN = obj->gpioMask;
|
|
} else if (direction == PIN_OUTPUT) {
|
|
obj->GPIOMEMBASE->W_OUT = obj->gpioMask;
|
|
}
|
|
|
|
}
|
|
|
|
/** Set the output value
|
|
*
|
|
* @param obj The GPIO object
|
|
* @param value The value to be set
|
|
*/
|
|
void gpio_write(gpio_t *obj, int value)
|
|
{
|
|
|
|
/* Enable the GPIO clock which may have been switched off by other drivers */
|
|
CLOCK_ENABLE(CLOCK_GPIO);
|
|
|
|
/* Set the GPIO based on value */
|
|
if (value) {
|
|
obj->GPIOMEMBASE->R_STATE_W_SET = obj->gpioMask;
|
|
} else {
|
|
obj->GPIOMEMBASE->R_IRQ_W_CLEAR = obj->gpioMask;
|
|
}
|
|
|
|
}
|
|
|
|
/** Read the input value
|
|
*
|
|
* @param obj The GPIO object
|
|
* @return An integer value 1 or 0
|
|
*/
|
|
int gpio_read(gpio_t *obj)
|
|
{
|
|
int ret;
|
|
|
|
/* Enable the GPIO clock which may have been switched off by other drivers */
|
|
CLOCK_ENABLE(CLOCK_GPIO);
|
|
|
|
ret = (obj->GPIOMEMBASE->R_STATE_W_SET & obj->gpioMask) ? 1: 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Checks if gpio object is connected (pin was not initialized with NC)
|
|
* @param pin The pin to be set as GPIO
|
|
* @return 0 if port is initialized with NC
|
|
**/
|
|
int gpio_is_connected(const gpio_t *obj)
|
|
{
|
|
if(obj->gpioPin != (PinName)NC) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|