mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 14:51:51 -04:00
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>
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 @@ static int rzt2h_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user