esp32: drivers: pinmux: code refactoring

to make use of Espressif's hal in order to ease both
driver maintenance and code reuse between socs.

Signed-off-by: Glauber Maroto Ferreira <glauber.ferreira@espressif.com>
This commit is contained in:
Glauber Maroto Ferreira 2021-08-11 13:56:53 -03:00 committed by Anas Nashif
parent 8b13046cb6
commit 17f3792abf
2 changed files with 25 additions and 116 deletions

View File

@ -280,6 +280,7 @@
/drivers/pinmux/*b91* @yurvyn
/drivers/pinmux/*hsdk* @iriszzw
/drivers/pinmux/*it8xxx2* @ite
/drivers/pinmux/*esp32* @glaubermaroto
/drivers/pm_cpu_ops/ @carlocaione
/drivers/ps2/ @franciscomunoz @scottwcpg
/drivers/ps2/*xec* @franciscomunoz @scottwcpg

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,100 +8,35 @@
#define DT_DRV_COMPAT espressif_esp32_pinmux
/* Include esp-idf headers first to avoid redefining BIT() macro */
#include <soc/gpio_reg.h>
#include <soc/io_mux_reg.h>
#include <soc/soc.h>
#include <hal/gpio_types.h>
#include <hal/gpio_ll.h>
#include <errno.h>
#include <sys/util.h>
#include <drivers/pinmux.h>
/* DR_REG_IO_MUX_BASE is a 32-bit constant. Define a pin mux table
* using only offsets, in order to reduce ROM footprint.
* This table has been compiled from information present in "ESP32
* Technical Reference Manual", "IO_MUX Pad List". The items in
* this array covers only the first function of each I/O pin.
* Items with offset `0` are not present in the documentation, and
* trying to configure them will result in -EINVAL being returned.
*
* Note: DR_REG_IO_MUX_BASE here is used to extract GPIO_X register offset.
* Don't replace it by device tree value, because PERIPHS_IO_MUX_
* is "internally" depends on it.
*/
#define PIN(id) ((PERIPHS_IO_MUX_ ## id ## _U) - (DR_REG_IO_MUX_BASE))
static const uint8_t pin_mux_off[] = {
PIN(GPIO0), PIN(U0TXD), PIN(GPIO2), PIN(U0RXD),
PIN(GPIO4), PIN(GPIO5), PIN(SD_CLK), PIN(SD_DATA0),
PIN(SD_DATA1), PIN(SD_DATA2), PIN(SD_DATA3), PIN(SD_CMD),
PIN(MTDI), PIN(MTCK), PIN(MTMS), PIN(MTDO),
PIN(GPIO16), PIN(GPIO17), PIN(GPIO18), PIN(GPIO19),
0, PIN(GPIO21), PIN(GPIO22), PIN(GPIO23),
0, PIN(GPIO25), PIN(GPIO26), PIN(GPIO27),
0, 0, 0, 0,
PIN(GPIO32), PIN(GPIO33), PIN(GPIO34), PIN(GPIO35),
PIN(GPIO36), PIN(GPIO37), PIN(GPIO38), PIN(GPIO39)
};
#undef PIN
static uint32_t *reg_for_pin(uint32_t pin)
{
uint8_t off;
if (pin >= ARRAY_SIZE(pin_mux_off)) {
return NULL;
}
off = pin_mux_off[pin];
if (!off) {
return NULL;
}
return (uint32_t *)(DT_INST_REG_ADDR(0) + off);
}
static int set_reg(uint32_t pin, uint32_t clr_mask, uint32_t set_mask)
{
volatile uint32_t *reg = reg_for_pin(pin);
uint32_t v;
if (!reg) {
return -EINVAL;
}
v = *reg;
v &= ~clr_mask;
v |= set_mask;
*reg = v;
return 0;
}
static int pinmux_set(const struct device *dev, uint32_t pin, uint32_t func)
{
ARG_UNUSED(dev);
/* FIXME: Drive strength (FUN_DRV) is also set here to its maximum
* value due to a deficiency in the pinmux API. This setting is
* part of the GPIO API.
*/
if (func > 6) {
if ((func > PINMUX_FUNC_G) || (pin >= GPIO_NUM_MAX)) {
return -EINVAL;
}
return set_reg(pin, MCU_SEL_M, func<<MCU_SEL_S | 2<<FUN_DRV_S);
gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[pin], func);
return 0;
}
static int pinmux_get(const struct device *dev, uint32_t pin, uint32_t *func)
{
ARG_UNUSED(dev);
volatile uint32_t *reg = reg_for_pin(pin);
if (!reg) {
if (pin >= GPIO_NUM_MAX) {
return -EINVAL;
}
*func = (*reg & MCU_SEL_M) >> MCU_SEL_S;
*func = REG_GET_FIELD(GPIO_PIN_MUX_REG[pin], MCU_SEL);
return 0;
}
@ -111,54 +47,35 @@ static int pinmux_pullup(const struct device *dev, uint32_t pin, uint8_t func)
switch (func) {
case PINMUX_PULLUP_DISABLE:
return set_reg(pin, FUN_PU, FUN_PD);
gpio_ll_pullup_dis(&GPIO, pin);
break;
case PINMUX_PULLUP_ENABLE:
return set_reg(pin, FUN_PD, FUN_PU);
gpio_ll_pullup_en(&GPIO, pin);
break;
default:
return -EINVAL;
}
return -EINVAL;
return 0;
}
#define CFG(id) ((GPIO_ ## id ## _REG) & 0xff)
static int pinmux_input(const struct device *dev, uint32_t pin, uint8_t func)
{
ARG_UNUSED(dev);
static const uint8_t offs[2][3] = {
{ CFG(ENABLE1_W1TC), CFG(ENABLE1_W1TS), 32 },
{ CFG(ENABLE_W1TC), CFG(ENABLE_W1TS), 0 },
};
const uint8_t *line = offs[pin < 32];
volatile uint32_t *reg;
int r;
/* Since PINMUX_INPUT_ENABLED == 1 and PINMUX_OUTPUT_ENABLED == 0,
* we can not set a gpio port as input and output at the same time,
* So we always set the gpio as input. Thus, the gpio can be used on
* I2C drivers for example.
*/
r = set_reg(pin, 0, FUN_IE);
if (func == PINMUX_INPUT_ENABLED) {
reg = (uint32_t *)(DR_REG_GPIO_BASE + line[0]);
} else if (func == PINMUX_OUTPUT_ENABLED) {
if (pin >= 34U && pin <= 39U) {
/* These pins are input only */
return -EINVAL;
}
reg = (uint32_t *)(DR_REG_GPIO_BASE + line[1]);
} else {
switch (func) {
case PINMUX_INPUT_ENABLED:
gpio_ll_input_enable(&GPIO, pin);
break;
case PINMUX_OUTPUT_ENABLED:
gpio_ll_output_enable(&GPIO, pin);
break;
default:
return -EINVAL;
}
if (r < 0) {
return r;
}
*reg = BIT(pin - line[2]);
return 0;
}
#undef CFG
static struct pinmux_driver_api api_funcs = {
.set = pinmux_set,
@ -171,15 +88,6 @@ static int pinmux_initialize(const struct device *dev)
{
ARG_UNUSED(dev);
#if !CONFIG_BOOTLOADER_ESP_IDF
uint32_t pin;
for (pin = 0U; pin < ARRAY_SIZE(pin_mux_off); pin++) {
pinmux_set(NULL, pin, 0);
}
#endif
return 0;
}