151 lines
3.9 KiB
C
151 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2016 Open-RnD Sp. z o.o.
|
|
* Copyright (c) 2021 Linaro Limited
|
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
* Copyright (c) 2021 Microchip Technology Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT microchip_xec_pinctrl
|
|
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#include <soc.h>
|
|
|
|
/* Microchip XEC: each GPIO pin has two 32-bit control register.
|
|
* The first 32-bit register contains all pin features except
|
|
* slew rate and driver strength in the second control register.
|
|
* We compute the register index from the beginning of the GPIO
|
|
* control address space which is the same range of the PINCTRL
|
|
* parent node.
|
|
*/
|
|
|
|
static void config_drive_slew(struct gpio_regs * const regs, uint32_t idx, uint32_t conf)
|
|
{
|
|
uint32_t slew = conf & (MCHP_XEC_OSPEEDR_MASK << MCHP_XEC_OSPEEDR_POS);
|
|
uint32_t drvstr = conf & (MCHP_XEC_ODRVSTR_MASK << MCHP_XEC_ODRVSTR_POS);
|
|
uint32_t val = 0;
|
|
uint32_t mask = 0;
|
|
|
|
if (slew != MCHP_XEC_OSPEEDR_NO_CHG) {
|
|
mask |= MCHP_GPIO_CTRL2_SLEW_MASK;
|
|
if (slew == MCHP_XEC_OSPEEDR_FAST) {
|
|
val |= MCHP_GPIO_CTRL2_SLEW_FAST;
|
|
}
|
|
}
|
|
if (drvstr != MCHP_XEC_ODRVSTR_NO_CHG) {
|
|
mask |= MCHP_GPIO_CTRL2_DRV_STR_MASK;
|
|
val |= (drvstr << MCHP_GPIO_CTRL2_DRV_STR_POS);
|
|
}
|
|
|
|
if (!mask) {
|
|
return;
|
|
}
|
|
|
|
regs->CTRL2[idx] = (regs->CTRL2[idx] & ~mask) | (val & mask);
|
|
}
|
|
|
|
/* Configure pin by writing GPIO Control and Control2 registers.
|
|
* NOTE: Disable alternate output feature since the GPIO driver does.
|
|
* While alternate output is enabled (default state of pin) HW does not
|
|
* ignores writes to the parallel output bit for the pin. To set parallel
|
|
* output value we must keep pin direction as input, set alternate output
|
|
* disable, program pin value to parallel output bit, and then disable
|
|
* alternate output mode.
|
|
*/
|
|
static int xec_config_pin(uint32_t portpin, uint32_t conf, uint32_t altf)
|
|
{
|
|
struct gpio_regs * const regs = (struct gpio_regs * const)DT_INST_REG_ADDR(0);
|
|
uint32_t port = MCHP_XEC_PINMUX_PORT(portpin);
|
|
uint32_t pin = (uint32_t)MCHP_XEC_PINMUX_PIN(portpin);
|
|
uint32_t msk = MCHP_GPIO_CTRL_AOD_MASK;
|
|
uint32_t val = MCHP_GPIO_CTRL_AOD_DIS;
|
|
uint32_t idx = 0u;
|
|
uint32_t temp = 0u;
|
|
|
|
if (port >= NUM_MCHP_GPIO_PORTS) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* MCHP XEC family is 32 pins per port */
|
|
idx = (port * 32U) + pin;
|
|
|
|
config_drive_slew(regs, idx, conf);
|
|
|
|
/* default input pad enabled, buffer type push-pull, no internal pulls */
|
|
msk |= (BIT(MCHP_GPIO_CTRL_INPAD_DIS_POS) | MCHP_GPIO_CTRL_BUFT_MASK |
|
|
MCHP_GPIO_CTRL_PUD_MASK |
|
|
MCHP_GPIO_CTRL_MUX_MASK);
|
|
|
|
if (conf & BIT(MCHP_XEC_PIN_LOW_POWER_POS)) {
|
|
msk |= MCHP_GPIO_CTRL_PWRG_MASK;
|
|
val |= MCHP_GPIO_CTRL_PWRG_OFF;
|
|
}
|
|
|
|
temp = (conf & MCHP_XEC_PUPDR_MASK) >> MCHP_XEC_PUPDR_POS;
|
|
switch (temp) {
|
|
case MCHP_XEC_PULL_UP:
|
|
val |= MCHP_GPIO_CTRL_PUD_PU;
|
|
break;
|
|
case MCHP_XEC_PULL_DOWN:
|
|
val |= MCHP_GPIO_CTRL_PUD_PD;
|
|
break;
|
|
case MCHP_XEC_REPEATER:
|
|
val |= MCHP_GPIO_CTRL_PUD_RPT;
|
|
break;
|
|
default:
|
|
val |= MCHP_GPIO_CTRL_PUD_NONE;
|
|
break;
|
|
}
|
|
|
|
if ((conf >> MCHP_XEC_OTYPER_POS) & MCHP_XEC_OTYPER_MASK) {
|
|
val |= MCHP_GPIO_CTRL_BUFT_OPENDRAIN;
|
|
}
|
|
|
|
regs->CTRL[idx] = (regs->CTRL[idx] & ~msk) | val;
|
|
|
|
temp = (conf >> MCHP_XEC_OVAL_POS) & MCHP_XEC_OVAL_MASK;
|
|
if (temp) {
|
|
if (temp == MCHP_XEC_OVAL_DRV_HIGH) {
|
|
regs->PAROUT[port] |= BIT(pin);
|
|
} else {
|
|
regs->PAROUT[port] &= ~BIT(pin);
|
|
}
|
|
|
|
regs->CTRL[idx] |= MCHP_GPIO_CTRL_DIR_OUTPUT;
|
|
}
|
|
|
|
val = (uint32_t)((altf & MCHP_GPIO_CTRL_MUX_MASK0) << MCHP_GPIO_CTRL_MUX_POS);
|
|
regs->CTRL[idx] |= val;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
|
|
uintptr_t reg)
|
|
{
|
|
uint32_t portpin, mux, cfg, func;
|
|
int ret;
|
|
|
|
ARG_UNUSED(reg);
|
|
|
|
for (uint8_t i = 0U; i < pin_cnt; i++) {
|
|
mux = pins[i].pinmux;
|
|
|
|
func = MCHP_XEC_PINMUX_FUNC(mux);
|
|
if (func >= MCHP_AFMAX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
cfg = pins[i].pincfg;
|
|
portpin = MEC_XEC_PINMUX_PORT_PIN(mux);
|
|
|
|
ret = xec_config_pin(portpin, cfg, func);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|