xref: /linux/drivers/pinctrl/sunxi/pinctrl-sunxi.c (revision f4c51c103b6a7373186dd6dc80759bc707bffdb4)
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>
1508e9e614SMaxime Ripard #include <linux/gpio.h>
1660242db1SMaxime Ripard #include <linux/irqdomain.h>
17905a5117SChen-Yu Tsai #include <linux/irqchip/chained_irq.h>
180e37f88dSMaxime Ripard #include <linux/module.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"
320e37f88dSMaxime Ripard #include "pinctrl-sunxi.h"
33eaa3d848SMaxime Ripard 
34*f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip;
35*f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip;
36*f4c51c10SHans de Goede 
370e37f88dSMaxime Ripard static struct sunxi_pinctrl_group *
380e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
390e37f88dSMaxime Ripard {
400e37f88dSMaxime Ripard 	int i;
410e37f88dSMaxime Ripard 
420e37f88dSMaxime Ripard 	for (i = 0; i < pctl->ngroups; i++) {
430e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp = pctl->groups + i;
440e37f88dSMaxime Ripard 
450e37f88dSMaxime Ripard 		if (!strcmp(grp->name, group))
460e37f88dSMaxime Ripard 			return grp;
470e37f88dSMaxime Ripard 	}
480e37f88dSMaxime Ripard 
490e37f88dSMaxime Ripard 	return NULL;
500e37f88dSMaxime Ripard }
510e37f88dSMaxime Ripard 
520e37f88dSMaxime Ripard static struct sunxi_pinctrl_function *
530e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
540e37f88dSMaxime Ripard 				    const char *name)
550e37f88dSMaxime Ripard {
560e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
570e37f88dSMaxime Ripard 	int i;
580e37f88dSMaxime Ripard 
590e37f88dSMaxime Ripard 	for (i = 0; i < pctl->nfunctions; i++) {
600e37f88dSMaxime Ripard 		if (!func[i].name)
610e37f88dSMaxime Ripard 			break;
620e37f88dSMaxime Ripard 
630e37f88dSMaxime Ripard 		if (!strcmp(func[i].name, name))
640e37f88dSMaxime Ripard 			return func + i;
650e37f88dSMaxime Ripard 	}
660e37f88dSMaxime Ripard 
670e37f88dSMaxime Ripard 	return NULL;
680e37f88dSMaxime Ripard }
690e37f88dSMaxime Ripard 
700e37f88dSMaxime Ripard static struct sunxi_desc_function *
710e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
720e37f88dSMaxime Ripard 					 const char *pin_name,
730e37f88dSMaxime Ripard 					 const char *func_name)
740e37f88dSMaxime Ripard {
750e37f88dSMaxime Ripard 	int i;
760e37f88dSMaxime Ripard 
770e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
780e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
790e37f88dSMaxime Ripard 
800e37f88dSMaxime Ripard 		if (!strcmp(pin->pin.name, pin_name)) {
810e37f88dSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
820e37f88dSMaxime Ripard 
830e37f88dSMaxime Ripard 			while (func->name) {
840e37f88dSMaxime Ripard 				if (!strcmp(func->name, func_name))
850e37f88dSMaxime Ripard 					return func;
860e37f88dSMaxime Ripard 
870e37f88dSMaxime Ripard 				func++;
880e37f88dSMaxime Ripard 			}
890e37f88dSMaxime Ripard 		}
900e37f88dSMaxime Ripard 	}
910e37f88dSMaxime Ripard 
920e37f88dSMaxime Ripard 	return NULL;
930e37f88dSMaxime Ripard }
940e37f88dSMaxime Ripard 
95814d4f2eSMaxime Ripard static struct sunxi_desc_function *
96814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
97814d4f2eSMaxime Ripard 					const u16 pin_num,
98814d4f2eSMaxime Ripard 					const char *func_name)
99814d4f2eSMaxime Ripard {
100814d4f2eSMaxime Ripard 	int i;
101814d4f2eSMaxime Ripard 
102814d4f2eSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
103814d4f2eSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
104814d4f2eSMaxime Ripard 
105814d4f2eSMaxime Ripard 		if (pin->pin.number == pin_num) {
106814d4f2eSMaxime Ripard 			struct sunxi_desc_function *func = pin->functions;
107814d4f2eSMaxime Ripard 
108814d4f2eSMaxime Ripard 			while (func->name) {
109814d4f2eSMaxime Ripard 				if (!strcmp(func->name, func_name))
110814d4f2eSMaxime Ripard 					return func;
111814d4f2eSMaxime Ripard 
112814d4f2eSMaxime Ripard 				func++;
113814d4f2eSMaxime Ripard 			}
114814d4f2eSMaxime Ripard 		}
115814d4f2eSMaxime Ripard 	}
116814d4f2eSMaxime Ripard 
117814d4f2eSMaxime Ripard 	return NULL;
118814d4f2eSMaxime Ripard }
119814d4f2eSMaxime Ripard 
1200e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
1210e37f88dSMaxime Ripard {
1220e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1230e37f88dSMaxime Ripard 
1240e37f88dSMaxime Ripard 	return pctl->ngroups;
1250e37f88dSMaxime Ripard }
1260e37f88dSMaxime Ripard 
1270e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
1280e37f88dSMaxime Ripard 					      unsigned group)
1290e37f88dSMaxime Ripard {
1300e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1310e37f88dSMaxime Ripard 
1320e37f88dSMaxime Ripard 	return pctl->groups[group].name;
1330e37f88dSMaxime Ripard }
1340e37f88dSMaxime Ripard 
1350e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
1360e37f88dSMaxime Ripard 				      unsigned group,
1370e37f88dSMaxime Ripard 				      const unsigned **pins,
1380e37f88dSMaxime Ripard 				      unsigned *num_pins)
1390e37f88dSMaxime Ripard {
1400e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1410e37f88dSMaxime Ripard 
1420e37f88dSMaxime Ripard 	*pins = (unsigned *)&pctl->groups[group].pin;
1430e37f88dSMaxime Ripard 	*num_pins = 1;
1440e37f88dSMaxime Ripard 
1450e37f88dSMaxime Ripard 	return 0;
1460e37f88dSMaxime Ripard }
1470e37f88dSMaxime Ripard 
1480e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
1490e37f88dSMaxime Ripard 				      struct device_node *node,
1500e37f88dSMaxime Ripard 				      struct pinctrl_map **map,
1510e37f88dSMaxime Ripard 				      unsigned *num_maps)
1520e37f88dSMaxime Ripard {
1530e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1540e37f88dSMaxime Ripard 	unsigned long *pinconfig;
1550e37f88dSMaxime Ripard 	struct property *prop;
1560e37f88dSMaxime Ripard 	const char *function;
1570e37f88dSMaxime Ripard 	const char *group;
1580e37f88dSMaxime Ripard 	int ret, nmaps, i = 0;
1590e37f88dSMaxime Ripard 	u32 val;
1600e37f88dSMaxime Ripard 
1610e37f88dSMaxime Ripard 	*map = NULL;
1620e37f88dSMaxime Ripard 	*num_maps = 0;
1630e37f88dSMaxime Ripard 
1640e37f88dSMaxime Ripard 	ret = of_property_read_string(node, "allwinner,function", &function);
1650e37f88dSMaxime Ripard 	if (ret) {
1660e37f88dSMaxime Ripard 		dev_err(pctl->dev,
1670e37f88dSMaxime Ripard 			"missing allwinner,function property in node %s\n",
1680e37f88dSMaxime Ripard 			node->name);
1690e37f88dSMaxime Ripard 		return -EINVAL;
1700e37f88dSMaxime Ripard 	}
1710e37f88dSMaxime Ripard 
1720e37f88dSMaxime Ripard 	nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
1730e37f88dSMaxime Ripard 	if (nmaps < 0) {
1740e37f88dSMaxime Ripard 		dev_err(pctl->dev,
1750e37f88dSMaxime Ripard 			"missing allwinner,pins property in node %s\n",
1760e37f88dSMaxime Ripard 			node->name);
1770e37f88dSMaxime Ripard 		return -EINVAL;
1780e37f88dSMaxime Ripard 	}
1790e37f88dSMaxime Ripard 
1800e37f88dSMaxime Ripard 	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
1813efa921dSSachin Kamat 	if (!*map)
1820e37f88dSMaxime Ripard 		return -ENOMEM;
1830e37f88dSMaxime Ripard 
1840e37f88dSMaxime Ripard 	of_property_for_each_string(node, "allwinner,pins", prop, group) {
1850e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *grp =
1860e37f88dSMaxime Ripard 			sunxi_pinctrl_find_group_by_name(pctl, group);
1870e37f88dSMaxime Ripard 		int j = 0, configlen = 0;
1880e37f88dSMaxime Ripard 
1890e37f88dSMaxime Ripard 		if (!grp) {
1900e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unknown pin %s", group);
1910e37f88dSMaxime Ripard 			continue;
1920e37f88dSMaxime Ripard 		}
1930e37f88dSMaxime Ripard 
1940e37f88dSMaxime Ripard 		if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
1950e37f88dSMaxime Ripard 							      grp->name,
1960e37f88dSMaxime Ripard 							      function)) {
1970e37f88dSMaxime Ripard 			dev_err(pctl->dev, "unsupported function %s on pin %s",
1980e37f88dSMaxime Ripard 				function, group);
1990e37f88dSMaxime Ripard 			continue;
2000e37f88dSMaxime Ripard 		}
2010e37f88dSMaxime Ripard 
2020e37f88dSMaxime Ripard 		(*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
2030e37f88dSMaxime Ripard 		(*map)[i].data.mux.group = group;
2040e37f88dSMaxime Ripard 		(*map)[i].data.mux.function = function;
2050e37f88dSMaxime Ripard 
2060e37f88dSMaxime Ripard 		i++;
2070e37f88dSMaxime Ripard 
2080e37f88dSMaxime Ripard 		(*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
2090e37f88dSMaxime Ripard 		(*map)[i].data.configs.group_or_pin = group;
2100e37f88dSMaxime Ripard 
2110e37f88dSMaxime Ripard 		if (of_find_property(node, "allwinner,drive", NULL))
2120e37f88dSMaxime Ripard 			configlen++;
2130e37f88dSMaxime Ripard 		if (of_find_property(node, "allwinner,pull", NULL))
2140e37f88dSMaxime Ripard 			configlen++;
2150e37f88dSMaxime Ripard 
2160e37f88dSMaxime Ripard 		pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
2170e37f88dSMaxime Ripard 
2180e37f88dSMaxime Ripard 		if (!of_property_read_u32(node, "allwinner,drive", &val)) {
2190e37f88dSMaxime Ripard 			u16 strength = (val + 1) * 10;
2200e37f88dSMaxime Ripard 			pinconfig[j++] =
2210e37f88dSMaxime Ripard 				pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
2220e37f88dSMaxime Ripard 							 strength);
2230e37f88dSMaxime Ripard 		}
2240e37f88dSMaxime Ripard 
2250e37f88dSMaxime Ripard 		if (!of_property_read_u32(node, "allwinner,pull", &val)) {
2260e37f88dSMaxime Ripard 			enum pin_config_param pull = PIN_CONFIG_END;
2270e37f88dSMaxime Ripard 			if (val == 1)
2280e37f88dSMaxime Ripard 				pull = PIN_CONFIG_BIAS_PULL_UP;
2290e37f88dSMaxime Ripard 			else if (val == 2)
2300e37f88dSMaxime Ripard 				pull = PIN_CONFIG_BIAS_PULL_DOWN;
2310e37f88dSMaxime Ripard 			pinconfig[j++] = pinconf_to_config_packed(pull, 0);
2320e37f88dSMaxime Ripard 		}
2330e37f88dSMaxime Ripard 
2340e37f88dSMaxime Ripard 		(*map)[i].data.configs.configs = pinconfig;
2350e37f88dSMaxime Ripard 		(*map)[i].data.configs.num_configs = configlen;
2360e37f88dSMaxime Ripard 
2370e37f88dSMaxime Ripard 		i++;
2380e37f88dSMaxime Ripard 	}
2390e37f88dSMaxime Ripard 
2400e37f88dSMaxime Ripard 	*num_maps = nmaps;
2410e37f88dSMaxime Ripard 
2420e37f88dSMaxime Ripard 	return 0;
2430e37f88dSMaxime Ripard }
2440e37f88dSMaxime Ripard 
2450e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
2460e37f88dSMaxime Ripard 				    struct pinctrl_map *map,
2470e37f88dSMaxime Ripard 				    unsigned num_maps)
2480e37f88dSMaxime Ripard {
2490e37f88dSMaxime Ripard 	int i;
2500e37f88dSMaxime Ripard 
2510e37f88dSMaxime Ripard 	for (i = 0; i < num_maps; i++) {
2520e37f88dSMaxime Ripard 		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
2530e37f88dSMaxime Ripard 			kfree(map[i].data.configs.configs);
2540e37f88dSMaxime Ripard 	}
2550e37f88dSMaxime Ripard 
2560e37f88dSMaxime Ripard 	kfree(map);
2570e37f88dSMaxime Ripard }
2580e37f88dSMaxime Ripard 
259022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = {
2600e37f88dSMaxime Ripard 	.dt_node_to_map		= sunxi_pctrl_dt_node_to_map,
2610e37f88dSMaxime Ripard 	.dt_free_map		= sunxi_pctrl_dt_free_map,
2620e37f88dSMaxime Ripard 	.get_groups_count	= sunxi_pctrl_get_groups_count,
2630e37f88dSMaxime Ripard 	.get_group_name		= sunxi_pctrl_get_group_name,
2640e37f88dSMaxime Ripard 	.get_group_pins		= sunxi_pctrl_get_group_pins,
2650e37f88dSMaxime Ripard };
2660e37f88dSMaxime Ripard 
2670e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
2680e37f88dSMaxime Ripard 				 unsigned group,
2690e37f88dSMaxime Ripard 				 unsigned long *config)
2700e37f88dSMaxime Ripard {
2710e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2720e37f88dSMaxime Ripard 
2730e37f88dSMaxime Ripard 	*config = pctl->groups[group].config;
2740e37f88dSMaxime Ripard 
2750e37f88dSMaxime Ripard 	return 0;
2760e37f88dSMaxime Ripard }
2770e37f88dSMaxime Ripard 
2780e37f88dSMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
2790e37f88dSMaxime Ripard 				 unsigned group,
28003b054e9SSherman Yin 				 unsigned long *configs,
28103b054e9SSherman Yin 				 unsigned num_configs)
2820e37f88dSMaxime Ripard {
2830e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2840e37f88dSMaxime Ripard 	struct sunxi_pinctrl_group *g = &pctl->groups[group];
2851bee963dSMaxime Ripard 	unsigned long flags;
286b4575c69SChen-Yu Tsai 	unsigned pin = g->pin - pctl->desc->pin_base;
2870e37f88dSMaxime Ripard 	u32 val, mask;
2880e37f88dSMaxime Ripard 	u16 strength;
2890e37f88dSMaxime Ripard 	u8 dlevel;
29003b054e9SSherman Yin 	int i;
2910e37f88dSMaxime Ripard 
2926ad30ce0SLinus Walleij 	spin_lock_irqsave(&pctl->lock, flags);
2936ad30ce0SLinus Walleij 
29403b054e9SSherman Yin 	for (i = 0; i < num_configs; i++) {
29503b054e9SSherman Yin 		switch (pinconf_to_config_param(configs[i])) {
2960e37f88dSMaxime Ripard 		case PIN_CONFIG_DRIVE_STRENGTH:
29703b054e9SSherman Yin 			strength = pinconf_to_config_argument(configs[i]);
29807b7eb92SLinus Walleij 			if (strength > 40) {
29907b7eb92SLinus Walleij 				spin_unlock_irqrestore(&pctl->lock, flags);
3000e37f88dSMaxime Ripard 				return -EINVAL;
30107b7eb92SLinus Walleij 			}
3020e37f88dSMaxime Ripard 			/*
3030e37f88dSMaxime Ripard 			 * We convert from mA to what the register expects:
3040e37f88dSMaxime Ripard 			 *   0: 10mA
3050e37f88dSMaxime Ripard 			 *   1: 20mA
3060e37f88dSMaxime Ripard 			 *   2: 30mA
3070e37f88dSMaxime Ripard 			 *   3: 40mA
3080e37f88dSMaxime Ripard 			 */
3090e37f88dSMaxime Ripard 			dlevel = strength / 10 - 1;
310b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_dlevel_reg(pin));
311b4575c69SChen-Yu Tsai 			mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
31203b054e9SSherman Yin 			writel((val & ~mask)
313b4575c69SChen-Yu Tsai 				| dlevel << sunxi_dlevel_offset(pin),
314b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_dlevel_reg(pin));
3150e37f88dSMaxime Ripard 			break;
3160e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_UP:
317b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_pull_reg(pin));
318b4575c69SChen-Yu Tsai 			mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
319b4575c69SChen-Yu Tsai 			writel((val & ~mask) | 1 << sunxi_pull_offset(pin),
320b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_pull_reg(pin));
3210e37f88dSMaxime Ripard 			break;
3220e37f88dSMaxime Ripard 		case PIN_CONFIG_BIAS_PULL_DOWN:
323b4575c69SChen-Yu Tsai 			val = readl(pctl->membase + sunxi_pull_reg(pin));
324b4575c69SChen-Yu Tsai 			mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
325b4575c69SChen-Yu Tsai 			writel((val & ~mask) | 2 << sunxi_pull_offset(pin),
326b4575c69SChen-Yu Tsai 				pctl->membase + sunxi_pull_reg(pin));
3270e37f88dSMaxime Ripard 			break;
3280e37f88dSMaxime Ripard 		default:
3290e37f88dSMaxime Ripard 			break;
3300e37f88dSMaxime Ripard 		}
3310e37f88dSMaxime Ripard 		/* cache the config value */
33203b054e9SSherman Yin 		g->config = configs[i];
33303b054e9SSherman Yin 	} /* for each config */
3340e37f88dSMaxime Ripard 
3356ad30ce0SLinus Walleij 	spin_unlock_irqrestore(&pctl->lock, flags);
3360e37f88dSMaxime Ripard 
3370e37f88dSMaxime Ripard 	return 0;
3380e37f88dSMaxime Ripard }
3390e37f88dSMaxime Ripard 
340022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = {
3410e37f88dSMaxime Ripard 	.pin_config_group_get	= sunxi_pconf_group_get,
3420e37f88dSMaxime Ripard 	.pin_config_group_set	= sunxi_pconf_group_set,
3430e37f88dSMaxime Ripard };
3440e37f88dSMaxime Ripard 
3450e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
3460e37f88dSMaxime Ripard {
3470e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3480e37f88dSMaxime Ripard 
3490e37f88dSMaxime Ripard 	return pctl->nfunctions;
3500e37f88dSMaxime Ripard }
3510e37f88dSMaxime Ripard 
3520e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
3530e37f88dSMaxime Ripard 					   unsigned function)
3540e37f88dSMaxime Ripard {
3550e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3560e37f88dSMaxime Ripard 
3570e37f88dSMaxime Ripard 	return pctl->functions[function].name;
3580e37f88dSMaxime Ripard }
3590e37f88dSMaxime Ripard 
3600e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
3610e37f88dSMaxime Ripard 				     unsigned function,
3620e37f88dSMaxime Ripard 				     const char * const **groups,
3630e37f88dSMaxime Ripard 				     unsigned * const num_groups)
3640e37f88dSMaxime Ripard {
3650e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3660e37f88dSMaxime Ripard 
3670e37f88dSMaxime Ripard 	*groups = pctl->functions[function].groups;
3680e37f88dSMaxime Ripard 	*num_groups = pctl->functions[function].ngroups;
3690e37f88dSMaxime Ripard 
3700e37f88dSMaxime Ripard 	return 0;
3710e37f88dSMaxime Ripard }
3720e37f88dSMaxime Ripard 
3730e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
3740e37f88dSMaxime Ripard 				 unsigned pin,
3750e37f88dSMaxime Ripard 				 u8 config)
3760e37f88dSMaxime Ripard {
3770e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3781bee963dSMaxime Ripard 	unsigned long flags;
3791bee963dSMaxime Ripard 	u32 val, mask;
3800e37f88dSMaxime Ripard 
3811bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
3821bee963dSMaxime Ripard 
383b4575c69SChen-Yu Tsai 	pin -= pctl->desc->pin_base;
3841bee963dSMaxime Ripard 	val = readl(pctl->membase + sunxi_mux_reg(pin));
3851bee963dSMaxime Ripard 	mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
3860e37f88dSMaxime Ripard 	writel((val & ~mask) | config << sunxi_mux_offset(pin),
3870e37f88dSMaxime Ripard 		pctl->membase + sunxi_mux_reg(pin));
3881bee963dSMaxime Ripard 
3891bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
3900e37f88dSMaxime Ripard }
3910e37f88dSMaxime Ripard 
3920e37f88dSMaxime Ripard static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
3930e37f88dSMaxime Ripard 			    unsigned function,
3940e37f88dSMaxime Ripard 			    unsigned group)
3950e37f88dSMaxime Ripard {
3960e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3970e37f88dSMaxime Ripard 	struct sunxi_pinctrl_group *g = pctl->groups + group;
3980e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions + function;
3990e37f88dSMaxime Ripard 	struct sunxi_desc_function *desc =
4000e37f88dSMaxime Ripard 		sunxi_pinctrl_desc_find_function_by_name(pctl,
4010e37f88dSMaxime Ripard 							 g->name,
4020e37f88dSMaxime Ripard 							 func->name);
4030e37f88dSMaxime Ripard 
4040e37f88dSMaxime Ripard 	if (!desc)
4050e37f88dSMaxime Ripard 		return -EINVAL;
4060e37f88dSMaxime Ripard 
4070e37f88dSMaxime Ripard 	sunxi_pmx_set(pctldev, g->pin, desc->muxval);
4080e37f88dSMaxime Ripard 
4090e37f88dSMaxime Ripard 	return 0;
4100e37f88dSMaxime Ripard }
4110e37f88dSMaxime Ripard 
41208e9e614SMaxime Ripard static int
41308e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
41408e9e614SMaxime Ripard 			struct pinctrl_gpio_range *range,
41508e9e614SMaxime Ripard 			unsigned offset,
41608e9e614SMaxime Ripard 			bool input)
41708e9e614SMaxime Ripard {
41808e9e614SMaxime Ripard 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
41908e9e614SMaxime Ripard 	struct sunxi_desc_function *desc;
42008e9e614SMaxime Ripard 	const char *func;
42108e9e614SMaxime Ripard 
42208e9e614SMaxime Ripard 	if (input)
42308e9e614SMaxime Ripard 		func = "gpio_in";
42408e9e614SMaxime Ripard 	else
42508e9e614SMaxime Ripard 		func = "gpio_out";
42608e9e614SMaxime Ripard 
427814d4f2eSMaxime Ripard 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func);
428814d4f2eSMaxime Ripard 	if (!desc)
429814d4f2eSMaxime Ripard 		return -EINVAL;
43008e9e614SMaxime Ripard 
43108e9e614SMaxime Ripard 	sunxi_pmx_set(pctldev, offset, desc->muxval);
43208e9e614SMaxime Ripard 
433814d4f2eSMaxime Ripard 	return 0;
43408e9e614SMaxime Ripard }
43508e9e614SMaxime Ripard 
436022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = {
4370e37f88dSMaxime Ripard 	.get_functions_count	= sunxi_pmx_get_funcs_cnt,
4380e37f88dSMaxime Ripard 	.get_function_name	= sunxi_pmx_get_func_name,
4390e37f88dSMaxime Ripard 	.get_function_groups	= sunxi_pmx_get_func_groups,
4400e37f88dSMaxime Ripard 	.enable			= sunxi_pmx_enable,
44108e9e614SMaxime Ripard 	.gpio_set_direction	= sunxi_pmx_gpio_set_direction,
4420e37f88dSMaxime Ripard };
4430e37f88dSMaxime Ripard 
44408e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_request(struct gpio_chip *chip, unsigned offset)
44508e9e614SMaxime Ripard {
44608e9e614SMaxime Ripard 	return pinctrl_request_gpio(chip->base + offset);
44708e9e614SMaxime Ripard }
44808e9e614SMaxime Ripard 
44908e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_free(struct gpio_chip *chip, unsigned offset)
45008e9e614SMaxime Ripard {
45108e9e614SMaxime Ripard 	pinctrl_free_gpio(chip->base + offset);
45208e9e614SMaxime Ripard }
45308e9e614SMaxime Ripard 
45408e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
45508e9e614SMaxime Ripard 					unsigned offset)
45608e9e614SMaxime Ripard {
45708e9e614SMaxime Ripard 	return pinctrl_gpio_direction_input(chip->base + offset);
45808e9e614SMaxime Ripard }
45908e9e614SMaxime Ripard 
46008e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
46108e9e614SMaxime Ripard {
46208e9e614SMaxime Ripard 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
46308e9e614SMaxime Ripard 
46408e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
46508e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
46608e9e614SMaxime Ripard 	u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
46708e9e614SMaxime Ripard 
46808e9e614SMaxime Ripard 	return val;
46908e9e614SMaxime Ripard }
47008e9e614SMaxime Ripard 
47108e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
47208e9e614SMaxime Ripard 				unsigned offset, int value)
47308e9e614SMaxime Ripard {
47408e9e614SMaxime Ripard 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
47508e9e614SMaxime Ripard 	u32 reg = sunxi_data_reg(offset);
47608e9e614SMaxime Ripard 	u8 index = sunxi_data_offset(offset);
4771bee963dSMaxime Ripard 	unsigned long flags;
4781bee963dSMaxime Ripard 	u32 regval;
47908e9e614SMaxime Ripard 
4801bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
4811bee963dSMaxime Ripard 
4821bee963dSMaxime Ripard 	regval = readl(pctl->membase + reg);
48308e9e614SMaxime Ripard 
484df7b34f4SMaxime Ripard 	if (value)
485df7b34f4SMaxime Ripard 		regval |= BIT(index);
486df7b34f4SMaxime Ripard 	else
487df7b34f4SMaxime Ripard 		regval &= ~(BIT(index));
488df7b34f4SMaxime Ripard 
489df7b34f4SMaxime Ripard 	writel(regval, pctl->membase + reg);
4901bee963dSMaxime Ripard 
4911bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
49208e9e614SMaxime Ripard }
49308e9e614SMaxime Ripard 
494fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
495fa8cf57cSChen-Yu Tsai 					unsigned offset, int value)
496fa8cf57cSChen-Yu Tsai {
497fa8cf57cSChen-Yu Tsai 	sunxi_pinctrl_gpio_set(chip, offset, value);
498fa8cf57cSChen-Yu Tsai 	return pinctrl_gpio_direction_output(chip->base + offset);
499fa8cf57cSChen-Yu Tsai }
500fa8cf57cSChen-Yu Tsai 
501a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
502a0d72094SMaxime Ripard 				const struct of_phandle_args *gpiospec,
503a0d72094SMaxime Ripard 				u32 *flags)
504a0d72094SMaxime Ripard {
505a0d72094SMaxime Ripard 	int pin, base;
506a0d72094SMaxime Ripard 
507a0d72094SMaxime Ripard 	base = PINS_PER_BANK * gpiospec->args[0];
508a0d72094SMaxime Ripard 	pin = base + gpiospec->args[1];
509a0d72094SMaxime Ripard 
510a0d72094SMaxime Ripard 	if (pin > (gc->base + gc->ngpio))
511a0d72094SMaxime Ripard 		return -EINVAL;
512a0d72094SMaxime Ripard 
513a0d72094SMaxime Ripard 	if (flags)
514a0d72094SMaxime Ripard 		*flags = gpiospec->args[2];
515a0d72094SMaxime Ripard 
516a0d72094SMaxime Ripard 	return pin;
517a0d72094SMaxime Ripard }
518a0d72094SMaxime Ripard 
51960242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
52060242db1SMaxime Ripard {
52160242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
52260242db1SMaxime Ripard 	struct sunxi_desc_function *desc;
52360242db1SMaxime Ripard 
524c9e3b2d8SAxel Lin 	if (offset >= chip->ngpio)
52560242db1SMaxime Ripard 		return -ENXIO;
52660242db1SMaxime Ripard 
52760242db1SMaxime Ripard 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
52860242db1SMaxime Ripard 	if (!desc)
52960242db1SMaxime Ripard 		return -EINVAL;
53060242db1SMaxime Ripard 
53160242db1SMaxime Ripard 	dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
53260242db1SMaxime Ripard 		chip->label, offset + chip->base, desc->irqnum);
53360242db1SMaxime Ripard 
53460242db1SMaxime Ripard 	return irq_find_mapping(pctl->domain, desc->irqnum);
53560242db1SMaxime Ripard }
53660242db1SMaxime Ripard 
537fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
538fea6d8efSHans de Goede {
539fea6d8efSHans de Goede 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
540fea6d8efSHans de Goede 	struct sunxi_desc_function *func;
541fea6d8efSHans de Goede 
542fea6d8efSHans de Goede 	func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
543fea6d8efSHans de Goede 					pctl->irq_array[d->hwirq], "irq");
544fea6d8efSHans de Goede 	if (!func)
545fea6d8efSHans de Goede 		return -EINVAL;
546fea6d8efSHans de Goede 
547fea6d8efSHans de Goede 	/* Change muxing to INT mode */
548fea6d8efSHans de Goede 	sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
549fea6d8efSHans de Goede 
550fea6d8efSHans de Goede 	return 0;
551fea6d8efSHans de Goede }
55208e9e614SMaxime Ripard 
553*f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
55460242db1SMaxime Ripard {
55560242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
556*f4c51c10SHans de Goede 	struct irq_desc *desc = container_of(d, struct irq_desc, irq_data);
55760242db1SMaxime Ripard 	u32 reg = sunxi_irq_cfg_reg(d->hwirq);
55860242db1SMaxime Ripard 	u8 index = sunxi_irq_cfg_offset(d->hwirq);
5591bee963dSMaxime Ripard 	unsigned long flags;
5602aaaddffSMaxime Ripard 	u32 regval;
56160242db1SMaxime Ripard 	u8 mode;
56260242db1SMaxime Ripard 
56360242db1SMaxime Ripard 	switch (type) {
56460242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_RISING:
56560242db1SMaxime Ripard 		mode = IRQ_EDGE_RISING;
56660242db1SMaxime Ripard 		break;
56760242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_FALLING:
56860242db1SMaxime Ripard 		mode = IRQ_EDGE_FALLING;
56960242db1SMaxime Ripard 		break;
57060242db1SMaxime Ripard 	case IRQ_TYPE_EDGE_BOTH:
57160242db1SMaxime Ripard 		mode = IRQ_EDGE_BOTH;
57260242db1SMaxime Ripard 		break;
57360242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_HIGH:
57460242db1SMaxime Ripard 		mode = IRQ_LEVEL_HIGH;
57560242db1SMaxime Ripard 		break;
57660242db1SMaxime Ripard 	case IRQ_TYPE_LEVEL_LOW:
57760242db1SMaxime Ripard 		mode = IRQ_LEVEL_LOW;
57860242db1SMaxime Ripard 		break;
57960242db1SMaxime Ripard 	default:
58060242db1SMaxime Ripard 		return -EINVAL;
58160242db1SMaxime Ripard 	}
58260242db1SMaxime Ripard 
583*f4c51c10SHans de Goede 	if (type & IRQ_TYPE_LEVEL_MASK) {
584*f4c51c10SHans de Goede 		d->chip = &sunxi_pinctrl_level_irq_chip;
585*f4c51c10SHans de Goede 		desc->handle_irq = handle_fasteoi_irq;
586*f4c51c10SHans de Goede 	} else {
587*f4c51c10SHans de Goede 		d->chip = &sunxi_pinctrl_edge_irq_chip;
588*f4c51c10SHans de Goede 		desc->handle_irq = handle_edge_irq;
589*f4c51c10SHans de Goede 	}
590*f4c51c10SHans de Goede 
5911bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
5921bee963dSMaxime Ripard 
5932aaaddffSMaxime Ripard 	regval = readl(pctl->membase + reg);
594d82f9401SHans de Goede 	regval &= ~(IRQ_CFG_IRQ_MASK << index);
5952aaaddffSMaxime Ripard 	writel(regval | (mode << index), pctl->membase + reg);
59660242db1SMaxime Ripard 
5971bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
59860242db1SMaxime Ripard 
59960242db1SMaxime Ripard 	return 0;
60060242db1SMaxime Ripard }
60160242db1SMaxime Ripard 
602645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d)
60360242db1SMaxime Ripard {
60460242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
60560242db1SMaxime Ripard 	u32 status_reg = sunxi_irq_status_reg(d->hwirq);
60660242db1SMaxime Ripard 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
60760242db1SMaxime Ripard 
60860242db1SMaxime Ripard 	/* Clear the IRQ */
60960242db1SMaxime Ripard 	writel(1 << status_idx, pctl->membase + status_reg);
61060242db1SMaxime Ripard }
61160242db1SMaxime Ripard 
61260242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d)
61360242db1SMaxime Ripard {
61460242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
61560242db1SMaxime Ripard 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
61660242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
6171bee963dSMaxime Ripard 	unsigned long flags;
61860242db1SMaxime Ripard 	u32 val;
61960242db1SMaxime Ripard 
6201bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
6211bee963dSMaxime Ripard 
62260242db1SMaxime Ripard 	/* Mask the IRQ */
62360242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
62460242db1SMaxime Ripard 	writel(val & ~(1 << idx), pctl->membase + reg);
6251bee963dSMaxime Ripard 
6261bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
62760242db1SMaxime Ripard }
62860242db1SMaxime Ripard 
62960242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
63060242db1SMaxime Ripard {
63160242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
63260242db1SMaxime Ripard 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
63360242db1SMaxime Ripard 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
6341bee963dSMaxime Ripard 	unsigned long flags;
63560242db1SMaxime Ripard 	u32 val;
63660242db1SMaxime Ripard 
6371bee963dSMaxime Ripard 	spin_lock_irqsave(&pctl->lock, flags);
6381bee963dSMaxime Ripard 
63960242db1SMaxime Ripard 	/* Unmask the IRQ */
64060242db1SMaxime Ripard 	val = readl(pctl->membase + reg);
64160242db1SMaxime Ripard 	writel(val | (1 << idx), pctl->membase + reg);
6421bee963dSMaxime Ripard 
6431bee963dSMaxime Ripard 	spin_unlock_irqrestore(&pctl->lock, flags);
64460242db1SMaxime Ripard }
64560242db1SMaxime Ripard 
646*f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
647645ec714SMaxime Ripard 	.irq_ack	= sunxi_pinctrl_irq_ack,
64860242db1SMaxime Ripard 	.irq_mask	= sunxi_pinctrl_irq_mask,
64960242db1SMaxime Ripard 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
650fea6d8efSHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
65160242db1SMaxime Ripard 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
652578c0a87SChen-Yu Tsai 	.flags		= IRQCHIP_SKIP_SET_WAKE,
65360242db1SMaxime Ripard };
65460242db1SMaxime Ripard 
655*f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = {
656*f4c51c10SHans de Goede 	.irq_eoi	= sunxi_pinctrl_irq_ack,
657*f4c51c10SHans de Goede 	.irq_mask	= sunxi_pinctrl_irq_mask,
658*f4c51c10SHans de Goede 	.irq_unmask	= sunxi_pinctrl_irq_unmask,
659*f4c51c10SHans de Goede 	.irq_request_resources = sunxi_pinctrl_irq_request_resources,
660*f4c51c10SHans de Goede 	.irq_set_type	= sunxi_pinctrl_irq_set_type,
661*f4c51c10SHans de Goede 	.flags		= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
662*f4c51c10SHans de Goede 			  IRQCHIP_EOI_IF_HANDLED,
663*f4c51c10SHans de Goede };
664*f4c51c10SHans de Goede 
66560242db1SMaxime Ripard static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
66660242db1SMaxime Ripard {
667905a5117SChen-Yu Tsai 	struct irq_chip *chip = irq_get_chip(irq);
66860242db1SMaxime Ripard 	struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
669aebdc8abSMaxime Ripard 	unsigned long bank, reg, val;
670aebdc8abSMaxime Ripard 
671aebdc8abSMaxime Ripard 	for (bank = 0; bank < pctl->desc->irq_banks; bank++)
672aebdc8abSMaxime Ripard 		if (irq == pctl->irq[bank])
673aebdc8abSMaxime Ripard 			break;
674aebdc8abSMaxime Ripard 
675aebdc8abSMaxime Ripard 	if (bank == pctl->desc->irq_banks)
676aebdc8abSMaxime Ripard 		return;
677aebdc8abSMaxime Ripard 
678aebdc8abSMaxime Ripard 	reg = sunxi_irq_status_reg_from_bank(bank);
679aebdc8abSMaxime Ripard 	val = readl(pctl->membase + reg);
68060242db1SMaxime Ripard 
681aebdc8abSMaxime Ripard 	if (val) {
68260242db1SMaxime Ripard 		int irqoffset;
68360242db1SMaxime Ripard 
684905a5117SChen-Yu Tsai 		chained_irq_enter(chip, desc);
685aebdc8abSMaxime Ripard 		for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) {
686aebdc8abSMaxime Ripard 			int pin_irq = irq_find_mapping(pctl->domain,
687aebdc8abSMaxime Ripard 						       bank * IRQ_PER_BANK + irqoffset);
68860242db1SMaxime Ripard 			generic_handle_irq(pin_irq);
68960242db1SMaxime Ripard 		}
690905a5117SChen-Yu Tsai 		chained_irq_exit(chip, desc);
69160242db1SMaxime Ripard 	}
69260242db1SMaxime Ripard }
69360242db1SMaxime Ripard 
6940e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
6950e37f88dSMaxime Ripard 					const char *name)
6960e37f88dSMaxime Ripard {
6970e37f88dSMaxime Ripard 	struct sunxi_pinctrl_function *func = pctl->functions;
6980e37f88dSMaxime Ripard 
6990e37f88dSMaxime Ripard 	while (func->name) {
7000e37f88dSMaxime Ripard 		/* function already there */
7010e37f88dSMaxime Ripard 		if (strcmp(func->name, name) == 0) {
7020e37f88dSMaxime Ripard 			func->ngroups++;
7030e37f88dSMaxime Ripard 			return -EEXIST;
7040e37f88dSMaxime Ripard 		}
7050e37f88dSMaxime Ripard 		func++;
7060e37f88dSMaxime Ripard 	}
7070e37f88dSMaxime Ripard 
7080e37f88dSMaxime Ripard 	func->name = name;
7090e37f88dSMaxime Ripard 	func->ngroups = 1;
7100e37f88dSMaxime Ripard 
7110e37f88dSMaxime Ripard 	pctl->nfunctions++;
7120e37f88dSMaxime Ripard 
7130e37f88dSMaxime Ripard 	return 0;
7140e37f88dSMaxime Ripard }
7150e37f88dSMaxime Ripard 
7160e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev)
7170e37f88dSMaxime Ripard {
7180e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
7190e37f88dSMaxime Ripard 	int i;
7200e37f88dSMaxime Ripard 
7210e37f88dSMaxime Ripard 	pctl->ngroups = pctl->desc->npins;
7220e37f88dSMaxime Ripard 
7230e37f88dSMaxime Ripard 	/* Allocate groups */
7240e37f88dSMaxime Ripard 	pctl->groups = devm_kzalloc(&pdev->dev,
7250e37f88dSMaxime Ripard 				    pctl->ngroups * sizeof(*pctl->groups),
7260e37f88dSMaxime Ripard 				    GFP_KERNEL);
7270e37f88dSMaxime Ripard 	if (!pctl->groups)
7280e37f88dSMaxime Ripard 		return -ENOMEM;
7290e37f88dSMaxime Ripard 
7300e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
7310e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
7320e37f88dSMaxime Ripard 		struct sunxi_pinctrl_group *group = pctl->groups + i;
7330e37f88dSMaxime Ripard 
7340e37f88dSMaxime Ripard 		group->name = pin->pin.name;
7350e37f88dSMaxime Ripard 		group->pin = pin->pin.number;
7360e37f88dSMaxime Ripard 	}
7370e37f88dSMaxime Ripard 
7380e37f88dSMaxime Ripard 	/*
7390e37f88dSMaxime Ripard 	 * We suppose that we won't have any more functions than pins,
7400e37f88dSMaxime Ripard 	 * we'll reallocate that later anyway
7410e37f88dSMaxime Ripard 	 */
7420e37f88dSMaxime Ripard 	pctl->functions = devm_kzalloc(&pdev->dev,
7430e37f88dSMaxime Ripard 				pctl->desc->npins * sizeof(*pctl->functions),
7440e37f88dSMaxime Ripard 				GFP_KERNEL);
7450e37f88dSMaxime Ripard 	if (!pctl->functions)
7460e37f88dSMaxime Ripard 		return -ENOMEM;
7470e37f88dSMaxime Ripard 
7480e37f88dSMaxime Ripard 	/* Count functions and their associated groups */
7490e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
7500e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
7510e37f88dSMaxime Ripard 		struct sunxi_desc_function *func = pin->functions;
7520e37f88dSMaxime Ripard 
7530e37f88dSMaxime Ripard 		while (func->name) {
754d54e9a28SChen-Yu Tsai 			/* Create interrupt mapping while we're at it */
755aebdc8abSMaxime Ripard 			if (!strcmp(func->name, "irq")) {
756aebdc8abSMaxime Ripard 				int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
757aebdc8abSMaxime Ripard 				pctl->irq_array[irqnum] = pin->pin.number;
758aebdc8abSMaxime Ripard 			}
759aebdc8abSMaxime Ripard 
7600e37f88dSMaxime Ripard 			sunxi_pinctrl_add_function(pctl, func->name);
7610e37f88dSMaxime Ripard 			func++;
7620e37f88dSMaxime Ripard 		}
7630e37f88dSMaxime Ripard 	}
7640e37f88dSMaxime Ripard 
7650e37f88dSMaxime Ripard 	pctl->functions = krealloc(pctl->functions,
7660e37f88dSMaxime Ripard 				pctl->nfunctions * sizeof(*pctl->functions),
7670e37f88dSMaxime Ripard 				GFP_KERNEL);
7680e37f88dSMaxime Ripard 
7690e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
7700e37f88dSMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
7710e37f88dSMaxime Ripard 		struct sunxi_desc_function *func = pin->functions;
7720e37f88dSMaxime Ripard 
7730e37f88dSMaxime Ripard 		while (func->name) {
7740e37f88dSMaxime Ripard 			struct sunxi_pinctrl_function *func_item;
7750e37f88dSMaxime Ripard 			const char **func_grp;
7760e37f88dSMaxime Ripard 
7770e37f88dSMaxime Ripard 			func_item = sunxi_pinctrl_find_function_by_name(pctl,
7780e37f88dSMaxime Ripard 									func->name);
7790e37f88dSMaxime Ripard 			if (!func_item)
7800e37f88dSMaxime Ripard 				return -EINVAL;
7810e37f88dSMaxime Ripard 
7820e37f88dSMaxime Ripard 			if (!func_item->groups) {
7830e37f88dSMaxime Ripard 				func_item->groups =
7840e37f88dSMaxime Ripard 					devm_kzalloc(&pdev->dev,
7850e37f88dSMaxime Ripard 						     func_item->ngroups * sizeof(*func_item->groups),
7860e37f88dSMaxime Ripard 						     GFP_KERNEL);
7870e37f88dSMaxime Ripard 				if (!func_item->groups)
7880e37f88dSMaxime Ripard 					return -ENOMEM;
7890e37f88dSMaxime Ripard 			}
7900e37f88dSMaxime Ripard 
7910e37f88dSMaxime Ripard 			func_grp = func_item->groups;
7920e37f88dSMaxime Ripard 			while (*func_grp)
7930e37f88dSMaxime Ripard 				func_grp++;
7940e37f88dSMaxime Ripard 
7950e37f88dSMaxime Ripard 			*func_grp = pin->pin.name;
7960e37f88dSMaxime Ripard 			func++;
7970e37f88dSMaxime Ripard 		}
7980e37f88dSMaxime Ripard 	}
7990e37f88dSMaxime Ripard 
8000e37f88dSMaxime Ripard 	return 0;
8010e37f88dSMaxime Ripard }
8020e37f88dSMaxime Ripard 
8032284ba6bSMaxime Ripard int sunxi_pinctrl_init(struct platform_device *pdev,
8042284ba6bSMaxime Ripard 		       const struct sunxi_pinctrl_desc *desc)
8050e37f88dSMaxime Ripard {
8060e37f88dSMaxime Ripard 	struct device_node *node = pdev->dev.of_node;
807ba6764d5SMaxime Ripard 	struct pinctrl_desc *pctrl_desc;
8080e37f88dSMaxime Ripard 	struct pinctrl_pin_desc *pins;
8090e37f88dSMaxime Ripard 	struct sunxi_pinctrl *pctl;
8104409cafcSMaxime Ripard 	struct resource *res;
81108e9e614SMaxime Ripard 	int i, ret, last_pin;
812950707c0SEmilio López 	struct clk *clk;
8130e37f88dSMaxime Ripard 
8140e37f88dSMaxime Ripard 	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
8150e37f88dSMaxime Ripard 	if (!pctl)
8160e37f88dSMaxime Ripard 		return -ENOMEM;
8170e37f88dSMaxime Ripard 	platform_set_drvdata(pdev, pctl);
8180e37f88dSMaxime Ripard 
8191bee963dSMaxime Ripard 	spin_lock_init(&pctl->lock);
8201bee963dSMaxime Ripard 
8214409cafcSMaxime Ripard 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8224409cafcSMaxime Ripard 	pctl->membase = devm_ioremap_resource(&pdev->dev, res);
8234409cafcSMaxime Ripard 	if (IS_ERR(pctl->membase))
8244409cafcSMaxime Ripard 		return PTR_ERR(pctl->membase);
8250e37f88dSMaxime Ripard 
826ba6764d5SMaxime Ripard 	pctl->dev = &pdev->dev;
8272284ba6bSMaxime Ripard 	pctl->desc = desc;
8280e37f88dSMaxime Ripard 
829aebdc8abSMaxime Ripard 	pctl->irq_array = devm_kcalloc(&pdev->dev,
830aebdc8abSMaxime Ripard 				       IRQ_PER_BANK * pctl->desc->irq_banks,
831aebdc8abSMaxime Ripard 				       sizeof(*pctl->irq_array),
832aebdc8abSMaxime Ripard 				       GFP_KERNEL);
833aebdc8abSMaxime Ripard 	if (!pctl->irq_array)
834aebdc8abSMaxime Ripard 		return -ENOMEM;
835aebdc8abSMaxime Ripard 
8360e37f88dSMaxime Ripard 	ret = sunxi_pinctrl_build_state(pdev);
8370e37f88dSMaxime Ripard 	if (ret) {
8380e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
8390e37f88dSMaxime Ripard 		return ret;
8400e37f88dSMaxime Ripard 	}
8410e37f88dSMaxime Ripard 
8420e37f88dSMaxime Ripard 	pins = devm_kzalloc(&pdev->dev,
8430e37f88dSMaxime Ripard 			    pctl->desc->npins * sizeof(*pins),
8440e37f88dSMaxime Ripard 			    GFP_KERNEL);
8450e37f88dSMaxime Ripard 	if (!pins)
8460e37f88dSMaxime Ripard 		return -ENOMEM;
8470e37f88dSMaxime Ripard 
8480e37f88dSMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++)
8490e37f88dSMaxime Ripard 		pins[i] = pctl->desc->pins[i].pin;
8500e37f88dSMaxime Ripard 
851ba6764d5SMaxime Ripard 	pctrl_desc = devm_kzalloc(&pdev->dev,
852ba6764d5SMaxime Ripard 				  sizeof(*pctrl_desc),
853ba6764d5SMaxime Ripard 				  GFP_KERNEL);
854ba6764d5SMaxime Ripard 	if (!pctrl_desc)
855ba6764d5SMaxime Ripard 		return -ENOMEM;
856ba6764d5SMaxime Ripard 
857ba6764d5SMaxime Ripard 	pctrl_desc->name = dev_name(&pdev->dev);
858ba6764d5SMaxime Ripard 	pctrl_desc->owner = THIS_MODULE;
859ba6764d5SMaxime Ripard 	pctrl_desc->pins = pins;
860ba6764d5SMaxime Ripard 	pctrl_desc->npins = pctl->desc->npins;
861ba6764d5SMaxime Ripard 	pctrl_desc->confops = &sunxi_pconf_ops;
862ba6764d5SMaxime Ripard 	pctrl_desc->pctlops = &sunxi_pctrl_ops;
863ba6764d5SMaxime Ripard 	pctrl_desc->pmxops =  &sunxi_pmx_ops;
864ba6764d5SMaxime Ripard 
865ba6764d5SMaxime Ripard 	pctl->pctl_dev = pinctrl_register(pctrl_desc,
8660e37f88dSMaxime Ripard 					  &pdev->dev, pctl);
8670e37f88dSMaxime Ripard 	if (!pctl->pctl_dev) {
8680e37f88dSMaxime Ripard 		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
8690e37f88dSMaxime Ripard 		return -EINVAL;
8700e37f88dSMaxime Ripard 	}
8710e37f88dSMaxime Ripard 
87208e9e614SMaxime Ripard 	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
87308e9e614SMaxime Ripard 	if (!pctl->chip) {
87408e9e614SMaxime Ripard 		ret = -ENOMEM;
87508e9e614SMaxime Ripard 		goto pinctrl_error;
87608e9e614SMaxime Ripard 	}
87708e9e614SMaxime Ripard 
87808e9e614SMaxime Ripard 	last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
879d83c82ceSBoris BREZILLON 	pctl->chip->owner = THIS_MODULE;
880d83c82ceSBoris BREZILLON 	pctl->chip->request = sunxi_pinctrl_gpio_request,
881d83c82ceSBoris BREZILLON 	pctl->chip->free = sunxi_pinctrl_gpio_free,
882d83c82ceSBoris BREZILLON 	pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,
883d83c82ceSBoris BREZILLON 	pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,
884d83c82ceSBoris BREZILLON 	pctl->chip->get = sunxi_pinctrl_gpio_get,
885d83c82ceSBoris BREZILLON 	pctl->chip->set = sunxi_pinctrl_gpio_set,
886d83c82ceSBoris BREZILLON 	pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate,
887d83c82ceSBoris BREZILLON 	pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq,
888d83c82ceSBoris BREZILLON 	pctl->chip->of_gpio_n_cells = 3,
889d83c82ceSBoris BREZILLON 	pctl->chip->can_sleep = false,
890d83c82ceSBoris BREZILLON 	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
891d83c82ceSBoris BREZILLON 			    pctl->desc->pin_base;
89208e9e614SMaxime Ripard 	pctl->chip->label = dev_name(&pdev->dev);
89308e9e614SMaxime Ripard 	pctl->chip->dev = &pdev->dev;
894d83c82ceSBoris BREZILLON 	pctl->chip->base = pctl->desc->pin_base;
89508e9e614SMaxime Ripard 
89608e9e614SMaxime Ripard 	ret = gpiochip_add(pctl->chip);
89708e9e614SMaxime Ripard 	if (ret)
89808e9e614SMaxime Ripard 		goto pinctrl_error;
89908e9e614SMaxime Ripard 
90008e9e614SMaxime Ripard 	for (i = 0; i < pctl->desc->npins; i++) {
90108e9e614SMaxime Ripard 		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
90208e9e614SMaxime Ripard 
90308e9e614SMaxime Ripard 		ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
90408e9e614SMaxime Ripard 					     pin->pin.number,
90508e9e614SMaxime Ripard 					     pin->pin.number, 1);
90608e9e614SMaxime Ripard 		if (ret)
90708e9e614SMaxime Ripard 			goto gpiochip_error;
90808e9e614SMaxime Ripard 	}
90908e9e614SMaxime Ripard 
910950707c0SEmilio López 	clk = devm_clk_get(&pdev->dev, NULL);
911d72f88a4SWei Yongjun 	if (IS_ERR(clk)) {
912d72f88a4SWei Yongjun 		ret = PTR_ERR(clk);
913950707c0SEmilio López 		goto gpiochip_error;
914d72f88a4SWei Yongjun 	}
915950707c0SEmilio López 
9166415093fSBoris BREZILLON 	ret = clk_prepare_enable(clk);
9176415093fSBoris BREZILLON 	if (ret)
9186415093fSBoris BREZILLON 		goto gpiochip_error;
919950707c0SEmilio López 
920aebdc8abSMaxime Ripard 	pctl->irq = devm_kcalloc(&pdev->dev,
921aebdc8abSMaxime Ripard 				 pctl->desc->irq_banks,
922aebdc8abSMaxime Ripard 				 sizeof(*pctl->irq),
923aebdc8abSMaxime Ripard 				 GFP_KERNEL);
92460242db1SMaxime Ripard 	if (!pctl->irq) {
925aebdc8abSMaxime Ripard 		ret = -ENOMEM;
926dc969106SMaxime Ripard 		goto clk_error;
92760242db1SMaxime Ripard 	}
92860242db1SMaxime Ripard 
929aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
930aebdc8abSMaxime Ripard 		pctl->irq[i] = platform_get_irq(pdev, i);
931aebdc8abSMaxime Ripard 		if (pctl->irq[i] < 0) {
932aebdc8abSMaxime Ripard 			ret = pctl->irq[i];
933aebdc8abSMaxime Ripard 			goto clk_error;
934aebdc8abSMaxime Ripard 		}
935aebdc8abSMaxime Ripard 	}
936aebdc8abSMaxime Ripard 
937aebdc8abSMaxime Ripard 	pctl->domain = irq_domain_add_linear(node,
938aebdc8abSMaxime Ripard 					     pctl->desc->irq_banks * IRQ_PER_BANK,
939aebdc8abSMaxime Ripard 					     &irq_domain_simple_ops,
940aebdc8abSMaxime Ripard 					     NULL);
94160242db1SMaxime Ripard 	if (!pctl->domain) {
94260242db1SMaxime Ripard 		dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
94360242db1SMaxime Ripard 		ret = -ENOMEM;
944dc969106SMaxime Ripard 		goto clk_error;
94560242db1SMaxime Ripard 	}
94660242db1SMaxime Ripard 
947aebdc8abSMaxime Ripard 	for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
94860242db1SMaxime Ripard 		int irqno = irq_create_mapping(pctl->domain, i);
94960242db1SMaxime Ripard 
950*f4c51c10SHans de Goede 		irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
951*f4c51c10SHans de Goede 					 handle_edge_irq);
95260242db1SMaxime Ripard 		irq_set_chip_data(irqno, pctl);
95360242db1SMaxime Ripard 	};
95460242db1SMaxime Ripard 
955aebdc8abSMaxime Ripard 	for (i = 0; i < pctl->desc->irq_banks; i++) {
956*f4c51c10SHans de Goede 		/* Mask and clear all IRQs before registering a handler */
957*f4c51c10SHans de Goede 		writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
958*f4c51c10SHans de Goede 		writel(0xffffffff,
959*f4c51c10SHans de Goede 			pctl->membase + sunxi_irq_status_reg_from_bank(i));
960*f4c51c10SHans de Goede 
961aebdc8abSMaxime Ripard 		irq_set_chained_handler(pctl->irq[i],
962aebdc8abSMaxime Ripard 					sunxi_pinctrl_irq_handler);
963aebdc8abSMaxime Ripard 		irq_set_handler_data(pctl->irq[i], pctl);
964aebdc8abSMaxime Ripard 	}
96560242db1SMaxime Ripard 
96608e9e614SMaxime Ripard 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
9670e37f88dSMaxime Ripard 
9680e37f88dSMaxime Ripard 	return 0;
96908e9e614SMaxime Ripard 
970e2bddc6aSBoris BREZILLON clk_error:
971e2bddc6aSBoris BREZILLON 	clk_disable_unprepare(clk);
97208e9e614SMaxime Ripard gpiochip_error:
97397fc4637SAxel Lin 	if (gpiochip_remove(pctl->chip))
97497fc4637SAxel Lin 		dev_err(&pdev->dev, "failed to remove gpio chip\n");
97508e9e614SMaxime Ripard pinctrl_error:
97608e9e614SMaxime Ripard 	pinctrl_unregister(pctl->pctl_dev);
97708e9e614SMaxime Ripard 	return ret;
9780e37f88dSMaxime Ripard }
979