Skip to contentSkip to conversation

support pinconf in pinctrl single driver

PATCH Superseded Haojian Zhuang 8 participants 51 messages Jan 18, 2013 – Feb 9, 2013

Subsystems (5)

v7 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Haojian Zhuang

author maintainer
#0 lore raw

v7 cover support pinconf in pinctrl single driver

Changelog:
v7:
1. Discard the method of adding gpio range from pinctrl-single driver. Use gpiolib driver to support gpio range from DTS instead.
2. Add gpio request function to claim pin in gpio pl061 driver.
3. Adjust the initcall level in gpio pl061 driver.
4. Allocate gpio number from lowest gpio number to highest. The original implementation is inverted. It's hard to use since it inverted the sequence of gpio number.
5. Remove the support of pxa910 temporarily since gpio pxa driver need to be updated for supporting this solution.

v6:
1. Two configuration array will be created for each pin group. This first array is stored in pcs_function structure. The 32-bit configruation argument is stored in this array. Driver stores data while parsing DTS file, and loads these config array if function selector is indicated.
The second array is stored in pinctrl_map structure. Driver won't use it directly. So we could avoid to append lookup pinctrl map method that is introduced in v5.

v5:
1. Move the properties of pinconf into pin group. So those mask properties could be merged with other pinconf properties.
2. Append lookup pinctrl map method.
3. Append input schmitt disable config parameter.
4. Clean code.

v4:
1. Define gpio range as sub-node, not label. And remove pinctrl-single,gpio-ranges property.
2. Use new two properties in sub-node, reg & pinctrl-single,gpio. GPIO number & GPIO function are listed in the pinctrl-single,gpio property.
3. Reference the names like pinctrl-single,bias.
4. Add compatible name "pinconf-single". If the compatible name is "pinctrl-single", there's no pinconf. If the compatible name is "pinconf-single", there's the generic pinconf in pinctrl-single.
5. Update documents.

v3:
1. Add more comments in document.
2. Replace pcs_readl() & pcs_writel() by pcs->read() & pcs->write().
3. Clean code.

v2:
1. Remove "pinctrl-single,gpio-mask". Since GPIO function is one of the mux function in the pinmux register of both OMAP and PXA/MMP silicons. Use "pinctrl-single,function-mask" instead.

author maintainer
#1 lore raw

PATCH v7 1/15 Revert "pinctrl: single: support gpio request and free"

This reverts commit 2e8b2eab94c35d83bb7da71c63b4695f32ddca88.

Conflicts:
drivers/pinctrl/pinctrl-single.c

ERROR: "__aeabi_uldivmod" [drivers/pinctrl/pinctrl-single.ko] undefined!]

Quoted 7 lines · Russell King

The above error happens in builds including pinctrl-single - the reason
is this, where resource_size_t may be 64-bit.

                gpio->range.pin_base = (r.start - pcs->res->start) /
                mux_bytes;
                gpio->range.npins = (r.end - r.start) / mux_bytes + 1;

The reason of not fixing this issue and reverting the patch instead is this patch can't handle another case. It's not easy to handle multiple gpios sharing one pin register. So this gpio range feature will be implemented by other patches.

---
 drivers/pinctrl/pinctrl-single.c |   79 +-------------------------------------
 1 file changed, 2 insertions(+), 77 deletions(-)
drivers/pinctrl/pinctrl-single.c +2 -77
index f6a360b..5c32e88 100644
@@ -30,7 +30,6 @@
 #define PCS_MUX_BITS_NAME		"pinctrl-single,bits"
 #define PCS_REG_NAME_LEN		((sizeof(unsigned long) * 2) + 1)
 #define PCS_OFF_DISABLED		~0U
-#define PCS_MAX_GPIO_VALUES		2
 
 /**
  * struct pcs_pingroup - pingroups for a function
@@ -78,16 +77,6 @@ struct pcs_function {
 };
 
 /**
- * struct pcs_gpio_range - pinctrl gpio range
- * @range:	subrange of the GPIO number space
- * @gpio_func:	gpio function value in the pinmux register
- */
-struct pcs_gpio_range {
-	struct pinctrl_gpio_range range;
-	int gpio_func;
-};
-
-/**
  * struct pcs_data - wrapper for data needed by pinctrl framework
  * @pa:		pindesc array
  * @cur:	index to current element
@@ -414,26 +403,9 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-			    struct pinctrl_gpio_range *range, unsigned pin)
+			struct pinctrl_gpio_range *range, unsigned offset)
 {
-	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
-	struct pcs_gpio_range *gpio = NULL;
-	int end, mux_bytes;
-	unsigned data;
-
-	gpio = container_of(range, struct pcs_gpio_range, range);
-	end = range->pin_base + range->npins - 1;
-	if (pin < range->pin_base || pin > end) {
-		dev_err(pctldev->dev,
-			"pin %d isn't in the range of %d to %d\n",
-			pin, range->pin_base, end);
-		return -EINVAL;
-	}
-	mux_bytes = pcs->width / BITS_PER_BYTE;
-	data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
-	data |= gpio->gpio_func;
-	pcs->write(data, pcs->base + pin * mux_bytes);
-	return 0;
+	return -ENOTSUPP;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -907,49 +879,6 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
-static int pcs_add_gpio_range(struct device_node *node, struct pcs_device *pcs)
-{
-	struct pcs_gpio_range *gpio;
-	struct device_node *child;
-	struct resource r;
-	const char name[] = "pinctrl-single";
-	u32 gpiores[PCS_MAX_GPIO_VALUES];
-	int ret, i = 0, mux_bytes = 0;
-
-	for_each_child_of_node(node, child) {
-		ret = of_address_to_resource(child, 0, &r);
-		if (ret < 0)
-			continue;
-		memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
-		ret = of_property_read_u32_array(child, "pinctrl-single,gpio",
-						 gpiores, PCS_MAX_GPIO_VALUES);
-		if (ret < 0)
-			continue;
-		gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
-		if (!gpio) {
-			dev_err(pcs->dev, "failed to allocate pcs gpio\n");
-			return -ENOMEM;
-		}
-		gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
-						GFP_KERNEL);
-		if (!gpio->range.name) {
-			dev_err(pcs->dev, "failed to allocate range name\n");
-			return -ENOMEM;
-		}
-		memcpy((char *)gpio->range.name, name, sizeof(name));
-
-		gpio->range.id = i++;
-		gpio->range.base = gpiores[0];
-		gpio->gpio_func = gpiores[1];
-		mux_bytes = pcs->width / BITS_PER_BYTE;
-		gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes;
-		gpio->range.npins = (r.end - r.start) / mux_bytes + 1;
-
-		pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
-	}
-	return 0;
-}
-
 static int pcs_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -1046,10 +975,6 @@ static int pcs_probe(struct platform_device *pdev)
 		goto free;
 	}
 
-	ret = pcs_add_gpio_range(np, pcs);
-	if (ret < 0)
-		goto free;
-
 	dev_info(pcs->dev, "%i pins at pa %p size %u\n",
 		 pcs->desc.npins, pcs->base, pcs->size);
 
Signature · 1 line
1.7.10.4
maintainer
#2 lore raw

PATCH v7 1/15 Revert "pinctrl: single: support gpio request and free"

Quoted 14 lines · Haojian Zhuang

This reverts commit 2e8b2eab94c35d83bb7da71c63b4695f32ddca88.

Conflicts:
drivers/pinctrl/pinctrl-single.c

ERROR: "__aeabi_uldivmod" [drivers/pinctrl/pinctrl-single.ko] undefined!]

Quoted 4 lines · Russell King

The above error happens in builds including pinctrl-single - the reason
is this, where resource_size_t may be 64-bit.

Quoted 8 lines
Quoted 3 lines
                gpio->range.pin_base = (r.start - pcs->res->start) /
                mux_bytes;
                gpio->range.npins = (r.end - r.start) / mux_bytes + 1;

The reason of not fixing this issue and reverting the patch instead is this patch can't handle another case. It's not easy to handle multiple gpios sharing one pin register. So this gpio range feature will be implemented by other patches.

Makes sense to me, I don't think we have any users yet for this:

Quoted 126 lines
---
 drivers/pinctrl/pinctrl-single.c |   79 +-------------------------------------
 1 file changed, 2 insertions(+), 77 deletions(-)
drivers/pinctrl/pinctrl-single.c +2 -77
index f6a360b..5c32e88 100644
@@ -30,7 +30,6 @@
 #define PCS_MUX_BITS_NAME		"pinctrl-single,bits"
 #define PCS_REG_NAME_LEN		((sizeof(unsigned long) * 2) + 1)
 #define PCS_OFF_DISABLED		~0U
-#define PCS_MAX_GPIO_VALUES		2
 
 /**
  * struct pcs_pingroup - pingroups for a function
@@ -78,16 +77,6 @@ struct pcs_function {
 };
 
 /**
- * struct pcs_gpio_range - pinctrl gpio range
- * @range:	subrange of the GPIO number space
- * @gpio_func:	gpio function value in the pinmux register
- */
-struct pcs_gpio_range {
-	struct pinctrl_gpio_range range;
-	int gpio_func;
-};
-
-/**
  * struct pcs_data - wrapper for data needed by pinctrl framework
  * @pa:		pindesc array
  * @cur:	index to current element
@@ -414,26 +403,9 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-			    struct pinctrl_gpio_range *range, unsigned pin)
+			struct pinctrl_gpio_range *range, unsigned offset)
 {
-	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
-	struct pcs_gpio_range *gpio = NULL;
-	int end, mux_bytes;
-	unsigned data;
-
-	gpio = container_of(range, struct pcs_gpio_range, range);
-	end = range->pin_base + range->npins - 1;
-	if (pin < range->pin_base || pin > end) {
-		dev_err(pctldev->dev,
-			"pin %d isn't in the range of %d to %d\n",
-			pin, range->pin_base, end);
-		return -EINVAL;
-	}
-	mux_bytes = pcs->width / BITS_PER_BYTE;
-	data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
-	data |= gpio->gpio_func;
-	pcs->write(data, pcs->base + pin * mux_bytes);
-	return 0;
+	return -ENOTSUPP;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -907,49 +879,6 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
-static int pcs_add_gpio_range(struct device_node *node, struct pcs_device *pcs)
-{
-	struct pcs_gpio_range *gpio;
-	struct device_node *child;
-	struct resource r;
-	const char name[] = "pinctrl-single";
-	u32 gpiores[PCS_MAX_GPIO_VALUES];
-	int ret, i = 0, mux_bytes = 0;
-
-	for_each_child_of_node(node, child) {
-		ret = of_address_to_resource(child, 0, &r);
-		if (ret < 0)
-			continue;
-		memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
-		ret = of_property_read_u32_array(child, "pinctrl-single,gpio",
-						 gpiores, PCS_MAX_GPIO_VALUES);
-		if (ret < 0)
-			continue;
-		gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
-		if (!gpio) {
-			dev_err(pcs->dev, "failed to allocate pcs gpio\n");
-			return -ENOMEM;
-		}
-		gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
-						GFP_KERNEL);
-		if (!gpio->range.name) {
-			dev_err(pcs->dev, "failed to allocate range name\n");
-			return -ENOMEM;
-		}
-		memcpy((char *)gpio->range.name, name, sizeof(name));
-
-		gpio->range.id = i++;
-		gpio->range.base = gpiores[0];
-		gpio->gpio_func = gpiores[1];
-		mux_bytes = pcs->width / BITS_PER_BYTE;
-		gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes;
-		gpio->range.npins = (r.end - r.start) / mux_bytes + 1;
-
-		pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
-	}
-	return 0;
-}
-
 static int pcs_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -1046,10 +975,6 @@ static int pcs_probe(struct platform_device *pdev)
 		goto free;
 	}
 
-	ret = pcs_add_gpio_range(np, pcs);
-	if (ret < 0)
-		goto free;
-
 	dev_info(pcs->dev, "%i pins at pa %p size %u\n",
 		 pcs->desc.npins, pcs->base, pcs->size);
 
Signature · 1 line
1.7.10.4
#3 lore raw

PATCH v7 1/15 Revert "pinctrl: single: support gpio request and free"

In reply to Haojian Zhuang
Quoted 7 lines · Haojian Zhuang

This reverts commit 2e8b2eab94c35d83bb7da71c63b4695f32ddca88.

Conflicts:
drivers/pinctrl/pinctrl-single.c

ERROR: "__aeabi_uldivmod" [drivers/pinctrl/pinctrl-single.ko] undefined!]

Applied to fixes with Tony's ACK.

I also took the liberty to add your Signed-off-by.

Yours,
Linus Walleij

author maintainer
#4 lore raw

PATCH v7 2/15 pinctrl: core: get devname from pinctrl_dev

In reply to Haojian Zhuang

Add new function to get devname from pinctrl_dev. pinctrl_dev_get_name() can only get pinctrl description name. If we want to use gpio driver to find pinctrl device node, we need to fetch the pinctrl device name.

---
 drivers/pinctrl/core.c          |    6 ++++++
 include/linux/pinctrl/pinctrl.h |    1 +
 2 files changed, 7 insertions(+)
drivers/pinctrl/core.c +6 -0
index 59f5a96..e7378a1 100644
@@ -83,6 +83,12 @@ const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
 }
 EXPORT_SYMBOL_GPL(pinctrl_dev_get_name);
 
+const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev)
+{
+	return dev_name(pctldev->dev);
+}
+EXPORT_SYMBOL_GPL(pinctrl_dev_get_devname);
+
 void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev)
 {
 	return pctldev->driver_data;
include/linux/pinctrl/pinctrl.h +1 -0
index 04d6700..778804d 100644
@@ -154,6 +154,7 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
 #endif /* CONFIG_OF */
 
 extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+extern const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev);
 extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
 #else
 
Signature · 1 line
1.7.10.4
#5 lore raw

PATCH v7 2/15 pinctrl: core: get devname from pinctrl_dev

Quoted 5 lines · Haojian Zhuang

Add new function to get devname from pinctrl_dev. pinctrl_dev_get_name() can only get pinctrl description name. If we want to use gpio driver to find pinctrl device node, we need to fetch the pinctrl device name.

Looks helpful in its own right, patch applied!

Yours,
Linus Walleij

author maintainer
#6 lore raw

PATCH v7 3/15 gpio: use pinctrl device name for add range

In reply to Haojian Zhuang

gpiochip_add_pin_range() needs pinctrl device name as parameter. Currently the parameter is pinctrl description name. So fix it.

---
 drivers/gpio/gpiolib-of.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib-of.c +1 -1
index d542a14..25b1dbe 100644
@@ -250,7 +250,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 		 * on the same GPIO chip.
 		 */
 		ret = gpiochip_add_pin_range(chip,
-					     pinctrl_dev_get_name(pctldev),
+					     pinctrl_dev_get_devname(pctldev),
 					     0, /* offset in gpiochip */
 					     pinspec.args[0],
 					     pinspec.args[1]);
Signature · 1 line
1.7.10.4
#7 lore raw

PATCH v7 3/15 gpio: use pinctrl device name for add range

Quoted 13 lines · Haojian Zhuang

gpiochip_add_pin_range() needs pinctrl device name as parameter. Currently the parameter is pinctrl description name. So fix it.

---
 drivers/gpio/gpiolib-of.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib-of.c +0 -0
index d542a14..25b1dbe 100644

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 256

Quoted 8 lines
drivers/gpio/gpiolib-of.c +1 -1
@@ -250,7 +250,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
                 * on the same GPIO chip.
                 */
                ret = gpiochip_add_pin_range(chip,
-                                            pinctrl_dev_get_name(pctldev),
+                                            pinctrl_dev_get_devname(pctldev),
                                             0, /* offset in gpiochip */
                                             pinspec.args[0],
                                             pinspec.args[1]);

Hm looks like the right thing to do!

Patch applied.

It must be such that everyone using this so far has just set the name to be identical to the device name.

Maybe we should just drop the name in the descriptor if it's causing problems like this?

Yours,
Linus Walleij

author maintainer
#8 lore raw

PATCH v7 3/15 gpio: use pinctrl device name for add range

Quoted 29 lines · Linus Walleij
Quoted 13 lines · Haojian Zhuang

gpiochip_add_pin_range() needs pinctrl device name as parameter. Currently the parameter is pinctrl description name. So fix it.

---
 drivers/gpio/gpiolib-of.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib-of.c +0 -0
index d542a14..25b1dbe 100644

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 256

Quoted 8 lines
drivers/gpio/gpiolib-of.c +1 -1
@@ -250,7 +250,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
                 * on the same GPIO chip.
                 */
                ret = gpiochip_add_pin_range(chip,
-                                            pinctrl_dev_get_name(pctldev),
+                                            pinctrl_dev_get_devname(pctldev),
                                             0, /* offset in gpiochip */
                                             pinspec.args[0],
                                             pinspec.args[1]);

Hm looks like the right thing to do!

Patch applied.

Quoted 8 lines

It must be such that everyone using this so far has just set the name to be identical to the device name.

Maybe we should just drop the name in the descriptor if it's causing problems like this?

Yours,
Linus Walleij

It seems that dropping the name won't impact any problem. I'll try to drop it in new patches.

Regards
Haojian

author maintainer
#9 lore raw

PATCH v7 4/15 gpio: set gpio range cells property as 3

In reply to Haojian Zhuang

Add gpio offset into "gpio-range-cells" property. It's used to support sparse pinctrl range in gpio chip.

---
 Documentation/devicetree/bindings/gpio/gpio.txt |    6 +++---
 arch/arm/boot/dts/spear1310.dtsi                |    4 ++--
 arch/arm/boot/dts/spear1340.dtsi                |    4 ++--
 arch/arm/boot/dts/spear310.dtsi                 |    4 ++--
 arch/arm/boot/dts/spear320.dtsi                 |    4 ++--
 drivers/gpio/gpiolib-of.c                       |    7 ++-----
 6 files changed, 13 insertions(+), 16 deletions(-)
Documentation/devicetree/bindings/gpio/gpio.txt +3 -3
index a336287..d933af3 100644
@@ -98,7 +98,7 @@ announce the pinrange to the pin ctrl subsystem. For example,
 		compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
 		reg = <0x1460 0x18>;
 		gpio-controller;
-		gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
+		gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
 
     }
 
@@ -107,8 +107,8 @@ where,
 
    Next values specify the base pin and number of pins for the range
    handled by 'qe_pio_e' gpio. In the given example from base pin 20 to
-   pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled
-   by this gpio controller.
+   pin 29 under pinctrl1 with gpio offset 0 and pin 50 to pin 69 under
+   pinctrl2 with gpio offset 10 is handled by this gpio controller.
 
 The pinctrl node must have "#gpio-range-cells" property to show number of
 arguments to pass with phandle from gpio controllers node.
arch/arm/boot/dts/spear1310.dtsi +2 -2
index 1513c19..122ae94 100644
@@ -89,7 +89,7 @@
 		pinmux: pinmux at e0700000 {
 			compatible = "st,spear1310-pinmux";
 			reg = <0xe0700000 0x1000>;
-			#gpio-range-cells = <2>;
+			#gpio-range-cells = <3>;
 		};
 
 		apb {
@@ -212,7 +212,7 @@
 				interrupt-controller;
 				gpio-controller;
 				#gpio-cells = <2>;
-				gpio-ranges = <&pinmux 0 246>;
+				gpio-ranges = <&pinmux 0 0 246>;
 				status = "disabled";
 
 				st-plgpio,ngpio = <246>;
arch/arm/boot/dts/spear1340.dtsi +2 -2
index 34da11a..c511c47 100644
@@ -63,7 +63,7 @@
 		pinmux: pinmux at e0700000 {
 			compatible = "st,spear1340-pinmux";
 			reg = <0xe0700000 0x1000>;
-			#gpio-range-cells = <2>;
+			#gpio-range-cells = <3>;
 		};
 
 		pwm: pwm at e0180000 {
@@ -127,7 +127,7 @@
 				interrupt-controller;
 				gpio-controller;
 				#gpio-cells = <2>;
-				gpio-ranges = <&pinmux 0 252>;
+				gpio-ranges = <&pinmux 0 0 252>;
 				status = "disabled";
 
 				st-plgpio,ngpio = <250>;
arch/arm/boot/dts/spear310.dtsi +2 -2
index ab45b8c..9537208 100644
@@ -25,7 +25,7 @@
 		pinmux: pinmux at b4000000 {
 			compatible = "st,spear310-pinmux";
 			reg = <0xb4000000 0x1000>;
-			#gpio-range-cells = <2>;
+			#gpio-range-cells = <3>;
 		};
 
 		fsmc: flash at 44000000 {
@@ -102,7 +102,7 @@
 				interrupt-controller;
 				gpio-controller;
 				#gpio-cells = <2>;
-				gpio-ranges = <&pinmux 0 102>;
+				gpio-ranges = <&pinmux 0 0 102>;
 				status = "disabled";
 
 				st-plgpio,ngpio = <102>;
arch/arm/boot/dts/spear320.dtsi +2 -2
index caa5520..ffea342 100644
@@ -24,7 +24,7 @@
 		pinmux: pinmux at b3000000 {
 			compatible = "st,spear320-pinmux";
 			reg = <0xb3000000 0x1000>;
-			#gpio-range-cells = <2>;
+			#gpio-range-cells = <3>;
 		};
 
 		clcd at 90000000 {
@@ -130,7 +130,7 @@
 				interrupt-controller;
 				gpio-controller;
 				#gpio-cells = <2>;
-				gpio-ranges = <&pinmux 0 102>;
+				gpio-ranges = <&pinmux 0 0 102>;
 				status = "disabled";
 
 				st-plgpio,ngpio = <102>;
drivers/gpio/gpiolib-of.c +2 -5
index 25b1dbe..b1f0682 100644
@@ -245,15 +245,12 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 		 * to add different ranges for one and the same GPIO chip,
 		 * as the code assumes that we have one consecutive range
 		 * on both, mapping 1-to-1.
-		 *
-		 * TODO: make the OF bindings handle multiple sparse ranges
-		 * on the same GPIO chip.
 		 */
 		ret = gpiochip_add_pin_range(chip,
 					     pinctrl_dev_get_devname(pctldev),
-					     0, /* offset in gpiochip */
 					     pinspec.args[0],
-					     pinspec.args[1]);
+					     pinspec.args[1],
+					     pinspec.args[2]);
 
 		if (ret)
 			break;
Signature · 1 line
1.7.10.4
#10 lore raw

PATCH v7 4/15 gpio: set gpio range cells property as 3

Quoted 4 lines · Haojian Zhuang

Add gpio offset into "gpio-range-cells" property. It's used to support sparse pinctrl range in gpio chip.

Need Shiraz to comment on this.

Yours,
Linus Walleij

author maintainer
#11 lore raw

PATCH v7 5/15 gpio: fix wrong checking condition for gpio range

In reply to Haojian Zhuang

Since index++ calculates from 0, the checking condition of "while (index++)" is always fake. So replace it by unconditional loop.

---
 drivers/gpio/gpiolib-of.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-of.c +3 -3
index b1f0682..011e1e98 100644
@@ -228,7 +228,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 	if (!np)
 		return;
 
-	do {
+	for (;;) {
 		ret = of_parse_phandle_with_args(np, "gpio-ranges",
 				"#gpio-range-cells", index, &pinspec);
 		if (ret)
@@ -254,8 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 
 		if (ret)
 			break;
-
-	} while (index++);
+		index++;
+	}
 }
 
 #else
Signature · 1 line
1.7.10.4
#12 lore raw

PATCH v7 5/15 gpio: fix wrong checking condition for gpio range

Hello.

Quoted 13 lines · Haojian Zhuang

Since index++ calculates from 0, the checking condition of "while (index++)" is always fake. So replace it by unconditional loop.

---
  drivers/gpio/gpiolib-of.c |    6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-of.c +0 -0
index b1f0682..011e1e98 100644

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 231

Quoted 5 lines
drivers/gpio/gpiolib-of.c +1 -1
@@ -228,7 +228,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
  	if (!np)
  		return;
 
-	do {
+	for (;;) {
    Why not:

	for (;; index++) {

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 259

Quoted 12 lines
drivers/gpio/gpiolib-of.c +2 -2
  		ret = of_parse_phandle_with_args(np, "gpio-ranges",
  				"#gpio-range-cells", index, &pinspec);
  		if (ret)
@@ -254,8 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 
  		if (ret)
  			break;
-
-	} while (index++);
+		index++;
+	}
  }

WBR, Sergei

author maintainer
#13 lore raw

PATCH v7 5/15 gpio: fix wrong checking condition for gpio range

Quoted 24 lines · Sergei Shtylyov

Hello.

Quoted 19 lines · Haojian Zhuang

Since index++ calculates from 0, the checking condition of "while (index++)" is always fake. So replace it by unconditional loop.

---
  drivers/gpio/gpiolib-of.c |    6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-of.c +0 -0
index b1f0682..011e1e98 100644
@@ -228,7 +228,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip
 *chip)
        if (!np)
                return;
 
Quoted 8 lines

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 231

Quoted 2 lines
drivers/gpio/gpiolib-of.c +1 -1
-       do {
+       for (;;) {
   Why not:

        for (;; index++) {

OK. I'll update it.

Quoted 18 lines
Quoted 5 lines
drivers/gpio/gpiolib-of.c +0 -0
                ret = of_parse_phandle_with_args(np, "gpio-ranges",
                                "#gpio-range-cells", index, &pinspec);

if (ret)

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip · line 260

Quoted 9 lines
drivers/gpio/gpiolib-of.c +2 -2
@@ -254,8 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip
 *chip)
 
                if (ret)
                        break;
-
-       } while (index++);
+               index++;
+       }
  }

WBR, Sergei

#14 lore raw

PATCH v7 5/15 gpio: fix wrong checking condition for gpio range

In reply to Haojian Zhuang
Quoted 2 lines · Haojian Zhuang

Since index++ calculates from 0, the checking condition of "while (index++)" is always fake.

You meanbt "false"? Actually if 'index' starts from 0, the loop will end
after the first iteration.

Quoted 21 lines

So replace it by unconditional loop.

---
  drivers/gpio/gpiolib-of.c |    6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-of.c +1 -1
index b1f0682..011e1e98 100644
@@ -228,7 +228,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
  	if (!np)
  		return;
 
-	do {
+	for (;;) {
  		ret = of_parse_phandle_with_args(np, "gpio-ranges",
  				"#gpio-range-cells", index, &pinspec);
  		if (ret)

drivers/gpio/gpiolib-of.c static void of_gpiochip_add_pin_range(struct gpio_chip *chip) · line 259

Quoted 8 lines
drivers/gpio/gpiolib-of.c +2 -2
@@ -254,8 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 
  		if (ret)
  			break;
-
-	} while (index++);
+		index++;
+	}
  }

WBR, Sergei

author maintainer
#15 lore raw

PATCH v7 6/15 gpio: find gpio base by ascend order

In reply to Haojian Zhuang

gpiochip_find_base() always tries to find valid gpio with descend order. It's inconvient if gpio information is passing from DTS. Now try to find valid gpio with ascend order.

---
 drivers/gpio/gpiolib.c |   19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)
drivers/gpio/gpiolib.c +10 -9
index 199fca1..8af57e7 100644
@@ -128,20 +128,21 @@ static int gpiochip_find_base(int ngpio)
 	int spare = 0;
 	int base = -ENOSPC;
 
-	for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
+	for (i = 0, base = 0; i < ARCH_NR_GPIOS; i++) {
 		struct gpio_desc *desc = &gpio_desc[i];
 		struct gpio_chip *chip = desc->chip;
 
-		if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
+		if (chip) {
+			spare = 0;
+			i += chip->ngpio - 1;
+			base = i + 1;
+		} else if (test_bit(FLAG_RESERVED, &desc->flags)) {
+			spare = 0;
+			base = i + 1;
+		} else {
 			spare++;
-			if (spare == ngpio) {
-				base = i;
+			if (spare == ngpio)
 				break;
-			}
-		} else {
-			spare = 0;
-			if (chip)
-				i -= chip->ngpio - 1;
 		}
 	}
 
Signature · 1 line
1.7.10.4
#16 lore raw

PATCH v7 6/15 gpio: find gpio base by ascend order

Quoted 5 lines · Haojian Zhuang

gpiochip_find_base() always tries to find valid gpio with descend order. It's inconvient if gpio information is passing from DTS. Now try to find valid gpio with ascend order.

Grant, can you comment on this?

You know DT and GPIO better than me....

Yours,
Linus Walleij

#17 lore raw

PATCH v7 6/15 gpio: find gpio base by ascend order

In reply to Haojian Zhuang
Quoted 3 lines · Haojian Zhuang

gpiochip_find_base() always tries to find valid gpio with descend order. It's inconvient if gpio information is passing from DTS. Now try to find valid gpio with ascend order.

Why is it more convenient? Just to make the numbers smaller? The reason it uses a descending search is to mimimize the possibility of collision with fixed GPIO numbers.

g.

author maintainer
#18 lore raw

PATCH v7 6/15 gpio: find gpio base by ascend order

Quoted 11 lines · Grant Likely
Quoted 3 lines · Haojian Zhuang

gpiochip_find_base() always tries to find valid gpio with descend order. It's inconvient if gpio information is passing from DTS. Now try to find valid gpio with ascend order.

Why is it more convenient? Just to make the numbers smaller? The reason it uses a descending search is to mimimize the possibility of collision with fixed GPIO numbers.

g.

I tried to parse global gpio number dynamically from DT, so I also used gpiochip_find_base() to seek gpio number. If it's descending order, all the gpio number are not also descending order. It will be inconvenient for linking it to SoC datasheet & schematic. Since changing it to ascending order may break user space application, Linus NACKed.

Now I'm trying to use fixed gpio number from machine driver.

Regards
Haojian

author maintainer
#19 lore raw

PATCH v7 7/15 gpio: pl061: allocate irq dynamically

In reply to Haojian Zhuang

In original implementation, irq base is always specified in platform data. If it's not specified, pl061 gpio driver can't pass the probe() function since irq base is missing. While moving to device tree, everything should be parsed from DTS file. So allocate irq dynamically for irq base.

---
 drivers/gpio/gpio-pl061.c |   15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/gpio/gpio-pl061.c +12 -3
index c1720de..8336719 100644
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
@@ -211,6 +212,10 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
 			       IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
 }
 
+static const struct irq_domain_ops pl061_domain_ops = {
+	.xlate	= irq_domain_xlate_twocell,
+};
+
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	struct device *dev = &adev->dev;
@@ -225,10 +230,14 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 	if (pdata) {
 		chip->gc.base = pdata->gpio_base;
 		chip->irq_base = pdata->irq_base;
-	} else if (adev->dev.of_node) {
+	} else {
 		chip->gc.base = -1;
-		chip->irq_base = 0;
-	} else
+		chip->irq_base = irq_alloc_descs(-1, 0, PL061_GPIO_NR, 0);
+		if (chip->irq_base < 0)
+			return chip->irq_base;
+	}
+	if (!irq_domain_add_legacy(adev->dev.of_node, PL061_GPIO_NR,
+				   chip->irq_base, 0, &pl061_domain_ops, chip))
 		return -ENODEV;
 
 	if (!devm_request_mem_region(dev, adev->res.start,
Signature · 1 line
1.7.10.4
author maintainer
#20 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

In reply to Haojian Zhuang

Add the pl061_gpio_request() to request pinctrl. Create the logic between pl061 gpio driver and pinctrl (pinctrl-single) driver.

While a gpio pin is requested, it will request pinctrl driver to set that pin with gpio function mode. So pinctrl driver should append .gpio_request_enable() in pinmux_ops.

---
 drivers/gpio/gpio-pl061.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
drivers/gpio/gpio-pl061.c +19 -0
index 8336719..8cfdf60 100644
@@ -23,6 +23,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm.h>
 #include <asm/mach/irq.h>
 
@@ -61,6 +62,23 @@ struct pl061_gpio {
 #endif
 };
 
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	/*
+	 * Map back to global GPIO space and request muxing, the direction
+	 * parameter does not matter for this controller.
+	 */
+	int gpio = chip->base + offset;
+
+	/*
+	 * Do NOT check the return value at here. Since sometimes the gpio
+	 * pin needn't to be configured in pinmux controller. So it's
+	 * impossible to find the matched gpio range.
+	 */
+	pinctrl_request_gpio(gpio);
+	return 0;
+}
+
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
 {
 	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -251,6 +269,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
 	spin_lock_init(&chip->lock);
 
+	chip->gc.request = pl061_gpio_request;
 	chip->gc.direction_input = pl061_direction_input;
 	chip->gc.direction_output = pl061_direction_output;
 	chip->gc.get = pl061_get_value;
Signature · 1 line
1.7.10.4
#21 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

Quoted 8 lines · Haojian Zhuang

Add the pl061_gpio_request() to request pinctrl. Create the logic between pl061 gpio driver and pinctrl (pinctrl-single) driver.

While a gpio pin is requested, it will request pinctrl driver to set that pin with gpio function mode. So pinctrl driver should append .gpio_request_enable() in pinmux_ops.

(...)

Quoted 4 lines
drivers/gpio/gpio-pl061.c +4 -0
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       /*
+        * Map back to global GPIO space and request muxing, the direction

drivers/gpio/gpio-pl061.c struct pl061_gpio { · line 78

Quoted 10 lines
drivers/gpio/gpio-pl061.c +10 -0
+        * parameter does not matter for this controller.
+        */
+       int gpio = chip->base + offset;
+
+       /*
+        * Do NOT check the return value at here. Since sometimes the gpio
+        * pin needn't to be configured in pinmux controller. So it's
+        * impossible to find the matched gpio range.
+        */
+       pinctrl_request_gpio(gpio);

Handling of error code?

(Maybe I should add a __must_check on this function.)

Quoted 7 lines
drivers/gpio/gpio-pl061.c +3 -0
+       return 0;
+}
+
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);

drivers/gpio/gpio-pl061.c static int pl061_probe(struct amba_device *adev, const struct amba_id *id) · line 275

Quoted 7 lines
drivers/gpio/gpio-pl061.c +1 -0
@@ -251,6 +269,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
        spin_lock_init(&chip->lock);
 
+       chip->gc.request = pl061_gpio_request;
        chip->gc.direction_input = pl061_direction_input;
        chip->gc.direction_output = pl061_direction_output;
        chip->gc.get = pl061_get_value;

What happens on a platform that has a PL061 GPIO block but no pinctrl related to it?

But still has some other pinctrl driver in the platform ....

Right, it'll return -EPROBE_DEFER from pinctrl_request_gpio().

This may happen on for example a combined SPEAr kernel where some platforms have PL061 and others us a pin controller, so both will be enabled.

I think, add a field like this to struct pl061_gpio:

bool has_pinctrl_backend;

The only call that from pl061_gpio_request() if this is set:

if (pl061->has_pinctrl_backend)
ret = pinctrl_request_gpio(gpio);

Then assign it in some clever way. For DT I think the proper way would be so add a cross-binding to the pin controller, like:

gpio2: gpio at d8100000 {
    #gpio-cells = <2>;
    compatible = "arm,pl061", "arm,primecell";
(...)
    pinctrl = <&mr_pincontrol>;
};

Then just check if you have this pinctrl binding set to figure out if has_pinctrl_backend should be true.

Yours,
Linus Walleij

author maintainer
#22 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

Quoted 30 lines · Linus Walleij
Quoted 8 lines · Haojian Zhuang

Add the pl061_gpio_request() to request pinctrl. Create the logic between pl061 gpio driver and pinctrl (pinctrl-single) driver.

While a gpio pin is requested, it will request pinctrl driver to set that pin with gpio function mode. So pinctrl driver should append .gpio_request_enable() in pinmux_ops.

(...)

Quoted 4 lines
drivers/gpio/gpio-pl061.c +4 -0
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       /*
+        * Map back to global GPIO space and request muxing, the direction

drivers/gpio/gpio-pl061.c struct pl061_gpio { · line 78

Quoted 10 lines
drivers/gpio/gpio-pl061.c +10 -0
+        * parameter does not matter for this controller.
+        */
+       int gpio = chip->base + offset;
+
+       /*
+        * Do NOT check the return value at here. Since sometimes the gpio
+        * pin needn't to be configured in pinmux controller. So it's
+        * impossible to find the matched gpio range.
+        */
+       pinctrl_request_gpio(gpio);

Handling of error code?

Quoted 2 lines

(Maybe I should add a __must_check on this function.)

My case is a little special. I don't want to check return value because some gpio pins don't have pinmux registers in Hisilicon SoC.
So pinctrl_request_gpio() will always return error for these special pins in Hisilicon SoC.

If we must check the return value, maybe we need append a dummy pinctrl driver for those special gpio pins. How do you think about it? Of course, I need to evaluate
whether it's possible to implement.

Quoted 28 lines
Quoted 7 lines
drivers/gpio/gpio-pl061.c +3 -0
+       return 0;
+}
+
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);

drivers/gpio/gpio-pl061.c static int pl061_probe(struct amba_device *adev, const struct amba_id *id) · line 275

Quoted 7 lines
drivers/gpio/gpio-pl061.c +1 -0
@@ -251,6 +269,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
        spin_lock_init(&chip->lock);
 
+       chip->gc.request = pl061_gpio_request;
        chip->gc.direction_input = pl061_direction_input;
        chip->gc.direction_output = pl061_direction_output;
        chip->gc.get = pl061_get_value;

What happens on a platform that has a PL061 GPIO block but no pinctrl related to it?

But still has some other pinctrl driver in the platform ....

Right, it'll return -EPROBE_DEFER from pinctrl_request_gpio().

This may happen on for example a combined SPEAr kernel where some platforms have PL061 and others us a pin controller, so both will be enabled.

I think, add a field like this to struct pl061_gpio:

Quoted 7 lines

bool has_pinctrl_backend;

The only call that from pl061_gpio_request() if this is set:

if (pl061->has_pinctrl_backend)
ret = pinctrl_request_gpio(gpio);

I'm OK to append "has_pinctrl_backend". But if we append a dummy pinctrl driver, is it OK to SPEAr kernel? Do we still need has_pinctrl_backend?

Quoted 11 lines

Then assign it in some clever way. For DT I think the proper way would be so add a cross-binding to the pin controller, like:

gpio2: gpio at d8100000 {
    #gpio-cells = <2>;
    compatible = "arm,pl061", "arm,primecell";
(...)
    pinctrl = <&mr_pincontrol>;
};

If we could append a dummy pinctrl driver, maybe we needn't to append pinctrl property into gpio node. What's your opinion?

Quoted 6 lines

Then just check if you have this pinctrl binding set to figure out if has_pinctrl_backend should be true.

Yours,
Linus Walleij

Regards
Haojian

#23 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

Quoted 11 lines · Haojian Zhuang
Quoted 6 lines
Quoted 1 line

+ pinctrl_request_gpio(gpio);

Handling of error code?

(Maybe I should add a __must_check on this function.)

My case is a little special. I don't want to check return value because some gpio pins don't have pinmux registers in Hisilicon SoC.
So pinctrl_request_gpio() will always return error for these special pins in Hisilicon SoC.

Quoted 4 lines

If we must check the return value, maybe we need append a dummy pinctrl driver for those special gpio pins. How do you think about it? Of course, I need to evaluate
whether it's possible to implement.

Hm. A dummy pinctrl back-end is not very elegant.

It's better if the GPIO driver (gpio-pl061) keep track of the ranges that are connected to the pinctrl.

If the ranges are encoded in the device tree (as I guess you want to do in this case) then the GPIO driver need to check these ranges to see if it uses a pinctrl backend. Magic behind-the-scenes is very hard to understand for people reading this code later.

What about this:

In gpiolib.c, function gpiochip_add_pin_range(), we save a copy of each range in &chip->pin_ranges.

Add a function to gpiolib.c to check if a certain gpio is in the range of the current chip.

Then use that:

if (gpio_in_pinrange(gpio))

    pinctrl_request_gpio(gpio);

Yours,
Linus Walleij

author maintainer
#24 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

Quoted 37 lines · Linus Walleij
Quoted 11 lines · Haojian Zhuang
Quoted 6 lines
Quoted 1 line

+ pinctrl_request_gpio(gpio);

Handling of error code?

(Maybe I should add a __must_check on this function.)

My case is a little special. I don't want to check return value because some gpio pins don't have pinmux registers in Hisilicon SoC.
So pinctrl_request_gpio() will always return error for these special pins in Hisilicon SoC.

Quoted 4 lines

If we must check the return value, maybe we need append a dummy pinctrl driver for those special gpio pins. How do you think about it? Of course, I need to evaluate
whether it's possible to implement.

Hm. A dummy pinctrl back-end is not very elegant.

It's better if the GPIO driver (gpio-pl061) keep track of the ranges that are connected to the pinctrl.

If the ranges are encoded in the device tree (as I guess you want to do in this case) then the GPIO driver need to check these ranges to see if it uses a pinctrl backend. Magic behind-the-scenes is very hard to understand for people reading this code later.

What about this:

In gpiolib.c, function gpiochip_add_pin_range(), we save a copy of each range in &chip->pin_ranges.

Add a function to gpiolib.c to check if a certain gpio is in the range of the current chip.

Quoted 7 lines

Then use that:

if (gpio_in_pinrange(gpio))

    pinctrl_request_gpio(gpio);

Yours,
Linus Walleij

It seems better. I'll update it.

Regards
Haojian

#25 lore raw

PATCH v7 8/15 gpio: pl061: bind pinctrl by gpio request

Quoted 5 lines · Haojian Zhuang
Quoted 5 lines

Add a function to gpiolib.c to check if a certain gpio is in the range of the current chip.

Then use that:

Quoted 7 lines
Quoted 5 lines

if (gpio_in_pinrange(gpio))

    pinctrl_request_gpio(gpio);

Yours,
Linus Walleij

It seems better. I'll update it.

Hm the function above will need to pass the chip as parameter as well, so a bit simplified.

Maybe it's better to add a function like gpio_check_pinctrl_backend(chip, gpio); that does the above two statements?

Yours,
Linus Walleij

author maintainer
#26 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

In reply to Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

---
 drivers/gpio/gpio-pl061.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-pl061.c +1 -1
index 8cfdf60..76adf33 100644
@@ -393,7 +393,7 @@ static int __init pl061_gpio_init(void)
 {
 	return amba_driver_register(&pl061_gpio_driver);
 }
-subsys_initcall(pl061_gpio_init);
+module_init(pl061_gpio_init);
 
 MODULE_AUTHOR("Baruch Siach <[email protected]>");
 MODULE_DESCRIPTION("PL061 GPIO driver");
Signature · 1 line
1.7.10.4
#27 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 5 lines · Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

On you platform maybe it works, but have you made sure that nobody else will be affected?

SPEAr of course, then these:

arch/arm/mach-realview/core.c: * GPIO on PL061 is active,
which is the proper
arch/arm/mach-socfpga/Kconfig: select GPIO_PL061 if GPIOLIB

Pawel, Dinh: are you OK with this change?

Yours,
Linus Walleij

#28 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 12 lines · Linus Walleij
Quoted 5 lines · Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

On you platform maybe it works, but have you made sure that nobody else will be affected?

Quoted 7 lines

SPEAr of course, then these:

arch/arm/mach-realview/core.c: * GPIO on PL061 is active,
which is the proper
arch/arm/mach-socfpga/Kconfig: select GPIO_PL061 if GPIOLIB

Pawel, Dinh: are you OK with this change?

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

Pawel

#29 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Hi Linus,

Quoted 13 lines · Pawel Moll
Quoted 12 lines · Linus Walleij
Quoted 5 lines · Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

On you platform maybe it works, but have you made sure that nobody else will be affected?

Quoted 7 lines
Quoted 7 lines

SPEAr of course, then these:

arch/arm/mach-realview/core.c: * GPIO on PL061 is active,
which is the proper
arch/arm/mach-socfpga/Kconfig: select GPIO_PL061 if GPIOLIB

Pawel, Dinh: are you OK with this change?

Still works ok on mach-socfpga.

Dinh

Quoted 11 lines

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

Pawel

#30 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 3 lines · Dinh Nguyen
Quoted 1 line
Quoted 1 line

Pawel, Dinh: are you OK with this change?

Still works ok on mach-socfpga.

Thanks! Adding your Tested-by tag, OK?

Yours,
Linus Walleij

#31 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Hi Linus,

Quoted 7 lines · Linus Walleij
Quoted 3 lines · Dinh Nguyen
Quoted 1 line
Quoted 1 line

Pawel, Dinh: are you OK with this change?

Still works ok on mach-socfpga.

Thanks! Adding your Tested-by tag, OK?

Yep, thanks.

Dinh

Quoted 4 lines

Yours,
Linus Walleij

author maintainer
#32 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

In reply to Pawel Moll
Quoted 19 lines · Pawel Moll
Quoted 18 lines · Linus Walleij
Quoted 5 lines · Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

On you platform maybe it works, but have you made sure that nobody else will be affected?

SPEAr of course, then these:

arch/arm/mach-realview/core.c: * GPIO on PL061 is active,
which is the proper
arch/arm/mach-socfpga/Kconfig: select GPIO_PL061 if GPIOLIB

Quoted 11 lines
Quoted 1 line

Pawel, Dinh: are you OK with this change?

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

Pawel

The sequence of module probe is pinctrl --> gpio --> mmc. So the dependance of mmc on gpio isn't broken.

Regards
Haojian

#33 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 2 lines · Haojian Zhuang

The sequence of module probe is pinctrl --> gpio --> mmc. So the dependance of mmc on gpio isn't broken.

I don't think you can guarantee the "gpio --> mmc" sequence if both drivers use module_init (the order could be completely random, generally it depends on what Kbuild is doing), but if gpio_request() behaves as Linus said, the sequence in the problematic scenario would be "pinctrl --> mmc --> EPROBE_DEFER --> gpio --> mmc" which is fine (subject to mmci driver fix, but it's a separate issue).

Pawe?

#34 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

In reply to Pawel Moll
Quoted 4 lines · Pawel Moll

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

According to Haojian it works, but for sure the MMCI driver *should* (on the eternal list of SHOULDDO) bail out and return any -EPROBE_DEFER up to the AMBA bus core properly so it
will be tried again later if this happens.

AFAICT gpio_request() will return -EPROBE_DEFER if the GPIO cannot be located.

Yours,
Linus Walleij

#35 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 2 lines · Linus Walleij

AFAICT gpio_request() will return -EPROBE_DEFER if the GPIO cannot be located.

If it does, I withdraw all my objections.

Cheers!

Pawe?

#36 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

In reply to Linus Walleij
Quoted 9 lines · Linus Walleij
Quoted 4 lines · Pawel Moll

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

According to Haojian it works, but for sure the MMCI driver *should* (on the eternal list of SHOULDDO) bail out and return any

Rather than talking about what should and should not, why not look at the code - it only takes a few moments to check what the behaviour would be. And it is correct - errors are correctly propagated out of the probe function.

That's hardly surprising given who's supposed to be the maintainer of that driver.

#37 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

Quoted 8 lines · Russell King - ARM Linux
Quoted 7 lines · Linus Walleij
Quoted 4 lines · Pawel Moll

Hm. Doesn't this make the MMCI probing depending on the module_init order? As in: wouldn't it make the mmci probe completely fail (not even defer it) if it was called before the pl061? In that case even your, Linus, hack with inverting the CD status wouldn't work...

Quoted 7 lines
Quoted 2 lines

According to Haojian it works, but for sure the MMCI driver *should* (on the eternal list of SHOULDDO) bail out and return any

Rather than talking about what should and should not, why not look at the code - it only takes a few moments to check what the behaviour would be. And it is correct - errors are correctly propagated out of the probe function.

OK good!

Quoted 2 lines

That's hardly surprising given who's supposed to be the maintainer of that driver.

Aouh that hurt! ;-)

Thanks Russell,
Linus Walleij

#38 lore raw

PATCH v7 9/15 gpio: pl061: set initcall level to module init

In reply to Haojian Zhuang
Quoted 5 lines · Haojian Zhuang

Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level.

OK some consensus that this works, and moving initcalls to module_init() should be encouraged, so applied this and thrown at linux-next for testing. No pain no gain.

Yours,
Linus Walleij

author maintainer
#39 lore raw

PATCH v7 10/15 pinctrl: single: create new gpio function range

In reply to Haojian Zhuang

Since gpio driver could create gpio range in DTS, it could invokes pinctrl_request_gpio(). In the pinctrl-single driver, it needs to configure pins with gpio function mode.

A new gpio function range should be created in DTS file in below.

pinctrl-single,gpio-range = <phandle pin_offset nr_pins gpio_func>;

range: gpio-range {
	#pinctrl-single,gpio-range-cells = <3>;
};

The difference between gpio-ranges property in gpio driver and pinctrl-single,gpio-range property in pinctrl-single driver.

1. gpio-ranges = <phandle gpio_offset_in_chip pin_offset nr_pins>

	gpio-ranges = < &pmx0 0 89 1 &pmx0 1 89 1 &pmx0 2 90 1
			&pmx0 3 90 1 &pmx0 4 91 1 &pmx0 5 92 1>;

2. gpio driver could get pin offset from gpio-ranges property. pinctrl-single driver could get gpio function mode from gpio_func that is stored in @gpiofuncs list in struct pcs_device. This new pinctrl-single,gpio-range is used as complement for gpio-ranges property in gpio driver.

---
 drivers/pinctrl/pinctrl-single.c |   73 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)
drivers/pinctrl/pinctrl-single.c +71 -2
index 5c32e88..8b9dd95 100644
@@ -77,6 +77,20 @@ struct pcs_function {
 };
 
 /**
+ * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function
+ * @offset:	offset base of pins
+ * @npins:	number pins with the same mux value of gpio function
+ * @gpiofunc:	mux value of gpio function
+ * @node:	list node
+ */
+struct pcs_gpiofunc_range {
+	unsigned offset;
+	unsigned npins;
+	unsigned gpiofunc;
+	struct list_head node;
+};
+
+/**
  * struct pcs_data - wrapper for data needed by pinctrl framework
  * @pa:		pindesc array
  * @cur:	index to current element
@@ -123,6 +137,7 @@ struct pcs_name {
  * @ftree:	function index radix tree
  * @pingroups:	list of pingroups
  * @functions:	list of functions
+ * @gpiofuncs:	list of gpio functions
  * @ngroups:	number of pingroups
  * @nfuncs:	number of functions
  * @desc:	pin controller descriptor
@@ -148,6 +163,7 @@ struct pcs_device {
 	struct radix_tree_root ftree;
 	struct list_head pingroups;
 	struct list_head functions;
+	struct list_head gpiofuncs;
 	unsigned ngroups;
 	unsigned nfuncs;
 	struct pinctrl_desc desc;
@@ -403,9 +419,26 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-			struct pinctrl_gpio_range *range, unsigned offset)
+			    struct pinctrl_gpio_range *range, unsigned pin)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	struct pcs_gpiofunc_range *frange = NULL;
+	struct list_head *pos, *tmp;
+	int mux_bytes = 0;
+	unsigned data;
+
+	list_for_each_safe(pos, tmp, &pcs->gpiofuncs) {
+		frange = list_entry(pos, struct pcs_gpiofunc_range, node);
+		if (pin >= frange->offset + frange->npins
+			|| pin < frange->offset)
+			continue;
+		mux_bytes = pcs->width / BITS_PER_BYTE;
+		data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+		data |= frange->gpiofunc;
+		pcs->write(data, pcs->base + pin * mux_bytes);
+		break;
+	}
+	return 0;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -879,6 +912,37 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
+static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
+{
+	const char *propname = "pinctrl-single,gpio-range";
+	const char *cellname = "#pinctrl-single,gpio-range-cells";
+	struct of_phandle_args gpiospec;
+	struct pcs_gpiofunc_range *range;
+	int ret, i;
+
+	for (i = 0; ; i++) {
+		ret = of_parse_phandle_with_args(node, propname, cellname,
+						 i, &gpiospec);
+		/* Do not treat it as error. Only treat it as end condition. */
+		if (ret) {
+			ret = 0;
+			break;
+		}
+		range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL);
+		if (!range) {
+			ret = -ENOMEM;
+			break;
+		}
+		range->offset = gpiospec.args[0];
+		range->npins = gpiospec.args[1];
+		range->gpiofunc = gpiospec.args[2];
+		mutex_lock(&pcs->mutex);
+		list_add_tail(&range->node, &pcs->gpiofuncs);
+		mutex_unlock(&pcs->mutex);
+	}
+	return ret;
+}
+
 static int pcs_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -900,6 +964,7 @@ static int pcs_probe(struct platform_device *pdev)
 	mutex_init(&pcs->mutex);
 	INIT_LIST_HEAD(&pcs->pingroups);
 	INIT_LIST_HEAD(&pcs->functions);
+	INIT_LIST_HEAD(&pcs->gpiofuncs);
 
 	PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
 			 "register width not specified\n");
@@ -975,6 +1040,10 @@ static int pcs_probe(struct platform_device *pdev)
 		goto free;
 	}
 
+	ret = pcs_add_gpio_func(np, pcs);
+	if (ret < 0)
+		goto free;
+
 	dev_info(pcs->dev, "%i pins at pa %p size %u\n",
 		 pcs->desc.npins, pcs->base, pcs->size);
 
Signature · 1 line
1.7.10.4
author maintainer
#40 lore raw

PATCH v7 11/15 pinctrl: generic: add slew rate config parameter

In reply to Haojian Zhuang

Add PIN_CONFIG_SLEW_RATE parameter into pinconf-generic driver.

---
 drivers/pinctrl/pinconf-generic.c       |    1 +
 include/linux/pinctrl/pinconf-generic.h |    4 ++++
 2 files changed, 5 insertions(+)
drivers/pinctrl/pinconf-generic.c +1 -0
index 833a364..678db63 100644
@@ -45,6 +45,7 @@ struct pin_config_item conf_items[] = {
 	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
 	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
 	PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
+	PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
 	PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
 };
 
include/linux/pinctrl/pinconf-generic.h +4 -0
index 47a1bdd..e970a12 100644
@@ -58,6 +58,9 @@
  * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
  *	supplies, the argument to this parameter (on a custom format) tells
  *	the driver which alternative power source to use.
+ * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
+ * 	this parameter (on a custom format) tells the driver which alternative
+ * 	slew rate to use.
  * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
  *	operation, if several modes of operation are supported these can be
  *	passed in the argument on a custom form, else just use argument 1
@@ -78,6 +81,7 @@ enum pin_config_param {
 	PIN_CONFIG_INPUT_SCHMITT,
 	PIN_CONFIG_INPUT_DEBOUNCE,
 	PIN_CONFIG_POWER_SOURCE,
+	PIN_CONFIG_SLEW_RATE,
 	PIN_CONFIG_LOW_POWER_MODE,
 	PIN_CONFIG_END = 0x7FFF,
 };
Signature · 1 line
1.7.10.4
#41 lore raw

PATCH v7 11/15 pinctrl: generic: add slew rate config parameter

Quoted 3 lines · Haojian Zhuang

Add PIN_CONFIG_SLEW_RATE parameter into pinconf-generic driver.

Aha you need this.

Patch applied!

Yours,
Linus Walleij

author maintainer
#42 lore raw

PATCH v7 12/15 pinctrl: generic: dump pin configuration

In reply to Haojian Zhuang

Add the support of dumping pin configuration.

---
 drivers/pinctrl/pinconf-generic.c |   12 ++++++++++++
 drivers/pinctrl/pinconf.h         |    8 ++++++++
 2 files changed, 20 insertions(+)
drivers/pinctrl/pinconf-generic.c +12 -0
index 678db63..9bb6d47 100644
@@ -119,4 +119,16 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
 	}
 }
 
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+				 struct seq_file *s, unsigned long config)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+		if (pinconf_to_config_param(config) != conf_items[i].param)
+			continue;
+		seq_printf(s, "%s: 0x%x", conf_items[i].display,
+			   pinconf_to_config_argument(config));
+	}
+}
 #endif
drivers/pinctrl/pinconf.h +8 -0
index e3ed8cb..8023421 100644
@@ -98,6 +98,8 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
 void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
 			      struct seq_file *s, const char *gname);
 
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+				 struct seq_file *s, unsigned long config);
 #else
 
 static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
@@ -114,4 +116,10 @@ static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
 	return;
 }
 
+static void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+					struct seq_file *s,
+					unsigned long config)
+{
+	return;
+}
 #endif
Signature · 1 line
1.7.10.4
author maintainer
#43 lore raw

PATCH v7 13/15 pinctrl: single: set function mask as optional

In reply to Haojian Zhuang

Since Hisilicon's pin controller is divided into two parts. One is the function mux, and the other is pin configuration. These two parts are in the different memory regions. So make pinctrl-single,function-mask as optional property. Then we can define pingroups without valid function mux that is only used for pin configuration.

---
 drivers/pinctrl/pinctrl-single.c |   26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)
drivers/pinctrl/pinctrl-single.c +22 -4
index 8b9dd95..fe8f321 100644
@@ -350,6 +350,9 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
 	int i;
 
 	pcs = pinctrl_dev_get_drvdata(pctldev);
+	/* If function mask is null, needn't enable it. */
+	if (!pcs->fmask)
+		return 0;
 	func = radix_tree_lookup(&pcs->ftree, fselector);
 	if (!func)
 		return -EINVAL;
@@ -384,6 +387,10 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 	int i;
 
 	pcs = pinctrl_dev_get_drvdata(pctldev);
+	/* If function mask is null, needn't disable it. */
+	if (!pcs->fmask)
+		return;
+
 	func = radix_tree_lookup(&pcs->ftree, fselector);
 	if (!func) {
 		dev_err(pcs->dev, "%s could not find function%i\n",
@@ -427,6 +434,10 @@ static int pcs_request_gpio(struct pinctrl_dev *pctldev,
 	int mux_bytes = 0;
 	unsigned data;
 
+	/* If function mask is null, return directly. */
+	if (!pcs->fmask)
+		return -ENOTSUPP;
+
 	list_for_each_safe(pos, tmp, &pcs->gpiofuncs) {
 		frange = list_entry(pos, struct pcs_gpiofunc_range, node);
 		if (pin >= frange->offset + frange->npins
@@ -969,10 +980,17 @@ static int pcs_probe(struct platform_device *pdev)
 	PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
 			 "register width not specified\n");
 
-	PCS_GET_PROP_U32("pinctrl-single,function-mask", &pcs->fmask,
-			 "function register mask not specified\n");
-	pcs->fshift = ffs(pcs->fmask) - 1;
-	pcs->fmax = pcs->fmask >> pcs->fshift;
+	ret = of_property_read_u32(np, "pinctrl-single,function-mask",
+				   &pcs->fmask);
+	if (!ret) {
+		pcs->fshift = ffs(pcs->fmask) - 1;
+		pcs->fmax = pcs->fmask >> pcs->fshift;
+	} else {
+		/* If mask property doesn't exist, function mux is invalid. */
+		pcs->fmask = 0;
+		pcs->fshift = 0;
+		pcs->fmax = 0;
+	}
 
 	ret = of_property_read_u32(np, "pinctrl-single,function-off",
 					&pcs->foff);
Signature · 1 line
1.7.10.4
author maintainer
#44 lore raw

PATCH v7 14/15 pinctrl: single: support generic pinconf

In reply to Haojian Zhuang

Support the operation of generic pinconf. The supported config arguments are INPUT_SCHMITT, INPUT_SCHMITT_DISABLE, POWER_SOURCE, BIAS_DISABLE, BIAS_PULLUP, BIAS_PULLDOWN, SLEW_RATE.

---
 drivers/pinctrl/Kconfig          |    1 +
 drivers/pinctrl/pinctrl-single.c |  339 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 333 insertions(+), 7 deletions(-)
drivers/pinctrl/Kconfig +1 -0
index c31aeb0..2434c21 100644
@@ -143,6 +143,7 @@ config PINCTRL_SINGLE
 	depends on OF
 	select PINMUX
 	select PINCONF
+	select GENERIC_PINCONF
 	help
 	  This selects the device tree based generic pinctrl driver.
 
drivers/pinctrl/pinctrl-single.c +332 -7

475 lines not on this page · raw message

Signature · 1 line
1.7.10.4
maintainer
#45 lore raw

PATCH v7 14/15 pinctrl: single: support generic pinconf

Hi,

Quoted 4 lines · Haojian Zhuang
drivers/pinctrl/pinctrl-single.c +4 -0
+static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
+			     struct pcs_function *func,
+			     struct pinctrl_map **map)
+

drivers/pinctrl/pinctrl-single.c static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) · line 949

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+{
+	struct pinctrl_map *m = *map;
+	int i = 0, nconfs = 0;
+	unsigned long *settings = NULL, *s = NULL;
+	struct pcs_conf_vals *conf = NULL;
+	struct pcs_conf_type prop2[] = {
+		{ "pinctrl-single,power-source", PIN_CONFIG_POWER_SOURCE, },
+		{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+		{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+	};

The PIN_CONFIG_POWER_SOURCE should be split to PIN_CONFIG_POWER_ENABLE and PIN_CONFIG_POWER_SOURCE. If you only have one bit for it, I guess then you can just use PIN_CONFIG_POWER_ENABLE and make PIN_CONFIG_POWER_SOURCE a NOP.

I also suggest we standardize on PIN_CONFIG_*_ENABLE on the naming instead of PIN_CONFIG_*_DISABLE. Many of these features enable some input logic, and by default they should be off to save power.

drivers/pinctrl/pinctrl-single.c static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) · line 956

Quoted 7 lines
drivers/pinctrl/pinctrl-single.c +7 -0
+	struct pcs_conf_type prop3[] = {
+		{ "pinctrl-single,bias-disable", PIN_CONFIG_BIAS_DISABLE, },
+		{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
+		{ "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
+		{ "pinctrl-single,input-schmitt-disable",
+			PIN_CONFIG_INPUT_SCHMITT_DISABLE, },
+	};

I'm not aware of cases where we need both INPUT_SCHMITT and INPUT_SCHMITT_DISABLE, so we may just want to have INPUT_SCHMITT_ENABLE if that works for you.

Other than that, looks good to me. I'll update my patches here and do some tests against my pinctrl-single,bits testcase.

Regards,

Tony

author maintainer
#46 lore raw

PATCH v7 14/15 pinctrl: single: support generic pinconf

Quoted 14 lines · Tony Lindgren

Hi,

Quoted 11 lines · Haojian Zhuang
drivers/pinctrl/pinctrl-single.c +11 -0
+static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
+                          struct pcs_function *func,
+                          struct pinctrl_map **map)
+
+{
+     struct pinctrl_map *m = *map;
+     int i = 0, nconfs = 0;
+     unsigned long *settings = NULL, *s = NULL;
+     struct pcs_conf_vals *conf = NULL;
+     struct pcs_conf_type prop2[] = {
+             { "pinctrl-single,power-source", PIN_CONFIG_POWER_SOURCE, },
Quoted 9 lines

drivers/pinctrl/pinctrl-single.c static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) · line 949

Quoted 3 lines
drivers/pinctrl/pinctrl-single.c +3 -0
+             { "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+             { "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+     };

The PIN_CONFIG_POWER_SOURCE should be split to PIN_CONFIG_POWER_ENABLE and PIN_CONFIG_POWER_SOURCE. If you only have one bit for it, I guess then you can just use PIN_CONFIG_POWER_ENABLE and make PIN_CONFIG_POWER_SOURCE a NOP.

In Hisilicon Hi3620 SoC, 4bits are used for power source. b0000 is 2mA, b0001 is 4mA, .... b1111 is 8mA.
There's no power enable bit. In Marvell silicon, it's also same.

Quoted 4 lines

I also suggest we standardize on PIN_CONFIG_*_ENABLE on the naming instead of PIN_CONFIG_*_DISABLE. Many of these features enable some input logic, and by default they should be off to save power.

In Hisilicon Hi3620 SoC, there's no bias enable or disable bit. They could only configure pull up or
pull down. We can think that no-pullup and no-pulldown is bias disable. If we define BIAS_ENABLE,
both pullup & pulldown meet the definition. It's a problem.

Quoted 11 lines

drivers/pinctrl/pinctrl-single.c static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) · line 956

Quoted 7 lines
drivers/pinctrl/pinctrl-single.c +7 -0
+     struct pcs_conf_type prop3[] = {
+             { "pinctrl-single,bias-disable", PIN_CONFIG_BIAS_DISABLE, },
+             { "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
+             { "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
+             { "pinctrl-single,input-schmitt-disable",
+                     PIN_CONFIG_INPUT_SCHMITT_DISABLE, },
+     };

I'm not aware of cases where we need both INPUT_SCHMITT and INPUT_SCHMITT_DISABLE, so we may just want to have INPUT_SCHMITT_ENABLE if that works for you.

Because marvell silicon coul configure two input schmitt type (rise edge or fall edge).

Could we always use DISABLE as our standard? It seems that this defintion could be compatible
with most silicons.

Quoted 6 lines

Other than that, looks good to me. I'll update my patches here and do some tests against my pinctrl-single,bits testcase.

Regards,

Tony

Thanks
Haojian

maintainer
#47 lore raw

PATCH v7 14/15 pinctrl: single: support generic pinconf

Quoted 25 lines · Haojian Zhuang
Quoted 14 lines · Tony Lindgren

Hi,

Quoted 11 lines · Haojian Zhuang
drivers/pinctrl/pinctrl-single.c +11 -0
+static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
+                          struct pcs_function *func,
+                          struct pinctrl_map **map)
+
+{
+     struct pinctrl_map *m = *map;
+     int i = 0, nconfs = 0;
+     unsigned long *settings = NULL, *s = NULL;
+     struct pcs_conf_vals *conf = NULL;
+     struct pcs_conf_type prop2[] = {
+             { "pinctrl-single,power-source", PIN_CONFIG_POWER_SOURCE, },
Quoted 9 lines

drivers/pinctrl/pinctrl-single.c static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) · line 949

Quoted 3 lines
drivers/pinctrl/pinctrl-single.c +3 -0
+             { "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+             { "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+     };

The PIN_CONFIG_POWER_SOURCE should be split to PIN_CONFIG_POWER_ENABLE and PIN_CONFIG_POWER_SOURCE. If you only have one bit for it, I guess then you can just use PIN_CONFIG_POWER_ENABLE and make PIN_CONFIG_POWER_SOURCE a NOP.

Quoted 3 lines

In Hisilicon Hi3620 SoC, 4bits are used for power source. b0000 is 2mA, b0001 is 4mA, .... b1111 is 8mA.
There's no power enable bit. In Marvell silicon, it's also same.

Yeah I figured from your earlier mails. Anyways, from client driver point of view, PIN_CONFIG_POWER_ENABLE should be just a NOP in your case?

This way the same client device driver can work on other platforms that might also use ENABLE. It's probably unsafe to attempt to handle any ENABLE bits automatically as the sequence to change POWER_SOURCE and then ENABLE might be hardware specific.

Then regarding the various values: We probably need a new pinconf generic function to set the POWER_SOURCE as it need to be passed a value too?

Regards,

Tony

author maintainer
#48 lore raw

PATCH v7 15/15 ARM: hs: enable hi4511 with device tree

In reply to Haojian Zhuang

Enable Hisilicon Hi4511 development platform with device tree support.

---
 arch/arm/boot/dts/Makefile    |    1 +
 arch/arm/boot/dts/hi3620.dtsi |  556 +++++++++++++++++++++++++++++
 arch/arm/boot/dts/hi4511.dts  |  772 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1329 insertions(+)
 create mode 100644 arch/arm/boot/dts/hi3620.dtsi
 create mode 100644 arch/arm/boot/dts/hi4511.dts
arch/arm/boot/dts/Makefile +1 -0
index e44da40..12626e4 100644
@@ -48,6 +48,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
 	exynos5440-ssdk5440.dtb
 dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
 	ecx-2000.dtb
+dtb-$(CONFIG_ARCH_HS) += hi4511.dtb
 dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \
 	integratorcp.dtb
 dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
arch/arm/boot/dts/hi3620.dtsi new file +556 -0

556 lines not on this page · raw message

arch/arm/boot/dts/hi4511.dts new file +772 -0

772 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#49 lore raw

v7 cover support pinconf in pinctrl single driver

In reply to Haojian Zhuang
Quoted 11 lines · Haojian Zhuang

Changelog:
v7:
1. Discard the method of adding gpio range from pinctrl-single driver. Use gpiolib driver to support gpio range from DTS instead.
2. Add gpio request function to claim pin in gpio pl061 driver.
3. Adjust the initcall level in gpio pl061 driver.
4. Allocate gpio number from lowest gpio number to highest. The original implementation is inverted. It's hard to use since it inverted the sequence of gpio number.
5. Remove the support of pxa910 temporarily since gpio pxa driver need to be updated for supporting this solution

Linus, I'll let you make decisions on this patch series since it is mostly pinctrl related.

g.

author maintainer
#50 lore raw

v7 cover support pinconf in pinctrl single driver

Quoted 13 lines · Grant Likely
Quoted 11 lines · Haojian Zhuang

Changelog:
v7:
1. Discard the method of adding gpio range from pinctrl-single driver. Use gpiolib driver to support gpio range from DTS instead.
2. Add gpio request function to claim pin in gpio pl061 driver.
3. Adjust the initcall level in gpio pl061 driver.
4. Allocate gpio number from lowest gpio number to highest. The original implementation is inverted. It's hard to use since it inverted the sequence of gpio number.
5. Remove the support of pxa910 temporarily since gpio pxa driver need to be updated for supporting this solution

Quoted 4 lines

Linus, I'll let you make decisions on this patch series since it is mostly pinctrl related.

g.

Since Tony has some opinions on pinctrl, I'll update them and send the v8 patches right now.

Thanks
Haojian