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 3142676fa4SMaxime Ripard #include <dt-bindings/pinctrl/sun4i-a10.h> 3242676fa4SMaxime Ripard 335f910777SMaxime Ripard #include "../core.h" 340e37f88dSMaxime Ripard #include "pinctrl-sunxi.h" 35eaa3d848SMaxime Ripard 36f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip; 37f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip; 38f4c51c10SHans de Goede 390e37f88dSMaxime Ripard static struct sunxi_pinctrl_group * 400e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group) 410e37f88dSMaxime Ripard { 420e37f88dSMaxime Ripard int i; 430e37f88dSMaxime Ripard 440e37f88dSMaxime Ripard for (i = 0; i < pctl->ngroups; i++) { 450e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = pctl->groups + i; 460e37f88dSMaxime Ripard 470e37f88dSMaxime Ripard if (!strcmp(grp->name, group)) 480e37f88dSMaxime Ripard return grp; 490e37f88dSMaxime Ripard } 500e37f88dSMaxime Ripard 510e37f88dSMaxime Ripard return NULL; 520e37f88dSMaxime Ripard } 530e37f88dSMaxime Ripard 540e37f88dSMaxime Ripard static struct sunxi_pinctrl_function * 550e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl, 560e37f88dSMaxime Ripard const char *name) 570e37f88dSMaxime Ripard { 580e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 590e37f88dSMaxime Ripard int i; 600e37f88dSMaxime Ripard 610e37f88dSMaxime Ripard for (i = 0; i < pctl->nfunctions; i++) { 620e37f88dSMaxime Ripard if (!func[i].name) 630e37f88dSMaxime Ripard break; 640e37f88dSMaxime Ripard 650e37f88dSMaxime Ripard if (!strcmp(func[i].name, name)) 660e37f88dSMaxime Ripard return func + i; 670e37f88dSMaxime Ripard } 680e37f88dSMaxime Ripard 690e37f88dSMaxime Ripard return NULL; 700e37f88dSMaxime Ripard } 710e37f88dSMaxime Ripard 720e37f88dSMaxime Ripard static struct sunxi_desc_function * 730e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, 740e37f88dSMaxime Ripard const char *pin_name, 750e37f88dSMaxime Ripard const char *func_name) 760e37f88dSMaxime Ripard { 770e37f88dSMaxime Ripard int i; 780e37f88dSMaxime Ripard 790e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 800e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 810e37f88dSMaxime Ripard 820e37f88dSMaxime Ripard if (!strcmp(pin->pin.name, pin_name)) { 830e37f88dSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 840e37f88dSMaxime Ripard 850e37f88dSMaxime Ripard while (func->name) { 860e37f88dSMaxime Ripard if (!strcmp(func->name, func_name)) 870e37f88dSMaxime Ripard return func; 880e37f88dSMaxime Ripard 890e37f88dSMaxime Ripard func++; 900e37f88dSMaxime Ripard } 910e37f88dSMaxime Ripard } 920e37f88dSMaxime Ripard } 930e37f88dSMaxime Ripard 940e37f88dSMaxime Ripard return NULL; 950e37f88dSMaxime Ripard } 960e37f88dSMaxime Ripard 97814d4f2eSMaxime Ripard static struct sunxi_desc_function * 98814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl, 99814d4f2eSMaxime Ripard const u16 pin_num, 100814d4f2eSMaxime Ripard const char *func_name) 101814d4f2eSMaxime Ripard { 102814d4f2eSMaxime Ripard int i; 103814d4f2eSMaxime Ripard 104814d4f2eSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 105814d4f2eSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 106814d4f2eSMaxime Ripard 107814d4f2eSMaxime Ripard if (pin->pin.number == pin_num) { 108814d4f2eSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 109814d4f2eSMaxime Ripard 110814d4f2eSMaxime Ripard while (func->name) { 111814d4f2eSMaxime Ripard if (!strcmp(func->name, func_name)) 112814d4f2eSMaxime Ripard return func; 113814d4f2eSMaxime Ripard 114814d4f2eSMaxime Ripard func++; 115814d4f2eSMaxime Ripard } 116814d4f2eSMaxime Ripard } 117814d4f2eSMaxime Ripard } 118814d4f2eSMaxime Ripard 119814d4f2eSMaxime Ripard return NULL; 120814d4f2eSMaxime Ripard } 121814d4f2eSMaxime Ripard 1220e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 1230e37f88dSMaxime Ripard { 1240e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1250e37f88dSMaxime Ripard 1260e37f88dSMaxime Ripard return pctl->ngroups; 1270e37f88dSMaxime Ripard } 1280e37f88dSMaxime Ripard 1290e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev, 1300e37f88dSMaxime Ripard unsigned group) 1310e37f88dSMaxime Ripard { 1320e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1330e37f88dSMaxime Ripard 1340e37f88dSMaxime Ripard return pctl->groups[group].name; 1350e37f88dSMaxime Ripard } 1360e37f88dSMaxime Ripard 1370e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 1380e37f88dSMaxime Ripard unsigned group, 1390e37f88dSMaxime Ripard const unsigned **pins, 1400e37f88dSMaxime Ripard unsigned *num_pins) 1410e37f88dSMaxime Ripard { 1420e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1430e37f88dSMaxime Ripard 1440e37f88dSMaxime Ripard *pins = (unsigned *)&pctl->groups[group].pin; 1450e37f88dSMaxime Ripard *num_pins = 1; 1460e37f88dSMaxime Ripard 1470e37f88dSMaxime Ripard return 0; 1480e37f88dSMaxime Ripard } 1490e37f88dSMaxime Ripard 150f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_bias_prop(struct device_node *node) 151f233dbcaSMaxime Ripard { 152cefbf1a1SMaxime Ripard return of_find_property(node, "bias-pull-up", NULL) || 153cefbf1a1SMaxime Ripard of_find_property(node, "bias-pull-down", NULL) || 154cefbf1a1SMaxime Ripard of_find_property(node, "bias-disable", NULL) || 155cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,pull", NULL); 156f233dbcaSMaxime Ripard } 157f233dbcaSMaxime Ripard 158f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_drive_prop(struct device_node *node) 159f233dbcaSMaxime Ripard { 160cefbf1a1SMaxime Ripard return of_find_property(node, "drive-strength", NULL) || 161cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,drive", NULL); 162f233dbcaSMaxime Ripard } 163f233dbcaSMaxime Ripard 164f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_bias_prop(struct device_node *node) 165f233dbcaSMaxime Ripard { 166f233dbcaSMaxime Ripard u32 val; 167f233dbcaSMaxime Ripard 168cefbf1a1SMaxime Ripard /* Try the new style binding */ 169cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-up", NULL)) 170cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 171cefbf1a1SMaxime Ripard 172cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-down", NULL)) 173cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 174cefbf1a1SMaxime Ripard 175cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-disable", NULL)) 176cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 177cefbf1a1SMaxime Ripard 178cefbf1a1SMaxime Ripard /* And fall back to the old binding */ 179f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,pull", &val)) 180f233dbcaSMaxime Ripard return -EINVAL; 181f233dbcaSMaxime Ripard 182f233dbcaSMaxime Ripard switch (val) { 18307fe64baSMaxime Ripard case SUN4I_PINCTRL_NO_PULL: 18407fe64baSMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 18542676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_UP: 186f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 18742676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_DOWN: 188f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 189f233dbcaSMaxime Ripard } 190f233dbcaSMaxime Ripard 191f233dbcaSMaxime Ripard return -EINVAL; 192f233dbcaSMaxime Ripard } 193f233dbcaSMaxime Ripard 194f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_drive_prop(struct device_node *node) 195f233dbcaSMaxime Ripard { 196f233dbcaSMaxime Ripard u32 val; 197f233dbcaSMaxime Ripard 198cefbf1a1SMaxime Ripard /* Try the new style binding */ 199cefbf1a1SMaxime Ripard if (!of_property_read_u32(node, "drive-strength", &val)) { 200cefbf1a1SMaxime Ripard /* We can't go below 10mA ... */ 201cefbf1a1SMaxime Ripard if (val < 10) 202cefbf1a1SMaxime Ripard return -EINVAL; 203cefbf1a1SMaxime Ripard 204cefbf1a1SMaxime Ripard /* ... and only up to 40 mA ... */ 205cefbf1a1SMaxime Ripard if (val > 40) 206cefbf1a1SMaxime Ripard val = 40; 207cefbf1a1SMaxime Ripard 208cefbf1a1SMaxime Ripard /* by steps of 10 mA */ 209cefbf1a1SMaxime Ripard return rounddown(val, 10); 210cefbf1a1SMaxime Ripard } 211cefbf1a1SMaxime Ripard 212cefbf1a1SMaxime Ripard /* And then fall back to the old binding */ 213f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,drive", &val)) 214f233dbcaSMaxime Ripard return -EINVAL; 215f233dbcaSMaxime Ripard 216f233dbcaSMaxime Ripard return (val + 1) * 10; 217f233dbcaSMaxime Ripard } 218f233dbcaSMaxime Ripard 219f233dbcaSMaxime Ripard static const char *sunxi_pctrl_parse_function_prop(struct device_node *node) 220f233dbcaSMaxime Ripard { 221f233dbcaSMaxime Ripard const char *function; 222f233dbcaSMaxime Ripard int ret; 223f233dbcaSMaxime Ripard 224cefbf1a1SMaxime Ripard /* Try the generic binding */ 225cefbf1a1SMaxime Ripard ret = of_property_read_string(node, "function", &function); 226cefbf1a1SMaxime Ripard if (!ret) 227cefbf1a1SMaxime Ripard return function; 228cefbf1a1SMaxime Ripard 229cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 230f233dbcaSMaxime Ripard ret = of_property_read_string(node, "allwinner,function", &function); 231f233dbcaSMaxime Ripard if (!ret) 232f233dbcaSMaxime Ripard return function; 233f233dbcaSMaxime Ripard 234f233dbcaSMaxime Ripard return NULL; 235f233dbcaSMaxime Ripard } 236f233dbcaSMaxime Ripard 237f233dbcaSMaxime Ripard static const char *sunxi_pctrl_find_pins_prop(struct device_node *node, 238f233dbcaSMaxime Ripard int *npins) 239f233dbcaSMaxime Ripard { 240f233dbcaSMaxime Ripard int count; 241f233dbcaSMaxime Ripard 242cefbf1a1SMaxime Ripard /* Try the generic binding */ 243cefbf1a1SMaxime Ripard count = of_property_count_strings(node, "pins"); 244cefbf1a1SMaxime Ripard if (count > 0) { 245cefbf1a1SMaxime Ripard *npins = count; 246cefbf1a1SMaxime Ripard return "pins"; 247cefbf1a1SMaxime Ripard } 248cefbf1a1SMaxime Ripard 249cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 250f233dbcaSMaxime Ripard count = of_property_count_strings(node, "allwinner,pins"); 251f233dbcaSMaxime Ripard if (count > 0) { 252f233dbcaSMaxime Ripard *npins = count; 253f233dbcaSMaxime Ripard return "allwinner,pins"; 254f233dbcaSMaxime Ripard } 255f233dbcaSMaxime Ripard 256f233dbcaSMaxime Ripard return NULL; 257f233dbcaSMaxime Ripard } 258f233dbcaSMaxime Ripard 259f233dbcaSMaxime Ripard static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node, 260f233dbcaSMaxime Ripard unsigned int *len) 261f233dbcaSMaxime Ripard { 262f233dbcaSMaxime Ripard unsigned long *pinconfig; 263f233dbcaSMaxime Ripard unsigned int configlen = 0, idx = 0; 264e11dee2eSMaxime Ripard int ret; 265f233dbcaSMaxime Ripard 266f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) 267f233dbcaSMaxime Ripard configlen++; 268f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) 269f233dbcaSMaxime Ripard configlen++; 270f233dbcaSMaxime Ripard 271e11dee2eSMaxime Ripard /* 272e11dee2eSMaxime Ripard * If we don't have any configuration, bail out 273e11dee2eSMaxime Ripard */ 274e11dee2eSMaxime Ripard if (!configlen) 275e11dee2eSMaxime Ripard return NULL; 276e11dee2eSMaxime Ripard 277f233dbcaSMaxime Ripard pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL); 278f233dbcaSMaxime Ripard if (!pinconfig) 279e11dee2eSMaxime Ripard return ERR_PTR(-ENOMEM); 280f233dbcaSMaxime Ripard 281f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) { 282f233dbcaSMaxime Ripard int drive = sunxi_pctrl_parse_drive_prop(node); 283e11dee2eSMaxime Ripard if (drive < 0) { 284e11dee2eSMaxime Ripard ret = drive; 285f233dbcaSMaxime Ripard goto err_free; 286e11dee2eSMaxime Ripard } 287f233dbcaSMaxime Ripard 288f233dbcaSMaxime Ripard pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, 289f233dbcaSMaxime Ripard drive); 290f233dbcaSMaxime Ripard } 291f233dbcaSMaxime Ripard 292f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) { 293f233dbcaSMaxime Ripard int pull = sunxi_pctrl_parse_bias_prop(node); 294223dba00SChen-Yu Tsai int arg = 0; 295e11dee2eSMaxime Ripard if (pull < 0) { 296e11dee2eSMaxime Ripard ret = pull; 297f233dbcaSMaxime Ripard goto err_free; 298e11dee2eSMaxime Ripard } 299f233dbcaSMaxime Ripard 300223dba00SChen-Yu Tsai if (pull != PIN_CONFIG_BIAS_DISABLE) 301223dba00SChen-Yu Tsai arg = 1; /* hardware uses weak pull resistors */ 302223dba00SChen-Yu Tsai 303223dba00SChen-Yu Tsai pinconfig[idx++] = pinconf_to_config_packed(pull, arg); 304f233dbcaSMaxime Ripard } 305f233dbcaSMaxime Ripard 306f233dbcaSMaxime Ripard 307f233dbcaSMaxime Ripard *len = configlen; 308f233dbcaSMaxime Ripard return pinconfig; 309f233dbcaSMaxime Ripard 310f233dbcaSMaxime Ripard err_free: 311f233dbcaSMaxime Ripard kfree(pinconfig); 312e11dee2eSMaxime Ripard return ERR_PTR(ret); 313f233dbcaSMaxime Ripard } 314f233dbcaSMaxime Ripard 3150e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 3160e37f88dSMaxime Ripard struct device_node *node, 3170e37f88dSMaxime Ripard struct pinctrl_map **map, 3180e37f88dSMaxime Ripard unsigned *num_maps) 3190e37f88dSMaxime Ripard { 3200e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 3210e37f88dSMaxime Ripard unsigned long *pinconfig; 3220e37f88dSMaxime Ripard struct property *prop; 323f233dbcaSMaxime Ripard const char *function, *pin_prop; 3240e37f88dSMaxime Ripard const char *group; 325f233dbcaSMaxime Ripard int ret, npins, nmaps, configlen = 0, i = 0; 3260e37f88dSMaxime Ripard 3270e37f88dSMaxime Ripard *map = NULL; 3280e37f88dSMaxime Ripard *num_maps = 0; 3290e37f88dSMaxime Ripard 330f233dbcaSMaxime Ripard function = sunxi_pctrl_parse_function_prop(node); 331f233dbcaSMaxime Ripard if (!function) { 332f233dbcaSMaxime Ripard dev_err(pctl->dev, "missing function property in node %s\n", 3330e37f88dSMaxime Ripard node->name); 3340e37f88dSMaxime Ripard return -EINVAL; 3350e37f88dSMaxime Ripard } 3360e37f88dSMaxime Ripard 337f233dbcaSMaxime Ripard pin_prop = sunxi_pctrl_find_pins_prop(node, &npins); 338f233dbcaSMaxime Ripard if (!pin_prop) { 339f233dbcaSMaxime Ripard dev_err(pctl->dev, "missing pins property in node %s\n", 3400e37f88dSMaxime Ripard node->name); 3410e37f88dSMaxime Ripard return -EINVAL; 3420e37f88dSMaxime Ripard } 3430e37f88dSMaxime Ripard 344f233dbcaSMaxime Ripard /* 345f233dbcaSMaxime Ripard * We have two maps for each pin: one for the function, one 346e11dee2eSMaxime Ripard * for the configuration (bias, strength, etc). 347e11dee2eSMaxime Ripard * 348e11dee2eSMaxime Ripard * We might be slightly overshooting, since we might not have 349e11dee2eSMaxime Ripard * any configuration. 350f233dbcaSMaxime Ripard */ 351f233dbcaSMaxime Ripard nmaps = npins * 2; 3520e37f88dSMaxime Ripard *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL); 3533efa921dSSachin Kamat if (!*map) 3540e37f88dSMaxime Ripard return -ENOMEM; 3550e37f88dSMaxime Ripard 356f233dbcaSMaxime Ripard pinconfig = sunxi_pctrl_build_pin_config(node, &configlen); 357e11dee2eSMaxime Ripard if (IS_ERR(pinconfig)) { 358e11dee2eSMaxime Ripard ret = PTR_ERR(pinconfig); 359f233dbcaSMaxime Ripard goto err_free_map; 360f233dbcaSMaxime Ripard } 361f233dbcaSMaxime Ripard 362f233dbcaSMaxime Ripard of_property_for_each_string(node, pin_prop, prop, group) { 3630e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = 3640e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(pctl, group); 3650e37f88dSMaxime Ripard 3660e37f88dSMaxime Ripard if (!grp) { 3670e37f88dSMaxime Ripard dev_err(pctl->dev, "unknown pin %s", group); 3680e37f88dSMaxime Ripard continue; 3690e37f88dSMaxime Ripard } 3700e37f88dSMaxime Ripard 3710e37f88dSMaxime Ripard if (!sunxi_pinctrl_desc_find_function_by_name(pctl, 3720e37f88dSMaxime Ripard grp->name, 3730e37f88dSMaxime Ripard function)) { 3740e37f88dSMaxime Ripard dev_err(pctl->dev, "unsupported function %s on pin %s", 3750e37f88dSMaxime Ripard function, group); 3760e37f88dSMaxime Ripard continue; 3770e37f88dSMaxime Ripard } 3780e37f88dSMaxime Ripard 3790e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP; 3800e37f88dSMaxime Ripard (*map)[i].data.mux.group = group; 3810e37f88dSMaxime Ripard (*map)[i].data.mux.function = function; 3820e37f88dSMaxime Ripard 3830e37f88dSMaxime Ripard i++; 3840e37f88dSMaxime Ripard 385e11dee2eSMaxime Ripard if (pinconfig) { 3860e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP; 3870e37f88dSMaxime Ripard (*map)[i].data.configs.group_or_pin = group; 3880e37f88dSMaxime Ripard (*map)[i].data.configs.configs = pinconfig; 3890e37f88dSMaxime Ripard (*map)[i].data.configs.num_configs = configlen; 3900e37f88dSMaxime Ripard i++; 3910e37f88dSMaxime Ripard } 392e11dee2eSMaxime Ripard } 3930e37f88dSMaxime Ripard 394e11dee2eSMaxime Ripard *num_maps = i; 395e11dee2eSMaxime Ripard 396e11dee2eSMaxime Ripard /* 397e11dee2eSMaxime Ripard * We know have the number of maps we need, we can resize our 398e11dee2eSMaxime Ripard * map array 399e11dee2eSMaxime Ripard */ 400e11dee2eSMaxime Ripard *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL); 401b3cde198SDan Carpenter if (!*map) 402e11dee2eSMaxime Ripard return -ENOMEM; 4030e37f88dSMaxime Ripard 4040e37f88dSMaxime Ripard return 0; 405f233dbcaSMaxime Ripard 406f233dbcaSMaxime Ripard err_free_map: 407b3cde198SDan Carpenter kfree(*map); 408b3cde198SDan Carpenter *map = NULL; 409f233dbcaSMaxime Ripard return ret; 4100e37f88dSMaxime Ripard } 4110e37f88dSMaxime Ripard 4120e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev, 4130e37f88dSMaxime Ripard struct pinctrl_map *map, 4140e37f88dSMaxime Ripard unsigned num_maps) 4150e37f88dSMaxime Ripard { 41688f01a1bSChen-Yu Tsai int i; 41788f01a1bSChen-Yu Tsai 41888f01a1bSChen-Yu Tsai /* pin config is never in the first map */ 41988f01a1bSChen-Yu Tsai for (i = 1; i < num_maps; i++) { 42088f01a1bSChen-Yu Tsai if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP) 42188f01a1bSChen-Yu Tsai continue; 42288f01a1bSChen-Yu Tsai 42388f01a1bSChen-Yu Tsai /* 42488f01a1bSChen-Yu Tsai * All the maps share the same pin config, 42588f01a1bSChen-Yu Tsai * free only the first one we find. 42688f01a1bSChen-Yu Tsai */ 42788f01a1bSChen-Yu Tsai kfree(map[i].data.configs.configs); 42888f01a1bSChen-Yu Tsai break; 42988f01a1bSChen-Yu Tsai } 43088f01a1bSChen-Yu Tsai 4310e37f88dSMaxime Ripard kfree(map); 4320e37f88dSMaxime Ripard } 4330e37f88dSMaxime Ripard 434022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = { 4350e37f88dSMaxime Ripard .dt_node_to_map = sunxi_pctrl_dt_node_to_map, 4360e37f88dSMaxime Ripard .dt_free_map = sunxi_pctrl_dt_free_map, 4370e37f88dSMaxime Ripard .get_groups_count = sunxi_pctrl_get_groups_count, 4380e37f88dSMaxime Ripard .get_group_name = sunxi_pctrl_get_group_name, 4390e37f88dSMaxime Ripard .get_group_pins = sunxi_pctrl_get_group_pins, 4400e37f88dSMaxime Ripard }; 4410e37f88dSMaxime Ripard 442c5fda170SChen-Yu Tsai static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param, 443c5fda170SChen-Yu Tsai u32 *offset, u32 *shift, u32 *mask) 444c5fda170SChen-Yu Tsai { 445c5fda170SChen-Yu Tsai switch (param) { 446c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 447c5fda170SChen-Yu Tsai *offset = sunxi_dlevel_reg(pin); 448c5fda170SChen-Yu Tsai *shift = sunxi_dlevel_offset(pin); 449c5fda170SChen-Yu Tsai *mask = DLEVEL_PINS_MASK; 450c5fda170SChen-Yu Tsai break; 451c5fda170SChen-Yu Tsai 452c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 453c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 454c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 455c5fda170SChen-Yu Tsai *offset = sunxi_pull_reg(pin); 456c5fda170SChen-Yu Tsai *shift = sunxi_pull_offset(pin); 457c5fda170SChen-Yu Tsai *mask = PULL_PINS_MASK; 458c5fda170SChen-Yu Tsai break; 459c5fda170SChen-Yu Tsai 460c5fda170SChen-Yu Tsai default: 461c5fda170SChen-Yu Tsai return -ENOTSUPP; 462c5fda170SChen-Yu Tsai } 463c5fda170SChen-Yu Tsai 464c5fda170SChen-Yu Tsai return 0; 465c5fda170SChen-Yu Tsai } 466c5fda170SChen-Yu Tsai 467c5fda170SChen-Yu Tsai static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin, 468c5fda170SChen-Yu Tsai unsigned long *config) 469c5fda170SChen-Yu Tsai { 470c5fda170SChen-Yu Tsai struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 471c5fda170SChen-Yu Tsai enum pin_config_param param = pinconf_to_config_param(*config); 472c5fda170SChen-Yu Tsai u32 offset, shift, mask, val; 473c5fda170SChen-Yu Tsai u16 arg; 474c5fda170SChen-Yu Tsai int ret; 475c5fda170SChen-Yu Tsai 476c5fda170SChen-Yu Tsai pin -= pctl->desc->pin_base; 477c5fda170SChen-Yu Tsai 478c5fda170SChen-Yu Tsai ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); 479c5fda170SChen-Yu Tsai if (ret < 0) 480c5fda170SChen-Yu Tsai return ret; 481c5fda170SChen-Yu Tsai 482c5fda170SChen-Yu Tsai val = (readl(pctl->membase + offset) >> shift) & mask; 483c5fda170SChen-Yu Tsai 484c5fda170SChen-Yu Tsai switch (pinconf_to_config_param(*config)) { 485c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 486c5fda170SChen-Yu Tsai arg = (val + 1) * 10; 487c5fda170SChen-Yu Tsai break; 488c5fda170SChen-Yu Tsai 489c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 490c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_UP) 491c5fda170SChen-Yu Tsai return -EINVAL; 492c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-up */ 493c5fda170SChen-Yu Tsai break; 494c5fda170SChen-Yu Tsai 495c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 496c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_DOWN) 497c5fda170SChen-Yu Tsai return -EINVAL; 498c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-down */ 499c5fda170SChen-Yu Tsai break; 500c5fda170SChen-Yu Tsai 501c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 502c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_NO_PULL) 503c5fda170SChen-Yu Tsai return -EINVAL; 504c5fda170SChen-Yu Tsai arg = 0; 505c5fda170SChen-Yu Tsai break; 506c5fda170SChen-Yu Tsai 507c5fda170SChen-Yu Tsai default: 508c5fda170SChen-Yu Tsai /* sunxi_pconf_reg should catch anything unsupported */ 509c5fda170SChen-Yu Tsai WARN_ON(1); 510c5fda170SChen-Yu Tsai return -ENOTSUPP; 511c5fda170SChen-Yu Tsai } 512c5fda170SChen-Yu Tsai 513c5fda170SChen-Yu Tsai *config = pinconf_to_config_packed(param, arg); 514c5fda170SChen-Yu Tsai 515c5fda170SChen-Yu Tsai return 0; 516c5fda170SChen-Yu Tsai } 517c5fda170SChen-Yu Tsai 5180e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev, 5190e37f88dSMaxime Ripard unsigned group, 5200e37f88dSMaxime Ripard unsigned long *config) 5210e37f88dSMaxime Ripard { 5220e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 523c5fda170SChen-Yu Tsai struct sunxi_pinctrl_group *g = &pctl->groups[group]; 5240e37f88dSMaxime Ripard 525c5fda170SChen-Yu Tsai /* We only support 1 pin per group. Chain it to the pin callback */ 526c5fda170SChen-Yu Tsai return sunxi_pconf_get(pctldev, g->pin, config); 5270e37f88dSMaxime Ripard } 5280e37f88dSMaxime Ripard 5290e37f88dSMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, 5300e37f88dSMaxime Ripard unsigned group, 53103b054e9SSherman Yin unsigned long *configs, 53203b054e9SSherman Yin unsigned num_configs) 5330e37f88dSMaxime Ripard { 5340e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 5350e37f88dSMaxime Ripard struct sunxi_pinctrl_group *g = &pctl->groups[group]; 536b4575c69SChen-Yu Tsai unsigned pin = g->pin - pctl->desc->pin_base; 53703b054e9SSherman Yin int i; 5380e37f88dSMaxime Ripard 53903b054e9SSherman Yin for (i = 0; i < num_configs; i++) { 54051814827SChen-Yu Tsai enum pin_config_param param; 54151814827SChen-Yu Tsai unsigned long flags; 54251814827SChen-Yu Tsai u32 offset, shift, mask, reg; 54358957d2eSMika Westerberg u32 arg, val; 54451814827SChen-Yu Tsai int ret; 54551814827SChen-Yu Tsai 54651814827SChen-Yu Tsai param = pinconf_to_config_param(configs[i]); 54751814827SChen-Yu Tsai arg = pinconf_to_config_argument(configs[i]); 54851814827SChen-Yu Tsai 54951814827SChen-Yu Tsai ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); 55051814827SChen-Yu Tsai if (ret < 0) 55151814827SChen-Yu Tsai return ret; 55251814827SChen-Yu Tsai 55351814827SChen-Yu Tsai switch (param) { 5540e37f88dSMaxime Ripard case PIN_CONFIG_DRIVE_STRENGTH: 55551814827SChen-Yu Tsai if (arg < 10 || arg > 40) 5560e37f88dSMaxime Ripard return -EINVAL; 5570e37f88dSMaxime Ripard /* 5580e37f88dSMaxime Ripard * We convert from mA to what the register expects: 5590e37f88dSMaxime Ripard * 0: 10mA 5600e37f88dSMaxime Ripard * 1: 20mA 5610e37f88dSMaxime Ripard * 2: 30mA 5620e37f88dSMaxime Ripard * 3: 40mA 5630e37f88dSMaxime Ripard */ 56451814827SChen-Yu Tsai val = arg / 10 - 1; 5650e37f88dSMaxime Ripard break; 56607fe64baSMaxime Ripard case PIN_CONFIG_BIAS_DISABLE: 567ac059e2aSPriit Laes val = 0; 568ac059e2aSPriit Laes break; 5690e37f88dSMaxime Ripard case PIN_CONFIG_BIAS_PULL_UP: 57051814827SChen-Yu Tsai if (arg == 0) 57151814827SChen-Yu Tsai return -EINVAL; 57251814827SChen-Yu Tsai val = 1; 5730e37f88dSMaxime Ripard break; 5740e37f88dSMaxime Ripard case PIN_CONFIG_BIAS_PULL_DOWN: 57551814827SChen-Yu Tsai if (arg == 0) 57651814827SChen-Yu Tsai return -EINVAL; 57751814827SChen-Yu Tsai val = 2; 5780e37f88dSMaxime Ripard break; 5790e37f88dSMaxime Ripard default: 58051814827SChen-Yu Tsai /* sunxi_pconf_reg should catch anything unsupported */ 58151814827SChen-Yu Tsai WARN_ON(1); 58251814827SChen-Yu Tsai return -ENOTSUPP; 5830e37f88dSMaxime Ripard } 5840e37f88dSMaxime Ripard 585f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 58651814827SChen-Yu Tsai reg = readl(pctl->membase + offset); 58751814827SChen-Yu Tsai reg &= ~(mask << shift); 58851814827SChen-Yu Tsai writel(reg | val << shift, pctl->membase + offset); 589f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 59051814827SChen-Yu Tsai } /* for each config */ 5910e37f88dSMaxime Ripard 5920e37f88dSMaxime Ripard return 0; 5930e37f88dSMaxime Ripard } 5940e37f88dSMaxime Ripard 595022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = { 596c5fda170SChen-Yu Tsai .is_generic = true, 597c5fda170SChen-Yu Tsai .pin_config_get = sunxi_pconf_get, 5980e37f88dSMaxime Ripard .pin_config_group_get = sunxi_pconf_group_get, 5990e37f88dSMaxime Ripard .pin_config_group_set = sunxi_pconf_group_set, 6000e37f88dSMaxime Ripard }; 6010e37f88dSMaxime Ripard 6020e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 6030e37f88dSMaxime Ripard { 6040e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6050e37f88dSMaxime Ripard 6060e37f88dSMaxime Ripard return pctl->nfunctions; 6070e37f88dSMaxime Ripard } 6080e37f88dSMaxime Ripard 6090e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev, 6100e37f88dSMaxime Ripard unsigned function) 6110e37f88dSMaxime Ripard { 6120e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6130e37f88dSMaxime Ripard 6140e37f88dSMaxime Ripard return pctl->functions[function].name; 6150e37f88dSMaxime Ripard } 6160e37f88dSMaxime Ripard 6170e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev, 6180e37f88dSMaxime Ripard unsigned function, 6190e37f88dSMaxime Ripard const char * const **groups, 6200e37f88dSMaxime Ripard unsigned * const num_groups) 6210e37f88dSMaxime Ripard { 6220e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6230e37f88dSMaxime Ripard 6240e37f88dSMaxime Ripard *groups = pctl->functions[function].groups; 6250e37f88dSMaxime Ripard *num_groups = pctl->functions[function].ngroups; 6260e37f88dSMaxime Ripard 6270e37f88dSMaxime Ripard return 0; 6280e37f88dSMaxime Ripard } 6290e37f88dSMaxime Ripard 6300e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev, 6310e37f88dSMaxime Ripard unsigned pin, 6320e37f88dSMaxime Ripard u8 config) 6330e37f88dSMaxime Ripard { 6340e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6351bee963dSMaxime Ripard unsigned long flags; 6361bee963dSMaxime Ripard u32 val, mask; 6370e37f88dSMaxime Ripard 638f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 6391bee963dSMaxime Ripard 640b4575c69SChen-Yu Tsai pin -= pctl->desc->pin_base; 6411bee963dSMaxime Ripard val = readl(pctl->membase + sunxi_mux_reg(pin)); 6421bee963dSMaxime Ripard mask = MUX_PINS_MASK << sunxi_mux_offset(pin); 6430e37f88dSMaxime Ripard writel((val & ~mask) | config << sunxi_mux_offset(pin), 6440e37f88dSMaxime Ripard pctl->membase + sunxi_mux_reg(pin)); 6451bee963dSMaxime Ripard 646f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 6470e37f88dSMaxime Ripard } 6480e37f88dSMaxime Ripard 64903e9f0caSLinus Walleij static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev, 6500e37f88dSMaxime Ripard unsigned function, 6510e37f88dSMaxime Ripard unsigned group) 6520e37f88dSMaxime Ripard { 6530e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6540e37f88dSMaxime Ripard struct sunxi_pinctrl_group *g = pctl->groups + group; 6550e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions + function; 6560e37f88dSMaxime Ripard struct sunxi_desc_function *desc = 6570e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(pctl, 6580e37f88dSMaxime Ripard g->name, 6590e37f88dSMaxime Ripard func->name); 6600e37f88dSMaxime Ripard 6610e37f88dSMaxime Ripard if (!desc) 6620e37f88dSMaxime Ripard return -EINVAL; 6630e37f88dSMaxime Ripard 6640e37f88dSMaxime Ripard sunxi_pmx_set(pctldev, g->pin, desc->muxval); 6650e37f88dSMaxime Ripard 6660e37f88dSMaxime Ripard return 0; 6670e37f88dSMaxime Ripard } 6680e37f88dSMaxime Ripard 66908e9e614SMaxime Ripard static int 67008e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 67108e9e614SMaxime Ripard struct pinctrl_gpio_range *range, 67208e9e614SMaxime Ripard unsigned offset, 67308e9e614SMaxime Ripard bool input) 67408e9e614SMaxime Ripard { 67508e9e614SMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 67608e9e614SMaxime Ripard struct sunxi_desc_function *desc; 67708e9e614SMaxime Ripard const char *func; 67808e9e614SMaxime Ripard 67908e9e614SMaxime Ripard if (input) 68008e9e614SMaxime Ripard func = "gpio_in"; 68108e9e614SMaxime Ripard else 68208e9e614SMaxime Ripard func = "gpio_out"; 68308e9e614SMaxime Ripard 684814d4f2eSMaxime Ripard desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func); 685814d4f2eSMaxime Ripard if (!desc) 686814d4f2eSMaxime Ripard return -EINVAL; 68708e9e614SMaxime Ripard 68808e9e614SMaxime Ripard sunxi_pmx_set(pctldev, offset, desc->muxval); 68908e9e614SMaxime Ripard 690814d4f2eSMaxime Ripard return 0; 69108e9e614SMaxime Ripard } 69208e9e614SMaxime Ripard 693022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = { 6940e37f88dSMaxime Ripard .get_functions_count = sunxi_pmx_get_funcs_cnt, 6950e37f88dSMaxime Ripard .get_function_name = sunxi_pmx_get_func_name, 6960e37f88dSMaxime Ripard .get_function_groups = sunxi_pmx_get_func_groups, 69703e9f0caSLinus Walleij .set_mux = sunxi_pmx_set_mux, 69808e9e614SMaxime Ripard .gpio_set_direction = sunxi_pmx_gpio_set_direction, 699*13960072SMaxime Ripard .strict = true, 7000e37f88dSMaxime Ripard }; 7010e37f88dSMaxime Ripard 70208e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, 70308e9e614SMaxime Ripard unsigned offset) 70408e9e614SMaxime Ripard { 70508e9e614SMaxime Ripard return pinctrl_gpio_direction_input(chip->base + offset); 70608e9e614SMaxime Ripard } 70708e9e614SMaxime Ripard 70808e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) 70908e9e614SMaxime Ripard { 71088057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 71108e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 71208e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 7136cee3821SLinus Walleij bool set_mux = pctl->desc->irq_read_needs_mux && 7146cee3821SLinus Walleij gpiochip_line_is_irq(chip, offset); 715be2d107fSKrzysztof Adamski u32 pin = offset + chip->base; 716ef6d24ccSHans de Goede u32 val; 717ef6d24ccSHans de Goede 718ef6d24ccSHans de Goede if (set_mux) 719be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT); 720ef6d24ccSHans de Goede 721ef6d24ccSHans de Goede val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; 722ef6d24ccSHans de Goede 723ef6d24ccSHans de Goede if (set_mux) 724be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ); 72508e9e614SMaxime Ripard 72639e24ac3SLinus Walleij return !!val; 72708e9e614SMaxime Ripard } 72808e9e614SMaxime Ripard 72908e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, 73008e9e614SMaxime Ripard unsigned offset, int value) 73108e9e614SMaxime Ripard { 73288057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 73308e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 73408e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 7351bee963dSMaxime Ripard unsigned long flags; 7361bee963dSMaxime Ripard u32 regval; 73708e9e614SMaxime Ripard 738f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 7391bee963dSMaxime Ripard 7401bee963dSMaxime Ripard regval = readl(pctl->membase + reg); 74108e9e614SMaxime Ripard 742df7b34f4SMaxime Ripard if (value) 743df7b34f4SMaxime Ripard regval |= BIT(index); 744df7b34f4SMaxime Ripard else 745df7b34f4SMaxime Ripard regval &= ~(BIT(index)); 746df7b34f4SMaxime Ripard 747df7b34f4SMaxime Ripard writel(regval, pctl->membase + reg); 7481bee963dSMaxime Ripard 749f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 75008e9e614SMaxime Ripard } 75108e9e614SMaxime Ripard 752fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, 753fa8cf57cSChen-Yu Tsai unsigned offset, int value) 754fa8cf57cSChen-Yu Tsai { 755fa8cf57cSChen-Yu Tsai sunxi_pinctrl_gpio_set(chip, offset, value); 756fa8cf57cSChen-Yu Tsai return pinctrl_gpio_direction_output(chip->base + offset); 757fa8cf57cSChen-Yu Tsai } 758fa8cf57cSChen-Yu Tsai 759a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, 760a0d72094SMaxime Ripard const struct of_phandle_args *gpiospec, 761a0d72094SMaxime Ripard u32 *flags) 762a0d72094SMaxime Ripard { 763a0d72094SMaxime Ripard int pin, base; 764a0d72094SMaxime Ripard 765a0d72094SMaxime Ripard base = PINS_PER_BANK * gpiospec->args[0]; 766a0d72094SMaxime Ripard pin = base + gpiospec->args[1]; 767a0d72094SMaxime Ripard 768343f1327SChen-Yu Tsai if (pin > gc->ngpio) 769a0d72094SMaxime Ripard return -EINVAL; 770a0d72094SMaxime Ripard 771a0d72094SMaxime Ripard if (flags) 772a0d72094SMaxime Ripard *flags = gpiospec->args[2]; 773a0d72094SMaxime Ripard 774a0d72094SMaxime Ripard return pin; 775a0d72094SMaxime Ripard } 776a0d72094SMaxime Ripard 77760242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 77860242db1SMaxime Ripard { 77988057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 78060242db1SMaxime Ripard struct sunxi_desc_function *desc; 781343f1327SChen-Yu Tsai unsigned pinnum = pctl->desc->pin_base + offset; 7820d3bafacSChen-Yu Tsai unsigned irqnum; 78360242db1SMaxime Ripard 784c9e3b2d8SAxel Lin if (offset >= chip->ngpio) 78560242db1SMaxime Ripard return -ENXIO; 78660242db1SMaxime Ripard 787343f1327SChen-Yu Tsai desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq"); 78860242db1SMaxime Ripard if (!desc) 78960242db1SMaxime Ripard return -EINVAL; 79060242db1SMaxime Ripard 7910d3bafacSChen-Yu Tsai irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum; 79260242db1SMaxime Ripard 79358383c78SLinus Walleij dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n", 7940d3bafacSChen-Yu Tsai chip->label, offset + chip->base, irqnum); 7950d3bafacSChen-Yu Tsai 7960d3bafacSChen-Yu Tsai return irq_find_mapping(pctl->domain, irqnum); 79760242db1SMaxime Ripard } 79860242db1SMaxime Ripard 799fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) 80060242db1SMaxime Ripard { 80160242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 802fea6d8efSHans de Goede struct sunxi_desc_function *func; 803f83549d6SChen-Yu Tsai int ret; 804fea6d8efSHans de Goede 805fea6d8efSHans de Goede func = sunxi_pinctrl_desc_find_function_by_pin(pctl, 806fea6d8efSHans de Goede pctl->irq_array[d->hwirq], "irq"); 807fea6d8efSHans de Goede if (!func) 808fea6d8efSHans de Goede return -EINVAL; 809fea6d8efSHans de Goede 810e3a2e878SAlexandre Courbot ret = gpiochip_lock_as_irq(pctl->chip, 811343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 812f83549d6SChen-Yu Tsai if (ret) { 813f83549d6SChen-Yu Tsai dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", 814f83549d6SChen-Yu Tsai irqd_to_hwirq(d)); 815f83549d6SChen-Yu Tsai return ret; 816f83549d6SChen-Yu Tsai } 817f83549d6SChen-Yu Tsai 818fea6d8efSHans de Goede /* Change muxing to INT mode */ 819fea6d8efSHans de Goede sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); 820fea6d8efSHans de Goede 821fea6d8efSHans de Goede return 0; 822fea6d8efSHans de Goede } 82308e9e614SMaxime Ripard 824f83549d6SChen-Yu Tsai static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) 825f83549d6SChen-Yu Tsai { 826f83549d6SChen-Yu Tsai struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 827f83549d6SChen-Yu Tsai 828e3a2e878SAlexandre Courbot gpiochip_unlock_as_irq(pctl->chip, 829343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 830f83549d6SChen-Yu Tsai } 831f83549d6SChen-Yu Tsai 832f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) 83360242db1SMaxime Ripard { 83460242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 8355e7515baSHans de Goede u32 reg = sunxi_irq_cfg_reg(d->hwirq, pctl->desc->irq_bank_base); 83660242db1SMaxime Ripard u8 index = sunxi_irq_cfg_offset(d->hwirq); 8371bee963dSMaxime Ripard unsigned long flags; 8382aaaddffSMaxime Ripard u32 regval; 83960242db1SMaxime Ripard u8 mode; 84060242db1SMaxime Ripard 84160242db1SMaxime Ripard switch (type) { 84260242db1SMaxime Ripard case IRQ_TYPE_EDGE_RISING: 84360242db1SMaxime Ripard mode = IRQ_EDGE_RISING; 84460242db1SMaxime Ripard break; 84560242db1SMaxime Ripard case IRQ_TYPE_EDGE_FALLING: 84660242db1SMaxime Ripard mode = IRQ_EDGE_FALLING; 84760242db1SMaxime Ripard break; 84860242db1SMaxime Ripard case IRQ_TYPE_EDGE_BOTH: 84960242db1SMaxime Ripard mode = IRQ_EDGE_BOTH; 85060242db1SMaxime Ripard break; 85160242db1SMaxime Ripard case IRQ_TYPE_LEVEL_HIGH: 85260242db1SMaxime Ripard mode = IRQ_LEVEL_HIGH; 85360242db1SMaxime Ripard break; 85460242db1SMaxime Ripard case IRQ_TYPE_LEVEL_LOW: 85560242db1SMaxime Ripard mode = IRQ_LEVEL_LOW; 85660242db1SMaxime Ripard break; 85760242db1SMaxime Ripard default: 85860242db1SMaxime Ripard return -EINVAL; 85960242db1SMaxime Ripard } 86060242db1SMaxime Ripard 861f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 8621bee963dSMaxime Ripard 863a0d6de9bSMaxime Ripard if (type & IRQ_TYPE_LEVEL_MASK) 864b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip, 865a0d6de9bSMaxime Ripard handle_fasteoi_irq, NULL); 866a0d6de9bSMaxime Ripard else 867b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip, 868a0d6de9bSMaxime Ripard handle_edge_irq, NULL); 869a0d6de9bSMaxime Ripard 8702aaaddffSMaxime Ripard regval = readl(pctl->membase + reg); 871d82f9401SHans de Goede regval &= ~(IRQ_CFG_IRQ_MASK << index); 8722aaaddffSMaxime Ripard writel(regval | (mode << index), pctl->membase + reg); 87360242db1SMaxime Ripard 874f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 87560242db1SMaxime Ripard 87660242db1SMaxime Ripard return 0; 87760242db1SMaxime Ripard } 87860242db1SMaxime Ripard 879645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d) 88060242db1SMaxime Ripard { 88160242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 8825e7515baSHans de Goede u32 status_reg = sunxi_irq_status_reg(d->hwirq, 8835e7515baSHans de Goede pctl->desc->irq_bank_base); 88460242db1SMaxime Ripard u8 status_idx = sunxi_irq_status_offset(d->hwirq); 88560242db1SMaxime Ripard 88660242db1SMaxime Ripard /* Clear the IRQ */ 88760242db1SMaxime Ripard writel(1 << status_idx, pctl->membase + status_reg); 88860242db1SMaxime Ripard } 88960242db1SMaxime Ripard 89060242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d) 89160242db1SMaxime Ripard { 89260242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 8935e7515baSHans de Goede u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base); 89460242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 8951bee963dSMaxime Ripard unsigned long flags; 89660242db1SMaxime Ripard u32 val; 89760242db1SMaxime Ripard 898f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 8991bee963dSMaxime Ripard 90060242db1SMaxime Ripard /* Mask the IRQ */ 90160242db1SMaxime Ripard val = readl(pctl->membase + reg); 90260242db1SMaxime Ripard writel(val & ~(1 << idx), pctl->membase + reg); 9031bee963dSMaxime Ripard 904f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 90560242db1SMaxime Ripard } 90660242db1SMaxime Ripard 90760242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d) 90860242db1SMaxime Ripard { 90960242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 9105e7515baSHans de Goede u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base); 91160242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 9121bee963dSMaxime Ripard unsigned long flags; 91360242db1SMaxime Ripard u32 val; 91460242db1SMaxime Ripard 915f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 9161bee963dSMaxime Ripard 91760242db1SMaxime Ripard /* Unmask the IRQ */ 91860242db1SMaxime Ripard val = readl(pctl->membase + reg); 91960242db1SMaxime Ripard writel(val | (1 << idx), pctl->membase + reg); 9201bee963dSMaxime Ripard 921f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 92260242db1SMaxime Ripard } 92360242db1SMaxime Ripard 924d61e23e5SHans de Goede static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) 925d61e23e5SHans de Goede { 926d61e23e5SHans de Goede sunxi_pinctrl_irq_ack(d); 927d61e23e5SHans de Goede sunxi_pinctrl_irq_unmask(d); 928d61e23e5SHans de Goede } 929d61e23e5SHans de Goede 930f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = { 931fb5b7788SMaxime Ripard .name = "sunxi_pio_edge", 932645ec714SMaxime Ripard .irq_ack = sunxi_pinctrl_irq_ack, 93360242db1SMaxime Ripard .irq_mask = sunxi_pinctrl_irq_mask, 93460242db1SMaxime Ripard .irq_unmask = sunxi_pinctrl_irq_unmask, 935fea6d8efSHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 936f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 93760242db1SMaxime Ripard .irq_set_type = sunxi_pinctrl_irq_set_type, 938578c0a87SChen-Yu Tsai .flags = IRQCHIP_SKIP_SET_WAKE, 93960242db1SMaxime Ripard }; 94060242db1SMaxime Ripard 941f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = { 942fb5b7788SMaxime Ripard .name = "sunxi_pio_level", 943f4c51c10SHans de Goede .irq_eoi = sunxi_pinctrl_irq_ack, 944f4c51c10SHans de Goede .irq_mask = sunxi_pinctrl_irq_mask, 945f4c51c10SHans de Goede .irq_unmask = sunxi_pinctrl_irq_unmask, 946d61e23e5SHans de Goede /* Define irq_enable / disable to avoid spurious irqs for drivers 947d61e23e5SHans de Goede * using these to suppress irqs while they clear the irq source */ 948d61e23e5SHans de Goede .irq_enable = sunxi_pinctrl_irq_ack_unmask, 949d61e23e5SHans de Goede .irq_disable = sunxi_pinctrl_irq_mask, 950f4c51c10SHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 951f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 952f4c51c10SHans de Goede .irq_set_type = sunxi_pinctrl_irq_set_type, 953f4c51c10SHans de Goede .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED | 954f4c51c10SHans de Goede IRQCHIP_EOI_IF_HANDLED, 95560242db1SMaxime Ripard }; 95660242db1SMaxime Ripard 957d8323c6bSMaxime Ripard static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, 958d8323c6bSMaxime Ripard struct device_node *node, 959d8323c6bSMaxime Ripard const u32 *intspec, 960d8323c6bSMaxime Ripard unsigned int intsize, 961d8323c6bSMaxime Ripard unsigned long *out_hwirq, 962d8323c6bSMaxime Ripard unsigned int *out_type) 963d8323c6bSMaxime Ripard { 9648297992cSHans de Goede struct sunxi_pinctrl *pctl = d->host_data; 965d8323c6bSMaxime Ripard struct sunxi_desc_function *desc; 966d8323c6bSMaxime Ripard int pin, base; 967d8323c6bSMaxime Ripard 968d8323c6bSMaxime Ripard if (intsize < 3) 969d8323c6bSMaxime Ripard return -EINVAL; 970d8323c6bSMaxime Ripard 971d8323c6bSMaxime Ripard base = PINS_PER_BANK * intspec[0]; 9728297992cSHans de Goede pin = pctl->desc->pin_base + base + intspec[1]; 973d8323c6bSMaxime Ripard 9748297992cSHans de Goede desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq"); 975d8323c6bSMaxime Ripard if (!desc) 976d8323c6bSMaxime Ripard return -EINVAL; 977d8323c6bSMaxime Ripard 978d8323c6bSMaxime Ripard *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; 979d8323c6bSMaxime Ripard *out_type = intspec[2]; 980d8323c6bSMaxime Ripard 981d8323c6bSMaxime Ripard return 0; 982d8323c6bSMaxime Ripard } 983d8323c6bSMaxime Ripard 9842421dfd6STobias Klauser static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { 985d8323c6bSMaxime Ripard .xlate = sunxi_pinctrl_irq_of_xlate, 986d8323c6bSMaxime Ripard }; 987d8323c6bSMaxime Ripard 988bd0b9ac4SThomas Gleixner static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) 98960242db1SMaxime Ripard { 990eeef97b1SThomas Gleixner unsigned int irq = irq_desc_get_irq(desc); 9915663bb27SJiang Liu struct irq_chip *chip = irq_desc_get_chip(desc); 9925663bb27SJiang Liu struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); 993aebdc8abSMaxime Ripard unsigned long bank, reg, val; 99460242db1SMaxime Ripard 995aebdc8abSMaxime Ripard for (bank = 0; bank < pctl->desc->irq_banks; bank++) 996aebdc8abSMaxime Ripard if (irq == pctl->irq[bank]) 997aebdc8abSMaxime Ripard break; 99860242db1SMaxime Ripard 999aebdc8abSMaxime Ripard if (bank == pctl->desc->irq_banks) 1000aebdc8abSMaxime Ripard return; 1001aebdc8abSMaxime Ripard 10025e7515baSHans de Goede reg = sunxi_irq_status_reg_from_bank(bank, pctl->desc->irq_bank_base); 1003aebdc8abSMaxime Ripard val = readl(pctl->membase + reg); 100460242db1SMaxime Ripard 1005aebdc8abSMaxime Ripard if (val) { 100660242db1SMaxime Ripard int irqoffset; 100760242db1SMaxime Ripard 1008905a5117SChen-Yu Tsai chained_irq_enter(chip, desc); 1009aebdc8abSMaxime Ripard for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) { 1010aebdc8abSMaxime Ripard int pin_irq = irq_find_mapping(pctl->domain, 1011aebdc8abSMaxime Ripard bank * IRQ_PER_BANK + irqoffset); 101260242db1SMaxime Ripard generic_handle_irq(pin_irq); 101360242db1SMaxime Ripard } 1014905a5117SChen-Yu Tsai chained_irq_exit(chip, desc); 101560242db1SMaxime Ripard } 101660242db1SMaxime Ripard } 101760242db1SMaxime Ripard 10180e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, 10190e37f88dSMaxime Ripard const char *name) 10200e37f88dSMaxime Ripard { 10210e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 10220e37f88dSMaxime Ripard 10230e37f88dSMaxime Ripard while (func->name) { 10240e37f88dSMaxime Ripard /* function already there */ 10250e37f88dSMaxime Ripard if (strcmp(func->name, name) == 0) { 10260e37f88dSMaxime Ripard func->ngroups++; 10270e37f88dSMaxime Ripard return -EEXIST; 10280e37f88dSMaxime Ripard } 10290e37f88dSMaxime Ripard func++; 10300e37f88dSMaxime Ripard } 10310e37f88dSMaxime Ripard 10320e37f88dSMaxime Ripard func->name = name; 10330e37f88dSMaxime Ripard func->ngroups = 1; 10340e37f88dSMaxime Ripard 10350e37f88dSMaxime Ripard pctl->nfunctions++; 10360e37f88dSMaxime Ripard 10370e37f88dSMaxime Ripard return 0; 10380e37f88dSMaxime Ripard } 10390e37f88dSMaxime Ripard 10400e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev) 10410e37f88dSMaxime Ripard { 10420e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); 10430e37f88dSMaxime Ripard int i; 10440e37f88dSMaxime Ripard 1045578db85fSMaxime Ripard /* 1046578db85fSMaxime Ripard * Allocate groups 1047578db85fSMaxime Ripard * 1048578db85fSMaxime Ripard * We assume that the number of groups is the number of pins 1049578db85fSMaxime Ripard * given in the data array. 10500e37f88dSMaxime Ripard 1051578db85fSMaxime Ripard * This will not always be true, since some pins might not be 1052578db85fSMaxime Ripard * available in the current variant, but fortunately for us, 1053578db85fSMaxime Ripard * this means that the number of pins is the maximum group 1054578db85fSMaxime Ripard * number we will ever see. 1055578db85fSMaxime Ripard */ 10560e37f88dSMaxime Ripard pctl->groups = devm_kzalloc(&pdev->dev, 1057578db85fSMaxime Ripard pctl->desc->npins * sizeof(*pctl->groups), 10580e37f88dSMaxime Ripard GFP_KERNEL); 10590e37f88dSMaxime Ripard if (!pctl->groups) 10600e37f88dSMaxime Ripard return -ENOMEM; 10610e37f88dSMaxime Ripard 10620e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 10630e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1064578db85fSMaxime Ripard struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; 1065578db85fSMaxime Ripard 1066578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1067578db85fSMaxime Ripard continue; 10680e37f88dSMaxime Ripard 10690e37f88dSMaxime Ripard group->name = pin->pin.name; 10700e37f88dSMaxime Ripard group->pin = pin->pin.number; 1071578db85fSMaxime Ripard 1072578db85fSMaxime Ripard /* And now we count the actual number of pins / groups */ 1073578db85fSMaxime Ripard pctl->ngroups++; 10740e37f88dSMaxime Ripard } 10750e37f88dSMaxime Ripard 10760e37f88dSMaxime Ripard /* 10770e37f88dSMaxime Ripard * We suppose that we won't have any more functions than pins, 10780e37f88dSMaxime Ripard * we'll reallocate that later anyway 10790e37f88dSMaxime Ripard */ 10800e37f88dSMaxime Ripard pctl->functions = devm_kzalloc(&pdev->dev, 1081578db85fSMaxime Ripard pctl->ngroups * sizeof(*pctl->functions), 10820e37f88dSMaxime Ripard GFP_KERNEL); 10830e37f88dSMaxime Ripard if (!pctl->functions) 10840e37f88dSMaxime Ripard return -ENOMEM; 10850e37f88dSMaxime Ripard 10860e37f88dSMaxime Ripard /* Count functions and their associated groups */ 10870e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 10880e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1089578db85fSMaxime Ripard struct sunxi_desc_function *func; 10900e37f88dSMaxime Ripard 1091578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1092578db85fSMaxime Ripard continue; 1093578db85fSMaxime Ripard 1094578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 1095578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1096578db85fSMaxime Ripard continue; 1097578db85fSMaxime Ripard 1098d54e9a28SChen-Yu Tsai /* Create interrupt mapping while we're at it */ 1099aebdc8abSMaxime Ripard if (!strcmp(func->name, "irq")) { 1100aebdc8abSMaxime Ripard int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; 1101aebdc8abSMaxime Ripard pctl->irq_array[irqnum] = pin->pin.number; 1102aebdc8abSMaxime Ripard } 1103aebdc8abSMaxime Ripard 11040e37f88dSMaxime Ripard sunxi_pinctrl_add_function(pctl, func->name); 11050e37f88dSMaxime Ripard } 11060e37f88dSMaxime Ripard } 11070e37f88dSMaxime Ripard 1108578db85fSMaxime Ripard /* And now allocated and fill the array for real */ 11090e37f88dSMaxime Ripard pctl->functions = krealloc(pctl->functions, 11100e37f88dSMaxime Ripard pctl->nfunctions * sizeof(*pctl->functions), 11110e37f88dSMaxime Ripard GFP_KERNEL); 1112578db85fSMaxime Ripard if (!pctl->functions) { 1113578db85fSMaxime Ripard kfree(pctl->functions); 1114578db85fSMaxime Ripard return -ENOMEM; 1115578db85fSMaxime Ripard } 11160e37f88dSMaxime Ripard 11170e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 11180e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1119578db85fSMaxime Ripard struct sunxi_desc_function *func; 11200e37f88dSMaxime Ripard 1121578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1122578db85fSMaxime Ripard continue; 1123578db85fSMaxime Ripard 1124578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 11250e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func_item; 11260e37f88dSMaxime Ripard const char **func_grp; 11270e37f88dSMaxime Ripard 1128578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1129578db85fSMaxime Ripard continue; 1130578db85fSMaxime Ripard 11310e37f88dSMaxime Ripard func_item = sunxi_pinctrl_find_function_by_name(pctl, 11320e37f88dSMaxime Ripard func->name); 11330e37f88dSMaxime Ripard if (!func_item) 11340e37f88dSMaxime Ripard return -EINVAL; 11350e37f88dSMaxime Ripard 11360e37f88dSMaxime Ripard if (!func_item->groups) { 11370e37f88dSMaxime Ripard func_item->groups = 11380e37f88dSMaxime Ripard devm_kzalloc(&pdev->dev, 11390e37f88dSMaxime Ripard func_item->ngroups * sizeof(*func_item->groups), 11400e37f88dSMaxime Ripard GFP_KERNEL); 11410e37f88dSMaxime Ripard if (!func_item->groups) 11420e37f88dSMaxime Ripard return -ENOMEM; 11430e37f88dSMaxime Ripard } 11440e37f88dSMaxime Ripard 11450e37f88dSMaxime Ripard func_grp = func_item->groups; 11460e37f88dSMaxime Ripard while (*func_grp) 11470e37f88dSMaxime Ripard func_grp++; 11480e37f88dSMaxime Ripard 11490e37f88dSMaxime Ripard *func_grp = pin->pin.name; 11500e37f88dSMaxime Ripard } 11510e37f88dSMaxime Ripard } 11520e37f88dSMaxime Ripard 11530e37f88dSMaxime Ripard return 0; 11540e37f88dSMaxime Ripard } 11550e37f88dSMaxime Ripard 11567c926492SMaxime Ripard static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff) 11577c926492SMaxime Ripard { 11587c926492SMaxime Ripard unsigned long clock = clk_get_rate(clk); 1159d8a22212SArnd Bergmann unsigned int best_diff, best_div; 11607c926492SMaxime Ripard int i; 11617c926492SMaxime Ripard 1162d8a22212SArnd Bergmann best_diff = abs(freq - clock); 1163d8a22212SArnd Bergmann best_div = 0; 1164d8a22212SArnd Bergmann 1165d8a22212SArnd Bergmann for (i = 1; i < 8; i++) { 11667c926492SMaxime Ripard int cur_diff = abs(freq - (clock >> i)); 11677c926492SMaxime Ripard 11687c926492SMaxime Ripard if (cur_diff < best_diff) { 11697c926492SMaxime Ripard best_diff = cur_diff; 11707c926492SMaxime Ripard best_div = i; 11717c926492SMaxime Ripard } 11727c926492SMaxime Ripard } 11737c926492SMaxime Ripard 11747c926492SMaxime Ripard *diff = best_diff; 11757c926492SMaxime Ripard return best_div; 11767c926492SMaxime Ripard } 11777c926492SMaxime Ripard 11787c926492SMaxime Ripard static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, 11797c926492SMaxime Ripard struct device_node *node) 11807c926492SMaxime Ripard { 11817c926492SMaxime Ripard unsigned int hosc_diff, losc_diff; 11827c926492SMaxime Ripard unsigned int hosc_div, losc_div; 11837c926492SMaxime Ripard struct clk *hosc, *losc; 11847c926492SMaxime Ripard u8 div, src; 11857c926492SMaxime Ripard int i, ret; 11867c926492SMaxime Ripard 11877c926492SMaxime Ripard /* Deal with old DTs that didn't have the oscillators */ 11887c926492SMaxime Ripard if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3) 11897c926492SMaxime Ripard return 0; 11907c926492SMaxime Ripard 11917c926492SMaxime Ripard /* If we don't have any setup, bail out */ 11927c926492SMaxime Ripard if (!of_find_property(node, "input-debounce", NULL)) 11937c926492SMaxime Ripard return 0; 11947c926492SMaxime Ripard 11957c926492SMaxime Ripard losc = devm_clk_get(pctl->dev, "losc"); 11967c926492SMaxime Ripard if (IS_ERR(losc)) 11977c926492SMaxime Ripard return PTR_ERR(losc); 11987c926492SMaxime Ripard 11997c926492SMaxime Ripard hosc = devm_clk_get(pctl->dev, "hosc"); 12007c926492SMaxime Ripard if (IS_ERR(hosc)) 12017c926492SMaxime Ripard return PTR_ERR(hosc); 12027c926492SMaxime Ripard 12037c926492SMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 12047c926492SMaxime Ripard unsigned long debounce_freq; 12057c926492SMaxime Ripard u32 debounce; 12067c926492SMaxime Ripard 12077c926492SMaxime Ripard ret = of_property_read_u32_index(node, "input-debounce", 12087c926492SMaxime Ripard i, &debounce); 12097c926492SMaxime Ripard if (ret) 12107c926492SMaxime Ripard return ret; 12117c926492SMaxime Ripard 12127c926492SMaxime Ripard if (!debounce) 12137c926492SMaxime Ripard continue; 12147c926492SMaxime Ripard 12157c926492SMaxime Ripard debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce); 12167c926492SMaxime Ripard losc_div = sunxi_pinctrl_get_debounce_div(losc, 12177c926492SMaxime Ripard debounce_freq, 12187c926492SMaxime Ripard &losc_diff); 12197c926492SMaxime Ripard 12207c926492SMaxime Ripard hosc_div = sunxi_pinctrl_get_debounce_div(hosc, 12217c926492SMaxime Ripard debounce_freq, 12227c926492SMaxime Ripard &hosc_diff); 12237c926492SMaxime Ripard 12247c926492SMaxime Ripard if (hosc_diff < losc_diff) { 12257c926492SMaxime Ripard div = hosc_div; 12267c926492SMaxime Ripard src = 1; 12277c926492SMaxime Ripard } else { 12287c926492SMaxime Ripard div = losc_div; 12297c926492SMaxime Ripard src = 0; 12307c926492SMaxime Ripard } 12317c926492SMaxime Ripard 12327c926492SMaxime Ripard writel(src | div << 4, 12337c926492SMaxime Ripard pctl->membase + 12347c926492SMaxime Ripard sunxi_irq_debounce_reg_from_bank(i, 12357c926492SMaxime Ripard pctl->desc->irq_bank_base)); 12367c926492SMaxime Ripard } 12377c926492SMaxime Ripard 12387c926492SMaxime Ripard return 0; 12397c926492SMaxime Ripard } 12407c926492SMaxime Ripard 1241578db85fSMaxime Ripard int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, 1242578db85fSMaxime Ripard const struct sunxi_pinctrl_desc *desc, 1243578db85fSMaxime Ripard unsigned long variant) 12440e37f88dSMaxime Ripard { 12450e37f88dSMaxime Ripard struct device_node *node = pdev->dev.of_node; 1246ba6764d5SMaxime Ripard struct pinctrl_desc *pctrl_desc; 12470e37f88dSMaxime Ripard struct pinctrl_pin_desc *pins; 12480e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl; 1249aae842a3SMaxime Ripard struct pinmux_ops *pmxops; 12504409cafcSMaxime Ripard struct resource *res; 1251578db85fSMaxime Ripard int i, ret, last_pin, pin_idx; 1252950707c0SEmilio López struct clk *clk; 12530e37f88dSMaxime Ripard 12540e37f88dSMaxime Ripard pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 12550e37f88dSMaxime Ripard if (!pctl) 12560e37f88dSMaxime Ripard return -ENOMEM; 12570e37f88dSMaxime Ripard platform_set_drvdata(pdev, pctl); 12580e37f88dSMaxime Ripard 1259f658ed36SJulia Cartwright raw_spin_lock_init(&pctl->lock); 12601bee963dSMaxime Ripard 12614409cafcSMaxime Ripard res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 12624409cafcSMaxime Ripard pctl->membase = devm_ioremap_resource(&pdev->dev, res); 12634409cafcSMaxime Ripard if (IS_ERR(pctl->membase)) 12644409cafcSMaxime Ripard return PTR_ERR(pctl->membase); 12650e37f88dSMaxime Ripard 1266ba6764d5SMaxime Ripard pctl->dev = &pdev->dev; 12672284ba6bSMaxime Ripard pctl->desc = desc; 1268578db85fSMaxime Ripard pctl->variant = variant; 12690e37f88dSMaxime Ripard 1270aebdc8abSMaxime Ripard pctl->irq_array = devm_kcalloc(&pdev->dev, 1271aebdc8abSMaxime Ripard IRQ_PER_BANK * pctl->desc->irq_banks, 1272aebdc8abSMaxime Ripard sizeof(*pctl->irq_array), 1273aebdc8abSMaxime Ripard GFP_KERNEL); 1274aebdc8abSMaxime Ripard if (!pctl->irq_array) 1275aebdc8abSMaxime Ripard return -ENOMEM; 1276aebdc8abSMaxime Ripard 12770e37f88dSMaxime Ripard ret = sunxi_pinctrl_build_state(pdev); 12780e37f88dSMaxime Ripard if (ret) { 12790e37f88dSMaxime Ripard dev_err(&pdev->dev, "dt probe failed: %d\n", ret); 12800e37f88dSMaxime Ripard return ret; 12810e37f88dSMaxime Ripard } 12820e37f88dSMaxime Ripard 12830e37f88dSMaxime Ripard pins = devm_kzalloc(&pdev->dev, 12840e37f88dSMaxime Ripard pctl->desc->npins * sizeof(*pins), 12850e37f88dSMaxime Ripard GFP_KERNEL); 12860e37f88dSMaxime Ripard if (!pins) 12870e37f88dSMaxime Ripard return -ENOMEM; 12880e37f88dSMaxime Ripard 1289578db85fSMaxime Ripard for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { 1290578db85fSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1291578db85fSMaxime Ripard 1292578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1293578db85fSMaxime Ripard continue; 1294578db85fSMaxime Ripard 1295578db85fSMaxime Ripard pins[pin_idx++] = pin->pin; 1296578db85fSMaxime Ripard } 12970e37f88dSMaxime Ripard 1298ba6764d5SMaxime Ripard pctrl_desc = devm_kzalloc(&pdev->dev, 1299ba6764d5SMaxime Ripard sizeof(*pctrl_desc), 1300ba6764d5SMaxime Ripard GFP_KERNEL); 1301ba6764d5SMaxime Ripard if (!pctrl_desc) 1302ba6764d5SMaxime Ripard return -ENOMEM; 1303ba6764d5SMaxime Ripard 1304ba6764d5SMaxime Ripard pctrl_desc->name = dev_name(&pdev->dev); 1305ba6764d5SMaxime Ripard pctrl_desc->owner = THIS_MODULE; 1306ba6764d5SMaxime Ripard pctrl_desc->pins = pins; 1307578db85fSMaxime Ripard pctrl_desc->npins = pctl->ngroups; 1308ba6764d5SMaxime Ripard pctrl_desc->confops = &sunxi_pconf_ops; 1309ba6764d5SMaxime Ripard pctrl_desc->pctlops = &sunxi_pctrl_ops; 1310aae842a3SMaxime Ripard 1311aae842a3SMaxime Ripard pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops), 1312aae842a3SMaxime Ripard GFP_KERNEL); 1313aae842a3SMaxime Ripard if (!pmxops) 1314aae842a3SMaxime Ripard return -ENOMEM; 1315aae842a3SMaxime Ripard 1316aae842a3SMaxime Ripard if (desc->disable_strict_mode) 1317aae842a3SMaxime Ripard pmxops->strict = false; 1318aae842a3SMaxime Ripard 1319aae842a3SMaxime Ripard pctrl_desc->pmxops = pmxops; 1320ba6764d5SMaxime Ripard 132145078ea0SLaxman Dewangan pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); 1322323de9efSMasahiro Yamada if (IS_ERR(pctl->pctl_dev)) { 13230e37f88dSMaxime Ripard dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); 1324323de9efSMasahiro Yamada return PTR_ERR(pctl->pctl_dev); 13250e37f88dSMaxime Ripard } 13260e37f88dSMaxime Ripard 132708e9e614SMaxime Ripard pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); 132845078ea0SLaxman Dewangan if (!pctl->chip) 132945078ea0SLaxman Dewangan return -ENOMEM; 133008e9e614SMaxime Ripard 133108e9e614SMaxime Ripard last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; 1332d83c82ceSBoris BREZILLON pctl->chip->owner = THIS_MODULE; 133398c85d58SJonas Gorski pctl->chip->request = gpiochip_generic_request, 133498c85d58SJonas Gorski pctl->chip->free = gpiochip_generic_free, 1335d83c82ceSBoris BREZILLON pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input, 1336d83c82ceSBoris BREZILLON pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output, 1337d83c82ceSBoris BREZILLON pctl->chip->get = sunxi_pinctrl_gpio_get, 1338d83c82ceSBoris BREZILLON pctl->chip->set = sunxi_pinctrl_gpio_set, 1339d83c82ceSBoris BREZILLON pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate, 1340d83c82ceSBoris BREZILLON pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq, 1341d83c82ceSBoris BREZILLON pctl->chip->of_gpio_n_cells = 3, 1342d83c82ceSBoris BREZILLON pctl->chip->can_sleep = false, 1343d83c82ceSBoris BREZILLON pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) - 1344d83c82ceSBoris BREZILLON pctl->desc->pin_base; 134508e9e614SMaxime Ripard pctl->chip->label = dev_name(&pdev->dev); 134658383c78SLinus Walleij pctl->chip->parent = &pdev->dev; 1347d83c82ceSBoris BREZILLON pctl->chip->base = pctl->desc->pin_base; 134808e9e614SMaxime Ripard 134988057d6eSLinus Walleij ret = gpiochip_add_data(pctl->chip, pctl); 135008e9e614SMaxime Ripard if (ret) 135145078ea0SLaxman Dewangan return ret; 135208e9e614SMaxime Ripard 135308e9e614SMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 135408e9e614SMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 135508e9e614SMaxime Ripard 135608e9e614SMaxime Ripard ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), 1357343f1327SChen-Yu Tsai pin->pin.number - pctl->desc->pin_base, 135808e9e614SMaxime Ripard pin->pin.number, 1); 135908e9e614SMaxime Ripard if (ret) 136008e9e614SMaxime Ripard goto gpiochip_error; 136108e9e614SMaxime Ripard } 136208e9e614SMaxime Ripard 1363950707c0SEmilio López clk = devm_clk_get(&pdev->dev, NULL); 1364d72f88a4SWei Yongjun if (IS_ERR(clk)) { 1365d72f88a4SWei Yongjun ret = PTR_ERR(clk); 1366950707c0SEmilio López goto gpiochip_error; 1367d72f88a4SWei Yongjun } 1368950707c0SEmilio López 13696415093fSBoris BREZILLON ret = clk_prepare_enable(clk); 13706415093fSBoris BREZILLON if (ret) 13716415093fSBoris BREZILLON goto gpiochip_error; 1372950707c0SEmilio López 1373aebdc8abSMaxime Ripard pctl->irq = devm_kcalloc(&pdev->dev, 1374aebdc8abSMaxime Ripard pctl->desc->irq_banks, 1375aebdc8abSMaxime Ripard sizeof(*pctl->irq), 1376aebdc8abSMaxime Ripard GFP_KERNEL); 137760242db1SMaxime Ripard if (!pctl->irq) { 1378aebdc8abSMaxime Ripard ret = -ENOMEM; 1379dc969106SMaxime Ripard goto clk_error; 138060242db1SMaxime Ripard } 138160242db1SMaxime Ripard 1382aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1383aebdc8abSMaxime Ripard pctl->irq[i] = platform_get_irq(pdev, i); 1384aebdc8abSMaxime Ripard if (pctl->irq[i] < 0) { 1385aebdc8abSMaxime Ripard ret = pctl->irq[i]; 1386aebdc8abSMaxime Ripard goto clk_error; 1387aebdc8abSMaxime Ripard } 1388aebdc8abSMaxime Ripard } 1389aebdc8abSMaxime Ripard 1390aebdc8abSMaxime Ripard pctl->domain = irq_domain_add_linear(node, 1391aebdc8abSMaxime Ripard pctl->desc->irq_banks * IRQ_PER_BANK, 1392d8323c6bSMaxime Ripard &sunxi_pinctrl_irq_domain_ops, 1393d8323c6bSMaxime Ripard pctl); 139460242db1SMaxime Ripard if (!pctl->domain) { 139560242db1SMaxime Ripard dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); 139660242db1SMaxime Ripard ret = -ENOMEM; 1397dc969106SMaxime Ripard goto clk_error; 139860242db1SMaxime Ripard } 139960242db1SMaxime Ripard 1400aebdc8abSMaxime Ripard for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) { 140160242db1SMaxime Ripard int irqno = irq_create_mapping(pctl->domain, i); 140260242db1SMaxime Ripard 1403f4c51c10SHans de Goede irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip, 1404f4c51c10SHans de Goede handle_edge_irq); 140560242db1SMaxime Ripard irq_set_chip_data(irqno, pctl); 14065c99c0ffSJavier Martinez Canillas } 140760242db1SMaxime Ripard 1408aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1409f4c51c10SHans de Goede /* Mask and clear all IRQs before registering a handler */ 14105e7515baSHans de Goede writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i, 14115e7515baSHans de Goede pctl->desc->irq_bank_base)); 1412f4c51c10SHans de Goede writel(0xffffffff, 14135e7515baSHans de Goede pctl->membase + sunxi_irq_status_reg_from_bank(i, 14145e7515baSHans de Goede pctl->desc->irq_bank_base)); 1415f4c51c10SHans de Goede 1416ef80e87dSThomas Gleixner irq_set_chained_handler_and_data(pctl->irq[i], 1417ef80e87dSThomas Gleixner sunxi_pinctrl_irq_handler, 1418ef80e87dSThomas Gleixner pctl); 1419aebdc8abSMaxime Ripard } 142060242db1SMaxime Ripard 14217c926492SMaxime Ripard sunxi_pinctrl_setup_debounce(pctl, node); 14227c926492SMaxime Ripard 142308e9e614SMaxime Ripard dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); 14240e37f88dSMaxime Ripard 14250e37f88dSMaxime Ripard return 0; 142608e9e614SMaxime Ripard 1427e2bddc6aSBoris BREZILLON clk_error: 1428e2bddc6aSBoris BREZILLON clk_disable_unprepare(clk); 142908e9e614SMaxime Ripard gpiochip_error: 1430b4e7c55dSabdoulaye berthe gpiochip_remove(pctl->chip); 143108e9e614SMaxime Ripard return ret; 14320e37f88dSMaxime Ripard } 1433