xref: /linux/drivers/pinctrl/sunxi/pinctrl-sunxi.c (revision 5e7515ba78fff2f5407eaa2f97c1d5c07801ac3d)
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>
1660242db1SMaxime Ripard #include <linux/irqdomain.h>
17905a5117SChen-Yu Tsai #include <linux/irqchip/chained_irq.h>
18bcc76199SPaul Gortmaker #include <linux/export.h>
190e37f88dSMaxime Ripard #include <linux/of.h>
200e37f88dSMaxime Ripard #include <linux/of_address.h>
210e37f88dSMaxime Ripard #include <linux/of_device.h>
2260242db1SMaxime Ripard #include <linux/of_irq.h>
230e37f88dSMaxime Ripard #include <linux/pinctrl/consumer.h>
240e37f88dSMaxime Ripard #include <linux/pinctrl/machine.h>
250e37f88dSMaxime Ripard #include <linux/pinctrl/pinctrl.h>
260e37f88dSMaxime Ripard #include <linux/pinctrl/pinconf-generic.h>
270e37f88dSMaxime Ripard #include <linux/pinctrl/pinmux.h>
280e37f88dSMaxime Ripard #include <linux/platform_device.h>
290e37f88dSMaxime Ripard #include <linux/slab.h>
300e37f88dSMaxime Ripard 
315f910777SMaxime Ripard #include "../core.h"
32ef6d24ccSHans de Goede #include "../../gpio/gpiolib.h"
330e37f88dSMaxime Ripard #include "pinctrl-sunxi.h"
34eaa3d848SMaxime Ripard 
35f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip;
36f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip;
37f4c51c10SHans de Goede 
380e37f88dSMaxime Ripard static struct sunxi_pinctrl_group *
390e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
400e37f88dSMaxime Ripard {
410e37f88dSMaxime Ripard 	int i;
420e37f88dSMaxime Ripard 
430e37f88dSMaxime Ripard 	for (i = 0; i < pctl->ngroups; i++) {
440e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp = pctl->groups + i;
450e37f88dSMaxime Ripard 
460e37f88dSMaxime Ripard 		if (!strcmp(grp->name, group))
470e37f88dSMaxime Ripard 			return grp;
480e37f88dSMaxime Ripard 	}
490e37f88dSMaxime Ripard 
500e37f88dSMaxime Ripard 	return NULL;
510e37f88dSMaxime Ripard }
520e37f88dSMaxime Ripard 
530e37f88dSMaxime Ripard static struct sunxi_pinctrl_function *
540e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
550e37f88dSMaxime Ripard 				    const char *name)
560e37f88dSMaxime Ripard {
570e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
580e37f88dSMaxime Ripard 	int i;
590e37f88dSMaxime Ripard 
600e37f88dSMaxime Ripard 	for (i = 0; i < pctl->nfunctions; i++) {
610e37f88dSMaxime Ripard 		if (!func[i].name)
620e37f88dSMaxime Ripard 			break;
630e37f88dSMaxime Ripard 
640e37f88dSMaxime Ripard 		if (!strcmp(func[i].name, name))
650e37f88dSMaxime Ripard 			return func + i;
660e37f88dSMaxime Ripard 	}
670e37f88dSMaxime Ripard 
680e37f88dSMaxime Ripard 	return NULL;
690e37f88dSMaxime Ripard }
700e37f88dSMaxime Ripard 
710e37f88dSMaxime Ripard static struct sunxi_desc_function *
720e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
730e37f88dSMaxime Ripard 					 const char *pin_name,
740e37f88dSMaxime Ripard 					 const char *func_name)
750e37f88dSMaxime Ripard {
760e37f88dSMaxime Ripard 	int i;
770e37f88dSMaxime Ripard 
780e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
790e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
800e37f88dSMaxime Ripard 
810e37f88dSMaxime Ripard 		if (!strcmp(pin->pin.name, pin_name)) {
820e37f88dSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
830e37f88dSMaxime Ripard 
840e37f88dSMaxime Ripard 			while (func->name) {
850e37f88dSMaxime Ripard 				if (!strcmp(func->name, func_name))
860e37f88dSMaxime Ripard 					return func;
870e37f88dSMaxime Ripard 
880e37f88dSMaxime Ripard 				func++;
890e37f88dSMaxime Ripard 			}
900e37f88dSMaxime Ripard 		}
910e37f88dSMaxime Ripard 	}
920e37f88dSMaxime Ripard 
930e37f88dSMaxime Ripard 	return NULL;
940e37f88dSMaxime Ripard }
950e37f88dSMaxime Ripard 
96814d4f2eSMaxime Ripard static struct sunxi_desc_function *
97814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
98814d4f2eSMaxime Ripard 					const u16 pin_num,
99814d4f2eSMaxime Ripard 					const char *func_name)
100814d4f2eSMaxime Ripard {
101814d4f2eSMaxime Ripard 	int i;
102814d4f2eSMaxime Ripard 
103814d4f2eSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
104814d4f2eSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
105814d4f2eSMaxime Ripard 
106814d4f2eSMaxime Ripard 		if (pin->pin.number == pin_num) {
107814d4f2eSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
108814d4f2eSMaxime Ripard 
109814d4f2eSMaxime Ripard 			while (func->name) {
110814d4f2eSMaxime Ripard 				if (!strcmp(func->name, func_name))
111814d4f2eSMaxime Ripard 					return func;
112814d4f2eSMaxime Ripard 
113814d4f2eSMaxime Ripard 				func++;
114814d4f2eSMaxime Ripard 			}
115814d4f2eSMaxime Ripard 		}
116814d4f2eSMaxime Ripard 	}
117814d4f2eSMaxime Ripard 
118814d4f2eSMaxime Ripard 	return NULL;
119814d4f2eSMaxime Ripard }
120814d4f2eSMaxime Ripard 
1210e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
1220e37f88dSMaxime Ripard {
1230e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1240e37f88dSMaxime Ripard 
1250e37f88dSMaxime Ripard 	return pctl->ngroups;
1260e37f88dSMaxime Ripard }
1270e37f88dSMaxime Ripard 
1280e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
1290e37f88dSMaxime Ripard 					      unsigned group)
1300e37f88dSMaxime Ripard {
1310e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1320e37f88dSMaxime Ripard 
1330e37f88dSMaxime Ripard 	return pctl->groups[group].name;
1340e37f88dSMaxime Ripard }
1350e37f88dSMaxime Ripard 
1360e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
1370e37f88dSMaxime Ripard 				      unsigned group,
1380e37f88dSMaxime Ripard 				      const unsigned **pins,
1390e37f88dSMaxime Ripard 				      unsigned *num_pins)
1400e37f88dSMaxime Ripard {
1410e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1420e37f88dSMaxime Ripard 
1430e37f88dSMaxime Ripard 	*pins = (unsigned *)&pctl->groups[group].pin;
1440e37f88dSMaxime Ripard 	*num_pins = 1;
1450e37f88dSMaxime Ripard 
1460e37f88dSMaxime Ripard 	return 0;
1470e37f88dSMaxime Ripard }
1480e37f88dSMaxime Ripard 
1490e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
1500e37f88dSMaxime Ripard 				      struct device_node *node,
1510e37f88dSMaxime Ripard 				      struct pinctrl_map **map,
1520e37f88dSMaxime Ripard 				      unsigned *num_maps)
1530e37f88dSMaxime Ripard {
1540e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1550e37f88dSMaxime Ripard 	unsigned long *pinconfig;
1560e37f88dSMaxime Ripard 	struct property *prop;
1570e37f88dSMaxime Ripard 	const char *function;
1580e37f88dSMaxime Ripard 	const char *group;
1590e37f88dSMaxime Ripard 	int ret, nmaps, i = 0;
1600e37f88dSMaxime Ripard 	u32 val;
1610e37f88dSMaxime Ripard 
1620e37f88dSMaxime Ripard 	*map = NULL;
1630e37f88dSMaxime Ripard 	*num_maps = 0;
1640e37f88dSMaxime Ripard 
1650e37f88dSMaxime Ripard 	ret = of_property_read_string(node, "allwinner,function", &function);
1660e37f88dSMaxime Ripard 	if (ret) {
1670e37f88dSMaxime Ripard 		dev_err(pctl->dev,
1680e37f88dSMaxime Ripard 			"missing allwinner,function property in node %s\n",
1690e37f88dSMaxime Ripard 			node->name);
1700e37f88dSMaxime Ripard 		return -EINVAL;
1710e37f88dSMaxime Ripard 	}
1720e37f88dSMaxime Ripard 
1730e37f88dSMaxime Ripard 	nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
1740e37f88dSMaxime Ripard 	if (nmaps < 0) {
1750e37f88dSMaxime Ripard 		dev_err(pctl->dev,
1760e37f88dSMaxime Ripard 			"missing allwinner,pins property in node %s\n",
1770e37f88dSMaxime Ripard 			node->name);
1780e37f88dSMaxime Ripard 		return -EINVAL;
1790e37f88dSMaxime Ripard 	}
1800e37f88dSMaxime Ripard 
1810e37f88dSMaxime Ripard 	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
1823efa921dSSachin Kamat 	if (!*map)
1830e37f88dSMaxime Ripard 		return -ENOMEM;
1840e37f88dSMaxime Ripard 
1850e37f88dSMaxime Ripard 	of_property_for_each_string(node, "allwinner,pins", prop, group) {
1860e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp =
1870e37f88dSMaxime Ripard 			sunxi_pinctrl_find_group_by_name(pctl, group);
1880e37f88dSMaxime Ripard 		int j = 0, configlen = 0;
1890e37f88dSMaxime Ripard 
1900e37f88dSMaxime Ripard 		if (!grp) {
1910e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unknown pin %s", group);
1920e37f88dSMaxime Ripard 			continue;
1930e37f88dSMaxime Ripard 		}
1940e37f88dSMaxime Ripard 
1950e37f88dSMaxime Ripard 		if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
1960e37f88dSMaxime Ripard 							      grp->name,
1970e37f88dSMaxime Ripard 							      function)) {
1980e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unsupported function %s on pin %s",
1990e37f88dSMaxime Ripard 				function, group);
2000e37f88dSMaxime Ripard 			continue;
2010e37f88dSMaxime Ripard 		}
2020e37f88dSMaxime Ripard 
2030e37f88dSMaxime Ripard 		(*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
2040e37f88dSMaxime Ripard 		(*map)[i].data.mux.group = group;
2050e37f88dSMaxime Ripard 		(*map)[i].data.mux.function = function;
2060e37f88dSMaxime Ripard 
2070e37f88dSMaxime Ripard 		i++;
2080e37f88dSMaxime Ripard 
2090e37f88dSMaxime Ripard 		(*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
2100e37f88dSMaxime Ripard 		(*map)[i].data.configs.group_or_pin = group;
2110e37f88dSMaxime Ripard 
2120e37f88dSMaxime Ripard 		if (of_find_property(node, "allwinner,drive", NULL))
2130e37f88dSMaxime Ripard 			configlen++;
2140e37f88dSMaxime Ripard 		if (of_find_property(node, "allwinner,pull", NULL))
2150e37f88dSMaxime Ripard 			configlen++;
2160e37f88dSMaxime Ripard 
2170e37f88dSMaxime Ripard 		pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
218bd07894eSSachin Kamat 		if (!pinconfig) {
219bd07894eSSachin Kamat 			kfree(*map);
220bd07894eSSachin Kamat 			return -ENOMEM;
221bd07894eSSachin Kamat 		}
2220e37f88dSMaxime Ripard 
2230e37f88dSMaxime Ripard 		if (!of_property_read_u32(node, "allwinner,drive", &val)) {
2240e37f88dSMaxime Ripard 			u16 strength = (val + 1) * 10;
2250e37f88dSMaxime Ripard 			pinconfig[j++] =
2260e37f88dSMaxime Ripard 				pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
2270e37f88dSMaxime Ripard 							 strength);
2280e37f88dSMaxime Ripard 		}
2290e37f88dSMaxime Ripard 
2300e37f88dSMaxime Ripard 		if (!of_property_read_u32(node, "allwinner,pull", &val)) {
2310e37f88dSMaxime Ripard 			enum pin_config_param pull = PIN_CONFIG_END;
2320e37f88dSMaxime Ripard 			if (val == 1)
2330e37f88dSMaxime Ripard 				pull = PIN_CONFIG_BIAS_PULL_UP;
2340e37f88dSMaxime Ripard 			else if (val == 2)
2350e37f88dSMaxime Ripard 				pull = PIN_CONFIG_BIAS_PULL_DOWN;
2360e37f88dSMaxime Ripard 			pinconfig[j++] = pinconf_to_config_packed(pull, 0);
2370e37f88dSMaxime Ripard 		}
2380e37f88dSMaxime Ripard 
2390e37f88dSMaxime Ripard 		(*map)[i].data.configs.configs = pinconfig;
2400e37f88dSMaxime Ripard 		(*map)[i].data.configs.num_configs = configlen;
2410e37f88dSMaxime Ripard 
2420e37f88dSMaxime Ripard 		i++;
2430e37f88dSMaxime Ripard 	}
2440e37f88dSMaxime Ripard 
2450e37f88dSMaxime Ripard 	*num_maps = nmaps;
2460e37f88dSMaxime Ripard 
2470e37f88dSMaxime Ripard 	return 0;
2480e37f88dSMaxime Ripard }
2490e37f88dSMaxime Ripard 
2500e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
2510e37f88dSMaxime Ripard 				    struct pinctrl_map *map,
2520e37f88dSMaxime Ripard 				    unsigned num_maps)
2530e37f88dSMaxime Ripard {
2540e37f88dSMaxime Ripard 	int i;
2550e37f88dSMaxime Ripard 
2560e37f88dSMaxime Ripard 	for (i = 0; i < num_maps; i++) {
2570e37f88dSMaxime Ripard 		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
2580e37f88dSMaxime Ripard 			kfree(map[i].data.configs.configs);
2590e37f88dSMaxime Ripard 	}
2600e37f88dSMaxime Ripard 
2610e37f88dSMaxime Ripard 	kfree(map);
2620e37f88dSMaxime Ripard }
2630e37f88dSMaxime Ripard 
264022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = {
2650e37f88dSMaxime Ripard 	.dt_node_to_map		= sunxi_pctrl_dt_node_to_map,
2660e37f88dSMaxime Ripard 	.dt_free_map		= sunxi_pctrl_dt_free_map,
2670e37f88dSMaxime Ripard 	.get_groups_count	= sunxi_pctrl_get_groups_count,
2680e37f88dSMaxime Ripard 	.get_group_name		= sunxi_pctrl_get_group_name,
2690e37f88dSMaxime Ripard 	.get_group_pins		= sunxi_pctrl_get_group_pins,
2700e37f88dSMaxime Ripard };
2710e37f88dSMaxime Ripard 
2720e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
2730e37f88dSMaxime Ripard 				 unsigned group,
2740e37f88dSMaxime Ripard 				 unsigned long *config)
2750e37f88dSMaxime Ripard {
2760e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2770e37f88dSMaxime Ripard 
2780e37f88dSMaxime Ripard 	*config = pctl->groups[group].config;
2790e37f88dSMaxime Ripard 
2800e37f88dSMaxime Ripard 	return 0;
2810e37f88dSMaxime Ripard }
2820e37f88dSMaxime Ripard 
2830e37f88dSMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
2840e37f88dSMaxime Ripard 				 unsigned group,
28503b054e9SSherman Yin 				 unsigned long *configs,
28603b054e9SSherman Yin 				 unsigned num_configs)
2870e37f88dSMaxime Ripard {
2880e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2890e37f88dSMaxime Ripard 	struct sunxi_pinctrl_group *g = &pctl->groups[group];
2901bee963dSMaxime Ripard 	unsigned long flags;
291b4575c69SChen-Yu Tsai 	unsigned pin = g->pin - pctl->desc->pin_base;
2920e37f88dSMaxime Ripard 	u32 val, mask;
2930e37f88dSMaxime Ripard 	u16 strength;
2940e37f88dSMaxime Ripard 	u8 dlevel;
29503b054e9SSherman Yin 	int i;
2960e37f88dSMaxime Ripard 
2976ad30ce0SLinus Walleij 	spin_lock_irqsave(&pctl->lock, flags);
2986ad30ce0SLinus Walleij 
29903b054e9SSherman Yin 	for (i = 0; i < num_configs; i++) {
30003b054e9SSherman Yin 		switch (pinconf_to_config_param(configs[i])) {
3010e37f88dSMaxime Ripard 		case PIN_CONFIG_DRIVE_STRENGTH:
30203b054e9SSherman Yin 			strength = pinconf_to_config_argument(configs[i]);
30307b7eb92SLinus Walleij 			if (strength > 40) {
30407b7eb92SLinus Walleij 				spin_unlock_irqrestore(&pctl->lock, flags);
3050e37f88dSMaxime Ripard 				return -EINVAL;
30607b7eb92SLinus Walleij 			}
3070e37f88dSMaxime Ripard 			/*
3080e37f88dSMaxime Ripard 			 * We convert from mA to what the register expects:
3090e37f88dSMaxime Ripard 			 *   0: 10mA
3100e37f88dSMaxime Ripard 			 *   1: 20mA
3110e37f88dSMaxime Ripard 			 *   2: 30mA
3120e37f88dSMaxime Ripard 			 *   3: 40mA
3130e37f88dSMaxime Ripard 			 */
3140e37f88dSMaxime Ripard 			dlevel = strength / 10 - 1;
315b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_dlevel_reg(pin));
316b4575c69SChen-Yu Tsai 			mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
31703b054e9SSherman Yin 			writel((val & ~mask)
318b4575c69SChen-Yu Tsai 				| dlevel << sunxi_dlevel_offset(pin),
319b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_dlevel_reg(pin));
3200e37f88dSMaxime Ripard 			break;
3210e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_UP:
322b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_pull_reg(pin));
323b4575c69SChen-Yu Tsai 			mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
324b4575c69SChen-Yu Tsai 			writel((val & ~mask) | 1 << sunxi_pull_offset(pin),
325b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_pull_reg(pin));
3260e37f88dSMaxime Ripard 			break;
3270e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_DOWN:
328b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_pull_reg(pin));
329b4575c69SChen-Yu Tsai 			mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
330b4575c69SChen-Yu Tsai 			writel((val & ~mask) | 2 << sunxi_pull_offset(pin),
331b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_pull_reg(pin));
3320e37f88dSMaxime Ripard 			break;
3330e37f88dSMaxime Ripard 		default:
3340e37f88dSMaxime Ripard 			break;
3350e37f88dSMaxime Ripard 		}
3360e37f88dSMaxime Ripard 		/* cache the config value */
33703b054e9SSherman Yin 		g->config = configs[i];
33803b054e9SSherman Yin 	} /* for each config */
3390e37f88dSMaxime Ripard 
3406ad30ce0SLinus Walleij 	spin_unlock_irqrestore(&pctl->lock, flags);
3410e37f88dSMaxime Ripard 
3420e37f88dSMaxime Ripard 	return 0;
3430e37f88dSMaxime Ripard }
3440e37f88dSMaxime Ripard 
345022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = {
3460e37f88dSMaxime Ripard 	.pin_config_group_get	= sunxi_pconf_group_get,
3470e37f88dSMaxime Ripard 	.pin_config_group_set	= sunxi_pconf_group_set,
3480e37f88dSMaxime Ripard };
3490e37f88dSMaxime Ripard 
3500e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
3510e37f88dSMaxime Ripard {
3520e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3530e37f88dSMaxime Ripard 
3540e37f88dSMaxime Ripard 	return pctl->nfunctions;
3550e37f88dSMaxime Ripard }
3560e37f88dSMaxime Ripard 
3570e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
3580e37f88dSMaxime Ripard 					   unsigned function)
3590e37f88dSMaxime Ripard {
3600e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3610e37f88dSMaxime Ripard 
3620e37f88dSMaxime Ripard 	return pctl->functions[function].name;
3630e37f88dSMaxime Ripard }
3640e37f88dSMaxime Ripard 
3650e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
3660e37f88dSMaxime Ripard 				     unsigned function,
3670e37f88dSMaxime Ripard 				     const char * const **groups,
3680e37f88dSMaxime Ripard 				     unsigned * const num_groups)
3690e37f88dSMaxime Ripard {
3700e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3710e37f88dSMaxime Ripard 
3720e37f88dSMaxime Ripard 	*groups = pctl->functions[function].groups;
3730e37f88dSMaxime Ripard 	*num_groups = pctl->functions[function].ngroups;
3740e37f88dSMaxime Ripard 
3750e37f88dSMaxime Ripard 	return 0;
3760e37f88dSMaxime Ripard }
3770e37f88dSMaxime Ripard 
3780e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
3790e37f88dSMaxime Ripard 				 unsigned pin,
3800e37f88dSMaxime Ripard 				 u8 config)
3810e37f88dSMaxime Ripard {
3820e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3831bee963dSMaxime Ripard 	unsigned long flags;
3841bee963dSMaxime Ripard 	u32 val, mask;
3850e37f88dSMaxime Ripard 
3861bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
3871bee963dSMaxime Ripard 
388b4575c69SChen-Yu Tsai 	pin -= pctl->desc->pin_base;
3891bee963dSMaxime Ripard 	val = readl(pctl->membase + sunxi_mux_reg(pin));
3901bee963dSMaxime Ripard 	mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
3910e37f88dSMaxime Ripard 	writel((val & ~mask) | config << sunxi_mux_offset(pin),
3920e37f88dSMaxime Ripard 		pctl->membase + sunxi_mux_reg(pin));
3931bee963dSMaxime Ripard 
3941bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
3950e37f88dSMaxime Ripard }
3960e37f88dSMaxime Ripard 
39703e9f0caSLinus Walleij static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev,
3980e37f88dSMaxime Ripard 			     unsigned function,
3990e37f88dSMaxime Ripard 			     unsigned group)
4000e37f88dSMaxime Ripard {
4010e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
4020e37f88dSMaxime Ripard 	struct sunxi_pinctrl_group *g = pctl->groups + group;
4030e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions + function;
4040e37f88dSMaxime Ripard 	struct sunxi_desc_function *desc =
4050e37f88dSMaxime Ripard 		sunxi_pinctrl_desc_find_function_by_name(pctl,
4060e37f88dSMaxime Ripard 							 g->name,
4070e37f88dSMaxime Ripard 							 func->name);
4080e37f88dSMaxime Ripard 
4090e37f88dSMaxime Ripard 	if (!desc)
4100e37f88dSMaxime Ripard 		return -EINVAL;
4110e37f88dSMaxime Ripard 
4120e37f88dSMaxime Ripard 	sunxi_pmx_set(pctldev, g->pin, desc->muxval);
4130e37f88dSMaxime Ripard 
4140e37f88dSMaxime Ripard 	return 0;
4150e37f88dSMaxime Ripard }
4160e37f88dSMaxime Ripard 
41708e9e614SMaxime Ripard static int
41808e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
41908e9e614SMaxime Ripard 			struct pinctrl_gpio_range *range,
42008e9e614SMaxime Ripard 			unsigned offset,
42108e9e614SMaxime Ripard 			bool input)
42208e9e614SMaxime Ripard {
42308e9e614SMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
42408e9e614SMaxime Ripard 	struct sunxi_desc_function *desc;
42508e9e614SMaxime Ripard 	const char *func;
42608e9e614SMaxime Ripard 
42708e9e614SMaxime Ripard 	if (input)
42808e9e614SMaxime Ripard 		func = "gpio_in";
42908e9e614SMaxime Ripard 	else
43008e9e614SMaxime Ripard 		func = "gpio_out";
43108e9e614SMaxime Ripard 
432814d4f2eSMaxime Ripard 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func);
433814d4f2eSMaxime Ripard 	if (!desc)
434814d4f2eSMaxime Ripard 		return -EINVAL;
43508e9e614SMaxime Ripard 
43608e9e614SMaxime Ripard 	sunxi_pmx_set(pctldev, offset, desc->muxval);
43708e9e614SMaxime Ripard 
438814d4f2eSMaxime Ripard 	return 0;
43908e9e614SMaxime Ripard }
44008e9e614SMaxime Ripard 
441022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = {
4420e37f88dSMaxime Ripard 	.get_functions_count	= sunxi_pmx_get_funcs_cnt,
4430e37f88dSMaxime Ripard 	.get_function_name	= sunxi_pmx_get_func_name,
4440e37f88dSMaxime Ripard 	.get_function_groups	= sunxi_pmx_get_func_groups,
44503e9f0caSLinus Walleij 	.set_mux		= sunxi_pmx_set_mux,
44608e9e614SMaxime Ripard 	.gpio_set_direction	= sunxi_pmx_gpio_set_direction,
4470e37f88dSMaxime Ripard };
4480e37f88dSMaxime Ripard 
44908e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
45008e9e614SMaxime Ripard 					unsigned offset)
45108e9e614SMaxime Ripard {
45208e9e614SMaxime Ripard 	return pinctrl_gpio_direction_input(chip->base + offset);
45308e9e614SMaxime Ripard }
45408e9e614SMaxime Ripard 
45508e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
45608e9e614SMaxime Ripard {
45788057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
45808e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
45908e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
4606cee3821SLinus Walleij 	bool set_mux = pctl->desc->irq_read_needs_mux &&
4616cee3821SLinus Walleij 		gpiochip_line_is_irq(chip, offset);
462be2d107fSKrzysztof Adamski 	u32 pin = offset + chip->base;
463ef6d24ccSHans de Goede 	u32 val;
464ef6d24ccSHans de Goede 
465ef6d24ccSHans de Goede 	if (set_mux)
466be2d107fSKrzysztof Adamski 		sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
467ef6d24ccSHans de Goede 
468ef6d24ccSHans de Goede 	val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
469ef6d24ccSHans de Goede 
470ef6d24ccSHans de Goede 	if (set_mux)
471be2d107fSKrzysztof Adamski 		sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
47208e9e614SMaxime Ripard 
47339e24ac3SLinus Walleij 	return !!val;
47408e9e614SMaxime Ripard }
47508e9e614SMaxime Ripard 
47608e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
47708e9e614SMaxime Ripard 				unsigned offset, int value)
47808e9e614SMaxime Ripard {
47988057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
48008e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
48108e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
4821bee963dSMaxime Ripard 	unsigned long flags;
4831bee963dSMaxime Ripard 	u32 regval;
48408e9e614SMaxime Ripard 
4851bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
4861bee963dSMaxime Ripard 
4871bee963dSMaxime Ripard 	regval = readl(pctl->membase + reg);
48808e9e614SMaxime Ripard 
489df7b34f4SMaxime Ripard 	if (value)
490df7b34f4SMaxime Ripard 		regval |= BIT(index);
491df7b34f4SMaxime Ripard 	else
492df7b34f4SMaxime Ripard 		regval &= ~(BIT(index));
493df7b34f4SMaxime Ripard 
494df7b34f4SMaxime Ripard 	writel(regval, pctl->membase + reg);
4951bee963dSMaxime Ripard 
4961bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
49708e9e614SMaxime Ripard }
49808e9e614SMaxime Ripard 
499fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
500fa8cf57cSChen-Yu Tsai 					unsigned offset, int value)
501fa8cf57cSChen-Yu Tsai {
502fa8cf57cSChen-Yu Tsai 	sunxi_pinctrl_gpio_set(chip, offset, value);
503fa8cf57cSChen-Yu Tsai 	return pinctrl_gpio_direction_output(chip->base + offset);
504fa8cf57cSChen-Yu Tsai }
505fa8cf57cSChen-Yu Tsai 
506a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
507a0d72094SMaxime Ripard 				const struct of_phandle_args *gpiospec,
508a0d72094SMaxime Ripard 				u32 *flags)
509a0d72094SMaxime Ripard {
510a0d72094SMaxime Ripard 	int pin, base;
511a0d72094SMaxime Ripard 
512a0d72094SMaxime Ripard 	base = PINS_PER_BANK * gpiospec->args[0];
513a0d72094SMaxime Ripard 	pin = base + gpiospec->args[1];
514a0d72094SMaxime Ripard 
515343f1327SChen-Yu Tsai 	if (pin > gc->ngpio)
516a0d72094SMaxime Ripard 		return -EINVAL;
517a0d72094SMaxime Ripard 
518a0d72094SMaxime Ripard 	if (flags)
519a0d72094SMaxime Ripard 		*flags = gpiospec->args[2];
520a0d72094SMaxime Ripard 
521a0d72094SMaxime Ripard 	return pin;
522a0d72094SMaxime Ripard }
523a0d72094SMaxime Ripard 
52460242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
52560242db1SMaxime Ripard {
52688057d6eSLinus Walleij 	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
52760242db1SMaxime Ripard 	struct sunxi_desc_function *desc;
528343f1327SChen-Yu Tsai 	unsigned pinnum = pctl->desc->pin_base + offset;
5290d3bafacSChen-Yu Tsai 	unsigned irqnum;
53060242db1SMaxime Ripard 
531c9e3b2d8SAxel Lin 	if (offset >= chip->ngpio)
53260242db1SMaxime Ripard 		return -ENXIO;
53360242db1SMaxime Ripard 
534343f1327SChen-Yu Tsai 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq");
53560242db1SMaxime Ripard 	if (!desc)
53660242db1SMaxime Ripard 		return -EINVAL;
53760242db1SMaxime Ripard 
5380d3bafacSChen-Yu Tsai 	irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
53960242db1SMaxime Ripard 
54058383c78SLinus Walleij 	dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n",
5410d3bafacSChen-Yu Tsai 		chip->label, offset + chip->base, irqnum);
5420d3bafacSChen-Yu Tsai 
5430d3bafacSChen-Yu Tsai 	return irq_find_mapping(pctl->domain, irqnum);
54460242db1SMaxime Ripard }
54560242db1SMaxime Ripard 
546fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
54760242db1SMaxime Ripard {
54860242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
549fea6d8efSHans de Goede 	struct sunxi_desc_function *func;
550f83549d6SChen-Yu Tsai 	int ret;
551fea6d8efSHans de Goede 
552fea6d8efSHans de Goede 	func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
553fea6d8efSHans de Goede 					pctl->irq_array[d->hwirq], "irq");
554fea6d8efSHans de Goede 	if (!func)
555fea6d8efSHans de Goede 		return -EINVAL;
556fea6d8efSHans de Goede 
557e3a2e878SAlexandre Courbot 	ret = gpiochip_lock_as_irq(pctl->chip,
558343f1327SChen-Yu Tsai 			pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
559f83549d6SChen-Yu Tsai 	if (ret) {
560f83549d6SChen-Yu Tsai 		dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
561f83549d6SChen-Yu Tsai 			irqd_to_hwirq(d));
562f83549d6SChen-Yu Tsai 		return ret;
563f83549d6SChen-Yu Tsai 	}
564f83549d6SChen-Yu Tsai 
565fea6d8efSHans de Goede 	/* Change muxing to INT mode */
566fea6d8efSHans de Goede 	sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
567fea6d8efSHans de Goede 
568fea6d8efSHans de Goede 	return 0;
569fea6d8efSHans de Goede }
57008e9e614SMaxime Ripard 
571f83549d6SChen-Yu Tsai static void sunxi_pinctrl_irq_release_resources(struct irq_data *d)
572f83549d6SChen-Yu Tsai {
573f83549d6SChen-Yu Tsai 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
574f83549d6SChen-Yu Tsai 
575e3a2e878SAlexandre Courbot 	gpiochip_unlock_as_irq(pctl->chip,
576343f1327SChen-Yu Tsai 			      pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
577f83549d6SChen-Yu Tsai }
578f83549d6SChen-Yu Tsai 
579f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
58060242db1SMaxime Ripard {
58160242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
582*5e7515baSHans de Goede 	u32 reg = sunxi_irq_cfg_reg(d->hwirq, pctl->desc->irq_bank_base);
58360242db1SMaxime Ripard 	u8 index = sunxi_irq_cfg_offset(d->hwirq);
5841bee963dSMaxime Ripard 	unsigned long flags;
5852aaaddffSMaxime Ripard 	u32 regval;
58660242db1SMaxime Ripard 	u8 mode;
58760242db1SMaxime Ripard 
58860242db1SMaxime Ripard 	switch (type) {
58960242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_RISING:
59060242db1SMaxime Ripard 		mode = IRQ_EDGE_RISING;
59160242db1SMaxime Ripard 		break;
59260242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_FALLING:
59360242db1SMaxime Ripard 		mode = IRQ_EDGE_FALLING;
59460242db1SMaxime Ripard 		break;
59560242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_BOTH:
59660242db1SMaxime Ripard 		mode = IRQ_EDGE_BOTH;
59760242db1SMaxime Ripard 		break;
59860242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_HIGH:
59960242db1SMaxime Ripard 		mode = IRQ_LEVEL_HIGH;
60060242db1SMaxime Ripard 		break;
60160242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_LOW:
60260242db1SMaxime Ripard 		mode = IRQ_LEVEL_LOW;
60360242db1SMaxime Ripard 		break;
60460242db1SMaxime Ripard 	default:
60560242db1SMaxime Ripard 		return -EINVAL;
60660242db1SMaxime Ripard 	}
60760242db1SMaxime Ripard 
6081bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
6091bee963dSMaxime Ripard 
610a0d6de9bSMaxime Ripard 	if (type & IRQ_TYPE_LEVEL_MASK)
611b9a5ec33SThomas Gleixner 		irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip,
612a0d6de9bSMaxime Ripard 						 handle_fasteoi_irq, NULL);
613a0d6de9bSMaxime Ripard 	else
614b9a5ec33SThomas Gleixner 		irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip,
615a0d6de9bSMaxime Ripard 						 handle_edge_irq, NULL);
616a0d6de9bSMaxime Ripard 
6172aaaddffSMaxime Ripard 	regval = readl(pctl->membase + reg);
618d82f9401SHans de Goede 	regval &= ~(IRQ_CFG_IRQ_MASK << index);
6192aaaddffSMaxime Ripard 	writel(regval | (mode << index), pctl->membase + reg);
62060242db1SMaxime Ripard 
6211bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
62260242db1SMaxime Ripard 
62360242db1SMaxime Ripard 	return 0;
62460242db1SMaxime Ripard }
62560242db1SMaxime Ripard 
626645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d)
62760242db1SMaxime Ripard {
62860242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
629*5e7515baSHans de Goede 	u32 status_reg = sunxi_irq_status_reg(d->hwirq,
630*5e7515baSHans de Goede 					      pctl->desc->irq_bank_base);
63160242db1SMaxime Ripard 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
63260242db1SMaxime Ripard 
63360242db1SMaxime Ripard 	/* Clear the IRQ */
63460242db1SMaxime Ripard 	writel(1 << status_idx, pctl->membase + status_reg);
63560242db1SMaxime Ripard }
63660242db1SMaxime Ripard 
63760242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d)
63860242db1SMaxime Ripard {
63960242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
640*5e7515baSHans de Goede 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
64160242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
6421bee963dSMaxime Ripard 	unsigned long flags;
64360242db1SMaxime Ripard 	u32 val;
64460242db1SMaxime Ripard 
6451bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
6461bee963dSMaxime Ripard 
64760242db1SMaxime Ripard 	/* Mask the IRQ */
64860242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
64960242db1SMaxime Ripard 	writel(val & ~(1 << idx), pctl->membase + reg);
6501bee963dSMaxime Ripard 
6511bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
65260242db1SMaxime Ripard }
65360242db1SMaxime Ripard 
65460242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
65560242db1SMaxime Ripard {
65660242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
657*5e7515baSHans de Goede 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
65860242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
6591bee963dSMaxime Ripard 	unsigned long flags;
66060242db1SMaxime Ripard 	u32 val;
66160242db1SMaxime Ripard 
6621bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
6631bee963dSMaxime Ripard 
66460242db1SMaxime Ripard 	/* Unmask the IRQ */
66560242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
66660242db1SMaxime Ripard 	writel(val | (1 << idx), pctl->membase + reg);
6671bee963dSMaxime Ripard 
6681bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
66960242db1SMaxime Ripard }
67060242db1SMaxime Ripard 
671d61e23e5SHans de Goede static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d)
672d61e23e5SHans de Goede {
673d61e23e5SHans de Goede 	sunxi_pinctrl_irq_ack(d);
674d61e23e5SHans de Goede 	sunxi_pinctrl_irq_unmask(d);
675d61e23e5SHans de Goede }
676d61e23e5SHans de Goede 
677f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
678fb5b7788SMaxime Ripard 	.name		= "sunxi_pio_edge",
679645ec714SMaxime Ripard 	.irq_ack	= sunxi_pinctrl_irq_ack,
68060242db1SMaxime Ripard 	.irq_mask	= sunxi_pinctrl_irq_mask,
68160242db1SMaxime Ripard 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
682fea6d8efSHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
683f83549d6SChen-Yu Tsai 	.irq_release_resources = sunxi_pinctrl_irq_release_resources,
68460242db1SMaxime Ripard 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
685578c0a87SChen-Yu Tsai 	.flags		= IRQCHIP_SKIP_SET_WAKE,
68660242db1SMaxime Ripard };
68760242db1SMaxime Ripard 
688f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = {
689fb5b7788SMaxime Ripard 	.name		= "sunxi_pio_level",
690f4c51c10SHans de Goede 	.irq_eoi	= sunxi_pinctrl_irq_ack,
691f4c51c10SHans de Goede 	.irq_mask	= sunxi_pinctrl_irq_mask,
692f4c51c10SHans de Goede 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
693d61e23e5SHans de Goede 	/* Define irq_enable / disable to avoid spurious irqs for drivers
694d61e23e5SHans de Goede 	 * using these to suppress irqs while they clear the irq source */
695d61e23e5SHans de Goede 	.irq_enable	= sunxi_pinctrl_irq_ack_unmask,
696d61e23e5SHans de Goede 	.irq_disable	= sunxi_pinctrl_irq_mask,
697f4c51c10SHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
698f83549d6SChen-Yu Tsai 	.irq_release_resources = sunxi_pinctrl_irq_release_resources,
699f4c51c10SHans de Goede 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
700f4c51c10SHans de Goede 	.flags		= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
701f4c51c10SHans de Goede 			  IRQCHIP_EOI_IF_HANDLED,
70260242db1SMaxime Ripard };
70360242db1SMaxime Ripard 
704d8323c6bSMaxime Ripard static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d,
705d8323c6bSMaxime Ripard 				      struct device_node *node,
706d8323c6bSMaxime Ripard 				      const u32 *intspec,
707d8323c6bSMaxime Ripard 				      unsigned int intsize,
708d8323c6bSMaxime Ripard 				      unsigned long *out_hwirq,
709d8323c6bSMaxime Ripard 				      unsigned int *out_type)
710d8323c6bSMaxime Ripard {
7118297992cSHans de Goede 	struct sunxi_pinctrl *pctl = d->host_data;
712d8323c6bSMaxime Ripard 	struct sunxi_desc_function *desc;
713d8323c6bSMaxime Ripard 	int pin, base;
714d8323c6bSMaxime Ripard 
715d8323c6bSMaxime Ripard 	if (intsize < 3)
716d8323c6bSMaxime Ripard 		return -EINVAL;
717d8323c6bSMaxime Ripard 
718d8323c6bSMaxime Ripard 	base = PINS_PER_BANK * intspec[0];
7198297992cSHans de Goede 	pin = pctl->desc->pin_base + base + intspec[1];
720d8323c6bSMaxime Ripard 
7218297992cSHans de Goede 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq");
722d8323c6bSMaxime Ripard 	if (!desc)
723d8323c6bSMaxime Ripard 		return -EINVAL;
724d8323c6bSMaxime Ripard 
725d8323c6bSMaxime Ripard 	*out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum;
726d8323c6bSMaxime Ripard 	*out_type = intspec[2];
727d8323c6bSMaxime Ripard 
728d8323c6bSMaxime Ripard 	return 0;
729d8323c6bSMaxime Ripard }
730d8323c6bSMaxime Ripard 
731d8323c6bSMaxime Ripard static struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = {
732d8323c6bSMaxime Ripard 	.xlate		= sunxi_pinctrl_irq_of_xlate,
733d8323c6bSMaxime Ripard };
734d8323c6bSMaxime Ripard 
735bd0b9ac4SThomas Gleixner static void sunxi_pinctrl_irq_handler(struct irq_desc *desc)
73660242db1SMaxime Ripard {
737eeef97b1SThomas Gleixner 	unsigned int irq = irq_desc_get_irq(desc);
7385663bb27SJiang Liu 	struct irq_chip *chip = irq_desc_get_chip(desc);
7395663bb27SJiang Liu 	struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc);
740aebdc8abSMaxime Ripard 	unsigned long bank, reg, val;
74160242db1SMaxime Ripard 
742aebdc8abSMaxime Ripard 	for (bank = 0; bank < pctl->desc->irq_banks; bank++)
743aebdc8abSMaxime Ripard 		if (irq == pctl->irq[bank])
744aebdc8abSMaxime Ripard 			break;
74560242db1SMaxime Ripard 
746aebdc8abSMaxime Ripard 	if (bank == pctl->desc->irq_banks)
747aebdc8abSMaxime Ripard 		return;
748aebdc8abSMaxime Ripard 
749*5e7515baSHans de Goede 	reg = sunxi_irq_status_reg_from_bank(bank, pctl->desc->irq_bank_base);
750aebdc8abSMaxime Ripard 	val = readl(pctl->membase + reg);
75160242db1SMaxime Ripard 
752aebdc8abSMaxime Ripard 	if (val) {
75360242db1SMaxime Ripard 		int irqoffset;
75460242db1SMaxime Ripard 
755905a5117SChen-Yu Tsai 		chained_irq_enter(chip, desc);
756aebdc8abSMaxime Ripard 		for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) {
757aebdc8abSMaxime Ripard 			int pin_irq = irq_find_mapping(pctl->domain,
758aebdc8abSMaxime Ripard 						       bank * IRQ_PER_BANK + irqoffset);
75960242db1SMaxime Ripard 			generic_handle_irq(pin_irq);
76060242db1SMaxime Ripard 		}
761905a5117SChen-Yu Tsai 		chained_irq_exit(chip, desc);
76260242db1SMaxime Ripard 	}
76360242db1SMaxime Ripard }
76460242db1SMaxime Ripard 
7650e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
7660e37f88dSMaxime Ripard 					const char *name)
7670e37f88dSMaxime Ripard {
7680e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
7690e37f88dSMaxime Ripard 
7700e37f88dSMaxime Ripard 	while (func->name) {
7710e37f88dSMaxime Ripard 		/* function already there */
7720e37f88dSMaxime Ripard 		if (strcmp(func->name, name) == 0) {
7730e37f88dSMaxime Ripard 			func->ngroups++;
7740e37f88dSMaxime Ripard 			return -EEXIST;
7750e37f88dSMaxime Ripard 		}
7760e37f88dSMaxime Ripard 		func++;
7770e37f88dSMaxime Ripard 	}
7780e37f88dSMaxime Ripard 
7790e37f88dSMaxime Ripard 	func->name = name;
7800e37f88dSMaxime Ripard 	func->ngroups = 1;
7810e37f88dSMaxime Ripard 
7820e37f88dSMaxime Ripard 	pctl->nfunctions++;
7830e37f88dSMaxime Ripard 
7840e37f88dSMaxime Ripard 	return 0;
7850e37f88dSMaxime Ripard }
7860e37f88dSMaxime Ripard 
7870e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev)
7880e37f88dSMaxime Ripard {
7890e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
7900e37f88dSMaxime Ripard 	int i;
7910e37f88dSMaxime Ripard 
7920e37f88dSMaxime Ripard 	pctl->ngroups = pctl->desc->npins;
7930e37f88dSMaxime Ripard 
7940e37f88dSMaxime Ripard 	/* Allocate groups */
7950e37f88dSMaxime Ripard 	pctl->groups = devm_kzalloc(&pdev->dev,
7960e37f88dSMaxime Ripard 				    pctl->ngroups * sizeof(*pctl->groups),
7970e37f88dSMaxime Ripard 				    GFP_KERNEL);
7980e37f88dSMaxime Ripard 	if (!pctl->groups)
7990e37f88dSMaxime Ripard 		return -ENOMEM;
8000e37f88dSMaxime Ripard 
8010e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
8020e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
8030e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *group = pctl->groups + i;
8040e37f88dSMaxime Ripard 
8050e37f88dSMaxime Ripard 		group->name = pin->pin.name;
8060e37f88dSMaxime Ripard 		group->pin = pin->pin.number;
8070e37f88dSMaxime Ripard 	}
8080e37f88dSMaxime Ripard 
8090e37f88dSMaxime Ripard 	/*
8100e37f88dSMaxime Ripard 	 * We suppose that we won't have any more functions than pins,
8110e37f88dSMaxime Ripard 	 * we'll reallocate that later anyway
8120e37f88dSMaxime Ripard 	 */
8130e37f88dSMaxime Ripard 	pctl->functions = devm_kzalloc(&pdev->dev,
8140e37f88dSMaxime Ripard 				pctl->desc->npins * sizeof(*pctl->functions),
8150e37f88dSMaxime Ripard 				GFP_KERNEL);
8160e37f88dSMaxime Ripard 	if (!pctl->functions)
8170e37f88dSMaxime Ripard 		return -ENOMEM;
8180e37f88dSMaxime Ripard 
8190e37f88dSMaxime Ripard 	/* Count functions and their associated groups */
8200e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
8210e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
8220e37f88dSMaxime Ripard 		struct sunxi_desc_function *func = pin->functions;
8230e37f88dSMaxime Ripard 
8240e37f88dSMaxime Ripard 		while (func->name) {
825d54e9a28SChen-Yu Tsai 			/* Create interrupt mapping while we're at it */
826aebdc8abSMaxime Ripard 			if (!strcmp(func->name, "irq")) {
827aebdc8abSMaxime Ripard 				int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
828aebdc8abSMaxime Ripard 				pctl->irq_array[irqnum] = pin->pin.number;
829aebdc8abSMaxime Ripard 			}
830aebdc8abSMaxime Ripard 
8310e37f88dSMaxime Ripard 			sunxi_pinctrl_add_function(pctl, func->name);
8320e37f88dSMaxime Ripard 			func++;
8330e37f88dSMaxime Ripard 		}
8340e37f88dSMaxime Ripard 	}
8350e37f88dSMaxime Ripard 
8360e37f88dSMaxime Ripard 	pctl->functions = krealloc(pctl->functions,
8370e37f88dSMaxime Ripard 				pctl->nfunctions * sizeof(*pctl->functions),
8380e37f88dSMaxime Ripard 				GFP_KERNEL);
8390e37f88dSMaxime Ripard 
8400e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
8410e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
8420e37f88dSMaxime Ripard 		struct sunxi_desc_function *func = pin->functions;
8430e37f88dSMaxime Ripard 
8440e37f88dSMaxime Ripard 		while (func->name) {
8450e37f88dSMaxime Ripard 			struct sunxi_pinctrl_function *func_item;
8460e37f88dSMaxime Ripard 			const char **func_grp;
8470e37f88dSMaxime Ripard 
8480e37f88dSMaxime Ripard 			func_item = sunxi_pinctrl_find_function_by_name(pctl,
8490e37f88dSMaxime Ripard 									func->name);
8500e37f88dSMaxime Ripard 			if (!func_item)
8510e37f88dSMaxime Ripard 				return -EINVAL;
8520e37f88dSMaxime Ripard 
8530e37f88dSMaxime Ripard 			if (!func_item->groups) {
8540e37f88dSMaxime Ripard 				func_item->groups =
8550e37f88dSMaxime Ripard 					devm_kzalloc(&pdev->dev,
8560e37f88dSMaxime Ripard 						     func_item->ngroups * sizeof(*func_item->groups),
8570e37f88dSMaxime Ripard 						     GFP_KERNEL);
8580e37f88dSMaxime Ripard 				if (!func_item->groups)
8590e37f88dSMaxime Ripard 					return -ENOMEM;
8600e37f88dSMaxime Ripard 			}
8610e37f88dSMaxime Ripard 
8620e37f88dSMaxime Ripard 			func_grp = func_item->groups;
8630e37f88dSMaxime Ripard 			while (*func_grp)
8640e37f88dSMaxime Ripard 				func_grp++;
8650e37f88dSMaxime Ripard 
8660e37f88dSMaxime Ripard 			*func_grp = pin->pin.name;
8670e37f88dSMaxime Ripard 			func++;
8680e37f88dSMaxime Ripard 		}
8690e37f88dSMaxime Ripard 	}
8700e37f88dSMaxime Ripard 
8710e37f88dSMaxime Ripard 	return 0;
8720e37f88dSMaxime Ripard }
8730e37f88dSMaxime Ripard 
8742284ba6bSMaxime Ripard int sunxi_pinctrl_init(struct platform_device *pdev,
8752284ba6bSMaxime Ripard 		       const struct sunxi_pinctrl_desc *desc)
8760e37f88dSMaxime Ripard {
8770e37f88dSMaxime Ripard 	struct device_node *node = pdev->dev.of_node;
878ba6764d5SMaxime Ripard 	struct pinctrl_desc *pctrl_desc;
8790e37f88dSMaxime Ripard 	struct pinctrl_pin_desc *pins;
8800e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl;
8814409cafcSMaxime Ripard 	struct resource *res;
88208e9e614SMaxime Ripard 	int i, ret, last_pin;
883950707c0SEmilio López 	struct clk *clk;
8840e37f88dSMaxime Ripard 
8850e37f88dSMaxime Ripard 	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
8860e37f88dSMaxime Ripard 	if (!pctl)
8870e37f88dSMaxime Ripard 		return -ENOMEM;
8880e37f88dSMaxime Ripard 	platform_set_drvdata(pdev, pctl);
8890e37f88dSMaxime Ripard 
8901bee963dSMaxime Ripard 	spin_lock_init(&pctl->lock);
8911bee963dSMaxime Ripard 
8924409cafcSMaxime Ripard 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8934409cafcSMaxime Ripard 	pctl->membase = devm_ioremap_resource(&pdev->dev, res);
8944409cafcSMaxime Ripard 	if (IS_ERR(pctl->membase))
8954409cafcSMaxime Ripard 		return PTR_ERR(pctl->membase);
8960e37f88dSMaxime Ripard 
897ba6764d5SMaxime Ripard 	pctl->dev = &pdev->dev;
8982284ba6bSMaxime Ripard 	pctl->desc = desc;
8990e37f88dSMaxime Ripard 
900aebdc8abSMaxime Ripard 	pctl->irq_array = devm_kcalloc(&pdev->dev,
901aebdc8abSMaxime Ripard 				       IRQ_PER_BANK * pctl->desc->irq_banks,
902aebdc8abSMaxime Ripard 				       sizeof(*pctl->irq_array),
903aebdc8abSMaxime Ripard 				       GFP_KERNEL);
904aebdc8abSMaxime Ripard 	if (!pctl->irq_array)
905aebdc8abSMaxime Ripard 		return -ENOMEM;
906aebdc8abSMaxime Ripard 
9070e37f88dSMaxime Ripard 	ret = sunxi_pinctrl_build_state(pdev);
9080e37f88dSMaxime Ripard 	if (ret) {
9090e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
9100e37f88dSMaxime Ripard 		return ret;
9110e37f88dSMaxime Ripard 	}
9120e37f88dSMaxime Ripard 
9130e37f88dSMaxime Ripard 	pins = devm_kzalloc(&pdev->dev,
9140e37f88dSMaxime Ripard 			    pctl->desc->npins * sizeof(*pins),
9150e37f88dSMaxime Ripard 			    GFP_KERNEL);
9160e37f88dSMaxime Ripard 	if (!pins)
9170e37f88dSMaxime Ripard 		return -ENOMEM;
9180e37f88dSMaxime Ripard 
9190e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++)
9200e37f88dSMaxime Ripard 		pins[i] = pctl->desc->pins[i].pin;
9210e37f88dSMaxime Ripard 
922ba6764d5SMaxime Ripard 	pctrl_desc = devm_kzalloc(&pdev->dev,
923ba6764d5SMaxime Ripard 				  sizeof(*pctrl_desc),
924ba6764d5SMaxime Ripard 				  GFP_KERNEL);
925ba6764d5SMaxime Ripard 	if (!pctrl_desc)
926ba6764d5SMaxime Ripard 		return -ENOMEM;
927ba6764d5SMaxime Ripard 
928ba6764d5SMaxime Ripard 	pctrl_desc->name = dev_name(&pdev->dev);
929ba6764d5SMaxime Ripard 	pctrl_desc->owner = THIS_MODULE;
930ba6764d5SMaxime Ripard 	pctrl_desc->pins = pins;
931ba6764d5SMaxime Ripard 	pctrl_desc->npins = pctl->desc->npins;
932ba6764d5SMaxime Ripard 	pctrl_desc->confops = &sunxi_pconf_ops;
933ba6764d5SMaxime Ripard 	pctrl_desc->pctlops = &sunxi_pctrl_ops;
934ba6764d5SMaxime Ripard 	pctrl_desc->pmxops =  &sunxi_pmx_ops;
935ba6764d5SMaxime Ripard 
936ba6764d5SMaxime Ripard 	pctl->pctl_dev = pinctrl_register(pctrl_desc,
9370e37f88dSMaxime Ripard 					  &pdev->dev, pctl);
938323de9efSMasahiro Yamada 	if (IS_ERR(pctl->pctl_dev)) {
9390e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
940323de9efSMasahiro Yamada 		return PTR_ERR(pctl->pctl_dev);
9410e37f88dSMaxime Ripard 	}
9420e37f88dSMaxime Ripard 
94308e9e614SMaxime Ripard 	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
94408e9e614SMaxime Ripard 	if (!pctl->chip) {
94508e9e614SMaxime Ripard 		ret = -ENOMEM;
94608e9e614SMaxime Ripard 		goto pinctrl_error;
94708e9e614SMaxime Ripard 	}
94808e9e614SMaxime Ripard 
94908e9e614SMaxime Ripard 	last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
950d83c82ceSBoris BREZILLON 	pctl->chip->owner = THIS_MODULE;
95198c85d58SJonas Gorski 	pctl->chip->request = gpiochip_generic_request,
95298c85d58SJonas Gorski 	pctl->chip->free = gpiochip_generic_free,
953d83c82ceSBoris BREZILLON 	pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,
954d83c82ceSBoris BREZILLON 	pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,
955d83c82ceSBoris BREZILLON 	pctl->chip->get = sunxi_pinctrl_gpio_get,
956d83c82ceSBoris BREZILLON 	pctl->chip->set = sunxi_pinctrl_gpio_set,
957d83c82ceSBoris BREZILLON 	pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate,
958d83c82ceSBoris BREZILLON 	pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq,
959d83c82ceSBoris BREZILLON 	pctl->chip->of_gpio_n_cells = 3,
960d83c82ceSBoris BREZILLON 	pctl->chip->can_sleep = false,
961d83c82ceSBoris BREZILLON 	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
962d83c82ceSBoris BREZILLON 			    pctl->desc->pin_base;
96308e9e614SMaxime Ripard 	pctl->chip->label = dev_name(&pdev->dev);
96458383c78SLinus Walleij 	pctl->chip->parent = &pdev->dev;
965d83c82ceSBoris BREZILLON 	pctl->chip->base = pctl->desc->pin_base;
96608e9e614SMaxime Ripard 
96788057d6eSLinus Walleij 	ret = gpiochip_add_data(pctl->chip, pctl);
96808e9e614SMaxime Ripard 	if (ret)
96908e9e614SMaxime Ripard 		goto pinctrl_error;
97008e9e614SMaxime Ripard 
97108e9e614SMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
97208e9e614SMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
97308e9e614SMaxime Ripard 
97408e9e614SMaxime Ripard 		ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
975343f1327SChen-Yu Tsai 					     pin->pin.number - pctl->desc->pin_base,
97608e9e614SMaxime Ripard 					     pin->pin.number, 1);
97708e9e614SMaxime Ripard 		if (ret)
97808e9e614SMaxime Ripard 			goto gpiochip_error;
97908e9e614SMaxime Ripard 	}
98008e9e614SMaxime Ripard 
981950707c0SEmilio López 	clk = devm_clk_get(&pdev->dev, NULL);
982d72f88a4SWei Yongjun 	if (IS_ERR(clk)) {
983d72f88a4SWei Yongjun 		ret = PTR_ERR(clk);
984950707c0SEmilio López 		goto gpiochip_error;
985d72f88a4SWei Yongjun 	}
986950707c0SEmilio López 
9876415093fSBoris BREZILLON 	ret = clk_prepare_enable(clk);
9886415093fSBoris BREZILLON 	if (ret)
9896415093fSBoris BREZILLON 		goto gpiochip_error;
990950707c0SEmilio López 
991aebdc8abSMaxime Ripard 	pctl->irq = devm_kcalloc(&pdev->dev,
992aebdc8abSMaxime Ripard 				 pctl->desc->irq_banks,
993aebdc8abSMaxime Ripard 				 sizeof(*pctl->irq),
994aebdc8abSMaxime Ripard 				 GFP_KERNEL);
99560242db1SMaxime Ripard 	if (!pctl->irq) {
996aebdc8abSMaxime Ripard 		ret = -ENOMEM;
997dc969106SMaxime Ripard 		goto clk_error;
99860242db1SMaxime Ripard 	}
99960242db1SMaxime Ripard 
1000aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
1001aebdc8abSMaxime Ripard 		pctl->irq[i] = platform_get_irq(pdev, i);
1002aebdc8abSMaxime Ripard 		if (pctl->irq[i] < 0) {
1003aebdc8abSMaxime Ripard 			ret = pctl->irq[i];
1004aebdc8abSMaxime Ripard 			goto clk_error;
1005aebdc8abSMaxime Ripard 		}
1006aebdc8abSMaxime Ripard 	}
1007aebdc8abSMaxime Ripard 
1008aebdc8abSMaxime Ripard 	pctl->domain = irq_domain_add_linear(node,
1009aebdc8abSMaxime Ripard 					     pctl->desc->irq_banks * IRQ_PER_BANK,
1010d8323c6bSMaxime Ripard 					     &sunxi_pinctrl_irq_domain_ops,
1011d8323c6bSMaxime Ripard 					     pctl);
101260242db1SMaxime Ripard 	if (!pctl->domain) {
101360242db1SMaxime Ripard 		dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
101460242db1SMaxime Ripard 		ret = -ENOMEM;
1015dc969106SMaxime Ripard 		goto clk_error;
101660242db1SMaxime Ripard 	}
101760242db1SMaxime Ripard 
1018aebdc8abSMaxime Ripard 	for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
101960242db1SMaxime Ripard 		int irqno = irq_create_mapping(pctl->domain, i);
102060242db1SMaxime Ripard 
1021f4c51c10SHans de Goede 		irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
1022f4c51c10SHans de Goede 					 handle_edge_irq);
102360242db1SMaxime Ripard 		irq_set_chip_data(irqno, pctl);
10245c99c0ffSJavier Martinez Canillas 	}
102560242db1SMaxime Ripard 
1026aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
1027f4c51c10SHans de Goede 		/* Mask and clear all IRQs before registering a handler */
1028*5e7515baSHans de Goede 		writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i,
1029*5e7515baSHans de Goede 						pctl->desc->irq_bank_base));
1030f4c51c10SHans de Goede 		writel(0xffffffff,
1031*5e7515baSHans de Goede 		       pctl->membase + sunxi_irq_status_reg_from_bank(i,
1032*5e7515baSHans de Goede 						pctl->desc->irq_bank_base));
1033f4c51c10SHans de Goede 
1034ef80e87dSThomas Gleixner 		irq_set_chained_handler_and_data(pctl->irq[i],
1035ef80e87dSThomas Gleixner 						 sunxi_pinctrl_irq_handler,
1036ef80e87dSThomas Gleixner 						 pctl);
1037aebdc8abSMaxime Ripard 	}
103860242db1SMaxime Ripard 
103908e9e614SMaxime Ripard 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
10400e37f88dSMaxime Ripard 
10410e37f88dSMaxime Ripard 	return 0;
104208e9e614SMaxime Ripard 
1043e2bddc6aSBoris BREZILLON clk_error:
1044e2bddc6aSBoris BREZILLON 	clk_disable_unprepare(clk);
104508e9e614SMaxime Ripard gpiochip_error:
1046b4e7c55dSabdoulaye berthe 	gpiochip_remove(pctl->chip);
104708e9e614SMaxime Ripard pinctrl_error:
104808e9e614SMaxime Ripard 	pinctrl_unregister(pctl->pctl_dev);
104908e9e614SMaxime Ripard 	return ret;
10500e37f88dSMaxime Ripard }
1051