blob: 7b7536be44f2689a29f69aa62b5cdb6e2b0e75f4 [file] [log] [blame]
/*
* Copyright (c) 2016 Open-RnD Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @brief
*
* Based on reference manual:
* STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx
* advanced ARM ® -based 32-bit MCUs
*
* Chapter 9: General-purpose and alternate-function I/Os
* (GPIOs and AFIOs)
*/
#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 uint32_t __func_to_mode(int func)
{
switch (func) {
case STM32F10X_PIN_CONFIG_ANALOG:
case STM32F10X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
case STM32F10X_PIN_CONFIG_BIAS_PULL_UP:
case STM32F10X_PIN_CONFIG_BIAS_PULL_DOWN:
return 0;
case STM32F10X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
case STM32F10X_PIN_CONFIG_DRIVE_PUSH_PULL:
case STM32F10X_PIN_CONFIG_AF_PUSH_PULL:
case STM32F10X_PIN_CONFIG_AF_OPEN_DRAIN:
return 0x1;
}
return 0;
}
/**
* @brief map pin function to CNF register value
*/
static uint32_t __func_to_cnf(int func)
{
switch (func) {
case STM32F10X_PIN_CONFIG_ANALOG:
return 0x0;
case STM32F10X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
return 0x1;
case STM32F10X_PIN_CONFIG_BIAS_PULL_UP:
case STM32F10X_PIN_CONFIG_BIAS_PULL_DOWN:
return 0x2;
case STM32F10X_PIN_CONFIG_DRIVE_PUSH_PULL:
return 0x0;
case STM32F10X_PIN_CONFIG_DRIVE_OPEN_DRAIN:
return 0x1;
case STM32F10X_PIN_CONFIG_AF_PUSH_PULL:
return 0x2;
case STM32F10X_PIN_CONFIG_AF_OPEN_DRAIN:
return 0x3;
}
return 0;
}
int stm32_gpio_flags_to_conf(int flags, int *pincfg)
{
int direction = flags & GPIO_DIR_MASK;
if (!pincfg) {
return -EINVAL;
}
if (direction == GPIO_DIR_OUT) {
*pincfg = STM32F10X_PIN_CONFIG_DRIVE_PUSH_PULL;
} else if (direction == GPIO_DIR_IN) {
int pud = flags & GPIO_PUD_MASK;
/* pull-{up,down} maybe? */
if (pud == GPIO_PUD_PULL_UP) {
*pincfg = STM32F10X_PIN_CONFIG_BIAS_PULL_UP;
} else if (pud == GPIO_PUD_PULL_DOWN) {
*pincfg = STM32F10X_PIN_CONFIG_BIAS_PULL_DOWN;
} else {
/* floating */
*pincfg = STM32F10X_PIN_CONFIG_BIAS_HIGH_IMPEDANCE;
}
} else {
return -ENOTSUP;
}
return 0;
}
int stm32_gpio_configure(uint32_t *base_addr, int pin, int conf)
{
volatile struct stm32f10x_gpio *gpio =
(struct stm32f10x_gpio *)(base_addr);
int cnf, mode;
int crpin = pin;
/* pins are configured in CRL (0-7) and CRH (8-15)
* registers
*/
volatile uint32_t *reg = &gpio->crl;
if (crpin > 7) {
reg = &gpio->crh;
crpin -= 8;
}
/* each port is configured by 2 registers:
* CNFy[1:0]: Port x configuration bits
* MODEy[1:0]: Port x mode bits
*
* memory layout is repeated for every port:
* | CNF | MODE |
* | [0:1] | [0:1] |
*/
cnf = __func_to_cnf(conf);
mode = __func_to_mode(conf);
/* clear bits */
*reg &= ~(0xf << (crpin * 4));
/* set bits */
*reg |= (cnf << (crpin * 4 + 2) | mode << (crpin * 4));
/* input mode - 0x1 */
if (conf == STM32F10X_PIN_CONFIG_BIAS_PULL_UP) {
/* enable pull up */
gpio->odr |= 1 << pin;
} else if (conf == STM32F10X_PIN_CONFIG_BIAS_PULL_DOWN) {
/* or pull down */
gpio->odr &= ~(1 << pin);
}
return 0;
}
int stm32_gpio_set(uint32_t *base, int pin, int value)
{
struct stm32f10x_gpio *gpio = (struct stm32f10x_gpio *)base;
int pval = 1 << (pin & 0xf);
if (value) {
gpio->odr |= pval;
} else {
gpio->odr &= ~pval;
}
return 0;
}
int stm32_gpio_get(uint32_t *base, int pin)
{
struct stm32f10x_gpio *gpio = (struct stm32f10x_gpio *)base;
return (gpio->idr >> pin) & 0x1;
}
int stm32_gpio_enable_int(int port, int pin)
{
volatile struct stm32f10x_afio *afio =
(struct stm32f10x_afio *)AFIO_BASE;
volatile union __afio_exticr *exticr;
int shift = 0;
if (pin <= 3) {
exticr = &afio->exticr1;
} else if (pin <= 7) {
exticr = &afio->exticr2;
} else if (pin <= 11) {
exticr = &afio->exticr3;
} else if (pin <= 15) {
exticr = &afio->exticr4;
} else {
return -EINVAL;
}
shift = 4 * (pin % 4);
exticr->val &= ~(0xf << shift);
exticr->val |= port << shift;
return 0;
}