blob: 6bd74b7afd7fd8f0cb4a6d4857f23e93ebdbd71c [file] [log] [blame]
/*
* 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>
/** @brief All GPIO register as arrays of registers */
struct gpio_regs {
volatile uint32_t CTRL[174];
uint32_t RESERVED[18];
volatile uint32_t PARIN[6];
uint32_t RESERVED1[26];
volatile uint32_t PAROUT[6];
uint32_t RESERVED2[20];
volatile uint32_t LOCK[6];
uint32_t RESERVED3[64];
volatile uint32_t CTRL2[174];
};
#define NUM_MCHP_GPIO_PORTS 6u
/* GPIO Control register field definitions. */
/* bits[1:0] internal pull up/down selection */
#define MCHP_GPIO_CTRL_PUD_POS 0
#define MCHP_GPIO_CTRL_PUD_MASK0 0x03u
#define MCHP_GPIO_CTRL_PUD_MASK 0x03u
#define MCHP_GPIO_CTRL_PUD_NONE 0x00u
#define MCHP_GPIO_CTRL_PUD_PU 0x01u
#define MCHP_GPIO_CTRL_PUD_PD 0x02u
/* Repeater(keeper) mode */
#define MCHP_GPIO_CTRL_PUD_RPT 0x03u
/* bits[3:2] power gating */
#define MCHP_GPIO_CTRL_PWRG_POS 2
#define MCHP_GPIO_CTRL_PWRG_MASK0 0x03u
#define MCHP_GPIO_CTRL_PWRG_VTR_IO 0
#define MCHP_GPIO_CTRL_PWRG_VCC_IO SHLU32(1, MCHP_GPIO_CTRL_PWRG_POS)
#define MCHP_GPIO_CTRL_PWRG_OFF SHLU32(2, MCHP_GPIO_CTRL_PWRG_POS)
#define MCHP_GPIO_CTRL_PWRG_RSVD SHLU32(3, MCHP_GPIO_CTRL_PWRG_POS)
#define MCHP_GPIO_CTRL_PWRG_MASK SHLU32(3, MCHP_GPIO_CTRL_PWRG_POS)
/* bit[8] output buffer type: push-pull or open-drain */
#define MCHP_GPIO_CTRL_BUFT_POS 8
#define MCHP_GPIO_CTRL_BUFT_MASK BIT(MCHP_GPIO_CTRL_BUFT_POS)
#define MCHP_GPIO_CTRL_BUFT_OPENDRAIN BIT(MCHP_GPIO_CTRL_BUFT_POS)
#define MCHP_GPIO_CTRL_BUFT_PUSHPULL 0
/* bit[9] direction */
#define MCHP_GPIO_CTRL_DIR_POS 9
#define MCHP_GPIO_CTRL_DIR_MASK BIT(MCHP_GPIO_CTRL_DIR_POS)
#define MCHP_GPIO_CTRL_DIR_OUTPUT BIT(MCHP_GPIO_CTRL_DIR_POS)
#define MCHP_GPIO_CTRL_DIR_INPUT 0
/*
* bit[10] Alternate output disable. Default==0(alternate output enabled)
* GPIO output value is controlled by bit[16] of this register.
* Set bit[10]=1 if you wish to control pin output using the parallel
* GPIO output register bit for this pin.
*/
#define MCHP_GPIO_CTRL_AOD_POS 10
#define MCHP_GPIO_CTRL_AOD_MASK BIT(MCHP_GPIO_CTRL_AOD_POS)
#define MCHP_GPIO_CTRL_AOD_DIS BIT(MCHP_GPIO_CTRL_AOD_POS)
/* bit[11] GPIO function output polarity */
#define MCHP_GPIO_CTRL_POL_POS 11
#define MCHP_GPIO_CTRL_POL_INVERT BIT(MCHP_GPIO_CTRL_POL_POS)
/* bits[14:12] pin mux (function) */
#define MCHP_GPIO_CTRL_MUX_POS 12
#define MCHP_GPIO_CTRL_MUX_MASK0 0x07u
#define MCHP_GPIO_CTRL_MUX_MASK SHLU32(7, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F0 0
#define MCHP_GPIO_CTRL_MUX_GPIO MCHP_GPIO_CTRL_MUX_F0
#define MCHP_GPIO_CTRL_MUX_F1 SHLU32(1, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F2 SHLU32(2, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F3 SHLU32(3, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F4 SHLU32(4, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F5 SHLU32(5, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F6 SHLU32(6, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX_F7 SHLU32(7, MCHP_GPIO_CTRL_MUX_POS)
#define MCHP_GPIO_CTRL_MUX(n) SHLU32(((n) & 0x7u), MCHP_GPIO_CTRL_MUX_POS)
/*
* bit[15] Disables input pad leaving output pad enabled
* Useful for reducing power consumption of output only pins.
*/
#define MCHP_GPIO_CTRL_INPAD_DIS_POS 15
#define MCHP_GPIO_CTRL_INPAD_DIS_MASK BIT(MCHP_GPIO_CTRL_INPAD_DIS_POS)
#define MCHP_GPIO_CTRL_INPAD_DIS BIT(MCHP_GPIO_CTRL_INPAD_DIS_POS)
/* bit[16]: Alternate output pin value. Enabled when bit[10]==0(default) */
#define MCHP_GPIO_CTRL_OUTVAL_POS 16
#define MCHP_GPIO_CTRL_OUTV_HI BIT(MCHP_GPIO_CTRL_OUTVAL_POS)
/* bit[24] Input pad value. Always live unless input pad is powered down */
#define MCHP_GPIO_CTRL_INPAD_VAL_POS 24
#define MCHP_GPIO_CTRL_INPAD_VAL_HI BIT(MCHP_GPIO_CTRL_INPAD_VAL_POS)
#define MCHP_GPIO_CTRL_DRIVE_OD_HI \
(MCHP_GPIO_CTRL_BUFT_OPENDRAIN + MCHP_GPIO_CTRL_DIR_OUTPUT + \
MCHP_GPIO_CTRL_MUX_GPIO + MCHP_GPIO_CTRL_OUTV_HI)
/*
* Each GPIO pin implements a second control register.
* GPIO Control 2 register selects pin drive strength and slew rate.
* bit[0] = slew rate: 0=slow, 1=fast
* bits[5:4] = drive strength
* 00b = 2mA (default)
* 01b = 4mA
* 10b = 8mA
* 11b = 12mA
*/
#define MCHP_GPIO_CTRL2_OFFSET 0x0500u
#define MCHP_GPIO_CTRL2_SLEW_POS 0
#define MCHP_GPIO_CTRL2_SLEW_MASK 0x01u
#define MCHP_GPIO_CTRL2_SLEW_SLOW 0
#define MCHP_GPIO_CTRL2_SLEW_FAST BIT(MCHP_GPIO_CTRL2_SLEW_POS)
#define MCHP_GPIO_CTRL2_DRV_STR_POS 4
#define MCHP_GPIO_CTRL2_DRV_STR_MASK 0x30u
#define MCHP_GPIO_CTRL2_DRV_STR_2MA 0
#define MCHP_GPIO_CTRL2_DRV_STR_4MA 0x10u
#define MCHP_GPIO_CTRL2_DRV_STR_8MA 0x20u
#define MCHP_GPIO_CTRL2_DRV_STR_12MA 0x30u
#define MCHP_XEC_NO_PULL 0x0
#define MCHP_XEC_PULL_UP 0x1
#define MCHP_XEC_PULL_DOWN 0x2
#define MCHP_XEC_REPEATER 0x3
#define MCHP_XEC_PUSH_PULL 0x0
#define MCHP_XEC_OPEN_DRAIN 0x1
#define MCHP_XEC_NO_OVAL 0x0
#define MCHP_XEC_OVAL_LOW 0x1
#define MCHP_XEC_OVAL_HIGH 0x2
#define MCHP_XEC_DRVSTR_NONE 0x0
#define MCHP_XEC_DRVSTR_2MA 0x1
#define MCHP_XEC_DRVSTR_4MA 0x2
#define MCHP_XEC_DRVSTR_8MA 0x3
#define MCHP_XEC_DRVSTR_12MA 0x4
#define SHLU32(v, n) ((uint32_t)(v) << (n))
/* 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;
}