[PATCH 08/14] pinctrl: renesas: rzg2l: Add output enable support

From: Claudiu
Date: Mon Nov 20 2023 - 02:02:07 EST


From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>

Some of the Ethernet pins on RZ/G3S (but also valid for RZ/G2L) need to
have direction of the IO buffer set as output for Ethernet to work
properly. On RZ/G3S these pins are P1_0/P7_0, P1_1/P7_1 with could have
the following Ethernet functions: TXC/TX_CLK or TX_CTL/TX_EN. To be able
to configure this the output enable has been implemented. This is
implemented with 2 per-platform read/write functions to be able to simply
validate the pins supporting this on a platform basis. Moreover, on RZ/G2L
the register though which these settings could be done is 8 bits long
whereas on RZ/G3S this is a 32 bit register. The Ethernet pins supporting
OEN are different. These differences could be handled in platform specific
OEN read/write functions.

Add support for OEN and enable it for RZ/G3S.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
---
drivers/pinctrl/renesas/pinctrl-rzg2l.c | 106 +++++++++++++++++++++++-
1 file changed, 104 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 1401bb215686..e942204e08a2 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -57,6 +57,7 @@
#define PIN_CFG_FILCLKSEL BIT(12)
#define PIN_CFG_IOLH_C BIT(13)
#define PIN_CFG_SOFT_PS BIT(14)
+#define PIN_CFG_OEN BIT(15)

#define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \
(PIN_CFG_IOLH_##group | \
@@ -109,6 +110,7 @@
#define SD_CH(off, ch) ((off) + (ch) * 4)
#define ETH_POC(off, ch) ((off) + (ch) * 4)
#define QSPI (0x3008)
+#define ETH_MODE (0x3018)

#define PVDD_2500 2 /* I/O domain voltage 2.5V */
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */
@@ -195,6 +197,7 @@ struct rzg2l_pinctrl_data {
unsigned int n_port_pins;
unsigned int n_dedicated_pins;
const struct rzg2l_hwcfg *hwcfg;
+ const struct rzg2l_cfg_ops *ops;
};

/**
@@ -228,6 +231,16 @@ struct rzg2l_pinctrl {
struct rzg2l_pinctrl_pin_settings *settings;
};

+/*
+ * struct rzg2l_cfg_ops - platform specific configuration ops
+ * @read_oen: read OEN function
+ * @write_oen: write OEN function
+ */
+struct rzg2l_cfg_ops {
+ u32 (*read_oen)(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin);
+ int (*write_oen)(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen);
+};
+
static const u16 available_ps[] = { 1800, 2500, 3300 };

static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl,
@@ -776,6 +789,67 @@ static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps,
return false;
}

+static bool rzg3s_oen_is_supported(u32 caps, u8 pin)
+{
+ if (!(caps & PIN_CFG_OEN))
+ return false;
+
+ /*
+ * Only pins 0 and 1 of P1 and P7 are supporting this thus add a simple
+ * check for this here.
+ */
+ if (pin > 1)
+ return false;
+
+ return true;
+}
+
+static u8 rzg3s_pin_to_oen_bit(u32 offset, u8 pin)
+{
+ if (pin)
+ pin *= 2;
+
+ if (offset / RZG2L_PINS_PER_PORT == 7)
+ pin += 1;
+
+ return pin;
+}
+
+static u32 rzg3s_read_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin)
+{
+ u8 bit;
+
+ if (!rzg3s_oen_is_supported(caps, pin))
+ return 0;
+
+ bit = rzg3s_pin_to_oen_bit(offset, pin);
+
+ return !(readl(pctrl->base + ETH_MODE) & BIT(bit));
+}
+
+static int rzg3s_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen)
+{
+ unsigned long flags;
+ u32 val;
+ u8 bit;
+
+ if (!rzg3s_oen_is_supported(caps, pin))
+ return -EINVAL;
+
+ bit = rzg3s_pin_to_oen_bit(offset, pin);
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl(pctrl->base + ETH_MODE);
+ if (oen)
+ val &= ~BIT(bit);
+ else
+ val |= BIT(bit);
+ writel(val, pctrl->base + ETH_MODE);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int _pin,
unsigned long *config)
@@ -813,6 +887,16 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
return -EINVAL;
break;

+ case PIN_CONFIG_OUTPUT_ENABLE:
+ if (!(pctrl->data->ops && pctrl->data->ops->read_oen))
+ return -EINVAL;
+
+ arg = pctrl->data->ops->read_oen(pctrl, cfg, _pin, bit);
+ if (!arg)
+ return -EINVAL;
+
+ break;
+
case PIN_CONFIG_POWER_SOURCE:
ret = rzg2l_get_power_source(pctrl, _pin, cfg);
if (ret < 0)
@@ -915,6 +999,16 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
break;
}

+ case PIN_CONFIG_OUTPUT_ENABLE:
+ if (!(pctrl->data->ops && pctrl->data->ops->write_oen))
+ return -EINVAL;
+
+ arg = pinconf_to_config_argument(_configs[i]);
+ ret = pctrl->data->ops->write_oen(pctrl, cfg, _pin, bit, !!arg);
+ if (ret)
+ return ret;
+ break;
+
case PIN_CONFIG_POWER_SOURCE:
settings.power_source = pinconf_to_config_argument(_configs[i]);
break;
@@ -1365,7 +1459,8 @@ static const u32 r9a07g043_gpio_configs[] = {
static const u32 r9a08g045_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(4, 0x20, RZG3S_MPXED_PIN_FUNCS(A)), /* P0 */
RZG2L_GPIO_PORT_PACK(5, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
- PIN_CFG_IO_VMC_ETH0)), /* P1 */
+ PIN_CFG_IO_VMC_ETH0)) |
+ PIN_CFG_IEN | PIN_CFG_OEN, /* P1 */
RZG2L_GPIO_PORT_PACK(4, 0x31, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
PIN_CFG_IO_VMC_ETH0)), /* P2 */
RZG2L_GPIO_PORT_PACK(4, 0x32, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1375,7 +1470,8 @@ static const u32 r9a08g045_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(5, 0x21, RZG3S_MPXED_PIN_FUNCS(A)), /* P5 */
RZG2L_GPIO_PORT_PACK(5, 0x22, RZG3S_MPXED_PIN_FUNCS(A)), /* P6 */
RZG2L_GPIO_PORT_PACK(5, 0x34, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
- PIN_CFG_IO_VMC_ETH1)), /* P7 */
+ PIN_CFG_IO_VMC_ETH1)) |
+ PIN_CFG_IEN | PIN_CFG_OEN, /* P7 */
RZG2L_GPIO_PORT_PACK(5, 0x35, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
PIN_CFG_IO_VMC_ETH1)), /* P8 */
RZG2L_GPIO_PORT_PACK(4, 0x36, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1958,6 +2054,11 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
.func_base = 1,
};

+static const struct rzg2l_cfg_ops rzg3s_ops = {
+ .read_oen = rzg3s_read_oen,
+ .write_oen = rzg3s_write_oen,
+};
+
static struct rzg2l_pinctrl_data r9a07g043_data = {
.port_pins = rzg2l_gpio_names,
.port_pin_configs = r9a07g043_gpio_configs,
@@ -1987,6 +2088,7 @@ static struct rzg2l_pinctrl_data r9a08g045_data = {
.n_port_pins = ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT,
.n_dedicated_pins = ARRAY_SIZE(rzg3s_dedicated_pins),
.hwcfg = &rzg3s_hwcfg,
+ .ops = &rzg3s_ops,
};

static const struct of_device_id rzg2l_pinctrl_of_table[] = {
--
2.39.2