Skip to content

Commit 829dde3

Browse files
Demon000geertu
authored andcommitted
pinctrl: renesas: rzt2h: Add GPIO IRQ chip to handle interrupts
The Renesas RZ/T2H (R9A09G077) and Renesas RZ/N2H (R9A09G087) SoCs have IRQ-capable pins handled by the ICU, which forwards them to the GIC. The ICU supports 16 IRQ lines, the pins map to these lines arbitrarily, and the mapping is not configurable. Add a GPIO IRQ chip to the pin controller that can be used to configure these pins as IRQ lines. The pin controller places the requested pins into IRQ function, disabling GPIO mode. A hierarchical IRQ domain is used to forward other functionality to the parent IRQ domain, the ICU. The ICU does level translation and then forwards other functionality to the GIC. Wakeup capability is implemented by placing the entire pin controller on the wakeup path if any pins are requested to be wakeup-capable. Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com> Reviewed-by: Linus Walleij <linusw@kernel.org> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://patch.msgid.link/20260109143910.645628-2-cosmin-gabriel.tanislav.xa@renesas.com Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
1 parent 8b12070 commit 829dde3

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

drivers/pinctrl/renesas/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,11 @@ config PINCTRL_RZT2H
308308
bool "pin control support for RZ/N2H and RZ/T2H" if COMPILE_TEST
309309
depends on 64BIT && OF
310310
select GPIOLIB
311+
select GPIOLIB_IRQCHIP
311312
select GENERIC_PINCTRL_GROUPS
312313
select GENERIC_PINMUX_FUNCTIONS
313314
select GENERIC_PINCONF
315+
select IRQ_DOMAIN_HIERARCHY
314316
help
315317
This selects GPIO and pinctrl driver for Renesas RZ/T2H
316318
platforms.

drivers/pinctrl/renesas/pinctrl-rzt2h.c

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/module.h>
1919
#include <linux/mutex.h>
2020
#include <linux/of_device.h>
21+
#include <linux/of_irq.h>
2122
#include <linux/platform_device.h>
2223
#include <linux/pm_runtime.h>
2324
#include <linux/spinlock.h>
@@ -65,6 +66,9 @@
6566

6667
#define RZT2H_MAX_SAFETY_PORTS 12
6768

69+
#define RZT2H_INTERRUPTS_START 16
70+
#define RZT2H_INTERRUPTS_NUM 17
71+
6872
struct rzt2h_pinctrl_data {
6973
unsigned int n_port_pins;
7074
const u8 *port_pin_configs;
@@ -80,9 +84,11 @@ struct rzt2h_pinctrl {
8084
struct device *dev;
8185
struct gpio_chip gpio_chip;
8286
struct pinctrl_gpio_range gpio_range;
87+
DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM);
8388
spinlock_t lock; /* lock read/write registers */
8489
struct mutex mutex; /* serialize adding groups and functions */
8590
bool safety_port_enabled;
91+
atomic_t wakeup_path;
8692
};
8793

8894
#define RZT2H_GET_BASE(pctrl, port) \
@@ -644,14 +650,185 @@ static const char * const rzt2h_gpio_names[] = {
644650
"P35_0", "P35_1", "P35_2", "P35_3", "P35_4", "P35_5", "P35_6", "P35_7",
645651
};
646652

653+
/*
654+
* Interrupts 0-15 are for INTCPUn, which are not exposed externally.
655+
* Interrupts 16-31 are for IRQn. SEI is 32.
656+
* This table matches the information found in User Manual's Section
657+
* 17.5, Multiplexed Pin Configurations, Tables 17.5 to 17.40, on the
658+
* Interrupt rows.
659+
* RZ/N2H has the same GPIO to IRQ mapping, except for the pins which
660+
* are not present.
661+
*/
662+
static const u8 rzt2h_gpio_irq_map[] = {
663+
32, 16, 17, 18, 19, 0, 20, 21,
664+
22, 0, 0, 0, 0, 0, 0, 0,
665+
23, 24, 25, 26, 27, 0, 0, 0,
666+
0, 0, 28, 29, 30, 31, 0, 0,
667+
0, 0, 0, 0, 0, 32, 16, 17,
668+
18, 19, 20, 21, 22, 0, 0, 0,
669+
0, 0, 24, 25, 26, 27, 0, 28,
670+
29, 30, 31, 0, 0, 0, 0, 0,
671+
0, 0, 0, 0, 0, 24, 32, 16,
672+
0, 0, 0, 0, 0, 0, 0, 0,
673+
20, 23, 17, 18, 19, 0, 16, 25,
674+
29, 20, 21, 22, 23, 0, 0, 0,
675+
0, 0, 0, 0, 17, 0, 0, 18,
676+
0, 0, 19, 0, 0, 20, 0, 30,
677+
21, 0, 0, 22, 0, 0, 24, 25,
678+
0, 0, 0, 0, 0, 16, 17, 0,
679+
18, 0, 0, 26, 27, 0, 0, 0,
680+
28, 29, 30, 31, 0, 0, 0, 0,
681+
23, 31, 32, 16, 17, 18, 19, 20,
682+
0, 0, 0, 0, 0, 0, 0, 0,
683+
0, 0, 0, 0, 0, 0, 0, 0,
684+
0, 0, 0, 0, 0, 0, 0, 0,
685+
27, 0, 0, 21, 22, 23, 24, 25,
686+
26, 0, 0, 0, 0, 0, 0, 0,
687+
27, 28, 29, 30, 31, 0, 0, 0,
688+
0, 0, 0, 0, 0, 0, 0, 0,
689+
0, 0, 0, 0, 0, 28, 32, 16,
690+
17, 18, 19, 0, 0, 0, 0, 20,
691+
21, 22, 23, 0, 0, 0, 0, 0,
692+
0, 0, 0, 0, 24, 25, 0, 0,
693+
0, 0, 26, 27, 0, 0, 0, 30,
694+
0, 29, 0, 0, 0, 0, 0, 0,
695+
0, 0, 0, 0, 0, 0, 0, 0,
696+
0, 0, 0, 28, 29, 30, 31, 0,
697+
0, 0, 0, 0, 0, 0, 0, 30,
698+
0, 0, 0, 0, 0, 0, 0, 0,
699+
};
700+
701+
static void rzt2h_gpio_irq_disable(struct irq_data *d)
702+
{
703+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
704+
unsigned int hwirq = irqd_to_hwirq(d);
705+
706+
irq_chip_disable_parent(d);
707+
gpiochip_disable_irq(gc, hwirq);
708+
}
709+
710+
static void rzt2h_gpio_irq_enable(struct irq_data *d)
711+
{
712+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
713+
unsigned int hwirq = irqd_to_hwirq(d);
714+
715+
gpiochip_enable_irq(gc, hwirq);
716+
irq_chip_enable_parent(d);
717+
}
718+
719+
static int rzt2h_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
720+
{
721+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
722+
struct rzt2h_pinctrl *pctrl = container_of(gc, struct rzt2h_pinctrl, gpio_chip);
723+
int ret;
724+
725+
ret = irq_chip_set_wake_parent(d, on);
726+
if (ret)
727+
return ret;
728+
729+
/*
730+
* If any of the IRQs are in use, put the entire pin controller on the
731+
* device wakeup path.
732+
*/
733+
if (on)
734+
atomic_inc(&pctrl->wakeup_path);
735+
else
736+
atomic_dec(&pctrl->wakeup_path);
737+
738+
return 0;
739+
}
740+
741+
static const struct irq_chip rzt2h_gpio_irqchip = {
742+
.name = "rzt2h-gpio",
743+
.irq_disable = rzt2h_gpio_irq_disable,
744+
.irq_enable = rzt2h_gpio_irq_enable,
745+
.irq_mask = irq_chip_mask_parent,
746+
.irq_unmask = irq_chip_unmask_parent,
747+
.irq_set_type = irq_chip_set_type_parent,
748+
.irq_set_wake = rzt2h_gpio_irq_set_wake,
749+
.irq_eoi = irq_chip_eoi_parent,
750+
.irq_set_affinity = irq_chip_set_affinity_parent,
751+
.flags = IRQCHIP_IMMUTABLE,
752+
GPIOCHIP_IRQ_RESOURCE_HELPERS,
753+
};
754+
755+
static int rzt2h_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
756+
unsigned int child,
757+
unsigned int child_type,
758+
unsigned int *parent,
759+
unsigned int *parent_type)
760+
{
761+
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
762+
u8 port = RZT2H_PIN_ID_TO_PORT(child);
763+
u8 pin = RZT2H_PIN_ID_TO_PIN(child);
764+
u8 parent_irq;
765+
766+
parent_irq = rzt2h_gpio_irq_map[child];
767+
if (parent_irq < RZT2H_INTERRUPTS_START)
768+
return -EINVAL;
769+
770+
if (test_and_set_bit(parent_irq - RZT2H_INTERRUPTS_START,
771+
pctrl->used_irqs))
772+
return -EBUSY;
773+
774+
rzt2h_pinctrl_set_pfc_mode(pctrl, port, pin, PFC_FUNC_INTERRUPT);
775+
776+
*parent = parent_irq;
777+
*parent_type = child_type;
778+
779+
return 0;
780+
}
781+
782+
static void rzt2h_gpio_irq_domain_free(struct irq_domain *domain, unsigned int virq,
783+
unsigned int nr_irqs)
784+
{
785+
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
786+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
787+
struct rzt2h_pinctrl *pctrl = container_of(gc, struct rzt2h_pinctrl, gpio_chip);
788+
irq_hw_number_t hwirq = irqd_to_hwirq(d);
789+
u8 port = RZT2H_PIN_ID_TO_PORT(hwirq);
790+
u8 pin = RZT2H_PIN_ID_TO_PIN(hwirq);
791+
792+
if (test_and_clear_bit(hwirq - RZT2H_INTERRUPTS_START, pctrl->used_irqs))
793+
rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, false);
794+
795+
irq_domain_free_irqs_common(domain, virq, nr_irqs);
796+
}
797+
798+
static void rzt2h_gpio_init_irq_valid_mask(struct gpio_chip *gc,
799+
unsigned long *valid_mask,
800+
unsigned int ngpios)
801+
{
802+
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
803+
unsigned int offset;
804+
805+
for (offset = 0; offset < ngpios; offset++) {
806+
if (!rzt2h_gpio_irq_map[offset] || rzt2h_validate_pin(pctrl, offset))
807+
clear_bit(offset, valid_mask);
808+
}
809+
}
810+
647811
static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
648812
{
649813
struct pinctrl_gpio_range *range = &pctrl->gpio_range;
650814
struct gpio_chip *chip = &pctrl->gpio_chip;
815+
struct device_node *np = pctrl->dev->of_node;
816+
struct irq_domain *parent_domain;
651817
struct device *dev = pctrl->dev;
652818
struct of_phandle_args of_args;
819+
struct device_node *parent_np;
820+
struct gpio_irq_chip *girq;
653821
int ret;
654822

823+
parent_np = of_irq_find_parent(np);
824+
if (!parent_np)
825+
return -ENXIO;
826+
827+
parent_domain = irq_find_host(parent_np);
828+
of_node_put(parent_np);
829+
if (!parent_domain)
830+
return -EPROBE_DEFER;
831+
655832
ret = of_parse_phandle_with_fixed_args(dev->of_node, "gpio-ranges", 3, 0, &of_args);
656833
if (ret)
657834
return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n");
@@ -675,6 +852,17 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
675852
chip->set = rzt2h_gpio_set;
676853
chip->label = dev_name(dev);
677854

855+
if (of_property_present(np, "interrupt-controller")) {
856+
girq = &chip->irq;
857+
gpio_irq_chip_set_chip(girq, &rzt2h_gpio_irqchip);
858+
girq->fwnode = dev_fwnode(pctrl->dev);
859+
girq->parent_domain = parent_domain;
860+
girq->child_to_parent_hwirq = rzt2h_gpio_child_to_parent_hwirq;
861+
girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;
862+
girq->child_irq_domain_ops.free = rzt2h_gpio_irq_domain_free;
863+
girq->init_valid_mask = rzt2h_gpio_init_irq_valid_mask;
864+
}
865+
678866
range->id = 0;
679867
range->pin_base = 0;
680868
range->base = 0;
@@ -819,10 +1007,25 @@ static const struct of_device_id rzt2h_pinctrl_of_table[] = {
8191007
{ /* sentinel */ }
8201008
};
8211009

1010+
static int rzt2h_pinctrl_suspend_noirq(struct device *dev)
1011+
{
1012+
struct rzt2h_pinctrl *pctrl = dev_get_drvdata(dev);
1013+
1014+
if (atomic_read(&pctrl->wakeup_path))
1015+
device_set_wakeup_path(dev);
1016+
1017+
return 0;
1018+
}
1019+
1020+
static const struct dev_pm_ops rzt2h_pinctrl_pm_ops = {
1021+
NOIRQ_SYSTEM_SLEEP_PM_OPS(rzt2h_pinctrl_suspend_noirq, NULL)
1022+
};
1023+
8221024
static struct platform_driver rzt2h_pinctrl_driver = {
8231025
.driver = {
8241026
.name = DRV_NAME,
8251027
.of_match_table = of_match_ptr(rzt2h_pinctrl_of_table),
1028+
.pm = pm_sleep_ptr(&rzt2h_pinctrl_pm_ops),
8261029
.suppress_bind_attrs = true,
8271030
},
8281031
.probe = rzt2h_pinctrl_probe,

0 commit comments

Comments
 (0)