xref: /linux/drivers/pinctrl/sunxi/pinctrl-sunxi.c (revision a30514a076cfe4b1962980e946a759f5556cf4a5)
10e37f88dSMaxime Ripard /*
20e37f88dSMaxime Ripard  * Allwinner A1X SoCs pinctrl driver.
30e37f88dSMaxime Ripard  *
40e37f88dSMaxime Ripard  * Copyright (C) 2012 Maxime Ripard
50e37f88dSMaxime Ripard  *
60e37f88dSMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
70e37f88dSMaxime Ripard  *
80e37f88dSMaxime Ripard  * This file is licensed under the terms of the GNU General Public
90e37f88dSMaxime Ripard  * License version 2.  This program is licensed "as is" without any
100e37f88dSMaxime Ripard  * warranty of any kind, whether express or implied.
110e37f88dSMaxime Ripard  */
120e37f88dSMaxime Ripard 
130e37f88dSMaxime Ripard #include <linux/io.h>
14950707c0SEmilio López #include <linux/clk.h>
1588057d6eSLinus Walleij #include <linux/gpio/driver.h>
16a59c99d9SSamuel Holland #include <linux/interrupt.h>
1760242db1SMaxime Ripard #include <linux/irqdomain.h>
18905a5117SChen-Yu Tsai #include <linux/irqchip/chained_irq.h>
19bcc76199SPaul Gortmaker #include <linux/export.h>
200e37f88dSMaxime Ripard #include <linux/of.h>
2110e3a88bSGeert Uytterhoeven #include <linux/of_clk.h>
220e37f88dSMaxime Ripard #include <linux/of_address.h>
230e37f88dSMaxime Ripard #include <linux/of_device.h>
2460242db1SMaxime Ripard #include <linux/of_irq.h>
250e37f88dSMaxime Ripard #include <linux/pinctrl/consumer.h>
260e37f88dSMaxime Ripard #include <linux/pinctrl/machine.h>
270e37f88dSMaxime Ripard #include <linux/pinctrl/pinctrl.h>
280e37f88dSMaxime Ripard #include <linux/pinctrl/pinconf-generic.h>
290e37f88dSMaxime Ripard #include <linux/pinctrl/pinmux.h>
309a2a566aSMaxime Ripard #include <linux/regulator/consumer.h>
310e37f88dSMaxime Ripard #include <linux/platform_device.h>
320e37f88dSMaxime Ripard #include <linux/slab.h>
330e37f88dSMaxime Ripard 
3442676fa4SMaxime Ripard #include <dt-bindings/pinctrl/sun4i-a10.h>
3542676fa4SMaxime Ripard 
365f910777SMaxime Ripard #include "../core.h"
370e37f88dSMaxime Ripard #include "pinctrl-sunxi.h"
38eaa3d848SMaxime Ripard 
39f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip;
40f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip;
41f4c51c10SHans de Goede 
420e37f88dSMaxime Ripard static struct sunxi_pinctrl_group *
430e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
440e37f88dSMaxime Ripard {
450e37f88dSMaxime Ripard 	int i;
460e37f88dSMaxime Ripard 
470e37f88dSMaxime Ripard 	for (i = 0; i < pctl->ngroups; i++) {
480e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp = pctl->groups + i;
490e37f88dSMaxime Ripard 
500e37f88dSMaxime Ripard 		if (!strcmp(grp->name, group))
510e37f88dSMaxime Ripard 			return grp;
520e37f88dSMaxime Ripard 	}
530e37f88dSMaxime Ripard 
540e37f88dSMaxime Ripard 	return NULL;
550e37f88dSMaxime Ripard }
560e37f88dSMaxime Ripard 
570e37f88dSMaxime Ripard static struct sunxi_pinctrl_function *
580e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
590e37f88dSMaxime Ripard 				    const char *name)
600e37f88dSMaxime Ripard {
610e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
620e37f88dSMaxime Ripard 	int i;
630e37f88dSMaxime Ripard 
640e37f88dSMaxime Ripard 	for (i = 0; i < pctl->nfunctions; i++) {
650e37f88dSMaxime Ripard 		if (!func[i].name)
660e37f88dSMaxime Ripard 			break;
670e37f88dSMaxime Ripard 
680e37f88dSMaxime Ripard 		if (!strcmp(func[i].name, name))
690e37f88dSMaxime Ripard 			return func + i;
700e37f88dSMaxime Ripard 	}
710e37f88dSMaxime Ripard 
720e37f88dSMaxime Ripard 	return NULL;
730e37f88dSMaxime Ripard }
740e37f88dSMaxime Ripard 
750e37f88dSMaxime Ripard static struct sunxi_desc_function *
760e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
770e37f88dSMaxime Ripard 					 const char *pin_name,
780e37f88dSMaxime Ripard 					 const char *func_name)
790e37f88dSMaxime Ripard {
800e37f88dSMaxime Ripard 	int i;
810e37f88dSMaxime Ripard 
820e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
830e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
840e37f88dSMaxime Ripard 
850e37f88dSMaxime Ripard 		if (!strcmp(pin->pin.name, pin_name)) {
860e37f88dSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
870e37f88dSMaxime Ripard 
880e37f88dSMaxime Ripard 			while (func->name) {
8932e21f08Shao_zhang 				if (!strcmp(func->name, func_name) &&
9032e21f08Shao_zhang 					(!func->variant ||
9132e21f08Shao_zhang 					func->variant & pctl->variant))
920e37f88dSMaxime Ripard 					return func;
930e37f88dSMaxime Ripard 
940e37f88dSMaxime Ripard 				func++;
950e37f88dSMaxime Ripard 			}
960e37f88dSMaxime Ripard 		}
970e37f88dSMaxime Ripard 	}
980e37f88dSMaxime Ripard 
990e37f88dSMaxime Ripard 	return NULL;
1000e37f88dSMaxime Ripard }
1010e37f88dSMaxime Ripard 
102814d4f2eSMaxime Ripard static struct sunxi_desc_function *
103814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
104814d4f2eSMaxime Ripard 					const u16 pin_num,
105814d4f2eSMaxime Ripard 					const char *func_name)
106814d4f2eSMaxime Ripard {
107814d4f2eSMaxime Ripard 	int i;
108814d4f2eSMaxime Ripard 
109814d4f2eSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
110814d4f2eSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
111814d4f2eSMaxime Ripard 
112814d4f2eSMaxime Ripard 		if (pin->pin.number == pin_num) {
113814d4f2eSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
114814d4f2eSMaxime Ripard 
115814d4f2eSMaxime Ripard 			while (func->name) {
116814d4f2eSMaxime Ripard 				if (!strcmp(func->name, func_name))
117814d4f2eSMaxime Ripard 					return func;
118814d4f2eSMaxime Ripard 
119814d4f2eSMaxime Ripard 				func++;
120814d4f2eSMaxime Ripard 			}
121814d4f2eSMaxime Ripard 		}
122814d4f2eSMaxime Ripard 	}
123814d4f2eSMaxime Ripard 
124814d4f2eSMaxime Ripard 	return NULL;
125814d4f2eSMaxime Ripard }
126814d4f2eSMaxime Ripard 
1270e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
1280e37f88dSMaxime Ripard {
1290e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1300e37f88dSMaxime Ripard 
1310e37f88dSMaxime Ripard 	return pctl->ngroups;
1320e37f88dSMaxime Ripard }
1330e37f88dSMaxime Ripard 
1340e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
1350e37f88dSMaxime Ripard 					      unsigned group)
1360e37f88dSMaxime Ripard {
1370e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1380e37f88dSMaxime Ripard 
1390e37f88dSMaxime Ripard 	return pctl->groups[group].name;
1400e37f88dSMaxime Ripard }
1410e37f88dSMaxime Ripard 
1420e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
1430e37f88dSMaxime Ripard 				      unsigned group,
1440e37f88dSMaxime Ripard 				      const unsigned **pins,
1450e37f88dSMaxime Ripard 				      unsigned *num_pins)
1460e37f88dSMaxime Ripard {
1470e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1480e37f88dSMaxime Ripard 
1490e37f88dSMaxime Ripard 	*pins = (unsigned *)&pctl->groups[group].pin;
1500e37f88dSMaxime Ripard 	*num_pins = 1;
1510e37f88dSMaxime Ripard 
1520e37f88dSMaxime Ripard 	return 0;
1530e37f88dSMaxime Ripard }
1540e37f88dSMaxime Ripard 
155f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_bias_prop(struct device_node *node)
156f233dbcaSMaxime Ripard {
157cefbf1a1SMaxime Ripard 	return of_find_property(node, "bias-pull-up", NULL) ||
158cefbf1a1SMaxime Ripard 		of_find_property(node, "bias-pull-down", NULL) ||
159cefbf1a1SMaxime Ripard 		of_find_property(node, "bias-disable", NULL) ||
160cefbf1a1SMaxime Ripard 		of_find_property(node, "allwinner,pull", NULL);
161f233dbcaSMaxime Ripard }
162f233dbcaSMaxime Ripard 
163f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_drive_prop(struct device_node *node)
164f233dbcaSMaxime Ripard {
165cefbf1a1SMaxime Ripard 	return of_find_property(node, "drive-strength", NULL) ||
166cefbf1a1SMaxime Ripard 		of_find_property(node, "allwinner,drive", NULL);
167f233dbcaSMaxime Ripard }
168f233dbcaSMaxime Ripard 
169f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_bias_prop(struct device_node *node)
170f233dbcaSMaxime Ripard {
171f233dbcaSMaxime Ripard 	u32 val;
172f233dbcaSMaxime Ripard 
173cefbf1a1SMaxime Ripard 	/* Try the new style binding */
174cefbf1a1SMaxime Ripard 	if (of_find_property(node, "bias-pull-up", NULL))
175cefbf1a1SMaxime Ripard 		return PIN_CONFIG_BIAS_PULL_UP;
176cefbf1a1SMaxime Ripard 
177cefbf1a1SMaxime Ripard 	if (of_find_property(node, "bias-pull-down", NULL))
178cefbf1a1SMaxime Ripard 		return PIN_CONFIG_BIAS_PULL_DOWN;
179cefbf1a1SMaxime Ripard 
180cefbf1a1SMaxime Ripard 	if (of_find_property(node, "bias-disable", NULL))
181cefbf1a1SMaxime Ripard 		return PIN_CONFIG_BIAS_DISABLE;
182cefbf1a1SMaxime Ripard 
183cefbf1a1SMaxime Ripard 	/* And fall back to the old binding */
184f233dbcaSMaxime Ripard 	if (of_property_read_u32(node, "allwinner,pull", &val))
185f233dbcaSMaxime Ripard 		return -EINVAL;
186f233dbcaSMaxime Ripard 
187f233dbcaSMaxime Ripard 	switch (val) {
18807fe64baSMaxime Ripard 	case SUN4I_PINCTRL_NO_PULL:
18907fe64baSMaxime Ripard 		return PIN_CONFIG_BIAS_DISABLE;
19042676fa4SMaxime Ripard 	case SUN4I_PINCTRL_PULL_UP:
191f233dbcaSMaxime Ripard 		return PIN_CONFIG_BIAS_PULL_UP;
19242676fa4SMaxime Ripard 	case SUN4I_PINCTRL_PULL_DOWN:
193f233dbcaSMaxime Ripard 		return PIN_CONFIG_BIAS_PULL_DOWN;
194f233dbcaSMaxime Ripard 	}
195f233dbcaSMaxime Ripard 
196f233dbcaSMaxime Ripard 	return -EINVAL;
197f233dbcaSMaxime Ripard }
198f233dbcaSMaxime Ripard 
199f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_drive_prop(struct device_node *node)
200f233dbcaSMaxime Ripard {
201f233dbcaSMaxime Ripard 	u32 val;
202f233dbcaSMaxime Ripard 
203cefbf1a1SMaxime Ripard 	/* Try the new style binding */
204cefbf1a1SMaxime Ripard 	if (!of_property_read_u32(node, "drive-strength", &val)) {
205cefbf1a1SMaxime Ripard 		/* We can't go below 10mA ... */
206cefbf1a1SMaxime Ripard 		if (val < 10)
207cefbf1a1SMaxime Ripard 			return -EINVAL;
208cefbf1a1SMaxime Ripard 
209cefbf1a1SMaxime Ripard 		/* ... and only up to 40 mA ... */
210cefbf1a1SMaxime Ripard 		if (val > 40)
211cefbf1a1SMaxime Ripard 			val = 40;
212cefbf1a1SMaxime Ripard 
213cefbf1a1SMaxime Ripard 		/* by steps of 10 mA */
214cefbf1a1SMaxime Ripard 		return rounddown(val, 10);
215cefbf1a1SMaxime Ripard 	}
216cefbf1a1SMaxime Ripard 
217cefbf1a1SMaxime Ripard 	/* And then fall back to the old binding */
218f233dbcaSMaxime Ripard 	if (of_property_read_u32(node, "allwinner,drive", &val))
219f233dbcaSMaxime Ripard 		return -EINVAL;
220f233dbcaSMaxime Ripard 
221f233dbcaSMaxime Ripard 	return (val + 1) * 10;
222f233dbcaSMaxime Ripard }
223f233dbcaSMaxime Ripard 
224f233dbcaSMaxime Ripard static const char *sunxi_pctrl_parse_function_prop(struct device_node *node)
225f233dbcaSMaxime Ripard {
226f233dbcaSMaxime Ripard 	const char *function;
227f233dbcaSMaxime Ripard 	int ret;
228f233dbcaSMaxime Ripard 
229cefbf1a1SMaxime Ripard 	/* Try the generic binding */
230cefbf1a1SMaxime Ripard 	ret = of_property_read_string(node, "function", &function);
231cefbf1a1SMaxime Ripard 	if (!ret)
232cefbf1a1SMaxime Ripard 		return function;
233cefbf1a1SMaxime Ripard 
234cefbf1a1SMaxime Ripard 	/* And fall back to our legacy one */
235f233dbcaSMaxime Ripard 	ret = of_property_read_string(node, "allwinner,function", &function);
236f233dbcaSMaxime Ripard 	if (!ret)
237f233dbcaSMaxime Ripard 		return function;
238f233dbcaSMaxime Ripard 
239f233dbcaSMaxime Ripard 	return NULL;
240f233dbcaSMaxime Ripard }
241f233dbcaSMaxime Ripard 
242f233dbcaSMaxime Ripard static const char *sunxi_pctrl_find_pins_prop(struct device_node *node,
243f233dbcaSMaxime Ripard 					      int *npins)
244f233dbcaSMaxime Ripard {
245f233dbcaSMaxime Ripard 	int count;
246f233dbcaSMaxime Ripard 
247cefbf1a1SMaxime Ripard 	/* Try the generic binding */
248cefbf1a1SMaxime Ripard 	count = of_property_count_strings(node, "pins");
249cefbf1a1SMaxime Ripard 	if (count > 0) {
250cefbf1a1SMaxime Ripard 		*npins = count;
251cefbf1a1SMaxime Ripard 		return "pins";
252cefbf1a1SMaxime Ripard 	}
253cefbf1a1SMaxime Ripard 
254cefbf1a1SMaxime Ripard 	/* And fall back to our legacy one */
255f233dbcaSMaxime Ripard 	count = of_property_count_strings(node, "allwinner,pins");
256f233dbcaSMaxime Ripard 	if (count > 0) {
257f233dbcaSMaxime Ripard 		*npins = count;
258f233dbcaSMaxime Ripard 		return "allwinner,pins";
259f233dbcaSMaxime Ripard 	}
260f233dbcaSMaxime Ripard 
261f233dbcaSMaxime Ripard 	return NULL;
262f233dbcaSMaxime Ripard }
263f233dbcaSMaxime Ripard 
264f233dbcaSMaxime Ripard static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node,
265f233dbcaSMaxime Ripard 						   unsigned int *len)
266f233dbcaSMaxime Ripard {
267f233dbcaSMaxime Ripard 	unsigned long *pinconfig;
268f233dbcaSMaxime Ripard 	unsigned int configlen = 0, idx = 0;
269e11dee2eSMaxime Ripard 	int ret;
270f233dbcaSMaxime Ripard 
271f233dbcaSMaxime Ripard 	if (sunxi_pctrl_has_drive_prop(node))
272f233dbcaSMaxime Ripard 		configlen++;
273f233dbcaSMaxime Ripard 	if (sunxi_pctrl_has_bias_prop(node))
274f233dbcaSMaxime Ripard 		configlen++;
275f233dbcaSMaxime Ripard 
276e11dee2eSMaxime Ripard 	/*
277e11dee2eSMaxime Ripard 	 * If we don't have any configuration, bail out
278e11dee2eSMaxime Ripard 	 */
279e11dee2eSMaxime Ripard 	if (!configlen)
280e11dee2eSMaxime Ripard 		return NULL;
281e11dee2eSMaxime Ripard 
2826396bb22SKees Cook 	pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL);
283f233dbcaSMaxime Ripard 	if (!pinconfig)
284e11dee2eSMaxime Ripard 		return ERR_PTR(-ENOMEM);
285f233dbcaSMaxime Ripard 
286f233dbcaSMaxime Ripard 	if (sunxi_pctrl_has_drive_prop(node)) {
287f233dbcaSMaxime Ripard 		int drive = sunxi_pctrl_parse_drive_prop(node);
288e11dee2eSMaxime Ripard 		if (drive < 0) {
289e11dee2eSMaxime Ripard 			ret = drive;
290f233dbcaSMaxime Ripard 			goto err_free;
291e11dee2eSMaxime Ripard 		}
292f233dbcaSMaxime Ripard 
293f233dbcaSMaxime Ripard 		pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
294f233dbcaSMaxime Ripard 							  drive);
295f233dbcaSMaxime Ripard 	}
296f233dbcaSMaxime Ripard 
297f233dbcaSMaxime Ripard 	if (sunxi_pctrl_has_bias_prop(node)) {
298f233dbcaSMaxime Ripard 		int pull = sunxi_pctrl_parse_bias_prop(node);
299223dba00SChen-Yu Tsai 		int arg = 0;
300e11dee2eSMaxime Ripard 		if (pull < 0) {
301e11dee2eSMaxime Ripard 			ret = pull;
302f233dbcaSMaxime Ripard 			goto err_free;
303e11dee2eSMaxime Ripard 		}
304f233dbcaSMaxime Ripard 
305223dba00SChen-Yu Tsai 		if (pull != PIN_CONFIG_BIAS_DISABLE)
306223dba00SChen-Yu Tsai 			arg = 1; /* hardware uses weak pull resistors */
307223dba00SChen-Yu Tsai 
308223dba00SChen-Yu Tsai 		pinconfig[idx++] = pinconf_to_config_packed(pull, arg);
309f233dbcaSMaxime Ripard 	}
310f233dbcaSMaxime Ripard 
311f233dbcaSMaxime Ripard 
312f233dbcaSMaxime Ripard 	*len = configlen;
313f233dbcaSMaxime Ripard 	return pinconfig;
314f233dbcaSMaxime Ripard 
315f233dbcaSMaxime Ripard err_free:
316f233dbcaSMaxime Ripard 	kfree(pinconfig);
317e11dee2eSMaxime Ripard 	return ERR_PTR(ret);
318f233dbcaSMaxime Ripard }
319f233dbcaSMaxime Ripard 
3200e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
3210e37f88dSMaxime Ripard 				      struct device_node *node,
3220e37f88dSMaxime Ripard 				      struct pinctrl_map **map,
3230e37f88dSMaxime Ripard 				      unsigned *num_maps)
3240e37f88dSMaxime Ripard {
3250e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3260e37f88dSMaxime Ripard 	unsigned long *pinconfig;
3270e37f88dSMaxime Ripard 	struct property *prop;
328f233dbcaSMaxime Ripard 	const char *function, *pin_prop;
3290e37f88dSMaxime Ripard 	const char *group;
330f233dbcaSMaxime Ripard 	int ret, npins, nmaps, configlen = 0, i = 0;
3310e37f88dSMaxime Ripard 
3320e37f88dSMaxime Ripard 	*map = NULL;
3330e37f88dSMaxime Ripard 	*num_maps = 0;
3340e37f88dSMaxime Ripard 
335f233dbcaSMaxime Ripard 	function = sunxi_pctrl_parse_function_prop(node);
336f233dbcaSMaxime Ripard 	if (!function) {
33794f4e54cSRob Herring 		dev_err(pctl->dev, "missing function property in node %pOFn\n",
33894f4e54cSRob Herring 			node);
3390e37f88dSMaxime Ripard 		return -EINVAL;
3400e37f88dSMaxime Ripard 	}
3410e37f88dSMaxime Ripard 
342f233dbcaSMaxime Ripard 	pin_prop = sunxi_pctrl_find_pins_prop(node, &npins);
343f233dbcaSMaxime Ripard 	if (!pin_prop) {
34494f4e54cSRob Herring 		dev_err(pctl->dev, "missing pins property in node %pOFn\n",
34594f4e54cSRob Herring 			node);
3460e37f88dSMaxime Ripard 		return -EINVAL;
3470e37f88dSMaxime Ripard 	}
3480e37f88dSMaxime Ripard 
349f233dbcaSMaxime Ripard 	/*
350f233dbcaSMaxime Ripard 	 * We have two maps for each pin: one for the function, one
351e11dee2eSMaxime Ripard 	 * for the configuration (bias, strength, etc).
352e11dee2eSMaxime Ripard 	 *
353e11dee2eSMaxime Ripard 	 * We might be slightly overshooting, since we might not have
354e11dee2eSMaxime Ripard 	 * any configuration.
355f233dbcaSMaxime Ripard 	 */
356f233dbcaSMaxime Ripard 	nmaps = npins * 2;
3576da2ec56SKees Cook 	*map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL);
3583efa921dSSachin Kamat 	if (!*map)
3590e37f88dSMaxime Ripard 		return -ENOMEM;
3600e37f88dSMaxime Ripard 
361f233dbcaSMaxime Ripard 	pinconfig = sunxi_pctrl_build_pin_config(node, &configlen);
362e11dee2eSMaxime Ripard 	if (IS_ERR(pinconfig)) {
363e11dee2eSMaxime Ripard 		ret = PTR_ERR(pinconfig);
364f233dbcaSMaxime Ripard 		goto err_free_map;
365f233dbcaSMaxime Ripard 	}
366f233dbcaSMaxime Ripard 
367f233dbcaSMaxime Ripard 	of_property_for_each_string(node, pin_prop, prop, group) {
3680e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp =
3690e37f88dSMaxime Ripard 			sunxi_pinctrl_find_group_by_name(pctl, group);
3700e37f88dSMaxime Ripard 
3710e37f88dSMaxime Ripard 		if (!grp) {
3720e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unknown pin %s", group);
3730e37f88dSMaxime Ripard 			continue;
3740e37f88dSMaxime Ripard 		}
3750e37f88dSMaxime Ripard 
3760e37f88dSMaxime Ripard 		if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
3770e37f88dSMaxime Ripard 							      grp->name,
3780e37f88dSMaxime Ripard 							      function)) {
3790e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unsupported function %s on pin %s",
3800e37f88dSMaxime Ripard 				function, group);
3810e37f88dSMaxime Ripard 			continue;
3820e37f88dSMaxime Ripard 		}
3830e37f88dSMaxime Ripard 
3840e37f88dSMaxime Ripard 		(*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
3850e37f88dSMaxime Ripard 		(*map)[i].data.mux.group = group;
3860e37f88dSMaxime Ripard 		(*map)[i].data.mux.function = function;
3870e37f88dSMaxime Ripard 
3880e37f88dSMaxime Ripard 		i++;
3890e37f88dSMaxime Ripard 
390e11dee2eSMaxime Ripard 		if (pinconfig) {
3910e37f88dSMaxime Ripard 			(*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
3920e37f88dSMaxime Ripard 			(*map)[i].data.configs.group_or_pin = group;
3930e37f88dSMaxime Ripard 			(*map)[i].data.configs.configs = pinconfig;
3940e37f88dSMaxime Ripard 			(*map)[i].data.configs.num_configs = configlen;
3950e37f88dSMaxime Ripard 			i++;
3960e37f88dSMaxime Ripard 		}
397e11dee2eSMaxime Ripard 	}
3980e37f88dSMaxime Ripard 
399e11dee2eSMaxime Ripard 	*num_maps = i;
400e11dee2eSMaxime Ripard 
401e11dee2eSMaxime Ripard 	/*
402e11dee2eSMaxime Ripard 	 * We know have the number of maps we need, we can resize our
403e11dee2eSMaxime Ripard 	 * map array
404e11dee2eSMaxime Ripard 	 */
405e11dee2eSMaxime Ripard 	*map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL);
406b3cde198SDan Carpenter 	if (!*map)
407e11dee2eSMaxime Ripard 		return -ENOMEM;
4080e37f88dSMaxime Ripard 
4090e37f88dSMaxime Ripard 	return 0;
410f233dbcaSMaxime Ripard 
411f233dbcaSMaxime Ripard err_free_map:
412b3cde198SDan Carpenter 	kfree(*map);
413b3cde198SDan Carpenter 	*map = NULL;
414f233dbcaSMaxime Ripard 	return ret;
4150e37f88dSMaxime Ripard }
4160e37f88dSMaxime Ripard 
4170e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
4180e37f88dSMaxime Ripard 				    struct pinctrl_map *map,
4190e37f88dSMaxime Ripard 				    unsigned num_maps)
4200e37f88dSMaxime Ripard {
42188f01a1bSChen-Yu Tsai 	int i;
42288f01a1bSChen-Yu Tsai 
42388f01a1bSChen-Yu Tsai 	/* pin config is never in the first map */
42488f01a1bSChen-Yu Tsai 	for (i = 1; i < num_maps; i++) {
42588f01a1bSChen-Yu Tsai 		if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP)
42688f01a1bSChen-Yu Tsai 			continue;
42788f01a1bSChen-Yu Tsai 
42888f01a1bSChen-Yu Tsai 		/*
42988f01a1bSChen-Yu Tsai 		 * All the maps share the same pin config,
43088f01a1bSChen-Yu Tsai 		 * free only the first one we find.
43188f01a1bSChen-Yu Tsai 		 */
43288f01a1bSChen-Yu Tsai 		kfree(map[i].data.configs.configs);
43388f01a1bSChen-Yu Tsai 		break;
43488f01a1bSChen-Yu Tsai 	}
43588f01a1bSChen-Yu Tsai 
4360e37f88dSMaxime Ripard 	kfree(map);
4370e37f88dSMaxime Ripard }
4380e37f88dSMaxime Ripard 
439022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = {
4400e37f88dSMaxime Ripard 	.dt_node_to_map		= sunxi_pctrl_dt_node_to_map,
4410e37f88dSMaxime Ripard 	.dt_free_map		= sunxi_pctrl_dt_free_map,
4420e37f88dSMaxime Ripard 	.get_groups_count	= sunxi_pctrl_get_groups_count,
4430e37f88dSMaxime Ripard 	.get_group_name		= sunxi_pctrl_get_group_name,
4440e37f88dSMaxime Ripard 	.get_group_pins		= sunxi_pctrl_get_group_pins,
4450e37f88dSMaxime Ripard };
4460e37f88dSMaxime Ripard 
447c5fda170SChen-Yu Tsai static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
448c5fda170SChen-Yu Tsai 			   u32 *offset, u32 *shift, u32 *mask)
449c5fda170SChen-Yu Tsai {
450c5fda170SChen-Yu Tsai 	switch (param) {
451c5fda170SChen-Yu Tsai 	case PIN_CONFIG_DRIVE_STRENGTH:
452c5fda170SChen-Yu Tsai 		*offset = sunxi_dlevel_reg(pin);
453c5fda170SChen-Yu Tsai 		*shift = sunxi_dlevel_offset(pin);
454c5fda170SChen-Yu Tsai 		*mask = DLEVEL_PINS_MASK;
455c5fda170SChen-Yu Tsai 		break;
456c5fda170SChen-Yu Tsai 
457c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_PULL_UP:
458c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_PULL_DOWN:
459c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_DISABLE:
460c5fda170SChen-Yu Tsai 		*offset = sunxi_pull_reg(pin);
461c5fda170SChen-Yu Tsai 		*shift = sunxi_pull_offset(pin);
462c5fda170SChen-Yu Tsai 		*mask = PULL_PINS_MASK;
463c5fda170SChen-Yu Tsai 		break;
464c5fda170SChen-Yu Tsai 
465c5fda170SChen-Yu Tsai 	default:
466c5fda170SChen-Yu Tsai 		return -ENOTSUPP;
467c5fda170SChen-Yu Tsai 	}
468c5fda170SChen-Yu Tsai 
469c5fda170SChen-Yu Tsai 	return 0;
470c5fda170SChen-Yu Tsai }
471c5fda170SChen-Yu Tsai 
472c5fda170SChen-Yu Tsai static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
473c5fda170SChen-Yu Tsai 			   unsigned long *config)
474c5fda170SChen-Yu Tsai {
475c5fda170SChen-Yu Tsai 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
476c5fda170SChen-Yu Tsai 	enum pin_config_param param = pinconf_to_config_param(*config);
477c5fda170SChen-Yu Tsai 	u32 offset, shift, mask, val;
478c5fda170SChen-Yu Tsai 	u16 arg;
479c5fda170SChen-Yu Tsai 	int ret;
480c5fda170SChen-Yu Tsai 
481c5fda170SChen-Yu Tsai 	pin -= pctl->desc->pin_base;
482c5fda170SChen-Yu Tsai 
483c5fda170SChen-Yu Tsai 	ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
484c5fda170SChen-Yu Tsai 	if (ret < 0)
485c5fda170SChen-Yu Tsai 		return ret;
486c5fda170SChen-Yu Tsai 
487c5fda170SChen-Yu Tsai 	val = (readl(pctl->membase + offset) >> shift) & mask;
488c5fda170SChen-Yu Tsai 
489c5fda170SChen-Yu Tsai 	switch (pinconf_to_config_param(*config)) {
490c5fda170SChen-Yu Tsai 	case PIN_CONFIG_DRIVE_STRENGTH:
491c5fda170SChen-Yu Tsai 		arg = (val + 1) * 10;
492c5fda170SChen-Yu Tsai 		break;
493c5fda170SChen-Yu Tsai 
494c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_PULL_UP:
495c5fda170SChen-Yu Tsai 		if (val != SUN4I_PINCTRL_PULL_UP)
496c5fda170SChen-Yu Tsai 			return -EINVAL;
497c5fda170SChen-Yu Tsai 		arg = 1; /* hardware is weak pull-up */
498c5fda170SChen-Yu Tsai 		break;
499c5fda170SChen-Yu Tsai 
500c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_PULL_DOWN:
501c5fda170SChen-Yu Tsai 		if (val != SUN4I_PINCTRL_PULL_DOWN)
502c5fda170SChen-Yu Tsai 			return -EINVAL;
503c5fda170SChen-Yu Tsai 		arg = 1; /* hardware is weak pull-down */
504c5fda170SChen-Yu Tsai 		break;
505c5fda170SChen-Yu Tsai 
506c5fda170SChen-Yu Tsai 	case PIN_CONFIG_BIAS_DISABLE:
507c5fda170SChen-Yu Tsai 		if (val != SUN4I_PINCTRL_NO_PULL)
508c5fda170SChen-Yu Tsai 			return -EINVAL;
509c5fda170SChen-Yu Tsai 		arg = 0;
510c5fda170SChen-Yu Tsai 		break;
511c5fda170SChen-Yu Tsai 
512c5fda170SChen-Yu Tsai 	default:
513c5fda170SChen-Yu Tsai 		/* sunxi_pconf_reg should catch anything unsupported */
514c5fda170SChen-Yu Tsai 		WARN_ON(1);
515c5fda170SChen-Yu Tsai 		return -ENOTSUPP;
516c5fda170SChen-Yu Tsai 	}
517c5fda170SChen-Yu Tsai 
518c5fda170SChen-Yu Tsai 	*config = pinconf_to_config_packed(param, arg);
519c5fda170SChen-Yu Tsai 
520c5fda170SChen-Yu Tsai 	return 0;
521c5fda170SChen-Yu Tsai }
522c5fda170SChen-Yu Tsai 
5230e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
5240e37f88dSMaxime Ripard 				 unsigned group,
5250e37f88dSMaxime Ripard 				 unsigned long *config)
5260e37f88dSMaxime Ripard {
5270e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
528c5fda170SChen-Yu Tsai 	struct sunxi_pinctrl_group *g = &pctl->groups[group];
5290e37f88dSMaxime Ripard 
530c5fda170SChen-Yu Tsai 	/* We only support 1 pin per group. Chain it to the pin callback */
531c5fda170SChen-Yu Tsai 	return sunxi_pconf_get(pctldev, g->pin, config);
5320e37f88dSMaxime Ripard }
5330e37f88dSMaxime Ripard 
53490be64e2SMaxime Ripard static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
53590be64e2SMaxime Ripard 			   unsigned long *configs, unsigned num_configs)
5360e37f88dSMaxime Ripard {
5370e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
53803b054e9SSherman Yin 	int i;
5390e37f88dSMaxime Ripard 
54003b054e9SSherman Yin 	for (i = 0; i < num_configs; i++) {
54151814827SChen-Yu Tsai 		enum pin_config_param param;
54251814827SChen-Yu Tsai 		unsigned long flags;
54351814827SChen-Yu Tsai 		u32 offset, shift, mask, reg;
54458957d2eSMika Westerberg 		u32 arg, val;
54551814827SChen-Yu Tsai 		int ret;
54651814827SChen-Yu Tsai 
54751814827SChen-Yu Tsai 		param = pinconf_to_config_param(configs[i]);
54851814827SChen-Yu Tsai 		arg = pinconf_to_config_argument(configs[i]);
54951814827SChen-Yu Tsai 
55051814827SChen-Yu Tsai 		ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
55151814827SChen-Yu Tsai 		if (ret < 0)
55251814827SChen-Yu Tsai 			return ret;
55351814827SChen-Yu Tsai 
55451814827SChen-Yu Tsai 		switch (param) {
5550e37f88dSMaxime Ripard 		case PIN_CONFIG_DRIVE_STRENGTH:
55651814827SChen-Yu Tsai 			if (arg < 10 || arg > 40)
5570e37f88dSMaxime Ripard 				return -EINVAL;
5580e37f88dSMaxime Ripard 			/*
5590e37f88dSMaxime Ripard 			 * We convert from mA to what the register expects:
5600e37f88dSMaxime Ripard 			 *   0: 10mA
5610e37f88dSMaxime Ripard 			 *   1: 20mA
5620e37f88dSMaxime Ripard 			 *   2: 30mA
5630e37f88dSMaxime Ripard 			 *   3: 40mA
5640e37f88dSMaxime Ripard 			 */
56551814827SChen-Yu Tsai 			val = arg / 10 - 1;
5660e37f88dSMaxime Ripard 			break;
56707fe64baSMaxime Ripard 		case PIN_CONFIG_BIAS_DISABLE:
568ac059e2aSPriit Laes 			val = 0;
569ac059e2aSPriit Laes 			break;
5700e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_UP:
57151814827SChen-Yu Tsai 			if (arg == 0)
57251814827SChen-Yu Tsai 				return -EINVAL;
57351814827SChen-Yu Tsai 			val = 1;
5740e37f88dSMaxime Ripard 			break;
5750e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_DOWN:
57651814827SChen-Yu Tsai 			if (arg == 0)
57751814827SChen-Yu Tsai 				return -EINVAL;
57851814827SChen-Yu Tsai 			val = 2;
5790e37f88dSMaxime Ripard 			break;
5800e37f88dSMaxime Ripard 		default:
58151814827SChen-Yu Tsai 			/* sunxi_pconf_reg should catch anything unsupported */
58251814827SChen-Yu Tsai 			WARN_ON(1);
58351814827SChen-Yu Tsai 			return -ENOTSUPP;
5840e37f88dSMaxime Ripard 		}
5850e37f88dSMaxime Ripard 
586f658ed36SJulia Cartwright 		raw_spin_lock_irqsave(&pctl->lock, flags);
58751814827SChen-Yu Tsai 		reg = readl(pctl->membase + offset);
58851814827SChen-Yu Tsai 		reg &= ~(mask << shift);
58951814827SChen-Yu Tsai 		writel(reg | val << shift, pctl->membase + offset);
590f658ed36SJulia Cartwright 		raw_spin_unlock_irqrestore(&pctl->lock, flags);
59151814827SChen-Yu Tsai 	} /* for each config */
5920e37f88dSMaxime Ripard 
5930e37f88dSMaxime Ripard 	return 0;
5940e37f88dSMaxime Ripard }
5950e37f88dSMaxime Ripard 
59690be64e2SMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
59790be64e2SMaxime Ripard 				 unsigned long *configs, unsigned num_configs)
59890be64e2SMaxime Ripard {
59990be64e2SMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
60090be64e2SMaxime Ripard 	struct sunxi_pinctrl_group *g = &pctl->groups[group];
60190be64e2SMaxime Ripard 
60290be64e2SMaxime Ripard 	/* We only support 1 pin per group. Chain it to the pin callback */
60390be64e2SMaxime Ripard 	return sunxi_pconf_set(pctldev, g->pin, configs, num_configs);
60490be64e2SMaxime Ripard }
60590be64e2SMaxime Ripard 
606022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = {
607c5fda170SChen-Yu Tsai 	.is_generic		= true,
608c5fda170SChen-Yu Tsai 	.pin_config_get		= sunxi_pconf_get,
60990be64e2SMaxime Ripard 	.pin_config_set		= sunxi_pconf_set,
6100e37f88dSMaxime Ripard 	.pin_config_group_get	= sunxi_pconf_group_get,
6110e37f88dSMaxime Ripard 	.pin_config_group_set	= sunxi_pconf_group_set,
6120e37f88dSMaxime Ripard };
6130e37f88dSMaxime Ripard 
614402bfb3cSChen-Yu Tsai static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
615402bfb3cSChen-Yu Tsai 					 unsigned pin,
616402bfb3cSChen-Yu Tsai 					 struct regulator *supply)
617402bfb3cSChen-Yu Tsai {
618cc62383fSOndrej Jirman 	unsigned short bank = pin / PINS_PER_BANK;
619cc62383fSOndrej Jirman 	unsigned long flags;
620402bfb3cSChen-Yu Tsai 	u32 val, reg;
621402bfb3cSChen-Yu Tsai 	int uV;
622402bfb3cSChen-Yu Tsai 
623f7275345SOndrej Jirman 	if (!pctl->desc->io_bias_cfg_variant)
624402bfb3cSChen-Yu Tsai 		return 0;
625402bfb3cSChen-Yu Tsai 
626402bfb3cSChen-Yu Tsai 	uV = regulator_get_voltage(supply);
627402bfb3cSChen-Yu Tsai 	if (uV < 0)
628402bfb3cSChen-Yu Tsai 		return uV;
629402bfb3cSChen-Yu Tsai 
630402bfb3cSChen-Yu Tsai 	/* Might be dummy regulator with no voltage set */
631402bfb3cSChen-Yu Tsai 	if (uV == 0)
632402bfb3cSChen-Yu Tsai 		return 0;
633402bfb3cSChen-Yu Tsai 
634f7275345SOndrej Jirman 	switch (pctl->desc->io_bias_cfg_variant) {
635f7275345SOndrej Jirman 	case BIAS_VOLTAGE_GRP_CONFIG:
636f7275345SOndrej Jirman 		/*
637f7275345SOndrej Jirman 		 * Configured value must be equal or greater to actual
638f7275345SOndrej Jirman 		 * voltage.
639f7275345SOndrej Jirman 		 */
640402bfb3cSChen-Yu Tsai 		if (uV <= 1800000)
641402bfb3cSChen-Yu Tsai 			val = 0x0; /* 1.8V */
642402bfb3cSChen-Yu Tsai 		else if (uV <= 2500000)
643402bfb3cSChen-Yu Tsai 			val = 0x6; /* 2.5V */
644402bfb3cSChen-Yu Tsai 		else if (uV <= 2800000)
645402bfb3cSChen-Yu Tsai 			val = 0x9; /* 2.8V */
646402bfb3cSChen-Yu Tsai 		else if (uV <= 3000000)
647402bfb3cSChen-Yu Tsai 			val = 0xA; /* 3.0V */
648402bfb3cSChen-Yu Tsai 		else
649402bfb3cSChen-Yu Tsai 			val = 0xD; /* 3.3V */
650402bfb3cSChen-Yu Tsai 
651402bfb3cSChen-Yu Tsai 		pin -= pctl->desc->pin_base;
652402bfb3cSChen-Yu Tsai 
653402bfb3cSChen-Yu Tsai 		reg = readl(pctl->membase + sunxi_grp_config_reg(pin));
654402bfb3cSChen-Yu Tsai 		reg &= ~IO_BIAS_MASK;
655402bfb3cSChen-Yu Tsai 		writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
656402bfb3cSChen-Yu Tsai 		return 0;
657cc62383fSOndrej Jirman 	case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
658cc62383fSOndrej Jirman 		val = uV <= 1800000 ? 1 : 0;
659cc62383fSOndrej Jirman 
660cc62383fSOndrej Jirman 		raw_spin_lock_irqsave(&pctl->lock, flags);
661cc62383fSOndrej Jirman 		reg = readl(pctl->membase + PIO_POW_MOD_SEL_REG);
662cc62383fSOndrej Jirman 		reg &= ~(1 << bank);
663cc62383fSOndrej Jirman 		writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG);
664cc62383fSOndrej Jirman 		raw_spin_unlock_irqrestore(&pctl->lock, flags);
665cc62383fSOndrej Jirman 		return 0;
666f7275345SOndrej Jirman 	default:
667f7275345SOndrej Jirman 		return -EINVAL;
668f7275345SOndrej Jirman 	}
669402bfb3cSChen-Yu Tsai }
670402bfb3cSChen-Yu Tsai 
6710e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
6720e37f88dSMaxime Ripard {
6730e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6740e37f88dSMaxime Ripard 
6750e37f88dSMaxime Ripard 	return pctl->nfunctions;
6760e37f88dSMaxime Ripard }
6770e37f88dSMaxime Ripard 
6780e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
6790e37f88dSMaxime Ripard 					   unsigned function)
6800e37f88dSMaxime Ripard {
6810e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6820e37f88dSMaxime Ripard 
6830e37f88dSMaxime Ripard 	return pctl->functions[function].name;
6840e37f88dSMaxime Ripard }
6850e37f88dSMaxime Ripard 
6860e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
6870e37f88dSMaxime Ripard 				     unsigned function,
6880e37f88dSMaxime Ripard 				     const char * const **groups,
6890e37f88dSMaxime Ripard 				     unsigned * const num_groups)
6900e37f88dSMaxime Ripard {
6910e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6920e37f88dSMaxime Ripard 
6930e37f88dSMaxime Ripard 	*groups = pctl->functions[function].groups;
6940e37f88dSMaxime Ripard 	*num_groups = pctl->functions[function].ngroups;
6950e37f88dSMaxime Ripard 
6960e37f88dSMaxime Ripard 	return 0;
6970e37f88dSMaxime Ripard }
6980e37f88dSMaxime Ripard 
6990e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
7000e37f88dSMaxime Ripard 				 unsigned pin,
7010e37f88dSMaxime Ripard 				 u8 config)
7020e37f88dSMaxime Ripard {
7030e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7041bee963dSMaxime Ripard 	unsigned long flags;
7051bee963dSMaxime Ripard 	u32 val, mask;
7060e37f88dSMaxime Ripard 
707f658ed36SJulia Cartwright 	raw_spin_lock_irqsave(&pctl->lock, flags);
7081bee963dSMaxime Ripard 
709b4575c69SChen-Yu Tsai 	pin -= pctl->desc->pin_base;
7101bee963dSMaxime Ripard 	val = readl(pctl->membase + sunxi_mux_reg(pin));
7111bee963dSMaxime Ripard 	mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
7120e37f88dSMaxime Ripard 	writel((val & ~mask) | config << sunxi_mux_offset(pin),
7130e37f88dSMaxime Ripard 		pctl->membase + sunxi_mux_reg(pin));
7141bee963dSMaxime Ripard 
715f658ed36SJulia Cartwright 	raw_spin_unlock_irqrestore(&pctl->lock, flags);
7160e37f88dSMaxime Ripard }
7170e37f88dSMaxime Ripard 
71803e9f0caSLinus Walleij static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev,
7190e37f88dSMaxime Ripard 			     unsigned function,
7200e37f88dSMaxime Ripard 			     unsigned group)
7210e37f88dSMaxime Ripard {
7220e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7230e37f88dSMaxime Ripard 	struct sunxi_pinctrl_group *g = pctl->groups + group;
7240e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions + function;
7250e37f88dSMaxime Ripard 	struct sunxi_desc_function *desc =
7260e37f88dSMaxime Ripard 		sunxi_pinctrl_desc_find_function_by_name(pctl,
7270e37f88dSMaxime Ripard 							 g->name,
7280e37f88dSMaxime Ripard 							 func->name);
7290e37f88dSMaxime Ripard 
7300e37f88dSMaxime Ripard 	if (!desc)
7310e37f88dSMaxime Ripard 		return -EINVAL;
7320e37f88dSMaxime Ripard 
7330e37f88dSMaxime Ripard 	sunxi_pmx_set(pctldev, g->pin, desc->muxval);
7340e37f88dSMaxime Ripard 
7350e37f88dSMaxime Ripard 	return 0;
7360e37f88dSMaxime Ripard }
7370e37f88dSMaxime Ripard 
73808e9e614SMaxime Ripard static int
73908e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
74008e9e614SMaxime Ripard 			struct pinctrl_gpio_range *range,
74108e9e614SMaxime Ripard 			unsigned offset,
74208e9e614SMaxime Ripard 			bool input)
74308e9e614SMaxime Ripard {
74408e9e614SMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
74508e9e614SMaxime Ripard 	struct sunxi_desc_function *desc;
74608e9e614SMaxime Ripard 	const char *func;
74708e9e614SMaxime Ripard 
74808e9e614SMaxime Ripard 	if (input)
74908e9e614SMaxime Ripard 		func = "gpio_in";
75008e9e614SMaxime Ripard 	else
75108e9e614SMaxime Ripard 		func = "gpio_out";
75208e9e614SMaxime Ripard 
753814d4f2eSMaxime Ripard 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func);
754814d4f2eSMaxime Ripard 	if (!desc)
755814d4f2eSMaxime Ripard 		return -EINVAL;
75608e9e614SMaxime Ripard 
75708e9e614SMaxime Ripard 	sunxi_pmx_set(pctldev, offset, desc->muxval);
75808e9e614SMaxime Ripard 
759814d4f2eSMaxime Ripard 	return 0;
76008e9e614SMaxime Ripard }
76108e9e614SMaxime Ripard 
7629a2a566aSMaxime Ripard static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
7639a2a566aSMaxime Ripard {
7649a2a566aSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7659a2a566aSMaxime Ripard 	unsigned short bank = offset / PINS_PER_BANK;
766ca443844SChen-Yu Tsai 	unsigned short bank_offset = bank - pctl->desc->pin_base /
767ca443844SChen-Yu Tsai 					    PINS_PER_BANK;
768ca443844SChen-Yu Tsai 	struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];
769dc144558SChen-Yu Tsai 	struct regulator *reg = s_reg->regulator;
770dc144558SChen-Yu Tsai 	char supply[16];
7719a2a566aSMaxime Ripard 	int ret;
7729a2a566aSMaxime Ripard 
773dc144558SChen-Yu Tsai 	if (reg) {
774dc144558SChen-Yu Tsai 		refcount_inc(&s_reg->refcount);
775dc144558SChen-Yu Tsai 		return 0;
776dc144558SChen-Yu Tsai 	}
7779a2a566aSMaxime Ripard 
7789a2a566aSMaxime Ripard 	snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank);
7799a2a566aSMaxime Ripard 	reg = regulator_get(pctl->dev, supply);
7809a2a566aSMaxime Ripard 	if (IS_ERR(reg)) {
7819a2a566aSMaxime Ripard 		dev_err(pctl->dev, "Couldn't get bank P%c regulator\n",
7829a2a566aSMaxime Ripard 			'A' + bank);
7839a2a566aSMaxime Ripard 		return PTR_ERR(reg);
7849a2a566aSMaxime Ripard 	}
7859a2a566aSMaxime Ripard 
7869a2a566aSMaxime Ripard 	ret = regulator_enable(reg);
7879a2a566aSMaxime Ripard 	if (ret) {
7889a2a566aSMaxime Ripard 		dev_err(pctl->dev,
7899a2a566aSMaxime Ripard 			"Couldn't enable bank P%c regulator\n", 'A' + bank);
7909a2a566aSMaxime Ripard 		goto out;
7919a2a566aSMaxime Ripard 	}
7929a2a566aSMaxime Ripard 
793402bfb3cSChen-Yu Tsai 	sunxi_pinctrl_set_io_bias_cfg(pctl, offset, reg);
794402bfb3cSChen-Yu Tsai 
795dc144558SChen-Yu Tsai 	s_reg->regulator = reg;
796dc144558SChen-Yu Tsai 	refcount_set(&s_reg->refcount, 1);
797dc144558SChen-Yu Tsai 
7989a2a566aSMaxime Ripard 	return 0;
7999a2a566aSMaxime Ripard 
8009a2a566aSMaxime Ripard out:
8019a2a566aSMaxime Ripard 	regulator_put(s_reg->regulator);
8029a2a566aSMaxime Ripard 
8039a2a566aSMaxime Ripard 	return ret;
8049a2a566aSMaxime Ripard }
8059a2a566aSMaxime Ripard 
8069a2a566aSMaxime Ripard static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset)
8079a2a566aSMaxime Ripard {
8089a2a566aSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
8099a2a566aSMaxime Ripard 	unsigned short bank = offset / PINS_PER_BANK;
810ca443844SChen-Yu Tsai 	unsigned short bank_offset = bank - pctl->desc->pin_base /
811ca443844SChen-Yu Tsai 					    PINS_PER_BANK;
812ca443844SChen-Yu Tsai 	struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];
8139a2a566aSMaxime Ripard 
8149a2a566aSMaxime Ripard 	if (!refcount_dec_and_test(&s_reg->refcount))
8159a2a566aSMaxime Ripard 		return 0;
8169a2a566aSMaxime Ripard 
8179a2a566aSMaxime Ripard 	regulator_disable(s_reg->regulator);
8189a2a566aSMaxime Ripard 	regulator_put(s_reg->regulator);
8199a2a566aSMaxime Ripard 	s_reg->regulator = NULL;
8209a2a566aSMaxime Ripard 
8219a2a566aSMaxime Ripard 	return 0;
8229a2a566aSMaxime Ripard }
8239a2a566aSMaxime Ripard 
824022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = {
8250e37f88dSMaxime Ripard 	.get_functions_count	= sunxi_pmx_get_funcs_cnt,
8260e37f88dSMaxime Ripard 	.get_function_name	= sunxi_pmx_get_func_name,
8270e37f88dSMaxime Ripard 	.get_function_groups	= sunxi_pmx_get_func_groups,
82803e9f0caSLinus Walleij 	.set_mux		= sunxi_pmx_set_mux,
82908e9e614SMaxime Ripard 	.gpio_set_direction	= sunxi_pmx_gpio_set_direction,
8309a2a566aSMaxime Ripard 	.request		= sunxi_pmx_request,
8319a2a566aSMaxime Ripard 	.free			= sunxi_pmx_free,
83213960072SMaxime Ripard 	.strict			= true,
8330e37f88dSMaxime Ripard };
8340e37f88dSMaxime Ripard 
83508e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
83608e9e614SMaxime Ripard 					unsigned offset)
83708e9e614SMaxime Ripard {
83808e9e614SMaxime Ripard 	return pinctrl_gpio_direction_input(chip->base + offset);
83908e9e614SMaxime Ripard }
84008e9e614SMaxime Ripard 
84108e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
84208e9e614SMaxime Ripard {
84388057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
84408e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
84508e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
8466cee3821SLinus Walleij 	bool set_mux = pctl->desc->irq_read_needs_mux &&
8476cee3821SLinus Walleij 		gpiochip_line_is_irq(chip, offset);
848be2d107fSKrzysztof Adamski 	u32 pin = offset + chip->base;
849ef6d24ccSHans de Goede 	u32 val;
850ef6d24ccSHans de Goede 
851ef6d24ccSHans de Goede 	if (set_mux)
852be2d107fSKrzysztof Adamski 		sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
853ef6d24ccSHans de Goede 
854ef6d24ccSHans de Goede 	val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
855ef6d24ccSHans de Goede 
856ef6d24ccSHans de Goede 	if (set_mux)
857be2d107fSKrzysztof Adamski 		sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
85808e9e614SMaxime Ripard 
85939e24ac3SLinus Walleij 	return !!val;
86008e9e614SMaxime Ripard }
86108e9e614SMaxime Ripard 
86208e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
86308e9e614SMaxime Ripard 				unsigned offset, int value)
86408e9e614SMaxime Ripard {
86588057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
86608e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
86708e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
8681bee963dSMaxime Ripard 	unsigned long flags;
8691bee963dSMaxime Ripard 	u32 regval;
87008e9e614SMaxime Ripard 
871f658ed36SJulia Cartwright 	raw_spin_lock_irqsave(&pctl->lock, flags);
8721bee963dSMaxime Ripard 
8731bee963dSMaxime Ripard 	regval = readl(pctl->membase + reg);
87408e9e614SMaxime Ripard 
875df7b34f4SMaxime Ripard 	if (value)
876df7b34f4SMaxime Ripard 		regval |= BIT(index);
877df7b34f4SMaxime Ripard 	else
878df7b34f4SMaxime Ripard 		regval &= ~(BIT(index));
879df7b34f4SMaxime Ripard 
880df7b34f4SMaxime Ripard 	writel(regval, pctl->membase + reg);
8811bee963dSMaxime Ripard 
882f658ed36SJulia Cartwright 	raw_spin_unlock_irqrestore(&pctl->lock, flags);
88308e9e614SMaxime Ripard }
88408e9e614SMaxime Ripard 
885fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
886fa8cf57cSChen-Yu Tsai 					unsigned offset, int value)
887fa8cf57cSChen-Yu Tsai {
888fa8cf57cSChen-Yu Tsai 	sunxi_pinctrl_gpio_set(chip, offset, value);
889fa8cf57cSChen-Yu Tsai 	return pinctrl_gpio_direction_output(chip->base + offset);
890fa8cf57cSChen-Yu Tsai }
891fa8cf57cSChen-Yu Tsai 
892a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
893a0d72094SMaxime Ripard 				const struct of_phandle_args *gpiospec,
894a0d72094SMaxime Ripard 				u32 *flags)
895a0d72094SMaxime Ripard {
896a0d72094SMaxime Ripard 	int pin, base;
897a0d72094SMaxime Ripard 
898a0d72094SMaxime Ripard 	base = PINS_PER_BANK * gpiospec->args[0];
899a0d72094SMaxime Ripard 	pin = base + gpiospec->args[1];
900a0d72094SMaxime Ripard 
901343f1327SChen-Yu Tsai 	if (pin > gc->ngpio)
902a0d72094SMaxime Ripard 		return -EINVAL;
903a0d72094SMaxime Ripard 
904a0d72094SMaxime Ripard 	if (flags)
905a0d72094SMaxime Ripard 		*flags = gpiospec->args[2];
906a0d72094SMaxime Ripard 
907a0d72094SMaxime Ripard 	return pin;
908a0d72094SMaxime Ripard }
909a0d72094SMaxime Ripard 
91060242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
91160242db1SMaxime Ripard {
91288057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
91360242db1SMaxime Ripard 	struct sunxi_desc_function *desc;
914343f1327SChen-Yu Tsai 	unsigned pinnum = pctl->desc->pin_base + offset;
9150d3bafacSChen-Yu Tsai 	unsigned irqnum;
91660242db1SMaxime Ripard 
917c9e3b2d8SAxel Lin 	if (offset >= chip->ngpio)
91860242db1SMaxime Ripard 		return -ENXIO;
91960242db1SMaxime Ripard 
920343f1327SChen-Yu Tsai 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq");
92160242db1SMaxime Ripard 	if (!desc)
92260242db1SMaxime Ripard 		return -EINVAL;
92360242db1SMaxime Ripard 
9240d3bafacSChen-Yu Tsai 	irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
92560242db1SMaxime Ripard 
92658383c78SLinus Walleij 	dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n",
9270d3bafacSChen-Yu Tsai 		chip->label, offset + chip->base, irqnum);
9280d3bafacSChen-Yu Tsai 
9290d3bafacSChen-Yu Tsai 	return irq_find_mapping(pctl->domain, irqnum);
93060242db1SMaxime Ripard }
93160242db1SMaxime Ripard 
932fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
93360242db1SMaxime Ripard {
93460242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
935fea6d8efSHans de Goede 	struct sunxi_desc_function *func;
936f83549d6SChen-Yu Tsai 	int ret;
937fea6d8efSHans de Goede 
938fea6d8efSHans de Goede 	func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
939fea6d8efSHans de Goede 					pctl->irq_array[d->hwirq], "irq");
940fea6d8efSHans de Goede 	if (!func)
941fea6d8efSHans de Goede 		return -EINVAL;
942fea6d8efSHans de Goede 
943e3a2e878SAlexandre Courbot 	ret = gpiochip_lock_as_irq(pctl->chip,
944343f1327SChen-Yu Tsai 			pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
945f83549d6SChen-Yu Tsai 	if (ret) {
946f83549d6SChen-Yu Tsai 		dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
947f83549d6SChen-Yu Tsai 			irqd_to_hwirq(d));
948f83549d6SChen-Yu Tsai 		return ret;
949f83549d6SChen-Yu Tsai 	}
950f83549d6SChen-Yu Tsai 
951fea6d8efSHans de Goede 	/* Change muxing to INT mode */
952fea6d8efSHans de Goede 	sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
953fea6d8efSHans de Goede 
954fea6d8efSHans de Goede 	return 0;
955fea6d8efSHans de Goede }
95608e9e614SMaxime Ripard 
957f83549d6SChen-Yu Tsai static void sunxi_pinctrl_irq_release_resources(struct irq_data *d)
958f83549d6SChen-Yu Tsai {
959f83549d6SChen-Yu Tsai 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
960f83549d6SChen-Yu Tsai 
961e3a2e878SAlexandre Courbot 	gpiochip_unlock_as_irq(pctl->chip,
962343f1327SChen-Yu Tsai 			      pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
963f83549d6SChen-Yu Tsai }
964f83549d6SChen-Yu Tsai 
965f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
96660242db1SMaxime Ripard {
96760242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
9684b0d6c5aSIcenowy Zheng 	u32 reg = sunxi_irq_cfg_reg(pctl->desc, d->hwirq);
96960242db1SMaxime Ripard 	u8 index = sunxi_irq_cfg_offset(d->hwirq);
9701bee963dSMaxime Ripard 	unsigned long flags;
9712aaaddffSMaxime Ripard 	u32 regval;
97260242db1SMaxime Ripard 	u8 mode;
97360242db1SMaxime Ripard 
97460242db1SMaxime Ripard 	switch (type) {
97560242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_RISING:
97660242db1SMaxime Ripard 		mode = IRQ_EDGE_RISING;
97760242db1SMaxime Ripard 		break;
97860242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_FALLING:
97960242db1SMaxime Ripard 		mode = IRQ_EDGE_FALLING;
98060242db1SMaxime Ripard 		break;
98160242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_BOTH:
98260242db1SMaxime Ripard 		mode = IRQ_EDGE_BOTH;
98360242db1SMaxime Ripard 		break;
98460242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_HIGH:
98560242db1SMaxime Ripard 		mode = IRQ_LEVEL_HIGH;
98660242db1SMaxime Ripard 		break;
98760242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_LOW:
98860242db1SMaxime Ripard 		mode = IRQ_LEVEL_LOW;
98960242db1SMaxime Ripard 		break;
99060242db1SMaxime Ripard 	default:
99160242db1SMaxime Ripard 		return -EINVAL;
99260242db1SMaxime Ripard 	}
99360242db1SMaxime Ripard 
994f658ed36SJulia Cartwright 	raw_spin_lock_irqsave(&pctl->lock, flags);
9951bee963dSMaxime Ripard 
996a0d6de9bSMaxime Ripard 	if (type & IRQ_TYPE_LEVEL_MASK)
997b9a5ec33SThomas Gleixner 		irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip,
998a0d6de9bSMaxime Ripard 						 handle_fasteoi_irq, NULL);
999a0d6de9bSMaxime Ripard 	else
1000b9a5ec33SThomas Gleixner 		irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip,
1001a0d6de9bSMaxime Ripard 						 handle_edge_irq, NULL);
1002a0d6de9bSMaxime Ripard 
10032aaaddffSMaxime Ripard 	regval = readl(pctl->membase + reg);
1004d82f9401SHans de Goede 	regval &= ~(IRQ_CFG_IRQ_MASK << index);
10052aaaddffSMaxime Ripard 	writel(regval | (mode << index), pctl->membase + reg);
100660242db1SMaxime Ripard 
1007f658ed36SJulia Cartwright 	raw_spin_unlock_irqrestore(&pctl->lock, flags);
100860242db1SMaxime Ripard 
100960242db1SMaxime Ripard 	return 0;
101060242db1SMaxime Ripard }
101160242db1SMaxime Ripard 
1012645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d)
101360242db1SMaxime Ripard {
101460242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
10154b0d6c5aSIcenowy Zheng 	u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq);
101660242db1SMaxime Ripard 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
101760242db1SMaxime Ripard 
101860242db1SMaxime Ripard 	/* Clear the IRQ */
101960242db1SMaxime Ripard 	writel(1 << status_idx, pctl->membase + status_reg);
102060242db1SMaxime Ripard }
102160242db1SMaxime Ripard 
102260242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d)
102360242db1SMaxime Ripard {
102460242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
10254b0d6c5aSIcenowy Zheng 	u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq);
102660242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
10271bee963dSMaxime Ripard 	unsigned long flags;
102860242db1SMaxime Ripard 	u32 val;
102960242db1SMaxime Ripard 
1030f658ed36SJulia Cartwright 	raw_spin_lock_irqsave(&pctl->lock, flags);
10311bee963dSMaxime Ripard 
103260242db1SMaxime Ripard 	/* Mask the IRQ */
103360242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
103460242db1SMaxime Ripard 	writel(val & ~(1 << idx), pctl->membase + reg);
10351bee963dSMaxime Ripard 
1036f658ed36SJulia Cartwright 	raw_spin_unlock_irqrestore(&pctl->lock, flags);
103760242db1SMaxime Ripard }
103860242db1SMaxime Ripard 
103960242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
104060242db1SMaxime Ripard {
104160242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
10424b0d6c5aSIcenowy Zheng 	u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq);
104360242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
10441bee963dSMaxime Ripard 	unsigned long flags;
104560242db1SMaxime Ripard 	u32 val;
104660242db1SMaxime Ripard 
1047f658ed36SJulia Cartwright 	raw_spin_lock_irqsave(&pctl->lock, flags);
10481bee963dSMaxime Ripard 
104960242db1SMaxime Ripard 	/* Unmask the IRQ */
105060242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
105160242db1SMaxime Ripard 	writel(val | (1 << idx), pctl->membase + reg);
10521bee963dSMaxime Ripard 
1053f658ed36SJulia Cartwright 	raw_spin_unlock_irqrestore(&pctl->lock, flags);
105460242db1SMaxime Ripard }
105560242db1SMaxime Ripard 
1056d61e23e5SHans de Goede static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d)
1057d61e23e5SHans de Goede {
1058d61e23e5SHans de Goede 	sunxi_pinctrl_irq_ack(d);
1059d61e23e5SHans de Goede 	sunxi_pinctrl_irq_unmask(d);
1060d61e23e5SHans de Goede }
1061d61e23e5SHans de Goede 
1062a59c99d9SSamuel Holland static int sunxi_pinctrl_irq_set_wake(struct irq_data *d, unsigned int on)
1063a59c99d9SSamuel Holland {
1064a59c99d9SSamuel Holland 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
1065a59c99d9SSamuel Holland 	u8 bank = d->hwirq / IRQ_PER_BANK;
1066a59c99d9SSamuel Holland 
1067a59c99d9SSamuel Holland 	return irq_set_irq_wake(pctl->irq[bank], on);
1068a59c99d9SSamuel Holland }
1069a59c99d9SSamuel Holland 
1070f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
1071fb5b7788SMaxime Ripard 	.name		= "sunxi_pio_edge",
1072645ec714SMaxime Ripard 	.irq_ack	= sunxi_pinctrl_irq_ack,
107360242db1SMaxime Ripard 	.irq_mask	= sunxi_pinctrl_irq_mask,
107460242db1SMaxime Ripard 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
1075fea6d8efSHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
1076f83549d6SChen-Yu Tsai 	.irq_release_resources = sunxi_pinctrl_irq_release_resources,
107760242db1SMaxime Ripard 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
1078a59c99d9SSamuel Holland 	.irq_set_wake	= sunxi_pinctrl_irq_set_wake,
10798587b21cSSamuel Holland 	.flags		= IRQCHIP_MASK_ON_SUSPEND,
108060242db1SMaxime Ripard };
108160242db1SMaxime Ripard 
1082f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = {
1083fb5b7788SMaxime Ripard 	.name		= "sunxi_pio_level",
1084f4c51c10SHans de Goede 	.irq_eoi	= sunxi_pinctrl_irq_ack,
1085f4c51c10SHans de Goede 	.irq_mask	= sunxi_pinctrl_irq_mask,
1086f4c51c10SHans de Goede 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
1087d61e23e5SHans de Goede 	/* Define irq_enable / disable to avoid spurious irqs for drivers
1088d61e23e5SHans de Goede 	 * using these to suppress irqs while they clear the irq source */
1089d61e23e5SHans de Goede 	.irq_enable	= sunxi_pinctrl_irq_ack_unmask,
1090d61e23e5SHans de Goede 	.irq_disable	= sunxi_pinctrl_irq_mask,
1091f4c51c10SHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
1092f83549d6SChen-Yu Tsai 	.irq_release_resources = sunxi_pinctrl_irq_release_resources,
1093f4c51c10SHans de Goede 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
1094a59c99d9SSamuel Holland 	.irq_set_wake	= sunxi_pinctrl_irq_set_wake,
1095a59c99d9SSamuel Holland 	.flags		= IRQCHIP_EOI_THREADED |
10968587b21cSSamuel Holland 			  IRQCHIP_MASK_ON_SUSPEND |
1097f4c51c10SHans de Goede 			  IRQCHIP_EOI_IF_HANDLED,
109860242db1SMaxime Ripard };
109960242db1SMaxime Ripard 
1100d8323c6bSMaxime Ripard static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d,
1101d8323c6bSMaxime Ripard 				      struct device_node *node,
1102d8323c6bSMaxime Ripard 				      const u32 *intspec,
1103d8323c6bSMaxime Ripard 				      unsigned int intsize,
1104d8323c6bSMaxime Ripard 				      unsigned long *out_hwirq,
1105d8323c6bSMaxime Ripard 				      unsigned int *out_type)
1106d8323c6bSMaxime Ripard {
11078297992cSHans de Goede 	struct sunxi_pinctrl *pctl = d->host_data;
1108d8323c6bSMaxime Ripard 	struct sunxi_desc_function *desc;
1109d8323c6bSMaxime Ripard 	int pin, base;
1110d8323c6bSMaxime Ripard 
1111d8323c6bSMaxime Ripard 	if (intsize < 3)
1112d8323c6bSMaxime Ripard 		return -EINVAL;
1113d8323c6bSMaxime Ripard 
1114d8323c6bSMaxime Ripard 	base = PINS_PER_BANK * intspec[0];
11158297992cSHans de Goede 	pin = pctl->desc->pin_base + base + intspec[1];
1116d8323c6bSMaxime Ripard 
11178297992cSHans de Goede 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq");
1118d8323c6bSMaxime Ripard 	if (!desc)
1119d8323c6bSMaxime Ripard 		return -EINVAL;
1120d8323c6bSMaxime Ripard 
1121d8323c6bSMaxime Ripard 	*out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum;
1122d8323c6bSMaxime Ripard 	*out_type = intspec[2];
1123d8323c6bSMaxime Ripard 
1124d8323c6bSMaxime Ripard 	return 0;
1125d8323c6bSMaxime Ripard }
1126d8323c6bSMaxime Ripard 
11272421dfd6STobias Klauser static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = {
1128d8323c6bSMaxime Ripard 	.xlate		= sunxi_pinctrl_irq_of_xlate,
1129d8323c6bSMaxime Ripard };
1130d8323c6bSMaxime Ripard 
1131bd0b9ac4SThomas Gleixner static void sunxi_pinctrl_irq_handler(struct irq_desc *desc)
113260242db1SMaxime Ripard {
1133eeef97b1SThomas Gleixner 	unsigned int irq = irq_desc_get_irq(desc);
11345663bb27SJiang Liu 	struct irq_chip *chip = irq_desc_get_chip(desc);
11355663bb27SJiang Liu 	struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc);
1136aebdc8abSMaxime Ripard 	unsigned long bank, reg, val;
113760242db1SMaxime Ripard 
1138aebdc8abSMaxime Ripard 	for (bank = 0; bank < pctl->desc->irq_banks; bank++)
1139aebdc8abSMaxime Ripard 		if (irq == pctl->irq[bank])
1140aebdc8abSMaxime Ripard 			break;
114160242db1SMaxime Ripard 
1142fd5198ddSYangtao Li 	WARN_ON(bank == pctl->desc->irq_banks);
1143aebdc8abSMaxime Ripard 
1144a1158e36SYangtao Li 	chained_irq_enter(chip, desc);
1145a1158e36SYangtao Li 
11464b0d6c5aSIcenowy Zheng 	reg = sunxi_irq_status_reg_from_bank(pctl->desc, bank);
1147aebdc8abSMaxime Ripard 	val = readl(pctl->membase + reg);
114860242db1SMaxime Ripard 
1149aebdc8abSMaxime Ripard 	if (val) {
115060242db1SMaxime Ripard 		int irqoffset;
115160242db1SMaxime Ripard 
1152aebdc8abSMaxime Ripard 		for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) {
1153aebdc8abSMaxime Ripard 			int pin_irq = irq_find_mapping(pctl->domain,
1154aebdc8abSMaxime Ripard 						       bank * IRQ_PER_BANK + irqoffset);
115560242db1SMaxime Ripard 			generic_handle_irq(pin_irq);
115660242db1SMaxime Ripard 		}
115760242db1SMaxime Ripard 	}
1158a1158e36SYangtao Li 
1159a1158e36SYangtao Li 	chained_irq_exit(chip, desc);
116060242db1SMaxime Ripard }
116160242db1SMaxime Ripard 
11620e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
11630e37f88dSMaxime Ripard 					const char *name)
11640e37f88dSMaxime Ripard {
11650e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
11660e37f88dSMaxime Ripard 
11670e37f88dSMaxime Ripard 	while (func->name) {
11680e37f88dSMaxime Ripard 		/* function already there */
11690e37f88dSMaxime Ripard 		if (strcmp(func->name, name) == 0) {
11700e37f88dSMaxime Ripard 			func->ngroups++;
11710e37f88dSMaxime Ripard 			return -EEXIST;
11720e37f88dSMaxime Ripard 		}
11730e37f88dSMaxime Ripard 		func++;
11740e37f88dSMaxime Ripard 	}
11750e37f88dSMaxime Ripard 
11760e37f88dSMaxime Ripard 	func->name = name;
11770e37f88dSMaxime Ripard 	func->ngroups = 1;
11780e37f88dSMaxime Ripard 
11790e37f88dSMaxime Ripard 	pctl->nfunctions++;
11800e37f88dSMaxime Ripard 
11810e37f88dSMaxime Ripard 	return 0;
11820e37f88dSMaxime Ripard }
11830e37f88dSMaxime Ripard 
11840e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev)
11850e37f88dSMaxime Ripard {
11860e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
1187a93a676bSChristophe JAILLET 	void *ptr;
11880e37f88dSMaxime Ripard 	int i;
11890e37f88dSMaxime Ripard 
1190578db85fSMaxime Ripard 	/*
1191578db85fSMaxime Ripard 	 * Allocate groups
1192578db85fSMaxime Ripard 	 *
1193578db85fSMaxime Ripard 	 * We assume that the number of groups is the number of pins
1194578db85fSMaxime Ripard 	 * given in the data array.
11950e37f88dSMaxime Ripard 
1196578db85fSMaxime Ripard 	 * This will not always be true, since some pins might not be
1197578db85fSMaxime Ripard 	 * available in the current variant, but fortunately for us,
1198578db85fSMaxime Ripard 	 * this means that the number of pins is the maximum group
1199578db85fSMaxime Ripard 	 * number we will ever see.
1200578db85fSMaxime Ripard 	 */
1201a86854d0SKees Cook 	pctl->groups = devm_kcalloc(&pdev->dev,
1202a86854d0SKees Cook 				    pctl->desc->npins, sizeof(*pctl->groups),
12030e37f88dSMaxime Ripard 				    GFP_KERNEL);
12040e37f88dSMaxime Ripard 	if (!pctl->groups)
12050e37f88dSMaxime Ripard 		return -ENOMEM;
12060e37f88dSMaxime Ripard 
12070e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
12080e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
1209578db85fSMaxime Ripard 		struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
1210578db85fSMaxime Ripard 
1211578db85fSMaxime Ripard 		if (pin->variant && !(pctl->variant & pin->variant))
1212578db85fSMaxime Ripard 			continue;
12130e37f88dSMaxime Ripard 
12140e37f88dSMaxime Ripard 		group->name = pin->pin.name;
12150e37f88dSMaxime Ripard 		group->pin = pin->pin.number;
1216578db85fSMaxime Ripard 
1217578db85fSMaxime Ripard 		/* And now we count the actual number of pins / groups */
1218578db85fSMaxime Ripard 		pctl->ngroups++;
12190e37f88dSMaxime Ripard 	}
12200e37f88dSMaxime Ripard 
12210e37f88dSMaxime Ripard 	/*
1222*d1dee814SAndre Przywara 	 * Find an upper bound for the maximum number of functions: in
1223*d1dee814SAndre Przywara 	 * the worst case we have gpio_in, gpio_out, irq and up to four
1224*d1dee814SAndre Przywara 	 * special functions per pin, plus one entry for the sentinel.
1225*d1dee814SAndre Przywara 	 * We'll reallocate that later anyway.
12260e37f88dSMaxime Ripard 	 */
1227*d1dee814SAndre Przywara 	pctl->functions = kcalloc(4 * pctl->ngroups + 4,
1228a86854d0SKees Cook 				  sizeof(*pctl->functions),
12290e37f88dSMaxime Ripard 				  GFP_KERNEL);
12300e37f88dSMaxime Ripard 	if (!pctl->functions)
12310e37f88dSMaxime Ripard 		return -ENOMEM;
12320e37f88dSMaxime Ripard 
12330e37f88dSMaxime Ripard 	/* Count functions and their associated groups */
12340e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
12350e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
1236578db85fSMaxime Ripard 		struct sunxi_desc_function *func;
12370e37f88dSMaxime Ripard 
1238578db85fSMaxime Ripard 		if (pin->variant && !(pctl->variant & pin->variant))
1239578db85fSMaxime Ripard 			continue;
1240578db85fSMaxime Ripard 
1241578db85fSMaxime Ripard 		for (func = pin->functions; func->name; func++) {
1242578db85fSMaxime Ripard 			if (func->variant && !(pctl->variant & func->variant))
1243578db85fSMaxime Ripard 				continue;
1244578db85fSMaxime Ripard 
1245d54e9a28SChen-Yu Tsai 			/* Create interrupt mapping while we're at it */
1246aebdc8abSMaxime Ripard 			if (!strcmp(func->name, "irq")) {
1247aebdc8abSMaxime Ripard 				int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
1248aebdc8abSMaxime Ripard 				pctl->irq_array[irqnum] = pin->pin.number;
1249aebdc8abSMaxime Ripard 			}
1250aebdc8abSMaxime Ripard 
12510e37f88dSMaxime Ripard 			sunxi_pinctrl_add_function(pctl, func->name);
12520e37f88dSMaxime Ripard 		}
12530e37f88dSMaxime Ripard 	}
12540e37f88dSMaxime Ripard 
1255578db85fSMaxime Ripard 	/* And now allocated and fill the array for real */
1256a93a676bSChristophe JAILLET 	ptr = krealloc(pctl->functions,
12570e37f88dSMaxime Ripard 		       pctl->nfunctions * sizeof(*pctl->functions),
12580e37f88dSMaxime Ripard 		       GFP_KERNEL);
1259a93a676bSChristophe JAILLET 	if (!ptr) {
1260578db85fSMaxime Ripard 		kfree(pctl->functions);
1261a93a676bSChristophe JAILLET 		pctl->functions = NULL;
1262578db85fSMaxime Ripard 		return -ENOMEM;
1263578db85fSMaxime Ripard 	}
1264a93a676bSChristophe JAILLET 	pctl->functions = ptr;
12650e37f88dSMaxime Ripard 
12660e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
12670e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
1268578db85fSMaxime Ripard 		struct sunxi_desc_function *func;
12690e37f88dSMaxime Ripard 
1270578db85fSMaxime Ripard 		if (pin->variant && !(pctl->variant & pin->variant))
1271578db85fSMaxime Ripard 			continue;
1272578db85fSMaxime Ripard 
1273578db85fSMaxime Ripard 		for (func = pin->functions; func->name; func++) {
12740e37f88dSMaxime Ripard 			struct sunxi_pinctrl_function *func_item;
12750e37f88dSMaxime Ripard 			const char **func_grp;
12760e37f88dSMaxime Ripard 
1277578db85fSMaxime Ripard 			if (func->variant && !(pctl->variant & func->variant))
1278578db85fSMaxime Ripard 				continue;
1279578db85fSMaxime Ripard 
12800e37f88dSMaxime Ripard 			func_item = sunxi_pinctrl_find_function_by_name(pctl,
12810e37f88dSMaxime Ripard 									func->name);
1282a4925311SYueHaibing 			if (!func_item) {
1283a4925311SYueHaibing 				kfree(pctl->functions);
12840e37f88dSMaxime Ripard 				return -EINVAL;
1285a4925311SYueHaibing 			}
12860e37f88dSMaxime Ripard 
12870e37f88dSMaxime Ripard 			if (!func_item->groups) {
12880e37f88dSMaxime Ripard 				func_item->groups =
1289a86854d0SKees Cook 					devm_kcalloc(&pdev->dev,
1290a86854d0SKees Cook 						     func_item->ngroups,
1291a86854d0SKees Cook 						     sizeof(*func_item->groups),
12920e37f88dSMaxime Ripard 						     GFP_KERNEL);
1293a4925311SYueHaibing 				if (!func_item->groups) {
1294a4925311SYueHaibing 					kfree(pctl->functions);
12950e37f88dSMaxime Ripard 					return -ENOMEM;
12960e37f88dSMaxime Ripard 				}
1297a4925311SYueHaibing 			}
12980e37f88dSMaxime Ripard 
12990e37f88dSMaxime Ripard 			func_grp = func_item->groups;
13000e37f88dSMaxime Ripard 			while (*func_grp)
13010e37f88dSMaxime Ripard 				func_grp++;
13020e37f88dSMaxime Ripard 
13030e37f88dSMaxime Ripard 			*func_grp = pin->pin.name;
13040e37f88dSMaxime Ripard 		}
13050e37f88dSMaxime Ripard 	}
13060e37f88dSMaxime Ripard 
13070e37f88dSMaxime Ripard 	return 0;
13080e37f88dSMaxime Ripard }
13090e37f88dSMaxime Ripard 
13107c926492SMaxime Ripard static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff)
13117c926492SMaxime Ripard {
13127c926492SMaxime Ripard 	unsigned long clock = clk_get_rate(clk);
1313d8a22212SArnd Bergmann 	unsigned int best_diff, best_div;
13147c926492SMaxime Ripard 	int i;
13157c926492SMaxime Ripard 
1316d8a22212SArnd Bergmann 	best_diff = abs(freq - clock);
1317d8a22212SArnd Bergmann 	best_div = 0;
1318d8a22212SArnd Bergmann 
1319d8a22212SArnd Bergmann 	for (i = 1; i < 8; i++) {
13207c926492SMaxime Ripard 		int cur_diff = abs(freq - (clock >> i));
13217c926492SMaxime Ripard 
13227c926492SMaxime Ripard 		if (cur_diff < best_diff) {
13237c926492SMaxime Ripard 			best_diff = cur_diff;
13247c926492SMaxime Ripard 			best_div = i;
13257c926492SMaxime Ripard 		}
13267c926492SMaxime Ripard 	}
13277c926492SMaxime Ripard 
13287c926492SMaxime Ripard 	*diff = best_diff;
13297c926492SMaxime Ripard 	return best_div;
13307c926492SMaxime Ripard }
13317c926492SMaxime Ripard 
13327c926492SMaxime Ripard static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
13337c926492SMaxime Ripard 					struct device_node *node)
13347c926492SMaxime Ripard {
13357c926492SMaxime Ripard 	unsigned int hosc_diff, losc_diff;
13367c926492SMaxime Ripard 	unsigned int hosc_div, losc_div;
13377c926492SMaxime Ripard 	struct clk *hosc, *losc;
13387c926492SMaxime Ripard 	u8 div, src;
13397c926492SMaxime Ripard 	int i, ret;
13407c926492SMaxime Ripard 
13417c926492SMaxime Ripard 	/* Deal with old DTs that didn't have the oscillators */
1342470b73a3SGeert Uytterhoeven 	if (of_clk_get_parent_count(node) != 3)
13437c926492SMaxime Ripard 		return 0;
13447c926492SMaxime Ripard 
13457c926492SMaxime Ripard 	/* If we don't have any setup, bail out */
13467c926492SMaxime Ripard 	if (!of_find_property(node, "input-debounce", NULL))
13477c926492SMaxime Ripard 		return 0;
13487c926492SMaxime Ripard 
13497c926492SMaxime Ripard 	losc = devm_clk_get(pctl->dev, "losc");
13507c926492SMaxime Ripard 	if (IS_ERR(losc))
13517c926492SMaxime Ripard 		return PTR_ERR(losc);
13527c926492SMaxime Ripard 
13537c926492SMaxime Ripard 	hosc = devm_clk_get(pctl->dev, "hosc");
13547c926492SMaxime Ripard 	if (IS_ERR(hosc))
13557c926492SMaxime Ripard 		return PTR_ERR(hosc);
13567c926492SMaxime Ripard 
13577c926492SMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
13587c926492SMaxime Ripard 		unsigned long debounce_freq;
13597c926492SMaxime Ripard 		u32 debounce;
13607c926492SMaxime Ripard 
13617c926492SMaxime Ripard 		ret = of_property_read_u32_index(node, "input-debounce",
13627c926492SMaxime Ripard 						 i, &debounce);
13637c926492SMaxime Ripard 		if (ret)
13647c926492SMaxime Ripard 			return ret;
13657c926492SMaxime Ripard 
13667c926492SMaxime Ripard 		if (!debounce)
13677c926492SMaxime Ripard 			continue;
13687c926492SMaxime Ripard 
13697c926492SMaxime Ripard 		debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
13707c926492SMaxime Ripard 		losc_div = sunxi_pinctrl_get_debounce_div(losc,
13717c926492SMaxime Ripard 							  debounce_freq,
13727c926492SMaxime Ripard 							  &losc_diff);
13737c926492SMaxime Ripard 
13747c926492SMaxime Ripard 		hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
13757c926492SMaxime Ripard 							  debounce_freq,
13767c926492SMaxime Ripard 							  &hosc_diff);
13777c926492SMaxime Ripard 
13787c926492SMaxime Ripard 		if (hosc_diff < losc_diff) {
13797c926492SMaxime Ripard 			div = hosc_div;
13807c926492SMaxime Ripard 			src = 1;
13817c926492SMaxime Ripard 		} else {
13827c926492SMaxime Ripard 			div = losc_div;
13837c926492SMaxime Ripard 			src = 0;
13847c926492SMaxime Ripard 		}
13857c926492SMaxime Ripard 
13867c926492SMaxime Ripard 		writel(src | div << 4,
13877c926492SMaxime Ripard 		       pctl->membase +
13884b0d6c5aSIcenowy Zheng 		       sunxi_irq_debounce_reg_from_bank(pctl->desc, i));
13897c926492SMaxime Ripard 	}
13907c926492SMaxime Ripard 
13917c926492SMaxime Ripard 	return 0;
13927c926492SMaxime Ripard }
13937c926492SMaxime Ripard 
1394578db85fSMaxime Ripard int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
1395578db85fSMaxime Ripard 				    const struct sunxi_pinctrl_desc *desc,
1396578db85fSMaxime Ripard 				    unsigned long variant)
13970e37f88dSMaxime Ripard {
13980e37f88dSMaxime Ripard 	struct device_node *node = pdev->dev.of_node;
1399ba6764d5SMaxime Ripard 	struct pinctrl_desc *pctrl_desc;
14000e37f88dSMaxime Ripard 	struct pinctrl_pin_desc *pins;
14010e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl;
1402aae842a3SMaxime Ripard 	struct pinmux_ops *pmxops;
1403578db85fSMaxime Ripard 	int i, ret, last_pin, pin_idx;
1404950707c0SEmilio López 	struct clk *clk;
14050e37f88dSMaxime Ripard 
14060e37f88dSMaxime Ripard 	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
14070e37f88dSMaxime Ripard 	if (!pctl)
14080e37f88dSMaxime Ripard 		return -ENOMEM;
14090e37f88dSMaxime Ripard 	platform_set_drvdata(pdev, pctl);
14100e37f88dSMaxime Ripard 
1411f658ed36SJulia Cartwright 	raw_spin_lock_init(&pctl->lock);
14121bee963dSMaxime Ripard 
14134b024225SYueHaibing 	pctl->membase = devm_platform_ioremap_resource(pdev, 0);
14144409cafcSMaxime Ripard 	if (IS_ERR(pctl->membase))
14154409cafcSMaxime Ripard 		return PTR_ERR(pctl->membase);
14160e37f88dSMaxime Ripard 
1417ba6764d5SMaxime Ripard 	pctl->dev = &pdev->dev;
14182284ba6bSMaxime Ripard 	pctl->desc = desc;
1419578db85fSMaxime Ripard 	pctl->variant = variant;
14200e37f88dSMaxime Ripard 
1421aebdc8abSMaxime Ripard 	pctl->irq_array = devm_kcalloc(&pdev->dev,
1422aebdc8abSMaxime Ripard 				       IRQ_PER_BANK * pctl->desc->irq_banks,
1423aebdc8abSMaxime Ripard 				       sizeof(*pctl->irq_array),
1424aebdc8abSMaxime Ripard 				       GFP_KERNEL);
1425aebdc8abSMaxime Ripard 	if (!pctl->irq_array)
1426aebdc8abSMaxime Ripard 		return -ENOMEM;
1427aebdc8abSMaxime Ripard 
14280e37f88dSMaxime Ripard 	ret = sunxi_pinctrl_build_state(pdev);
14290e37f88dSMaxime Ripard 	if (ret) {
14300e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
14310e37f88dSMaxime Ripard 		return ret;
14320e37f88dSMaxime Ripard 	}
14330e37f88dSMaxime Ripard 
1434a86854d0SKees Cook 	pins = devm_kcalloc(&pdev->dev,
1435a86854d0SKees Cook 			    pctl->desc->npins, sizeof(*pins),
14360e37f88dSMaxime Ripard 			    GFP_KERNEL);
14370e37f88dSMaxime Ripard 	if (!pins)
14380e37f88dSMaxime Ripard 		return -ENOMEM;
14390e37f88dSMaxime Ripard 
1440578db85fSMaxime Ripard 	for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
1441578db85fSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
1442578db85fSMaxime Ripard 
1443578db85fSMaxime Ripard 		if (pin->variant && !(pctl->variant & pin->variant))
1444578db85fSMaxime Ripard 			continue;
1445578db85fSMaxime Ripard 
1446578db85fSMaxime Ripard 		pins[pin_idx++] = pin->pin;
1447578db85fSMaxime Ripard 	}
14480e37f88dSMaxime Ripard 
1449ba6764d5SMaxime Ripard 	pctrl_desc = devm_kzalloc(&pdev->dev,
1450ba6764d5SMaxime Ripard 				  sizeof(*pctrl_desc),
1451ba6764d5SMaxime Ripard 				  GFP_KERNEL);
1452ba6764d5SMaxime Ripard 	if (!pctrl_desc)
1453ba6764d5SMaxime Ripard 		return -ENOMEM;
1454ba6764d5SMaxime Ripard 
1455ba6764d5SMaxime Ripard 	pctrl_desc->name = dev_name(&pdev->dev);
1456ba6764d5SMaxime Ripard 	pctrl_desc->owner = THIS_MODULE;
1457ba6764d5SMaxime Ripard 	pctrl_desc->pins = pins;
1458578db85fSMaxime Ripard 	pctrl_desc->npins = pctl->ngroups;
1459ba6764d5SMaxime Ripard 	pctrl_desc->confops = &sunxi_pconf_ops;
1460ba6764d5SMaxime Ripard 	pctrl_desc->pctlops = &sunxi_pctrl_ops;
1461aae842a3SMaxime Ripard 
1462aae842a3SMaxime Ripard 	pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops),
1463aae842a3SMaxime Ripard 			      GFP_KERNEL);
1464aae842a3SMaxime Ripard 	if (!pmxops)
1465aae842a3SMaxime Ripard 		return -ENOMEM;
1466aae842a3SMaxime Ripard 
1467aae842a3SMaxime Ripard 	if (desc->disable_strict_mode)
1468aae842a3SMaxime Ripard 		pmxops->strict = false;
1469aae842a3SMaxime Ripard 
1470aae842a3SMaxime Ripard 	pctrl_desc->pmxops = pmxops;
1471ba6764d5SMaxime Ripard 
147245078ea0SLaxman Dewangan 	pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
1473323de9efSMasahiro Yamada 	if (IS_ERR(pctl->pctl_dev)) {
14740e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
1475323de9efSMasahiro Yamada 		return PTR_ERR(pctl->pctl_dev);
14760e37f88dSMaxime Ripard 	}
14770e37f88dSMaxime Ripard 
147808e9e614SMaxime Ripard 	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
147945078ea0SLaxman Dewangan 	if (!pctl->chip)
148045078ea0SLaxman Dewangan 		return -ENOMEM;
148108e9e614SMaxime Ripard 
148208e9e614SMaxime Ripard 	last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
1483d83c82ceSBoris BREZILLON 	pctl->chip->owner = THIS_MODULE;
1484fb7dea60SMaxime Ripard 	pctl->chip->request = gpiochip_generic_request;
1485fb7dea60SMaxime Ripard 	pctl->chip->free = gpiochip_generic_free;
148604ed8c0cSMaxime Ripard 	pctl->chip->set_config = gpiochip_generic_config;
1487fb7dea60SMaxime Ripard 	pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
1488fb7dea60SMaxime Ripard 	pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
1489fb7dea60SMaxime Ripard 	pctl->chip->get = sunxi_pinctrl_gpio_get;
1490fb7dea60SMaxime Ripard 	pctl->chip->set = sunxi_pinctrl_gpio_set;
1491fb7dea60SMaxime Ripard 	pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate;
1492fb7dea60SMaxime Ripard 	pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq;
1493fb7dea60SMaxime Ripard 	pctl->chip->of_gpio_n_cells = 3;
1494fb7dea60SMaxime Ripard 	pctl->chip->can_sleep = false;
1495d83c82ceSBoris BREZILLON 	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
1496d83c82ceSBoris BREZILLON 			    pctl->desc->pin_base;
149708e9e614SMaxime Ripard 	pctl->chip->label = dev_name(&pdev->dev);
149858383c78SLinus Walleij 	pctl->chip->parent = &pdev->dev;
1499d83c82ceSBoris BREZILLON 	pctl->chip->base = pctl->desc->pin_base;
150008e9e614SMaxime Ripard 
150188057d6eSLinus Walleij 	ret = gpiochip_add_data(pctl->chip, pctl);
150208e9e614SMaxime Ripard 	if (ret)
150345078ea0SLaxman Dewangan 		return ret;
150408e9e614SMaxime Ripard 
150508e9e614SMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
150608e9e614SMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
150708e9e614SMaxime Ripard 
150808e9e614SMaxime Ripard 		ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
1509343f1327SChen-Yu Tsai 					     pin->pin.number - pctl->desc->pin_base,
151008e9e614SMaxime Ripard 					     pin->pin.number, 1);
151108e9e614SMaxime Ripard 		if (ret)
151208e9e614SMaxime Ripard 			goto gpiochip_error;
151308e9e614SMaxime Ripard 	}
151408e9e614SMaxime Ripard 
151510e3a88bSGeert Uytterhoeven 	ret = of_clk_get_parent_count(node);
1516a34ea4b4SAndre Przywara 	clk = devm_clk_get(&pdev->dev, ret == 1 ? NULL : "apb");
1517d72f88a4SWei Yongjun 	if (IS_ERR(clk)) {
1518d72f88a4SWei Yongjun 		ret = PTR_ERR(clk);
1519950707c0SEmilio López 		goto gpiochip_error;
1520d72f88a4SWei Yongjun 	}
1521950707c0SEmilio López 
15226415093fSBoris BREZILLON 	ret = clk_prepare_enable(clk);
15236415093fSBoris BREZILLON 	if (ret)
15246415093fSBoris BREZILLON 		goto gpiochip_error;
1525950707c0SEmilio López 
1526aebdc8abSMaxime Ripard 	pctl->irq = devm_kcalloc(&pdev->dev,
1527aebdc8abSMaxime Ripard 				 pctl->desc->irq_banks,
1528aebdc8abSMaxime Ripard 				 sizeof(*pctl->irq),
1529aebdc8abSMaxime Ripard 				 GFP_KERNEL);
153060242db1SMaxime Ripard 	if (!pctl->irq) {
1531aebdc8abSMaxime Ripard 		ret = -ENOMEM;
1532dc969106SMaxime Ripard 		goto clk_error;
153360242db1SMaxime Ripard 	}
153460242db1SMaxime Ripard 
1535aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
1536aebdc8abSMaxime Ripard 		pctl->irq[i] = platform_get_irq(pdev, i);
1537aebdc8abSMaxime Ripard 		if (pctl->irq[i] < 0) {
1538aebdc8abSMaxime Ripard 			ret = pctl->irq[i];
1539aebdc8abSMaxime Ripard 			goto clk_error;
1540aebdc8abSMaxime Ripard 		}
1541aebdc8abSMaxime Ripard 	}
1542aebdc8abSMaxime Ripard 
1543aebdc8abSMaxime Ripard 	pctl->domain = irq_domain_add_linear(node,
1544aebdc8abSMaxime Ripard 					     pctl->desc->irq_banks * IRQ_PER_BANK,
1545d8323c6bSMaxime Ripard 					     &sunxi_pinctrl_irq_domain_ops,
1546d8323c6bSMaxime Ripard 					     pctl);
154760242db1SMaxime Ripard 	if (!pctl->domain) {
154860242db1SMaxime Ripard 		dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
154960242db1SMaxime Ripard 		ret = -ENOMEM;
1550dc969106SMaxime Ripard 		goto clk_error;
155160242db1SMaxime Ripard 	}
155260242db1SMaxime Ripard 
1553aebdc8abSMaxime Ripard 	for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
155460242db1SMaxime Ripard 		int irqno = irq_create_mapping(pctl->domain, i);
155560242db1SMaxime Ripard 
1556f4c51c10SHans de Goede 		irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
1557f4c51c10SHans de Goede 					 handle_edge_irq);
155860242db1SMaxime Ripard 		irq_set_chip_data(irqno, pctl);
15595c99c0ffSJavier Martinez Canillas 	}
156060242db1SMaxime Ripard 
1561aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
1562f4c51c10SHans de Goede 		/* Mask and clear all IRQs before registering a handler */
15634b0d6c5aSIcenowy Zheng 		writel(0, pctl->membase +
15644b0d6c5aSIcenowy Zheng 			  sunxi_irq_ctrl_reg_from_bank(pctl->desc, i));
1565f4c51c10SHans de Goede 		writel(0xffffffff,
15664b0d6c5aSIcenowy Zheng 		       pctl->membase +
15674b0d6c5aSIcenowy Zheng 		       sunxi_irq_status_reg_from_bank(pctl->desc, i));
1568f4c51c10SHans de Goede 
1569ef80e87dSThomas Gleixner 		irq_set_chained_handler_and_data(pctl->irq[i],
1570ef80e87dSThomas Gleixner 						 sunxi_pinctrl_irq_handler,
1571ef80e87dSThomas Gleixner 						 pctl);
1572aebdc8abSMaxime Ripard 	}
157360242db1SMaxime Ripard 
15747c926492SMaxime Ripard 	sunxi_pinctrl_setup_debounce(pctl, node);
15757c926492SMaxime Ripard 
157608e9e614SMaxime Ripard 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
15770e37f88dSMaxime Ripard 
15780e37f88dSMaxime Ripard 	return 0;
157908e9e614SMaxime Ripard 
1580e2bddc6aSBoris BREZILLON clk_error:
1581e2bddc6aSBoris BREZILLON 	clk_disable_unprepare(clk);
158208e9e614SMaxime Ripard gpiochip_error:
1583b4e7c55dSabdoulaye berthe 	gpiochip_remove(pctl->chip);
158408e9e614SMaxime Ripard 	return ret;
15850e37f88dSMaxime Ripard }
1586