Skip to contentSkip to conversation

use pinctrl-single in arch mmp

PATCH New Haojian Zhuang 4 participants 22 messages Nov 15, 2012 – Nov 26, 2012

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

v5 cover use pinctrl-single in arch mmp

Changelog:
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.
2. Remove "pinctrl-single,gpio-enable" & "pinctrl-single,gpio-disable". Use "pinctrl-single,gpio-func" instead. Because GPIO mode is only one of the mux functions in the pinmux register. Defining "gpio-enable" & "gpio-disable" are redundant.
3. Define register with __iomem, not u32 type.
4. Remove "pinctrl-single,input-schmit-shift", "pinctrl-single,power-source-shift", "pinctrl-single,bias-shift". All these properties could be calculated by mask fields.
5. Return -EPROBE_DEFER if pinmux could be got in device driver. And the device driver would be probed again deferred.

#1 lore raw

PATCH v5 1/10 ARM: mmp: select pinctrl driver

Pinctrl driver is necessary for MMP DT & MMP2 DT platforms.

---
 arch/arm/mach-mmp/Kconfig |    4 ++++
 1 file changed, 4 insertions(+)
arch/arm/mach-mmp/Kconfig +4 -0
index 178d4da..ebdda83 100644
@@ -89,6 +89,8 @@ config MACH_MMP_DT
 	select CPU_PXA168
 	select CPU_PXA910
 	select USE_OF
+	select PINCTRL
+	select PINCTRL_SINGLE
 	help
 	  Include support for Marvell MMP2 based platforms using
 	  the device tree. Needn't select any other machine while
@@ -99,6 +101,8 @@ config MACH_MMP2_DT
 	depends on !CPU_MOHAWK
 	select CPU_MMP2
 	select USE_OF
+	select PINCTRL
+	select PINCTRL_SINGLE
 	help
 	  Include support for Marvell MMP2 based platforms using
 	  the device tree.
Signature · 1 line
1.7.10.4
#2 lore raw

PATCH v5 2/10 pinctrl: single: support gpio request and free

In reply to Haojian Zhuang

Marvell's PXA/MMP silicon also match the behavior of pinctrl-single. Each pin binds to one register. A lot of pins could be configured as gpio.

GPIO range is defined as a child node of pinmux in .dtsi file. If those pins are with the same gpio function configuration in the pinmux register, they could be defined in the same GPIO range. For this new child node, two properties are used.

reg = <the start of pinmux register in range, size of range>

pinctrl-single,gpio: <gpio base in range, the gpio function of the range
in the pinmux register>

---
 drivers/pinctrl/pinctrl-single.c |   80 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 2 deletions(-)
drivers/pinctrl/pinctrl-single.c +78 -2
index 726a729..2476a68 100644
@@ -30,6 +30,7 @@
 #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
@@ -77,6 +78,16 @@ 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
@@ -403,9 +414,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_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;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -879,6 +907,50 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
+static int __devinit 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 __devinit pcs_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -975,6 +1047,10 @@ static int __devinit 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
#3 lore raw

PATCH v5 2/10 pinctrl: single: support gpio request and free

Quoted 9 lines · Haojian Zhuang

Marvell's PXA/MMP silicon also match the behavior of pinctrl-single. Each pin binds to one register. A lot of pins could be configured as gpio.

GPIO range is defined as a child node of pinmux in .dtsi file. If those pins are with the same gpio function configuration in the pinmux register, they could be defined in the same GPIO range. For this new child node, two properties are used.

Quoted 6 lines

reg = <the start of pinmux register in range, size of range>

pinctrl-single,gpio: <gpio base in range, the gpio function of the range
in the pinmux register>

#4 lore raw

PATCH v5 2/10 pinctrl: single: support gpio request and free

In reply to Haojian Zhuang
Quoted 9 lines · Haojian Zhuang

Marvell's PXA/MMP silicon also match the behavior of pinctrl-single. Each pin binds to one register. A lot of pins could be configured as gpio.

GPIO range is defined as a child node of pinmux in .dtsi file. If those pins are with the same gpio function configuration in the pinmux register, they could be defined in the same GPIO range. For this new child node, two properties are used.

Quoted 6 lines

reg = <the start of pinmux register in range, size of range>

pinctrl-single,gpio: <gpio base in range, the gpio function of the range
in the pinmux register>

Patch applied with Tony's ACK.

Yours,
Linus Walleij

#5 lore raw

PATCH v5 3/10 pinctrl: append method of lookup pinctrl map

In reply to Haojian Zhuang

pinctrl driver gets pinctrl map if both group and map type is specified. In pinctrl-single driver, each pin group is defined in DT file. The pinconf information is also defined in each pin group.

pinctrl-single driver could store those mask/shift/value information into pinctrl map. pinconf_get()/pinconf_set() and pinconf_group_get()/pinconf_group_set() could get those information from pinctrl map.

---
 drivers/pinctrl/core.c           |   24 ++++++++++++++++++++++++
 include/linux/pinctrl/consumer.h |    4 ++++
 2 files changed, 28 insertions(+)
drivers/pinctrl/core.c +24 -0
index 2e39c04..0d36270 100644
@@ -839,6 +839,30 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
 }
 EXPORT_SYMBOL_GPL(pinctrl_select_state);
 
+const struct pinctrl_map *pinctrl_lookup_map(struct pinctrl *p,
+					     const char *name, unsigned type)
+{
+	struct pinctrl_maps *maps_node;
+	struct pinctrl_map const *map;
+	int i;
+
+	for_each_maps(maps_node, i, map) {
+		/* Map must be for this device */
+		if (strcmp(map->ctrl_dev_name, dev_name(p->dev)))
+			continue;
+		if (map->type != type)
+			continue;
+		if (map->type == PIN_MAP_TYPE_MUX_GROUP)
+			if (!strcmp(map->data.mux.group, name))
+				return map;
+		if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP)
+			if (!strcmp(map->data.configs.group_or_pin, name))
+				return map;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(pinctrl_lookup_map);
+
 static void devm_pinctrl_release(struct device *dev, void *res)
 {
 	pinctrl_put(*(struct pinctrl **)res);
include/linux/pinctrl/consumer.h +4 -0
index 4aad3ce..2687515 100644
@@ -36,6 +36,10 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
 							struct pinctrl *p,
 							const char *name);
 extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+extern const struct pinctrl_map * __must_check pinctrl_lookup_map(
+						struct pinctrl *p,
+						const char *name,
+						unsigned type);
 
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);
Signature · 1 line
1.7.10.4
maintainer
#6 lore raw

PATCH v5 3/10 pinctrl: append method of lookup pinctrl map

include/linux/pinctrl/consumer.h extern struct pinctrl_state * __must_check pinctrl_lookup_state( · line 45

Quoted 13 lines · Haojian Zhuang
include/linux/pinctrl/consumer.h +4 -0
@@ -36,6 +36,10 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
 							struct pinctrl *p,
 							const char *name);
 extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+extern const struct pinctrl_map * __must_check pinctrl_lookup_map(
+						struct pinctrl *p,
+						const char *name,
+						unsigned type);
 
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);

I think this should be in drivers/pinctrl/core.h, or is there a need for the consumer drivers to use this?

Regards,

Tony

#7 lore raw

PATCH v5 3/10 pinctrl: append method of lookup pinctrl map

Quoted 12 lines · Tony Lindgren
Quoted 11 lines · Haojian Zhuang
include/linux/pinctrl/consumer.h +4 -0
@@ -36,6 +36,10 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                      struct pinctrl *p,
                                                      const char *name);
 extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+extern const struct pinctrl_map * __must_check pinctrl_lookup_map(
+                                             struct pinctrl *p,
+                                             const char *name,
+                                             unsigned type);
 
Quoted 6 lines

include/linux/pinctrl/consumer.h extern struct pinctrl_state * __must_check pinctrl_lookup_state( · line 45

Quoted 2 lines
include/linux/pinctrl/consumer.h +0 -0
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);

I think this should be in drivers/pinctrl/core.h, or is there a need for the consumer drivers to use this?

Seems reasonable. I'll move into into core.h.

#8 lore raw

PATCH v5 4/10 pinctrl: generic: add input schmitt disable parameter

In reply to Haojian Zhuang

In Marvell PXA/MMP silicons, input schmitt disable value is 0x40, not 0. So append new config parameter -- input schmitt disable.

---
 drivers/pinctrl/pinconf-generic.c       |    1 +
 include/linux/pinctrl/pinconf-generic.h |    5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/pinctrl/pinconf-generic.c +1 -0
index 33fbaea..833a364 100644
@@ -41,6 +41,7 @@ struct pin_config_item conf_items[] = {
 	PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
 	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
 	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL),
 	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"),
include/linux/pinctrl/pinconf-generic.h +3 -2
index 4f0abb9..47a1bdd 100644
@@ -46,11 +46,11 @@
  * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
  *	(open emitter). Sending this config will enabale open drain mode, the
  *	argument is ignored.
+ * @PIN_CONFIG_INPUT_SCHMITT_DISABLE: disable schmitt-trigger mode on the pin.
  * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
  *	schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
  *	the threshold value is given on a custom format as argument when
- *	setting pins to this mode. The argument zero turns the schmitt trigger
- *	off.
+ *	setting pins to this mode.
  * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
  *	which means it will wait for signals to settle when reading inputs. The
  *	argument gives the debounce time on a custom format. Setting the
@@ -74,6 +74,7 @@ enum pin_config_param {
 	PIN_CONFIG_DRIVE_PUSH_PULL,
 	PIN_CONFIG_DRIVE_OPEN_DRAIN,
 	PIN_CONFIG_DRIVE_OPEN_SOURCE,
+	PIN_CONFIG_INPUT_SCHMITT_DISABLE,
 	PIN_CONFIG_INPUT_SCHMITT,
 	PIN_CONFIG_INPUT_DEBOUNCE,
 	PIN_CONFIG_POWER_SOURCE,
Signature · 1 line
1.7.10.4
#9 lore raw

PATCH v5 4/10 pinctrl: generic: add input schmitt disable parameter

Quoted 4 lines · Haojian Zhuang

In Marvell PXA/MMP silicons, input schmitt disable value is 0x40, not 0. So append new config parameter -- input schmitt disable.

I've applied this to the pinctrl tree, doesn't hurt anyone...

Yours,
Linus Walleij

#10 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

In reply to Haojian Zhuang

Add pinconf generic support with POWER SOURCE, BIAS PULL.

---
 drivers/pinctrl/Kconfig          |    1 +
 drivers/pinctrl/pinctrl-single.c |  322 +++++++++++++++++++++++++++++++++++---
 2 files changed, 305 insertions(+), 18 deletions(-)
drivers/pinctrl/Kconfig +1 -0
index 7bf914d..e9f2d2d 100644
@@ -139,6 +139,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 +304 -18

470 lines not on this page · raw message

Signature · 1 line
1.7.10.4
maintainer
#11 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

Hi,

Quoted 13 lines

static int pcs_pinconf_get(struct pinctrl_dev *pctldev,

drivers/pinctrl/pinctrl-single.c +9 -1
 				unsigned pin, unsigned long *config)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param config_param = pinconf_to_config_param(*config);
+	union pcs_pinconf_argument_t arg;
+	u32 offset;
+	unsigned data;
+	int ret;
+
+	if (!pcs->conf.nconfs)
+		return -ENOTSUPP;

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 548

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+
+	ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+	if (ret < 0)
+		return ret;
+
+	offset = pin * (pcs->width / BITS_PER_BYTE);
+	data = pcs->read(pcs->base + offset);
+
+	arg.data = pinconf_to_config_argument(ret);
+	data = (data >> arg.bits.shift) & arg.bits.mask;

Shouldn't you just return data here?

	*config = data;

	return 0;

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 551

Quoted 3 lines
drivers/pinctrl/pinctrl-single.c +3 -0
+	arg.bits.value = data;
+	*config = pinconf_to_config_packed(config_param, arg.data);
+	return 0;

Instead of these? Or how else is the consumer driver supposed to use the value?

Quoted 20 lines

}

static int pcs_pinconf_set(struct pinctrl_dev *pctldev,

drivers/pinctrl/pinctrl-single.c +14 -1
 				unsigned pin, unsigned long config)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param config_param = pinconf_to_config_param(config);
+	union pcs_pinconf_argument_t arg;
+	u32 offset;
+	unsigned data;
+	int ret;
+
+	if (!pcs->conf.nconfs)
+		return -ENOTSUPP;
+
+	ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+	if (ret < 0)
+		return ret;
+

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 580

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +9 -0
+	offset = pin * (pcs->width / BITS_PER_BYTE);
+	data = pcs->read(pcs->base + offset);
+
+	arg.data = pinconf_to_config_argument(config);
+	data = (data >> arg.bits.shift) & arg.bits.mask;
+	arg.bits.value = data;
+	data = pinconf_to_config_packed(config_param, arg.data);
+	pcs->write(data, pcs->base + offset);
+	return 0;
 }

I need to look at this more to understand how this actually relates to what gets written to the register with my test case :)

Quoted 32 lines
drivers/pinctrl/pinctrl-single.c +25 -3
@@ -765,12 +958,82 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 	if (res < 0)
 		goto free_function;
 
-	(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
-	(*map)->data.mux.group = np->name;
-	(*map)->data.mux.function = np->name;
+	m->type = PIN_MAP_TYPE_MUX_GROUP;
+	m->data.mux.group = np->name;
+	m->data.mux.function = np->name;
+
+	if (!nconfs)
+		return 0;
+
+	conf = devm_kzalloc(pcs->dev, sizeof(*conf) * nconfs, GFP_KERNEL);
+	if (!conf) {
+		res = -ENOMEM;
+		goto free_pingroup;
+	}
+	i = 0;
+	if (!of_property_read_u32_array(np, "pinctrl-single,bias",
+					value, 5)) {
+		/* array: bias value, mask, disable, pull down, pull up */
+		data = value[0] & value[1];
+		arg.bits.shift = ffs(value[1]) - 1;
+		arg.bits.mask = value[1] >> arg.bits.shift;
+		if (pcs_config_match(data, value[2])) {
+			arg.bits.value = value[2] >> arg.bits.shift;
+			conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_DISABLE,
+						    arg.data);
+		}
+		if (pcs_config_match(data, value[3])) {

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 995

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+			arg.bits.value = value[3] >> arg.bits.shift;
+			conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN,
+						    arg.data);
+		}
+		if (pcs_config_match(data, value[4])) {
+			arg.bits.value = value[4] >> arg.bits.shift;
+			conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP,
+						    arg.data);
+		}
+	}

Doesn't this mean you only get one of the above working? What happens if you initially need to set BIAS_DISABLE, but then the consumer driver wants to set BIAS_PULL_DOWN or something?

Maybe we need separate pinctrl-single,bias-disable, pinctrl-single,bias-pull-down and pinctrl-single,bias-pull-up?

Quoted 15 lines
drivers/pinctrl/pinctrl-single.c +15 -0
+	if (!of_property_read_u32_array(np, "pinctrl-single,power-source",
+					value, 2)) {
+		/* array: power source value, mask */
+		data = value[0] & value[1];
+		arg.bits.shift = ffs(value[1]) - 1;
+		arg.bits.mask = value[1] >> arg.bits.shift;
+		arg.bits.value = data >> arg.bits.shift;
+		conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_POWER_SOURCE, arg.data);
+	}
+	if (!of_property_read_u32_array(np, "pinctrl-single,input-schmitt",
+					value, 3)) {
+		/* array: input schmitt value, mask, disable */
+		data = value[0] & value[1];
+		arg.bits.shift = ffs(value[1]) - 1;
+		arg.bits.mask = value[1] >> arg.bits.shift;

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 1020

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+		if (pcs_config_match(data, value[2])) {
+			arg.bits.value = value[2] >> arg.bits.shift;
+			conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT_DISABLE,
+						    arg.data);
+		} else {
+			arg.bits.value = data >> arg.bits.shift;
+			conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT,
+						    arg.data);
+		}
+	}

And I think this has a similar problem? What if the consumer driver wants to set INPUT_SCHMITT with pin_config_set() and the initial value is SCHMITT_DISABLE? Doesn't the consumer driver get -ENOTSUPP in that case?

I'll look at this more early next week and try to get my testcase working with it.

Regards,

Tony

#12 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

Quoted 28 lines · Tony Lindgren

Hi,

Quoted 13 lines

static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{

drivers/pinctrl/pinctrl-single.c +9 -1
-     return -ENOTSUPP;
+     struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+     enum pin_config_param config_param = pinconf_to_config_param(*config);
+     union pcs_pinconf_argument_t arg;
+     u32 offset;
+     unsigned data;
+     int ret;
+
+     if (!pcs->conf.nconfs)
+             return -ENOTSUPP;

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 548

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+
+     ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+     if (ret < 0)
+             return ret;
+
+     offset = pin * (pcs->width / BITS_PER_BYTE);
+     data = pcs->read(pcs->base + offset);
+
+     arg.data = pinconf_to_config_argument(ret);
+     data = (data >> arg.bits.shift) & arg.bits.mask;

Shouldn't you just return data here?

Quoted 4 lines
        *config = data;

        return 0;

Since we're using pinconf-generic, let's review how pinconf_generic_dump_pin() works.

pinconf_generic_dump_pin():
config = pinconf_to_config_packed(conf_items[i].param, 0); The lower 16-bit values are parameters. and the upper 16-bit
values are pre-set with 0 for argument.

ret = pin_config_get_for_pin(pctldev, pin, &config); It'll invoke pcs_pinconf_get() that we're taking care. I want
to return the value with both argument
and parameters. Since the argument may be any location in 32-bit register, I organize them into packed
structure. If I return the value field directly, it may conflict with the lower 16-bit config parameter.

        if (conf_items[i].format && pinconf_to_config_argument(config) != 0)
            seq_printf(s, " (%u %s)",

pinconf_to_config_argument(config), conf_items[i].format);
At here, it loads the upper 16-bit config argument. It also
means that returning value field directly
will break this.

So how about change it in below.
if (conf_items[i].format)
seq_printf(s, " (%u %s)", config, conf_items[i].format);

Quoted 7 lines

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 551

Quoted 3 lines
drivers/pinctrl/pinctrl-single.c +3 -0
+     arg.bits.value = data;
+     *config = pinconf_to_config_packed(config_param, arg.data);
+     return 0;

Instead of these? Or how else is the consumer driver supposed to use the value?

I agree that returning data directly would be easy for the usage in device driver. Let's define it as "data >> shift".
Is it OK?

Quoted 25 lines
Quoted 25 lines

}

static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{

drivers/pinctrl/pinctrl-single.c +19 -1
-     return -ENOTSUPP;
+     struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+     enum pin_config_param config_param = pinconf_to_config_param(config);
+     union pcs_pinconf_argument_t arg;
+     u32 offset;
+     unsigned data;
+     int ret;
+
+     if (!pcs->conf.nconfs)
+             return -ENOTSUPP;
+
+     ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+     if (ret < 0)
+             return ret;
+
+     offset = pin * (pcs->width / BITS_PER_BYTE);
+     data = pcs->read(pcs->base + offset);
+
+     arg.data = pinconf_to_config_argument(config);
+     data = (data >> arg.bits.shift) & arg.bits.mask;
Quoted 8 lines

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 580

Quoted 5 lines
drivers/pinctrl/pinctrl-single.c +4 -0
+     arg.bits.value = data;
+     data = pinconf_to_config_packed(config_param, arg.data);
+     pcs->write(data, pcs->base + offset);
+     return 0;
 }

I need to look at this more to understand how this actually relates to what gets written to the register with my test case :)

No problem.

Quoted 48 lines
Quoted 33 lines
drivers/pinctrl/pinctrl-single.c +25 -3
@@ -765,12 +958,82 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
      if (res < 0)
              goto free_function;
 
-     (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
-     (*map)->data.mux.group = np->name;
-     (*map)->data.mux.function = np->name;
+     m->type = PIN_MAP_TYPE_MUX_GROUP;
+     m->data.mux.group = np->name;
+     m->data.mux.function = np->name;
+
+     if (!nconfs)
+             return 0;
+
+     conf = devm_kzalloc(pcs->dev, sizeof(*conf) * nconfs, GFP_KERNEL);
+     if (!conf) {
+             res = -ENOMEM;
+             goto free_pingroup;
+     }
+     i = 0;
+     if (!of_property_read_u32_array(np, "pinctrl-single,bias",
+                                     value, 5)) {
+             /* array: bias value, mask, disable, pull down, pull up */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;
+             if (pcs_config_match(data, value[2])) {
+                     arg.bits.value = value[2] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_DISABLE,
+                                                 arg.data);
+             }
+             if (pcs_config_match(data, value[3])) {

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 995

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+                     arg.bits.value = value[3] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN,
+                                                 arg.data);
+             }
+             if (pcs_config_match(data, value[4])) {
+                     arg.bits.value = value[4] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP,
+                                                 arg.data);
+             }
+     }

Doesn't this mean you only get one of the above working? What happens if you initially need to set BIAS_DISABLE, but then the consumer driver wants to set BIAS_PULL_DOWN or something?

Quoted 3 lines

Maybe we need separate pinctrl-single,bias-disable, pinctrl-single,bias-pull-down and pinctrl-single,bias-pull-up?

Good point. I'll separate them.

Quoted 26 lines
Quoted 15 lines
drivers/pinctrl/pinctrl-single.c +15 -0
+     if (!of_property_read_u32_array(np, "pinctrl-single,power-source",
+                                     value, 2)) {
+             /* array: power source value, mask */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;
+             arg.bits.value = data >> arg.bits.shift;
+             conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_POWER_SOURCE, arg.data);
+     }
+     if (!of_property_read_u32_array(np, "pinctrl-single,input-schmitt",
+                                     value, 3)) {
+             /* array: input schmitt value, mask, disable */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 1020

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+             if (pcs_config_match(data, value[2])) {
+                     arg.bits.value = value[2] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT_DISABLE,
+                                                 arg.data);
+             } else {
+                     arg.bits.value = data >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT,
+                                                 arg.data);
+             }
+     }
Quoted 4 lines

And I think this has a similar problem? What if the consumer driver wants to set INPUT_SCHMITT with pin_config_set() and the initial value is SCHMITT_DISABLE? Doesn't the consumer driver get -ENOTSUPP in that case?

OK. I'll update them.

Quoted 6 lines

I'll look at this more early next week and try to get my testcase working with it.

Regards,

Tony

#13 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

Quoted 52 lines · Haojian Zhuang
Quoted 28 lines · Tony Lindgren

Hi,

Quoted 13 lines

static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{

drivers/pinctrl/pinctrl-single.c +9 -1
-     return -ENOTSUPP;
+     struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+     enum pin_config_param config_param = pinconf_to_config_param(*config);
+     union pcs_pinconf_argument_t arg;
+     u32 offset;
+     unsigned data;
+     int ret;
+
+     if (!pcs->conf.nconfs)
+             return -ENOTSUPP;

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 548

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+
+     ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+     if (ret < 0)
+             return ret;
+
+     offset = pin * (pcs->width / BITS_PER_BYTE);
+     data = pcs->read(pcs->base + offset);
+
+     arg.data = pinconf_to_config_argument(ret);
+     data = (data >> arg.bits.shift) & arg.bits.mask;

Shouldn't you just return data here?

Quoted 4 lines
        *config = data;

        return 0;

Since we're using pinconf-generic, let's review how pinconf_generic_dump_pin() works.

pinconf_generic_dump_pin():
config = pinconf_to_config_packed(conf_items[i].param, 0); The lower 16-bit values are parameters. and the upper 16-bit
values are pre-set with 0 for argument.

ret = pin_config_get_for_pin(pctldev, pin, &config); It'll invoke pcs_pinconf_get() that we're taking care. I want
to return the value with both argument
and parameters. Since the argument may be any location in 32-bit register, I organize them into packed
structure. If I return the value field directly, it may conflict with the lower 16-bit config parameter.

        if (conf_items[i].format && pinconf_to_config_argument(config) != 0)
            seq_printf(s, " (%u %s)",
Quoted 9 lines

pinconf_to_config_argument(config), conf_items[i].format);
At here, it loads the upper 16-bit config argument. It also
means that returning value field directly
will break this.

So how about change it in below.
if (conf_items[i].format)
seq_printf(s, " (%u %s)", config, conf_items[i].format);

Oh. I messed with something. Let's the usage case again.

pin_config_set() sets the config value into pinmux register. The upper 16-bit is config argument, and the lower 16-bit is config parameter. The pinmux register
is 32-bit in Marvell's silicon. I think it's 32-bit value in most silicons.

And real field value could be lower 16-bit. So I have to pack mask, shift, config value
& config parameter into 32-bit data. The limitation is mask, shift, value are all 5-bit
value. And this is also the reason that I define pinctrl_lookup_map() into consumer.h.
How could consumer driver know mask & shift? It has to lookup map to get the real
configuration.

We also need to keep pin_config_get() compatible with pin_config_set(). I define the config data as packed mask, shift, config value & config parameter.

The conclusion is that we have two choices.
1. Use packed way. It's a little complex.
2. Change the interface of pin_config_set()/pin_config_get(). We need to use the new
interface in below.
pin_config_set(const char *dev_name, const char *name, unsigned
long parameter,
unsigned long config);
pin_config_get(const char *dev_name, const char *name, unsigned
long parameter,
unsigned long *config);
And the config should be "value >> shift".

What's your opinion? I prefer the second method since it's easy to understand and maintain.
Then I could hide pinctrl_lookup_map() in core.h.

Quoted 138 lines
Quoted 7 lines

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 551

Quoted 3 lines
drivers/pinctrl/pinctrl-single.c +3 -0
+     arg.bits.value = data;
+     *config = pinconf_to_config_packed(config_param, arg.data);
+     return 0;

Instead of these? Or how else is the consumer driver supposed to use the value?

I agree that returning data directly would be easy for the usage in device driver. Let's define it as "data >> shift".
Is it OK?

Quoted 25 lines
Quoted 25 lines

}

static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{

drivers/pinctrl/pinctrl-single.c +19 -1
-     return -ENOTSUPP;
+     struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+     enum pin_config_param config_param = pinconf_to_config_param(config);
+     union pcs_pinconf_argument_t arg;
+     u32 offset;
+     unsigned data;
+     int ret;
+
+     if (!pcs->conf.nconfs)
+             return -ENOTSUPP;
+
+     ret = pcs_pinconf_get_config(pctldev, pin, config_param);
+     if (ret < 0)
+             return ret;
+
+     offset = pin * (pcs->width / BITS_PER_BYTE);
+     data = pcs->read(pcs->base + offset);
+
+     arg.data = pinconf_to_config_argument(config);
+     data = (data >> arg.bits.shift) & arg.bits.mask;
Quoted 8 lines

drivers/pinctrl/pinctrl-single.c static struct pinmux_ops pcs_pinmux_ops = { · line 580

Quoted 5 lines
drivers/pinctrl/pinctrl-single.c +4 -0
+     arg.bits.value = data;
+     data = pinconf_to_config_packed(config_param, arg.data);
+     pcs->write(data, pcs->base + offset);
+     return 0;
 }

I need to look at this more to understand how this actually relates to what gets written to the register with my test case :)

No problem.

Quoted 48 lines
Quoted 33 lines
drivers/pinctrl/pinctrl-single.c +25 -3
@@ -765,12 +958,82 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
      if (res < 0)
              goto free_function;
 
-     (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
-     (*map)->data.mux.group = np->name;
-     (*map)->data.mux.function = np->name;
+     m->type = PIN_MAP_TYPE_MUX_GROUP;
+     m->data.mux.group = np->name;
+     m->data.mux.function = np->name;
+
+     if (!nconfs)
+             return 0;
+
+     conf = devm_kzalloc(pcs->dev, sizeof(*conf) * nconfs, GFP_KERNEL);
+     if (!conf) {
+             res = -ENOMEM;
+             goto free_pingroup;
+     }
+     i = 0;
+     if (!of_property_read_u32_array(np, "pinctrl-single,bias",
+                                     value, 5)) {
+             /* array: bias value, mask, disable, pull down, pull up */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;
+             if (pcs_config_match(data, value[2])) {
+                     arg.bits.value = value[2] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_DISABLE,
+                                                 arg.data);
+             }
+             if (pcs_config_match(data, value[3])) {

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 995

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+                     arg.bits.value = value[3] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN,
+                                                 arg.data);
+             }
+             if (pcs_config_match(data, value[4])) {
+                     arg.bits.value = value[4] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP,
+                                                 arg.data);
+             }
+     }

Doesn't this mean you only get one of the above working? What happens if you initially need to set BIAS_DISABLE, but then the consumer driver wants to set BIAS_PULL_DOWN or something?

Quoted 3 lines

Maybe we need separate pinctrl-single,bias-disable, pinctrl-single,bias-pull-down and pinctrl-single,bias-pull-up?

Good point. I'll separate them.

Quoted 26 lines
Quoted 15 lines
drivers/pinctrl/pinctrl-single.c +15 -0
+     if (!of_property_read_u32_array(np, "pinctrl-single,power-source",
+                                     value, 2)) {
+             /* array: power source value, mask */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;
+             arg.bits.value = data >> arg.bits.shift;
+             conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_POWER_SOURCE, arg.data);
+     }
+     if (!of_property_read_u32_array(np, "pinctrl-single,input-schmitt",
+                                     value, 3)) {
+             /* array: input schmitt value, mask, disable */
+             data = value[0] & value[1];
+             arg.bits.shift = ffs(value[1]) - 1;
+             arg.bits.mask = value[1] >> arg.bits.shift;

drivers/pinctrl/pinctrl-single.c static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, · line 1020

Quoted 10 lines
drivers/pinctrl/pinctrl-single.c +10 -0
+             if (pcs_config_match(data, value[2])) {
+                     arg.bits.value = value[2] >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT_DISABLE,
+                                                 arg.data);
+             } else {
+                     arg.bits.value = data >> arg.bits.shift;
+                     conf[i++] = PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT,
+                                                 arg.data);
+             }
+     }
Quoted 4 lines

And I think this has a similar problem? What if the consumer driver wants to set INPUT_SCHMITT with pin_config_set() and the initial value is SCHMITT_DISABLE? Doesn't the consumer driver get -ENOTSUPP in that case?

OK. I'll update them.

Quoted 6 lines

I'll look at this more early next week and try to get my testcase working with it.

Regards,

Tony

maintainer
#14 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

Quoted 5 lines · Haojian Zhuang

pin_config_set() sets the config value into pinmux register. The upper 16-bit is config argument, and the lower 16-bit is config parameter. The pinmux register
is 32-bit in Marvell's silicon. I think it's 32-bit value in most silicons.

Well what if we soon have a 64-bit mux register? We should probably reserve more than 5 bits for the shift to handle those cases as well.

Quoted 6 lines

And real field value could be lower 16-bit. So I have to pack mask, shift, config value
& config parameter into 32-bit data. The limitation is mask, shift, value are all 5-bit
value. And this is also the reason that I define pinctrl_lookup_map() into consumer.h.

Yes this might be problematic for 64-bit systems..

Quoted 3 lines

How could consumer driver know mask & shift? It has to lookup map to get the real
configuration.

I think the consumer driver should not know anything about the mask & shift.

Quoted 5 lines

We also need to keep pin_config_get() compatible with pin_config_set(). I define the config data as packed mask, shift, config value & config parameter.

The conclusion is that we have two choices.
1. Use packed way. It's a little complex.

I think the packed way won't work well for consumer drivers.

Quoted 11 lines

2. Change the interface of pin_config_set()/pin_config_get(). We need to use the new
interface in below.
pin_config_set(const char *dev_name, const char *name, unsigned
long parameter,
unsigned long config);
pin_config_get(const char *dev_name, const char *name, unsigned
long parameter,
unsigned long *config);
And the config should be "value >> shift".

Quoted 3 lines

What's your opinion? I prefer the second method since it's easy to understand and maintain.
Then I could hide pinctrl_lookup_map() in core.h.

Yes something like that makes sense to me. Except IMHO we should use some cookie for a pin instead of dev_name + name, and have some struct for the config. Something like this perhaps:

pin_config_get(struct pin *pin, struct pin_config *config,

		unsigned long parameter);

Regards,

Tony

maintainer
#15 lore raw

PATCH v5 5/10 pinctrl: single: support pinconf generic

In reply to Haojian Zhuang
Quoted 5 lines · Haojian Zhuang

On Sat, Nov 17, 2012 at 8:43 AM, Tony Lindgren <[email protected]> wrote:

I agree that returning data directly would be easy for the usage in device driver. Let's define it as "data >> shift".
Is it OK?

Yes returning data >> shift makes sense to me from consumer driver point of view, so I guess then it's just what I too suggested:

data = (data >> arg.bits.shift) & arg.bits.mask;
*config = data;

Or did I miss something?

Regards,

Tony

#16 lore raw

PATCH v5 6/10 ARM: dts: support pinctrl single in pxa910

In reply to Haojian Zhuang

Add pinctrl-single support with device tree in pxa910 dkb platform.

---
 arch/arm/boot/dts/pxa910-dkb.dts |  204 +++++++++++++++++++++++++++++++++++++-
 arch/arm/boot/dts/pxa910.dtsi    |   68 +++++++++++++
 2 files changed, 271 insertions(+), 1 deletion(-)
arch/arm/boot/dts/pxa910-dkb.dts +203 -1
index 595492a..76e9c8d 100644
@@ -24,10 +24,212 @@
 
 	soc {
 		apb at d4000000 {
-			uart1: uart at d4017000 {
+			pmx: pinmux at d401e000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&board_pins>;
+
+				board_pins: pinmux_board_pins {
+					/* pins not owned by device driver */
+					/* w1 */
+					pinctrl-single,pins = <
+						0x0cc 0x2	/* CLK_REQ_W1 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				uart1_pins: pinmux_uart1_pins {
+					pinctrl-single,pins = <
+						0x198 0x6	/* GPIO47_UART1_RXD */
+						0x19c 0x6	/* GPIO48_UART1_TXD */
+					>;
+					/* power source, mask */
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					/* bias, mask, disable, pull down, pull up */
+					pinctrl-single,bias = <0xc000 0xe000 0 0xa000 0xc000>;
+					/* input schmitt, mask, disable */
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				uart2_pins: pinmux_uart2_pins {
+					pinctrl-single,pins = <
+						0x150 0x4	/* GPIO29_UART2_CTS */
+						0x154 0x4	/* GPIO30_UART2_RTS */
+						0x158 0x4	/* GPIO31_UART2_TXD */
+						0x15c 0x4	/* GPIO32_UART2_RXD */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				uart3_pins: pinmux_uart3_pins {
+					pinctrl-single,pins = <
+						0x188 0x7	/* GPIO43_UART3_RXD */
+						0x18c 0x7	/* GPIO44_UART3_TXD */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				twsi1_pins: pinmux_twsi1_pins {
+					pinctrl-single,pins = <
+						0x1b0 0x2	/* GPIO53_TWSI_SCL */
+						0x1b4 0x2	/* GPIO54_TWSI_SDA */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				nand_pins: pinmux_nand_pins {
+					pinctrl-single,pins = <
+						0x040 0x0	/* ND_IO0 */
+						0x03c 0x0	/* ND_IO1 */
+						0x038 0x0	/* ND_IO2 */
+						0x034 0x0	/* ND_IO3 */
+						0x030 0x0	/* ND_IO4 */
+						0x02c 0x0	/* ND_IO5 */
+						0x028 0x0	/* ND_IO6 */
+						0x024 0x0	/* ND_IO7 */
+						0x020 0x0	/* ND_IO8 */
+						0x01c 0x0	/* ND_IO9 */
+						0x018 0x0	/* ND_IO10 */
+						0x014 0x0	/* ND_IO11 */
+						0x010 0x0	/* ND_IO12 */
+						0x00c 0x0	/* ND_IO13 */
+						0x008 0x0	/* ND_IO14 */
+						0x004 0x0	/* ND_IO15 */
+						0x044 0x0	/* ND_nCS0 */
+						0x060 0x1	/* ND_ALE */
+						0x05c 0x0	/* ND_CLE */
+						0x054 0x1	/* ND_nWE */
+						0x058 0x1	/* ND_nRE */
+						0x068 0x0	/* ND_RDY0 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				mmc1_ldata_pins: pinmux_mmc1_ldata_pins {
+					pinctrl-single,pins = <
+						0x0a0 0x0	/* MMC1_DATA0 */
+						0x09c 0x0	/* MMC1_DATA1 */
+						0x098 0x0	/* MMC1_DATA2 */
+						0x094 0x0	/* MMC1_DATA3 */
+					>;
+					pinctrl-single,power-source = <0x1800 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				mmc1_hdata_pins: pinmux_mmc1_hdata_pins {
+					pinctrl-single,pins = <
+						0x090 0x0	/* MMC1_DATA4 */
+						0x08c 0x0	/* MMC1_DATA5 */
+						0x088 0x0	/* MMC1_DATA6 */
+						0x084 0x0	/* MMC1_DATA7 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				mmc1_clk_pins: pinmux_mmc1_clk_pins {
+					pinctrl-single,pins = <
+						0x0a4 0x0	/* MMC1_CMD */
+						0x0a8 0x0	/* MMC1_CLK */
+					>;
+					pinctrl-single,power-source = <0x1800 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				mmc1_cd_pins: pinmux_mmc1_cd_pins {
+					pinctrl-single,pins = <
+						0x0ac 0x0	/* MMC1_CD */
+						0x0b0 0x0	/* MMC1_WP */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				mmc2_pins: pinmux_mmc2_pins {
+					pinctrl-single,pins = <
+						0x180 0x1	/* MMC2_CMD */
+						0x184 0x1	/* MMC2_CLK */
+						0x17c 0x1	/* MMC2_DATA0 */
+						0x178 0x1	/* MMC2_DATA1 */
+						0x174 0x1	/* MMC2_DATA2 */
+						0x170 0x1	/* MMC2_DATA3 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				ssp1_pins: pinmux_ssp1_pins {
+					pinctrl-single,pins = <
+						0x130 0x1	/* GPIO21_SSP1_SCLK */
+						0x134 0x1	/* GPIO22_SSP1_FRM */
+						0x138 0x1	/* GPIO23_SSP1_TXD */
+						0x13c 0x1	/* GPIO24_SSP1_RXD */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				keypad_pins: pinmux_keypad_pins {
+					pinctrl-single,pins = <
+						0x0dc 0x1	/* GPIO0_MKIN0 */
+						0x0e0 0x1	/* GPIO1_MKOUT0 */
+						0x0e4 0x1	/* GPIO2_MKIN1 */
+						0x0e8 0x1	/* GPIO3_MKOUT1 */
+						0x0ec 0x1	/* GPIO4_MKIN2 */
+						0x0f0 0x1	/* GPIO5_MKOUT2 */
+						0x0f4 0x1	/* GPIO6_MKIN3 */
+						0x0f8 0x1	/* GPIO7_MKOUT3 */
+						0x0fc 0x1	/* GPIO8_MKIN4 */
+						0x100 0x1	/* GPIO9_MKOUT4 */
+						0x10c 0x1	/* GPIO12_MKIN6 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				nfc_pins: pinmux_nfc_pins {
+					pinctrl-single,pins = <
+						0x120 0x0	/* GPIO17 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+				wlan_pins: pinmux_wlan_pins {
+					pinctrl-single,pins = <
+						0x114 0x0	/* GPIO14 */
+						0x12c 0x0	/* GPIO20 */
+						0x160 0x0	/* GPIO33 */
+						0x164 0x0	/* GPIO34 */
+						0x168 0x0	/* GPIO35 */
+						0x16c 0x0	/* GPIO36 */
+					>;
+					pinctrl-single,power-source = <0x1000 0x1800>;
+					pinctrl-single,bias = <0 0xe000 0 0xa000 0xc000>;
+					pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+				};
+			};
+			uart1: uart at d4017000 {	/* FFUART */
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart1_pins>;
+				status = "okay";
+			};
+			uart2: uart at d4018000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart2_pins>;
+				status = "okay";
+			};
+			uart3: uart at d4036000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart3_pins>;
 				status = "okay";
 			};
 			twsi1: i2c at d4011000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&twsi1_pins>;
 				status = "okay";
 
 				pmic: 88pm860x at 34 {
arch/arm/boot/dts/pxa910.dtsi +68 -0

74 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#17 lore raw

PATCH v5 7/10 document: devicetree: bind pinconf with pin single

In reply to Haojian Zhuang

Add comments with pinconf & gpio range in the document of pinctrl-single.

---
 .../devicetree/bindings/pinctrl/pinctrl-single.txt |   82 +++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +81 -1
index 2c81e45..8f0c0dd 100644
@@ -1,7 +1,9 @@
 One-register-per-pin type device tree based pinctrl driver
 
 Required properties:
-- compatible : "pinctrl-single"
+- compatible : "pinctrl-single" or "pinconf-single".
+  "pinctrl-single" means that pinconf isn't supported.
+  "pinconf-single" means that generic pinconf is supported.
 
 - reg : offset and length of the register set for the mux registers
 
@@ -14,9 +16,31 @@ Optional properties:
 - pinctrl-single,function-off : function off mode for disabled state if
   available and same for all registers; if not specified, disabling of
   pin functions is ignored
+
 - pinctrl-single,bit-per-mux : boolean to indicate that one register controls
   more than one pin
 
+- pinctrl-single,power-source : array of value that are used to configure
+  power source in the pinmux register. They're value of power source field
+  and power source mask.
+
+		/* power source, mask */
+		pinctrl-single,power-source = <0x1000 0x1800>;
+
+- pinctrl-single,bias : array of value that are used to configure the input
+  bias in the pinmux register.  They're value of bias field, bias mask,
+  bias disable value, bias pull down value & bias pull up value.
+
+		/* bias, mask, disable, pull down, pull up */
+		pinctrl-single,bias = <0xc000 0xe000 0 0xa000 0xc000>;
+
+- pinctrl-single,input-schmitt : array of value that are used to configure
+  input schmitt in the pinmux register. They're value of input schmitt field,
+  mask, & disable value.
+
+		/* input schmitt value, mask, disable */
+		pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+
 This driver assumes that there is only one register for each pin (unless the
 pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
 specified in the pinctrl-bindings.txt document in this directory.
@@ -42,6 +66,24 @@ Where 0xdc is the offset from the pinctrl register base address for the
 device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
 be used when applying this change to the register.
 
+
+Optional sub-node: In case some pins could be configured as GPIO in the pinmux
+register, those pins could be defined as a GPIO range. The sub-node should
+be defined in .dtsi files of those silicons.
+
+Required properties in sub-node:
+- reg : offset and length of the GPIO range sub-node.
+
+- pinctrl-single,gpio : array of GPIO base number in the range and the GPIO
+  function in the pinmux register.
+
+	range0: {
+		/* GPIO0 ~ GPIO54 */
+		reg = <0xd401e0dc 55>;
+		pinctrl-single,gpio = <0 0>;
+	};
+
+
 Example:
 
 /* SoC common file */
@@ -76,6 +118,26 @@ control_devconf0: pinmux at 48002274 {
 	pinctrl-single,function-mask = <0x5F>;
 };
 
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux at d401e000 {
+	compatible = "pinconf-single";
+	reg = <0xd401e000 0x0330>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	pinctrl-single,register-width = <32>;
+	pinctrl-single,function-mask = <7>;
+
+	range0: range at d401e0dc {
+		/* GPIO0 ~ GPIO54 */
+		reg = <0xd401e0dc 0xdc>;
+		/* gpio base & gpio func */
+		pinctrl-single,gpio = <0 0>;
+	};     
+};
+
+
 /* board specific .dts file */
 
 &pmx_core {
@@ -96,6 +158,19 @@ control_devconf0: pinmux at 48002274 {
 		>;
 	};
 
+	uart1_pins: pinmux_uart1_pins {
+		pinctrl-single,pins = <
+			0x198 0x6	/* GPIO47_UART1_RXD */
+			0x19c 0x6	/* GPIO48_UART1_TXD */
+		>;
+		/* power source, mask */
+		pinctrl-single,power-source = <0x1000 0x1800>;
+		/* bias, mask, disable, pull down, pull up */
+		pinctrl-single,bias = <0xc000 0xe000 0 0xa000 0xc000>;
+		/* input schmitt, mask, disable */
+		pinctrl-single,input-schmitt = <0x40 0x70 0x40>;
+	};
+
 	/* map uart2 pins */
 	uart2_pins: pinmux_uart2_pins {
 		pinctrl-single,pins = <
@@ -122,6 +197,11 @@ control_devconf0: pinmux@48002274 {
 
 };
 
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>;
+};
+
 &uart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart2_pins>;
Signature · 1 line
1.7.10.4
#18 lore raw

PATCH v5 7/10 document: devicetree: bind pinconf with pin single

Quoted 15 lines · Haojian Zhuang

Add comments with pinconf & gpio range in the document of pinctrl-single.

+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt

+- pinctrl-single,power-source : array of value that are used to configure

Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +9 -0
+  power source in the pinmux register. They're value of power source field
+  and power source mask.
+
+		/* power source, mask */
+		pinctrl-single,power-source = <0x1000 0x1800>;
+
+- pinctrl-single,bias : array of value that are used to configure the input
+  bias in the pinmux register.  They're value of bias field, bias mask,
+  bias disable value, bias pull down value & bias pull up value.

Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt Optional properties: · line 42

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +10 -0
+
+		/* bias, mask, disable, pull down, pull up */
+		pinctrl-single,bias = <0xc000 0xe000 0 0xa000 0xc000>;
+
+- pinctrl-single,input-schmitt : array of value that are used to configure
+  input schmitt in the pinmux register. They're value of input schmitt field,
+  mask, & disable value.
+
+		/* input schmitt value, mask, disable */
+		pinctrl-single,input-schmitt = <0x40 0x70 0x40>;

For all 3 of those, the first cell in the property is "value". What does "value" represent? Surely the properties in the pinmux controller node itself just specify how to write to the field (so should specify field mask, and perhaps values for specific enums). However, any "value" to be actually written to the field should be specified by the pin configuration (sub) nodes, not the global top-level properties.

#19 lore raw

PATCH v5 8/10 tty: pxa: configure pin

In reply to Haojian Zhuang

Configure pins by pinctrl driver.

---
 drivers/tty/serial/pxa.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/tty/serial/pxa.c +7 -1
index 9033fc6..02dc771 100644
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -809,6 +810,7 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
 			       struct uart_pxa_port *sport)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pinctrl *pinctrl;
 	int ret;
 
 	if (!np)
@@ -819,6 +821,10 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
 		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
 		return ret;
 	}
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		return -EPROBE_DEFER;
+
 	sport->port.line = ret;
 	return 0;
 }
@@ -857,7 +863,7 @@ static int serial_pxa_probe(struct platform_device *dev)
 	ret = serial_pxa_probe_dt(dev, sport);
 	if (ret > 0)
 		sport->port.line = dev->id;
-	else if (ret < 0)
+	if (ret < 0)
 		goto err_clk;
 	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
 
Signature · 1 line
1.7.10.4
#20 lore raw

PATCH v5 9/10 i2c: pxa: use devm_kzalloc

In reply to Haojian Zhuang

Use devm_kzalloc & add checking in probe() function.

---
 drivers/i2c/busses/i2c-pxa.c |   26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)
drivers/i2c/busses/i2c-pxa.c +10 -16
index 1034d93..7c8b5d0 100644
@@ -1078,6 +1078,8 @@ static int i2c_pxa_probe_pdata(struct platform_device *pdev,
 	struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
 	const struct platform_device_id *id = platform_get_device_id(pdev);
 
+	if (!id)
+		return -EINVAL;
 	*i2c_types = id->driver_data;
 	if (plat) {
 		i2c->use_pio = plat->use_pio;
@@ -1094,29 +1096,23 @@ static int i2c_pxa_probe(struct platform_device *dev)
 	struct resource *res = NULL;
 	int ret, irq;
 
-	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
-	if (!i2c) {
-		ret = -ENOMEM;
-		goto emalloc;
-	}
+	i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
 
 	ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
 	if (ret > 0)
 		ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
 	if (ret < 0)
-		goto eclk;
+		return ret;
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(dev, 0);
-	if (res == NULL || irq < 0) {
-		ret = -ENODEV;
-		goto eclk;
-	}
+	if (res == NULL || irq < 0)
+		return -ENODEV;
 
-	if (!request_mem_region(res->start, resource_size(res), res->name)) {
-		ret = -ENOMEM;
-		goto eclk;
-	}
+	if (!request_mem_region(res->start, resource_size(res), res->name))
+		return -ENOMEM;
 
 	i2c->adap.owner   = THIS_MODULE;
 	i2c->adap.retries = 5;
@@ -1209,8 +1205,6 @@ ereqirq:
 eremap:
 	clk_put(i2c->clk);
 eclk:
-	kfree(i2c);
-emalloc:
 	release_mem_region(res->start, resource_size(res));
 	return ret;
 }
Signature · 1 line
1.7.10.4
#21 lore raw

PATCH v5 10/10 i2c: pxa: configure pinmux

In reply to Haojian Zhuang

Configure pins by pinctrl driver.

---
 drivers/i2c/busses/i2c-pxa.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/i2c/busses/i2c-pxa.c +5 -0
index 7c8b5d0..11e4a30 100644
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -1051,6 +1052,7 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
 			    enum pxa_i2c_types *i2c_types)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pinctrl *pinctrl;
 	const struct of_device_id *of_id =
 			of_match_device(i2c_pxa_dt_ids, &pdev->dev);
 	int ret;
@@ -1063,6 +1065,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
 		return ret;
 	}
 	pdev->id = ret;
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		return -EPROBE_DEFER;
 	if (of_get_property(np, "mrvl,i2c-polling", NULL))
 		i2c->use_pio = 1;
 	if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
Signature · 1 line
1.7.10.4