[PATCH v5 1/5] pinctrl: renesas: rzg2l: Generalize the power source code
Claudiu Beznea <[email protected]>
| Newsgroups | org.kernel.vger.linux-gpio,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc |
|---|---|
| Message-ID | <[email protected]> |
From: Claudiu Beznea <[email protected]> The current functions used to get/set the pin power source check the OTHER_POC register, which is specific to the RZ/G3L SoC only. To allow the code to be extended for other power source functionalities (e.g. I3C on RZ/G3S), generalize the functions used to get/set the pin power source. For this, introduce the struct rzg2l_register_masks data structure whose purpose is to store SoC specific register bit masks. The members of this structure are then used in rzg2l_caps_to_pwr_reg() to retrieve the bitmask corresponding to a SoC specific power source capability. The conversion between HW specific power source values and SW specific power source values is now handled through rzg2l_pwr_reg_val_to_ps() and rzg2l_ps_to_pwr_reg_val(). Finally, to keep the code generic, the register update in rzg2l_set_power_source() was changed to a read-modify-write approach to cover all cases. Signed-off-by: Claudiu Beznea <[email protected]> --- Changes in v5: - in function rzg2l_ps_to_pwr_reg_val() return power source register value or negative error; due to this, in rzg2l_set_power_source() dropped the val local variable and use ret instead; due to this, to be able to use ret on register setup, moved the rzg2l_ps_to_pwr_reg_val() call after rzg2l_caps_to_pwr_reg() - dropped the tags - collected tags Changes in v4: - none Changes in v3: - collected tags Changes in v2: - none drivers/pinctrl/renesas/pinctrl-rzg2l.c | 174 +++++++++++++++--------- 1 file changed, 109 insertions(+), 65 deletions(-) diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index be52d47d77ae..72e0783d5845 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -186,6 +186,7 @@ #define PVDD_2500 2 /* I/O domain voltage 2.5V */ #define PVDD_1800 1 /* I/O domain voltage <= 1.8V */ #define PVDD_3300 0 /* I/O domain voltage >= 3.3V */ +#define PVDD_MASK 0x3 #define PWPR_B0WI BIT(7) /* Bit Write Disable */ #define PWPR_PFCWE BIT(6) /* PFC Register Write Enable */ @@ -268,6 +269,23 @@ struct rzg2l_register_offsets { u16 other_poc; }; +/** + * struct rzg2l_register_masks - Masks for different RZ/G2L pinctrl functionalities + * @other_poc_pvdd1833_oth_awo_poc: PVDD1833_OTH_AWO_POC mask + * @other_poc_pvdd1833_oth_iso_poc: PVDD1833_OTH_ISO_POC mask + * @other_poc_wdtovf_n_poc: WDTOVF_N_POC mask + */ +struct rzg2l_register_masks { + union { + /* RZ/G3L masks */ + struct { + u8 other_poc_pvdd1833_oth_awo_poc; + u8 other_poc_pvdd1833_oth_iso_poc; + u8 other_poc_wdtovf_n_poc; + }; + }; +}; + /** * enum rzg2l_iolh_index - starting indices in IOLH specific arrays * @RZG2L_IOLH_IDX_1V8: starting index for 1V8 power source @@ -288,6 +306,8 @@ enum rzg2l_iolh_index { /** * struct rzg2l_hwcfg - hardware configuration data structure * @regs: hardware specific register offsets + * @masks: hardware specific masks for various functionalities available in + * the registers described by regs * @iolh_groupa_ua: IOLH group A uA specific values * @iolh_groupb_ua: IOLH group B uA specific values * @iolh_groupc_ua: IOLH group C uA specific values @@ -301,6 +321,7 @@ enum rzg2l_iolh_index { */ struct rzg2l_hwcfg { const struct rzg2l_register_offsets regs; + const struct rzg2l_register_masks masks; u16 iolh_groupa_ua[RZG2L_IOLH_IDX_MAX]; u16 iolh_groupb_ua[RZG2L_IOLH_IDX_MAX]; u16 iolh_groupc_ua[RZG2L_IOLH_IDX_MAX]; @@ -1047,27 +1068,70 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset, } static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, - u32 caps, u8 *mask) + const struct rzg2l_register_masks *masks, + u32 caps, u16 *offset, u8 *mask) { - if (caps & PIN_CFG_IO_VMC_SD0) - return SD_CH(regs->sd_ch, 0); - if (caps & PIN_CFG_IO_VMC_SD1) - return SD_CH(regs->sd_ch, 1); - if (caps & PIN_CFG_IO_VMC_ETH0) - return ETH_POC(regs->eth_poc, 0); - if (caps & PIN_CFG_IO_VMC_ETH1) - return ETH_POC(regs->eth_poc, 1); - if (caps & PIN_CFG_IO_VMC_QSPI) - return QSPI; + *mask = PVDD_MASK; + + if (caps & PIN_CFG_IO_VMC_SD0) { + *offset = SD_CH(regs->sd_ch, 0); + return 0; + } + if (caps & PIN_CFG_IO_VMC_SD1) { + *offset = SD_CH(regs->sd_ch, 1); + return 0; + } + if (caps & PIN_CFG_IO_VMC_ETH0) { + *offset = ETH_POC(regs->eth_poc, 0); + return 0; + } + if (caps & PIN_CFG_IO_VMC_ETH1) { + *offset = ETH_POC(regs->eth_poc, 1); + return 0; + } + if (caps & PIN_CFG_IO_VMC_QSPI) { + *offset = regs->qspi; + return 0; + } if (caps & PIN_CFG_OTHER_POC_MASK) { + *offset = regs->other_poc; if (caps & PIN_CFG_PVDD1833_OTH_AWO_POC) - *mask = BIT(0); + *mask = masks->other_poc_pvdd1833_oth_awo_poc; else if (caps & PIN_CFG_PVDD1833_OTH_ISO_POC) - *mask = BIT(1); + *mask = masks->other_poc_pvdd1833_oth_iso_poc; else - *mask = BIT(2); + *mask = masks->other_poc_wdtovf_n_poc; + return 0; + } - return OTHER_POC; + return -EINVAL; +} + +static int rzg2l_pwr_reg_val_to_ps(u8 val, u32 caps) +{ + switch (val) { + case PVDD_1800: + return 1800; + case PVDD_2500: + return 2500; + case PVDD_3300: + return 3300; + } + + return -EINVAL; +} + +static int rzg2l_ps_to_pwr_reg_val(u32 ps, u32 caps) +{ + switch (ps) { + case 1800: + return PVDD_1800; + case 2500: + if (!(caps & (PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1))) + return -EINVAL; + return PVDD_2500; + case 3300: + return PVDD_3300; } return -EINVAL; @@ -1077,76 +1141,51 @@ static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps { const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; const struct rzg2l_register_offsets *regs = &hwcfg->regs; - u8 val, mask; - int pwr_reg; + const struct rzg2l_register_masks *masks = &hwcfg->masks; + u8 mask, val; + u16 offset; + int ret; if (caps & PIN_CFG_SOFT_PS) return pctrl->settings[pin].power_source; - pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps, &mask); - if (pwr_reg < 0) - return pwr_reg; + ret = rzg2l_caps_to_pwr_reg(regs, masks, caps, &offset, &mask); + if (ret) + return ret; - val = readb(pctrl->base + pwr_reg); - if (pwr_reg == OTHER_POC) - val = field_get(mask, val); + val = readb(pctrl->base + offset); - switch (val) { - case PVDD_1800: - return 1800; - case PVDD_2500: - return 2500; - case PVDD_3300: - return 3300; - default: - /* Should not happen. */ - return -EINVAL; - } + return rzg2l_pwr_reg_val_to_ps(field_get(mask, val), caps); } static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps, u32 ps) { const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg; const struct rzg2l_register_offsets *regs = &hwcfg->regs; - u8 poc_val, val, mask; - int pwr_reg; + const struct rzg2l_register_masks *masks = &hwcfg->masks; + u16 offset; + u8 mask; + int ret; if (caps & PIN_CFG_SOFT_PS) { pctrl->settings[pin].power_source = ps; return 0; } - switch (ps) { - case 1800: - poc_val = PVDD_1800; - break; - case 2500: - if (!(caps & (PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1))) - return -EINVAL; - poc_val = PVDD_2500; - break; - case 3300: - poc_val = PVDD_3300; - break; - default: - return -EINVAL; - } + ret = rzg2l_caps_to_pwr_reg(regs, masks, caps, &offset, &mask); + if (ret) + return ret; - pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps, &mask); - if (pwr_reg < 0) - return pwr_reg; + ret = rzg2l_ps_to_pwr_reg_val(ps, caps); + if (ret < 0) + return ret; - if (pwr_reg == OTHER_POC) { - scoped_guard(raw_spinlock_irqsave, &pctrl->lock) { - val = readb(pctrl->base + pwr_reg); - if (poc_val) - val |= mask; - else - val &= ~mask; - writeb(val, pctrl->base + pwr_reg); - } - } else { - writeb(poc_val, pctrl->base + pwr_reg); + scoped_guard(raw_spinlock_irqsave, &pctrl->lock) { + u8 tmp = readb(pctrl->base + offset); + + tmp &= ~mask; + tmp |= field_prep(mask, ret); + writeb(tmp, pctrl->base + offset); } pctrl->settings[pin].power_source = ps; @@ -3795,6 +3834,11 @@ static const struct rzg2l_hwcfg rzg3l_hwcfg = { .oen = 0x3018, .other_poc = OTHER_POC, }, + .masks = { + .other_poc_pvdd1833_oth_awo_poc = BIT(0), + .other_poc_pvdd1833_oth_iso_poc = BIT(1), + .other_poc_wdtovf_n_poc = BIT(2), + }, .iolh_groupa_ua = { /* 1v8 power source */ [RZG2L_IOLH_IDX_1V8] = 2200, 4400, 9000, 10000, -- 2.43.0