Skip to contentSkip to conversation

Hi,

PATCH Superseded Gregory CLEMENT 2 participants 22 messages Mar 21, 2017 – Mar 30, 2017

Subsystems (6)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover Hi,

this series add support for the pin and gpio controllers present on the Armada 37xx SoCs.

Each Armada 37xx SoC comes with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

Gregory

Gregory CLEMENT (7):
pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
arm64: marvell: enable the Armada 37xx pinctrl driver
pinctrl: armada-37xx: Add pin controller support for Armada 37xx
pinctrl: armada-37xx: Add gpio support
pinctrl: aramda-37xx: Add irqchip support
ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 +++++++++++-
 arch/arm64/Kconfig.platforms                                              |   2 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  71 +++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 918 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1153 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

base-commit: c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201

Signature · 1 line
git-series 0.9.1
#1 lore raw

PATCH v2 1/7 pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers

Document the device tree binding for the pin controllers found on the Armada 37xx SoCs.

Update the binding documention of the xtal clk which is a subnode of this syscon node.

---
 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 ++--
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 147 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt +4 -3
index a88f1f05fbd6..4c0807f28cfa 100644
@@ -5,6 +5,7 @@ reading the gpio latch register.
 
 This node must be a subnode of the node exposing the register address
 of the GPIO block where the gpio latch is located.
+See Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 
 Required properties:
 - compatible : shall be one of the following:
@@ -16,9 +17,9 @@ Optional properties:
 	output names ("xtal")
 
 Example:
-gpio1: gpio at 13800 {
-	compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd";
-	reg = <0x13800 0x1000>;
+pinctrl_nb: pinctrl-nb at 13800 {
+	compatible = "armada3710-nb-pinctrl", "syscon", "simple-mfd";
+	reg = <0x13800 0x100>, <0x13C00 0x20>;
 
 	xtalclk: xtal-clk {
 		compatible = "marvell,armada-3700-xtal-clock";
Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt new file +143 -0

143 lines not on this page · raw message

Signature · 1 line
git-series 0.9.1
#2 lore raw

Re: [PATCH v2 1/7] pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers

Quoted 7 lines · Gregory CLEMENT

Document the device tree binding for the pin controllers found on the Armada 37xx SoCs.

Update the binding documention of the xtal clk which is a subnode of this syscon node.

These look all right to me, but let's see what the DT people say.

This business with a subnode named "gpio-controller" that the code is checking for is not in the bindings or examples, is this part of the old Armada bindings?

Yours,
Linus Walleij

#3 lore raw

Re: [PATCH v2 1/7] pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers

Hi Linus,

Quoted 9 lines · Linus Walleij
Quoted 6 lines · Gregory CLEMENT

Document the device tree binding for the pin controllers found on the Armada 37xx SoCs.

Update the binding documention of the xtal clk which is a subnode of this syscon node.

Quoted 7 lines
Quoted 1 line

These look all right to me, but let's see what the DT people say.

This business with a subnode named "gpio-controller" that the code is checking for is not in the bindings or examples, is this part of the old Armada bindings?

It was updated in the version 3 I sent last week.

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#4 lore raw

PATCH v2 2/7 arm64: marvell: enable the Armada 37xx pinctrl driver

In reply to Gregory CLEMENT

This commit makes sure the driver for the Armada 37xx pin controller is enabled.

---
 arch/arm64/Kconfig.platforms | 2 ++
 1 file changed, 2 insertions(+)
arch/arm64/Kconfig.platforms +2 -0
index 129cc5ae4091..f2bb1691264f 100644
@@ -105,6 +105,8 @@ config ARCH_MVEBU
 	select ARMADA_37XX_CLK
 	select MVEBU_ODMI
 	select MVEBU_PIC
+	select PINCTRL
+	select PINCTRL_ARMADA_37XX
 	help
 	  This enables support for Marvell EBU familly, including:
 	   - Armada 3700 SoC Family
Signature · 1 line
git-series 0.9.1
#5 lore raw

PATCH v2 3/7 pinctrl: armada-37xx: Add pin controller support for Armada 37xx

In reply to Gregory CLEMENT

The Armada 37xx SoC come with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin. This constraint is reflected in the design of the driver:
only the group related functions are implemented.

---
 drivers/pinctrl/Makefile                    |   2 +-
 drivers/pinctrl/mvebu/Kconfig               |   7 +-
 drivers/pinctrl/mvebu/Makefile              |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 605 +++++++++++++++++++++-
 4 files changed, 615 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
drivers/pinctrl/Makefile +1 -1
index a251f439626f..95080811f36f 100644
@@ -44,7 +44,7 @@ obj-y				+= bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)	+= berlin/
 obj-y				+= freescale/
 obj-$(CONFIG_X86)		+= intel/
-obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
+obj-y				+= mvebu/
 obj-y				+= nomadik/
 obj-$(CONFIG_PINCTRL_PXA)	+= pxa/
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
drivers/pinctrl/mvebu/Kconfig +7 -0
index 170602407c0d..5bade32d3089 100644
@@ -39,3 +39,10 @@ config PINCTRL_ORION
 	select PINCTRL_MVEBU
 
 endif
+
+config PINCTRL_ARMADA_37XX
+       bool
+       select GENERIC_PINCONF
+       select MFD_SYSCON
+       select PINCONF
+       select PINMUX
drivers/pinctrl/mvebu/Makefile +2 -1
index 18270cd5ea43..60c245a60f39 100644
@@ -1,4 +1,4 @@
-obj-y				+= pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_MVEBU)	+= pinctrl-mvebu.o
 obj-$(CONFIG_PINCTRL_DOVE)	+= pinctrl-dove.o
 obj-$(CONFIG_PINCTRL_KIRKWOOD)	+= pinctrl-kirkwood.o
 obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
@@ -6,4 +6,5 @@ obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o
 obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
 obj-$(CONFIG_PINCTRL_ARMADA_39X) += pinctrl-armada-39x.o
 obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
+obj-$(CONFIG_PINCTRL_ARMADA_37XX)  += pinctrl-armada-37xx.o
 obj-$(CONFIG_PINCTRL_ORION)  += pinctrl-orion.o
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +605 -0

605 lines not on this page · raw message

Signature · 1 line
git-series 0.9.1
#6 lore raw

Re: [PATCH v2 3/7] pinctrl: armada-37xx: Add pin controller support for Armada 37xx

Quoted 6 lines · Gregory CLEMENT

The Armada 37xx SoC come with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin. This constraint is reflected in the design of the driver:
only the group related functions are implemented.

Interesting!

Quoted 7 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +7 -0
+static int armada_37xx_pmx_direction_input(struct armada_37xx_pinctrl *info,
+                                          unsigned int offset)
+{
+       unsigned int reg = OUTPUT_EN;
+       unsigned int mask;
+
+       if (offset >= GPIO_PER_REG) {

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 331

Quoted 10 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +10 -0
+               offset -= GPIO_PER_REG;
+               reg += sizeof(u32);
+       }
+       mask = BIT(offset);
+
+       return regmap_update_bits(info->regmap, reg, mask, 0);
+}
+
+
+

A bit of excess whitespace, OK nitpicking.

Then this stuff:

Quoted 89 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +89 -0
+static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs,
+                                   int *funcsize, const char *name)
+{
+       int i = 0;
+
+       if (*funcsize <= 0)
+               return -EOVERFLOW;
+
+       while (funcs->ngroups) {
+               /* function already there */
+               if (strcmp(funcs->name, name) == 0) {
+                       funcs->ngroups++;
+
+                       return -EEXIST;
+               }
+               funcs++;
+               i++;
+       }
+
+       /* append new unique function */
+       funcs->name = name;
+       funcs->ngroups = 1;
+       (*funcsize)--;
+
+       return 0;
+}
+
+static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info, int base)
+{
+       int n, num = 0, funcsize = info->data->nr_pins;
+
+       for (n = 0; n < info->ngroups; n++) {
+               struct armada_37xx_pin_group *grp = &info->groups[n];
+               int i, j, f;
+
+               grp->pins = devm_kzalloc(info->dev,
+                                        (grp->npins + grp->extra_npins) *
+                                        sizeof(*grp->pins), GFP_KERNEL);
+               if (!grp->pins)
+                       return -ENOMEM;
+
+               for (i = 0; i < grp->npins; i++)
+                       grp->pins[i] = grp->start_pin + base + i;
+
+               for (j = 0; j < grp->extra_npins; j++)
+                       grp->pins[i+j] = grp->extra_pin + base + j;
+
+               for (f = 0; f < NB_FUNCS; f++) {
+                       int ret;
+                       /* check for unique functions and count groups */
+                       ret = armada_37xx_add_function(info->funcs, &funcsize,
+                                           grp->funcs[f]);
+                       if (ret == -EOVERFLOW)
+                               dev_err(info->dev,
+                                       "More functions than pins(%d)\n",
+                                       info->data->nr_pins);
+                       if (ret < 0)
+                               continue;
+                       num++;
+               }
+       }
+
+       info->nfuncs = num;
+
+       return 0;
+}
+
+static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
+{
+       struct armada_37xx_pmx_func *funcs = info->funcs;
+       int n;
+
+       for (n = 0; n < info->nfuncs; n++) {
+               const char *name = funcs[n].name;
+               const char **groups;
+               int g;
+
+               funcs[n].groups = devm_kzalloc(info->dev, funcs[n].ngroups *
+                                              sizeof(*(funcs[n].groups)),
+                                              GFP_KERNEL);
+               if (!funcs[n].groups)
+                       return -ENOMEM;
+
+               groups = funcs[n].groups;
+
+               for (g = 0; g < info->ngroups; g++) {
+                       struct armada_37xx_pin_group *gp = &info->groups[g];
+                       int f;
+

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 487

Quoted 10 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +10 -0
+                       for (f = 0; f < NB_FUNCS; f++) {
+                               if (strcmp(gp->funcs[f], name) == 0) {
+                                       *groups = gp->name;
+                                       groups++;
+                               }
+                       }
+               }
+       }
+       return 0;
+}

I would be happy if you add kerneldoc to these functions and explain what they do. Because I don't get it. I guess they are filling in the data structures but yeah. Hard to follow.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 586

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +2 -0
+       match = of_match_node(armada_37xx_pinctrl_of_match, np);
+       info->data = (struct armada_37xx_pin_data *)match->data;

Use of_device_get_match_data()

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 605

Quoted 9 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +9 -0
+static struct platform_driver armada_37xx_pinctrl_driver = {
+       .driver = {
+               .name = "armada-37xx-pinctrl",
+               .of_match_table = armada_37xx_pinctrl_of_match,
+       },
+       .probe = armada_37xx_pinctrl_probe,
+};
+
+builtin_platform_driver(armada_37xx_pinctrl_driver);

It almost looks like your could use builting_platform_driver_probe() actually, and tag the costly initfunctions with __init so they get dicarded after probe.

Yours,
Linus Walleij

#7 lore raw

Re: [PATCH v2 3/7] pinctrl: armada-37xx: Add pin controller support for Armada 37xx

Hi Linus,

Quoted 23 lines · Linus Walleij
Quoted 6 lines · Gregory CLEMENT

The Armada 37xx SoC come with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin. This constraint is reflected in the design of the driver:
only the group related functions are implemented.

Interesting!

Quoted 11 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +11 -0
+static int armada_37xx_pmx_direction_input(struct armada_37xx_pinctrl *info,
+                                          unsigned int offset)
+{
+       unsigned int reg = OUTPUT_EN;
+       unsigned int mask;
+
+       if (offset >= GPIO_PER_REG) {
+               offset -= GPIO_PER_REG;
+               reg += sizeof(u32);
+       }
+       mask = BIT(offset);
Quoted 9 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 331

Quoted 6 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +6 -0
+
+       return regmap_update_bits(info->regmap, reg, mask, 0);
+}
+
+
+

A bit of excess whitespace, OK nitpicking.

As I need to send a v4, I will fix it in the same time.

Quoted 97 lines

Then this stuff:

Quoted 95 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +95 -0
+static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs,
+                                   int *funcsize, const char *name)
+{
+       int i = 0;
+
+       if (*funcsize <= 0)
+               return -EOVERFLOW;
+
+       while (funcs->ngroups) {
+               /* function already there */
+               if (strcmp(funcs->name, name) == 0) {
+                       funcs->ngroups++;
+
+                       return -EEXIST;
+               }
+               funcs++;
+               i++;
+       }
+
+       /* append new unique function */
+       funcs->name = name;
+       funcs->ngroups = 1;
+       (*funcsize)--;
+
+       return 0;
+}
+
+static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info, int base)
+{
+       int n, num = 0, funcsize = info->data->nr_pins;
+
+       for (n = 0; n < info->ngroups; n++) {
+               struct armada_37xx_pin_group *grp = &info->groups[n];
+               int i, j, f;
+
+               grp->pins = devm_kzalloc(info->dev,
+                                        (grp->npins + grp->extra_npins) *
+                                        sizeof(*grp->pins), GFP_KERNEL);
+               if (!grp->pins)
+                       return -ENOMEM;
+
+               for (i = 0; i < grp->npins; i++)
+                       grp->pins[i] = grp->start_pin + base + i;
+
+               for (j = 0; j < grp->extra_npins; j++)
+                       grp->pins[i+j] = grp->extra_pin + base + j;
+
+               for (f = 0; f < NB_FUNCS; f++) {
+                       int ret;
+                       /* check for unique functions and count groups */
+                       ret = armada_37xx_add_function(info->funcs, &funcsize,
+                                           grp->funcs[f]);
+                       if (ret == -EOVERFLOW)
+                               dev_err(info->dev,
+                                       "More functions than pins(%d)\n",
+                                       info->data->nr_pins);
+                       if (ret < 0)
+                               continue;
+                       num++;
+               }
+       }
+
+       info->nfuncs = num;
+
+       return 0;
+}
+
+static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
+{
+       struct armada_37xx_pmx_func *funcs = info->funcs;
+       int n;
+
+       for (n = 0; n < info->nfuncs; n++) {
+               const char *name = funcs[n].name;
+               const char **groups;
+               int g;
+
+               funcs[n].groups = devm_kzalloc(info->dev, funcs[n].ngroups *
+                                              sizeof(*(funcs[n].groups)),
+                                              GFP_KERNEL);
+               if (!funcs[n].groups)
+                       return -ENOMEM;
+
+               groups = funcs[n].groups;
+
+               for (g = 0; g < info->ngroups; g++) {
+                       struct armada_37xx_pin_group *gp = &info->groups[g];
+                       int f;
+
+                       for (f = 0; f < NB_FUNCS; f++) {
+                               if (strcmp(gp->funcs[f], name) == 0) {
+                                       *groups = gp->name;
+                                       groups++;
+                               }
+                       }
Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 237

Quoted 4 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +4 -0
+               }
+       }
+       return 0;
+}

I would be happy if you add kerneldoc to these functions and explain what they do. Because I don't get it. I guess they are filling in the data structures but yeah. Hard to follow.

OK

Quoted 5 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 586

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +2 -0
+       match = of_match_node(armada_37xx_pinctrl_of_match, np);
+       info->data = (struct armada_37xx_pin_data *)match->data;

Use of_device_get_match_data()

OK

Quoted 15 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 605

Quoted 11 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file +9 -0
+static struct platform_driver armada_37xx_pinctrl_driver = {
+       .driver = {
+               .name = "armada-37xx-pinctrl",
+               .of_match_table = armada_37xx_pinctrl_of_match,
+       },
+       .probe = armada_37xx_pinctrl_probe,
+};
+
+builtin_platform_driver(armada_37xx_pinctrl_driver);

It almost looks like your could use builting_platform_driver_probe() actually, and tag the costly initfunctions with __init so they get dicarded after probe.

Sure, I will do it

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#8 lore raw

PATCH v2 4/7 pinctrl: armada-37xx: Add gpio support

In reply to Gregory CLEMENT

GPIO management is pretty simple and is part of the same IP than the pin controller for the Armada 37xx SoCs. This patch adds the GPIO support to the pinctrl-armada-37xx.c file, it also allows sharing common functions between the gpiolib and the pinctrl drivers.

---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 134 ++++++++++++++++++---
 1 file changed, 119 insertions(+), 15 deletions(-)
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +119 -15
index 98cde04e07e1..e41e2d02aca7 100644
@@ -10,6 +10,7 @@
  * without any warranty of any kind, whether express or implied.
  */
 
+#include <linux/gpio/driver.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -24,6 +25,8 @@
 #include "../pinctrl-utils.h"
 
 #define OUTPUT_EN	0x0
+#define INPUT_VAL	0x10
+#define OUTPUT_VAL	0x18
 #define OUTPUT_CTL	0x20
 #define SELECTION	0x30
 
@@ -75,6 +78,7 @@ struct armada_37xx_pinctrl {
 	struct regmap			*regmap;
 	struct armada_37xx_pin_data	*data;
 	struct device			*dev;
+	struct gpio_chip		gpio_chip;
 	struct pinctrl_desc		pctl;
 	struct pinctrl_dev		*pctl_dev;
 	struct armada_37xx_pin_group	*groups;
@@ -312,51 +316,99 @@ static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
 	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
 }
 
-static int armada_37xx_pmx_direction_input(struct armada_37xx_pinctrl *info,
-					   unsigned int offset)
+static inline void aramda_37xx_update_reg(unsigned int *reg,
+					  unsigned int offset)
 {
-	unsigned int reg = OUTPUT_EN;
-	unsigned int mask;
-
+	/* We never have more than 2 registers */
 	if (offset >= GPIO_PER_REG) {
 		offset -= GPIO_PER_REG;
-		reg += sizeof(u32);
+		*reg += sizeof(u32);
 	}
+}
+
+static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
+					    unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int mask;
+
+	aramda_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, 0);
 }
 
+static int armada_37xx_gpio_get_direction(struct gpio_chip *chip,
+					  unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int val, mask;
+
+	aramda_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	regmap_read(info->regmap, reg, &val);
 
+	return !(val & mask);
+}
 
-static int armada_37xx_pmx_direction_output(struct armada_37xx_pinctrl *info,
-					    unsigned int offset, int value)
+static int armada_37xx_gpio_direction_output(struct gpio_chip *chip,
+					     unsigned int offset, int value)
 {
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
 	unsigned int reg = OUTPUT_EN;
 	unsigned int mask;
 
-	if (offset >= GPIO_PER_REG) {
-		offset -= GPIO_PER_REG;
-		reg += sizeof(u32);
-	}
+	aramda_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, mask);
 }
 
+static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = INPUT_VAL;
+	unsigned int val, mask;
+
+	aramda_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	regmap_read(info->regmap, reg, &val);
+
+	return (val & mask) != 0;
+}
+
+static void armada_37xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+				 int value)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = OUTPUT_VAL;
+	unsigned int mask, val;
+
+	aramda_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+	val = value ? mask : 0;
+
+	regmap_update_bits(info->regmap, reg, mask, val);
+}
+
 static int armada_37xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 					      struct pinctrl_gpio_range *range,
 					      unsigned int offset, bool input)
 {
 	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = range->gc;
 
 	dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
 		offset, range->name, offset, input ? "input" : "output");
 
 	if (input)
-		armada_37xx_pmx_direction_input(info, offset);
+		armada_37xx_gpio_direction_input(chip, offset);
 	else
-		armada_37xx_pmx_direction_output(info, offset, 0);
+		armada_37xx_gpio_direction_output(chip, offset, 0);
 
 	return 0;
 }
@@ -386,6 +438,49 @@ static const struct pinmux_ops armada_37xx_pmx_ops = {
 	.gpio_set_direction	= armada_37xx_pmx_gpio_set_direction,
 };
 
+static const struct gpio_chip armada_37xx_gpiolib_chip = {
+	.request = gpiochip_generic_request,
+	.free = gpiochip_generic_free,
+	.set = armada_37xx_gpio_set,
+	.get = armada_37xx_gpio_get,
+	.get_direction	= armada_37xx_gpio_get_direction,
+	.direction_input = armada_37xx_gpio_direction_input,
+	.direction_output = armada_37xx_gpio_direction_output,
+	.owner = THIS_MODULE,
+};
+
+static int armada_37xx_gpiochip_register(struct platform_device *pdev,
+					struct armada_37xx_pinctrl *info)
+{
+	struct device_node *np;
+	struct gpio_chip *gc;
+	int ret = -ENODEV;
+
+	for_each_child_of_node(info->dev->of_node, np) {
+		if (of_find_property(np, "gpio-controller", NULL)) {
+			ret = 0;
+			break;
+		}
+	};
+	if (ret)
+		return ret;
+
+	info->gpio_chip = armada_37xx_gpiolib_chip;
+
+	gc = &info->gpio_chip;
+	gc->ngpio = info->data->nr_pins;
+	gc->parent = &pdev->dev;
+	gc->base = -1;
+	gc->of_node = np;
+	gc->label = info->data->name;
+
+	ret = gpiochip_add_data(gc, info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs,
 				    int *funcsize, const char *name)
 {
@@ -566,7 +661,7 @@ static int armada_37xx_pinctrl_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct regmap *regmap;
-	int ret;
+	int ret, pinbase = global_pin;
 
 	info = devm_kzalloc(dev, sizeof(struct armada_37xx_pinctrl),
 			    GFP_KERNEL);
@@ -585,10 +680,19 @@ static int armada_37xx_pinctrl_probe(struct platform_device *pdev)
 	match = of_match_node(armada_37xx_pinctrl_of_match, np);
 	info->data = (struct armada_37xx_pin_data *)match->data;
 
+	ret = armada_37xx_gpiochip_register(pdev, info);
+	if (ret)
+		return ret;
+
 	ret = armada_37xx_pinctrl_register(pdev, info);
 	if (ret)
 		return ret;
 
+	ret = gpiochip_add_pin_range(&info->gpio_chip, dev_name(dev), 0,
+				     pinbase, info->data->nr_pins);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, info);
 
 	return 0;
Signature · 1 line
git-series 0.9.1
#9 lore raw

Re: [PATCH v2 4/7] pinctrl: armada-37xx: Add gpio support

On Tue, Mar 21, 2017 at 7:28 PM, Gregory CLEMENT
<[email protected]> wrote:

You should add something to your Kconfig including:

select GPIOLIB
select OF_GPIO

or so... or depends on. You certainly need them.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct pinmux_ops armada_37xx_pmx_ops = { · line 464

Quoted 13 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +13 -0
+static int armada_37xx_gpiochip_register(struct platform_device *pdev,
+                                       struct armada_37xx_pinctrl *info)
+{
+       struct device_node *np;
+       struct gpio_chip *gc;
+       int ret = -ENODEV;
+
+       for_each_child_of_node(info->dev->of_node, np) {
+               if (of_find_property(np, "gpio-controller", NULL)) {
+                       ret = 0;
+                       break;
+               }
+       };

OK so several GPIO chips as subnodes, why not one device per chip? Or have we discussed this before? It seems a bit weird, apparently there is just one node with a gpio-controller, as you're just adding one pin range.

What happens if there would be two gpio-controllers? The second is just ignored without error?

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct pinmux_ops armada_37xx_pmx_ops = { · line 479

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+       ret = gpiochip_add_data(gc, info);
+       if (ret)
+               return ret;

Can't you use devm_gpiochip_add_data()?

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static int armada_37xx_pinctrl_probe(struct platform_device *pdev) · line 694

Quoted 4 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +4 -0
+       ret = gpiochip_add_pin_range(&info->gpio_chip, dev_name(dev), 0,
+                                    pinbase, info->data->nr_pins);
+       if (ret)
+               return ret;

Why can't you put the range(s) into the device tree?

We already have code in drivers/gpio/gpiolib-of.c to do this for you. And generic range definition bindings.

Yours,
Linus Walleij

#10 lore raw

Re: [PATCH v2 4/7] pinctrl: armada-37xx: Add gpio support

Hi Linus,

Quoted 9 lines · Linus Walleij

On Tue, Mar 21, 2017 at 7:28 PM, Gregory CLEMENT
<[email protected]> wrote:

You should add something to your Kconfig including:

select GPIOLIB
select OF_GPIO

or so... or depends on. You certainly need them.

I missed it I will do it in v4.

Quoted 11 lines
Quoted 11 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +10 -0
+static int armada_37xx_gpiochip_register(struct platform_device *pdev,
+                                       struct armada_37xx_pinctrl *info)
+{
+       struct device_node *np;
+       struct gpio_chip *gc;
+       int ret = -ENODEV;
+
+       for_each_child_of_node(info->dev->of_node, np) {
+               if (of_find_property(np, "gpio-controller", NULL)) {
+                       ret = 0;
Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct pinmux_ops armada_37xx_pmx_ops = { · line 464

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+                       break;
+               }
+       };

OK so several GPIO chips as subnodes, why not one device per chip? Or have we discussed this before? It seems a bit weird, apparently there is just one node with a gpio-controller, as you're just adding one pin range.

As you probably noticed pinctrl and gpio register are mixed in this hardware. One of the register is alos use to get some clock freqeuncy, so that's why I ended with a syscon node. The parent node is the pinctrl. My main motivation to use a subnode was to be ablee to have a phandle associated with the GPIO chip. In my first version I only have one node but then I realized that I could not use GPIO in the device tree without an phandle to point it.

If you have an other solution, I would be happy to remove this subnode.

Quoted 3 lines

What happens if there would be two gpio-controllers? The second is just ignored without error?

There won't be a second gpio-controllers because we only have one gpio controller by pin controller (as they are actually the same). Also as I said above, the subnode is mainly here to provide a phandle.

But I can add a comment to emphasize it.

Quoted 6 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct pinmux_ops armada_37xx_pmx_ops = { · line 479

Quoted 4 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+       ret = gpiochip_add_data(gc, info);
+       if (ret)
+               return ret;

Can't you use devm_gpiochip_add_data()?

I think I can.

Quoted 10 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static int armada_37xx_pinctrl_probe(struct platform_device *pdev) · line 694

Quoted 5 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +4 -0
+       ret = gpiochip_add_pin_range(&info->gpio_chip, dev_name(dev), 0,
+                                    pinbase, info->data->nr_pins);
+       if (ret)
+               return ret;

Why can't you put the range(s) into the device tree?

We already have code in drivers/gpio/gpiolib-of.c to do this for you. And generic range definition bindings.

It was done in the v3.

Tanks,

Gregory

Quoted 8 lines

Yours,
Linus Walleij

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#11 lore raw

PATCH v2 5/7 pinctrl: aramda-37xx: Add irqchip support

In reply to Gregory CLEMENT

The Armada 37xx SoCs can handle interrupt through GPIO. However it can only manage the edge ones.

The way the interrupt are managed are classical so we can use the generic interrupt chip model.

The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them.

---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 223 ++++++++++++++++++++-
 1 file changed, 216 insertions(+), 7 deletions(-)
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +216 -7
index e41e2d02aca7..5d3af27f1ba9 100644
@@ -13,7 +13,9 @@
 #include <linux/gpio/driver.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -30,6 +32,11 @@
 #define OUTPUT_CTL	0x20
 #define SELECTION	0x30
 
+#define IRQ_EN		0x0
+#define IRQ_POL		0x08
+#define IRQ_STATUS	0x10
+#define IRQ_WKUP	0x18
+
 static int global_pin;
 
 #define NB_FUNCS 2
@@ -76,9 +83,12 @@ struct armada_37xx_pmx_func {
 
 struct armada_37xx_pinctrl {
 	struct regmap			*regmap;
+	void __iomem			*base;
 	struct armada_37xx_pin_data	*data;
 	struct device			*dev;
 	struct gpio_chip		gpio_chip;
+	struct irq_chip			irq_chip;
+	spinlock_t			irq_lock;
 	struct pinctrl_desc		pctl;
 	struct pinctrl_dev		*pctl_dev;
 	struct armada_37xx_pin_group	*groups;
@@ -316,7 +326,7 @@ static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
 	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
 }
 
-static inline void aramda_37xx_update_reg(unsigned int *reg,
+static inline void armada_37xx_update_reg(unsigned int *reg,
 					  unsigned int offset)
 {
 	/* We never have more than 2 registers */
@@ -326,6 +336,14 @@ static inline void aramda_37xx_update_reg(unsigned int *reg,
 	}
 }
 
+static inline void armada_37xx_irq_update_reg(unsigned int *reg,
+					  struct irq_data *d)
+{
+	int offset = irqd_to_hwirq(d);
+
+	armada_37xx_update_reg(reg, offset);
+}
+
 static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
 					    unsigned int offset)
 {
@@ -333,7 +351,7 @@ static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
 	unsigned int reg = OUTPUT_EN;
 	unsigned int mask;
 
-	aramda_37xx_update_reg(&reg, offset);
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, 0);
@@ -346,7 +364,7 @@ static int armada_37xx_gpio_get_direction(struct gpio_chip *chip,
 	unsigned int reg = OUTPUT_EN;
 	unsigned int val, mask;
 
-	aramda_37xx_update_reg(&reg, offset);
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	regmap_read(info->regmap, reg, &val);
@@ -361,7 +379,7 @@ static int armada_37xx_gpio_direction_output(struct gpio_chip *chip,
 	unsigned int reg = OUTPUT_EN;
 	unsigned int mask;
 
-	aramda_37xx_update_reg(&reg, offset);
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, mask);
@@ -373,7 +391,7 @@ static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	unsigned int reg = INPUT_VAL;
 	unsigned int val, mask;
 
-	aramda_37xx_update_reg(&reg, offset);
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	regmap_read(info->regmap, reg, &val);
@@ -388,7 +406,7 @@ static void armada_37xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	unsigned int reg = OUTPUT_VAL;
 	unsigned int mask, val;
 
-	aramda_37xx_update_reg(&reg, offset);
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 	val = value ? mask : 0;
 
@@ -449,6 +467,194 @@ static const struct gpio_chip armada_37xx_gpiolib_chip = {
 	.owner = THIS_MODULE,
 };
 
+void armada_37xx_irq_ack(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 reg = IRQ_STATUS, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	writel(mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+void armada_37xx_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_EN, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	writel(val & ~mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+void armada_37xx_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_EN, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	writel(val | mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_WKUP, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	if (on)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel(val, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+
+	return 0;
+}
+
+static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_POL, mask = d->mask;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->irq_lock, flags);
+	armada_37xx_irq_update_reg(&reg, d);
+	val = readl(info->base + reg);
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		val &= ~mask;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		val |= mask;
+		break;
+	default:
+		spin_unlock_irqrestore(&info->irq_lock, flags);
+		return -EINVAL;
+	}
+	writel(val, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+
+	return 0;
+}
+
+
+static void armada_37xx_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
+	struct irq_domain *d = gc->irqdomain;
+	int i;
+
+	chained_irq_enter(chip, desc);
+	for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) {
+		u32 status;
+		unsigned long flags;
+
+		spin_lock_irqsave(&info->irq_lock, flags);
+		status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
+		/* Manage only the interrupt that was enabled */
+		status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
+		spin_unlock_irqrestore(&info->irq_lock, flags);
+		while (status) {
+			u32 hwirq = ffs(status) - 1;
+			u32 virq = irq_linear_revmap(d, hwirq +
+						     i * GPIO_PER_REG);
+
+			generic_handle_irq(virq);
+			status &= ~(1 << hwirq);
+		}
+	}
+	chained_irq_exit(chip, desc);
+}
+
+static int armada_37xx_irqchip_register(struct platform_device *pdev,
+					struct armada_37xx_pinctrl *info)
+{
+	struct device_node *np = info->dev->of_node;
+	int nrirqs = info->data->nr_pins;
+	struct gpio_chip *gc = &info->gpio_chip;
+	struct irq_chip *irqchip = &info->irq_chip;
+	struct resource res;
+	int ret, i, nr_irq_parent;
+
+	for_each_child_of_node(info->dev->of_node, np) {
+		if (of_find_property(np, "gpio-controller", NULL)) {
+			ret = 0;
+			break;
+		}
+	};
+	if (ret)
+		return ret;
+
+	nr_irq_parent = of_irq_count(np);
+	spin_lock_init(&info->irq_lock);
+
+	if (!nr_irq_parent) {
+		dev_err(&pdev->dev, "Invalid or no IRQ\n");
+		return 0;
+	}
+
+	if (of_address_to_resource(info->dev->of_node, 1, &res)) {
+		dev_err(info->dev, "cannot find IO resource\n");
+		return -ENOENT;
+	}
+
+	info->base = devm_ioremap_resource(info->dev, &res);
+	if (IS_ERR(info->base))
+		return PTR_ERR(info->base);
+
+	irqchip->irq_ack = armada_37xx_irq_ack;
+	irqchip->irq_mask = armada_37xx_irq_mask;
+	irqchip->irq_unmask = armada_37xx_irq_unmask;
+	irqchip->irq_set_wake = armada_37xx_irq_set_wake;
+	irqchip->irq_set_type = armada_37xx_irq_set_type;
+	irqchip->name = info->data->name;
+
+	ret = gpiochip_irqchip_add(gc, irqchip, 0,
+				   handle_level_irq, IRQ_TYPE_NONE);
+	if (ret) {
+		dev_info(&pdev->dev, "could not add irqchip\n");
+		return ret;
+	}
+
+	for (i = 0; i < nrirqs; i++) {
+		struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+		d->mask = 1 << (i % GPIO_PER_REG);
+	}
+
+	for (i = 0; i < nr_irq_parent; i++) {
+		int irq = irq_of_parse_and_map(np, i);
+
+		if (irq < 0)
+			continue;
+
+		gpiochip_set_chained_irqchip(gc, irqchip, irq,
+					     armada_37xx_irq_handler);
+	}
+
+	return 0;
+}
+
 static int armada_37xx_gpiochip_register(struct platform_device *pdev,
 					struct armada_37xx_pinctrl *info)
 {
@@ -477,6 +683,9 @@ static int armada_37xx_gpiochip_register(struct platform_device *pdev,
 	ret = gpiochip_add_data(gc, info);
 	if (ret)
 		return ret;
+	ret = armada_37xx_irqchip_register(pdev, info);
+	if (ret)
+		return ret;
 
 	return 0;
 }
@@ -518,7 +727,7 @@ static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info, int base)
 
 		grp->pins = devm_kzalloc(info->dev,
 					 (grp->npins + grp->extra_npins) *
-					 sizeof(*grp->pins), GFP_KERNEL);
+				 sizeof(*grp->pins), GFP_KERNEL);
 		if (!grp->pins)
 			return -ENOMEM;
 
Signature · 1 line
git-series 0.9.1
#12 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Quoted 11 lines · Gregory CLEMENT

The Armada 37xx SoCs can handle interrupt through GPIO. However it can only manage the edge ones.

The way the interrupt are managed are classical so we can use the generic interrupt chip model.

The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them.

You need something in your Kconfig
doing select GPIOLIB_IRQCHIP unless there is
something I miss here.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 37

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+#define IRQ_EN         0x0
+#define IRQ_POL                0x08
+#define IRQ_STATUS     0x10

This just cries out to me that there is a register 0x0c and I bet it handles edges vs levels so you could also implement level IRQs. Am I right?

Quoted 2 lines
(quoted diff) +1 -1
-       aramda_37xx_update_reg(&reg, offset);
+       armada_37xx_update_reg(&reg, offset);

(...)

Review

Quoted 2 lines
(quoted diff) +1 -1
-       aramda_37xx_update_reg(&reg, offset);
+       armada_37xx_update_reg(&reg, offset);

These spelling fixes, do not do them in this patch, fix the first patch adding them
instead. It's super-confusing. Applies everywhere.

Quoted 12 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +12 -0
+static void armada_37xx_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
+       struct irq_domain *d = gc->irqdomain;
+       int i;
+
+       chained_irq_enter(chip, desc);
+       for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) {
+               u32 status;
+               unsigned long flags;

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 580

Quoted 10 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +10 -0
+
+               spin_lock_irqsave(&info->irq_lock, flags);
+               status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
+               /* Manage only the interrupt that was enabled */
+               status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
+               spin_unlock_irqrestore(&info->irq_lock, flags);
+               while (status) {
+                       u32 hwirq = ffs(status) - 1;
+                       u32 virq = irq_linear_revmap(d, hwirq +
+                                                    i * GPIO_PER_REG);

Use irq_find_mapping() instead please.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 583

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+                       generic_handle_irq(virq);
+                       status &= ~(1 << hwirq);

Why not status &= ~BIT(hwirq);

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 586

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+               }
+       }
+       chained_irq_exit(chip, desc);

Apart from that nice, it re-reads status on every iteration which is good.

Quoted 6 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +6 -0
+static int armada_37xx_irqchip_register(struct platform_device *pdev,
+                                       struct armada_37xx_pinctrl *info)
+{
+       struct device_node *np = info->dev->of_node;
+       int nrirqs = info->data->nr_pins;
+       struct gpio_chip *gc = &info->gpio_chip;

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 604

Quoted 10 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +10 -0
+       struct irq_chip *irqchip = &info->irq_chip;
+       struct resource res;
+       int ret, i, nr_irq_parent;
+
+       for_each_child_of_node(info->dev->of_node, np) {
+               if (of_find_property(np, "gpio-controller", NULL)) {
+                       ret = 0;
+                       break;
+               }
+       };

Now there is this thing again looping over the nodes.

Review

Quoted 2 lines
(quoted diff) +2 -0
+       if (ret)
+               return ret;

ret may be used uninitialized here, if you loop over all nodes and do not find any "gpio-controller".

The static code checks will just scream about this.

(Please fix in the other patch as well if present there.)

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 614

Quoted 7 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +7 -0
+       nr_irq_parent = of_irq_count(np);
+       spin_lock_init(&info->irq_lock);
+
+       if (!nr_irq_parent) {
+               dev_err(&pdev->dev, "Invalid or no IRQ\n");
+               return 0;
+       }

What if it is > 1? That doesn't seem to work but will pass this check silently.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 633

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       ret = gpiochip_irqchip_add(gc, irqchip, 0,
+                                  handle_level_irq, IRQ_TYPE_NONE);

If you also set up the handler in .set_type() you can assign handle_bad_irq() here and let .set_type set the right handler as e.g. drivers/gpio/gpio-pl061.c.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 643

Quoted 5 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +5 -0
+       for (i = 0; i < nrirqs; i++) {
+               struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+               d->mask = 1 << (i % GPIO_PER_REG);
+       }

What is this? It looks like a big hack. At least put in a fat comment about what is going on and why.

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 646

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       for (i = 0; i < nr_irq_parent; i++) {
+               int irq = irq_of_parse_and_map(np, i);

I think gpiochip_irqchip_add() will do this for you already, as it calls irq_create_mapping() for all offsets which will call irq_of_parse_and_map() am I right?

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 653

Quoted 7 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +7 -0
+
+               if (irq < 0)
+                       continue;
+
+               gpiochip_set_chained_irqchip(gc, irqchip, irq,
+                                            armada_37xx_irq_handler);
+       }

So only this statement for each IRQ should be all right.

I think this driver needs a bit of tinkering and refining.

Yours,
Linus Walleij

#13 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Hi Linus,

Quoted 13 lines · Linus Walleij
Quoted 10 lines · Gregory CLEMENT

The Armada 37xx SoCs can handle interrupt through GPIO. However it can only manage the edge ones.

The way the interrupt are managed are classical so we can use the generic interrupt chip model.

The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them.

Quoted 5 lines
Quoted 1 line

You need something in your Kconfig
doing select GPIOLIB_IRQCHIP unless there is
something I miss here.

I forgot to add it, I will do it in the v4.

Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c line 37

Quoted 4 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+#define IRQ_EN         0x0
+#define IRQ_POL                0x08
+#define IRQ_STATUS     0x10

This just cries out to me that there is a register 0x0c and I bet it handles edges vs levels so you could also implement level IRQs. Am I right?

Unfortunately, no :(

As far as I know there is now way to handle level. The 0xc register is the IRQ_POL for the GPIO above 32.

Quoted 10 lines
Quoted 3 lines
(quoted diff) +1 -1
-       aramda_37xx_update_reg(&reg, offset);
+       armada_37xx_update_reg(&reg, offset);

(...)

Review

Quoted 2 lines
(quoted diff) +1 -1
-       aramda_37xx_update_reg(&reg, offset);
+       armada_37xx_update_reg(&reg, offset);

These spelling fixes, do not do them in this patch, fix the first patch adding them
instead. It's super-confusing. Applies everywhere.

It was a typo (too much 'a' in the same word) that I properly fixed in the v3. (But I still need to fix the title of the patch in the v4)

Quoted 16 lines
Quoted 16 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +16 -0
+static void armada_37xx_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
+       struct irq_domain *d = gc->irqdomain;
+       int i;
+
+       chained_irq_enter(chip, desc);
+       for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) {
+               u32 status;
+               unsigned long flags;
+
+               spin_lock_irqsave(&info->irq_lock, flags);
+               status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
+               /* Manage only the interrupt that was enabled */
Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 580

Quoted 6 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +6 -0
+               status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
+               spin_unlock_irqrestore(&info->irq_lock, flags);
+               while (status) {
+                       u32 hwirq = ffs(status) - 1;
+                       u32 virq = irq_linear_revmap(d, hwirq +
+                                                    i * GPIO_PER_REG);

Use irq_find_mapping() instead please.

As we are in the interrupt handler I chose to use this function because according to its documentation: "This is a fast path alternative to irq_find_mapping() that can be called directly by irq controller code to save a handful of instructions".

The only restriction is "It is always safe to call, but won't find irqs mapped using the radix tree.". So I think that for this driver it is okay.

Quoted 5 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 583

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+                       generic_handle_irq(virq);
+                       status &= ~(1 << hwirq);

Why not status &= ~BIT(hwirq);

OK

Quoted 18 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 586

Quoted 4 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +3 -0
+               }
+       }
+       chained_irq_exit(chip, desc);

Apart from that nice, it re-reads status on every iteration which is good.

Quoted 10 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +10 -0
+static int armada_37xx_irqchip_register(struct platform_device *pdev,
+                                       struct armada_37xx_pinctrl *info)
+{
+       struct device_node *np = info->dev->of_node;
+       int nrirqs = info->data->nr_pins;
+       struct gpio_chip *gc = &info->gpio_chip;
+       struct irq_chip *irqchip = &info->irq_chip;
+       struct resource res;
+       int ret, i, nr_irq_parent;
+
Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 604

Quoted 6 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +6 -0
+       for_each_child_of_node(info->dev->of_node, np) {
+               if (of_find_property(np, "gpio-controller", NULL)) {
+                       ret = 0;
+                       break;
+               }
+       };

Now there is this thing again looping over the nodes.

As explained in the other patch we will only have one GPIO subnode.

Quoted 10 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+       if (ret)
+               return ret;

ret may be used uninitialized here, if you loop over all nodes and do not find any "gpio-controller".

The static code checks will just scream about this.

(Please fix in the other patch as well if present there.)

OK

Quoted 11 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 614

Quoted 8 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +7 -0
+       nr_irq_parent = of_irq_count(np);
+       spin_lock_init(&info->irq_lock);
+
+       if (!nr_irq_parent) {
+               dev_err(&pdev->dev, "Invalid or no IRQ\n");
+               return 0;
+       }

What if it is > 1? That doesn't seem to work but will pass this check silently.

If we have nr_irq_parent > 1, it will work and it is actually expected.

Quoted 7 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 633

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       ret = gpiochip_irqchip_add(gc, irqchip, 0,
+                                  handle_level_irq, IRQ_TYPE_NONE);

If you also set up the handler in .set_type() you can assign handle_bad_irq() here and let .set_type set the right handler as e.g. drivers/gpio/gpio-pl061.c.

Well the hardware can only manage the edge trigger, so there is no benefit to modify it each time we want to change the kind of edge we want (raising or falling). But your comment make me realized that I used the wrong one, I will move to handle_edge_irq in the v4.

Quoted 9 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 643

Quoted 6 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +5 -0
+       for (i = 0; i < nrirqs; i++) {
+               struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+               d->mask = 1 << (i % GPIO_PER_REG);
+       }

What is this? It looks like a big hack. At least put in a fat comment about what is going on and why.

I can reuse a part of the commit log here: "The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them."

Quoted 7 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 646

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       for (i = 0; i < nr_irq_parent; i++) {
+               int irq = irq_of_parse_and_map(np, i);

I think gpiochip_irqchip_add() will do this for you already, as it calls irq_create_mapping() for all offsets which will call irq_of_parse_and_map() am I right?

After reading the code, it doesn't seem it is the case. At least there is no irq_of_parse_and_map() call from gpiochip_irqchip_add(). And waht we need here is to associate each IRQ to the same GPIO handler.

I can still try without this line to confirm it.

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#14 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Quoted 7 lines · Gregory CLEMENT
Quoted 4 lines · Linus Walleij

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 580

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+                       u32 virq = irq_linear_revmap(d, hwirq +
+                                                    i * GPIO_PER_REG);

Use irq_find_mapping() instead please.

Quoted 8 lines

As we are in the interrupt handler I chose to use this function because according to its documentation: "This is a fast path alternative to irq_find_mapping() that can be called directly by irq controller code to save a handful of instructions".

The only restriction is "It is always safe to call, but won't find irqs mapped using the radix tree.". So I think that for this driver it is okay.

So you are relying on the core code in gpiolib to select a linear map. That is implicit semantics, and either all drivers using GPIOLIB_IRQCHIP should be changed to irq_linear_revmap() or all stay with irq_find_mapping().

In this case, I doubt it that you are actually so timing critical that it matters. Please use irq_find_mapping().

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +7 -0
+       nr_irq_parent = of_irq_count(np);
+       spin_lock_init(&info->irq_lock);
+
+       if (!nr_irq_parent) {
+               dev_err(&pdev->dev, "Invalid or no IRQ\n");
+               return 0;
+       }
Quoted 4 lines
Quoted 2 lines

What if it is > 1? That doesn't seem to work but will pass this check silently.

If we have nr_irq_parent > 1, it will work and it is actually expected.

Ah, I get it. Nice.

Quoted 11 lines
Quoted 6 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 633

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       ret = gpiochip_irqchip_add(gc, irqchip, 0,
+                                  handle_level_irq, IRQ_TYPE_NONE);

If you also set up the handler in .set_type() you can assign handle_bad_irq() here and let .set_type set the right handler as e.g. drivers/gpio/gpio-pl061.c.

Well the hardware can only manage the edge trigger, so there is no benefit to modify it each time we want to change the kind of edge we want (raising or falling). But your comment make me realized that I used the wrong one, I will move to handle_edge_irq in the v4.

Ooops, yeah handle_edge_irq() is what calls the ACK callback.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +5 -0
+       for (i = 0; i < nrirqs; i++) {
+               struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+               d->mask = 1 << (i % GPIO_PER_REG);
+       }
Quoted 7 lines
Quoted 2 lines

What is this? It looks like a big hack. At least put in a fat comment about what is going on and why.

I can reuse a part of the commit log here: "The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them."

What you're doing is mocking around with core irqchip semantics. Is ->mask really supposed to be played around with from the outsid like this?

Anyways: BIT(i % GPIO_PER_REG) is nicer.

Quoted 7 lines
Quoted 6 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 646

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       for (i = 0; i < nr_irq_parent; i++) {
+               int irq = irq_of_parse_and_map(np, i);

I think gpiochip_irqchip_add() will do this for you already, as it calls irq_create_mapping() for all offsets which will call irq_of_parse_and_map() am I right?

Quoted 5 lines

After reading the code, it doesn't seem it is the case. At least there is no irq_of_parse_and_map() call from gpiochip_irqchip_add(). And waht we need here is to associate each IRQ to the same GPIO handler.

I can still try without this line to confirm it.

It has irq_create_mapping(gpiochip->irqdomain, offset); that get called for every IRQ, and that will eventually call irq_of_parse_and_map() if the IRQs are defined in the device tree. (IIRC)

Yours,
Linus Walleij

#15 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Hi Linus,

Quoted 18 lines · Linus Walleij
Quoted 7 lines · Gregory CLEMENT
Quoted 4 lines · Linus Walleij

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 580

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+                       u32 virq = irq_linear_revmap(d, hwirq +
+                                                    i * GPIO_PER_REG);

Use irq_find_mapping() instead please.

Quoted 8 lines

As we are in the interrupt handler I chose to use this function because according to its documentation: "This is a fast path alternative to irq_find_mapping() that can be called directly by irq controller code to save a handful of instructions".

The only restriction is "It is always safe to call, but won't find irqs mapped using the radix tree.". So I think that for this driver it is okay.

Quoted 7 lines

So you are relying on the core code in gpiolib to select a linear map. That is implicit semantics, and either all drivers using GPIOLIB_IRQCHIP should be changed to irq_linear_revmap() or all stay with irq_find_mapping().

In this case, I doubt it that you are actually so timing critical that it matters. Please use irq_find_mapping().

OK

Quoted 23 lines
Quoted 11 lines
Quoted 6 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 633

Quoted 2 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       ret = gpiochip_irqchip_add(gc, irqchip, 0,
+                                  handle_level_irq, IRQ_TYPE_NONE);

If you also set up the handler in .set_type() you can assign handle_bad_irq() here and let .set_type set the right handler as e.g. drivers/gpio/gpio-pl061.c.

Well the hardware can only manage the edge trigger, so there is no benefit to modify it each time we want to change the kind of edge we want (raising or falling). But your comment make me realized that I used the wrong one, I will move to handle_edge_irq in the v4.

Ooops, yeah handle_edge_irq() is what calls the ACK callback.

Quoted 9 lines
Quoted 8 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 643

Quoted 5 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +5 -0
+       for (i = 0; i < nrirqs; i++) {
+               struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+               d->mask = 1 << (i % GPIO_PER_REG);
+       }

What is this? It looks like a big hack. At least put in a fat comment about what is going on and why.

Quoted 8 lines
Quoted 4 lines

I can reuse a part of the commit log here: "The only unusual "feature" is that many interrupts are connected to the parent interrupt controller. But we do not take advantage of this and use the chained irq with all of them."

What you're doing is mocking around with core irqchip semantics. Is ->mask really supposed to be played around with from the outsid like this?

According to the documentation mask is a "precomputed bitmask for accessing the chip registers" and it is exactly the way it is used in this driver.

Moreover, currently ->mask is only used by the generic irqchip framework and not by the core of the irqchip subsystem. So the mask initialization is not done from the oustide but at the same level as the generic irqchip which is not used here.

Quoted 1 line

Anyways: BIT(i % GPIO_PER_REG) is nicer.

OK

Quoted 12 lines
Quoted 12 lines
Quoted 7 lines

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c static const struct gpio_chip armada_37xx_gpiolib_chip = { · line 646

Quoted 3 lines
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +2 -0
+       for (i = 0; i < nr_irq_parent; i++) {
+               int irq = irq_of_parse_and_map(np, i);

I think gpiochip_irqchip_add() will do this for you already, as it calls irq_create_mapping() for all offsets which will call irq_of_parse_and_map() am I right?

After reading the code, it doesn't seem it is the case. At least there is no irq_of_parse_and_map() call from gpiochip_irqchip_add(). And waht we need here is to associate each IRQ to the same GPIO handler.

Quoted 5 lines
Quoted 1 line

I can still try without this line to confirm it.

It has irq_create_mapping(gpiochip->irqdomain, offset); that get called for every IRQ, and that will eventually call irq_of_parse_and_map() if the IRQs are defined in the device tree. (IIRC)

When I followed the functions called I never find a call to irq_of_parse_and_map(), the closer things related to device tree I found was:
"virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);"
http://elixir.free-electrons.com/source/kernel/irq/irqdomain.c?v=4.11-rc4#L507

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#16 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Quoted 6 lines · Gregory CLEMENT
Quoted 3 lines · Linus Walleij

What you're doing is mocking around with core irqchip semantics. Is ->mask really supposed to be played around with from the outsid like this?

Quoted 8 lines

According to the documentation mask is a "precomputed bitmask for accessing the chip registers" and it is exactly the way it is used in this driver.

Moreover, currently ->mask is only used by the generic irqchip framework and not by the core of the irqchip subsystem. So the mask initialization is not done from the oustide but at the same level as the generic irqchip which is not used here.

OK excellent, sorry for my ignorance. We should rather point to your driver as a good example of how to do this. Care to add some few lines of comment as to what is going on for others that need to do the same?

Actually it would even be good to have something in Documentation/gpio/driver.txt

Quoted 10 lines
Quoted 3 lines

It has irq_create_mapping(gpiochip->irqdomain, offset); that get called for every IRQ, and that will eventually call irq_of_parse_and_map() if the IRQs are defined in the device tree. (IIRC)

When I followed the functions called I never find a call to irq_of_parse_and_map(), the closer things related to device tree I found was:
"virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);"
http://elixir.free-electrons.com/source/kernel/irq/irqdomain.c?v=4.11-rc4#L507

I don't know if I'm rambling or what. I'm pretty sure it gets called, maybe even earlier, like when the DT is parsed for the platform. We have so many drivers not seemingly needing this, but if your driver needs it, all others may need to be fixed too.

Can you put a print in irq_of_parse_and_map() and see what happens?

Yours,
Linus Walleij

#17 lore raw

Re: [PATCH v2 5/7] pinctrl: aramda-37xx: Add irqchip support

Hi Linus,

Quoted 11 lines · Linus Walleij
Quoted 10 lines
Quoted 3 lines

It has irq_create_mapping(gpiochip->irqdomain, offset); that get called for every IRQ, and that will eventually call irq_of_parse_and_map() if the IRQs are defined in the device tree. (IIRC)

When I followed the functions called I never find a call to irq_of_parse_and_map(), the closer things related to device tree I found was:
"virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);"
http://elixir.free-electrons.com/source/kernel/irq/irqdomain.c?v=4.11-rc4#L507

Quoted 6 lines

I don't know if I'm rambling or what. I'm pretty sure it gets called, maybe even earlier, like when the DT is parsed for the platform. We have so many drivers not seemingly needing this, but if your driver needs it, all others may need to be fixed too.

Can you put a print in irq_of_parse_and_map() and see what happens?

So if I don't call it explicitly in my driver, then this function is never called for the gpio.

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#18 lore raw

PATCH v2 6/7 ARM64: dts: marvell: Add pinctrl nodes for Armada 3700

In reply to Gregory CLEMENT

Add the nodes for the two pin controller present in the Armada 37xx SoCs.

Initially the node was named gpio1 using the same name that for the register range in the datasheet. However renaming it pinctr_nb (nb for North Bridge) makes more sens.

---
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 40 +++++++++++++++++++--
 1 file changed, 37 insertions(+), 3 deletions(-)
arch/arm64/boot/dts/marvell/armada-37xx.dtsi +37 -3
index b48d668a6ab6..229946c57a07 100644
@@ -157,10 +157,28 @@
 				#clock-cells = <1>;
 			};
 
-			gpio1: gpio at 13800 {
-				compatible = "marvell,mvebu-gpio-3700",
+			pinctrl_nb: pinctrl-nb at 13800 {
+				compatible = "marvell,armada3710-nb-pinctrl",
 				"syscon", "simple-mfd";
-				reg = <0x13800 0x500>;
+				reg = <0x13800 0x100>, <0x13C00 0x20>;
+				gpionb: gpionb {
+					#gpio-cells = <2>;
+					gpio-controller;
+					interrupts =
+					<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+
+				};
 
 				xtalclk: xtal-clk {
 					compatible = "marvell,armada-3700-xtal-clock";
@@ -169,6 +187,22 @@
 				};
 			};
 
+			pinctrl_sb: pinctrl-sb at 18800 {
+				compatible = "marvell,armada3710-sb-pinctrl",
+				"syscon", "simple-mfd";
+				reg = <0x18800 0x100>, <0x18C00 0x20>;
+				gpiosb: gpiosb {
+					#gpio-cells = <2>;
+					gpio-controller;
+					interrupts =
+					<GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+				};
+			};
+
 			eth0: ethernet at 30000 {
 				   compatible = "marvell,armada-3700-neta";
 				   reg = <0x30000 0x4000>;
Signature · 1 line
git-series 0.9.1
#19 lore raw

PATCH v2 7/7 ARM64: dts: marvell: armada37xx: add pinctrl definition

In reply to Gregory CLEMENT

Start to populate the device tree of the Armada 37xx with the pincontrol configuration used on the board providing a dts.

---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts |  8 +++++-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi   | 31 +++++++++++++++++++-
 2 files changed, 39 insertions(+)
arch/arm64/boot/dts/marvell/armada-3720-db.dts +8 -0
index 86602c907a61..e749c5727490 100644
@@ -63,6 +63,8 @@
 };
 
 &i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	status = "okay";
 };
 
@@ -73,6 +75,8 @@
 
 &spi0 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_quad_pins>;
 
 	m25p80 at 0 {
 		compatible = "jedec,spi-nor";
@@ -103,6 +107,8 @@
 
 /* Exported on the micro USB connector CON32 through an FTDI */
 &uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
 	status = "okay";
 };
 
@@ -128,6 +134,8 @@
 };
 
 &eth0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
 	phy-mode = "rgmii-id";
 	phy = <&phy0>;
 	status = "okay";
arch/arm64/boot/dts/marvell/armada-37xx.dtsi +31 -0
index 229946c57a07..dbc842d9310f 100644
@@ -185,6 +185,31 @@
 					clock-output-names = "xtal";
 					#clock-cells = <0>;
 				};
+
+				spi_quad_pins: spi-quad-pins {
+					groups = "spi_quad";
+					function = "spi";
+				};
+
+				i2c1_pins: i2c1-pins {
+					groups = "i2c1";
+					function = "i2c";
+				};
+
+				i2c2_pins: i2c2-pins {
+					groups = "i2c2";
+					function = "i2c";
+				};
+
+				uart1_pins: uart1-pins {
+					groups = "uart1";
+					function = "uart";
+				};
+
+				uart2_pins: uart2-pins {
+					groups = "uart2";
+					function = "uart";
+				};
 			};
 
 			pinctrl_sb: pinctrl-sb at 18800 {
@@ -201,6 +226,12 @@
 					<GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
 					<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
 				};
+
+				rgmii_pins: mii-pins {
+					groups = "rgmii";
+					function = "mii";
+				};
+
 			};
 
 			eth0: ethernet at 30000 {
Signature · 1 line
git-series 0.9.1
#20 lore raw

v2 cover Add support for pinctrl/gpio on Armada 37xx Was Re: [PATCH v2 0/7] Hi,

In reply to Gregory CLEMENT

Hi,

Obviously this cover letter is wrong. Actually I forgot to commit it in git series. Here it is the correct one:

After several months here it is the second version of the series adding support for the pin and gpio controllers present on the Armada 37xx SoCs.

Each Armada 37xx SoC comes with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

In the second version several changes has been done:

- Update binding documentation making clear that mfd and syscon must be used (patch 1).

- Split the fist patch adding pin controller support for Armada 37xx in arm64 part (for kconfig) and pinctrl part (patch 2 and 3)

- Add MFD_SYSCON dependency (patch 3)

- Add kerneldoc for the armada_37xx_pin_group struct (patch 3)

- Rename _add_function() to armada_37xx_add_function() (patch 3)

- Use an inline function to update the reg offset (patch 4)

- Rename gpiolib_register to gpiochip_register (patch 4)

- Add a comment about the two registers limit (patch 4)

- Add explicit gpio node in the device tree (patch 4)

- Convert the driver to use GPIOLIB_IRQCHIP (patch 5)

- Add a critical section when accessing the hardware registers (patch 5)

- Use the gpio sub-node (patch 5)

With these change most of the comment of the first revision have been addressed.

Thanks,

Gregory

Gregory CLEMENT (7):
pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
arm64: marvell: enable the Armada 37xx pinctrl driver
pinctrl: armada-37xx: Add pin controller support for Armada 37xx
pinctrl: armada-37xx: Add gpio support
pinctrl: aramda-37xx: Add irqchip support
ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 +++++++++++-
 arch/arm64/Kconfig.platforms                                              |   2 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  71 +++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 918 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1153 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

Sorry for the noise,

Gregory

Quoted 38 lines · Gregory CLEMENT

this series add support for the pin and gpio controllers present on the Armada 37xx SoCs.

Each Armada 37xx SoC comes with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

Gregory

Gregory CLEMENT (7):
pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
arm64: marvell: enable the Armada 37xx pinctrl driver
pinctrl: armada-37xx: Add pin controller support for Armada 37xx
pinctrl: armada-37xx: Add gpio support
pinctrl: aramda-37xx: Add irqchip support
ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 +++++++++++-
 arch/arm64/Kconfig.platforms                                              |   2 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  71 +++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 918 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1153 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

base-commit: c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201

Signature · 1 line
git-series 0.9.1
Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#21 lore raw

Re: [PATCH v2 0/7] Add support for pinctrl/gpio on Armada 37xx Was Re: [PATCH v2 0/7] Hi,

Hi Linus,

Quoted 8 lines · Gregory CLEMENT

Hi,

Obviously this cover letter is wrong. Actually I forgot to commit it in git series. Here it is the correct one:

After several months here it is the second version of the series adding support for the pin and gpio controllers present on the Armada 37xx SoCs.

As the first version was sent in December here it is a link to it:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-December/475216.html

Also I am going to answer to your review to point what I have done in this new series.

Gregory

Quoted 121 lines

Each Armada 37xx SoC comes with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

In the second version several changes has been done:

- Update binding documentation making clear that mfd and syscon must be used (patch 1).

- Split the fist patch adding pin controller support for Armada 37xx in arm64 part (for kconfig) and pinctrl part (patch 2 and 3)

- Add MFD_SYSCON dependency (patch 3)

- Add kerneldoc for the armada_37xx_pin_group struct (patch 3)

- Rename _add_function() to armada_37xx_add_function() (patch 3)

- Use an inline function to update the reg offset (patch 4)

- Rename gpiolib_register to gpiochip_register (patch 4)

- Add a comment about the two registers limit (patch 4)

- Add explicit gpio node in the device tree (patch 4)

- Convert the driver to use GPIOLIB_IRQCHIP (patch 5)

- Add a critical section when accessing the hardware registers (patch 5)

- Use the gpio sub-node (patch 5)

With these change most of the comment of the first revision have been addressed.

Thanks,

Gregory

Gregory CLEMENT (7):
pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
arm64: marvell: enable the Armada 37xx pinctrl driver
pinctrl: armada-37xx: Add pin controller support for Armada 37xx
pinctrl: armada-37xx: Add gpio support
pinctrl: aramda-37xx: Add irqchip support
ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 +++++++++++-
 arch/arm64/Kconfig.platforms                                              |   2 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  71 +++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 918 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1153 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

Sorry for the noise,

Gregory

Quoted 38 lines · Gregory CLEMENT

this series add support for the pin and gpio controllers present on the Armada 37xx SoCs.

Each Armada 37xx SoC comes with 2 pin controllers: one on the south bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

Gregory

Gregory CLEMENT (7):
pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
arm64: marvell: enable the Armada 37xx pinctrl driver
pinctrl: armada-37xx: Add pin controller support for Armada 37xx
pinctrl: armada-37xx: Add gpio support
pinctrl: aramda-37xx: Add irqchip support
ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 143 +++++++++++-
 arch/arm64/Kconfig.platforms                                              |   2 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  71 +++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 918 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1153 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

base-commit: c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201

Signature · 1 line
git-series 0.9.1
Signature · 9 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com