[PATCH 8/9] pinctrl: renesas: rzg2l: Add RZ/G3S support for selecting the I3C standby state
From: Claudiu Beznea
Date: Fri May 22 2026 - 06:44:30 EST
From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
The I3C pins on the Renesas RZ/G3S SoC can be switched to a standby mode
when the controller operates in I2C mode. According to the RZ/G3S HW
manual (Rev. 1.20), in standby mode "the output is fixed at Hi-Z and no
data is transferred to the inside even if data is input from outside".
Add support to configure the I3C standby mode.
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
---
drivers/pinctrl/renesas/pinctrl-rzg2l.c | 49 ++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 68329b6c6649..b313de35e9df 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -70,6 +70,7 @@
#define PIN_CFG_PVDD1833_OTH_ISO_POC BIT(20) /* known on RZ/G3L only */
#define PIN_CFG_WDTOVF_N_POC BIT(21) /* known on RZ/G3L only */
#define PIN_CFG_IO_VMC_I3C BIT(22)
+#define PIN_CFG_I3C_STANDBY_RZG3S BIT(23)
#define RZG2L_SINGLE_PIN BIT_ULL(63) /* Dedicated pin */
#define RZG2L_VARIABLE_CFG BIT_ULL(62) /* Variable cfg for port pins */
@@ -215,15 +216,24 @@
/* Custom pinconf parameters */
#define RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE (PIN_CONFIG_END + 1)
+#define RENESAS_RZG3S_PIN_CONFIG_I3C_STANDBY (PIN_CONFIG_END + 2)
static const struct pinconf_generic_params renesas_rzv2h_custom_bindings[] = {
{ "renesas,output-impedance", RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE, 1 },
};
+static const struct pinconf_generic_params renesas_rzg3s_custom_bindings[] = {
+ { "renesas,i3c-standby", RENESAS_RZG3S_PIN_CONFIG_I3C_STANDBY, 0 },
+};
+
#ifdef CONFIG_DEBUG_FS
static const struct pin_config_item renesas_rzv2h_conf_items[] = {
PCONFDUMP(RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE, "output-impedance", "x", true),
};
+
+static const struct pin_config_item renesas_rzg3s_conf_items[] = {
+ PCONFDUMP(RENESAS_RZG3S_PIN_CONFIG_I3C_STANDBY, "standby", NULL, true),
+};
#endif
/* Read/write 8 bits register */
@@ -279,6 +289,7 @@ struct rzg2l_register_offsets {
* @other_poc_pvdd1833_oth_iso_poc: PVDD1833_OTH_ISO_POC mask
* @other_poc_wdtovf_n_poc: WDTOVF_N_POC mask
* @i3c_set_poc: I3C_SET_POC mask
+ * @i3c_set_stbn: I3C_SET_STBN mask
*/
struct rzg2l_register_masks {
union {
@@ -292,6 +303,7 @@ struct rzg2l_register_masks {
/* RZ/G3S masks */
struct {
u8 i3c_set_poc;
+ u8 i3c_set_stbn;
};
};
};
@@ -1560,6 +1572,8 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+ const struct rzg2l_register_offsets *regs = &hwcfg->regs;
+ const struct rzg2l_register_masks *masks = &hwcfg->masks;
u32 param = pinconf_to_config_param(*config);
u64 *pin_data = pin->drv_data;
unsigned int arg = 0;
@@ -1702,6 +1716,14 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
arg = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK);
break;
+ case RENESAS_RZG3S_PIN_CONFIG_I3C_STANDBY:
+ if (!(cfg & PIN_CFG_I3C_STANDBY_RZG3S))
+ return -EINVAL;
+
+ arg = readb(pctrl->base + regs->i3c_set);
+ arg = !field_get(masks->i3c_set_stbn, arg);
+ break;
+
default:
return -ENOTSUPP;
}
@@ -1720,6 +1742,8 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
struct rzg2l_pinctrl_pin_settings settings = pctrl->settings[_pin];
+ const struct rzg2l_register_offsets *regs = &hwcfg->regs;
+ const struct rzg2l_register_masks *masks = &hwcfg->masks;
u64 *pin_data = pin->drv_data;
unsigned int i, arg, index;
u32 off, param;
@@ -1846,6 +1870,19 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, arg);
break;
+ case RENESAS_RZG3S_PIN_CONFIG_I3C_STANDBY:
+ if (!(cfg & PIN_CFG_I3C_STANDBY_RZG3S))
+ return -EINVAL;
+
+ scoped_guard(raw_spinlock, &pctrl->lock) {
+ u8 tmp = readb(pctrl->base + regs->i3c_set);
+
+ tmp &= ~masks->i3c_set_stbn;
+ tmp |= field_prep(masks->i3c_set_stbn, !arg);
+ writeb(tmp, pctrl->base + regs->i3c_set);
+ }
+ break;
+
default:
return -ENOTSUPP;
}
@@ -2551,8 +2588,10 @@ static const struct rzg2l_dedicated_configs rzg3s_dedicated_pins[] = {
{ "AUDIO_CLK1", RZG2L_SINGLE_PIN_PACK(0x2, 0, PIN_CFG_IEN) },
{ "AUDIO_CLK2", RZG2L_SINGLE_PIN_PACK(0x2, 1, PIN_CFG_IEN) },
{ "WDTOVF_PERROUT#", RZG2L_SINGLE_PIN_PACK(0x6, 0, PIN_CFG_IOLH_A | PIN_CFG_SOFT_PS) },
- { "I3C_SDA", RZG2L_SINGLE_PIN_PACK(0x9, 0, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C)) },
- { "I3C_SCL", RZG2L_SINGLE_PIN_PACK(0x9, 1, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C)) },
+ { "I3C_SDA", RZG2L_SINGLE_PIN_PACK(0x9, 0, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C |
+ PIN_CFG_I3C_STANDBY_RZG3S)) },
+ { "I3C_SCL", RZG2L_SINGLE_PIN_PACK(0x9, 1, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C |
+ PIN_CFG_I3C_STANDBY_RZG3S)) },
{ "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x10, 0, (PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0)) },
{ "SD0_CMD", RZG2L_SINGLE_PIN_PACK(0x10, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
PIN_CFG_IO_VMC_SD0)) },
@@ -3934,6 +3973,7 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
.oen = 0x3018,
},
.masks = {
+ .i3c_set_stbn = BIT(0),
.i3c_set_poc = BIT(2),
},
.iolh_groupa_ua = {
@@ -4020,6 +4060,11 @@ static struct rzg2l_pinctrl_data r9a08g045_data = {
.pin_to_oen_bit = &rzg3s_pin_to_oen_bit,
.hw_to_bias_param = &rzg2l_hw_to_bias_param,
.bias_param_to_hw = &rzg2l_bias_param_to_hw,
+ .num_custom_params = ARRAY_SIZE(renesas_rzg3s_custom_bindings),
+ .custom_params = renesas_rzg3s_custom_bindings,
+#ifdef CONFIG_DEBUG_FS
+ .custom_conf_items = renesas_rzg3s_conf_items,
+#endif
};
static struct rzg2l_pinctrl_data r9a08g046_data = {
--
2.43.0