Subject: [PATCH 2/2] pinctrl: add function to separate combined pinconfig values

From: [email-masked] (Heiko Stübner)
Date: Sun, 9 Jun 2013 02:00:29 +0200

The previous patch introduced constants to combine pinconfig settings
into one value for easier devicetree handling.

Therefore also add a function, that can separate these bitmaps into
regular generic pinconfig options for handling inside pinctrl drivers.

Signed-off-by: Heiko Stuebner <[email-masked]>
---
 .../bindings/pinctrl/pinctrl-bindings.txt          |    3 +
 drivers/pinctrl/pinconf-generic.c                  |   61 ++++++++++++++++++++
 drivers/pinctrl/pinconf.h                          |    6 ++
 3 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index d206da0..55141af 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -132,3 +132,6 @@ controller device.
 dt-bindings/pinctrl/pinconfig.h defines a set of constants to combine basic
 generic pinconfig settings, like pulls, into one value, that can be used
 in pinctrl bindings like <bank pin mux CONFIG>.
+
+This value can then be split into individual generic pinconfig values in the
+driver using pinconf_generic_parse_dt_bitmap.
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 9a6812b..90896fe 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -139,3 +139,64 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
 }
 EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
 #endif
+
+/*
+ * Maps the devicetree config bits to actual pinconf values.
+ * The array indizes match the bits set in dt-bindings/pinctrl/pinconf.h
+ * and the array should contain an entry for each bit defined there
+ */
+static unsigned long conf_map[] = {
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_DISABLE, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_BUS_HOLD, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_DOWN, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_DRIVE_PUSH_PULL, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_DRIVE_OPEN_DRAIN, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_DRIVE_OPEN_SOURCE, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1),
+	PIN_CONF_PACKED(PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_LOW_POWER_MODE, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 0),
+	PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 1),
+};
+
+/*
+ * Parse a pinconf bitmap from a devicetree entry into individual pin configs.
+ * @pinconf: the bitmap containing config bits
+ * @configs: after the function returns contains a pointer to an array of
+ *	     pin configs
+ * @nconfigs: number of entries of configs
+ */
+int pinconf_generic_parse_dt_bitmap(unsigned long pinconf,
+				    unsigned long **configs,
+				    unsigned int *nconfigs)
+{
+	int bit;
+	int i;
+	unsigned long *cnf;
+	unsigned int ncnf;
+
+	ncnf = hweight_long(pinconf);
+	cnf = kzalloc(ncnf * sizeof(unsigned long), GFP_KERNEL);
+
+	i = 0;
+	while (pinconf && i < ncnf) {
+		bit = __ffs(pinconf);
+		pinconf &= ~BIT(i);
+
+		if (bit > ARRAY_SIZE(conf_map)) {
+			pr_err("%s: unknown bit %d\n", __func__, bit);
+			kfree(cnf);
+			return -EINVAL;
+		}
+
+		cnf[i] = conf_map[bit];
+		i++;
+	}
+
+	*configs = cnf;
+	*nconfigs = ncnf;
+	return 0;
+}
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 92c7267..ae7480c 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -123,3 +123,9 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
 	return;
 }
 #endif
+
+#ifdef CONFIG_GENERIC_PINCONF
+int pinconf_generic_parse_dt_bitmap(unsigned long pinconf,
+				    unsigned long **configs,
+				    unsigned int *nconfigs);
+#endif
-- 
1.7.2.3