pinctrl: imx: move hard-coding data into device tree

Currently, all imx pinctrl drivers maintain a big array of struct
imx_pin_reg which hard-codes data like register offset and mux mode
setting for each pin function.  Every time a new imx SoC support is
added, we need to add such a big mount of data.  With moving to single
kernel build, it's only matter of time to be blamed on memory consuming.

With DTC pre-processor support in place, the patch moves all these data
into device tree by redefining the PIN_FUNC_ID in imxXX-pinfunc.h and
changing the PIN_FUNC_ID parsing code a little bit.

The pin id gets re-numbered based on mux register offset, or config
register offset if the pin has no mux register, so that kernel can
identify the pin id from register offsets provided by device tree.

As a bonus point of the change, those arbitrary magic numbers standing
for particular PIN_FUNC_ID in device tree sources are now replaced by
macros to improve the readability of dts files.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 4cebb9c..93f50e2 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -54,32 +54,6 @@
 	const struct imx_pinctrl_soc_info *info;
 };
 
-static const struct imx_pin_reg *imx_find_pin_reg(
-				const struct imx_pinctrl_soc_info *info,
-				unsigned pin, bool is_mux, unsigned mux)
-{
-	const struct imx_pin_reg *pin_reg = NULL;
-	int i;
-
-	for (i = 0; i < info->npin_regs; i++) {
-		pin_reg = &info->pin_regs[i];
-		if (pin_reg->pid != pin)
-			continue;
-		if (!is_mux)
-			break;
-		else if (pin_reg->mux_mode == (mux & IMX_MUX_MASK))
-			break;
-	}
-
-	if (i == info->npin_regs) {
-		dev_err(info->dev, "Pin(%s): unable to find pin reg map\n",
-			info->pins[pin].name);
-		return NULL;
-	}
-
-	return pin_reg;
-}
-
 static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
 				const struct imx_pinctrl_soc_info *info,
 				const char *name)
@@ -223,7 +197,8 @@
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg;
-	const unsigned *pins, *mux;
+	const unsigned *pins, *mux, *input_val;
+	u16 *input_reg;
 	unsigned int npins, pin_id;
 	int i;
 
@@ -234,18 +209,17 @@
 	pins = info->groups[group].pins;
 	npins = info->groups[group].npins;
 	mux = info->groups[group].mux_mode;
+	input_val = info->groups[group].input_val;
+	input_reg = info->groups[group].input_reg;
 
-	WARN_ON(!pins || !npins || !mux);
+	WARN_ON(!pins || !npins || !mux || !input_val || !input_reg);
 
 	dev_dbg(ipctl->dev, "enable function %s group %s\n",
 		info->functions[selector].name, info->groups[group].name);
 
 	for (i = 0; i < npins; i++) {
 		pin_id = pins[i];
-
-		pin_reg = imx_find_pin_reg(info, pin_id, 1, mux[i]);
-		if (!pin_reg)
-			return -EINVAL;
+		pin_reg = &info->pin_regs[pin_id];
 
 		if (!pin_reg->mux_reg) {
 			dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
@@ -258,11 +232,11 @@
 			pin_reg->mux_reg, mux[i]);
 
 		/* some pins also need select input setting, set it if found */
-		if (pin_reg->input_reg) {
-			writel(pin_reg->input_val, ipctl->base + pin_reg->input_reg);
+		if (input_reg[i]) {
+			writel(input_val[i], ipctl->base + input_reg[i]);
 			dev_dbg(ipctl->dev,
 				"==>select_input: offset 0x%x val 0x%x\n",
-				pin_reg->input_reg, pin_reg->input_val);
+				input_reg[i], input_val[i]);
 		}
 	}
 
@@ -311,11 +285,7 @@
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg;
-
-	pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
-	if (!pin_reg)
-		return -EINVAL;
+	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 
 	if (!pin_reg->conf_reg) {
 		dev_err(info->dev, "Pin(%s) does not support config function\n",
@@ -333,11 +303,7 @@
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg;
-
-	pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
-	if (!pin_reg)
-		return -EINVAL;
+	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 
 	if (!pin_reg->conf_reg) {
 		dev_err(info->dev, "Pin(%s) does not support config function\n",
@@ -360,10 +326,9 @@
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg;
+	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 	unsigned long config;
 
-	pin_reg = imx_find_pin_reg(info, pin_id, 0, 0);
 	if (!pin_reg || !pin_reg->conf_reg) {
 		seq_printf(s, "N/A");
 		return;
@@ -411,29 +376,20 @@
 	.owner = THIS_MODULE,
 };
 
-/* decode pin id and mux from pin function id got from device tree*/
-static int imx_pinctrl_get_pin_id_and_mux(const struct imx_pinctrl_soc_info *info,
-				unsigned int pin_func_id, unsigned int *pin_id,
-				unsigned int *mux)
-{
-	if (pin_func_id > info->npin_regs)
-		return -EINVAL;
-
-	*pin_id = info->pin_regs[pin_func_id].pid;
-	*mux = info->pin_regs[pin_func_id].mux_mode;
-
-	return 0;
-}
+/*
+ * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
+ * 1 u32 CONFIG, so 24 types in total for each pin.
+ */
+#define FSL_PIN_SIZE 24
 
 static int imx_pinctrl_parse_groups(struct device_node *np,
 				    struct imx_pin_group *grp,
 				    struct imx_pinctrl_soc_info *info,
 				    u32 index)
 {
-	unsigned int pin_func_id;
-	int ret, size;
+	int size;
 	const __be32 *list;
-	int i, j;
+	int i;
 	u32 config;
 
 	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
@@ -447,32 +403,40 @@
 	 */
 	list = of_get_property(np, "fsl,pins", &size);
 	/* we do not check return since it's safe node passed down */
-	size /= sizeof(*list);
-	if (!size || size % 2) {
-		dev_err(info->dev, "wrong pins number or pins and configs should be pairs\n");
+	if (!size || size % FSL_PIN_SIZE) {
+		dev_err(info->dev, "Invalid fsl,pins property\n");
 		return -EINVAL;
 	}
 
-	grp->npins = size / 2;
+	grp->npins = size / FSL_PIN_SIZE;
 	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
 				GFP_KERNEL);
 	grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
 				GFP_KERNEL);
+	grp->input_reg = devm_kzalloc(info->dev, grp->npins * sizeof(u16),
+				GFP_KERNEL);
+	grp->input_val = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+				GFP_KERNEL);
 	grp->configs = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned long),
 				GFP_KERNEL);
-	for (i = 0, j = 0; i < size; i += 2, j++) {
-		pin_func_id = be32_to_cpu(*list++);
-		ret = imx_pinctrl_get_pin_id_and_mux(info, pin_func_id,
-					&grp->pins[j], &grp->mux_mode[j]);
-		if (ret) {
-			dev_err(info->dev, "get invalid pin function id\n");
-			return -EINVAL;
-		}
+	for (i = 0; i < grp->npins; i++) {
+		u32 mux_reg = be32_to_cpu(*list++);
+		u32 conf_reg = be32_to_cpu(*list++);
+		unsigned int pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
+		struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+
+		grp->pins[i] = pin_id;
+		pin_reg->mux_reg = mux_reg;
+		pin_reg->conf_reg = conf_reg;
+		grp->input_reg[i] = be32_to_cpu(*list++);
+		grp->mux_mode[i] = be32_to_cpu(*list++);
+		grp->input_val[i] = be32_to_cpu(*list++);
+
 		/* SION bit is in mux register */
 		config = be32_to_cpu(*list++);
 		if (config & IMX_PAD_SION)
-			grp->mux_mode[j] |= IOMUXC_CONFIG_SION;
-		grp->configs[j] = config & ~IMX_PAD_SION;
+			grp->mux_mode[i] |= IOMUXC_CONFIG_SION;
+		grp->configs[i] = config & ~IMX_PAD_SION;
 	}
 
 #ifdef DEBUG
@@ -568,8 +532,7 @@
 	struct resource *res;
 	int ret;
 
-	if (!info || !info->pins || !info->npins
-		  || !info->pin_regs || !info->npin_regs) {
+	if (!info || !info->pins || !info->npins) {
 		dev_err(&pdev->dev, "wrong pinctrl info\n");
 		return -EINVAL;
 	}
@@ -580,6 +543,11 @@
 	if (!ipctl)
 		return -ENOMEM;
 
+	info->pin_regs = devm_kzalloc(&pdev->dev, sizeof(*info->pin_regs) *
+				      info->npins, GFP_KERNEL);
+	if (!info->pin_regs)
+		return -ENOMEM;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
 		return -ENOENT;