| /* |
| * 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 */ |
| } |