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 <mykola_kvach@epam.com>
This commit is contained in:
Mykola Kvach 2023-04-14 04:51:38 +03:00 committed by Carles Cufí
parent b8008c4727
commit 72758f96d1
6 changed files with 139 additions and 0 deletions

View file

@ -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

View file

@ -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);

View file

@ -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:

View file

@ -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_ */

View file

@ -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)), \
},
/**

View file

@ -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)), \
},
/**