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