diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 5c99dd82e8f..99cb8d6b9e5 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -39,5 +39,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ENE_KB1200 pinctrl_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_MAX32 pinctrl_max32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCMI pinctrl_imx_scmi.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCHP_MEC5 pinctrl_mchp_mec5.c) add_subdirectory(renesas) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b919fa0f169..511a8a22cb9 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -66,6 +66,7 @@ source "drivers/pinctrl/Kconfig.mci_io_mux" source "drivers/pinctrl/Kconfig.ene" source "drivers/pinctrl/Kconfig.zynqmp" source "drivers/pinctrl/Kconfig.max32" +source "drivers/pinctrl/Kconfig.mec5" rsource "renesas/Kconfig" diff --git a/drivers/pinctrl/Kconfig.mec5 b/drivers/pinctrl/Kconfig.mec5 new file mode 100644 index 00000000000..837af56b375 --- /dev/null +++ b/drivers/pinctrl/Kconfig.mec5 @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_MCHP_MEC5 + bool "Pin controller driver for MCHP MEC5 MCUs" + default y + depends on DT_HAS_MICROCHIP_MEC5_PINCTRL_ENABLED + help + Enable pin controller driver for Microchip MEC5 MCUs diff --git a/drivers/pinctrl/pinctrl_mchp_mec5.c b/drivers/pinctrl/pinctrl_mchp_mec5.c new file mode 100644 index 00000000000..bb4437a5f54 --- /dev/null +++ b/drivers/pinctrl/pinctrl_mchp_mec5.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * Copyright (c) 2021 Linaro Limited + * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mec5_pinctrl + +#include +#include +#include + +static const struct mec_gpio_props cfg1[] = { + {MEC_GPIO_OSEL_PROP_ID, MEC_GPIO_PROP_OSEL_CTRL}, + {MEC_GPIO_INPAD_DIS_PROP_ID, MEC_GPIO_PROP_INPAD_EN}, +}; + +/* DT enable booleans take precedence over disable booleans. + * We initially clear alternate output disable allowing us to set output state + * in the control register. Hardware sets output state bit in both control and + * parallel output register bits. Alternate output disable only controls which + * register bit is writable by the EC. We also clear the input pad disable + * bit because we need the input pin state and we don't know if the requested + * alternate function is input or bi-directional. + * Note 1: hardware allows input and output to be simultaneously enabled. + * Note 2: hardware interrupt detection is only on the input path. + */ +static int mec5_config_pin(uint32_t pinmux, uint32_t altf) +{ + uint32_t conf = pinmux; + uint32_t pin = 0, temp = 0; + int ret = 0; + size_t idx = 0; + struct mec_gpio_props cfg2[12]; + + ret = mec_hal_gpio_pin_num(MCHP_XEC_PINMUX_PORT(pinmux), MCHP_XEC_PINMUX_PIN(pinmux), &pin); + if (ret) { + return -EINVAL; + } + + ret = mec_hal_gpio_set_props(pin, cfg1, ARRAY_SIZE(cfg1)); + if (ret) { + return -EIO; + } + + /* slew rate */ + temp = (conf >> MCHP_XEC_SLEW_RATE_POS) & MCHP_XEC_SLEW_RATE_MSK0; + if (temp != MCHP_XEC_SLEW_RATE_MSK0) { + cfg2[idx].prop = MEC_GPIO_SLEW_RATE_ID; + cfg2[idx].val = (uint8_t)MEC_GPIO_SLEW_RATE_SLOW; + if (temp == MCHP_XEC_SLEW_RATE_FAST0) { + cfg2[idx].val = (uint8_t)MEC_GPIO_SLEW_RATE_FAST; + } + idx++; + } + + /* drive strength */ + temp = (conf >> MCHP_XEC_DRV_STR_POS) & MCHP_XEC_DRV_STR_MSK0; + if (temp != MCHP_XEC_DRV_STR_MSK0) { + cfg2[idx].prop = MEC_GPIO_DRV_STR_ID; + cfg2[idx].val = (uint8_t)(temp - 1u); + idx++; + } + + /* Touch internal pull-up/pull-down? */ + cfg2[idx].prop = MEC_GPIO_PUD_PROP_ID; + if (conf & BIT(MCHP_XEC_NO_PUD_POS)) { + cfg2[idx++].val = MEC_GPIO_PROP_NO_PUD; + } else if (conf & BIT(MCHP_XEC_PU_POS)) { + cfg2[idx++].val = MEC_GPIO_PROP_PULL_UP; + } else if (conf & BIT(MCHP_XEC_PD_POS)) { + cfg2[idx++].val = MEC_GPIO_PROP_PULL_DN; + } + + /* Touch output enable. We always enable input */ + if (conf & (BIT(MCHP_XEC_OUT_DIS_POS) | BIT(MCHP_XEC_OUT_EN_POS))) { + cfg2[idx].prop = MEC_GPIO_DIR_PROP_ID; + cfg2[idx].val = MEC_GPIO_PROP_DIR_IN; + if (conf & BIT(MCHP_XEC_OUT_EN_POS)) { + cfg2[idx].val = MEC_GPIO_PROP_DIR_OUT; + } + idx++; + } + + /* Touch output state? Bit can be set even if the direction is input only */ + if (conf & (BIT(MCHP_XEC_OUT_LO_POS) | BIT(MCHP_XEC_OUT_HI_POS))) { + cfg2[idx].prop = MEC_GPIO_CTRL_OUT_VAL_ID; + cfg2[idx].val = 0u; + if (conf & BIT(MCHP_XEC_OUT_HI_POS)) { + cfg2[idx].val = 1u; + } + idx++; + } + + /* Touch output buffer type? */ + if (conf & (BIT(MCHP_XEC_PUSH_PULL_POS) | BIT(MCHP_XEC_OPEN_DRAIN_POS))) { + cfg2[idx].prop = MEC_GPIO_OBUFT_PROP_ID; + cfg2[idx].val = MEC_GPIO_PROP_PUSH_PULL; + if (conf & BIT(MCHP_XEC_OPEN_DRAIN_POS)) { + cfg2[idx].val = MEC_GPIO_PROP_OPEN_DRAIN; + } + idx++; + } + + /* Always touch power gate */ + cfg2[idx].prop = MEC_GPIO_PWRGT_PROP_ID; + cfg2[idx].val = MEC_GPIO_PROP_PWRGT_VTR; + if (conf & BIT(MCHP_XEC_PIN_LOW_POWER_POS)) { + cfg2[idx].val = MEC_GPIO_PROP_PWRGT_OFF; + } + idx++; + + /* Always touch MUX (alternate function) */ + cfg2[idx].prop = MEC_GPIO_MUX_PROP_ID; + cfg2[idx].val = (uint8_t)altf; + idx++; + + /* Always touch invert of alternate function. Need another bit to avoid touching */ + cfg2[idx].prop = MEC_GPIO_FUNC_POL_PROP_ID; + cfg2[idx].val = MEC_GPIO_PROP_FUNC_OUT_NON_INV; + if (conf & BIT(MCHP_XEC_FUNC_INV_POS)) { + cfg2[idx].val = MEC_GPIO_PROP_FUNC_OUT_INV; + } + idx++; + + /* HW sets output state set in control & parallel regs */ + ret = mec_hal_gpio_set_props(pin, cfg2, idx); + if (ret) { + return -EIO; + } + + /* make output state in control read-only in control and read-write in parallel reg */ + ret = mec_hal_gpio_set_property(pin, MEC_GPIO_OSEL_PROP_ID, MEC_GPIO_PROP_OSEL_PAROUT); + if (ret) { + return -EIO; + } + + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + uint32_t pinmux, func; + int ret; + + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinmux = pins[i]; + + func = MCHP_XEC_PINMUX_FUNC(pinmux); + if (func >= MCHP_AFMAX) { + return -EINVAL; + } + + ret = mec5_config_pin(pinmux, func); + if (ret < 0) { + return ret; + } + } + + return 0; +} diff --git a/dts/arm/microchip/mec5.dtsi b/dts/arm/microchip/mec5.dtsi index 9e16bfd75cc..e105bea6baf 100644 --- a/dts/arm/microchip/mec5.dtsi +++ b/dts/arm/microchip/mec5.dtsi @@ -136,6 +136,7 @@ }; }; pinctrl: pin-controller@40081000 { + compatible = "microchip,mec5-pinctrl"; #address-cells = <1>; #size-cells = <1>; reg = <0x40081000 0x1000>; diff --git a/dts/bindings/pinctrl/microchip,mec5-pinctrl.yaml b/dts/bindings/pinctrl/microchip,mec5-pinctrl.yaml new file mode 100644 index 00000000000..b469aa41a03 --- /dev/null +++ b/dts/bindings/pinctrl/microchip,mec5-pinctrl.yaml @@ -0,0 +1,124 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Microchip XEC Pin controller Node + Based on pincfg-node.yaml binding. + The MCHP XEC pin controller is a singleton node responsible for controlling + pin function selection and pin properties. For example, you can use this + node to select peripheral pin functions. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as in the spi0 example shown at the end: + + A group can also specify shared pin properties common to all the specified + pins, such as the 'bias-pull-up' property in group 2. Here is a list of + supported standard pin properties: + + - bias-disable: Disable pull-up/down (default behavior, not required). + - bias-pull-down: Enable pull-down resistor. + - bias-pull-up: Enable pull-up resistor. + - drive-push-pull: Output driver is push-pull (default, not required). + - drive-open-drain: Output driver is open-drain. + - output-high: Set output state high when pin configured. + - output-low: Set output state low when pin configured. + + Custom pin properties for drive strength and slew rate are available: + - drive-strength + - slew-rate + + Driver strength and slew rate hardware defaults vary by SoC and pin. + + An example for MEC174x family, include the chip level pinctrl + DTSI file in the board level DTS: + + #include + + We want to use the shared SPI port of the MEC172x QMSPI controller + and want the chip select 0 to be open-drain. + + To change a pin's pinctrl default properties add a reference to the + pin in the board's DTS file and set the properties. + + &spi0 { + pinctrl-0 = < &shd_cs0_n_gpio055 + &shd_clk_gpio056 + &shd_io0_gpio223 + &shd_io1_gpio224 + &shd_io3_gpio016 >; + pinctrl-names = "default"; + } + + &shd_cs0_n_gpio055 { + drive-open-drain; + }; + +compatible: "microchip,mec5-pinctrl" + +include: base.yaml + +properties: + reg: + required: true + +child-binding: + description: | + This binding gives a base representation of the Microchip XEC pins + configuration + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - drive-push-pull + - drive-open-drain + - low-power-enable + - output-disable + - output-enable + - output-high + - output-low + + properties: + pinmux: + type: int + required: true + description: Pinmux selection + + slew-rate: + type: string + enum: + - "low-speed" + - "high-speed" + description: | + Pin speed. The default value of slew-rate is the SoC power-on-reset + value. Please refer to the data sheet as a small number of pins + may have a different default and some pins do not implement + slew rate adjustment. + + drive-strength: + type: string + enum: + - "1x" + - "2x" + - "4x" + - "6x" + description: | + Pin output drive strength for PIO and PIO-24 pin types. Default + is "1x" for most pins. PIO pins are 2, 4, 8, or 12 mA. PIO-24 pins + are 4, 8, 16, or 24 mA. Please refer to the data sheet for each + pin's PIO type and default drive strength. + + microchip,output-func-invert: + type: boolean + description: + Invert polarity of an output alternate function. Input functions + are not affected. diff --git a/soc/microchip/mec/common/pinctrl_soc.h b/soc/microchip/mec/common/pinctrl_soc.h index 1e5b5005027..0182167779d 100644 --- a/soc/microchip/mec/common/pinctrl_soc.h +++ b/soc/microchip/mec/common/pinctrl_soc.h @@ -31,28 +31,45 @@ typedef uint32_t pinctrl_soc_pin_t; /* initialize pinmux member fields of pinctrl_pin_t */ #define Z_PINCTRL_MCHP_XEC_PINMUX_INIT(node_id) (uint32_t)(DT_PROP(node_id, pinmux)) -#define Z_PINCTRL_STATE_PINCFG_INIT(node_id) \ - ((DT_PROP(node_id, bias_disable) << MCHP_XEC_NO_PUD_POS) \ - | (DT_PROP(node_id, bias_pull_down) << MCHP_XEC_PD_POS) \ - | (DT_PROP(node_id, bias_pull_up) << MCHP_XEC_PU_POS) \ - | (DT_PROP(node_id, drive_push_pull) << MCHP_XEC_PUSH_PULL_POS) \ - | (DT_PROP(node_id, drive_open_drain) << MCHP_XEC_OPEN_DRAIN_POS) \ - | (DT_PROP(node_id, output_disable) << MCHP_XEC_OUT_DIS_POS) \ - | (DT_PROP(node_id, output_enable) << MCHP_XEC_OUT_EN_POS) \ - | (DT_PROP(node_id, output_high) << MCHP_XEC_OUT_HI_POS) \ - | (DT_PROP(node_id, output_low) << MCHP_XEC_OUT_LO_POS) \ - | (DT_PROP(node_id, low_power_enable) << MCHP_XEC_PIN_LOW_POWER_POS) \ - | (DT_PROP(node_id, microchip_output_func_invert) << MCHP_XEC_FUNC_INV_POS) \ - | (DT_ENUM_IDX(node_id, slew_rate) << MCHP_XEC_SLEW_RATE_POS) \ - | (DT_ENUM_IDX(node_id, drive_strength) << MCHP_XEC_DRV_STR_POS)) +#ifdef CONFIG_HAS_MEC5_HAL +#define Z_PINCTRL_STATE_PINCFG_INIT(node_id) \ + ((DT_PROP(node_id, bias_disable) << MCHP_XEC_NO_PUD_POS) | \ + (DT_PROP(node_id, bias_pull_down) << MCHP_XEC_PD_POS) | \ + (DT_PROP(node_id, bias_pull_up) << MCHP_XEC_PU_POS) | \ + (DT_PROP(node_id, drive_push_pull) << MCHP_XEC_PUSH_PULL_POS) | \ + (DT_PROP(node_id, drive_open_drain) << MCHP_XEC_OPEN_DRAIN_POS) | \ + (DT_PROP(node_id, output_disable) << MCHP_XEC_OUT_DIS_POS) | \ + (DT_PROP(node_id, output_enable) << MCHP_XEC_OUT_EN_POS) | \ + (DT_PROP(node_id, output_high) << MCHP_XEC_OUT_HI_POS) | \ + (DT_PROP(node_id, output_low) << MCHP_XEC_OUT_LO_POS) | \ + (DT_PROP(node_id, low_power_enable) << MCHP_XEC_PIN_LOW_POWER_POS) | \ + (DT_PROP(node_id, microchip_output_func_invert) << MCHP_XEC_FUNC_INV_POS) | \ + (DT_ENUM_IDX_OR(node_id, slew_rate, 0x3) << MCHP_XEC_SLEW_RATE_POS) | \ + (DT_ENUM_IDX_OR(node_id, drive_strength, 0x7) << MCHP_XEC_DRV_STR_POS)) +#else +#define Z_PINCTRL_STATE_PINCFG_INIT(node_id) \ + ((DT_PROP(node_id, bias_disable) << MCHP_XEC_NO_PUD_POS) | \ + (DT_PROP(node_id, bias_pull_down) << MCHP_XEC_PD_POS) | \ + (DT_PROP(node_id, bias_pull_up) << MCHP_XEC_PU_POS) | \ + (DT_PROP(node_id, drive_push_pull) << MCHP_XEC_PUSH_PULL_POS) | \ + (DT_PROP(node_id, drive_open_drain) << MCHP_XEC_OPEN_DRAIN_POS) | \ + (DT_PROP(node_id, output_disable) << MCHP_XEC_OUT_DIS_POS) | \ + (DT_PROP(node_id, output_enable) << MCHP_XEC_OUT_EN_POS) | \ + (DT_PROP(node_id, output_high) << MCHP_XEC_OUT_HI_POS) | \ + (DT_PROP(node_id, output_low) << MCHP_XEC_OUT_LO_POS) | \ + (DT_PROP(node_id, low_power_enable) << MCHP_XEC_PIN_LOW_POWER_POS) | \ + (DT_PROP(node_id, microchip_output_func_invert) << MCHP_XEC_FUNC_INV_POS) | \ + (DT_ENUM_IDX(node_id, slew_rate) << MCHP_XEC_SLEW_RATE_POS) | \ + (DT_ENUM_IDX(node_id, drive_strength) << MCHP_XEC_DRV_STR_POS)) +#endif /* initialize pin structure members */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ - (Z_PINCTRL_MCHP_XEC_PINMUX_INIT(DT_PROP_BY_IDX(node_id, state_prop, idx)) \ - | Z_PINCTRL_STATE_PINCFG_INIT(DT_PROP_BY_IDX(node_id, state_prop, idx))), +#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ + (Z_PINCTRL_MCHP_XEC_PINMUX_INIT(DT_PROP_BY_IDX(node_id, state_prop, idx)) | \ + Z_PINCTRL_STATE_PINCFG_INIT(DT_PROP_BY_IDX(node_id, state_prop, idx))), /* Use DT FOREACH macro to initialize each used pin */ -#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ {DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT)} /** @endcond */