diff options
| author | Linus Walleij <linusw@kernel.org> | 2026-03-28 17:14:58 +0100 |
|---|---|---|
| committer | Linus Walleij <linusw@kernel.org> | 2026-03-28 17:14:58 +0100 |
| commit | a91cbf52c115e52392729a855ddb9d85da0517df (patch) | |
| tree | f7059f9cc474d1b1220d55b297a5e4cf7a185d43 | |
| parent | b4e93cbc60641ce2d02d3438cdf59657c8c268b6 (diff) | |
| parent | 3f92867ce3ee2a274ebb7e7d5de7f6ee85da21f6 (diff) | |
Merge tag 'renesas-pinctrl-for-v7.1-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into devel
pinctrl: renesas: Updates for v7.1
- Add pin configuration support for RZ/T2H and RZ/N2H,
- Fix save/restore of registers for ports with variable pincfg per pin
on RZ/G3E, RZ/V2H(P), RZ/V2N, and RZ/Five,
- Drop a superfluous blank line.
Signed-off-by: Linus Walleij <linusw@kernel.org>
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml | 17 | ||||
| -rw-r--r-- | drivers/pinctrl/renesas/pinctrl-rza1.c | 2 | ||||
| -rw-r--r-- | drivers/pinctrl/renesas/pinctrl-rzg2l.c | 8 | ||||
| -rw-r--r-- | drivers/pinctrl/renesas/pinctrl-rzt2h.c | 273 |
4 files changed, 291 insertions, 9 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml index f049013a4e0c..63993b20524f 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,r9a09g077-pinctrl.yaml @@ -83,6 +83,23 @@ definitions: input: true input-enable: true output-enable: true + bias-disable: true + bias-pull-down: true + bias-pull-up: true + input-schmitt-enable: true + input-schmitt-disable: true + slew-rate: + description: 0 is slow slew rate, 1 is fast slew rate + enum: [0, 1] + drive-strength-microamp: + description: | + Four discrete levels are supported (via registers DRCTLm), corresponding + to the following nominal values: + - 2500 (Low strength) + - 5000 (Middle strength) + - 9000 (High strength) + - 11800 (Ultra High strength) + enum: [2500, 5000, 9000, 11800] oneOf: - required: [pinmux] - required: [pins] diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index bc8b9b9ad05b..d2949e4dbaf7 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -589,7 +589,7 @@ static inline unsigned int rza1_get_bit(struct rza1_port *port, { void __iomem *mem = RZA1_ADDR(port->base, reg, port->id); - return ioread16(mem) & BIT(bit); + return !!(ioread16(mem) & BIT(bit)); } /** diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 863e779dda02..561e6018fd89 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -1475,7 +1475,6 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, arg = pinconf_to_config_argument(_configs[i]); switch (param) { case PIN_CONFIG_INPUT_ENABLE: - if (!(cfg & PIN_CFG_IEN)) return -EINVAL; @@ -3012,6 +3011,13 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg); pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg)); + if (cfg & RZG2L_VARIABLE_CFG) { + unsigned int pin = port * RZG2L_PINS_PER_PORT; + + for (unsigned int i = 0; i < RZG2L_PINS_PER_PORT; i++) + cfg |= *(u64 *)pctrl->desc.pins[pin + i].drv_data; + } + caps = FIELD_GET(PIN_CFG_MASK, cfg); has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); has_ien = !!(caps & PIN_CFG_IEN); diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c index 9949108a35bb..4ba11a83b604 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -7,6 +7,7 @@ * Copyright (C) 2025 Renesas Electronics Corporation. */ +#include <linux/array_size.h> #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/bits.h> @@ -43,6 +44,7 @@ #define PMC(m) (0x400 + (m)) #define PFC(m) (0x600 + 8 * (m)) #define PIN(m) (0x800 + (m)) +#define DRCTL(n) (0xa00 + 8 * (n)) #define RSELP(m) (0xc00 + (m)) #define PM_MASK GENMASK(1, 0) @@ -54,6 +56,15 @@ #define PFC_PIN_MASK(pin) (PFC_MASK << ((pin) * 8)) #define PFC_FUNC_INTERRUPT 0 +#define DRCTL_DRV_PIN_MASK(pin) (GENMASK_ULL(1, 0) << ((pin) * 8)) +#define DRCTL_PUD_PIN_MASK(pin) (GENMASK_ULL(3, 2) << ((pin) * 8)) +#define DRCTL_SMT_PIN_MASK(pin) (BIT_ULL(4) << ((pin) * 8)) +#define DRCTL_SR_PIN_MASK(pin) (BIT_ULL(5) << ((pin) * 8)) + +#define DRCTL_PUD_NONE 0 +#define DRCTL_PUD_PULL_UP 1 +#define DRCTL_PUD_PULL_DOWN 2 + /* * Use 16 lower bits [15:0] for pin identifier * Use 8 higher bits [23:16] for pin mux function @@ -85,12 +96,14 @@ struct rzt2h_pinctrl { struct gpio_chip gpio_chip; struct pinctrl_gpio_range gpio_range; DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM); - spinlock_t lock; /* lock read/write registers */ + raw_spinlock_t lock; /* lock read/write registers */ struct mutex mutex; /* serialize adding groups and functions */ bool safety_port_enabled; atomic_t wakeup_path; }; +static const unsigned int rzt2h_drive_strength_ua[] = { 2500, 5000, 9000, 11800 }; + #define RZT2H_GET_BASE(pctrl, port) \ ((port) > RZT2H_MAX_SAFETY_PORTS ? (pctrl)->base0 : (pctrl)->base1) @@ -110,6 +123,37 @@ RZT2H_PINCTRL_REG_ACCESS(b, u8) RZT2H_PINCTRL_REG_ACCESS(w, u16) RZT2H_PINCTRL_REG_ACCESS(q, u64) +static int rzt2h_drive_strength_ua_to_idx(unsigned int ua) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rzt2h_drive_strength_ua); i++) { + if (rzt2h_drive_strength_ua[i] == ua) + return i; + } + + return -EINVAL; +} + +static int rzt2h_drive_strength_idx_to_ua(unsigned int idx) +{ + if (idx >= ARRAY_SIZE(rzt2h_drive_strength_ua)) + return -EINVAL; + + return rzt2h_drive_strength_ua[idx]; +} + +static void rzt2h_pinctrl_drctl_rmwq(struct rzt2h_pinctrl *pctrl, + u32 port, u64 mask, u64 val) +{ + u32 offset = DRCTL(port); + u64 drctl; + + guard(raw_spinlock_irqsave)(&pctrl->lock); + drctl = rzt2h_pinctrl_readq(pctrl, port, offset) & ~mask; + rzt2h_pinctrl_writeq(pctrl, port, drctl | val, offset); +} + static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset) { u8 port = RZT2H_PIN_ID_TO_PORT(offset); @@ -145,7 +189,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl, u64 reg64; u16 reg16; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); /* Set pin to 'Non-use (Hi-Z input protection)' */ reg16 = rzt2h_pinctrl_readw(pctrl, port, PM(port)); @@ -443,6 +487,210 @@ done: return ret; } +static int rzt2h_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *config) +{ + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + u32 port, param = pinconf_to_config_param(*config); + unsigned int arg; + u8 port_pin; + u64 drctl; + int ret; + + ret = rzt2h_validate_pin(pctrl, pin); + if (ret) + return ret; + + port = RZT2H_PIN_ID_TO_PORT(pin); + port_pin = RZT2H_PIN_ID_TO_PIN(pin); + + switch (param) { + case PIN_CONFIG_SLEW_RATE: + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); + arg = field_get(DRCTL_SR_PIN_MASK(port_pin), drctl); + break; + + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); + arg = field_get(DRCTL_PUD_PIN_MASK(port_pin), drctl); + /* for PIN_CONFIG_BIAS_PULL_UP/DOWN when enabled we just return 1 */ + switch (arg) { + case DRCTL_PUD_NONE: + if (param != PIN_CONFIG_BIAS_DISABLE) + return -EINVAL; + break; + case DRCTL_PUD_PULL_UP: + if (param != PIN_CONFIG_BIAS_PULL_UP) + return -EINVAL; + arg = 1; + break; + case DRCTL_PUD_PULL_DOWN: + if (param != PIN_CONFIG_BIAS_PULL_DOWN) + return -EINVAL; + arg = 1; + break; + default: + return -EINVAL; + } + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); + arg = field_get(DRCTL_SMT_PIN_MASK(port_pin), drctl); + if (!arg) + return -EINVAL; + break; + + case PIN_CONFIG_DRIVE_STRENGTH_UA: { + int idx_drv; + + drctl = rzt2h_pinctrl_readq(pctrl, port, DRCTL(port)); + arg = field_get(DRCTL_DRV_PIN_MASK(port_pin), drctl); + idx_drv = rzt2h_drive_strength_idx_to_ua(arg); + if (idx_drv < 0) + return idx_drv; + arg = idx_drv; + break; + } + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int rzt2h_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs) +{ + struct rzt2h_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned int i; + u8 port_pin; + int ret; + + ret = rzt2h_validate_pin(pctrl, pin); + if (ret) + return ret; + + port_pin = RZT2H_PIN_ID_TO_PIN(pin); + + for (i = 0; i < num_configs; i++) { + u32 arg = pinconf_to_config_argument(configs[i]); + u32 param = pinconf_to_config_param(configs[i]); + u64 mask, val; + + switch (param) { + case PIN_CONFIG_SLEW_RATE: + mask = DRCTL_SR_PIN_MASK(port_pin); + val = field_prep(mask, !!arg); + break; + + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: { + u32 bias; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + bias = DRCTL_PUD_NONE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + bias = DRCTL_PUD_PULL_UP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + bias = DRCTL_PUD_PULL_DOWN; + break; + } + + mask = DRCTL_PUD_PIN_MASK(port_pin); + val = field_prep(mask, bias); + break; + } + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask = DRCTL_SMT_PIN_MASK(port_pin); + val = field_prep(mask, !!arg); + break; + + case PIN_CONFIG_DRIVE_STRENGTH_UA: { + int drv_idx; + + drv_idx = rzt2h_drive_strength_ua_to_idx(arg); + if (drv_idx < 0) + return drv_idx; + + mask = DRCTL_DRV_PIN_MASK(port_pin); + val = field_prep(mask, drv_idx); + break; + } + + default: + return -ENOTSUPP; + } + + rzt2h_pinctrl_drctl_rmwq(pctrl, RZT2H_PIN_ID_TO_PORT(pin), mask, val); + } + + return 0; +} + +static int rzt2h_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *config) +{ + unsigned long prev_config = 0; + const unsigned int *pins; + unsigned int i, npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + ret = rzt2h_pinctrl_pinconf_get(pctldev, pins[i], config); + if (ret) + return ret; + + /* Check config matches previous pins */ + if (i && prev_config != *config) + return -ENOTSUPP; + + prev_config = *config; + } + + return 0; +} + +static int rzt2h_pinctrl_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *configs, + unsigned int num_configs) +{ + const unsigned int *pins; + unsigned int i, npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + ret = rzt2h_pinctrl_pinconf_set(pctldev, pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + static const struct pinctrl_ops rzt2h_pinctrl_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, @@ -459,6 +707,15 @@ static const struct pinmux_ops rzt2h_pinctrl_pmxops = { .strict = true, }; +static const struct pinconf_ops rzt2h_pinctrl_confops = { + .is_generic = true, + .pin_config_get = rzt2h_pinctrl_pinconf_get, + .pin_config_set = rzt2h_pinctrl_pinconf_set, + .pin_config_group_set = rzt2h_pinctrl_pinconf_group_set, + .pin_config_group_get = rzt2h_pinctrl_pinconf_group_get, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset) { struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip); @@ -474,7 +731,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); /* Select GPIO mode in PMC Register */ rzt2h_pinctrl_set_gpio_en(pctrl, port, bit, true); @@ -487,7 +744,7 @@ static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port, { u16 reg; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); reg &= ~PM_PIN_MASK(bit); @@ -509,7 +766,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) { /* @@ -547,7 +804,7 @@ static int rzt2h_gpio_set(struct gpio_chip *chip, unsigned int offset, u8 bit = RZT2H_PIN_ID_TO_PIN(offset); u8 reg; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); reg = rzt2h_pinctrl_readb(pctrl, port, P(port)); if (value) @@ -833,6 +1090,7 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl) if (ret) return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n"); + of_node_put(of_args.np); if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) return dev_err_probe(dev, -EINVAL, @@ -889,6 +1147,7 @@ static int rzt2h_pinctrl_register(struct rzt2h_pinctrl *pctrl) desc->npins = pctrl->data->n_port_pins; desc->pctlops = &rzt2h_pinctrl_pctlops; desc->pmxops = &rzt2h_pinctrl_pmxops; + desc->confops = &rzt2h_pinctrl_confops; desc->owner = THIS_MODULE; pins = devm_kcalloc(dev, desc->npins, sizeof(*pins), GFP_KERNEL); @@ -964,7 +1223,7 @@ static int rzt2h_pinctrl_probe(struct platform_device *pdev) if (ret) return ret; - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); mutex_init(&pctrl->mutex); platform_set_drvdata(pdev, pctrl); |
