Convert code to use u{8,16,32,64}_t and s{8,16,32,64}_t instead of C99 integer types. There are few places we dont convert over to the new types because of compatiability with ext/HALs or for ease of transition at this point. Fixup a few of the PRI formatters so we build with newlib. Jira: ZEP-2051 Change-Id: I7d2d3697cad04f20aaa8f6e77228f502cd9c8286 Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
264 lines
6.1 KiB
C
264 lines
6.1 KiB
C
/*
|
|
* Copyright (c) Linaro Limited.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @brief
|
|
*
|
|
* Based on reference manual:
|
|
* RM0368 Reference manual STM32F401xB/C and STM32F401xD/E
|
|
* advanced ARM ® -based 32-bit MCUs
|
|
*
|
|
* Chapter 8: General-purpose I/Os (GPIOs)
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include <device.h>
|
|
#include "soc.h"
|
|
#include "soc_registers.h"
|
|
#include <gpio.h>
|
|
#include <gpio/gpio_stm32.h>
|
|
|
|
/**
|
|
* @brief map pin function to MODE register value
|
|
*/
|
|
static u32_t __func_to_mode(int func)
|
|
{
|
|
switch (func) {
|
|
case STM32F4X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
|
case STM32F4X_PIN_CONFIG_BIAS_PULL_UP:
|
|
case STM32F4X_PIN_CONFIG_BIAS_PULL_DOWN:
|
|
return 0x0;
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DOWN:
|
|
return 0x1;
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DOWN:
|
|
return 0x2;
|
|
case STM32F4X_PIN_CONFIG_ANALOG:
|
|
return 0x3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief map pin function to OTYPE register value
|
|
*/
|
|
static u32_t __func_to_otype(int func)
|
|
{
|
|
switch (func) {
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DOWN:
|
|
return 0x1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief map pin function to OSPEED register value
|
|
*/
|
|
static u32_t __func_to_ospeed(int func)
|
|
{
|
|
switch (func) {
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DOWN:
|
|
/* Force fast speed by default */
|
|
return 0x2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief map pin function to PUPD register value
|
|
*/
|
|
static u32_t __func_to_pupd(int func)
|
|
{
|
|
switch (func) {
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_PULL:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DRAIN:
|
|
case STM32F4X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
|
case STM32F4X_PIN_CONFIG_ANALOG:
|
|
return 0x0;
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_UP:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_UP:
|
|
case STM32F4X_PIN_CONFIG_BIAS_PULL_UP:
|
|
return 0x1;
|
|
case STM32F4X_PIN_CONFIG_DRIVE_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_DRIVE_OPEN_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_PUSH_DOWN:
|
|
case STM32F4X_PIN_CONFIG_AF_OPEN_DOWN:
|
|
case STM32F4X_PIN_CONFIG_BIAS_PULL_DOWN:
|
|
return 0x2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int stm32_gpio_flags_to_conf(int flags, int *pincfg)
|
|
{
|
|
int direction = flags & GPIO_DIR_MASK;
|
|
int pud = flags & GPIO_PUD_MASK;
|
|
|
|
if (!pincfg) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (direction == GPIO_DIR_OUT) {
|
|
if (pud == GPIO_PUD_PULL_UP) {
|
|
*pincfg = STM32F4X_PIN_CONFIG_DRIVE_PUSH_UP;
|
|
} else if (pud == GPIO_PUD_PULL_DOWN) {
|
|
*pincfg = STM32F4X_PIN_CONFIG_DRIVE_PUSH_DOWN;
|
|
} else {
|
|
*pincfg = STM32F4X_PIN_CONFIG_DRIVE_PUSH_PULL;
|
|
}
|
|
} else if (direction == GPIO_DIR_IN) {
|
|
if (pud == GPIO_PUD_PULL_UP) {
|
|
*pincfg = STM32F4X_PIN_CONFIG_BIAS_PULL_UP;
|
|
} else if (pud == GPIO_PUD_PULL_DOWN) {
|
|
*pincfg = STM32F4X_PIN_CONFIG_BIAS_PULL_DOWN;
|
|
} else {
|
|
*pincfg = STM32F4X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE;
|
|
}
|
|
} else {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_configure(u32_t *base_addr, int pin, int conf, int altf)
|
|
{
|
|
volatile struct stm32f4x_gpio *gpio =
|
|
(struct stm32f4x_gpio *)(base_addr);
|
|
u32_t mode = __func_to_mode(conf);
|
|
u32_t otype = __func_to_otype(conf);
|
|
u32_t ospeed = __func_to_ospeed(conf);
|
|
u32_t pupd = __func_to_pupd(conf);
|
|
u32_t tmpreg = 0;
|
|
|
|
/* TODO: validate if indeed alternate */
|
|
if (altf) {
|
|
/* Set the alternate function */
|
|
tmpreg = gpio->afr[pin >> 0x3];
|
|
tmpreg &= ~(0xf << ((pin & 0x07) * 4));
|
|
tmpreg |= (altf << ((pin & 0x07) * 4));
|
|
gpio->afr[pin >> 0x3] = tmpreg;
|
|
}
|
|
|
|
/* Set the IO direction mode */
|
|
tmpreg = gpio->mode;
|
|
tmpreg &= ~(0x3 << (pin * 2));
|
|
tmpreg |= (mode << (pin * 2));
|
|
gpio->mode = tmpreg;
|
|
|
|
if (otype) {
|
|
tmpreg = gpio->otype;
|
|
tmpreg &= ~(0x1 << pin);
|
|
tmpreg |= (otype << pin);
|
|
gpio->otype = tmpreg;
|
|
}
|
|
|
|
if (ospeed) {
|
|
tmpreg = gpio->ospeed;
|
|
tmpreg &= ~(0x3 << (pin * 2));
|
|
tmpreg |= (ospeed << (pin * 2));
|
|
gpio->ospeed = tmpreg;
|
|
}
|
|
|
|
tmpreg = gpio->pupdr;
|
|
tmpreg &= ~(0x3 << (pin * 2));
|
|
tmpreg |= (pupd << (pin * 2));
|
|
gpio->pupdr = tmpreg;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_set(u32_t *base, int pin, int value)
|
|
{
|
|
struct stm32f4x_gpio *gpio = (struct stm32f4x_gpio *)base;
|
|
|
|
if (value) {
|
|
/* atomic set */
|
|
gpio->bsr = (1 << (pin & 0x0f));
|
|
} else {
|
|
/* atomic reset */
|
|
gpio->bsr = (1 << ((pin & 0x0f) + 0x10));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_get(u32_t *base, int pin)
|
|
{
|
|
struct stm32f4x_gpio *gpio = (struct stm32f4x_gpio *)base;
|
|
|
|
return (gpio->idr >> pin) & 0x1;
|
|
}
|
|
|
|
int stm32_gpio_enable_int(int port, int pin)
|
|
{
|
|
volatile struct stm32f4x_syscfg *syscfg =
|
|
(struct stm32f4x_syscfg *)SYSCFG_BASE;
|
|
volatile union syscfg_exticr *exticr;
|
|
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
|
|
struct stm32f4x_pclken pclken = {
|
|
.bus = STM32F4X_CLOCK_BUS_APB2,
|
|
.enr = STM32F4X_CLOCK_ENABLE_SYSCFG
|
|
};
|
|
int shift = 0;
|
|
|
|
/* Enable SYSCFG clock */
|
|
clock_control_on(clk, (clock_control_subsys_t *) &pclken);
|
|
|
|
if (pin <= 3) {
|
|
exticr = &syscfg->exticr1;
|
|
} else if (pin <= 7) {
|
|
exticr = &syscfg->exticr2;
|
|
} else if (pin <= 11) {
|
|
exticr = &syscfg->exticr3;
|
|
} else if (pin <= 15) {
|
|
exticr = &syscfg->exticr4;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
shift = 4 * (pin % 4);
|
|
|
|
exticr->val &= ~(0xf << shift);
|
|
exticr->val |= port << shift;
|
|
|
|
return 0;
|
|
}
|