1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 04:32:52 +01:00
RIOT/cpu/atmega_common/periph/gpio_ll.c
Marian Buschsieweke 2a00ec13e5
drivers/periph/gpio_ll: shrink gpio_conf_t
This commit optimizes the `gpio_conf_t` type in the following
regards:

- The "base" `gpio_conf_t` is stripped from members that only some
  platforms support, e.g. drive strength, slew rate, and disabling of
  the Schmitt Trigger are no longer universally available but
  platform-specific extensions
- The `gpio_conf_t` is now crammed into a bit-field that is 8 bit or
  16 bit wide. This allows for storing lots of them e.g. in
  `driver_foo_params_t` or `uart_conf_t` etc.
- A `union` of the `struct` with bit-field members and a `bits` is used
  to allow accessing all bits in a simple C statement and to ensure
  alignment for efficient handling of the type

Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
2024-01-21 08:38:40 +01:00

97 lines
2.5 KiB
C

/*
* Copyright (C) 2015 HAW Hamburg
* 2016 INRIA
* 2021 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_atmega_common
* @ingroup drivers_periph_gpio_ll
* @{
*
* @file
* @brief Peripheral GPIO Low-Level API implementation for the ATmega GPIO peripheral
*
* @author René Herthel <rene-herthel@outlook.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
* @author Laurent Navet <laurent.navet@gmail.com>
* @author Robert Hartung <hartung@ibr.cs.tu-bs.de>
* @author Torben Petersen <petersen@ibr.cs.tu-bs.de>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <string.h>
#include "cpu.h"
#include "irq.h"
#include "periph/gpio_ll.h"
static void _set_dir(gpio_port_t port, uint8_t pin, bool output)
{
atmega_gpio_port_t *p = (void *)port;
if (output) {
p->ddr |= 1U << pin;
}
else {
p-> ddr &= ~(1U << pin);
}
}
static bool _is_output(gpio_port_t port, uint8_t pin)
{
atmega_gpio_port_t *p = (void *)port;
return (p->ddr >> pin) & 1U;
}
static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull)
{
atmega_gpio_port_t *p = (void *)port;
p->port |= pull << pin;
}
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
{
if ((conf->pull > GPIO_PULL_UP)
|| (conf->state == GPIO_OUTPUT_OPEN_DRAIN)
|| (conf->state == GPIO_OUTPUT_OPEN_SOURCE)) {
return -ENOTSUP;
}
unsigned state = irq_disable();
if (conf->initial_value) {
gpio_ll_set(port, 1UL << pin);
}
else {
gpio_ll_clear(port, 1UL << pin);
}
_set_dir(port, pin, conf->state == GPIO_OUTPUT_PUSH_PULL);
if (conf->state == GPIO_INPUT) {
_set_pull_config(port, pin, conf->pull);
}
irq_restore(state);
return 0;
}
void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
{
assert(dest);
memset(dest, 0, sizeof(*dest));
if (_is_output(port, pin)) {
dest->state = GPIO_OUTPUT_PUSH_PULL;
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1U;
}
else {
dest->state = GPIO_INPUT;
dest->pull = (gpio_ll_read_output(port) >> pin) & 1U;
dest->initial_value = (gpio_ll_read(port) >> pin) & 1U;
}
}