From 72758f96d1529e72c9fc00f1a270fd2211bb6d7b Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Fri, 14 Apr 2023 04:51:38 +0300 Subject: [PATCH] drivers: pinctrl: pfc_rcar: add support of voltage control to pfc driver Add support of voltage control to Renesas PFC driver. Voltage register mappings have been added to r8a77951 and r8a77961 SoCs. Allow 'power-source' property for 'renesas,rcar-pfc' node. This property will be used for configuring IO voltage on appropriate pin. For now it is possible to have only two voltages: 1.8 and 3.3. Note: it is possible to change voltage only for SD/MMC pins on r8a77951 and r8a77961 SoCs. Signed-off-by: Mykola Kvach --- drivers/pinctrl/Kconfig.rcar | 5 + drivers/pinctrl/pfc_rcar.c | 118 ++++++++++++++++++ dts/bindings/pinctrl/renesas,rcar-pfc.yaml | 2 + .../pinctrl/renesas/pinctrl-rcar-common.h | 4 + soc/arm/renesas_rcar/common/pinctrl_rcar.h | 5 + soc/arm64/renesas_rcar/gen3/pinctrl_soc.h | 5 + 6 files changed, 139 insertions(+) diff --git a/drivers/pinctrl/Kconfig.rcar b/drivers/pinctrl/Kconfig.rcar index 5aabd54371d..cc3ff51b9d6 100644 --- a/drivers/pinctrl/Kconfig.rcar +++ b/drivers/pinctrl/Kconfig.rcar @@ -7,3 +7,8 @@ config PINCTRL_RCAR_PFC depends on DT_HAS_RENESAS_RCAR_PFC_ENABLED help Enable pin controller driver for Renesas RCar SoC + +config PINCTRL_RCAR_VOLTAGE_CONTROL + bool "Voltage control functionality of Renesas R-Car PFC driver" + default y if SOC_SERIES_RCAR_GEN3 + depends on PINCTRL_RCAR_PFC diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 26c5d08c20b..17e4146bbaa 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -35,6 +35,14 @@ static const uintptr_t reg_base[] = { #error Unsupported SoC Series #endif +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL +/* POC Control Register can control IO voltage level that is supplied to the pin */ +struct pfc_pocctrl_reg { + uint32_t offset; + const uint16_t pins[32]; +}; +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ + /* * Each drive step is either encoded in 2 or 3 bits. * So based on a 24 mA maximum value each step is either @@ -189,6 +197,110 @@ int pfc_rcar_set_bias(uintptr_t pfc_base, uint16_t pin, uint16_t flags) return 0; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + +const struct pfc_pocctrl_reg pfc_r8a77951_r8a77961_volt_regs[] = { + { + .offset = 0x0380, + .pins = { + [0] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ + [1] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ + [2] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ + [3] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ + [4] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ + [5] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ + [6] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ + [7] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ + [8] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ + [9] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ + [10] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ + [11] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ + [12] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ + [13] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ + [14] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ + [15] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ + [16] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ + [17] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ + [18] = RCAR_GP_PIN(4, 6), /* SD2_DS */ + [19] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ + [20] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ + [21] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ + [22] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ + [23] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ + [24] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ + [25] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ + [26] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ + [27] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ + [28] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ + [29] = RCAR_GP_PIN(4, 17), /* SD3_DS */ + [30] = -1, + [31] = -1, + } + }, + { /* sentinel */ }, +}; + +static const struct pfc_pocctrl_reg *pfc_rcar_get_io_voltage_regs(void) +{ + return pfc_r8a77951_r8a77961_volt_regs; +} + +static const struct pfc_pocctrl_reg *pfc_rcar_get_pocctrl_reg(uint16_t pin, uint8_t *bit) +{ + const struct pfc_pocctrl_reg *voltage_regs = pfc_rcar_get_io_voltage_regs(); + + BUILD_ASSERT(ARRAY_SIZE(voltage_regs->pins) < UINT8_MAX); + + /* Loop around all the registers to find the bit for a given pin */ + while (voltage_regs && voltage_regs->offset) { + uint8_t i; + + for (i = 0U; i < ARRAY_SIZE(voltage_regs->pins); i++) { + if (voltage_regs->pins[i] == pin) { + *bit = i; + return voltage_regs; + } + } + voltage_regs++; + } + + return NULL; +} + +static void pfc_rcar_set_voltage(uintptr_t pfc_base, uint16_t pin, uint16_t voltage) +{ + uint32_t val; + uint8_t bit; + const struct pfc_pocctrl_reg *voltage_reg; + + voltage_reg = pfc_rcar_get_pocctrl_reg(pin, &bit); + if (!voltage_reg) { + return; + } + + val = sys_read32(pfc_base + voltage_reg->offset); + + switch (voltage) { + case PIN_VOLTAGE_1P8V: + if (!(val & BIT(bit))) { + return; + } + val &= ~BIT(bit); + break; + case PIN_VOLTAGE_3P3V: + if (val & BIT(bit)) { + return; + } + val |= BIT(bit); + break; + default: + break; + } + + pfc_rcar_write(pfc_base, voltage_reg->offset, val); +} +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ + int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) { int ret = 0; @@ -214,6 +326,12 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) return -EINVAL; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + if (pin->voltage != PIN_VOLTAGE_NONE) { + pfc_rcar_set_voltage(pfc_base, pin->pin, pin->voltage); + } +#endif + /* Select function for pin */ if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) { pfc_rcar_set_ipsr(pfc_base, &pin->func); diff --git a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml index fa94cd11c05..8d7ee2c6bbb 100644 --- a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml +++ b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml @@ -51,6 +51,7 @@ description: | - bias-pull-down - bias-pull-up - drive-strength + - power-source To link pin configurations with a device, use a pinctrl-N property for some number N, like this example you could place in your board's DTS file: @@ -82,6 +83,7 @@ child-binding: - bias-pull-down - bias-pull-up - drive-strength + - power-source properties: pin: diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index 504ee2a4d55..f483ec1bb49 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -72,4 +72,8 @@ #define IP2SR5(shift, func) IPnSR(2, 5, shift, func) #define IP3SR5(shift, func) IPnSR(3, 5, shift, func) +#define PIN_VOLTAGE_NONE 0 +#define PIN_VOLTAGE_1P8V 1 +#define PIN_VOLTAGE_3P3V 2 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RCAR_COMMON_H_ */ diff --git a/soc/arm/renesas_rcar/common/pinctrl_rcar.h b/soc/arm/renesas_rcar/common/pinctrl_rcar.h index 0533649d413..c3563e014ba 100644 --- a/soc/arm/renesas_rcar/common/pinctrl_rcar.h +++ b/soc/arm/renesas_rcar/common/pinctrl_rcar.h @@ -38,6 +38,7 @@ typedef struct pinctrl_soc_pin { struct rcar_pin_func func; uint8_t flags; uint8_t drive_strength; + uint8_t voltage; } pinctrl_soc_pin_t; #define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) @@ -66,6 +67,10 @@ typedef struct pinctrl_soc_pin { .drive_strength = \ COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ }, /** diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h index 72c07ae9a4f..0b80eb46634 100644 --- a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -37,6 +37,7 @@ typedef struct pinctrl_soc_pin { struct rcar_pin_func func; uint8_t flags; uint8_t drive_strength; + uint8_t voltage; } pinctrl_soc_pin_t; #define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) @@ -65,6 +66,10 @@ typedef struct pinctrl_soc_pin { .drive_strength = \ COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ }, /**