* [PATCH 0/3] pinctrl: ingenic: Add X2600 support
@ 2026-11-13 8:14 H. Nikolaus Schaller
2026-11-13 8:14 ` [PATCH 1/3] dt-bindings: " H. Nikolaus Schaller
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: H. Nikolaus Schaller @ 2026-11-13 8:14 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Cercueil, Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel,
H. Nikolaus Schaller
PATCH V1 2026-11-13 09:13:47:
This series adds pinctrl and GPIO support for the Lumissil X2600
SoC.
It introduces the devicetree bindings, adapts the register access
and GPIO interrupt handling to the X2600 hardware, and adds the
pin groups and mux functions.
The changes also correct hardware both-edge GPIO interrupt
configuration on X1600 and X2000.
The updated driver has been tested on X1600, X2000, and X2600
including GPIO both-edge interrupt handling.
The code has been tested by ChatGPT which also helped to formulate
the messages.
H. Nikolaus Schaller (3):
dt-bindings: pinctrl: ingenic: Add X2600 support
pinctrl: ingenic: Add X2600 register and GPIO IRQ support
pinctrl: ingenic: Add X2600 pin groups and functions
.../bindings/pinctrl/ingenic,pinctrl.yaml | 10 +-
drivers/pinctrl/pinctrl-ingenic.c | 573 +++++++++++++++++-
2 files changed, 566 insertions(+), 17 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/3] dt-bindings: pinctrl: ingenic: Add X2600 support 2026-11-13 8:14 [PATCH 0/3] pinctrl: ingenic: Add X2600 support H. Nikolaus Schaller @ 2026-11-13 8:14 ` H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 3/3] pinctrl: ingenic: Add X2600 pin groups and functions H. Nikolaus Schaller 2 siblings, 0 replies; 8+ messages in thread From: H. Nikolaus Schaller @ 2026-11-13 8:14 UTC (permalink / raw) To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, Bartosz Golaszewski Cc: linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel, H. Nikolaus Schaller Add the pinctrl and GPIO compatible strings for the Lumissil X2600 SoC. The X2600 provides five GPIO ports with 32 pins each. Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- .../devicetree/bindings/pinctrl/ingenic,pinctrl.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml index 84e960255a36d..05c1a31469a42 100644 --- a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml @@ -19,10 +19,10 @@ description: > pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and PB31 is the last pin in GPIO port B. The JZ4730, the JZ4740, the JZ4725B, the X1000 and the X1830 contains 4 GPIO ports, PA to PD, for a total of 128 - pins. The X2000 and the X2100 contains 5 GPIO ports, PA to PE, for a total of - 160 pins. The JZ4750, the JZ4755 the JZ4760, the JZ4770 and the JZ4780 contains - 6 GPIO ports, PA to PF, for a total of 192 pins. The JZ4775 contains 7 GPIO - ports, PA to PG, for a total of 224 pins. + pins. The X2000, the X2100 and the X2600 contains 5 GPIO ports, PA to PE, for a + total of 160 pins. The JZ4750, the JZ4755 the JZ4760, the JZ4770 and the JZ4780 + contains 6 GPIO ports, PA to PF, for a total of 192 pins. The JZ4775 contains + 7 GPIO ports, PA to PG, for a total of 224 pins. maintainers: - Paul Cercueil <paul@crapouillou.net> @@ -46,6 +46,7 @@ properties: - ingenic,x1830-pinctrl - ingenic,x2000-pinctrl - ingenic,x2100-pinctrl + - ingenic,x2600-pinctrl - items: - const: ingenic,jz4760b-pinctrl - const: ingenic,jz4760-pinctrl @@ -86,6 +87,7 @@ patternProperties: - ingenic,x1830-gpio - ingenic,x2000-gpio - ingenic,x2100-gpio + - ingenic,x2600-gpio reg: items: -- 2.56.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support 2026-11-13 8:14 [PATCH 0/3] pinctrl: ingenic: Add X2600 support H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 1/3] dt-bindings: " H. Nikolaus Schaller @ 2026-11-13 8:14 ` H. Nikolaus Schaller 2026-11-13 9:37 ` Paul Cercueil 2026-11-13 8:14 ` [PATCH 3/3] pinctrl: ingenic: Add X2600 pin groups and functions H. Nikolaus Schaller 2 siblings, 1 reply; 8+ messages in thread From: H. Nikolaus Schaller @ 2026-11-13 8:14 UTC (permalink / raw) To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, Bartosz Golaszewski Cc: linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel, H. Nikolaus Schaller Add the X2600 SoC ID and adapt the GPIO register access functions to its register layout. Unlike earlier Ingenic SoCs, the X2600 uses a register bank spacing of 0x1000 and provides separate shadow registers and load registers for each GPIO port. It also uses a dedicated register for clearing GPIO interrupt flags. Update the GPIO interrupt configuration to account for hardware dual-edge detection on X1600, X2000 and X2600. These SoCs require PAT1 to be set when dual-edge detection is enabled, while X1000 and X1830 continue to use software emulation. The corrected interrupt configuration has been tested on X1600, X2000, and X2600, including GPIO dual-edge interrupts by a gpio-button. Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- drivers/pinctrl/pinctrl-ingenic.c | 71 +++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index a62532c49fb60..90c734c74d267 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -70,6 +70,10 @@ #define X2000_GPIO_SR 0xd0 #define X2000_GPIO_SMT 0xe0 +#define X2600_GPIO_FLAG_CLR 0x58 /* write only */ +#define X2600_GPIO_SHADOW_OFFSET 0x800 +#define X2600_GPIO_PAGLD (X2600_GPIO_SHADOW_OFFSET + 0xf0) + #define REG_SET(x) ((x) + 0x4) #define REG_CLEAR(x) ((x) + 0x8) @@ -114,6 +118,7 @@ enum jz_version { ID_X1830, ID_X2000, ID_X2100, + ID_X2600, }; struct ingenic_chip_info { @@ -164,7 +169,8 @@ static const unsigned long enabled_socs = IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | - IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; + IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100 | + IS_ENABLED(CONFIG_MACH_X2600) << ID_X2600; static bool is_soc_or_above(const struct ingenic_pinctrl *jzpc, enum jz_version version) @@ -3545,15 +3551,21 @@ static void ingenic_gpio_shadow_set_bit(struct ingenic_gpio_chip *jzgc, else reg = REG_CLEAR(reg); - regmap_write(jzgc->jzpc->map, REG_PZ_BASE( - jzgc->jzpc->info->reg_offset) + reg, BIT(offset)); + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) + regmap_write(jzgc->jzpc->map, jzgc->reg_base + X2600_GPIO_SHADOW_OFFSET + reg, + BIT(offset)); + else + regmap_write(jzgc->jzpc->map, REG_PZ_BASE(jzgc->jzpc->info->reg_offset) + reg, + BIT(offset)); } static void ingenic_gpio_shadow_set_bit_load(struct ingenic_gpio_chip *jzgc) { - regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD( - jzgc->jzpc->info->reg_offset), - jzgc->gc.base / PINS_PER_GPIO_CHIP); + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) + regmap_write(jzgc->jzpc->map, jzgc->reg_base + X2600_GPIO_PAGLD, 1); + else + regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD(jzgc->jzpc->info->reg_offset), + jzgc->gc.base / PINS_PER_GPIO_CHIP); } static void jz4730_gpio_set_bits(struct ingenic_gpio_chip *jzgc, @@ -3618,6 +3630,12 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc, break; } + if (type == IRQ_TYPE_EDGE_BOTH && + (is_soc_or_above(jzgc->jzpc, ID_X2000) || + (is_soc_or_above(jzgc->jzpc, ID_X1600) && + !is_soc_or_above(jzgc->jzpc, ID_X1830)))) + val2 = true; + if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) { reg1 = JZ4770_GPIO_PAT1; reg2 = JZ4770_GPIO_PAT0; @@ -3640,6 +3658,9 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc, ingenic_gpio_shadow_set_bit(jzgc, reg2, offset, val1); ingenic_gpio_shadow_set_bit(jzgc, reg1, offset, val2); ingenic_gpio_shadow_set_bit_load(jzgc); + + if (is_soc_or_above(jzgc->jzpc, ID_X1600) && !is_soc_or_above(jzgc->jzpc, ID_X1830)) + ingenic_gpio_set_bit(jzgc, X2000_GPIO_EDG, offset, val3); } else { ingenic_gpio_set_bit(jzgc, reg2, offset, val1); ingenic_gpio_set_bit(jzgc, reg1, offset, val2); @@ -3714,7 +3735,8 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) bool high; if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) && - !is_soc_or_above(jzgc->jzpc, ID_X2000)) { + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc->jzpc, ID_X2000)))) { /* * Switch to an interrupt for the opposite edge to the one that * triggered the interrupt being ACKed. @@ -3726,7 +3748,9 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH); } - if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) + regmap_write(jzgc->jzpc->map, jzgc->reg_base + X2600_GPIO_FLAG_CLR, BIT(irq)); + else if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); else if (is_soc_or_above(jzgc->jzpc, ID_JZ4740)) ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); @@ -3754,7 +3778,9 @@ static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) irq_set_handler_locked(irqd, handle_bad_irq); } - if ((type == IRQ_TYPE_EDGE_BOTH) && !is_soc_or_above(jzgc->jzpc, ID_X2000)) { + if (type == IRQ_TYPE_EDGE_BOTH && + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc->jzpc, ID_X2000)))) { /* * The hardware does not support interrupts on both edges. The * best we can do is to set up a single-edge interrupt and then @@ -3849,16 +3875,35 @@ static inline void ingenic_shadow_config_pin(struct ingenic_pinctrl *jzpc, unsigned int pin, u8 reg, bool set) { unsigned int idx = pin % PINS_PER_GPIO_CHIP; + unsigned int offt = pin / PINS_PER_GPIO_CHIP; - regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + - (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx)); + if (set) + reg = REG_SET(reg); + else + reg = REG_CLEAR(reg); + + if (is_soc_or_above(jzpc, ID_X2600)) { + u32 target_reg = (offt * jzpc->info->reg_offset) + X2600_GPIO_SHADOW_OFFSET + reg; + + regmap_write(jzpc->map, target_reg, BIT(idx)); + } else { + regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + reg, BIT(idx)); + } } static inline void ingenic_shadow_config_pin_load(struct ingenic_pinctrl *jzpc, unsigned int pin) { - regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), - pin / PINS_PER_GPIO_CHIP); + unsigned int offt = pin / PINS_PER_GPIO_CHIP; + + if (is_soc_or_above(jzpc, ID_X2600)) { + u32 target_load_reg = (offt * jzpc->info->reg_offset) + X2600_GPIO_PAGLD; + + regmap_write(jzpc->map, target_load_reg, 1); + } else { + regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), + pin / PINS_PER_GPIO_CHIP); + } } static inline void jz4730_config_pin_function(struct ingenic_pinctrl *jzpc, -- 2.56.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support 2026-11-13 8:14 ` [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support H. Nikolaus Schaller @ 2026-11-13 9:37 ` Paul Cercueil 2026-11-13 9:49 ` H. Nikolaus Schaller 0 siblings, 1 reply; 8+ messages in thread From: Paul Cercueil @ 2026-11-13 9:37 UTC (permalink / raw) To: H. Nikolaus Schaller, Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski Cc: linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel Hi Nikolaus, Le vendredi 13 novembre 2026 à 09:14 +0100, H. Nikolaus Schaller a écrit : > Add the X2600 SoC ID and adapt the GPIO register access functions > to its register layout. > > Unlike earlier Ingenic SoCs, the X2600 uses a register bank > spacing of 0x1000 and provides separate shadow registers and > load registers for each GPIO port. It also uses a dedicated > register for clearing GPIO interrupt flags. > > Update the GPIO interrupt configuration to account for hardware > dual-edge detection on X1600, X2000 and X2600. These SoCs require > PAT1 to be set when dual-edge detection is enabled, while X1000 > and X1830 continue to use software emulation. So at the same time you're fixing X1600/X2000 and adding support for X2600. Looks to me like it should be splitted into two patches. > > The corrected interrupt configuration has been tested on X1600, > X2000, and X2600, including GPIO dual-edge interrupts by a > gpio-button. > > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > --- > drivers/pinctrl/pinctrl-ingenic.c | 71 +++++++++++++++++++++++++------ > 1 file changed, 58 insertions(+), 13 deletions(-) > > diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl- > ingenic.c > index a62532c49fb60..90c734c74d267 100644 > --- a/drivers/pinctrl/pinctrl-ingenic.c > +++ b/drivers/pinctrl/pinctrl-ingenic.c > @@ -70,6 +70,10 @@ > #define X2000_GPIO_SR 0xd0 > #define X2000_GPIO_SMT 0xe0 > > +#define X2600_GPIO_FLAG_CLR 0x58 /* write only */ > +#define X2600_GPIO_SHADOW_OFFSET 0x800 > +#define X2600_GPIO_PAGLD (X2600_GPIO_SHADOW_OFFSET + > 0xf0) > + > #define REG_SET(x) ((x) + 0x4) > #define REG_CLEAR(x) ((x) + 0x8) > > @@ -114,6 +118,7 @@ enum jz_version { > ID_X1830, > ID_X2000, > ID_X2100, > + ID_X2600, > }; > > struct ingenic_chip_info { > @@ -164,7 +169,8 @@ static const unsigned long enabled_socs = > IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | > IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | > IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | > - IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; > + IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100 | > + IS_ENABLED(CONFIG_MACH_X2600) << ID_X2600; > > static bool > is_soc_or_above(const struct ingenic_pinctrl *jzpc, enum jz_version version) > @@ -3545,15 +3551,21 @@ static void ingenic_gpio_shadow_set_bit(struct > ingenic_gpio_chip *jzgc, > else > reg = REG_CLEAR(reg); > > - regmap_write(jzgc->jzpc->map, REG_PZ_BASE( > - jzgc->jzpc->info->reg_offset) + reg, BIT(offset)); > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > X2600_GPIO_SHADOW_OFFSET + reg, > + BIT(offset)); > + else > + regmap_write(jzgc->jzpc->map, REG_PZ_BASE(jzgc->jzpc->info- > >reg_offset) + reg, > + BIT(offset)); > } > > static void ingenic_gpio_shadow_set_bit_load(struct ingenic_gpio_chip *jzgc) > { > - regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD( > - jzgc->jzpc->info->reg_offset), > - jzgc->gc.base / PINS_PER_GPIO_CHIP); > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > X2600_GPIO_PAGLD, 1); > + else > + regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD(jzgc->jzpc->info- > >reg_offset), > + jzgc->gc.base / PINS_PER_GPIO_CHIP); > } > > static void jz4730_gpio_set_bits(struct ingenic_gpio_chip *jzgc, > @@ -3618,6 +3630,12 @@ static void irq_set_type(struct ingenic_gpio_chip > *jzgc, > break; > } > > + if (type == IRQ_TYPE_EDGE_BOTH && > + (is_soc_or_above(jzgc->jzpc, ID_X2000) || > + (is_soc_or_above(jzgc->jzpc, ID_X1600) && > + !is_soc_or_above(jzgc->jzpc, ID_X1830)))) I remember you saying (in another patchset) that the X1830 was older than the X1600, if that's the case the IDs for X1600 and X1830 should be swapped. I believe this patch would then become much simpler. Cheers, -Paul > + val2 = true; > + > if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) { > reg1 = JZ4770_GPIO_PAT1; > reg2 = JZ4770_GPIO_PAT0; > @@ -3640,6 +3658,9 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc, > ingenic_gpio_shadow_set_bit(jzgc, reg2, offset, val1); > ingenic_gpio_shadow_set_bit(jzgc, reg1, offset, val2); > ingenic_gpio_shadow_set_bit_load(jzgc); > + > + if (is_soc_or_above(jzgc->jzpc, ID_X1600) && > !is_soc_or_above(jzgc->jzpc, ID_X1830)) > + ingenic_gpio_set_bit(jzgc, X2000_GPIO_EDG, offset, > val3); > } else { > ingenic_gpio_set_bit(jzgc, reg2, offset, val1); > ingenic_gpio_set_bit(jzgc, reg1, offset, val2); > @@ -3714,7 +3735,8 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) > bool high; > > if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) && > - !is_soc_or_above(jzgc->jzpc, ID_X2000)) { > + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || > + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- > >jzpc, ID_X2000)))) { > /* > * Switch to an interrupt for the opposite edge to the one > that > * triggered the interrupt being ACKed. > @@ -3726,7 +3748,9 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) > irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH); > } > > - if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > X2600_GPIO_FLAG_CLR, BIT(irq)); > + else if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) > ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); > else if (is_soc_or_above(jzgc->jzpc, ID_JZ4740)) > ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); > @@ -3754,7 +3778,9 @@ static int ingenic_gpio_irq_set_type(struct irq_data > *irqd, unsigned int type) > irq_set_handler_locked(irqd, handle_bad_irq); > } > > - if ((type == IRQ_TYPE_EDGE_BOTH) && !is_soc_or_above(jzgc->jzpc, > ID_X2000)) { > + if (type == IRQ_TYPE_EDGE_BOTH && > + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || > + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- > >jzpc, ID_X2000)))) { > /* > * The hardware does not support interrupts on both edges. > The > * best we can do is to set up a single-edge interrupt and > then > @@ -3849,16 +3875,35 @@ static inline void ingenic_shadow_config_pin(struct > ingenic_pinctrl *jzpc, > unsigned int pin, u8 reg, bool set) > { > unsigned int idx = pin % PINS_PER_GPIO_CHIP; > + unsigned int offt = pin / PINS_PER_GPIO_CHIP; > > - regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + > - (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx)); > + if (set) > + reg = REG_SET(reg); > + else > + reg = REG_CLEAR(reg); > + > + if (is_soc_or_above(jzpc, ID_X2600)) { > + u32 target_reg = (offt * jzpc->info->reg_offset) + > X2600_GPIO_SHADOW_OFFSET + reg; > + > + regmap_write(jzpc->map, target_reg, BIT(idx)); > + } else { > + regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + > reg, BIT(idx)); > + } > } > > static inline void ingenic_shadow_config_pin_load(struct ingenic_pinctrl > *jzpc, > unsigned int pin) > { > - regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), > - pin / PINS_PER_GPIO_CHIP); > + unsigned int offt = pin / PINS_PER_GPIO_CHIP; > + > + if (is_soc_or_above(jzpc, ID_X2600)) { > + u32 target_load_reg = (offt * jzpc->info->reg_offset) + > X2600_GPIO_PAGLD; > + > + regmap_write(jzpc->map, target_load_reg, 1); > + } else { > + regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info- > >reg_offset), > + pin / PINS_PER_GPIO_CHIP); > + } > } > > static inline void jz4730_config_pin_function(struct ingenic_pinctrl *jzpc, ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support 2026-11-13 9:37 ` Paul Cercueil @ 2026-11-13 9:49 ` H. Nikolaus Schaller 2026-11-13 9:54 ` Paul Cercueil 0 siblings, 1 reply; 8+ messages in thread From: H. Nikolaus Schaller @ 2026-11-13 9:49 UTC (permalink / raw) To: Paul Cercueil Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski, linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel Hi Paul, > Am 13.11.2026 um 10:37 schrieb Paul Cercueil <paul@crapouillou.net>: > > Hi Nikolaus, > > Le vendredi 13 novembre 2026 à 09:14 +0100, H. Nikolaus Schaller a écrit : >> Add the X2600 SoC ID and adapt the GPIO register access functions >> to its register layout. >> >> Unlike earlier Ingenic SoCs, the X2600 uses a register bank >> spacing of 0x1000 and provides separate shadow registers and >> load registers for each GPIO port. It also uses a dedicated >> register for clearing GPIO interrupt flags. >> >> Update the GPIO interrupt configuration to account for hardware >> dual-edge detection on X1600, X2000 and X2600. These SoCs require >> PAT1 to be set when dual-edge detection is enabled, while X1000 >> and X1830 continue to use software emulation. > > So at the same time you're fixing X1600/X2000 and adding support for X2600. > Looks to me like it should be splitted into two patches. Well, I have to look if it can be split. So far the driver for X1600/X2000 does not have dual-edge support by hardware (programming the EDG bit). But registers and programming model are the same. Therefore it is more or less a nice side-effect that x2600 adds functions to x1600/x2000. I.e. new code would be replacing some is_soc_or_above(jzgc->jzpc, ID_X2600) with is_soc_or_above(jzgc->jzpc, ID_X1600) to fix it for them. Or otherwise we have to split full x2600 support into two patches. Is this worth a separate patch or should we leave it as a comment in the commit message? > >> >> The corrected interrupt configuration has been tested on X1600, >> X2000, and X2600, including GPIO dual-edge interrupts by a >> gpio-button. >> >> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> >> --- >> drivers/pinctrl/pinctrl-ingenic.c | 71 +++++++++++++++++++++++++------ >> 1 file changed, 58 insertions(+), 13 deletions(-) >> >> diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl- >> ingenic.c >> index a62532c49fb60..90c734c74d267 100644 >> --- a/drivers/pinctrl/pinctrl-ingenic.c >> +++ b/drivers/pinctrl/pinctrl-ingenic.c >> @@ -70,6 +70,10 @@ >> #define X2000_GPIO_SR 0xd0 >> #define X2000_GPIO_SMT 0xe0 >> >> +#define X2600_GPIO_FLAG_CLR 0x58 /* write only */ >> +#define X2600_GPIO_SHADOW_OFFSET 0x800 >> +#define X2600_GPIO_PAGLD (X2600_GPIO_SHADOW_OFFSET + >> 0xf0) >> + >> #define REG_SET(x) ((x) + 0x4) >> #define REG_CLEAR(x) ((x) + 0x8) >> >> @@ -114,6 +118,7 @@ enum jz_version { >> ID_X1830, >> ID_X2000, >> ID_X2100, >> + ID_X2600, >> }; >> >> struct ingenic_chip_info { >> @@ -164,7 +169,8 @@ static const unsigned long enabled_socs = >> IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | >> IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | >> IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | >> - IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; >> + IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100 | >> + IS_ENABLED(CONFIG_MACH_X2600) << ID_X2600; >> >> static bool >> is_soc_or_above(const struct ingenic_pinctrl *jzpc, enum jz_version version) >> @@ -3545,15 +3551,21 @@ static void ingenic_gpio_shadow_set_bit(struct >> ingenic_gpio_chip *jzgc, >> else >> reg = REG_CLEAR(reg); >> >> - regmap_write(jzgc->jzpc->map, REG_PZ_BASE( >> - jzgc->jzpc->info->reg_offset) + reg, BIT(offset)); >> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >> X2600_GPIO_SHADOW_OFFSET + reg, >> + BIT(offset)); >> + else >> + regmap_write(jzgc->jzpc->map, REG_PZ_BASE(jzgc->jzpc->info- >>> reg_offset) + reg, >> + BIT(offset)); >> } >> >> static void ingenic_gpio_shadow_set_bit_load(struct ingenic_gpio_chip *jzgc) >> { >> - regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD( >> - jzgc->jzpc->info->reg_offset), >> - jzgc->gc.base / PINS_PER_GPIO_CHIP); >> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >> X2600_GPIO_PAGLD, 1); >> + else >> + regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD(jzgc->jzpc->info- >>> reg_offset), >> + jzgc->gc.base / PINS_PER_GPIO_CHIP); >> } >> >> static void jz4730_gpio_set_bits(struct ingenic_gpio_chip *jzgc, >> @@ -3618,6 +3630,12 @@ static void irq_set_type(struct ingenic_gpio_chip >> *jzgc, >> break; >> } >> >> + if (type == IRQ_TYPE_EDGE_BOTH && >> + (is_soc_or_above(jzgc->jzpc, ID_X2000) || >> + (is_soc_or_above(jzgc->jzpc, ID_X1600) && >> + !is_soc_or_above(jzgc->jzpc, ID_X1830)))) > > I remember you saying (in another patchset) that the X1830 was older than the > X1600, if that's the case the IDs for X1600 and X1830 should be swapped. I > believe this patch would then become much simpler. Indeed. So I can swap the ID's in V2. BR and thanks, Nikolaus > > Cheers, > -Paul > >> + val2 = true; >> + >> if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) { >> reg1 = JZ4770_GPIO_PAT1; >> reg2 = JZ4770_GPIO_PAT0; >> @@ -3640,6 +3658,9 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc, >> ingenic_gpio_shadow_set_bit(jzgc, reg2, offset, val1); >> ingenic_gpio_shadow_set_bit(jzgc, reg1, offset, val2); >> ingenic_gpio_shadow_set_bit_load(jzgc); >> + >> + if (is_soc_or_above(jzgc->jzpc, ID_X1600) && >> !is_soc_or_above(jzgc->jzpc, ID_X1830)) >> + ingenic_gpio_set_bit(jzgc, X2000_GPIO_EDG, offset, >> val3); >> } else { >> ingenic_gpio_set_bit(jzgc, reg2, offset, val1); >> ingenic_gpio_set_bit(jzgc, reg1, offset, val2); >> @@ -3714,7 +3735,8 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) >> bool high; >> >> if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) && >> - !is_soc_or_above(jzgc->jzpc, ID_X2000)) { >> + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || >> + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- >>> jzpc, ID_X2000)))) { >> /* >> * Switch to an interrupt for the opposite edge to the one >> that >> * triggered the interrupt being ACKed. >> @@ -3726,7 +3748,9 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd) >> irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH); >> } >> >> - if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) >> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >> X2600_GPIO_FLAG_CLR, BIT(irq)); >> + else if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) >> ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); >> else if (is_soc_or_above(jzgc->jzpc, ID_JZ4740)) >> ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); >> @@ -3754,7 +3778,9 @@ static int ingenic_gpio_irq_set_type(struct irq_data >> *irqd, unsigned int type) >> irq_set_handler_locked(irqd, handle_bad_irq); >> } >> >> - if ((type == IRQ_TYPE_EDGE_BOTH) && !is_soc_or_above(jzgc->jzpc, >> ID_X2000)) { >> + if (type == IRQ_TYPE_EDGE_BOTH && >> + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || >> + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- >>> jzpc, ID_X2000)))) { >> /* >> * The hardware does not support interrupts on both edges. >> The >> * best we can do is to set up a single-edge interrupt and >> then >> @@ -3849,16 +3875,35 @@ static inline void ingenic_shadow_config_pin(struct >> ingenic_pinctrl *jzpc, >> unsigned int pin, u8 reg, bool set) >> { >> unsigned int idx = pin % PINS_PER_GPIO_CHIP; >> + unsigned int offt = pin / PINS_PER_GPIO_CHIP; >> >> - regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + >> - (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx)); >> + if (set) >> + reg = REG_SET(reg); >> + else >> + reg = REG_CLEAR(reg); >> + >> + if (is_soc_or_above(jzpc, ID_X2600)) { >> + u32 target_reg = (offt * jzpc->info->reg_offset) + >> X2600_GPIO_SHADOW_OFFSET + reg; >> + >> + regmap_write(jzpc->map, target_reg, BIT(idx)); >> + } else { >> + regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + >> reg, BIT(idx)); >> + } >> } >> >> static inline void ingenic_shadow_config_pin_load(struct ingenic_pinctrl >> *jzpc, >> unsigned int pin) >> { >> - regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), >> - pin / PINS_PER_GPIO_CHIP); >> + unsigned int offt = pin / PINS_PER_GPIO_CHIP; >> + >> + if (is_soc_or_above(jzpc, ID_X2600)) { >> + u32 target_load_reg = (offt * jzpc->info->reg_offset) + >> X2600_GPIO_PAGLD; >> + >> + regmap_write(jzpc->map, target_load_reg, 1); >> + } else { >> + regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info- >>> reg_offset), >> + pin / PINS_PER_GPIO_CHIP); >> + } >> } >> >> static inline void jz4730_config_pin_function(struct ingenic_pinctrl *jzpc, ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support 2026-11-13 9:49 ` H. Nikolaus Schaller @ 2026-11-13 9:54 ` Paul Cercueil 2026-11-13 10:02 ` H. Nikolaus Schaller 0 siblings, 1 reply; 8+ messages in thread From: Paul Cercueil @ 2026-11-13 9:54 UTC (permalink / raw) To: H. Nikolaus Schaller Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski, linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel Le vendredi 13 novembre 2026 à 10:49 +0100, H. Nikolaus Schaller a écrit : > Hi Paul, > > > Am 13.11.2026 um 10:37 schrieb Paul Cercueil <paul@crapouillou.net>: > > > > Hi Nikolaus, > > > > Le vendredi 13 novembre 2026 à 09:14 +0100, H. Nikolaus Schaller a écrit : > > > Add the X2600 SoC ID and adapt the GPIO register access functions > > > to its register layout. > > > > > > Unlike earlier Ingenic SoCs, the X2600 uses a register bank > > > spacing of 0x1000 and provides separate shadow registers and > > > load registers for each GPIO port. It also uses a dedicated > > > register for clearing GPIO interrupt flags. > > > > > > Update the GPIO interrupt configuration to account for hardware > > > dual-edge detection on X1600, X2000 and X2600. These SoCs require > > > PAT1 to be set when dual-edge detection is enabled, while X1000 > > > and X1830 continue to use software emulation. > > > > So at the same time you're fixing X1600/X2000 and adding support for X2600. > > Looks to me like it should be splitted into two patches. > > Well, I have to look if it can be split. > > So far the driver for X1600/X2000 does not have dual-edge support by > hardware (programming the EDG bit). > > But registers and programming model are the same. Therefore it is more > or less a nice side-effect that x2600 adds functions to x1600/x2000. > > I.e. new code would be replacing some is_soc_or_above(jzgc->jzpc, ID_X2600) > with is_soc_or_above(jzgc->jzpc, ID_X1600) to fix it for them. > > Or otherwise we have to split full x2600 support into two patches. > > Is this worth a separate patch or should we leave it as a comment in > the commit message? My idea was that you'd first swap X1600/X1830, then add support for hardware dual-edge support if >= X1600, and finally add X2600 support. > > > The corrected interrupt configuration has been tested on X1600, > > > X2000, and X2600, including GPIO dual-edge interrupts by a > > > gpio-button. > > > > > > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > > > --- > > > drivers/pinctrl/pinctrl-ingenic.c | 71 +++++++++++++++++++++++++------ > > > 1 file changed, 58 insertions(+), 13 deletions(-) > > > > > > diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl- > > > ingenic.c > > > index a62532c49fb60..90c734c74d267 100644 > > > --- a/drivers/pinctrl/pinctrl-ingenic.c > > > +++ b/drivers/pinctrl/pinctrl-ingenic.c > > > @@ -70,6 +70,10 @@ > > > #define X2000_GPIO_SR 0xd0 > > > #define X2000_GPIO_SMT 0xe0 > > > > > > +#define X2600_GPIO_FLAG_CLR 0x58 /* write only */ > > > +#define X2600_GPIO_SHADOW_OFFSET 0x800 > > > +#define X2600_GPIO_PAGLD (X2600_GPIO_SHADOW_OFFSET + > > > 0xf0) > > > + > > > #define REG_SET(x) ((x) + 0x4) > > > #define REG_CLEAR(x) ((x) + 0x8) > > > > > > @@ -114,6 +118,7 @@ enum jz_version { > > > ID_X1830, > > > ID_X2000, > > > ID_X2100, > > > + ID_X2600, > > > }; > > > > > > struct ingenic_chip_info { > > > @@ -164,7 +169,8 @@ static const unsigned long enabled_socs = > > > IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | > > > IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | > > > IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | > > > - IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; > > > + IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100 | > > > + IS_ENABLED(CONFIG_MACH_X2600) << ID_X2600; > > > > > > static bool > > > is_soc_or_above(const struct ingenic_pinctrl *jzpc, enum jz_version > > > version) > > > @@ -3545,15 +3551,21 @@ static void ingenic_gpio_shadow_set_bit(struct > > > ingenic_gpio_chip *jzgc, > > > else > > > reg = REG_CLEAR(reg); > > > > > > - regmap_write(jzgc->jzpc->map, REG_PZ_BASE( > > > - jzgc->jzpc->info->reg_offset) + reg, BIT(offset)); > > > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > > > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > > > X2600_GPIO_SHADOW_OFFSET + reg, > > > + BIT(offset)); > > > + else > > > + regmap_write(jzgc->jzpc->map, REG_PZ_BASE(jzgc->jzpc->info- > > > > reg_offset) + reg, > > > + BIT(offset)); > > > } > > > > > > static void ingenic_gpio_shadow_set_bit_load(struct ingenic_gpio_chip > > > *jzgc) > > > { > > > - regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD( > > > - jzgc->jzpc->info->reg_offset), > > > - jzgc->gc.base / PINS_PER_GPIO_CHIP); > > > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > > > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > > > X2600_GPIO_PAGLD, 1); > > > + else > > > + regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD(jzgc->jzpc->info- > > > > reg_offset), > > > + jzgc->gc.base / PINS_PER_GPIO_CHIP); > > > } > > > > > > static void jz4730_gpio_set_bits(struct ingenic_gpio_chip *jzgc, > > > @@ -3618,6 +3630,12 @@ static void irq_set_type(struct ingenic_gpio_chip > > > *jzgc, > > > break; > > > } > > > > > > + if (type == IRQ_TYPE_EDGE_BOTH && > > > + (is_soc_or_above(jzgc->jzpc, ID_X2000) || > > > + (is_soc_or_above(jzgc->jzpc, ID_X1600) && > > > + !is_soc_or_above(jzgc->jzpc, ID_X1830)))) > > > > I remember you saying (in another patchset) that the X1830 was older than > > the > > X1600, if that's the case the IDs for X1600 and X1830 should be swapped. I > > believe this patch would then become much simpler. > > Indeed. So I can swap the ID's in V2. I just checked in the programming manuals and indeed it seems to be the case. Weird! I had no idea. Cheers, -Paul > > > + val2 = true; > > > + > > > if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) { > > > reg1 = JZ4770_GPIO_PAT1; > > > reg2 = JZ4770_GPIO_PAT0; > > > @@ -3640,6 +3658,9 @@ static void irq_set_type(struct ingenic_gpio_chip > > > *jzgc, > > > ingenic_gpio_shadow_set_bit(jzgc, reg2, offset, val1); > > > ingenic_gpio_shadow_set_bit(jzgc, reg1, offset, val2); > > > ingenic_gpio_shadow_set_bit_load(jzgc); > > > + > > > + if (is_soc_or_above(jzgc->jzpc, ID_X1600) && > > > !is_soc_or_above(jzgc->jzpc, ID_X1830)) > > > + ingenic_gpio_set_bit(jzgc, X2000_GPIO_EDG, offset, > > > val3); > > > } else { > > > ingenic_gpio_set_bit(jzgc, reg2, offset, val1); > > > ingenic_gpio_set_bit(jzgc, reg1, offset, val2); > > > @@ -3714,7 +3735,8 @@ static void ingenic_gpio_irq_ack(struct irq_data > > > *irqd) > > > bool high; > > > > > > if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) && > > > - !is_soc_or_above(jzgc->jzpc, ID_X2000)) { > > > + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || > > > + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- > > > > jzpc, ID_X2000)))) { > > > /* > > > * Switch to an interrupt for the opposite edge to the one > > > that > > > * triggered the interrupt being ACKed. > > > @@ -3726,7 +3748,9 @@ static void ingenic_gpio_irq_ack(struct irq_data > > > *irqd) > > > irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH); > > > } > > > > > > - if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) > > > + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) > > > + regmap_write(jzgc->jzpc->map, jzgc->reg_base + > > > X2600_GPIO_FLAG_CLR, BIT(irq)); > > > + else if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) > > > ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); > > > else if (is_soc_or_above(jzgc->jzpc, ID_JZ4740)) > > > ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); > > > @@ -3754,7 +3778,9 @@ static int ingenic_gpio_irq_set_type(struct irq_data > > > *irqd, unsigned int type) > > > irq_set_handler_locked(irqd, handle_bad_irq); > > > } > > > > > > - if ((type == IRQ_TYPE_EDGE_BOTH) && !is_soc_or_above(jzgc->jzpc, > > > ID_X2000)) { > > > + if (type == IRQ_TYPE_EDGE_BOTH && > > > + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || > > > + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- > > > > jzpc, ID_X2000)))) { > > > /* > > > * The hardware does not support interrupts on both edges. > > > The > > > * best we can do is to set up a single-edge interrupt and > > > then > > > @@ -3849,16 +3875,35 @@ static inline void > > > ingenic_shadow_config_pin(struct > > > ingenic_pinctrl *jzpc, > > > unsigned int pin, u8 reg, bool set) > > > { > > > unsigned int idx = pin % PINS_PER_GPIO_CHIP; > > > + unsigned int offt = pin / PINS_PER_GPIO_CHIP; > > > > > > - regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + > > > - (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx)); > > > + if (set) > > > + reg = REG_SET(reg); > > > + else > > > + reg = REG_CLEAR(reg); > > > + > > > + if (is_soc_or_above(jzpc, ID_X2600)) { > > > + u32 target_reg = (offt * jzpc->info->reg_offset) + > > > X2600_GPIO_SHADOW_OFFSET + reg; > > > + > > > + regmap_write(jzpc->map, target_reg, BIT(idx)); > > > + } else { > > > + regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + > > > reg, BIT(idx)); > > > + } > > > } > > > > > > static inline void ingenic_shadow_config_pin_load(struct ingenic_pinctrl > > > *jzpc, > > > unsigned int pin) > > > { > > > - regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), > > > - pin / PINS_PER_GPIO_CHIP); > > > + unsigned int offt = pin / PINS_PER_GPIO_CHIP; > > > + > > > + if (is_soc_or_above(jzpc, ID_X2600)) { > > > + u32 target_load_reg = (offt * jzpc->info->reg_offset) + > > > X2600_GPIO_PAGLD; > > > + > > > + regmap_write(jzpc->map, target_load_reg, 1); > > > + } else { > > > + regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info- > > > > reg_offset), > > > + pin / PINS_PER_GPIO_CHIP); > > > + } > > > } > > > > > > static inline void jz4730_config_pin_function(struct ingenic_pinctrl > > > *jzpc, > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support 2026-11-13 9:54 ` Paul Cercueil @ 2026-11-13 10:02 ` H. Nikolaus Schaller 0 siblings, 0 replies; 8+ messages in thread From: H. Nikolaus Schaller @ 2026-11-13 10:02 UTC (permalink / raw) To: Paul Cercueil Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski, linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel > Am 13.11.2026 um 10:54 schrieb Paul Cercueil <paul@crapouillou.net>: > > Le vendredi 13 novembre 2026 à 10:49 +0100, H. Nikolaus Schaller a écrit : >> Hi Paul, >> >>> Am 13.11.2026 um 10:37 schrieb Paul Cercueil <paul@crapouillou.net>: >>> >>> Hi Nikolaus, >>> >>> Le vendredi 13 novembre 2026 à 09:14 +0100, H. Nikolaus Schaller a écrit : >>>> Add the X2600 SoC ID and adapt the GPIO register access functions >>>> to its register layout. >>>> >>>> Unlike earlier Ingenic SoCs, the X2600 uses a register bank >>>> spacing of 0x1000 and provides separate shadow registers and >>>> load registers for each GPIO port. It also uses a dedicated >>>> register for clearing GPIO interrupt flags. >>>> >>>> Update the GPIO interrupt configuration to account for hardware >>>> dual-edge detection on X1600, X2000 and X2600. These SoCs require >>>> PAT1 to be set when dual-edge detection is enabled, while X1000 >>>> and X1830 continue to use software emulation. >>> >>> So at the same time you're fixing X1600/X2000 and adding support for X2600. >>> Looks to me like it should be splitted into two patches. >> >> Well, I have to look if it can be split. >> >> So far the driver for X1600/X2000 does not have dual-edge support by >> hardware (programming the EDG bit). >> >> But registers and programming model are the same. Therefore it is more >> or less a nice side-effect that x2600 adds functions to x1600/x2000. >> >> I.e. new code would be replacing some is_soc_or_above(jzgc->jzpc, ID_X2600) >> with is_soc_or_above(jzgc->jzpc, ID_X1600) to fix it for them. >> >> Or otherwise we have to split full x2600 support into two patches. >> >> Is this worth a separate patch or should we leave it as a comment in >> the commit message? > > My idea was that you'd first swap X1600/X1830, then add support for hardware > dual-edge support if >= X1600, and finally add X2600 support. Ah, ok. Fine with that. Will do for V2. BR and thanks, Nikolaus > >>>> The corrected interrupt configuration has been tested on X1600, >>>> X2000, and X2600, including GPIO dual-edge interrupts by a >>>> gpio-button. >>>> >>>> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> >>>> --- >>>> drivers/pinctrl/pinctrl-ingenic.c | 71 +++++++++++++++++++++++++------ >>>> 1 file changed, 58 insertions(+), 13 deletions(-) >>>> >>>> diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl- >>>> ingenic.c >>>> index a62532c49fb60..90c734c74d267 100644 >>>> --- a/drivers/pinctrl/pinctrl-ingenic.c >>>> +++ b/drivers/pinctrl/pinctrl-ingenic.c >>>> @@ -70,6 +70,10 @@ >>>> #define X2000_GPIO_SR 0xd0 >>>> #define X2000_GPIO_SMT 0xe0 >>>> >>>> +#define X2600_GPIO_FLAG_CLR 0x58 /* write only */ >>>> +#define X2600_GPIO_SHADOW_OFFSET 0x800 >>>> +#define X2600_GPIO_PAGLD (X2600_GPIO_SHADOW_OFFSET + >>>> 0xf0) >>>> + >>>> #define REG_SET(x) ((x) + 0x4) >>>> #define REG_CLEAR(x) ((x) + 0x8) >>>> >>>> @@ -114,6 +118,7 @@ enum jz_version { >>>> ID_X1830, >>>> ID_X2000, >>>> ID_X2100, >>>> + ID_X2600, >>>> }; >>>> >>>> struct ingenic_chip_info { >>>> @@ -164,7 +169,8 @@ static const unsigned long enabled_socs = >>>> IS_ENABLED(CONFIG_MACH_X1600) << ID_X1600 | >>>> IS_ENABLED(CONFIG_MACH_X1830) << ID_X1830 | >>>> IS_ENABLED(CONFIG_MACH_X2000) << ID_X2000 | >>>> - IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100; >>>> + IS_ENABLED(CONFIG_MACH_X2100) << ID_X2100 | >>>> + IS_ENABLED(CONFIG_MACH_X2600) << ID_X2600; >>>> >>>> static bool >>>> is_soc_or_above(const struct ingenic_pinctrl *jzpc, enum jz_version >>>> version) >>>> @@ -3545,15 +3551,21 @@ static void ingenic_gpio_shadow_set_bit(struct >>>> ingenic_gpio_chip *jzgc, >>>> else >>>> reg = REG_CLEAR(reg); >>>> >>>> - regmap_write(jzgc->jzpc->map, REG_PZ_BASE( >>>> - jzgc->jzpc->info->reg_offset) + reg, BIT(offset)); >>>> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >>>> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >>>> X2600_GPIO_SHADOW_OFFSET + reg, >>>> + BIT(offset)); >>>> + else >>>> + regmap_write(jzgc->jzpc->map, REG_PZ_BASE(jzgc->jzpc->info- >>>>> reg_offset) + reg, >>>> + BIT(offset)); >>>> } >>>> >>>> static void ingenic_gpio_shadow_set_bit_load(struct ingenic_gpio_chip >>>> *jzgc) >>>> { >>>> - regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD( >>>> - jzgc->jzpc->info->reg_offset), >>>> - jzgc->gc.base / PINS_PER_GPIO_CHIP); >>>> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >>>> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >>>> X2600_GPIO_PAGLD, 1); >>>> + else >>>> + regmap_write(jzgc->jzpc->map, REG_PZ_GID2LD(jzgc->jzpc->info- >>>>> reg_offset), >>>> + jzgc->gc.base / PINS_PER_GPIO_CHIP); >>>> } >>>> >>>> static void jz4730_gpio_set_bits(struct ingenic_gpio_chip *jzgc, >>>> @@ -3618,6 +3630,12 @@ static void irq_set_type(struct ingenic_gpio_chip >>>> *jzgc, >>>> break; >>>> } >>>> >>>> + if (type == IRQ_TYPE_EDGE_BOTH && >>>> + (is_soc_or_above(jzgc->jzpc, ID_X2000) || >>>> + (is_soc_or_above(jzgc->jzpc, ID_X1600) && >>>> + !is_soc_or_above(jzgc->jzpc, ID_X1830)))) >>> >>> I remember you saying (in another patchset) that the X1830 was older than >>> the >>> X1600, if that's the case the IDs for X1600 and X1830 should be swapped. I >>> believe this patch would then become much simpler. >> >> Indeed. So I can swap the ID's in V2. > > I just checked in the programming manuals and indeed it seems to be the case. > Weird! I had no idea. > > Cheers, > -Paul > >>>> + val2 = true; >>>> + >>>> if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) { >>>> reg1 = JZ4770_GPIO_PAT1; >>>> reg2 = JZ4770_GPIO_PAT0; >>>> @@ -3640,6 +3658,9 @@ static void irq_set_type(struct ingenic_gpio_chip >>>> *jzgc, >>>> ingenic_gpio_shadow_set_bit(jzgc, reg2, offset, val1); >>>> ingenic_gpio_shadow_set_bit(jzgc, reg1, offset, val2); >>>> ingenic_gpio_shadow_set_bit_load(jzgc); >>>> + >>>> + if (is_soc_or_above(jzgc->jzpc, ID_X1600) && >>>> !is_soc_or_above(jzgc->jzpc, ID_X1830)) >>>> + ingenic_gpio_set_bit(jzgc, X2000_GPIO_EDG, offset, >>>> val3); >>>> } else { >>>> ingenic_gpio_set_bit(jzgc, reg2, offset, val1); >>>> ingenic_gpio_set_bit(jzgc, reg1, offset, val2); >>>> @@ -3714,7 +3735,8 @@ static void ingenic_gpio_irq_ack(struct irq_data >>>> *irqd) >>>> bool high; >>>> >>>> if ((irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) && >>>> - !is_soc_or_above(jzgc->jzpc, ID_X2000)) { >>>> + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || >>>> + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- >>>>> jzpc, ID_X2000)))) { >>>> /* >>>> * Switch to an interrupt for the opposite edge to the one >>>> that >>>> * triggered the interrupt being ACKed. >>>> @@ -3726,7 +3748,9 @@ static void ingenic_gpio_irq_ack(struct irq_data >>>> *irqd) >>>> irq_set_type(jzgc, irq, IRQ_TYPE_LEVEL_HIGH); >>>> } >>>> >>>> - if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) >>>> + if (is_soc_or_above(jzgc->jzpc, ID_X2600)) >>>> + regmap_write(jzgc->jzpc->map, jzgc->reg_base + >>>> X2600_GPIO_FLAG_CLR, BIT(irq)); >>>> + else if (is_soc_or_above(jzgc->jzpc, ID_JZ4770)) >>>> ingenic_gpio_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); >>>> else if (is_soc_or_above(jzgc->jzpc, ID_JZ4740)) >>>> ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); >>>> @@ -3754,7 +3778,9 @@ static int ingenic_gpio_irq_set_type(struct irq_data >>>> *irqd, unsigned int type) >>>> irq_set_handler_locked(irqd, handle_bad_irq); >>>> } >>>> >>>> - if ((type == IRQ_TYPE_EDGE_BOTH) && !is_soc_or_above(jzgc->jzpc, >>>> ID_X2000)) { >>>> + if (type == IRQ_TYPE_EDGE_BOTH && >>>> + (!is_soc_or_above(jzgc->jzpc, ID_X1600) || >>>> + (is_soc_or_above(jzgc->jzpc, ID_X1830) && !is_soc_or_above(jzgc- >>>>> jzpc, ID_X2000)))) { >>>> /* >>>> * The hardware does not support interrupts on both edges. >>>> The >>>> * best we can do is to set up a single-edge interrupt and >>>> then >>>> @@ -3849,16 +3875,35 @@ static inline void >>>> ingenic_shadow_config_pin(struct >>>> ingenic_pinctrl *jzpc, >>>> unsigned int pin, u8 reg, bool set) >>>> { >>>> unsigned int idx = pin % PINS_PER_GPIO_CHIP; >>>> + unsigned int offt = pin / PINS_PER_GPIO_CHIP; >>>> >>>> - regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + >>>> - (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx)); >>>> + if (set) >>>> + reg = REG_SET(reg); >>>> + else >>>> + reg = REG_CLEAR(reg); >>>> + >>>> + if (is_soc_or_above(jzpc, ID_X2600)) { >>>> + u32 target_reg = (offt * jzpc->info->reg_offset) + >>>> X2600_GPIO_SHADOW_OFFSET + reg; >>>> + >>>> + regmap_write(jzpc->map, target_reg, BIT(idx)); >>>> + } else { >>>> + regmap_write(jzpc->map, REG_PZ_BASE(jzpc->info->reg_offset) + >>>> reg, BIT(idx)); >>>> + } >>>> } >>>> >>>> static inline void ingenic_shadow_config_pin_load(struct ingenic_pinctrl >>>> *jzpc, >>>> unsigned int pin) >>>> { >>>> - regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info->reg_offset), >>>> - pin / PINS_PER_GPIO_CHIP); >>>> + unsigned int offt = pin / PINS_PER_GPIO_CHIP; >>>> + >>>> + if (is_soc_or_above(jzpc, ID_X2600)) { >>>> + u32 target_load_reg = (offt * jzpc->info->reg_offset) + >>>> X2600_GPIO_PAGLD; >>>> + >>>> + regmap_write(jzpc->map, target_load_reg, 1); >>>> + } else { >>>> + regmap_write(jzpc->map, REG_PZ_GID2LD(jzpc->info- >>>>> reg_offset), >>>> + pin / PINS_PER_GPIO_CHIP); >>>> + } >>>> } >>>> >>>> static inline void jz4730_config_pin_function(struct ingenic_pinctrl >>>> *jzpc, ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/3] pinctrl: ingenic: Add X2600 pin groups and functions 2026-11-13 8:14 [PATCH 0/3] pinctrl: ingenic: Add X2600 support H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 1/3] dt-bindings: " H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support H. Nikolaus Schaller @ 2026-11-13 8:14 ` H. Nikolaus Schaller 2 siblings, 0 replies; 8+ messages in thread From: H. Nikolaus Schaller @ 2026-11-13 8:14 UTC (permalink / raw) To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, Bartosz Golaszewski Cc: linux-gpio, devicetree, linux-kernel, linux-mips, letux-kernel, H. Nikolaus Schaller Add the pin groups, mux functions and GPIO configuration data for the Lumissil X2600 SoC. The X2600 provides five GPIO ports with configurable pull-up and pull-down support on selected pins. Define the register access ranges for the X2600 GPIO controller, which uses a bank spacing of 0x1000 instead of 0x100 and includes additional registers beyond the first 0x100 bytes of each bank. Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- drivers/pinctrl/pinctrl-ingenic.c | 502 ++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 90c734c74d267..a0bdf5eb6a672 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -3517,6 +3517,503 @@ static const struct ingenic_chip_info x2100_chip_info = { .access_table = &x2000_access_table, }; +static const u32 x2600_pull_ups[5] = { + 0x000007ff, 0xffffffff, 0x7ffbfff, 0x0000ffff, 0x000ffffe, +}; + +static const u32 x2600_pull_downs[5] = { + 0x000007ff, 0xffffffff, 0x01ffff1, 0x0001e000, 0x000fffff, +}; + +static int x2600_can0_pins[] = { 0x47, 0x48, }; +static int x2600_can1_pins[] = { 0x49, 0x4a, }; + +static int x2600_cim_pins[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static int x2600_clk_pins[] = { 0x82, }; + +static int x2600_dmic_pins[] = { 0x44, 0x45, 0x46, }; + +static int x2600_i2c0_c_pins[] = { 0x40, 0x41, }; +static int x2600_i2c0_d_pins[] = { 0x64, 0x63, }; + +static int x2600_i2c1_b_pins[] = { 0x20, 0x21, }; +static int x2600_i2c1_c_pins[] = { 0x42, 0x43, }; + +static int x2600_i2c2_b_pins[] = { 0x23, 0x22, }; +static int x2600_i2c2_c_pins[] = { 0x53, 0x54, }; +static int x2600_i2c3_c_pins[] = { 0x55, 0x56, }; +static int x2600_i2c3_e_pins[] = { 0x85, 0x86, }; + +static int x2600_i2s_clk_rx_pins[] = { 0x4f, }; /* PC15 */ +static int x2600_i2s_sysclk_pins[] = { 0x50, }; /* PC16 */ +static int x2600_i2s_clk_tx_pins[] = { 0x51, }; /* PC17 */ +static int x2600_i2s_data_pins[] = { 0x52, 0x53, }; /* PC18, PC19 */ + +static int x2600_lcd_16bit_pins[] = { + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, +}; + +static int x2600_lcd_18bit_pins[] = { 0x34, 0x35, }; + +static int x2600_lcd_24bit_pins[] = { + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, +}; + +static int x2600_lcd_sync_pins[] = { 0x3c, 0x3d, 0x3e, 0x3f, }; + +static int x2600_lcd_none_pins[] = { }; + +static int x2600_mac_pins[] = { + 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, +}; + +static int x2600_msc0_1bit_pins[] = { 0x60, 0x61, 0x62, }; +static int x2600_msc0_4bit_pins[] = { 0x63, 0x64, 0x65, }; +static int x2600_msc0_8bit_pins[] = { 0x81, 0x82, 0x83, 0x84, }; + +static int x2600_msc1_1bit_c_pins[] = { 0x59, 0x5a, 0x5b, }; +static int x2600_msc1_4bit_c_pins[] = { 0x5c, 0x5d, 0x5e, }; + +static int x2600_msc1_1bit_d_pins[] = { 0x66, 0x67, 0x68, }; +static int x2600_msc1_4bit_d_pins[] = { 0x69, 0x6a, 0x6b, }; + +static int x2600_otg_pins[] = { 0x81, }; + +static int x2600_pcm_pins[] = { 0x40, 0x41, 0x42, 0x43, }; /* PC0-PC3 (Func3) */ + +static int x2600_pwm0_pins[] = { 0x2c, }; /* PB12 (Func2) */ +static int x2600_pwm1_pins[] = { 0x2d, }; /* PB13 (Func2) */ +static int x2600_pwm2_pins[] = { 0x2e, }; /* PB14 (Func2) */ +static int x2600_pwm3_pins[] = { 0x2f, }; /* PB15 (Func2) */ +static int x2600_pwm4_pins[] = { 0x30, }; /* PB16 (Func2) */ +static int x2600_pwm5_pins[] = { 0x31, }; /* PB17 (Func2) */ +static int x2600_pwm6_pins[] = { 0x32, }; /* PB18 (Func2) */ +static int x2600_pwm7_pins[] = { 0x33, }; /* PB19 (Func2) */ +static int x2600_pwm8_pins[] = { 0x47, }; /* PC07 (Func0) */ +static int x2600_pwm9_pins[] = { 0x48, }; /* PC08 (Func0) */ +static int x2600_pwm10_c_pins[] = { 0x49, }; /* PC09 (Func0) */ +static int x2600_pwm10_e_pins[] = { 0x82, }; /* PE02 (Func2) */ +static int x2600_pwm11_pins[] = { 0x4a, }; /* PC10 (Func0) */ +static int x2600_pwm12_pins[] = { 0x4b, }; /* PC11 (Func0) */ +static int x2600_pwm13_pins[] = { 0x4c, }; /* PC12 (Func0) */ +static int x2600_pwm14_pins[] = { 0x4d, }; /* PC13 (Func0) */ +static int x2600_pwm15_pins[] = { 0x4e, }; /* PC14 (Func0) */ +static int x2600_pwm_trig_c_pins[] = { 0x54, }; /* PC20 (Func1) */ +static int x2600_pwm_trig_d_pins[] = { 0x6c, }; /* PD12 (Func1) */ + +static int x2600_sfc_d0_pins[] = { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, }; +static int x2600_sfc_d6_pins[] = { 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, }; + +static int x2600_slcd_8bit_pins[] = { + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, +}; + +static int x2600_slcd_16bit_pins[] = { + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, +}; + +static int x2600_slcd_ctrl_pins[] = { + 0x34, 0x3c, 0x3d, 0x3e, 0x3f, +}; + +static int x2600_ssi0_dt_b_pins[] = { 0x22, }; +static int x2600_ssi0_dr_b_pins[] = { 0x21, }; +static int x2600_ssi0_clk_b_pins[] = { 0x23, }; +static int x2600_ssi0_ce0_b_pins[] = { 0x20, }; + +static int x2600_ssi0_dt_d_pins[] = { 0x61, }; +static int x2600_ssi0_dr_d_pins[] = { 0x62, }; +static int x2600_ssi0_clk_d_pins[] = { 0x60, }; +static int x2600_ssi0_ce0_d_pins[] = { 0x65, }; + +static int x2600_ssi1_dt_c15_pins[] = { 0x50, }; +static int x2600_ssi1_dr_c15_pins[] = { 0x51, }; +static int x2600_ssi1_clk_c15_pins[] = { 0x4f, }; +static int x2600_ssi1_ce0_c15_pins[] = { 0x52, }; + +static int x2600_ssi1_dt_c25_pins[] = { 0x5a, }; +static int x2600_ssi1_dr_c25_pins[] = { 0x5b, }; +static int x2600_ssi1_clk_c25_pins[] = { 0x59, }; +static int x2600_ssi1_ce0_c25_pins[] = { 0x5e, }; + +static int x2600_ssi_slv_dt_pins[] = { 0x3d, }; /* PB29 (Func2) */ +static int x2600_ssi_slv_dr_pins[] = { 0x3e, }; /* PB30 (Func2) */ +static int x2600_ssi_slv_clk_pins[] = { 0x3c, }; /* PB28 (Func2) */ +static int x2600_ssi_slv_ce0_pins[] = { 0x3f, }; /* PB31 (Func2) */ + +static int x2600_tcu0_in0_pins[] = { 0x34, }; /* PB20 (Func2) */ +static int x2600_tcu0_in1_pins[] = { 0x35, }; /* PB21 (Func2) */ +static int x2600_tcu1_in0_pins[] = { 0x36, }; /* PB22 (Func2) */ +static int x2600_tcu1_in1_pins[] = { 0x37, }; /* PB23 (Func2) */ +static int x2600_tcu2_in0_pins[] = { 0x38, }; /* PB24 (Func2) */ +static int x2600_tcu2_in1_pins[] = { 0x39, }; /* PB25 (Func2) */ +static int x2600_tcu3_in0_pins[] = { 0x3a, }; /* PB26 (Func2) */ +static int x2600_tcu3_in1_pins[] = { 0x3b, }; /* PB27 (Func2) */ + +static int x2600_tcu4_in0_pins[] = { 0x47, }; /* PC07 (Func1) */ +static int x2600_tcu4_in1_pins[] = { 0x48, }; /* PC08 (Func1) */ +static int x2600_tcu5_in0_pins[] = { 0x49, }; /* PC09 (Func1) */ +static int x2600_tcu5_in1_pins[] = { 0x4a, }; /* PC10 (Func1) */ +static int x2600_tcu6_in0_pins[] = { 0x4b, }; /* PC11 (Func1) */ +static int x2600_tcu6_in1_pins[] = { 0x4c, }; /* PC12 (Func1) */ +static int x2600_tcu7_in0_pins[] = { 0x4d, }; /* PC13 (Func1) */ +static int x2600_tcu7_in1_pins[] = { 0x4e, }; /* PC14 (Func1) */ + +static int x2600_uart0_data_c_pins[] = { 0x57, 0x58, }; +static int x2600_uart0_hwflow_c_pins[] = { 0x55, 0x56, }; +static int x2600_uart0_data_e_pins[] = { 0x89, 0x8a, }; +static int x2600_uart0_hwflow_e_pins[] = { 0x8b, 0x8c, }; + +static int x2600_uart1_data_b_pins[] = { 0x20, 0x21, }; +static int x2600_uart1_data_c_pins[] = { 0x42, 0x43, }; +static int x2600_uart1_hwflow_pins[] = { 0x44, 0x45, }; + +static int x2600_uart2_data_pins[] = { 0x6d, 0x6c, }; + +static int x2600_uart3_data_b_pins[] = { 0x37, 0x36, }; +static int x2600_uart3_data_c_pins[] = { 0x50, 0x4f, }; + +static int x2600_uart4_data_b_pins[] = { 0x38, 0x39, }; +static int x2600_uart4_data_c_pins[] = { 0x51, 0x52, }; +static int x2600_uart5_data_b_pins[] = { 0x3a, 0x3b, }; +static int x2600_uart5_data_c_pins[] = { 0x47, 0x48, }; +static int x2600_uart6_data_c_pins[] = { 0x40, 0x41, }; +static int x2600_uart7_data_c_pins[] = { 0x44, 0x45, }; +static int x2600_uart7_data_e_pins[] = { 0x83, 0x84, }; + +static int x2600_wait_pins[] = { 0x6b, }; + +static const struct group_desc x2600_groups[] = { + /* CAN (Controller Area Network) */ + INGENIC_PIN_GROUP("can0-data", x2600_can0, 2), + INGENIC_PIN_GROUP("can1-data", x2600_can1, 2), + + /* CIM (Camera) */ + INGENIC_PIN_GROUP("cim-data", x2600_cim, 0), + + /* EXCLK (externel clock output) */ + INGENIC_PIN_GROUP("ex-clk", x2600_clk, 1), + + /* DMIC */ + INGENIC_PIN_GROUP("dmic-data", x2600_dmic, 0), + + /* I2Cs */ + INGENIC_PIN_GROUP("i2c0-data-c", x2600_i2c0_c, 1), + INGENIC_PIN_GROUP("i2c0-data-d", x2600_i2c0_d, 2), + INGENIC_PIN_GROUP("i2c1-data-b", x2600_i2c1_b, 3), + INGENIC_PIN_GROUP("i2c1-data-c", x2600_i2c1_c, 1), + INGENIC_PIN_GROUP("i2c2-data-b", x2600_i2c2_b, 3), + INGENIC_PIN_GROUP("i2c2-data-c", x2600_i2c2_c, 2), + INGENIC_PIN_GROUP("i2c3-data-c", x2600_i2c3_c, 2), + INGENIC_PIN_GROUP("i2c3-data-e", x2600_i2c3_e, 1), + + /* I2S (Audio) & PCM */ + INGENIC_PIN_GROUP("i2s-clk-rx", x2600_i2s_clk_rx, 1), + INGENIC_PIN_GROUP("i2s-sysclk", x2600_i2s_sysclk, 1), + INGENIC_PIN_GROUP("i2s-clk-tx", x2600_i2s_clk_tx, 1), + INGENIC_PIN_GROUP("i2s-data", x2600_i2s_data, 1), + INGENIC_PIN_GROUP("pcm", x2600_pcm, 3), + + /* LCD & SLCD */ + INGENIC_PIN_GROUP("lcd-16bit", x2600_lcd_16bit, 0), + INGENIC_PIN_GROUP("lcd-18bit", x2600_lcd_18bit, 0), + INGENIC_PIN_GROUP("lcd-24bit", x2600_lcd_24bit, 0), + INGENIC_PIN_GROUP("lcd-sync", x2600_lcd_sync, 0), + INGENIC_PIN_GROUP("lcd-none", x2600_lcd_none, 1), + INGENIC_PIN_GROUP("slcd-8bit", x2600_slcd_8bit, 1), + INGENIC_PIN_GROUP("slcd-16bit", x2600_slcd_16bit, 1), + INGENIC_PIN_GROUP("slcd-ctrl", x2600_slcd_ctrl, 1), + + /* MAC (Ethernet) */ + INGENIC_PIN_GROUP("mac", x2600_mac, 0), + + /* MMCs (MSC) */ + INGENIC_PIN_GROUP("mmc0-1bit", x2600_msc0_1bit, 0), + INGENIC_PIN_GROUP("mmc0-4bit", x2600_msc0_4bit, 0), + INGENIC_PIN_GROUP("mmc0-8bit", x2600_msc0_8bit, 0), + INGENIC_PIN_GROUP("mmc1-1bit-c", x2600_msc1_1bit_c, 0), + INGENIC_PIN_GROUP("mmc1-4bit-c", x2600_msc1_4bit_c, 0), + INGENIC_PIN_GROUP("mmc1-1bit-d", x2600_msc1_1bit_d, 1), + INGENIC_PIN_GROUP("mmc1-4bit-d", x2600_msc1_4bit_d, 1), + + /* OTG (Vbus driver) */ + INGENIC_PIN_GROUP("otg-vbus", x2600_otg, 1), + + /* PWMs */ + INGENIC_PIN_GROUP("pwm0", x2600_pwm0, 2), + INGENIC_PIN_GROUP("pwm1", x2600_pwm1, 2), + INGENIC_PIN_GROUP("pwm2", x2600_pwm2, 2), + INGENIC_PIN_GROUP("pwm3", x2600_pwm3, 2), + INGENIC_PIN_GROUP("pwm4", x2600_pwm4, 2), + INGENIC_PIN_GROUP("pwm5", x2600_pwm5, 2), + INGENIC_PIN_GROUP("pwm6", x2600_pwm6, 2), + INGENIC_PIN_GROUP("pwm7", x2600_pwm7, 2), + INGENIC_PIN_GROUP("pwm8", x2600_pwm8, 0), + INGENIC_PIN_GROUP("pwm9", x2600_pwm9, 0), + INGENIC_PIN_GROUP("pwm10-c", x2600_pwm10_c, 0), + INGENIC_PIN_GROUP("pwm10-e", x2600_pwm10_e, 2), + INGENIC_PIN_GROUP("pwm11", x2600_pwm11, 0), + INGENIC_PIN_GROUP("pwm12", x2600_pwm12, 0), + INGENIC_PIN_GROUP("pwm13", x2600_pwm13, 0), + INGENIC_PIN_GROUP("pwm14", x2600_pwm14, 0), + INGENIC_PIN_GROUP("pwm15", x2600_pwm15, 0), + INGENIC_PIN_GROUP("pwm-trig-c", x2600_pwm_trig_c, 1), + INGENIC_PIN_GROUP("pwm-trig-d", x2600_pwm_trig_d, 1), + + /* SFC (Serial Flash Controller) */ + INGENIC_PIN_GROUP("sfc-d0", x2600_sfc_d0, 1), + INGENIC_PIN_GROUP("sfc-d6", x2600_sfc_d6, 0), + + /* SSIs (SPI) */ + INGENIC_PIN_GROUP("ssi0-dt-b", x2600_ssi0_dt_b, 0), + INGENIC_PIN_GROUP("ssi0-dr-b", x2600_ssi0_dr_b, 0), + INGENIC_PIN_GROUP("ssi0-clk-b", x2600_ssi0_clk_b, 0), + INGENIC_PIN_GROUP("ssi0-ce0-b", x2600_ssi0_ce0_b, 0), + INGENIC_PIN_GROUP("ssi0-dt-d", x2600_ssi0_dt_d, 2), + INGENIC_PIN_GROUP("ssi0-dr-d", x2600_ssi0_dr_d, 2), + INGENIC_PIN_GROUP("ssi0-clk-d", x2600_ssi0_clk_d, 2), + INGENIC_PIN_GROUP("ssi0-ce0-d", x2600_ssi0_ce0_d, 2), + INGENIC_PIN_GROUP("ssi1-dt-c15", x2600_ssi1_dt_c15, 2), + INGENIC_PIN_GROUP("ssi1-dr-c15", x2600_ssi1_dr_c15, 2), + INGENIC_PIN_GROUP("ssi1-clk-c15", x2600_ssi1_clk_c15, 2), + INGENIC_PIN_GROUP("ssi1-ce0-c15", x2600_ssi1_ce0_c15, 2), + INGENIC_PIN_GROUP("ssi1-dt-c25", x2600_ssi1_dt_c25, 1), + INGENIC_PIN_GROUP("ssi1-dr-c25", x2600_ssi1_dr_c25, 1), + INGENIC_PIN_GROUP("ssi1-clk-c25", x2600_ssi1_clk_c25, 1), + INGENIC_PIN_GROUP("ssi1-ce0-c25", x2600_ssi1_ce0_c25, 1), + INGENIC_PIN_GROUP("ssi-slv-dt-b", x2600_ssi_slv_dt, 2), + INGENIC_PIN_GROUP("ssi-slv-dr-b", x2600_ssi_slv_dr, 2), + INGENIC_PIN_GROUP("ssi-slv-clk-b", x2600_ssi_slv_clk, 2), + INGENIC_PIN_GROUP("ssi-slv-ce0-b", x2600_ssi_slv_ce0, 2), + + /* TCUs (Timer & Counter Units) */ + INGENIC_PIN_GROUP("tcu0_in0", x2600_tcu0_in0, 2), + INGENIC_PIN_GROUP("tcu0_in1", x2600_tcu0_in1, 2), + INGENIC_PIN_GROUP("tcu1_in0", x2600_tcu1_in0, 2), + INGENIC_PIN_GROUP("tcu1_in1", x2600_tcu1_in1, 2), + INGENIC_PIN_GROUP("tcu2_in0", x2600_tcu2_in0, 2), + INGENIC_PIN_GROUP("tcu2_in1", x2600_tcu2_in1, 2), + INGENIC_PIN_GROUP("tcu3_in0", x2600_tcu3_in0, 2), + INGENIC_PIN_GROUP("tcu3_in1", x2600_tcu3_in1, 2), + INGENIC_PIN_GROUP("tcu4_in0", x2600_tcu4_in0, 1), + INGENIC_PIN_GROUP("tcu4_in1", x2600_tcu4_in1, 1), + INGENIC_PIN_GROUP("tcu5_in0", x2600_tcu5_in0, 1), + INGENIC_PIN_GROUP("tcu5_in1", x2600_tcu5_in1, 1), + INGENIC_PIN_GROUP("tcu6_in0", x2600_tcu6_in0, 1), + INGENIC_PIN_GROUP("tcu6_in1", x2600_tcu6_in1, 1), + INGENIC_PIN_GROUP("tcu7_in0", x2600_tcu7_in0, 1), + INGENIC_PIN_GROUP("tcu7_in1", x2600_tcu7_in1, 1), + + /* UARTs */ + INGENIC_PIN_GROUP("uart0-data-c", x2600_uart0_data_c, 1), + INGENIC_PIN_GROUP("uart0-hwflow-c", x2600_uart0_hwflow_c, 1), + INGENIC_PIN_GROUP("uart0-data-e", x2600_uart0_data_e, 1), + INGENIC_PIN_GROUP("uart0-hwflow-e", x2600_uart0_hwflow_e, 1), + INGENIC_PIN_GROUP("uart1-data-b", x2600_uart1_data_b, 1), + INGENIC_PIN_GROUP("uart1-data-c", x2600_uart1_data_c, 1), + INGENIC_PIN_GROUP("uart1-hwflow", x2600_uart1_hwflow, 2), + INGENIC_PIN_GROUP("uart2-data", x2600_uart2_data, 1), + INGENIC_PIN_GROUP("uart3-data-b", x2600_uart3_data_b, 1), + INGENIC_PIN_GROUP("uart3-data-c", x2600_uart3_data_c, 3), + INGENIC_PIN_GROUP("uart4-data-b", x2600_uart4_data_b, 2), + INGENIC_PIN_GROUP("uart4-data-c", x2600_uart4_data_c, 3), + INGENIC_PIN_GROUP("uart5-data-b", x2600_uart5_data_b, 2), + INGENIC_PIN_GROUP("uart5-data-c", x2600_uart5_data_c, 3), + INGENIC_PIN_GROUP("uart6-data-c", x2600_uart6_data_c, 2), + INGENIC_PIN_GROUP("uart7-data-c", x2600_uart7_data_c, 1), + INGENIC_PIN_GROUP("uart7-data-e", x2600_uart7_data_e, 1), + + /* WAIT */ + INGENIC_PIN_GROUP("wait", x2600_wait, 3), +}; + +static const char * const x2600_can0_groups[] = { "can0-data", }; +static const char * const x2600_can1_groups[] = { "can1-data", }; + +static const char * const x2600_cim_groups[] = { "cim-data", }; + +static const char * const x2600_clk_groups[] = { "ex-clk", }; + +static const char * const x2600_dmic_groups[] = { "dmic-data", }; + +static const char * const x2600_lcd_groups[] = { + "lcd-16bit", "lcd-18bit", "lcd-24bit", "lcd-sync", "lcd-none", +}; + +static const char * const x2600_i2c0_groups[] = { "i2c0-data-c", "i2c0-data-d", }; +static const char * const x2600_i2c1_groups[] = { "i2c1-data-b", "i2c1-data-c", }; +static const char * const x2600_i2c2_groups[] = { "i2c2-data-b", "i2c2-data-c", }; +static const char * const x2600_i2c3_groups[] = { "i2c3-data-c", "i2c3-data-e", }; + +static const char * const x2600_i2s_groups[] = { + "i2s-data", "i2s-clk-rx", "i2s-clk-tx", "i2s-sysclk", +}; + +static const char * const x2600_mac_groups[] = { "mac", }; + +static const char * const x2600_msc0_groups[] = { "mmc0-1bit", "mmc0-4bit", "mmc0-8bit", }; + +static const char * const x2600_msc1_groups[] = { + "mmc1-1bit-c", "mmc1-4bit-c", "mmc1-1bit-d", "mmc1-4bit-d", +}; + +static const char * const x2600_otg_groups[] = { "otg-vbus", }; + +static const char * const x2600_pwm0_groups[] = { "pwm0", }; +static const char * const x2600_pwm1_groups[] = { "pwm1", }; +static const char * const x2600_pwm2_groups[] = { "pwm2", }; +static const char * const x2600_pwm3_groups[] = { "pwm3", }; +static const char * const x2600_pwm4_groups[] = { "pwm4", }; +static const char * const x2600_pwm5_groups[] = { "pwm5", }; +static const char * const x2600_pwm6_groups[] = { "pwm6", }; +static const char * const x2600_pwm7_groups[] = { "pwm7", }; +static const char * const x2600_pwm8_groups[] = { "pwm8", }; +static const char * const x2600_pwm9_groups[] = { "pwm9", }; +static const char * const x2600_pwm10_groups[] = { "pwm10-c", "pwm10-e", }; + +static const char * const x2600_sfc_groups[] = { "sfc-d0", "sfc-d6", }; + +static const char * const x2600_slcd_groups[] = { "slcd-8bit", "slcd-16bit", "slcd-ctrl", }; + +static const char * const x2600_ssi0_groups[] = { + "ssi0-dt-b", "ssi0-dr-b", "ssi0-clk-b", "ssi0-ce0-b", + "ssi0-dt-d", "ssi0-dr-d", "ssi0-clk-d", "ssi0-ce0-d", +}; + +static const char * const x2600_ssi1_groups[] = { + "ssi1-dt-c15", "ssi1-dr-c15", "ssi1-clk-c15", "ssi1-ce0-c15", + "ssi1-dt-c25", "ssi1-dr-c25", "ssi1-clk-c25", "ssi1-ce0-c25", +}; + +static const char * const x2600_ssi_slv_groups[] = { + "ssi-slv-dt-b", "ssi-slv-dr-b", "ssi-slv-clk-b", "ssi-slv-ce0-b", +}; + +static const char * const x2600_tcu_groups[] = { + "tcu0_in0", "tcu0_in1", + "tcu1_in0", "tcu1_in1", + "tcu2_in0", "tcu2_in1", + "tcu3_in0", "tcu3_in1", + "tcu4_in0", "tcu4_in1", + "tcu5_in0", "tcu5_in1", + "tcu6_in0", "tcu6_in1", + "tcu7_in0", "tcu7_in1", +}; + +static const char * const x2600_uart0_groups[] = { + "uart0-data-c", "uart0-hwflow-c", "uart0-data-e", "uart0-hwflow-e", +}; + +static const char * const x2600_uart1_groups[] = { + "uart1-data-b", "uart1-data-c", "uart1-hwflow", +}; + +static const char * const x2600_uart2_groups[] = { "uart2-data", }; +static const char * const x2600_uart3_groups[] = { "uart3-data-b", "uart3-data-c", }; +static const char * const x2600_uart4_groups[] = { "uart4-data-b", "uart4-data-c", }; +static const char * const x2600_uart5_groups[] = { "uart5-data-b", "uart5-data-c", }; +static const char * const x2600_uart6_groups[] = { "uart6-data-c", }; +static const char * const x2600_uart7_groups[] = { "uart7-data-c", "uart7-data-e", }; + +static const struct pinfunction x2600_functions[] = { + INGENIC_PIN_FUNCTION("can0", x2600_can0), + INGENIC_PIN_FUNCTION("can1", x2600_can1), + INGENIC_PIN_FUNCTION("cim", x2600_cim), + INGENIC_PIN_FUNCTION("exclk", x2600_clk), + INGENIC_PIN_FUNCTION("dmic", x2600_dmic), + INGENIC_PIN_FUNCTION("i2c0", x2600_i2c0), + INGENIC_PIN_FUNCTION("i2c1", x2600_i2c1), + INGENIC_PIN_FUNCTION("i2c2", x2600_i2c2), + INGENIC_PIN_FUNCTION("i2c3", x2600_i2c3), + INGENIC_PIN_FUNCTION("i2s", x2600_i2s), + INGENIC_PIN_FUNCTION("lcd", x2600_lcd), + INGENIC_PIN_FUNCTION("mac", x2600_mac), + INGENIC_PIN_FUNCTION("mmc0", x2600_msc0), + INGENIC_PIN_FUNCTION("mmc1", x2600_msc1), + INGENIC_PIN_FUNCTION("otg", x2600_otg), + INGENIC_PIN_FUNCTION("pwm0", x2600_pwm0), + INGENIC_PIN_FUNCTION("pwm1", x2600_pwm1), + INGENIC_PIN_FUNCTION("pwm2", x2600_pwm2), + INGENIC_PIN_FUNCTION("pwm3", x2600_pwm3), + INGENIC_PIN_FUNCTION("pwm4", x2600_pwm4), + INGENIC_PIN_FUNCTION("pwm5", x2600_pwm5), + INGENIC_PIN_FUNCTION("pwm6", x2600_pwm6), + INGENIC_PIN_FUNCTION("pwm7", x2600_pwm7), + INGENIC_PIN_FUNCTION("pwm8", x2600_pwm8), + INGENIC_PIN_FUNCTION("pwm9", x2600_pwm9), + INGENIC_PIN_FUNCTION("pwm10", x2600_pwm10), + INGENIC_PIN_FUNCTION("sfc", x2600_sfc), + INGENIC_PIN_FUNCTION("slcd", x2600_slcd), + INGENIC_PIN_FUNCTION("ssi0", x2600_ssi0), + INGENIC_PIN_FUNCTION("ssi1", x2600_ssi1), + INGENIC_PIN_FUNCTION("ssi-slv", x2600_ssi_slv), + INGENIC_PIN_FUNCTION("uart0", x2600_uart0), + INGENIC_PIN_FUNCTION("uart1", x2600_uart1), + INGENIC_PIN_FUNCTION("uart2", x2600_uart2), + INGENIC_PIN_FUNCTION("uart3", x2600_uart3), + INGENIC_PIN_FUNCTION("uart4", x2600_uart4), + INGENIC_PIN_FUNCTION("uart5", x2600_uart5), + INGENIC_PIN_FUNCTION("uart6", x2600_uart6), + INGENIC_PIN_FUNCTION("uart7", x2600_uart7), + INGENIC_PIN_FUNCTION("tcu", x2600_tcu), +}; + +static const struct regmap_range x2600_access_ranges[] = { + regmap_reg_range(0x0000 + 0x000, 0x0000 + 0x0e8), + regmap_reg_range(0x0000 + 0x170, 0x0000 + 0x190), + regmap_reg_range(0x0000 + 0x200, 0x0000 + 0x210), + regmap_reg_range(0x0000 + 0x814, 0x0000 + 0x8f0), + regmap_reg_range(0x0000 + 0x974, 0x0000 + 0x978), + + regmap_reg_range(0x1000 + 0x000, 0x1000 + 0x0e8), + regmap_reg_range(0x1000 + 0x170, 0x1000 + 0x190), + regmap_reg_range(0x1000 + 0x200, 0x1000 + 0x210), + regmap_reg_range(0x1000 + 0x814, 0x1000 + 0x8f0), + regmap_reg_range(0x1000 + 0x974, 0x1000 + 0x978), + + regmap_reg_range(0x2000 + 0x000, 0x2000 + 0x0e8), + regmap_reg_range(0x2000 + 0x170, 0x2000 + 0x190), + regmap_reg_range(0x2000 + 0x200, 0x2000 + 0x210), + regmap_reg_range(0x2000 + 0x814, 0x2000 + 0x8f0), + regmap_reg_range(0x2000 + 0x974, 0x2000 + 0x978), + + regmap_reg_range(0x3000 + 0x000, 0x3000 + 0x0e8), + regmap_reg_range(0x3000 + 0x170, 0x3000 + 0x190), + regmap_reg_range(0x3000 + 0x200, 0x3000 + 0x210), + regmap_reg_range(0x3000 + 0x814, 0x3000 + 0x8f0), + regmap_reg_range(0x3000 + 0x974, 0x3000 + 0x978), + + regmap_reg_range(0x4000 + 0x000, 0x4000 + 0x0e8), + regmap_reg_range(0x4000 + 0x100, 0x4000 + 0x118), + regmap_reg_range(0x4000 + 0x170, 0x4000 + 0x190), + regmap_reg_range(0x4000 + 0x200, 0x4000 + 0x210), + regmap_reg_range(0x4000 + 0x814, 0x4000 + 0x8f0), + regmap_reg_range(0x4000 + 0x974, 0x4000 + 0x978), +}; + +static const struct regmap_access_table x2600_access_table = { + .yes_ranges = x2600_access_ranges, + .n_yes_ranges = ARRAY_SIZE(x2600_access_ranges), +}; + +static const struct ingenic_chip_info x2600_chip_info = { + .num_chips = 5, + .reg_offset = 0x1000, + .version = ID_X2600, + .groups = x2600_groups, + .num_groups = ARRAY_SIZE(x2600_groups), + .functions = x2600_functions, + .num_functions = ARRAY_SIZE(x2600_functions), + .pull_ups = x2600_pull_ups, + .pull_downs = x2600_pull_downs, + .access_table = &x2600_access_table, +}; + static u32 ingenic_gpio_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg) { unsigned int val; @@ -4453,6 +4950,7 @@ static const struct of_device_id ingenic_gpio_of_matches[] __initconst = { { .compatible = "ingenic,x1830-gpio" }, { .compatible = "ingenic,x2000-gpio" }, { .compatible = "ingenic,x2100-gpio" }, + { .compatible = "ingenic,x2600-gpio" }, {}, }; @@ -4714,6 +5212,10 @@ static const struct of_device_id ingenic_pinctrl_of_matches[] = { .compatible = "ingenic,x2100-pinctrl", .data = IF_ENABLED(CONFIG_MACH_X2100, &x2100_chip_info) }, + { + .compatible = "ingenic,x2600-pinctrl", + .data = IF_ENABLED(CONFIG_MACH_X2600, &x2600_chip_info) + }, { /* sentinel */ }, }; -- 2.56.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-13 10:03 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-13 8:14 [PATCH 0/3] pinctrl: ingenic: Add X2600 support H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 1/3] dt-bindings: " H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 2/3] pinctrl: ingenic: Add X2600 register and GPIO IRQ support H. Nikolaus Schaller 2026-11-13 9:37 ` Paul Cercueil 2026-11-13 9:49 ` H. Nikolaus Schaller 2026-11-13 9:54 ` Paul Cercueil 2026-11-13 10:02 ` H. Nikolaus Schaller 2026-11-13 8:14 ` [PATCH 3/3] pinctrl: ingenic: Add X2600 pin groups and functions H. Nikolaus Schaller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox