164 lines
3.7 KiB
C
164 lines
3.7 KiB
C
/*
|
|
* Copyright (c) 2016 Open-RnD Sp. z o.o.
|
|
* Copyright (c) 2016 BayLibre, SAS
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @brief
|
|
*
|
|
* Based on reference manual:
|
|
* STM32L4x1, STM32L4x2, STM32L431xx STM32L443xx STM32L433xx, STM32L4x5,
|
|
* STM32l4x6 advanced ARM ® -based 32-bit MCUs
|
|
*
|
|
* 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>
|
|
|
|
|
|
enum {
|
|
STM32L4X_PIN3 = 3,
|
|
STM32L4X_PIN7 = 7,
|
|
STM32L4X_PIN11 = 11,
|
|
STM32L4X_PIN15 = 15,
|
|
};
|
|
|
|
#define STM32L4X_IDR_PIN_MASK 0x1
|
|
#define STM32L4X_AFR_MASK 0xf
|
|
|
|
/* GPIO registers - each GPIO port controls 16 pins */
|
|
struct stm32l4x_gpio {
|
|
u32_t moder;
|
|
u32_t otyper;
|
|
u32_t ospeedr;
|
|
u32_t pupdr;
|
|
u32_t idr;
|
|
u32_t odr;
|
|
u32_t bsrr;
|
|
u32_t lckr;
|
|
u32_t afr[2];
|
|
u32_t brr;
|
|
u32_t ascr; /* Only present on STM32L4x1, STM32L4x5, STM32L4x6 */
|
|
};
|
|
|
|
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) {
|
|
*pincfg = STM32_MODER_OUTPUT_MODE;
|
|
} else {
|
|
/* pull-{up,down} maybe? */
|
|
*pincfg = STM32_MODER_INPUT_MODE;
|
|
|
|
if (pud == GPIO_PUD_PULL_UP) {
|
|
*pincfg = *pincfg | STM32_PUPDR_PULL_UP;
|
|
} else if (pud == GPIO_PUD_PULL_DOWN) {
|
|
*pincfg = *pincfg | STM32_PUPDR_PULL_DOWN;
|
|
} else {
|
|
/* floating */
|
|
*pincfg = *pincfg | STM32_PUPDR_NO_PULL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_configure(u32_t *base_addr, int pin, int pinconf, int afnum)
|
|
{
|
|
volatile struct stm32l4x_gpio *gpio =
|
|
(struct stm32l4x_gpio *)(base_addr);
|
|
unsigned int mode, otype, ospeed, pupd;
|
|
unsigned int pin_shift = pin << 1;
|
|
unsigned int afr_bank = pin / 8;
|
|
unsigned int afr_shift = (pin % 8) << 2;
|
|
u32_t scratch;
|
|
|
|
mode = (pinconf >> STM32_MODER_SHIFT) & STM32_MODER_MASK;
|
|
otype = (pinconf >> STM32_OTYPER_SHIFT) & STM32_OTYPER_MASK;
|
|
ospeed = (pinconf >> STM32_OSPEEDR_SHIFT) & STM32_OSPEEDR_MASK;
|
|
pupd = (pinconf >> STM32_PUPDR_SHIFT) & STM32_PUPDR_MASK;
|
|
|
|
scratch = gpio->moder & ~(STM32_MODER_MASK << pin_shift);
|
|
gpio->moder = scratch | (mode << pin_shift);
|
|
|
|
scratch = gpio->ospeedr & ~(STM32_OSPEEDR_MASK << pin_shift);
|
|
gpio->ospeedr = scratch | (ospeed << pin_shift);
|
|
|
|
scratch = gpio->otyper & ~(STM32_OTYPER_MASK << pin);
|
|
gpio->otyper = scratch | (otype << pin);
|
|
|
|
scratch = gpio->pupdr & ~(STM32_PUPDR_MASK << pin_shift);
|
|
gpio->pupdr = scratch | (pupd << pin_shift);
|
|
|
|
scratch = gpio->afr[afr_bank] & ~(STM32_AFR_MASK << afr_shift);
|
|
gpio->afr[afr_bank] = scratch | (afnum << afr_shift);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_set(u32_t *base, int pin, int value)
|
|
{
|
|
struct stm32l4x_gpio *gpio = (struct stm32l4x_gpio *)base;
|
|
int pval = 1 << (pin & 0xf);
|
|
|
|
if (value) {
|
|
gpio->odr |= pval;
|
|
} else {
|
|
gpio->odr &= ~pval;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int stm32_gpio_get(u32_t *base, int pin)
|
|
{
|
|
struct stm32l4x_gpio *gpio = (struct stm32l4x_gpio *)base;
|
|
|
|
return (gpio->idr >> pin) & STM32L4X_IDR_PIN_MASK;
|
|
}
|
|
|
|
int stm32_gpio_enable_int(int port, int pin)
|
|
{
|
|
struct stm32l4x_syscfg *syscfg = (struct stm32l4x_syscfg *)SYSCFG_BASE;
|
|
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
|
|
u32_t *reg;
|
|
|
|
/* Enable SYSCFG clock */
|
|
struct stm32_pclken pclken = {
|
|
.bus = STM32_CLOCK_BUS_APB2,
|
|
.enr = LL_APB2_GRP1_PERIPH_SYSCFG
|
|
};
|
|
clock_control_on(clk, (clock_control_subsys_t *) &pclken);
|
|
|
|
if (pin <= STM32L4X_PIN3) {
|
|
reg = &syscfg->exticr1;
|
|
} else if (pin <= STM32L4X_PIN7) {
|
|
reg = &syscfg->exticr2;
|
|
} else if (pin <= STM32L4X_PIN11) {
|
|
reg = &syscfg->exticr3;
|
|
} else if (pin <= STM32L4X_PIN15) {
|
|
reg = &syscfg->exticr4;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*reg &= STM32L4X_SYSCFG_EXTICR_PIN_MASK << ((pin % 4) * 4);
|
|
*reg |= port << ((pin % 4) * 4);
|
|
|
|
return 0; /* Nothing to do here for STM32L4s */
|
|
}
|