|
|
|
/**
|
|
|
|
* @ingroup PAC55xx_gpio
|
|
|
|
* @brief <b>PAC55xxxx General-Purpose Input/Output (GPIO)</b>
|
|
|
|
* @author @htmlonly © @endhtmlonly 2019 Brian Viele <vielster@allocor.tech>
|
|
|
|
* @date December 1, 2019
|
|
|
|
*
|
|
|
|
* This library supports the GPIO module in the PAC55xx SoC from Qorvo.
|
|
|
|
*
|
|
|
|
* LGPL License Terms @ref lgpl_license
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* This file is part of the libopencm3 project.
|
|
|
|
*
|
|
|
|
* This library is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include <libopencm3/pac55xx/gpio.h>
|
|
|
|
|
|
|
|
static uint32_t get_ccs_port_base(uint32_t gpioport) {
|
|
|
|
switch (gpioport) {
|
|
|
|
case GPIOA:
|
|
|
|
return CCS_PORTA;
|
|
|
|
case GPIOB:
|
|
|
|
return CCS_PORTB;
|
|
|
|
case GPIOC:
|
|
|
|
return CCS_PORTC;
|
|
|
|
case GPIOD:
|
|
|
|
return CCS_PORTD;
|
|
|
|
case GPIOE:
|
|
|
|
return CCS_PORTE;
|
|
|
|
case GPIOF:
|
|
|
|
return CCS_PORTF;
|
|
|
|
case GPIOG:
|
|
|
|
return CCS_PORTG;
|
|
|
|
default:
|
|
|
|
return 0U;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_mode_setup(uint32_t gpioport, gpio_mode_t mode,
|
|
|
|
ccs_pull_updown_t pull_up_down, uint16_t gpios) {
|
|
|
|
/* Read the current value of the register. */
|
|
|
|
uint32_t reg = GPIO_MODER(gpioport);
|
|
|
|
uint32_t port = get_ccs_port_base(gpioport);
|
|
|
|
|
|
|
|
/* Loop through only set bits, utilize built-ins for optimized assembly. */
|
|
|
|
int ffs = __builtin_ffs(gpios);
|
|
|
|
while (ffs) {
|
|
|
|
const int pin = ffs - 1;
|
|
|
|
const int bit = (1 << pin);
|
|
|
|
|
|
|
|
/* Update the cached mode value by clearing then setting values. */
|
|
|
|
reg &= ~GPIO_MODER_MASK_PIN(pin);
|
|
|
|
reg |= GPIO_MODER_MODE(pin, mode);
|
|
|
|
|
|
|
|
/* Set the pinmux configurations for the pull-up / pull-down. */
|
|
|
|
if (pull_up_down == CCS_IO_PULL_UP) {
|
|
|
|
CCS_PDENR(port) &= ~bit;
|
|
|
|
CCS_PUENR(port) |= bit;
|
|
|
|
} else if (pull_up_down == CCS_IO_PULL_DOWN) {
|
|
|
|
CCS_PUENR(port) &= ~bit;
|
|
|
|
CCS_PDENR(port) |= bit;
|
|
|
|
} else {
|
|
|
|
CCS_PDENR(port) &= ~bit;
|
|
|
|
CCS_PUENR(port) &= ~bit;
|
|
|
|
}
|
|
|
|
gpios ^= bit; /* Clear the bit we just serviced. */
|
|
|
|
ffs = __builtin_ffs(gpios);
|
|
|
|
}
|
|
|
|
GPIO_MODER(gpioport) = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_set_outmask(uint32_t gpioport, bool enable, uint16_t gpios) {
|
|
|
|
uint32_t reg = GPIO_OUTMASKR(gpioport);
|
|
|
|
if (enable) {
|
|
|
|
reg |= gpios;
|
|
|
|
} else {
|
|
|
|
reg &= ~gpios;
|
|
|
|
}
|
|
|
|
GPIO_OUTMASKR(gpioport) = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_set(uint32_t gpioport, uint16_t gpios) {
|
|
|
|
GPIO_DOSETR(gpioport) = gpios;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_clear(uint32_t gpioport, uint16_t gpios) {
|
|
|
|
GPIO_DOCLEARR(gpioport) = gpios;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios) {
|
|
|
|
return GPIO_INR(gpioport) & gpios;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_set_af(uint32_t gpioport, ccs_muxsel_func_t muxsel, uint16_t gpios) {
|
|
|
|
uint32_t port = get_ccs_port_base(gpioport);
|
|
|
|
|
|
|
|
/* Update each of the pin configs. */
|
|
|
|
uint32_t reg = CCS_MUXSELR(port);
|
|
|
|
int ffs = __builtin_ffs(gpios);
|
|
|
|
while (ffs) {
|
|
|
|
const int pin = ffs - 1;
|
|
|
|
const int shift = pin * 4;
|
|
|
|
|
|
|
|
reg &= CCS_MUXSELR_MASK << shift;
|
|
|
|
reg |= muxsel << shift;
|
|
|
|
|
|
|
|
/* Set the pinmux configurations for the pull-up / pull-down. */
|
|
|
|
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
|
|
|
|
ffs = __builtin_ffs(gpios);
|
|
|
|
}
|
|
|
|
CCS_MUXSELR(port) = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_set_output_options(uint32_t gpioport, ccs_drive_strength_t strength,
|
|
|
|
uint16_t gpios) {
|
|
|
|
uint32_t port = get_ccs_port_base(gpioport);
|
|
|
|
|
|
|
|
/* Update each of the pin configs. */
|
|
|
|
uint32_t reg = CCS_DSR(port);
|
|
|
|
int ffs = __builtin_ffs(gpios);
|
|
|
|
while (ffs) {
|
|
|
|
const int pin = ffs - 1;
|
|
|
|
|
|
|
|
reg &= ~CCS_DSR_MASK_PIN(pin);
|
|
|
|
reg |= CCS_DSR_DS_VAL(pin, strength);
|
|
|
|
|
|
|
|
/* Set the pinmux configurations for the pull-up / pull-down. */
|
|
|
|
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
|
|
|
|
ffs = __builtin_ffs(gpios);
|
|
|
|
}
|
|
|
|
CCS_DSR(port) = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpio_set_schmidt_trigger(uint32_t gpioport, bool enable, uint16_t gpios) {
|
|
|
|
uint32_t port = get_ccs_port_base(gpioport);
|
|
|
|
|
|
|
|
/* Update each of the pin configs. */
|
|
|
|
uint32_t reg = CCS_DSR(port);
|
|
|
|
int ffs = __builtin_ffs(gpios);
|
|
|
|
while (ffs) {
|
|
|
|
const int pin = ffs - 1;
|
|
|
|
if (enable) {
|
|
|
|
reg |= CCS_DSR_SCHMIDT_PIN(pin);
|
|
|
|
} else {
|
|
|
|
reg &= ~CCS_DSR_SCHMIDT_PIN(pin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the pinmux configurations for the pull-up / pull-down. */
|
|
|
|
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
|
|
|
|
ffs = __builtin_ffs(gpios);
|
|
|
|
}
|
|
|
|
CCS_DSR(port) = reg;
|
|
|
|
}
|