Commit 43519f54 authored by Linus Walleij's avatar Linus Walleij
Browse files

Merge tag 'renesas-pinctrl-for-v6.20-tag1' of...

Merge tag 'renesas-pinctrl-for-v6.20-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers

 into devel

pinctrl: renesas: Updates for v6.20

  - Add support for GPIO IRQs on RZ/T2H and RZ/N2H.

Signed-off-by: default avatarLinus Walleij <linusw@kernel.org>
parents ba769301 829dde33
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -49,6 +49,17 @@ properties:
  gpio-ranges:
    maxItems: 1

  interrupt-controller: true

  '#interrupt-cells':
    const: 2
    description:
      The first cell contains the global GPIO port index, constructed using the
      RZT2H_GPIO() helper macro from <dt-bindings/pinctrl/renesas,r9a09g077-pinctrl.h>
      and the second cell is used to specify the flag.
      E.g. "interrupts = <RZT2H_GPIO(8, 6) IRQ_TYPE_EDGE_FALLING>;" if P08_6 is
      being used as an interrupt.

  clocks:
    maxItems: 1

@@ -139,6 +150,8 @@ examples:
        gpio-controller;
        #gpio-cells = <2>;
        gpio-ranges = <&pinctrl 0 0 288>;
        interrupt-controller;
        #interrupt-cells = <2>;
        power-domains = <&cpg>;

        serial0-pins {
+2 −0
Original line number Diff line number Diff line
@@ -308,9 +308,11 @@ config PINCTRL_RZT2H
	bool "pin control support for RZ/N2H and RZ/T2H" if COMPILE_TEST
	depends on 64BIT && OF
	select GPIOLIB
	select GPIOLIB_IRQCHIP
	select GENERIC_PINCTRL_GROUPS
	select GENERIC_PINMUX_FUNCTIONS
	select GENERIC_PINCONF
	select IRQ_DOMAIN_HIERARCHY
	help
	  This selects GPIO and pinctrl driver for Renesas RZ/T2H
	  platforms.
+239 −9
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
@@ -51,6 +52,7 @@

#define PFC_MASK		GENMASK_ULL(5, 0)
#define PFC_PIN_MASK(pin)	(PFC_MASK << ((pin) * 8))
#define PFC_FUNC_INTERRUPT	0

/*
 * Use 16 lower bits [15:0] for pin identifier
@@ -64,6 +66,9 @@

#define RZT2H_MAX_SAFETY_PORTS		12

#define RZT2H_INTERRUPTS_START		16
#define RZT2H_INTERRUPTS_NUM		17

struct rzt2h_pinctrl_data {
	unsigned int n_port_pins;
	const u8 *port_pin_configs;
@@ -79,9 +84,11 @@ struct rzt2h_pinctrl {
	struct device			*dev;
	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 */
	struct mutex			mutex; /* serialize adding groups and functions */
	bool				safety_port_enabled;
	atomic_t			wakeup_path;
};

#define RZT2H_GET_BASE(pctrl, port) \
@@ -119,6 +126,19 @@ static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset)
	return (pincfg & BIT(pin)) ? 0 : -EINVAL;
}

static void rzt2h_pinctrl_set_gpio_en(struct rzt2h_pinctrl *pctrl,
				      u8 port, u8 pin, bool en)
{
	u8 reg = rzt2h_pinctrl_readb(pctrl, port, PMC(port));

	if (en)
		reg &= ~BIT(pin);
	else
		reg |= BIT(pin);

	rzt2h_pinctrl_writeb(pctrl, port, reg, PMC(port));
}

static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
				       u8 port, u8 pin, u8 func)
{
@@ -133,8 +153,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
	rzt2h_pinctrl_writew(pctrl, port, reg16, PM(port));

	/* Temporarily switch to GPIO mode with PMC register */
	reg16 = rzt2h_pinctrl_readb(pctrl, port, PMC(port));
	rzt2h_pinctrl_writeb(pctrl, port, reg16 & ~BIT(pin), PMC(port));
	rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, true);

	/* Select Pin function mode with PFC register */
	reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
@@ -142,8 +161,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
	rzt2h_pinctrl_writeq(pctrl, port, reg64 | ((u64)func << (pin * 8)), PFC(port));

	/* Switch to Peripheral pin function with PMC register */
	reg16 = rzt2h_pinctrl_readb(pctrl, port, PMC(port));
	rzt2h_pinctrl_writeb(pctrl, port, reg16 | BIT(pin), PMC(port));
	rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, false);
}

static int rzt2h_pinctrl_set_mux(struct pinctrl_dev *pctldev,
@@ -447,7 +465,6 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset)
	u8 port = RZT2H_PIN_ID_TO_PORT(offset);
	u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
	int ret;
	u8 reg;

	ret = rzt2h_validate_pin(pctrl, offset);
	if (ret)
@@ -460,9 +477,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset)
	guard(spinlock_irqsave)(&pctrl->lock);

	/* Select GPIO mode in PMC Register */
	reg = rzt2h_pinctrl_readb(pctrl, port, PMC(port));
	reg &= ~BIT(bit);
	rzt2h_pinctrl_writeb(pctrl, port, reg, PMC(port));
	rzt2h_pinctrl_set_gpio_en(pctrl, port, bit, true);

	return 0;
}
@@ -486,6 +501,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
	struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip);
	u8 port = RZT2H_PIN_ID_TO_PORT(offset);
	u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
	u64 reg64;
	u16 reg;
	int ret;

@@ -493,8 +509,25 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
	if (ret)
		return ret;

	if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit))
	guard(spinlock_irqsave)(&pctrl->lock);

	if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) {
		/*
		 * When a GPIO is being requested as an IRQ, the pinctrl
		 * framework expects to be able to read the GPIO's direction.
		 * IRQ function is separate from GPIO, and enabling it takes the
		 * pin out of GPIO mode.
		 * At this point, .child_to_parent_hwirq() has already been
		 * called to enable the IRQ function.
		 * Default to input direction for IRQ function.
		 */
		reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
		reg64 = (reg64 >> (bit * 8)) & PFC_MASK;
		if (reg64 == PFC_FUNC_INTERRUPT)
			return GPIO_LINE_DIRECTION_IN;

		return -EINVAL;
	}

	reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
	reg = (reg >> (bit * 2)) & PM_MASK;
@@ -617,14 +650,185 @@ static const char * const rzt2h_gpio_names[] = {
	"P35_0", "P35_1", "P35_2", "P35_3", "P35_4", "P35_5", "P35_6", "P35_7",
};

/*
 * Interrupts 0-15 are for INTCPUn, which are not exposed externally.
 * Interrupts 16-31 are for IRQn. SEI is 32.
 * This table matches the information found in User Manual's Section
 * 17.5, Multiplexed Pin Configurations, Tables 17.5 to 17.40, on the
 * Interrupt rows.
 * RZ/N2H has the same GPIO to IRQ mapping, except for the pins which
 * are not present.
 */
static const u8 rzt2h_gpio_irq_map[] = {
	32, 16, 17, 18, 19,  0, 20, 21,
	22,  0,  0,  0,  0,  0,  0,  0,
	23, 24, 25, 26, 27,  0,  0,  0,
	 0,  0, 28, 29, 30, 31,  0,  0,
	 0,  0,  0,  0,  0, 32, 16, 17,
	18, 19, 20, 21, 22,  0,  0,  0,
	 0,  0, 24, 25, 26, 27,  0, 28,
	29, 30, 31,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  0, 24, 32, 16,
	 0,  0,  0,  0,  0,  0,  0,  0,
	20, 23, 17, 18, 19,  0, 16, 25,
	29, 20, 21, 22, 23,  0,  0,  0,
	 0,  0,  0,  0, 17,  0,  0, 18,
	 0,  0, 19,  0,  0, 20,  0, 30,
	21,  0,  0, 22,  0,  0, 24, 25,
	 0,  0,  0,  0,  0, 16, 17,  0,
	18,  0,  0, 26, 27,  0,  0,  0,
	28, 29, 30, 31,  0,  0,  0,  0,
	23, 31, 32, 16, 17, 18, 19, 20,
	 0,  0,  0,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  0,  0,  0,  0,
	27,  0,  0, 21, 22, 23, 24, 25,
	26,  0,  0,  0,  0,  0,  0,  0,
	27, 28, 29, 30, 31,  0,  0,  0,
	 0,  0,  0,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  0, 28, 32, 16,
	17, 18, 19,  0,  0,  0,  0, 20,
	21, 22, 23,  0,  0,  0,  0,  0,
	 0,  0,  0,  0, 24, 25,  0,  0,
	 0,  0, 26, 27,  0,  0,  0, 30,
	 0, 29,  0,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  0,  0,  0,  0,
	 0,  0,  0, 28, 29, 30, 31,  0,
	 0,  0,  0,  0,  0,  0,  0, 30,
	 0,  0,  0,  0,  0,  0,  0,  0,
};

static void rzt2h_gpio_irq_disable(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	unsigned int hwirq = irqd_to_hwirq(d);

	irq_chip_disable_parent(d);
	gpiochip_disable_irq(gc, hwirq);
}

static void rzt2h_gpio_irq_enable(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	unsigned int hwirq = irqd_to_hwirq(d);

	gpiochip_enable_irq(gc, hwirq);
	irq_chip_enable_parent(d);
}

static int rzt2h_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct rzt2h_pinctrl *pctrl = container_of(gc, struct rzt2h_pinctrl, gpio_chip);
	int ret;

	ret = irq_chip_set_wake_parent(d, on);
	if (ret)
		return ret;

	/*
	 * If any of the IRQs are in use, put the entire pin controller on the
	 * device wakeup path.
	 */
	if (on)
		atomic_inc(&pctrl->wakeup_path);
	else
		atomic_dec(&pctrl->wakeup_path);

	return 0;
}

static const struct irq_chip rzt2h_gpio_irqchip = {
	.name = "rzt2h-gpio",
	.irq_disable = rzt2h_gpio_irq_disable,
	.irq_enable = rzt2h_gpio_irq_enable,
	.irq_mask = irq_chip_mask_parent,
	.irq_unmask = irq_chip_unmask_parent,
	.irq_set_type = irq_chip_set_type_parent,
	.irq_set_wake = rzt2h_gpio_irq_set_wake,
	.irq_eoi = irq_chip_eoi_parent,
	.irq_set_affinity = irq_chip_set_affinity_parent,
	.flags = IRQCHIP_IMMUTABLE,
	GPIOCHIP_IRQ_RESOURCE_HELPERS,
};

static int rzt2h_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
					    unsigned int child,
					    unsigned int child_type,
					    unsigned int *parent,
					    unsigned int *parent_type)
{
	struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
	u8 port = RZT2H_PIN_ID_TO_PORT(child);
	u8 pin = RZT2H_PIN_ID_TO_PIN(child);
	u8 parent_irq;

	parent_irq = rzt2h_gpio_irq_map[child];
	if (parent_irq < RZT2H_INTERRUPTS_START)
		return -EINVAL;

	if (test_and_set_bit(parent_irq - RZT2H_INTERRUPTS_START,
			     pctrl->used_irqs))
		return -EBUSY;

	rzt2h_pinctrl_set_pfc_mode(pctrl, port, pin, PFC_FUNC_INTERRUPT);

	*parent = parent_irq;
	*parent_type = child_type;

	return 0;
}

static void rzt2h_gpio_irq_domain_free(struct irq_domain *domain, unsigned int virq,
				       unsigned int nr_irqs)
{
	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct rzt2h_pinctrl *pctrl = container_of(gc, struct rzt2h_pinctrl, gpio_chip);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);
	u8 port = RZT2H_PIN_ID_TO_PORT(hwirq);
	u8 pin = RZT2H_PIN_ID_TO_PIN(hwirq);

	if (test_and_clear_bit(hwirq - RZT2H_INTERRUPTS_START, pctrl->used_irqs))
		rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, false);

	irq_domain_free_irqs_common(domain, virq, nr_irqs);
}

static void rzt2h_gpio_init_irq_valid_mask(struct gpio_chip *gc,
					   unsigned long *valid_mask,
					   unsigned int ngpios)
{
	struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
	unsigned int offset;

	for (offset = 0; offset < ngpios; offset++) {
		if (!rzt2h_gpio_irq_map[offset] || rzt2h_validate_pin(pctrl, offset))
			clear_bit(offset, valid_mask);
	}
}

static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
{
	struct pinctrl_gpio_range *range = &pctrl->gpio_range;
	struct gpio_chip *chip = &pctrl->gpio_chip;
	struct device_node *np = pctrl->dev->of_node;
	struct irq_domain *parent_domain;
	struct device *dev = pctrl->dev;
	struct of_phandle_args of_args;
	struct device_node *parent_np;
	struct gpio_irq_chip *girq;
	int ret;

	parent_np = of_irq_find_parent(np);
	if (!parent_np)
		return -ENXIO;

	parent_domain = irq_find_host(parent_np);
	of_node_put(parent_np);
	if (!parent_domain)
		return -EPROBE_DEFER;

	ret = of_parse_phandle_with_fixed_args(dev->of_node, "gpio-ranges", 3, 0, &of_args);
	if (ret)
		return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n");
@@ -648,6 +852,17 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
	chip->set = rzt2h_gpio_set;
	chip->label = dev_name(dev);

	if (of_property_present(np, "interrupt-controller")) {
		girq = &chip->irq;
		gpio_irq_chip_set_chip(girq, &rzt2h_gpio_irqchip);
		girq->fwnode = dev_fwnode(pctrl->dev);
		girq->parent_domain = parent_domain;
		girq->child_to_parent_hwirq = rzt2h_gpio_child_to_parent_hwirq;
		girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;
		girq->child_irq_domain_ops.free = rzt2h_gpio_irq_domain_free;
		girq->init_valid_mask = rzt2h_gpio_init_irq_valid_mask;
	}

	range->id = 0;
	range->pin_base = 0;
	range->base = 0;
@@ -792,10 +1007,25 @@ static const struct of_device_id rzt2h_pinctrl_of_table[] = {
	{ /* sentinel */ }
};

static int rzt2h_pinctrl_suspend_noirq(struct device *dev)
{
	struct rzt2h_pinctrl *pctrl = dev_get_drvdata(dev);

	if (atomic_read(&pctrl->wakeup_path))
		device_set_wakeup_path(dev);

	return 0;
}

static const struct dev_pm_ops rzt2h_pinctrl_pm_ops = {
	NOIRQ_SYSTEM_SLEEP_PM_OPS(rzt2h_pinctrl_suspend_noirq, NULL)
};

static struct platform_driver rzt2h_pinctrl_driver = {
	.driver = {
		.name = DRV_NAME,
		.of_match_table = of_match_ptr(rzt2h_pinctrl_of_table),
		.pm = pm_sleep_ptr(&rzt2h_pinctrl_pm_ops),
		.suppress_bind_attrs = true,
	},
	.probe = rzt2h_pinctrl_probe,