xref: /linux/drivers/pinctrl/freescale/pinctrl-imx.c (revision 7d6989ade916c37227e3054445b3fc3eebacb5d6)
1edad3b2aSLinus Walleij /*
2edad3b2aSLinus Walleij  * Core driver for the imx pin controller
3edad3b2aSLinus Walleij  *
4edad3b2aSLinus Walleij  * Copyright (C) 2012 Freescale Semiconductor, Inc.
5edad3b2aSLinus Walleij  * Copyright (C) 2012 Linaro Ltd.
6edad3b2aSLinus Walleij  *
7edad3b2aSLinus Walleij  * Author: Dong Aisheng <dong.aisheng@linaro.org>
8edad3b2aSLinus Walleij  *
9edad3b2aSLinus Walleij  * This program is free software; you can redistribute it and/or modify
10edad3b2aSLinus Walleij  * it under the terms of the GNU General Public License as published by
11edad3b2aSLinus Walleij  * the Free Software Foundation; either version 2 of the License, or
12edad3b2aSLinus Walleij  * (at your option) any later version.
13edad3b2aSLinus Walleij  */
14edad3b2aSLinus Walleij 
15edad3b2aSLinus Walleij #include <linux/err.h>
16edad3b2aSLinus Walleij #include <linux/init.h>
17edad3b2aSLinus Walleij #include <linux/io.h>
188626ada8SPhilipp Zabel #include <linux/mfd/syscon.h>
19edad3b2aSLinus Walleij #include <linux/of.h>
20edad3b2aSLinus Walleij #include <linux/of_device.h>
2126d8cde5SAdrian Alonso #include <linux/of_address.h>
22edad3b2aSLinus Walleij #include <linux/pinctrl/machine.h>
23edad3b2aSLinus Walleij #include <linux/pinctrl/pinconf.h>
24edad3b2aSLinus Walleij #include <linux/pinctrl/pinctrl.h>
25edad3b2aSLinus Walleij #include <linux/pinctrl/pinmux.h>
26edad3b2aSLinus Walleij #include <linux/slab.h>
278626ada8SPhilipp Zabel #include <linux/regmap.h>
28edad3b2aSLinus Walleij 
29edad3b2aSLinus Walleij #include "../core.h"
30a5cadbbbSDong Aisheng #include "../pinconf.h"
313fd6d6adSGary Bisson #include "../pinmux.h"
32edad3b2aSLinus Walleij #include "pinctrl-imx.h"
33edad3b2aSLinus Walleij 
34edad3b2aSLinus Walleij /* The bits in CONFIG cell defined in binding doc*/
35edad3b2aSLinus Walleij #define IMX_NO_PAD_CTL	0x80000000	/* no pin config need */
36edad3b2aSLinus Walleij #define IMX_PAD_SION 0x40000000		/* set SION */
37edad3b2aSLinus Walleij 
38e566fc11SGary Bisson static inline const struct group_desc *imx_pinctrl_find_group_by_name(
39e566fc11SGary Bisson 				struct pinctrl_dev *pctldev,
40edad3b2aSLinus Walleij 				const char *name)
41edad3b2aSLinus Walleij {
42e566fc11SGary Bisson 	const struct group_desc *grp = NULL;
43edad3b2aSLinus Walleij 	int i;
44edad3b2aSLinus Walleij 
45e566fc11SGary Bisson 	for (i = 0; i < pctldev->num_groups; i++) {
46e566fc11SGary Bisson 		grp = pinctrl_generic_get_group(pctldev, i);
47a51c158bSGary Bisson 		if (grp && !strcmp(grp->name, name))
48edad3b2aSLinus Walleij 			break;
49edad3b2aSLinus Walleij 	}
50edad3b2aSLinus Walleij 
51edad3b2aSLinus Walleij 	return grp;
52edad3b2aSLinus Walleij }
53edad3b2aSLinus Walleij 
54edad3b2aSLinus Walleij static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
55edad3b2aSLinus Walleij 		   unsigned offset)
56edad3b2aSLinus Walleij {
57edad3b2aSLinus Walleij 	seq_printf(s, "%s", dev_name(pctldev->dev));
58edad3b2aSLinus Walleij }
59edad3b2aSLinus Walleij 
60edad3b2aSLinus Walleij static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
61edad3b2aSLinus Walleij 			struct device_node *np,
62edad3b2aSLinus Walleij 			struct pinctrl_map **map, unsigned *num_maps)
63edad3b2aSLinus Walleij {
64edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
65e566fc11SGary Bisson 	const struct group_desc *grp;
66edad3b2aSLinus Walleij 	struct pinctrl_map *new_map;
67edad3b2aSLinus Walleij 	struct device_node *parent;
68edad3b2aSLinus Walleij 	int map_num = 1;
69edad3b2aSLinus Walleij 	int i, j;
70edad3b2aSLinus Walleij 
71edad3b2aSLinus Walleij 	/*
72edad3b2aSLinus Walleij 	 * first find the group of this node and check if we need create
73edad3b2aSLinus Walleij 	 * config maps for pins
74edad3b2aSLinus Walleij 	 */
75e566fc11SGary Bisson 	grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
76edad3b2aSLinus Walleij 	if (!grp) {
77f5843492SStefan Agner 		dev_err(ipctl->dev, "unable to find group for node %s\n",
78edad3b2aSLinus Walleij 			np->name);
79edad3b2aSLinus Walleij 		return -EINVAL;
80edad3b2aSLinus Walleij 	}
81edad3b2aSLinus Walleij 
82e566fc11SGary Bisson 	for (i = 0; i < grp->num_pins; i++) {
83e566fc11SGary Bisson 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
84e566fc11SGary Bisson 
85e566fc11SGary Bisson 		if (!(pin->config & IMX_NO_PAD_CTL))
86edad3b2aSLinus Walleij 			map_num++;
87edad3b2aSLinus Walleij 	}
88edad3b2aSLinus Walleij 
89edad3b2aSLinus Walleij 	new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
90edad3b2aSLinus Walleij 	if (!new_map)
91edad3b2aSLinus Walleij 		return -ENOMEM;
92edad3b2aSLinus Walleij 
93edad3b2aSLinus Walleij 	*map = new_map;
94edad3b2aSLinus Walleij 	*num_maps = map_num;
95edad3b2aSLinus Walleij 
96edad3b2aSLinus Walleij 	/* create mux map */
97edad3b2aSLinus Walleij 	parent = of_get_parent(np);
98edad3b2aSLinus Walleij 	if (!parent) {
99edad3b2aSLinus Walleij 		kfree(new_map);
100edad3b2aSLinus Walleij 		return -EINVAL;
101edad3b2aSLinus Walleij 	}
102edad3b2aSLinus Walleij 	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
103edad3b2aSLinus Walleij 	new_map[0].data.mux.function = parent->name;
104edad3b2aSLinus Walleij 	new_map[0].data.mux.group = np->name;
105edad3b2aSLinus Walleij 	of_node_put(parent);
106edad3b2aSLinus Walleij 
107edad3b2aSLinus Walleij 	/* create config map */
108edad3b2aSLinus Walleij 	new_map++;
109e566fc11SGary Bisson 	for (i = j = 0; i < grp->num_pins; i++) {
110e566fc11SGary Bisson 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
111e566fc11SGary Bisson 
112e566fc11SGary Bisson 		if (!(pin->config & IMX_NO_PAD_CTL)) {
113edad3b2aSLinus Walleij 			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
114edad3b2aSLinus Walleij 			new_map[j].data.configs.group_or_pin =
115e566fc11SGary Bisson 					pin_get_name(pctldev, pin->pin);
116e566fc11SGary Bisson 			new_map[j].data.configs.configs = &pin->config;
117edad3b2aSLinus Walleij 			new_map[j].data.configs.num_configs = 1;
118edad3b2aSLinus Walleij 			j++;
119edad3b2aSLinus Walleij 		}
120edad3b2aSLinus Walleij 	}
121edad3b2aSLinus Walleij 
122edad3b2aSLinus Walleij 	dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
123edad3b2aSLinus Walleij 		(*map)->data.mux.function, (*map)->data.mux.group, map_num);
124edad3b2aSLinus Walleij 
125edad3b2aSLinus Walleij 	return 0;
126edad3b2aSLinus Walleij }
127edad3b2aSLinus Walleij 
128edad3b2aSLinus Walleij static void imx_dt_free_map(struct pinctrl_dev *pctldev,
129edad3b2aSLinus Walleij 				struct pinctrl_map *map, unsigned num_maps)
130edad3b2aSLinus Walleij {
131edad3b2aSLinus Walleij 	kfree(map);
132edad3b2aSLinus Walleij }
133edad3b2aSLinus Walleij 
134edad3b2aSLinus Walleij static const struct pinctrl_ops imx_pctrl_ops = {
135e566fc11SGary Bisson 	.get_groups_count = pinctrl_generic_get_group_count,
136e566fc11SGary Bisson 	.get_group_name = pinctrl_generic_get_group_name,
137e566fc11SGary Bisson 	.get_group_pins = pinctrl_generic_get_group_pins,
138edad3b2aSLinus Walleij 	.pin_dbg_show = imx_pin_dbg_show,
139edad3b2aSLinus Walleij 	.dt_node_to_map = imx_dt_node_to_map,
140edad3b2aSLinus Walleij 	.dt_free_map = imx_dt_free_map,
141edad3b2aSLinus Walleij 
142edad3b2aSLinus Walleij };
143edad3b2aSLinus Walleij 
144edad3b2aSLinus Walleij static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
145edad3b2aSLinus Walleij 		       unsigned group)
146edad3b2aSLinus Walleij {
147edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
148f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
149edad3b2aSLinus Walleij 	const struct imx_pin_reg *pin_reg;
150edad3b2aSLinus Walleij 	unsigned int npins, pin_id;
151edad3b2aSLinus Walleij 	int i;
152e566fc11SGary Bisson 	struct group_desc *grp = NULL;
1533fd6d6adSGary Bisson 	struct function_desc *func = NULL;
154edad3b2aSLinus Walleij 
155edad3b2aSLinus Walleij 	/*
156edad3b2aSLinus Walleij 	 * Configure the mux mode for each pin in the group for a specific
157edad3b2aSLinus Walleij 	 * function.
158edad3b2aSLinus Walleij 	 */
159e566fc11SGary Bisson 	grp = pinctrl_generic_get_group(pctldev, group);
160a51c158bSGary Bisson 	if (!grp)
161a51c158bSGary Bisson 		return -EINVAL;
162a51c158bSGary Bisson 
1633fd6d6adSGary Bisson 	func = pinmux_generic_get_function(pctldev, selector);
164a51c158bSGary Bisson 	if (!func)
165a51c158bSGary Bisson 		return -EINVAL;
166a51c158bSGary Bisson 
167e566fc11SGary Bisson 	npins = grp->num_pins;
168edad3b2aSLinus Walleij 
169edad3b2aSLinus Walleij 	dev_dbg(ipctl->dev, "enable function %s group %s\n",
170a51c158bSGary Bisson 		func->name, grp->name);
171edad3b2aSLinus Walleij 
172edad3b2aSLinus Walleij 	for (i = 0; i < npins; i++) {
173e566fc11SGary Bisson 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
174e566fc11SGary Bisson 
175edad3b2aSLinus Walleij 		pin_id = pin->pin;
176f5843492SStefan Agner 		pin_reg = &ipctl->pin_regs[pin_id];
177edad3b2aSLinus Walleij 
1783dac1918SStefan Agner 		if (pin_reg->mux_reg == -1) {
179ba562d5eSAlexander Shiyan 			dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
180edad3b2aSLinus Walleij 				info->pins[pin_id].name);
181ba562d5eSAlexander Shiyan 			continue;
182edad3b2aSLinus Walleij 		}
183edad3b2aSLinus Walleij 
184edad3b2aSLinus Walleij 		if (info->flags & SHARE_MUX_CONF_REG) {
185edad3b2aSLinus Walleij 			u32 reg;
186edad3b2aSLinus Walleij 			reg = readl(ipctl->base + pin_reg->mux_reg);
1875586ee41SDong Aisheng 			reg &= ~info->mux_mask;
1885586ee41SDong Aisheng 			reg |= (pin->mux_mode << info->mux_shift);
189edad3b2aSLinus Walleij 			writel(reg, ipctl->base + pin_reg->mux_reg);
19066b54e3aSDong Aisheng 			dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
19166b54e3aSDong Aisheng 				pin_reg->mux_reg, reg);
192edad3b2aSLinus Walleij 		} else {
193edad3b2aSLinus Walleij 			writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
194edad3b2aSLinus Walleij 			dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
195edad3b2aSLinus Walleij 				pin_reg->mux_reg, pin->mux_mode);
19666b54e3aSDong Aisheng 		}
197edad3b2aSLinus Walleij 
198edad3b2aSLinus Walleij 		/*
199edad3b2aSLinus Walleij 		 * If the select input value begins with 0xff, it's a quirky
200edad3b2aSLinus Walleij 		 * select input and the value should be interpreted as below.
201edad3b2aSLinus Walleij 		 *     31     23      15      7        0
202edad3b2aSLinus Walleij 		 *     | 0xff | shift | width | select |
203edad3b2aSLinus Walleij 		 * It's used to work around the problem that the select
204edad3b2aSLinus Walleij 		 * input for some pin is not implemented in the select
205edad3b2aSLinus Walleij 		 * input register but in some general purpose register.
206edad3b2aSLinus Walleij 		 * We encode the select input value, width and shift of
207edad3b2aSLinus Walleij 		 * the bit field into input_val cell of pin function ID
208edad3b2aSLinus Walleij 		 * in device tree, and then decode them here for setting
209edad3b2aSLinus Walleij 		 * up the select input bits in general purpose register.
210edad3b2aSLinus Walleij 		 */
211edad3b2aSLinus Walleij 		if (pin->input_val >> 24 == 0xff) {
212edad3b2aSLinus Walleij 			u32 val = pin->input_val;
213edad3b2aSLinus Walleij 			u8 select = val & 0xff;
214edad3b2aSLinus Walleij 			u8 width = (val >> 8) & 0xff;
215edad3b2aSLinus Walleij 			u8 shift = (val >> 16) & 0xff;
216edad3b2aSLinus Walleij 			u32 mask = ((1 << width) - 1) << shift;
217edad3b2aSLinus Walleij 			/*
218edad3b2aSLinus Walleij 			 * The input_reg[i] here is actually some IOMUXC general
219edad3b2aSLinus Walleij 			 * purpose register, not regular select input register.
220edad3b2aSLinus Walleij 			 */
221edad3b2aSLinus Walleij 			val = readl(ipctl->base + pin->input_reg);
222edad3b2aSLinus Walleij 			val &= ~mask;
223edad3b2aSLinus Walleij 			val |= select << shift;
224edad3b2aSLinus Walleij 			writel(val, ipctl->base + pin->input_reg);
225edad3b2aSLinus Walleij 		} else if (pin->input_reg) {
226edad3b2aSLinus Walleij 			/*
227edad3b2aSLinus Walleij 			 * Regular select input register can never be at offset
228edad3b2aSLinus Walleij 			 * 0, and we only print register value for regular case.
229edad3b2aSLinus Walleij 			 */
23026d8cde5SAdrian Alonso 			if (ipctl->input_sel_base)
23126d8cde5SAdrian Alonso 				writel(pin->input_val, ipctl->input_sel_base +
23226d8cde5SAdrian Alonso 						pin->input_reg);
23326d8cde5SAdrian Alonso 			else
23426d8cde5SAdrian Alonso 				writel(pin->input_val, ipctl->base +
23526d8cde5SAdrian Alonso 						pin->input_reg);
236edad3b2aSLinus Walleij 			dev_dbg(ipctl->dev,
237edad3b2aSLinus Walleij 				"==>select_input: offset 0x%x val 0x%x\n",
238edad3b2aSLinus Walleij 				pin->input_reg, pin->input_val);
239edad3b2aSLinus Walleij 		}
240edad3b2aSLinus Walleij 	}
241edad3b2aSLinus Walleij 
242edad3b2aSLinus Walleij 	return 0;
243edad3b2aSLinus Walleij }
244edad3b2aSLinus Walleij 
2453be6f651SDong Aisheng struct pinmux_ops imx_pmx_ops = {
2463fd6d6adSGary Bisson 	.get_functions_count = pinmux_generic_get_function_count,
2473fd6d6adSGary Bisson 	.get_function_name = pinmux_generic_get_function_name,
2483fd6d6adSGary Bisson 	.get_function_groups = pinmux_generic_get_function_groups,
249edad3b2aSLinus Walleij 	.set_mux = imx_pmx_set,
250edad3b2aSLinus Walleij };
251edad3b2aSLinus Walleij 
252a5cadbbbSDong Aisheng /* decode generic config into raw register values */
253a5cadbbbSDong Aisheng static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl,
254a5cadbbbSDong Aisheng 					      unsigned long *configs,
255a5cadbbbSDong Aisheng 					      unsigned int num_configs)
256a5cadbbbSDong Aisheng {
257f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
258d6093367SStefan Agner 	const struct imx_cfg_params_decode *decode;
259a5cadbbbSDong Aisheng 	enum pin_config_param param;
260a5cadbbbSDong Aisheng 	u32 raw_config = 0;
261a5cadbbbSDong Aisheng 	u32 param_val;
262a5cadbbbSDong Aisheng 	int i, j;
263a5cadbbbSDong Aisheng 
264a5cadbbbSDong Aisheng 	WARN_ON(num_configs > info->num_decodes);
265a5cadbbbSDong Aisheng 
266a5cadbbbSDong Aisheng 	for (i = 0; i < num_configs; i++) {
267a5cadbbbSDong Aisheng 		param = pinconf_to_config_param(configs[i]);
268a5cadbbbSDong Aisheng 		param_val = pinconf_to_config_argument(configs[i]);
269a5cadbbbSDong Aisheng 		decode = info->decodes;
270a5cadbbbSDong Aisheng 		for (j = 0; j < info->num_decodes; j++) {
271a5cadbbbSDong Aisheng 			if (param == decode->param) {
272a5cadbbbSDong Aisheng 				if (decode->invert)
273a5cadbbbSDong Aisheng 					param_val = !param_val;
274a5cadbbbSDong Aisheng 				raw_config |= (param_val << decode->shift)
275a5cadbbbSDong Aisheng 					      & decode->mask;
276a5cadbbbSDong Aisheng 				break;
277a5cadbbbSDong Aisheng 			}
278a5cadbbbSDong Aisheng 			decode++;
279a5cadbbbSDong Aisheng 		}
280a5cadbbbSDong Aisheng 	}
281a5cadbbbSDong Aisheng 
282a5cadbbbSDong Aisheng 	if (info->fixup)
283a5cadbbbSDong Aisheng 		info->fixup(configs, num_configs, &raw_config);
284a5cadbbbSDong Aisheng 
285a5cadbbbSDong Aisheng 	return raw_config;
286a5cadbbbSDong Aisheng }
287a5cadbbbSDong Aisheng 
288a5cadbbbSDong Aisheng static u32 imx_pinconf_parse_generic_config(struct device_node *np,
289a5cadbbbSDong Aisheng 					    struct imx_pinctrl *ipctl)
290a5cadbbbSDong Aisheng {
291f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
292a5cadbbbSDong Aisheng 	struct pinctrl_dev *pctl = ipctl->pctl;
293a5cadbbbSDong Aisheng 	unsigned int num_configs;
294a5cadbbbSDong Aisheng 	unsigned long *configs;
295a5cadbbbSDong Aisheng 	int ret;
296a5cadbbbSDong Aisheng 
297a5cadbbbSDong Aisheng 	if (!info->generic_pinconf)
298a5cadbbbSDong Aisheng 		return 0;
299a5cadbbbSDong Aisheng 
300a5cadbbbSDong Aisheng 	ret = pinconf_generic_parse_dt_config(np, pctl, &configs,
301a5cadbbbSDong Aisheng 					      &num_configs);
302a5cadbbbSDong Aisheng 	if (ret)
303a5cadbbbSDong Aisheng 		return 0;
304a5cadbbbSDong Aisheng 
305a5cadbbbSDong Aisheng 	return imx_pinconf_decode_generic_config(ipctl, configs, num_configs);
306a5cadbbbSDong Aisheng }
307a5cadbbbSDong Aisheng 
308edad3b2aSLinus Walleij static int imx_pinconf_get(struct pinctrl_dev *pctldev,
309edad3b2aSLinus Walleij 			     unsigned pin_id, unsigned long *config)
310edad3b2aSLinus Walleij {
311edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
312f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
313f5843492SStefan Agner 	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
314edad3b2aSLinus Walleij 
3153dac1918SStefan Agner 	if (pin_reg->conf_reg == -1) {
316f5843492SStefan Agner 		dev_err(ipctl->dev, "Pin(%s) does not support config function\n",
317edad3b2aSLinus Walleij 			info->pins[pin_id].name);
318edad3b2aSLinus Walleij 		return -EINVAL;
319edad3b2aSLinus Walleij 	}
320edad3b2aSLinus Walleij 
321edad3b2aSLinus Walleij 	*config = readl(ipctl->base + pin_reg->conf_reg);
322edad3b2aSLinus Walleij 
323edad3b2aSLinus Walleij 	if (info->flags & SHARE_MUX_CONF_REG)
3245586ee41SDong Aisheng 		*config &= ~info->mux_mask;
325edad3b2aSLinus Walleij 
326edad3b2aSLinus Walleij 	return 0;
327edad3b2aSLinus Walleij }
328edad3b2aSLinus Walleij 
329edad3b2aSLinus Walleij static int imx_pinconf_set(struct pinctrl_dev *pctldev,
330edad3b2aSLinus Walleij 			     unsigned pin_id, unsigned long *configs,
331edad3b2aSLinus Walleij 			     unsigned num_configs)
332edad3b2aSLinus Walleij {
333edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
334f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
335f5843492SStefan Agner 	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
336edad3b2aSLinus Walleij 	int i;
337edad3b2aSLinus Walleij 
3383dac1918SStefan Agner 	if (pin_reg->conf_reg == -1) {
339f5843492SStefan Agner 		dev_err(ipctl->dev, "Pin(%s) does not support config function\n",
340edad3b2aSLinus Walleij 			info->pins[pin_id].name);
341edad3b2aSLinus Walleij 		return -EINVAL;
342edad3b2aSLinus Walleij 	}
343edad3b2aSLinus Walleij 
344edad3b2aSLinus Walleij 	dev_dbg(ipctl->dev, "pinconf set pin %s\n",
345edad3b2aSLinus Walleij 		info->pins[pin_id].name);
346edad3b2aSLinus Walleij 
347edad3b2aSLinus Walleij 	for (i = 0; i < num_configs; i++) {
348edad3b2aSLinus Walleij 		if (info->flags & SHARE_MUX_CONF_REG) {
349edad3b2aSLinus Walleij 			u32 reg;
350edad3b2aSLinus Walleij 			reg = readl(ipctl->base + pin_reg->conf_reg);
3515586ee41SDong Aisheng 			reg &= info->mux_mask;
352edad3b2aSLinus Walleij 			reg |= configs[i];
353edad3b2aSLinus Walleij 			writel(reg, ipctl->base + pin_reg->conf_reg);
35466b54e3aSDong Aisheng 			dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
35566b54e3aSDong Aisheng 				pin_reg->conf_reg, reg);
356edad3b2aSLinus Walleij 		} else {
357edad3b2aSLinus Walleij 			writel(configs[i], ipctl->base + pin_reg->conf_reg);
358edad3b2aSLinus Walleij 			dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
359edad3b2aSLinus Walleij 				pin_reg->conf_reg, configs[i]);
36066b54e3aSDong Aisheng 		}
361edad3b2aSLinus Walleij 	} /* for each config */
362edad3b2aSLinus Walleij 
363edad3b2aSLinus Walleij 	return 0;
364edad3b2aSLinus Walleij }
365edad3b2aSLinus Walleij 
366edad3b2aSLinus Walleij static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
367edad3b2aSLinus Walleij 				   struct seq_file *s, unsigned pin_id)
368edad3b2aSLinus Walleij {
369edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
370f5843492SStefan Agner 	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
371edad3b2aSLinus Walleij 	unsigned long config;
372edad3b2aSLinus Walleij 
3734ff0f034SUwe Kleine-König 	if (!pin_reg || pin_reg->conf_reg == -1) {
374*7d6989adSDong Aisheng 		seq_puts(s, "N/A");
375edad3b2aSLinus Walleij 		return;
376edad3b2aSLinus Walleij 	}
377edad3b2aSLinus Walleij 
378edad3b2aSLinus Walleij 	config = readl(ipctl->base + pin_reg->conf_reg);
379edad3b2aSLinus Walleij 	seq_printf(s, "0x%lx", config);
380edad3b2aSLinus Walleij }
381edad3b2aSLinus Walleij 
382edad3b2aSLinus Walleij static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
383edad3b2aSLinus Walleij 					 struct seq_file *s, unsigned group)
384edad3b2aSLinus Walleij {
385e566fc11SGary Bisson 	struct group_desc *grp;
386edad3b2aSLinus Walleij 	unsigned long config;
387edad3b2aSLinus Walleij 	const char *name;
388edad3b2aSLinus Walleij 	int i, ret;
389edad3b2aSLinus Walleij 
390e566fc11SGary Bisson 	if (group > pctldev->num_groups)
391edad3b2aSLinus Walleij 		return;
392edad3b2aSLinus Walleij 
393*7d6989adSDong Aisheng 	seq_puts(s, "\n");
394e566fc11SGary Bisson 	grp = pinctrl_generic_get_group(pctldev, group);
395a51c158bSGary Bisson 	if (!grp)
396a51c158bSGary Bisson 		return;
397a51c158bSGary Bisson 
398e566fc11SGary Bisson 	for (i = 0; i < grp->num_pins; i++) {
399e566fc11SGary Bisson 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
400e566fc11SGary Bisson 
401edad3b2aSLinus Walleij 		name = pin_get_name(pctldev, pin->pin);
402edad3b2aSLinus Walleij 		ret = imx_pinconf_get(pctldev, pin->pin, &config);
403edad3b2aSLinus Walleij 		if (ret)
404edad3b2aSLinus Walleij 			return;
405a2d16a21SVladimir Zapolskiy 		seq_printf(s, "  %s: 0x%lx\n", name, config);
406edad3b2aSLinus Walleij 	}
407edad3b2aSLinus Walleij }
408edad3b2aSLinus Walleij 
409edad3b2aSLinus Walleij static const struct pinconf_ops imx_pinconf_ops = {
410edad3b2aSLinus Walleij 	.pin_config_get = imx_pinconf_get,
411edad3b2aSLinus Walleij 	.pin_config_set = imx_pinconf_set,
412edad3b2aSLinus Walleij 	.pin_config_dbg_show = imx_pinconf_dbg_show,
413edad3b2aSLinus Walleij 	.pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
414edad3b2aSLinus Walleij };
415edad3b2aSLinus Walleij 
416edad3b2aSLinus Walleij /*
41737c1628fSDong Aisheng  * Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID
41837c1628fSDong Aisheng  * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin.
41937c1628fSDong Aisheng  * For generic_pinconf case, there's no extra u32 CONFIG.
42037c1628fSDong Aisheng  *
42137c1628fSDong Aisheng  * PIN_FUNC_ID format:
42237c1628fSDong Aisheng  * Default:
42337c1628fSDong Aisheng  *     <mux_reg conf_reg input_reg mux_mode input_val>
42437c1628fSDong Aisheng  * SHARE_MUX_CONF_REG:
42537c1628fSDong Aisheng  *     <mux_conf_reg input_reg mux_mode input_val>
426edad3b2aSLinus Walleij  */
427edad3b2aSLinus Walleij #define FSL_PIN_SIZE 24
42837c1628fSDong Aisheng #define FSL_PIN_SHARE_SIZE 20
429edad3b2aSLinus Walleij 
430edad3b2aSLinus Walleij static int imx_pinctrl_parse_groups(struct device_node *np,
431e566fc11SGary Bisson 				    struct group_desc *grp,
432a5cadbbbSDong Aisheng 				    struct imx_pinctrl *ipctl,
433edad3b2aSLinus Walleij 				    u32 index)
434edad3b2aSLinus Walleij {
435f5843492SStefan Agner 	const struct imx_pinctrl_soc_info *info = ipctl->info;
436edad3b2aSLinus Walleij 	int size, pin_size;
437edad3b2aSLinus Walleij 	const __be32 *list;
438edad3b2aSLinus Walleij 	int i;
439edad3b2aSLinus Walleij 	u32 config;
440edad3b2aSLinus Walleij 
441f5843492SStefan Agner 	dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name);
442edad3b2aSLinus Walleij 
443edad3b2aSLinus Walleij 	if (info->flags & SHARE_MUX_CONF_REG)
44437c1628fSDong Aisheng 		pin_size = FSL_PIN_SHARE_SIZE;
445edad3b2aSLinus Walleij 	else
446edad3b2aSLinus Walleij 		pin_size = FSL_PIN_SIZE;
447a5cadbbbSDong Aisheng 
448a5cadbbbSDong Aisheng 	if (info->generic_pinconf)
449a5cadbbbSDong Aisheng 		pin_size -= 4;
450a5cadbbbSDong Aisheng 
451edad3b2aSLinus Walleij 	/* Initialise group */
452edad3b2aSLinus Walleij 	grp->name = np->name;
453edad3b2aSLinus Walleij 
454edad3b2aSLinus Walleij 	/*
455edad3b2aSLinus Walleij 	 * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>,
456edad3b2aSLinus Walleij 	 * do sanity check and calculate pins number
457a5cadbbbSDong Aisheng 	 *
458a5cadbbbSDong Aisheng 	 * First try legacy 'fsl,pins' property, then fall back to the
459fc4f351aSDong Aisheng 	 * generic 'pinmux'.
460a5cadbbbSDong Aisheng 	 *
461fc4f351aSDong Aisheng 	 * Note: for generic 'pinmux' case, there's no CONFIG part in
462a5cadbbbSDong Aisheng 	 * the binding format.
463edad3b2aSLinus Walleij 	 */
464edad3b2aSLinus Walleij 	list = of_get_property(np, "fsl,pins", &size);
465edad3b2aSLinus Walleij 	if (!list) {
466fc4f351aSDong Aisheng 		list = of_get_property(np, "pinmux", &size);
467a5cadbbbSDong Aisheng 		if (!list) {
468f5843492SStefan Agner 			dev_err(ipctl->dev,
469f5292d06SRob Herring 				"no fsl,pins and pins property in node %pOF\n", np);
470edad3b2aSLinus Walleij 			return -EINVAL;
471edad3b2aSLinus Walleij 		}
472a5cadbbbSDong Aisheng 	}
473edad3b2aSLinus Walleij 
474edad3b2aSLinus Walleij 	/* we do not check return since it's safe node passed down */
475edad3b2aSLinus Walleij 	if (!size || size % pin_size) {
476f5843492SStefan Agner 		dev_err(ipctl->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
477edad3b2aSLinus Walleij 		return -EINVAL;
478edad3b2aSLinus Walleij 	}
479edad3b2aSLinus Walleij 
480a5cadbbbSDong Aisheng 	/* first try to parse the generic pin config */
481a5cadbbbSDong Aisheng 	config = imx_pinconf_parse_generic_config(np, ipctl);
482a5cadbbbSDong Aisheng 
483e566fc11SGary Bisson 	grp->num_pins = size / pin_size;
484f5843492SStefan Agner 	grp->data = devm_kzalloc(ipctl->dev, grp->num_pins *
485e566fc11SGary Bisson 				 sizeof(struct imx_pin), GFP_KERNEL);
486f5843492SStefan Agner 	grp->pins = devm_kzalloc(ipctl->dev, grp->num_pins *
487e566fc11SGary Bisson 				 sizeof(unsigned int), GFP_KERNEL);
488e566fc11SGary Bisson 	if (!grp->pins || !grp->data)
489edad3b2aSLinus Walleij 		return -ENOMEM;
490edad3b2aSLinus Walleij 
491e566fc11SGary Bisson 	for (i = 0; i < grp->num_pins; i++) {
492edad3b2aSLinus Walleij 		u32 mux_reg = be32_to_cpu(*list++);
493edad3b2aSLinus Walleij 		u32 conf_reg;
494edad3b2aSLinus Walleij 		unsigned int pin_id;
495edad3b2aSLinus Walleij 		struct imx_pin_reg *pin_reg;
496e566fc11SGary Bisson 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
497edad3b2aSLinus Walleij 
498e7b37a52SAdrian Alonso 		if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
499e7b37a52SAdrian Alonso 			mux_reg = -1;
500e7b37a52SAdrian Alonso 
50116837f95SMarkus Pargmann 		if (info->flags & SHARE_MUX_CONF_REG) {
502edad3b2aSLinus Walleij 			conf_reg = mux_reg;
50316837f95SMarkus Pargmann 		} else {
504edad3b2aSLinus Walleij 			conf_reg = be32_to_cpu(*list++);
50516837f95SMarkus Pargmann 			if (!conf_reg)
50616837f95SMarkus Pargmann 				conf_reg = -1;
50716837f95SMarkus Pargmann 		}
508edad3b2aSLinus Walleij 
509e7b37a52SAdrian Alonso 		pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
510f5843492SStefan Agner 		pin_reg = &ipctl->pin_regs[pin_id];
511edad3b2aSLinus Walleij 		pin->pin = pin_id;
512e566fc11SGary Bisson 		grp->pins[i] = pin_id;
513edad3b2aSLinus Walleij 		pin_reg->mux_reg = mux_reg;
514edad3b2aSLinus Walleij 		pin_reg->conf_reg = conf_reg;
515edad3b2aSLinus Walleij 		pin->input_reg = be32_to_cpu(*list++);
516edad3b2aSLinus Walleij 		pin->mux_mode = be32_to_cpu(*list++);
517edad3b2aSLinus Walleij 		pin->input_val = be32_to_cpu(*list++);
518edad3b2aSLinus Walleij 
519a5cadbbbSDong Aisheng 		if (info->generic_pinconf) {
520a5cadbbbSDong Aisheng 			/* generic pin config decoded */
521a5cadbbbSDong Aisheng 			pin->config = config;
522a5cadbbbSDong Aisheng 		} else {
523a5cadbbbSDong Aisheng 			/* legacy pin config read from devicetree */
524edad3b2aSLinus Walleij 			config = be32_to_cpu(*list++);
525a5cadbbbSDong Aisheng 
526a5cadbbbSDong Aisheng 			/* SION bit is in mux register */
527edad3b2aSLinus Walleij 			if (config & IMX_PAD_SION)
528edad3b2aSLinus Walleij 				pin->mux_mode |= IOMUXC_CONFIG_SION;
529edad3b2aSLinus Walleij 			pin->config = config & ~IMX_PAD_SION;
530a5cadbbbSDong Aisheng 		}
531edad3b2aSLinus Walleij 
532f5843492SStefan Agner 		dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
533edad3b2aSLinus Walleij 				pin->mux_mode, pin->config);
534edad3b2aSLinus Walleij 	}
535edad3b2aSLinus Walleij 
536edad3b2aSLinus Walleij 	return 0;
537edad3b2aSLinus Walleij }
538edad3b2aSLinus Walleij 
539edad3b2aSLinus Walleij static int imx_pinctrl_parse_functions(struct device_node *np,
540e566fc11SGary Bisson 				       struct imx_pinctrl *ipctl,
541edad3b2aSLinus Walleij 				       u32 index)
542edad3b2aSLinus Walleij {
543e566fc11SGary Bisson 	struct pinctrl_dev *pctl = ipctl->pctl;
544edad3b2aSLinus Walleij 	struct device_node *child;
5453fd6d6adSGary Bisson 	struct function_desc *func;
546e566fc11SGary Bisson 	struct group_desc *grp;
547edad3b2aSLinus Walleij 	u32 i = 0;
548edad3b2aSLinus Walleij 
549f5843492SStefan Agner 	dev_dbg(pctl->dev, "parse function(%d): %s\n", index, np->name);
550edad3b2aSLinus Walleij 
5513fd6d6adSGary Bisson 	func = pinmux_generic_get_function(pctl, index);
552a51c158bSGary Bisson 	if (!func)
553a51c158bSGary Bisson 		return -EINVAL;
554edad3b2aSLinus Walleij 
555edad3b2aSLinus Walleij 	/* Initialise function */
556edad3b2aSLinus Walleij 	func->name = np->name;
5573fd6d6adSGary Bisson 	func->num_group_names = of_get_child_count(np);
5583fd6d6adSGary Bisson 	if (func->num_group_names == 0) {
559f5843492SStefan Agner 		dev_err(ipctl->dev, "no groups defined in %pOF\n", np);
560edad3b2aSLinus Walleij 		return -EINVAL;
561edad3b2aSLinus Walleij 	}
562f5843492SStefan Agner 	func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names,
5633fd6d6adSGary Bisson 					 sizeof(char *), GFP_KERNEL);
56449af64e6SChristophe JAILLET 	if (!func->group_names)
56549af64e6SChristophe JAILLET 		return -ENOMEM;
566edad3b2aSLinus Walleij 
567edad3b2aSLinus Walleij 	for_each_child_of_node(np, child) {
5683fd6d6adSGary Bisson 		func->group_names[i] = child->name;
569a51c158bSGary Bisson 
570f5843492SStefan Agner 		grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
571a51c158bSGary Bisson 				   GFP_KERNEL);
572a51c158bSGary Bisson 		if (!grp)
573a51c158bSGary Bisson 			return -ENOMEM;
574a51c158bSGary Bisson 
575f5843492SStefan Agner 		mutex_lock(&ipctl->mutex);
576e566fc11SGary Bisson 		radix_tree_insert(&pctl->pin_group_tree,
577f5843492SStefan Agner 				  ipctl->group_index++, grp);
578f5843492SStefan Agner 		mutex_unlock(&ipctl->mutex);
579a51c158bSGary Bisson 
580a5cadbbbSDong Aisheng 		imx_pinctrl_parse_groups(child, grp, ipctl, i++);
581edad3b2aSLinus Walleij 	}
582edad3b2aSLinus Walleij 
583edad3b2aSLinus Walleij 	return 0;
584edad3b2aSLinus Walleij }
585edad3b2aSLinus Walleij 
5865fcdf6a7SMarkus Pargmann /*
5875fcdf6a7SMarkus Pargmann  * Check if the DT contains pins in the direct child nodes. This indicates the
5885fcdf6a7SMarkus Pargmann  * newer DT format to store pins. This function returns true if the first found
5895fcdf6a7SMarkus Pargmann  * fsl,pins property is in a child of np. Otherwise false is returned.
5905fcdf6a7SMarkus Pargmann  */
5915fcdf6a7SMarkus Pargmann static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
5925fcdf6a7SMarkus Pargmann {
5935fcdf6a7SMarkus Pargmann 	struct device_node *function_np;
5945fcdf6a7SMarkus Pargmann 	struct device_node *pinctrl_np;
5955fcdf6a7SMarkus Pargmann 
5965fcdf6a7SMarkus Pargmann 	for_each_child_of_node(np, function_np) {
5975fcdf6a7SMarkus Pargmann 		if (of_property_read_bool(function_np, "fsl,pins"))
5985fcdf6a7SMarkus Pargmann 			return true;
5995fcdf6a7SMarkus Pargmann 
6005fcdf6a7SMarkus Pargmann 		for_each_child_of_node(function_np, pinctrl_np) {
6015fcdf6a7SMarkus Pargmann 			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
6025fcdf6a7SMarkus Pargmann 				return false;
6035fcdf6a7SMarkus Pargmann 		}
6045fcdf6a7SMarkus Pargmann 	}
6055fcdf6a7SMarkus Pargmann 
6065fcdf6a7SMarkus Pargmann 	return true;
6075fcdf6a7SMarkus Pargmann }
6085fcdf6a7SMarkus Pargmann 
609edad3b2aSLinus Walleij static int imx_pinctrl_probe_dt(struct platform_device *pdev,
610e566fc11SGary Bisson 				struct imx_pinctrl *ipctl)
611edad3b2aSLinus Walleij {
612edad3b2aSLinus Walleij 	struct device_node *np = pdev->dev.of_node;
613edad3b2aSLinus Walleij 	struct device_node *child;
614e566fc11SGary Bisson 	struct pinctrl_dev *pctl = ipctl->pctl;
615edad3b2aSLinus Walleij 	u32 nfuncs = 0;
616edad3b2aSLinus Walleij 	u32 i = 0;
6175fcdf6a7SMarkus Pargmann 	bool flat_funcs;
618edad3b2aSLinus Walleij 
619edad3b2aSLinus Walleij 	if (!np)
620edad3b2aSLinus Walleij 		return -ENODEV;
621edad3b2aSLinus Walleij 
6225fcdf6a7SMarkus Pargmann 	flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
6235fcdf6a7SMarkus Pargmann 	if (flat_funcs) {
6245fcdf6a7SMarkus Pargmann 		nfuncs = 1;
6255fcdf6a7SMarkus Pargmann 	} else {
626edad3b2aSLinus Walleij 		nfuncs = of_get_child_count(np);
627562088eeSDong Aisheng 		if (nfuncs == 0) {
628edad3b2aSLinus Walleij 			dev_err(&pdev->dev, "no functions defined\n");
629edad3b2aSLinus Walleij 			return -EINVAL;
630edad3b2aSLinus Walleij 		}
6315fcdf6a7SMarkus Pargmann 	}
632edad3b2aSLinus Walleij 
633a51c158bSGary Bisson 	for (i = 0; i < nfuncs; i++) {
6343fd6d6adSGary Bisson 		struct function_desc *function;
635a51c158bSGary Bisson 
636a51c158bSGary Bisson 		function = devm_kzalloc(&pdev->dev, sizeof(*function),
637edad3b2aSLinus Walleij 					GFP_KERNEL);
638a51c158bSGary Bisson 		if (!function)
639edad3b2aSLinus Walleij 			return -ENOMEM;
640edad3b2aSLinus Walleij 
641f5843492SStefan Agner 		mutex_lock(&ipctl->mutex);
6423fd6d6adSGary Bisson 		radix_tree_insert(&pctl->pin_function_tree, i, function);
643f5843492SStefan Agner 		mutex_unlock(&ipctl->mutex);
644a51c158bSGary Bisson 	}
6453fd6d6adSGary Bisson 	pctl->num_functions = nfuncs;
646a51c158bSGary Bisson 
647f5843492SStefan Agner 	ipctl->group_index = 0;
6485fcdf6a7SMarkus Pargmann 	if (flat_funcs) {
649e566fc11SGary Bisson 		pctl->num_groups = of_get_child_count(np);
6505fcdf6a7SMarkus Pargmann 	} else {
651e566fc11SGary Bisson 		pctl->num_groups = 0;
652edad3b2aSLinus Walleij 		for_each_child_of_node(np, child)
653e566fc11SGary Bisson 			pctl->num_groups += of_get_child_count(child);
6545fcdf6a7SMarkus Pargmann 	}
655edad3b2aSLinus Walleij 
6565fcdf6a7SMarkus Pargmann 	if (flat_funcs) {
657e566fc11SGary Bisson 		imx_pinctrl_parse_functions(np, ipctl, 0);
6585fcdf6a7SMarkus Pargmann 	} else {
659a51c158bSGary Bisson 		i = 0;
660edad3b2aSLinus Walleij 		for_each_child_of_node(np, child)
661e566fc11SGary Bisson 			imx_pinctrl_parse_functions(child, ipctl, i++);
6625fcdf6a7SMarkus Pargmann 	}
663edad3b2aSLinus Walleij 
664edad3b2aSLinus Walleij 	return 0;
665edad3b2aSLinus Walleij }
666edad3b2aSLinus Walleij 
667a51c158bSGary Bisson /*
668a51c158bSGary Bisson  * imx_free_resources() - free memory used by this driver
669a51c158bSGary Bisson  * @info: info driver instance
670a51c158bSGary Bisson  */
671a51c158bSGary Bisson static void imx_free_resources(struct imx_pinctrl *ipctl)
672a51c158bSGary Bisson {
673a51c158bSGary Bisson 	if (ipctl->pctl)
674a51c158bSGary Bisson 		pinctrl_unregister(ipctl->pctl);
675a51c158bSGary Bisson }
676a51c158bSGary Bisson 
677edad3b2aSLinus Walleij int imx_pinctrl_probe(struct platform_device *pdev,
678f5843492SStefan Agner 		      const struct imx_pinctrl_soc_info *info)
679edad3b2aSLinus Walleij {
6808626ada8SPhilipp Zabel 	struct regmap_config config = { .name = "gpr" };
68126d8cde5SAdrian Alonso 	struct device_node *dev_np = pdev->dev.of_node;
6826e408ed8SPeng Fan 	struct pinctrl_desc *imx_pinctrl_desc;
68326d8cde5SAdrian Alonso 	struct device_node *np;
684edad3b2aSLinus Walleij 	struct imx_pinctrl *ipctl;
685edad3b2aSLinus Walleij 	struct resource *res;
6868626ada8SPhilipp Zabel 	struct regmap *gpr;
6874691dd01SStefan Agner 	int ret, i;
688edad3b2aSLinus Walleij 
689edad3b2aSLinus Walleij 	if (!info || !info->pins || !info->npins) {
690edad3b2aSLinus Walleij 		dev_err(&pdev->dev, "wrong pinctrl info\n");
691edad3b2aSLinus Walleij 		return -EINVAL;
692edad3b2aSLinus Walleij 	}
693edad3b2aSLinus Walleij 
6948626ada8SPhilipp Zabel 	if (info->gpr_compatible) {
6958626ada8SPhilipp Zabel 		gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible);
6968626ada8SPhilipp Zabel 		if (!IS_ERR(gpr))
6978626ada8SPhilipp Zabel 			regmap_attach_dev(&pdev->dev, gpr, &config);
6988626ada8SPhilipp Zabel 	}
6998626ada8SPhilipp Zabel 
700edad3b2aSLinus Walleij 	/* Create state holders etc for this driver */
701edad3b2aSLinus Walleij 	ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
702edad3b2aSLinus Walleij 	if (!ipctl)
703edad3b2aSLinus Walleij 		return -ENOMEM;
704edad3b2aSLinus Walleij 
705f5843492SStefan Agner 	ipctl->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*ipctl->pin_regs) *
706edad3b2aSLinus Walleij 				      info->npins, GFP_KERNEL);
707f5843492SStefan Agner 	if (!ipctl->pin_regs)
708edad3b2aSLinus Walleij 		return -ENOMEM;
7094691dd01SStefan Agner 
7104691dd01SStefan Agner 	for (i = 0; i < info->npins; i++) {
711f5843492SStefan Agner 		ipctl->pin_regs[i].mux_reg = -1;
712f5843492SStefan Agner 		ipctl->pin_regs[i].conf_reg = -1;
7134691dd01SStefan Agner 	}
714edad3b2aSLinus Walleij 
715edad3b2aSLinus Walleij 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
716edad3b2aSLinus Walleij 	ipctl->base = devm_ioremap_resource(&pdev->dev, res);
717edad3b2aSLinus Walleij 	if (IS_ERR(ipctl->base))
718edad3b2aSLinus Walleij 		return PTR_ERR(ipctl->base);
719edad3b2aSLinus Walleij 
72026d8cde5SAdrian Alonso 	if (of_property_read_bool(dev_np, "fsl,input-sel")) {
72126d8cde5SAdrian Alonso 		np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
7229a4f4245SVladimir Zapolskiy 		if (!np) {
72326d8cde5SAdrian Alonso 			dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
72426d8cde5SAdrian Alonso 			return -EINVAL;
72526d8cde5SAdrian Alonso 		}
7269a4f4245SVladimir Zapolskiy 
7279a4f4245SVladimir Zapolskiy 		ipctl->input_sel_base = of_iomap(np, 0);
72826d8cde5SAdrian Alonso 		of_node_put(np);
7299a4f4245SVladimir Zapolskiy 		if (!ipctl->input_sel_base) {
7309a4f4245SVladimir Zapolskiy 			dev_err(&pdev->dev,
7319a4f4245SVladimir Zapolskiy 				"iomuxc input select base address not found\n");
7329a4f4245SVladimir Zapolskiy 			return -ENOMEM;
7339a4f4245SVladimir Zapolskiy 		}
73426d8cde5SAdrian Alonso 	}
73526d8cde5SAdrian Alonso 
7366e408ed8SPeng Fan 	imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
7376e408ed8SPeng Fan 					GFP_KERNEL);
7386e408ed8SPeng Fan 	if (!imx_pinctrl_desc)
7396e408ed8SPeng Fan 		return -ENOMEM;
7406e408ed8SPeng Fan 
7416e408ed8SPeng Fan 	imx_pinctrl_desc->name = dev_name(&pdev->dev);
7426e408ed8SPeng Fan 	imx_pinctrl_desc->pins = info->pins;
7436e408ed8SPeng Fan 	imx_pinctrl_desc->npins = info->npins;
7448f5983adSGary Bisson 	imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
7458f5983adSGary Bisson 	imx_pinctrl_desc->pmxops = &imx_pmx_ops;
7468f5983adSGary Bisson 	imx_pinctrl_desc->confops = &imx_pinconf_ops;
7478f5983adSGary Bisson 	imx_pinctrl_desc->owner = THIS_MODULE;
748edad3b2aSLinus Walleij 
749a5cadbbbSDong Aisheng 	/* for generic pinconf */
750a5cadbbbSDong Aisheng 	imx_pinctrl_desc->custom_params = info->custom_params;
751a5cadbbbSDong Aisheng 	imx_pinctrl_desc->num_custom_params = info->num_custom_params;
752a5cadbbbSDong Aisheng 
7533be6f651SDong Aisheng 	/* platform specific callback */
7543be6f651SDong Aisheng 	imx_pmx_ops.gpio_set_direction = info->gpio_set_direction;
7553be6f651SDong Aisheng 
756f5843492SStefan Agner 	mutex_init(&ipctl->mutex);
757a51c158bSGary Bisson 
758edad3b2aSLinus Walleij 	ipctl->info = info;
759f5843492SStefan Agner 	ipctl->dev = &pdev->dev;
760edad3b2aSLinus Walleij 	platform_set_drvdata(pdev, ipctl);
761950b0d91STony Lindgren 	ret = devm_pinctrl_register_and_init(&pdev->dev,
762950b0d91STony Lindgren 					     imx_pinctrl_desc, ipctl,
763950b0d91STony Lindgren 					     &ipctl->pctl);
764950b0d91STony Lindgren 	if (ret) {
765edad3b2aSLinus Walleij 		dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
766a51c158bSGary Bisson 		goto free;
767edad3b2aSLinus Walleij 	}
768edad3b2aSLinus Walleij 
769e566fc11SGary Bisson 	ret = imx_pinctrl_probe_dt(pdev, ipctl);
770e566fc11SGary Bisson 	if (ret) {
771e566fc11SGary Bisson 		dev_err(&pdev->dev, "fail to probe dt properties\n");
772e566fc11SGary Bisson 		goto free;
773e566fc11SGary Bisson 	}
774e566fc11SGary Bisson 
775edad3b2aSLinus Walleij 	dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
776edad3b2aSLinus Walleij 
77761187142STony Lindgren 	return pinctrl_enable(ipctl->pctl);
778a51c158bSGary Bisson 
779a51c158bSGary Bisson free:
780a51c158bSGary Bisson 	imx_free_resources(ipctl);
781a51c158bSGary Bisson 
782a51c158bSGary Bisson 	return ret;
783edad3b2aSLinus Walleij }
784