drivers: pinctrl: add pin group for NuMaker pinctrl

Update Nuvoton numaker series pinctrl, let support pin group.

Signed-off-by: cyliang tw <cyliang@nuvoton.com>
This commit is contained in:
cyliang tw 2023-06-27 16:06:02 +08:00 committed by Fabio Baltieri
parent db8881dd97
commit 51d57f612d
5 changed files with 115 additions and 61 deletions

View file

@ -8,16 +8,20 @@
&pinctrl {
uart0_default: uart0_default {
pinmux = <PB12MFP_UART0_RXD>,
<PB13MFP_UART0_TXD>;
group0 {
pinmux = <PB12MFP_UART0_RXD>,
<PB13MFP_UART0_TXD>;
};
};
/* TX/RX/RTS/CTS/RST --> D1/D0/A2/A3/D2 --> PB3/PB2/PB8/PB9/PC9 */
uart1_default: uart1_default {
pinmux = <PB9MFP_UART1_nCTS>,
<PB8MFP_UART1_nRTS>,
<PB2MFP_UART1_RXD>,
<PB3MFP_UART1_TXD>,
<PC9MFP_GPIO>;
group0 {
pinmux = <PB9MFP_UART1_nCTS>,
<PB8MFP_UART1_nRTS>,
<PB2MFP_UART1_RXD>,
<PB3MFP_UART1_TXD>,
<PC9MFP_GPIO>;
};
};
};

View file

@ -9,20 +9,40 @@
#include <zephyr/drivers/pinctrl.h>
#include <NuMicro.h>
/* Get mfp_base, it should be == (&SYS->GPA_MFP0) */
#define MFP_BASE DT_INST_REG_ADDR_BY_NAME(0, mfp)
#define MFOS_BASE DT_INST_REG_ADDR_BY_NAME(0, mfos)
#define GPA_BASE DT_REG_ADDR(DT_NODELABEL(gpioa))
#define GPIO_SIZE DT_REG_SIZE(DT_NODELABEL(gpioa))
#define SLEWCTL_PIN_SHIFT(pin_idx) ((pin_idx) * 2)
#define SLEWCTL_MASK(pin_idx) (3 << SLEWCTL_PIN_SHIFT(pin_idx))
static void gpio_configure(const pinctrl_soc_pin_t *pin, uint8_t port_idx, uint8_t pin_idx)
{
GPIO_T *port;
port = (GPIO_T *)(GPA_BASE + port_idx * GPIO_SIZE);
port->SMTEN = (port->SMTEN & ~BIT(pin_idx)) |
((pin->schmitt_enable ? 1 : 0) << pin_idx);
port->SLEWCTL = (port->SLEWCTL & ~SLEWCTL_MASK(pin_idx)) |
(pin->slew_rate << SLEWCTL_PIN_SHIFT(pin_idx));
}
/**
* Configure pin multi-function
*/
static void configure_pin(const pinctrl_soc_pin_t *pin)
{
uint32_t pin_mux = pin->pin_mux;
uint32_t pin_index = PIN_INDEX(pin_mux);
uint32_t port_index = PORT_INDEX(pin_mux);
uint8_t pin_index = PIN_INDEX(pin_mux);
uint8_t port_index = PORT_INDEX(pin_mux);
uint32_t mfp_cfg = MFP_CFG(pin_mux);
/* Get mfp_base, it should be == (&SYS->GPA_MFP0) in M467 */
uint32_t mfp_base = DT_REG_ADDR(DT_NODELABEL(pinctrl));
uint32_t *GPx_MFPx = ((uint32_t *)mfp_base) + port_index * 4 + (pin_index / 4);
uint32_t *GPx_MFPx = ((uint32_t *)MFP_BASE) + port_index * 4 + (pin_index / 4);
uint32_t *GPx_MFOSx = ((uint32_t *)MFOS_BASE) + port_index;
uint32_t pinMask = NU_MFP_MASK(pin_index);
/*
@ -30,6 +50,13 @@ static void configure_pin(const pinctrl_soc_pin_t *pin)
* SYS_GPA_MFP0_PA0MFP_SC0_CD;
*/
*GPx_MFPx = (*GPx_MFPx & (~pinMask)) | mfp_cfg;
if (pin->open_drain != 0) {
*GPx_MFOSx |= BIT(pin_index);
} else {
*GPx_MFOSx &= ~BIT(pin_index);
}
gpio_configure(pin, port_index, pin_index);
}
/* Pinctrl API implementation */

View file

@ -165,9 +165,11 @@
status = "disabled";
};
pinctrl: pin-controller@40000500 {
pinctrl: pin-controller@40000080 {
compatible = "nuvoton,numaker-pinctrl";
reg = <0x40000500 0xa0>;
reg = <0x40000080 0x28
0x40000500 0xa0>;
reg-names = "mfos", "mfp";
status = "okay";
};

View file

@ -20,7 +20,9 @@ description: |
/* configuration for the uart0 "default" state */
uart0_default: uart0_default {
/* configure PB13 as UART0 TX and PB12 as UART0 RX */
pinmux = <PB12MFP_UART0_RXD 0x0000>, <PB13MFP_UART0_TXD 0x0000>;
group0 {
pinmux = <PB12MFP_UART0_RXD>, <PB13MFP_UART0_TXD>;
};
};
};
@ -37,44 +39,47 @@ description: |
compatible: "nuvoton,numaker-pinctrl"
include:
- name: base.yaml
- name: pincfg-node.yaml
child-binding:
property-allowlist:
- drive-push-pull
- drive-open-drain
- bias-disable
- bias-pull-down
- bias-pull-up
include: base.yaml
properties:
reg:
required: true
child-binding:
description: |
Each child node defines the configuration for a particular state.
properties:
pinmux:
required: true
type: array
description: |
An array of pins sharing the same group properties. The pins should
be defined using pre-defined macros or, alternatively, using NVT_PINMUX
macros depending on the pinmux model used by the SoC series.
drive-strength:
type: string
default: "low"
enum:
- "low"
- "fast"
description: |
Set the driving strength of a pin. Hardware default configuration is low and
it's enough to drive most components, like as LED, CAN transceiver and so on.
slew-rate:
type: string
default: "low"
enum:
- "fast"
- "low"
description: |
Set the speed of a pin. This setting effectively limits the
slew rate of the output signal. Hardware default configuration is low.
Fast slew rate could support high speed pins, like as SPI CLK up to 50MHz.
description: NuMaker pin controller pin group
child-binding:
description: |
Each child node defines the configuration for a particular state.
include:
- name: pincfg-node.yaml
property-allowlist:
- drive-open-drain
- input-schmitt-enable
properties:
pinmux:
required: true
type: array
description: |
An array of pins sharing the same group properties. The pins should
be defined using pre-defined macros or, alternatively, using NVT_PINMUX
macros depending on the pinmux model used by the SoC series.
drive-strength:
type: string
default: "low"
enum:
- "low"
- "fast"
description: |
Set the driving strength of a pin. Hardware default configuration is low and
it's enough to drive most components, like as LED, CAN transceiver and so on.
slew-rate:
type: string
default: "low"
enum:
- "low"
- "high"
- "fast"
description: |
Set the speed of a pin. This setting effectively limits the
slew rate of the output signal. Hardware default configuration is low.
Fast slew rate could support fast speed pins, like as SPI CLK up to 50MHz.

View file

@ -12,21 +12,37 @@
#define PORT_INDEX(pinmux) (((pinmux)&0xF0000000) >> 28)
#define PIN_INDEX(pinmux) (((pinmux)&0x0F000000) >> 24)
#define MFP_CFG(pinmux) (((pinmux)&0x000000FF) << ((PIN_INDEX(pinmux) % 4) * 8))
#define MFP_CFG(pinmux) (((pinmux)&0x000000FF) << ((PIN_INDEX(pinmux) % 4) * 8))
#define NU_MFP_POS(pinindex) ((pinindex % 4) * 8)
#define NU_MFP_MASK(pinindex) (0x1f << NU_MFP_POS(pinindex))
#ifdef __cplusplus
extern "C" {
#endif
typedef struct pinctrl_soc_pin_t {
uint32_t pin_mux;
uint32_t open_drain: 1;
uint32_t schmitt_enable: 1;
uint32_t slew_rate: 2;
} pinctrl_soc_pin_t;
#define NUMAKER_DT_PIN(node_id, prop, idx) {.pin_mux = DT_PROP_BY_IDX(node_id, prop, idx)},
#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \
{ \
.pin_mux = DT_PROP_BY_IDX(node_id, prop, idx), \
.open_drain = DT_PROP(node_id, drive_open_drain), \
.schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \
.slew_rate = DT_ENUM_IDX(node_id, slew_rate), \
},
#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) NUMAKER_DT_PIN(node_id, prop, idx)
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
{ \
DT_FOREACH_PROP_ELEM(DT_PHANDLE(node_id, prop), pinmux, Z_PINCTRL_STATE_PIN_INIT) \
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
{ \
DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \
Z_PINCTRL_STATE_PIN_INIT) \
}
#ifdef __cplusplus
}
#endif
#endif /* _NUVOTON_NUMAKER_PINCTRL_SOC_H_ */