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> 2010e3a88bSGeert Uytterhoeven #include <linux/of_clk.h> 210e37f88dSMaxime Ripard #include <linux/of_address.h> 220e37f88dSMaxime Ripard #include <linux/of_device.h> 2360242db1SMaxime Ripard #include <linux/of_irq.h> 240e37f88dSMaxime Ripard #include <linux/pinctrl/consumer.h> 250e37f88dSMaxime Ripard #include <linux/pinctrl/machine.h> 260e37f88dSMaxime Ripard #include <linux/pinctrl/pinctrl.h> 270e37f88dSMaxime Ripard #include <linux/pinctrl/pinconf-generic.h> 280e37f88dSMaxime Ripard #include <linux/pinctrl/pinmux.h> 299a2a566aSMaxime Ripard #include <linux/regulator/consumer.h> 300e37f88dSMaxime Ripard #include <linux/platform_device.h> 310e37f88dSMaxime Ripard #include <linux/slab.h> 320e37f88dSMaxime Ripard 3342676fa4SMaxime Ripard #include <dt-bindings/pinctrl/sun4i-a10.h> 3442676fa4SMaxime Ripard 355f910777SMaxime Ripard #include "../core.h" 360e37f88dSMaxime Ripard #include "pinctrl-sunxi.h" 37eaa3d848SMaxime Ripard 38f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip; 39f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip; 40f4c51c10SHans de Goede 410e37f88dSMaxime Ripard static struct sunxi_pinctrl_group * 420e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group) 430e37f88dSMaxime Ripard { 440e37f88dSMaxime Ripard int i; 450e37f88dSMaxime Ripard 460e37f88dSMaxime Ripard for (i = 0; i < pctl->ngroups; i++) { 470e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = pctl->groups + i; 480e37f88dSMaxime Ripard 490e37f88dSMaxime Ripard if (!strcmp(grp->name, group)) 500e37f88dSMaxime Ripard return grp; 510e37f88dSMaxime Ripard } 520e37f88dSMaxime Ripard 530e37f88dSMaxime Ripard return NULL; 540e37f88dSMaxime Ripard } 550e37f88dSMaxime Ripard 560e37f88dSMaxime Ripard static struct sunxi_pinctrl_function * 570e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl, 580e37f88dSMaxime Ripard const char *name) 590e37f88dSMaxime Ripard { 600e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 610e37f88dSMaxime Ripard int i; 620e37f88dSMaxime Ripard 630e37f88dSMaxime Ripard for (i = 0; i < pctl->nfunctions; i++) { 640e37f88dSMaxime Ripard if (!func[i].name) 650e37f88dSMaxime Ripard break; 660e37f88dSMaxime Ripard 670e37f88dSMaxime Ripard if (!strcmp(func[i].name, name)) 680e37f88dSMaxime Ripard return func + i; 690e37f88dSMaxime Ripard } 700e37f88dSMaxime Ripard 710e37f88dSMaxime Ripard return NULL; 720e37f88dSMaxime Ripard } 730e37f88dSMaxime Ripard 740e37f88dSMaxime Ripard static struct sunxi_desc_function * 750e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, 760e37f88dSMaxime Ripard const char *pin_name, 770e37f88dSMaxime Ripard const char *func_name) 780e37f88dSMaxime Ripard { 790e37f88dSMaxime Ripard int i; 800e37f88dSMaxime Ripard 810e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 820e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 830e37f88dSMaxime Ripard 840e37f88dSMaxime Ripard if (!strcmp(pin->pin.name, pin_name)) { 850e37f88dSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 860e37f88dSMaxime Ripard 870e37f88dSMaxime Ripard while (func->name) { 8832e21f08Shao_zhang if (!strcmp(func->name, func_name) && 8932e21f08Shao_zhang (!func->variant || 9032e21f08Shao_zhang func->variant & pctl->variant)) 910e37f88dSMaxime Ripard return func; 920e37f88dSMaxime Ripard 930e37f88dSMaxime Ripard func++; 940e37f88dSMaxime Ripard } 950e37f88dSMaxime Ripard } 960e37f88dSMaxime Ripard } 970e37f88dSMaxime Ripard 980e37f88dSMaxime Ripard return NULL; 990e37f88dSMaxime Ripard } 1000e37f88dSMaxime Ripard 101814d4f2eSMaxime Ripard static struct sunxi_desc_function * 102814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl, 103814d4f2eSMaxime Ripard const u16 pin_num, 104814d4f2eSMaxime Ripard const char *func_name) 105814d4f2eSMaxime Ripard { 106814d4f2eSMaxime Ripard int i; 107814d4f2eSMaxime Ripard 108814d4f2eSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 109814d4f2eSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 110814d4f2eSMaxime Ripard 111814d4f2eSMaxime Ripard if (pin->pin.number == pin_num) { 112814d4f2eSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 113814d4f2eSMaxime Ripard 114814d4f2eSMaxime Ripard while (func->name) { 115814d4f2eSMaxime Ripard if (!strcmp(func->name, func_name)) 116814d4f2eSMaxime Ripard return func; 117814d4f2eSMaxime Ripard 118814d4f2eSMaxime Ripard func++; 119814d4f2eSMaxime Ripard } 120814d4f2eSMaxime Ripard } 121814d4f2eSMaxime Ripard } 122814d4f2eSMaxime Ripard 123814d4f2eSMaxime Ripard return NULL; 124814d4f2eSMaxime Ripard } 125814d4f2eSMaxime Ripard 1260e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 1270e37f88dSMaxime Ripard { 1280e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1290e37f88dSMaxime Ripard 1300e37f88dSMaxime Ripard return pctl->ngroups; 1310e37f88dSMaxime Ripard } 1320e37f88dSMaxime Ripard 1330e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev, 1340e37f88dSMaxime Ripard unsigned group) 1350e37f88dSMaxime Ripard { 1360e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1370e37f88dSMaxime Ripard 1380e37f88dSMaxime Ripard return pctl->groups[group].name; 1390e37f88dSMaxime Ripard } 1400e37f88dSMaxime Ripard 1410e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 1420e37f88dSMaxime Ripard unsigned group, 1430e37f88dSMaxime Ripard const unsigned **pins, 1440e37f88dSMaxime Ripard unsigned *num_pins) 1450e37f88dSMaxime Ripard { 1460e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1470e37f88dSMaxime Ripard 1480e37f88dSMaxime Ripard *pins = (unsigned *)&pctl->groups[group].pin; 1490e37f88dSMaxime Ripard *num_pins = 1; 1500e37f88dSMaxime Ripard 1510e37f88dSMaxime Ripard return 0; 1520e37f88dSMaxime Ripard } 1530e37f88dSMaxime Ripard 154f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_bias_prop(struct device_node *node) 155f233dbcaSMaxime Ripard { 156cefbf1a1SMaxime Ripard return of_find_property(node, "bias-pull-up", NULL) || 157cefbf1a1SMaxime Ripard of_find_property(node, "bias-pull-down", NULL) || 158cefbf1a1SMaxime Ripard of_find_property(node, "bias-disable", NULL) || 159cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,pull", NULL); 160f233dbcaSMaxime Ripard } 161f233dbcaSMaxime Ripard 162f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_drive_prop(struct device_node *node) 163f233dbcaSMaxime Ripard { 164cefbf1a1SMaxime Ripard return of_find_property(node, "drive-strength", NULL) || 165cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,drive", NULL); 166f233dbcaSMaxime Ripard } 167f233dbcaSMaxime Ripard 168f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_bias_prop(struct device_node *node) 169f233dbcaSMaxime Ripard { 170f233dbcaSMaxime Ripard u32 val; 171f233dbcaSMaxime Ripard 172cefbf1a1SMaxime Ripard /* Try the new style binding */ 173cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-up", NULL)) 174cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 175cefbf1a1SMaxime Ripard 176cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-down", NULL)) 177cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 178cefbf1a1SMaxime Ripard 179cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-disable", NULL)) 180cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 181cefbf1a1SMaxime Ripard 182cefbf1a1SMaxime Ripard /* And fall back to the old binding */ 183f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,pull", &val)) 184f233dbcaSMaxime Ripard return -EINVAL; 185f233dbcaSMaxime Ripard 186f233dbcaSMaxime Ripard switch (val) { 18707fe64baSMaxime Ripard case SUN4I_PINCTRL_NO_PULL: 18807fe64baSMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 18942676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_UP: 190f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 19142676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_DOWN: 192f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 193f233dbcaSMaxime Ripard } 194f233dbcaSMaxime Ripard 195f233dbcaSMaxime Ripard return -EINVAL; 196f233dbcaSMaxime Ripard } 197f233dbcaSMaxime Ripard 198f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_drive_prop(struct device_node *node) 199f233dbcaSMaxime Ripard { 200f233dbcaSMaxime Ripard u32 val; 201f233dbcaSMaxime Ripard 202cefbf1a1SMaxime Ripard /* Try the new style binding */ 203cefbf1a1SMaxime Ripard if (!of_property_read_u32(node, "drive-strength", &val)) { 204cefbf1a1SMaxime Ripard /* We can't go below 10mA ... */ 205cefbf1a1SMaxime Ripard if (val < 10) 206cefbf1a1SMaxime Ripard return -EINVAL; 207cefbf1a1SMaxime Ripard 208cefbf1a1SMaxime Ripard /* ... and only up to 40 mA ... */ 209cefbf1a1SMaxime Ripard if (val > 40) 210cefbf1a1SMaxime Ripard val = 40; 211cefbf1a1SMaxime Ripard 212cefbf1a1SMaxime Ripard /* by steps of 10 mA */ 213cefbf1a1SMaxime Ripard return rounddown(val, 10); 214cefbf1a1SMaxime Ripard } 215cefbf1a1SMaxime Ripard 216cefbf1a1SMaxime Ripard /* And then fall back to the old binding */ 217f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,drive", &val)) 218f233dbcaSMaxime Ripard return -EINVAL; 219f233dbcaSMaxime Ripard 220f233dbcaSMaxime Ripard return (val + 1) * 10; 221f233dbcaSMaxime Ripard } 222f233dbcaSMaxime Ripard 223f233dbcaSMaxime Ripard static const char *sunxi_pctrl_parse_function_prop(struct device_node *node) 224f233dbcaSMaxime Ripard { 225f233dbcaSMaxime Ripard const char *function; 226f233dbcaSMaxime Ripard int ret; 227f233dbcaSMaxime Ripard 228cefbf1a1SMaxime Ripard /* Try the generic binding */ 229cefbf1a1SMaxime Ripard ret = of_property_read_string(node, "function", &function); 230cefbf1a1SMaxime Ripard if (!ret) 231cefbf1a1SMaxime Ripard return function; 232cefbf1a1SMaxime Ripard 233cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 234f233dbcaSMaxime Ripard ret = of_property_read_string(node, "allwinner,function", &function); 235f233dbcaSMaxime Ripard if (!ret) 236f233dbcaSMaxime Ripard return function; 237f233dbcaSMaxime Ripard 238f233dbcaSMaxime Ripard return NULL; 239f233dbcaSMaxime Ripard } 240f233dbcaSMaxime Ripard 241f233dbcaSMaxime Ripard static const char *sunxi_pctrl_find_pins_prop(struct device_node *node, 242f233dbcaSMaxime Ripard int *npins) 243f233dbcaSMaxime Ripard { 244f233dbcaSMaxime Ripard int count; 245f233dbcaSMaxime Ripard 246cefbf1a1SMaxime Ripard /* Try the generic binding */ 247cefbf1a1SMaxime Ripard count = of_property_count_strings(node, "pins"); 248cefbf1a1SMaxime Ripard if (count > 0) { 249cefbf1a1SMaxime Ripard *npins = count; 250cefbf1a1SMaxime Ripard return "pins"; 251cefbf1a1SMaxime Ripard } 252cefbf1a1SMaxime Ripard 253cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 254f233dbcaSMaxime Ripard count = of_property_count_strings(node, "allwinner,pins"); 255f233dbcaSMaxime Ripard if (count > 0) { 256f233dbcaSMaxime Ripard *npins = count; 257f233dbcaSMaxime Ripard return "allwinner,pins"; 258f233dbcaSMaxime Ripard } 259f233dbcaSMaxime Ripard 260f233dbcaSMaxime Ripard return NULL; 261f233dbcaSMaxime Ripard } 262f233dbcaSMaxime Ripard 263f233dbcaSMaxime Ripard static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node, 264f233dbcaSMaxime Ripard unsigned int *len) 265f233dbcaSMaxime Ripard { 266f233dbcaSMaxime Ripard unsigned long *pinconfig; 267f233dbcaSMaxime Ripard unsigned int configlen = 0, idx = 0; 268e11dee2eSMaxime Ripard int ret; 269f233dbcaSMaxime Ripard 270f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) 271f233dbcaSMaxime Ripard configlen++; 272f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) 273f233dbcaSMaxime Ripard configlen++; 274f233dbcaSMaxime Ripard 275e11dee2eSMaxime Ripard /* 276e11dee2eSMaxime Ripard * If we don't have any configuration, bail out 277e11dee2eSMaxime Ripard */ 278e11dee2eSMaxime Ripard if (!configlen) 279e11dee2eSMaxime Ripard return NULL; 280e11dee2eSMaxime Ripard 2816396bb22SKees Cook pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL); 282f233dbcaSMaxime Ripard if (!pinconfig) 283e11dee2eSMaxime Ripard return ERR_PTR(-ENOMEM); 284f233dbcaSMaxime Ripard 285f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) { 286f233dbcaSMaxime Ripard int drive = sunxi_pctrl_parse_drive_prop(node); 287e11dee2eSMaxime Ripard if (drive < 0) { 288e11dee2eSMaxime Ripard ret = drive; 289f233dbcaSMaxime Ripard goto err_free; 290e11dee2eSMaxime Ripard } 291f233dbcaSMaxime Ripard 292f233dbcaSMaxime Ripard pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, 293f233dbcaSMaxime Ripard drive); 294f233dbcaSMaxime Ripard } 295f233dbcaSMaxime Ripard 296f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) { 297f233dbcaSMaxime Ripard int pull = sunxi_pctrl_parse_bias_prop(node); 298223dba00SChen-Yu Tsai int arg = 0; 299e11dee2eSMaxime Ripard if (pull < 0) { 300e11dee2eSMaxime Ripard ret = pull; 301f233dbcaSMaxime Ripard goto err_free; 302e11dee2eSMaxime Ripard } 303f233dbcaSMaxime Ripard 304223dba00SChen-Yu Tsai if (pull != PIN_CONFIG_BIAS_DISABLE) 305223dba00SChen-Yu Tsai arg = 1; /* hardware uses weak pull resistors */ 306223dba00SChen-Yu Tsai 307223dba00SChen-Yu Tsai pinconfig[idx++] = pinconf_to_config_packed(pull, arg); 308f233dbcaSMaxime Ripard } 309f233dbcaSMaxime Ripard 310f233dbcaSMaxime Ripard 311f233dbcaSMaxime Ripard *len = configlen; 312f233dbcaSMaxime Ripard return pinconfig; 313f233dbcaSMaxime Ripard 314f233dbcaSMaxime Ripard err_free: 315f233dbcaSMaxime Ripard kfree(pinconfig); 316e11dee2eSMaxime Ripard return ERR_PTR(ret); 317f233dbcaSMaxime Ripard } 318f233dbcaSMaxime Ripard 3190e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 3200e37f88dSMaxime Ripard struct device_node *node, 3210e37f88dSMaxime Ripard struct pinctrl_map **map, 3220e37f88dSMaxime Ripard unsigned *num_maps) 3230e37f88dSMaxime Ripard { 3240e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 3250e37f88dSMaxime Ripard unsigned long *pinconfig; 3260e37f88dSMaxime Ripard struct property *prop; 327f233dbcaSMaxime Ripard const char *function, *pin_prop; 3280e37f88dSMaxime Ripard const char *group; 329f233dbcaSMaxime Ripard int ret, npins, nmaps, configlen = 0, i = 0; 3300e37f88dSMaxime Ripard 3310e37f88dSMaxime Ripard *map = NULL; 3320e37f88dSMaxime Ripard *num_maps = 0; 3330e37f88dSMaxime Ripard 334f233dbcaSMaxime Ripard function = sunxi_pctrl_parse_function_prop(node); 335f233dbcaSMaxime Ripard if (!function) { 33694f4e54cSRob Herring dev_err(pctl->dev, "missing function property in node %pOFn\n", 33794f4e54cSRob Herring node); 3380e37f88dSMaxime Ripard return -EINVAL; 3390e37f88dSMaxime Ripard } 3400e37f88dSMaxime Ripard 341f233dbcaSMaxime Ripard pin_prop = sunxi_pctrl_find_pins_prop(node, &npins); 342f233dbcaSMaxime Ripard if (!pin_prop) { 34394f4e54cSRob Herring dev_err(pctl->dev, "missing pins property in node %pOFn\n", 34494f4e54cSRob Herring node); 3450e37f88dSMaxime Ripard return -EINVAL; 3460e37f88dSMaxime Ripard } 3470e37f88dSMaxime Ripard 348f233dbcaSMaxime Ripard /* 349f233dbcaSMaxime Ripard * We have two maps for each pin: one for the function, one 350e11dee2eSMaxime Ripard * for the configuration (bias, strength, etc). 351e11dee2eSMaxime Ripard * 352e11dee2eSMaxime Ripard * We might be slightly overshooting, since we might not have 353e11dee2eSMaxime Ripard * any configuration. 354f233dbcaSMaxime Ripard */ 355f233dbcaSMaxime Ripard nmaps = npins * 2; 3566da2ec56SKees Cook *map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL); 3573efa921dSSachin Kamat if (!*map) 3580e37f88dSMaxime Ripard return -ENOMEM; 3590e37f88dSMaxime Ripard 360f233dbcaSMaxime Ripard pinconfig = sunxi_pctrl_build_pin_config(node, &configlen); 361e11dee2eSMaxime Ripard if (IS_ERR(pinconfig)) { 362e11dee2eSMaxime Ripard ret = PTR_ERR(pinconfig); 363f233dbcaSMaxime Ripard goto err_free_map; 364f233dbcaSMaxime Ripard } 365f233dbcaSMaxime Ripard 366f233dbcaSMaxime Ripard of_property_for_each_string(node, pin_prop, prop, group) { 3670e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = 3680e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(pctl, group); 3690e37f88dSMaxime Ripard 3700e37f88dSMaxime Ripard if (!grp) { 3710e37f88dSMaxime Ripard dev_err(pctl->dev, "unknown pin %s", group); 3720e37f88dSMaxime Ripard continue; 3730e37f88dSMaxime Ripard } 3740e37f88dSMaxime Ripard 3750e37f88dSMaxime Ripard if (!sunxi_pinctrl_desc_find_function_by_name(pctl, 3760e37f88dSMaxime Ripard grp->name, 3770e37f88dSMaxime Ripard function)) { 3780e37f88dSMaxime Ripard dev_err(pctl->dev, "unsupported function %s on pin %s", 3790e37f88dSMaxime Ripard function, group); 3800e37f88dSMaxime Ripard continue; 3810e37f88dSMaxime Ripard } 3820e37f88dSMaxime Ripard 3830e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP; 3840e37f88dSMaxime Ripard (*map)[i].data.mux.group = group; 3850e37f88dSMaxime Ripard (*map)[i].data.mux.function = function; 3860e37f88dSMaxime Ripard 3870e37f88dSMaxime Ripard i++; 3880e37f88dSMaxime Ripard 389e11dee2eSMaxime Ripard if (pinconfig) { 3900e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP; 3910e37f88dSMaxime Ripard (*map)[i].data.configs.group_or_pin = group; 3920e37f88dSMaxime Ripard (*map)[i].data.configs.configs = pinconfig; 3930e37f88dSMaxime Ripard (*map)[i].data.configs.num_configs = configlen; 3940e37f88dSMaxime Ripard i++; 3950e37f88dSMaxime Ripard } 396e11dee2eSMaxime Ripard } 3970e37f88dSMaxime Ripard 398e11dee2eSMaxime Ripard *num_maps = i; 399e11dee2eSMaxime Ripard 400e11dee2eSMaxime Ripard /* 401e11dee2eSMaxime Ripard * We know have the number of maps we need, we can resize our 402e11dee2eSMaxime Ripard * map array 403e11dee2eSMaxime Ripard */ 404e11dee2eSMaxime Ripard *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL); 405b3cde198SDan Carpenter if (!*map) 406e11dee2eSMaxime Ripard return -ENOMEM; 4070e37f88dSMaxime Ripard 4080e37f88dSMaxime Ripard return 0; 409f233dbcaSMaxime Ripard 410f233dbcaSMaxime Ripard err_free_map: 411b3cde198SDan Carpenter kfree(*map); 412b3cde198SDan Carpenter *map = NULL; 413f233dbcaSMaxime Ripard return ret; 4140e37f88dSMaxime Ripard } 4150e37f88dSMaxime Ripard 4160e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev, 4170e37f88dSMaxime Ripard struct pinctrl_map *map, 4180e37f88dSMaxime Ripard unsigned num_maps) 4190e37f88dSMaxime Ripard { 42088f01a1bSChen-Yu Tsai int i; 42188f01a1bSChen-Yu Tsai 42288f01a1bSChen-Yu Tsai /* pin config is never in the first map */ 42388f01a1bSChen-Yu Tsai for (i = 1; i < num_maps; i++) { 42488f01a1bSChen-Yu Tsai if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP) 42588f01a1bSChen-Yu Tsai continue; 42688f01a1bSChen-Yu Tsai 42788f01a1bSChen-Yu Tsai /* 42888f01a1bSChen-Yu Tsai * All the maps share the same pin config, 42988f01a1bSChen-Yu Tsai * free only the first one we find. 43088f01a1bSChen-Yu Tsai */ 43188f01a1bSChen-Yu Tsai kfree(map[i].data.configs.configs); 43288f01a1bSChen-Yu Tsai break; 43388f01a1bSChen-Yu Tsai } 43488f01a1bSChen-Yu Tsai 4350e37f88dSMaxime Ripard kfree(map); 4360e37f88dSMaxime Ripard } 4370e37f88dSMaxime Ripard 438022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = { 4390e37f88dSMaxime Ripard .dt_node_to_map = sunxi_pctrl_dt_node_to_map, 4400e37f88dSMaxime Ripard .dt_free_map = sunxi_pctrl_dt_free_map, 4410e37f88dSMaxime Ripard .get_groups_count = sunxi_pctrl_get_groups_count, 4420e37f88dSMaxime Ripard .get_group_name = sunxi_pctrl_get_group_name, 4430e37f88dSMaxime Ripard .get_group_pins = sunxi_pctrl_get_group_pins, 4440e37f88dSMaxime Ripard }; 4450e37f88dSMaxime Ripard 446c5fda170SChen-Yu Tsai static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param, 447c5fda170SChen-Yu Tsai u32 *offset, u32 *shift, u32 *mask) 448c5fda170SChen-Yu Tsai { 449c5fda170SChen-Yu Tsai switch (param) { 450c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 451c5fda170SChen-Yu Tsai *offset = sunxi_dlevel_reg(pin); 452c5fda170SChen-Yu Tsai *shift = sunxi_dlevel_offset(pin); 453c5fda170SChen-Yu Tsai *mask = DLEVEL_PINS_MASK; 454c5fda170SChen-Yu Tsai break; 455c5fda170SChen-Yu Tsai 456c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 457c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 458c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 459c5fda170SChen-Yu Tsai *offset = sunxi_pull_reg(pin); 460c5fda170SChen-Yu Tsai *shift = sunxi_pull_offset(pin); 461c5fda170SChen-Yu Tsai *mask = PULL_PINS_MASK; 462c5fda170SChen-Yu Tsai break; 463c5fda170SChen-Yu Tsai 464c5fda170SChen-Yu Tsai default: 465c5fda170SChen-Yu Tsai return -ENOTSUPP; 466c5fda170SChen-Yu Tsai } 467c5fda170SChen-Yu Tsai 468c5fda170SChen-Yu Tsai return 0; 469c5fda170SChen-Yu Tsai } 470c5fda170SChen-Yu Tsai 471c5fda170SChen-Yu Tsai static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin, 472c5fda170SChen-Yu Tsai unsigned long *config) 473c5fda170SChen-Yu Tsai { 474c5fda170SChen-Yu Tsai struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 475c5fda170SChen-Yu Tsai enum pin_config_param param = pinconf_to_config_param(*config); 476c5fda170SChen-Yu Tsai u32 offset, shift, mask, val; 477c5fda170SChen-Yu Tsai u16 arg; 478c5fda170SChen-Yu Tsai int ret; 479c5fda170SChen-Yu Tsai 480c5fda170SChen-Yu Tsai pin -= pctl->desc->pin_base; 481c5fda170SChen-Yu Tsai 482c5fda170SChen-Yu Tsai ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); 483c5fda170SChen-Yu Tsai if (ret < 0) 484c5fda170SChen-Yu Tsai return ret; 485c5fda170SChen-Yu Tsai 486c5fda170SChen-Yu Tsai val = (readl(pctl->membase + offset) >> shift) & mask; 487c5fda170SChen-Yu Tsai 488c5fda170SChen-Yu Tsai switch (pinconf_to_config_param(*config)) { 489c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 490c5fda170SChen-Yu Tsai arg = (val + 1) * 10; 491c5fda170SChen-Yu Tsai break; 492c5fda170SChen-Yu Tsai 493c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 494c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_UP) 495c5fda170SChen-Yu Tsai return -EINVAL; 496c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-up */ 497c5fda170SChen-Yu Tsai break; 498c5fda170SChen-Yu Tsai 499c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 500c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_DOWN) 501c5fda170SChen-Yu Tsai return -EINVAL; 502c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-down */ 503c5fda170SChen-Yu Tsai break; 504c5fda170SChen-Yu Tsai 505c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 506c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_NO_PULL) 507c5fda170SChen-Yu Tsai return -EINVAL; 508c5fda170SChen-Yu Tsai arg = 0; 509c5fda170SChen-Yu Tsai break; 510c5fda170SChen-Yu Tsai 511c5fda170SChen-Yu Tsai default: 512c5fda170SChen-Yu Tsai /* sunxi_pconf_reg should catch anything unsupported */ 513c5fda170SChen-Yu Tsai WARN_ON(1); 514c5fda170SChen-Yu Tsai return -ENOTSUPP; 515c5fda170SChen-Yu Tsai } 516c5fda170SChen-Yu Tsai 517c5fda170SChen-Yu Tsai *config = pinconf_to_config_packed(param, arg); 518c5fda170SChen-Yu Tsai 519c5fda170SChen-Yu Tsai return 0; 520c5fda170SChen-Yu Tsai } 521c5fda170SChen-Yu Tsai 5220e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev, 5230e37f88dSMaxime Ripard unsigned group, 5240e37f88dSMaxime Ripard unsigned long *config) 5250e37f88dSMaxime Ripard { 5260e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 527c5fda170SChen-Yu Tsai struct sunxi_pinctrl_group *g = &pctl->groups[group]; 5280e37f88dSMaxime Ripard 529c5fda170SChen-Yu Tsai /* We only support 1 pin per group. Chain it to the pin callback */ 530c5fda170SChen-Yu Tsai return sunxi_pconf_get(pctldev, g->pin, config); 5310e37f88dSMaxime Ripard } 5320e37f88dSMaxime Ripard 53390be64e2SMaxime Ripard static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin, 53490be64e2SMaxime Ripard unsigned long *configs, unsigned num_configs) 5350e37f88dSMaxime Ripard { 5360e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 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 59590be64e2SMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 59690be64e2SMaxime Ripard unsigned long *configs, unsigned num_configs) 59790be64e2SMaxime Ripard { 59890be64e2SMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 59990be64e2SMaxime Ripard struct sunxi_pinctrl_group *g = &pctl->groups[group]; 60090be64e2SMaxime Ripard 60190be64e2SMaxime Ripard /* We only support 1 pin per group. Chain it to the pin callback */ 60290be64e2SMaxime Ripard return sunxi_pconf_set(pctldev, g->pin, configs, num_configs); 60390be64e2SMaxime Ripard } 60490be64e2SMaxime Ripard 605022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = { 606c5fda170SChen-Yu Tsai .is_generic = true, 607c5fda170SChen-Yu Tsai .pin_config_get = sunxi_pconf_get, 60890be64e2SMaxime Ripard .pin_config_set = sunxi_pconf_set, 6090e37f88dSMaxime Ripard .pin_config_group_get = sunxi_pconf_group_get, 6100e37f88dSMaxime Ripard .pin_config_group_set = sunxi_pconf_group_set, 6110e37f88dSMaxime Ripard }; 6120e37f88dSMaxime Ripard 613402bfb3cSChen-Yu Tsai static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, 614402bfb3cSChen-Yu Tsai unsigned pin, 615402bfb3cSChen-Yu Tsai struct regulator *supply) 616402bfb3cSChen-Yu Tsai { 617402bfb3cSChen-Yu Tsai u32 val, reg; 618402bfb3cSChen-Yu Tsai int uV; 619402bfb3cSChen-Yu Tsai 620402bfb3cSChen-Yu Tsai if (!pctl->desc->has_io_bias_cfg) 621402bfb3cSChen-Yu Tsai return 0; 622402bfb3cSChen-Yu Tsai 623402bfb3cSChen-Yu Tsai uV = regulator_get_voltage(supply); 624402bfb3cSChen-Yu Tsai if (uV < 0) 625402bfb3cSChen-Yu Tsai return uV; 626402bfb3cSChen-Yu Tsai 627402bfb3cSChen-Yu Tsai /* Might be dummy regulator with no voltage set */ 628402bfb3cSChen-Yu Tsai if (uV == 0) 629402bfb3cSChen-Yu Tsai return 0; 630402bfb3cSChen-Yu Tsai 631402bfb3cSChen-Yu Tsai /* Configured value must be equal or greater to actual voltage */ 632402bfb3cSChen-Yu Tsai if (uV <= 1800000) 633402bfb3cSChen-Yu Tsai val = 0x0; /* 1.8V */ 634402bfb3cSChen-Yu Tsai else if (uV <= 2500000) 635402bfb3cSChen-Yu Tsai val = 0x6; /* 2.5V */ 636402bfb3cSChen-Yu Tsai else if (uV <= 2800000) 637402bfb3cSChen-Yu Tsai val = 0x9; /* 2.8V */ 638402bfb3cSChen-Yu Tsai else if (uV <= 3000000) 639402bfb3cSChen-Yu Tsai val = 0xA; /* 3.0V */ 640402bfb3cSChen-Yu Tsai else 641402bfb3cSChen-Yu Tsai val = 0xD; /* 3.3V */ 642402bfb3cSChen-Yu Tsai 643402bfb3cSChen-Yu Tsai pin -= pctl->desc->pin_base; 644402bfb3cSChen-Yu Tsai 645402bfb3cSChen-Yu Tsai reg = readl(pctl->membase + sunxi_grp_config_reg(pin)); 646402bfb3cSChen-Yu Tsai reg &= ~IO_BIAS_MASK; 647402bfb3cSChen-Yu Tsai writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin)); 648402bfb3cSChen-Yu Tsai 649402bfb3cSChen-Yu Tsai return 0; 650402bfb3cSChen-Yu Tsai } 651402bfb3cSChen-Yu Tsai 6520e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 6530e37f88dSMaxime Ripard { 6540e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6550e37f88dSMaxime Ripard 6560e37f88dSMaxime Ripard return pctl->nfunctions; 6570e37f88dSMaxime Ripard } 6580e37f88dSMaxime Ripard 6590e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev, 6600e37f88dSMaxime Ripard unsigned function) 6610e37f88dSMaxime Ripard { 6620e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6630e37f88dSMaxime Ripard 6640e37f88dSMaxime Ripard return pctl->functions[function].name; 6650e37f88dSMaxime Ripard } 6660e37f88dSMaxime Ripard 6670e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev, 6680e37f88dSMaxime Ripard unsigned function, 6690e37f88dSMaxime Ripard const char * const **groups, 6700e37f88dSMaxime Ripard unsigned * const num_groups) 6710e37f88dSMaxime Ripard { 6720e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6730e37f88dSMaxime Ripard 6740e37f88dSMaxime Ripard *groups = pctl->functions[function].groups; 6750e37f88dSMaxime Ripard *num_groups = pctl->functions[function].ngroups; 6760e37f88dSMaxime Ripard 6770e37f88dSMaxime Ripard return 0; 6780e37f88dSMaxime Ripard } 6790e37f88dSMaxime Ripard 6800e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev, 6810e37f88dSMaxime Ripard unsigned pin, 6820e37f88dSMaxime Ripard u8 config) 6830e37f88dSMaxime Ripard { 6840e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6851bee963dSMaxime Ripard unsigned long flags; 6861bee963dSMaxime Ripard u32 val, mask; 6870e37f88dSMaxime Ripard 688f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 6891bee963dSMaxime Ripard 690b4575c69SChen-Yu Tsai pin -= pctl->desc->pin_base; 6911bee963dSMaxime Ripard val = readl(pctl->membase + sunxi_mux_reg(pin)); 6921bee963dSMaxime Ripard mask = MUX_PINS_MASK << sunxi_mux_offset(pin); 6930e37f88dSMaxime Ripard writel((val & ~mask) | config << sunxi_mux_offset(pin), 6940e37f88dSMaxime Ripard pctl->membase + sunxi_mux_reg(pin)); 6951bee963dSMaxime Ripard 696f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 6970e37f88dSMaxime Ripard } 6980e37f88dSMaxime Ripard 69903e9f0caSLinus Walleij static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev, 7000e37f88dSMaxime Ripard unsigned function, 7010e37f88dSMaxime Ripard unsigned group) 7020e37f88dSMaxime Ripard { 7030e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7040e37f88dSMaxime Ripard struct sunxi_pinctrl_group *g = pctl->groups + group; 7050e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions + function; 7060e37f88dSMaxime Ripard struct sunxi_desc_function *desc = 7070e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(pctl, 7080e37f88dSMaxime Ripard g->name, 7090e37f88dSMaxime Ripard func->name); 7100e37f88dSMaxime Ripard 7110e37f88dSMaxime Ripard if (!desc) 7120e37f88dSMaxime Ripard return -EINVAL; 7130e37f88dSMaxime Ripard 7140e37f88dSMaxime Ripard sunxi_pmx_set(pctldev, g->pin, desc->muxval); 7150e37f88dSMaxime Ripard 7160e37f88dSMaxime Ripard return 0; 7170e37f88dSMaxime Ripard } 7180e37f88dSMaxime Ripard 71908e9e614SMaxime Ripard static int 72008e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 72108e9e614SMaxime Ripard struct pinctrl_gpio_range *range, 72208e9e614SMaxime Ripard unsigned offset, 72308e9e614SMaxime Ripard bool input) 72408e9e614SMaxime Ripard { 72508e9e614SMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 72608e9e614SMaxime Ripard struct sunxi_desc_function *desc; 72708e9e614SMaxime Ripard const char *func; 72808e9e614SMaxime Ripard 72908e9e614SMaxime Ripard if (input) 73008e9e614SMaxime Ripard func = "gpio_in"; 73108e9e614SMaxime Ripard else 73208e9e614SMaxime Ripard func = "gpio_out"; 73308e9e614SMaxime Ripard 734814d4f2eSMaxime Ripard desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func); 735814d4f2eSMaxime Ripard if (!desc) 736814d4f2eSMaxime Ripard return -EINVAL; 73708e9e614SMaxime Ripard 73808e9e614SMaxime Ripard sunxi_pmx_set(pctldev, offset, desc->muxval); 73908e9e614SMaxime Ripard 740814d4f2eSMaxime Ripard return 0; 74108e9e614SMaxime Ripard } 74208e9e614SMaxime Ripard 7439a2a566aSMaxime Ripard static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) 7449a2a566aSMaxime Ripard { 7459a2a566aSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7469a2a566aSMaxime Ripard unsigned short bank = offset / PINS_PER_BANK; 747ca443844SChen-Yu Tsai unsigned short bank_offset = bank - pctl->desc->pin_base / 748ca443844SChen-Yu Tsai PINS_PER_BANK; 749ca443844SChen-Yu Tsai struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; 750dc144558SChen-Yu Tsai struct regulator *reg = s_reg->regulator; 751dc144558SChen-Yu Tsai char supply[16]; 7529a2a566aSMaxime Ripard int ret; 7539a2a566aSMaxime Ripard 754dc144558SChen-Yu Tsai if (reg) { 755dc144558SChen-Yu Tsai refcount_inc(&s_reg->refcount); 756dc144558SChen-Yu Tsai return 0; 757dc144558SChen-Yu Tsai } 7589a2a566aSMaxime Ripard 7599a2a566aSMaxime Ripard snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); 7609a2a566aSMaxime Ripard reg = regulator_get(pctl->dev, supply); 7619a2a566aSMaxime Ripard if (IS_ERR(reg)) { 7629a2a566aSMaxime Ripard dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", 7639a2a566aSMaxime Ripard 'A' + bank); 7649a2a566aSMaxime Ripard return PTR_ERR(reg); 7659a2a566aSMaxime Ripard } 7669a2a566aSMaxime Ripard 7679a2a566aSMaxime Ripard ret = regulator_enable(reg); 7689a2a566aSMaxime Ripard if (ret) { 7699a2a566aSMaxime Ripard dev_err(pctl->dev, 7709a2a566aSMaxime Ripard "Couldn't enable bank P%c regulator\n", 'A' + bank); 7719a2a566aSMaxime Ripard goto out; 7729a2a566aSMaxime Ripard } 7739a2a566aSMaxime Ripard 774402bfb3cSChen-Yu Tsai sunxi_pinctrl_set_io_bias_cfg(pctl, offset, reg); 775402bfb3cSChen-Yu Tsai 776dc144558SChen-Yu Tsai s_reg->regulator = reg; 777dc144558SChen-Yu Tsai refcount_set(&s_reg->refcount, 1); 778dc144558SChen-Yu Tsai 7799a2a566aSMaxime Ripard return 0; 7809a2a566aSMaxime Ripard 7819a2a566aSMaxime Ripard out: 7829a2a566aSMaxime Ripard regulator_put(s_reg->regulator); 7839a2a566aSMaxime Ripard 7849a2a566aSMaxime Ripard return ret; 7859a2a566aSMaxime Ripard } 7869a2a566aSMaxime Ripard 7879a2a566aSMaxime Ripard static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) 7889a2a566aSMaxime Ripard { 7899a2a566aSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7909a2a566aSMaxime Ripard unsigned short bank = offset / PINS_PER_BANK; 791ca443844SChen-Yu Tsai unsigned short bank_offset = bank - pctl->desc->pin_base / 792ca443844SChen-Yu Tsai PINS_PER_BANK; 793ca443844SChen-Yu Tsai struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; 7949a2a566aSMaxime Ripard 7959a2a566aSMaxime Ripard if (!refcount_dec_and_test(&s_reg->refcount)) 7969a2a566aSMaxime Ripard return 0; 7979a2a566aSMaxime Ripard 7989a2a566aSMaxime Ripard regulator_disable(s_reg->regulator); 7999a2a566aSMaxime Ripard regulator_put(s_reg->regulator); 8009a2a566aSMaxime Ripard s_reg->regulator = NULL; 8019a2a566aSMaxime Ripard 8029a2a566aSMaxime Ripard return 0; 8039a2a566aSMaxime Ripard } 8049a2a566aSMaxime Ripard 805022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = { 8060e37f88dSMaxime Ripard .get_functions_count = sunxi_pmx_get_funcs_cnt, 8070e37f88dSMaxime Ripard .get_function_name = sunxi_pmx_get_func_name, 8080e37f88dSMaxime Ripard .get_function_groups = sunxi_pmx_get_func_groups, 80903e9f0caSLinus Walleij .set_mux = sunxi_pmx_set_mux, 81008e9e614SMaxime Ripard .gpio_set_direction = sunxi_pmx_gpio_set_direction, 8119a2a566aSMaxime Ripard .request = sunxi_pmx_request, 8129a2a566aSMaxime Ripard .free = sunxi_pmx_free, 81313960072SMaxime Ripard .strict = true, 8140e37f88dSMaxime Ripard }; 8150e37f88dSMaxime Ripard 81608e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, 81708e9e614SMaxime Ripard unsigned offset) 81808e9e614SMaxime Ripard { 81908e9e614SMaxime Ripard return pinctrl_gpio_direction_input(chip->base + offset); 82008e9e614SMaxime Ripard } 82108e9e614SMaxime Ripard 82208e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) 82308e9e614SMaxime Ripard { 82488057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 82508e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 82608e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 8276cee3821SLinus Walleij bool set_mux = pctl->desc->irq_read_needs_mux && 8286cee3821SLinus Walleij gpiochip_line_is_irq(chip, offset); 829be2d107fSKrzysztof Adamski u32 pin = offset + chip->base; 830ef6d24ccSHans de Goede u32 val; 831ef6d24ccSHans de Goede 832ef6d24ccSHans de Goede if (set_mux) 833be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT); 834ef6d24ccSHans de Goede 835ef6d24ccSHans de Goede val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; 836ef6d24ccSHans de Goede 837ef6d24ccSHans de Goede if (set_mux) 838be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ); 83908e9e614SMaxime Ripard 84039e24ac3SLinus Walleij return !!val; 84108e9e614SMaxime Ripard } 84208e9e614SMaxime Ripard 84308e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, 84408e9e614SMaxime Ripard unsigned offset, int value) 84508e9e614SMaxime Ripard { 84688057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 84708e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 84808e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 8491bee963dSMaxime Ripard unsigned long flags; 8501bee963dSMaxime Ripard u32 regval; 85108e9e614SMaxime Ripard 852f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 8531bee963dSMaxime Ripard 8541bee963dSMaxime Ripard regval = readl(pctl->membase + reg); 85508e9e614SMaxime Ripard 856df7b34f4SMaxime Ripard if (value) 857df7b34f4SMaxime Ripard regval |= BIT(index); 858df7b34f4SMaxime Ripard else 859df7b34f4SMaxime Ripard regval &= ~(BIT(index)); 860df7b34f4SMaxime Ripard 861df7b34f4SMaxime Ripard writel(regval, pctl->membase + reg); 8621bee963dSMaxime Ripard 863f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 86408e9e614SMaxime Ripard } 86508e9e614SMaxime Ripard 866fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, 867fa8cf57cSChen-Yu Tsai unsigned offset, int value) 868fa8cf57cSChen-Yu Tsai { 869fa8cf57cSChen-Yu Tsai sunxi_pinctrl_gpio_set(chip, offset, value); 870fa8cf57cSChen-Yu Tsai return pinctrl_gpio_direction_output(chip->base + offset); 871fa8cf57cSChen-Yu Tsai } 872fa8cf57cSChen-Yu Tsai 873a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, 874a0d72094SMaxime Ripard const struct of_phandle_args *gpiospec, 875a0d72094SMaxime Ripard u32 *flags) 876a0d72094SMaxime Ripard { 877a0d72094SMaxime Ripard int pin, base; 878a0d72094SMaxime Ripard 879a0d72094SMaxime Ripard base = PINS_PER_BANK * gpiospec->args[0]; 880a0d72094SMaxime Ripard pin = base + gpiospec->args[1]; 881a0d72094SMaxime Ripard 882343f1327SChen-Yu Tsai if (pin > gc->ngpio) 883a0d72094SMaxime Ripard return -EINVAL; 884a0d72094SMaxime Ripard 885a0d72094SMaxime Ripard if (flags) 886a0d72094SMaxime Ripard *flags = gpiospec->args[2]; 887a0d72094SMaxime Ripard 888a0d72094SMaxime Ripard return pin; 889a0d72094SMaxime Ripard } 890a0d72094SMaxime Ripard 89160242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 89260242db1SMaxime Ripard { 89388057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 89460242db1SMaxime Ripard struct sunxi_desc_function *desc; 895343f1327SChen-Yu Tsai unsigned pinnum = pctl->desc->pin_base + offset; 8960d3bafacSChen-Yu Tsai unsigned irqnum; 89760242db1SMaxime Ripard 898c9e3b2d8SAxel Lin if (offset >= chip->ngpio) 89960242db1SMaxime Ripard return -ENXIO; 90060242db1SMaxime Ripard 901343f1327SChen-Yu Tsai desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq"); 90260242db1SMaxime Ripard if (!desc) 90360242db1SMaxime Ripard return -EINVAL; 90460242db1SMaxime Ripard 9050d3bafacSChen-Yu Tsai irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum; 90660242db1SMaxime Ripard 90758383c78SLinus Walleij dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n", 9080d3bafacSChen-Yu Tsai chip->label, offset + chip->base, irqnum); 9090d3bafacSChen-Yu Tsai 9100d3bafacSChen-Yu Tsai return irq_find_mapping(pctl->domain, irqnum); 91160242db1SMaxime Ripard } 91260242db1SMaxime Ripard 913fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) 91460242db1SMaxime Ripard { 91560242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 916fea6d8efSHans de Goede struct sunxi_desc_function *func; 917f83549d6SChen-Yu Tsai int ret; 918fea6d8efSHans de Goede 919fea6d8efSHans de Goede func = sunxi_pinctrl_desc_find_function_by_pin(pctl, 920fea6d8efSHans de Goede pctl->irq_array[d->hwirq], "irq"); 921fea6d8efSHans de Goede if (!func) 922fea6d8efSHans de Goede return -EINVAL; 923fea6d8efSHans de Goede 924e3a2e878SAlexandre Courbot ret = gpiochip_lock_as_irq(pctl->chip, 925343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 926f83549d6SChen-Yu Tsai if (ret) { 927f83549d6SChen-Yu Tsai dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", 928f83549d6SChen-Yu Tsai irqd_to_hwirq(d)); 929f83549d6SChen-Yu Tsai return ret; 930f83549d6SChen-Yu Tsai } 931f83549d6SChen-Yu Tsai 932fea6d8efSHans de Goede /* Change muxing to INT mode */ 933fea6d8efSHans de Goede sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); 934fea6d8efSHans de Goede 935fea6d8efSHans de Goede return 0; 936fea6d8efSHans de Goede } 93708e9e614SMaxime Ripard 938f83549d6SChen-Yu Tsai static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) 939f83549d6SChen-Yu Tsai { 940f83549d6SChen-Yu Tsai struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 941f83549d6SChen-Yu Tsai 942e3a2e878SAlexandre Courbot gpiochip_unlock_as_irq(pctl->chip, 943343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 944f83549d6SChen-Yu Tsai } 945f83549d6SChen-Yu Tsai 946f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) 94760242db1SMaxime Ripard { 94860242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 9494b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_cfg_reg(pctl->desc, d->hwirq); 95060242db1SMaxime Ripard u8 index = sunxi_irq_cfg_offset(d->hwirq); 9511bee963dSMaxime Ripard unsigned long flags; 9522aaaddffSMaxime Ripard u32 regval; 95360242db1SMaxime Ripard u8 mode; 95460242db1SMaxime Ripard 95560242db1SMaxime Ripard switch (type) { 95660242db1SMaxime Ripard case IRQ_TYPE_EDGE_RISING: 95760242db1SMaxime Ripard mode = IRQ_EDGE_RISING; 95860242db1SMaxime Ripard break; 95960242db1SMaxime Ripard case IRQ_TYPE_EDGE_FALLING: 96060242db1SMaxime Ripard mode = IRQ_EDGE_FALLING; 96160242db1SMaxime Ripard break; 96260242db1SMaxime Ripard case IRQ_TYPE_EDGE_BOTH: 96360242db1SMaxime Ripard mode = IRQ_EDGE_BOTH; 96460242db1SMaxime Ripard break; 96560242db1SMaxime Ripard case IRQ_TYPE_LEVEL_HIGH: 96660242db1SMaxime Ripard mode = IRQ_LEVEL_HIGH; 96760242db1SMaxime Ripard break; 96860242db1SMaxime Ripard case IRQ_TYPE_LEVEL_LOW: 96960242db1SMaxime Ripard mode = IRQ_LEVEL_LOW; 97060242db1SMaxime Ripard break; 97160242db1SMaxime Ripard default: 97260242db1SMaxime Ripard return -EINVAL; 97360242db1SMaxime Ripard } 97460242db1SMaxime Ripard 975f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 9761bee963dSMaxime Ripard 977a0d6de9bSMaxime Ripard if (type & IRQ_TYPE_LEVEL_MASK) 978b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip, 979a0d6de9bSMaxime Ripard handle_fasteoi_irq, NULL); 980a0d6de9bSMaxime Ripard else 981b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip, 982a0d6de9bSMaxime Ripard handle_edge_irq, NULL); 983a0d6de9bSMaxime Ripard 9842aaaddffSMaxime Ripard regval = readl(pctl->membase + reg); 985d82f9401SHans de Goede regval &= ~(IRQ_CFG_IRQ_MASK << index); 9862aaaddffSMaxime Ripard writel(regval | (mode << index), pctl->membase + reg); 98760242db1SMaxime Ripard 988f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 98960242db1SMaxime Ripard 99060242db1SMaxime Ripard return 0; 99160242db1SMaxime Ripard } 99260242db1SMaxime Ripard 993645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d) 99460242db1SMaxime Ripard { 99560242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 9964b0d6c5aSIcenowy Zheng u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq); 99760242db1SMaxime Ripard u8 status_idx = sunxi_irq_status_offset(d->hwirq); 99860242db1SMaxime Ripard 99960242db1SMaxime Ripard /* Clear the IRQ */ 100060242db1SMaxime Ripard writel(1 << status_idx, pctl->membase + status_reg); 100160242db1SMaxime Ripard } 100260242db1SMaxime Ripard 100360242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d) 100460242db1SMaxime Ripard { 100560242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 10064b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); 100760242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 10081bee963dSMaxime Ripard unsigned long flags; 100960242db1SMaxime Ripard u32 val; 101060242db1SMaxime Ripard 1011f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 10121bee963dSMaxime Ripard 101360242db1SMaxime Ripard /* Mask the IRQ */ 101460242db1SMaxime Ripard val = readl(pctl->membase + reg); 101560242db1SMaxime Ripard writel(val & ~(1 << idx), pctl->membase + reg); 10161bee963dSMaxime Ripard 1017f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 101860242db1SMaxime Ripard } 101960242db1SMaxime Ripard 102060242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d) 102160242db1SMaxime Ripard { 102260242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 10234b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); 102460242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 10251bee963dSMaxime Ripard unsigned long flags; 102660242db1SMaxime Ripard u32 val; 102760242db1SMaxime Ripard 1028f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 10291bee963dSMaxime Ripard 103060242db1SMaxime Ripard /* Unmask the IRQ */ 103160242db1SMaxime Ripard val = readl(pctl->membase + reg); 103260242db1SMaxime Ripard writel(val | (1 << idx), pctl->membase + reg); 10331bee963dSMaxime Ripard 1034f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 103560242db1SMaxime Ripard } 103660242db1SMaxime Ripard 1037d61e23e5SHans de Goede static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) 1038d61e23e5SHans de Goede { 1039d61e23e5SHans de Goede sunxi_pinctrl_irq_ack(d); 1040d61e23e5SHans de Goede sunxi_pinctrl_irq_unmask(d); 1041d61e23e5SHans de Goede } 1042d61e23e5SHans de Goede 1043f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = { 1044fb5b7788SMaxime Ripard .name = "sunxi_pio_edge", 1045645ec714SMaxime Ripard .irq_ack = sunxi_pinctrl_irq_ack, 104660242db1SMaxime Ripard .irq_mask = sunxi_pinctrl_irq_mask, 104760242db1SMaxime Ripard .irq_unmask = sunxi_pinctrl_irq_unmask, 1048fea6d8efSHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 1049f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 105060242db1SMaxime Ripard .irq_set_type = sunxi_pinctrl_irq_set_type, 1051578c0a87SChen-Yu Tsai .flags = IRQCHIP_SKIP_SET_WAKE, 105260242db1SMaxime Ripard }; 105360242db1SMaxime Ripard 1054f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = { 1055fb5b7788SMaxime Ripard .name = "sunxi_pio_level", 1056f4c51c10SHans de Goede .irq_eoi = sunxi_pinctrl_irq_ack, 1057f4c51c10SHans de Goede .irq_mask = sunxi_pinctrl_irq_mask, 1058f4c51c10SHans de Goede .irq_unmask = sunxi_pinctrl_irq_unmask, 1059d61e23e5SHans de Goede /* Define irq_enable / disable to avoid spurious irqs for drivers 1060d61e23e5SHans de Goede * using these to suppress irqs while they clear the irq source */ 1061d61e23e5SHans de Goede .irq_enable = sunxi_pinctrl_irq_ack_unmask, 1062d61e23e5SHans de Goede .irq_disable = sunxi_pinctrl_irq_mask, 1063f4c51c10SHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 1064f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 1065f4c51c10SHans de Goede .irq_set_type = sunxi_pinctrl_irq_set_type, 1066f4c51c10SHans de Goede .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED | 1067f4c51c10SHans de Goede IRQCHIP_EOI_IF_HANDLED, 106860242db1SMaxime Ripard }; 106960242db1SMaxime Ripard 1070d8323c6bSMaxime Ripard static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, 1071d8323c6bSMaxime Ripard struct device_node *node, 1072d8323c6bSMaxime Ripard const u32 *intspec, 1073d8323c6bSMaxime Ripard unsigned int intsize, 1074d8323c6bSMaxime Ripard unsigned long *out_hwirq, 1075d8323c6bSMaxime Ripard unsigned int *out_type) 1076d8323c6bSMaxime Ripard { 10778297992cSHans de Goede struct sunxi_pinctrl *pctl = d->host_data; 1078d8323c6bSMaxime Ripard struct sunxi_desc_function *desc; 1079d8323c6bSMaxime Ripard int pin, base; 1080d8323c6bSMaxime Ripard 1081d8323c6bSMaxime Ripard if (intsize < 3) 1082d8323c6bSMaxime Ripard return -EINVAL; 1083d8323c6bSMaxime Ripard 1084d8323c6bSMaxime Ripard base = PINS_PER_BANK * intspec[0]; 10858297992cSHans de Goede pin = pctl->desc->pin_base + base + intspec[1]; 1086d8323c6bSMaxime Ripard 10878297992cSHans de Goede desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq"); 1088d8323c6bSMaxime Ripard if (!desc) 1089d8323c6bSMaxime Ripard return -EINVAL; 1090d8323c6bSMaxime Ripard 1091d8323c6bSMaxime Ripard *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; 1092d8323c6bSMaxime Ripard *out_type = intspec[2]; 1093d8323c6bSMaxime Ripard 1094d8323c6bSMaxime Ripard return 0; 1095d8323c6bSMaxime Ripard } 1096d8323c6bSMaxime Ripard 10972421dfd6STobias Klauser static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { 1098d8323c6bSMaxime Ripard .xlate = sunxi_pinctrl_irq_of_xlate, 1099d8323c6bSMaxime Ripard }; 1100d8323c6bSMaxime Ripard 1101bd0b9ac4SThomas Gleixner static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) 110260242db1SMaxime Ripard { 1103eeef97b1SThomas Gleixner unsigned int irq = irq_desc_get_irq(desc); 11045663bb27SJiang Liu struct irq_chip *chip = irq_desc_get_chip(desc); 11055663bb27SJiang Liu struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); 1106aebdc8abSMaxime Ripard unsigned long bank, reg, val; 110760242db1SMaxime Ripard 1108aebdc8abSMaxime Ripard for (bank = 0; bank < pctl->desc->irq_banks; bank++) 1109aebdc8abSMaxime Ripard if (irq == pctl->irq[bank]) 1110aebdc8abSMaxime Ripard break; 111160242db1SMaxime Ripard 1112aebdc8abSMaxime Ripard if (bank == pctl->desc->irq_banks) 1113aebdc8abSMaxime Ripard return; 1114aebdc8abSMaxime Ripard 11154b0d6c5aSIcenowy Zheng reg = sunxi_irq_status_reg_from_bank(pctl->desc, bank); 1116aebdc8abSMaxime Ripard val = readl(pctl->membase + reg); 111760242db1SMaxime Ripard 1118aebdc8abSMaxime Ripard if (val) { 111960242db1SMaxime Ripard int irqoffset; 112060242db1SMaxime Ripard 1121905a5117SChen-Yu Tsai chained_irq_enter(chip, desc); 1122aebdc8abSMaxime Ripard for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) { 1123aebdc8abSMaxime Ripard int pin_irq = irq_find_mapping(pctl->domain, 1124aebdc8abSMaxime Ripard bank * IRQ_PER_BANK + irqoffset); 112560242db1SMaxime Ripard generic_handle_irq(pin_irq); 112660242db1SMaxime Ripard } 1127905a5117SChen-Yu Tsai chained_irq_exit(chip, desc); 112860242db1SMaxime Ripard } 112960242db1SMaxime Ripard } 113060242db1SMaxime Ripard 11310e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, 11320e37f88dSMaxime Ripard const char *name) 11330e37f88dSMaxime Ripard { 11340e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 11350e37f88dSMaxime Ripard 11360e37f88dSMaxime Ripard while (func->name) { 11370e37f88dSMaxime Ripard /* function already there */ 11380e37f88dSMaxime Ripard if (strcmp(func->name, name) == 0) { 11390e37f88dSMaxime Ripard func->ngroups++; 11400e37f88dSMaxime Ripard return -EEXIST; 11410e37f88dSMaxime Ripard } 11420e37f88dSMaxime Ripard func++; 11430e37f88dSMaxime Ripard } 11440e37f88dSMaxime Ripard 11450e37f88dSMaxime Ripard func->name = name; 11460e37f88dSMaxime Ripard func->ngroups = 1; 11470e37f88dSMaxime Ripard 11480e37f88dSMaxime Ripard pctl->nfunctions++; 11490e37f88dSMaxime Ripard 11500e37f88dSMaxime Ripard return 0; 11510e37f88dSMaxime Ripard } 11520e37f88dSMaxime Ripard 11530e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev) 11540e37f88dSMaxime Ripard { 11550e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); 1156a93a676bSChristophe JAILLET void *ptr; 11570e37f88dSMaxime Ripard int i; 11580e37f88dSMaxime Ripard 1159578db85fSMaxime Ripard /* 1160578db85fSMaxime Ripard * Allocate groups 1161578db85fSMaxime Ripard * 1162578db85fSMaxime Ripard * We assume that the number of groups is the number of pins 1163578db85fSMaxime Ripard * given in the data array. 11640e37f88dSMaxime Ripard 1165578db85fSMaxime Ripard * This will not always be true, since some pins might not be 1166578db85fSMaxime Ripard * available in the current variant, but fortunately for us, 1167578db85fSMaxime Ripard * this means that the number of pins is the maximum group 1168578db85fSMaxime Ripard * number we will ever see. 1169578db85fSMaxime Ripard */ 1170a86854d0SKees Cook pctl->groups = devm_kcalloc(&pdev->dev, 1171a86854d0SKees Cook pctl->desc->npins, sizeof(*pctl->groups), 11720e37f88dSMaxime Ripard GFP_KERNEL); 11730e37f88dSMaxime Ripard if (!pctl->groups) 11740e37f88dSMaxime Ripard return -ENOMEM; 11750e37f88dSMaxime Ripard 11760e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 11770e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1178578db85fSMaxime Ripard struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; 1179578db85fSMaxime Ripard 1180578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1181578db85fSMaxime Ripard continue; 11820e37f88dSMaxime Ripard 11830e37f88dSMaxime Ripard group->name = pin->pin.name; 11840e37f88dSMaxime Ripard group->pin = pin->pin.number; 1185578db85fSMaxime Ripard 1186578db85fSMaxime Ripard /* And now we count the actual number of pins / groups */ 1187578db85fSMaxime Ripard pctl->ngroups++; 11880e37f88dSMaxime Ripard } 11890e37f88dSMaxime Ripard 11900e37f88dSMaxime Ripard /* 11910e37f88dSMaxime Ripard * We suppose that we won't have any more functions than pins, 11920e37f88dSMaxime Ripard * we'll reallocate that later anyway 11930e37f88dSMaxime Ripard */ 1194a4925311SYueHaibing pctl->functions = kcalloc(pctl->ngroups, 1195a86854d0SKees Cook sizeof(*pctl->functions), 11960e37f88dSMaxime Ripard GFP_KERNEL); 11970e37f88dSMaxime Ripard if (!pctl->functions) 11980e37f88dSMaxime Ripard return -ENOMEM; 11990e37f88dSMaxime Ripard 12000e37f88dSMaxime Ripard /* Count functions and their associated groups */ 12010e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 12020e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1203578db85fSMaxime Ripard struct sunxi_desc_function *func; 12040e37f88dSMaxime Ripard 1205578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1206578db85fSMaxime Ripard continue; 1207578db85fSMaxime Ripard 1208578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 1209578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1210578db85fSMaxime Ripard continue; 1211578db85fSMaxime Ripard 1212d54e9a28SChen-Yu Tsai /* Create interrupt mapping while we're at it */ 1213aebdc8abSMaxime Ripard if (!strcmp(func->name, "irq")) { 1214aebdc8abSMaxime Ripard int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; 1215aebdc8abSMaxime Ripard pctl->irq_array[irqnum] = pin->pin.number; 1216aebdc8abSMaxime Ripard } 1217aebdc8abSMaxime Ripard 12180e37f88dSMaxime Ripard sunxi_pinctrl_add_function(pctl, func->name); 12190e37f88dSMaxime Ripard } 12200e37f88dSMaxime Ripard } 12210e37f88dSMaxime Ripard 1222578db85fSMaxime Ripard /* And now allocated and fill the array for real */ 1223a93a676bSChristophe JAILLET ptr = krealloc(pctl->functions, 12240e37f88dSMaxime Ripard pctl->nfunctions * sizeof(*pctl->functions), 12250e37f88dSMaxime Ripard GFP_KERNEL); 1226a93a676bSChristophe JAILLET if (!ptr) { 1227578db85fSMaxime Ripard kfree(pctl->functions); 1228a93a676bSChristophe JAILLET pctl->functions = NULL; 1229578db85fSMaxime Ripard return -ENOMEM; 1230578db85fSMaxime Ripard } 1231a93a676bSChristophe JAILLET pctl->functions = ptr; 12320e37f88dSMaxime Ripard 12330e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 12340e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1235578db85fSMaxime Ripard struct sunxi_desc_function *func; 12360e37f88dSMaxime Ripard 1237578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1238578db85fSMaxime Ripard continue; 1239578db85fSMaxime Ripard 1240578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 12410e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func_item; 12420e37f88dSMaxime Ripard const char **func_grp; 12430e37f88dSMaxime Ripard 1244578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1245578db85fSMaxime Ripard continue; 1246578db85fSMaxime Ripard 12470e37f88dSMaxime Ripard func_item = sunxi_pinctrl_find_function_by_name(pctl, 12480e37f88dSMaxime Ripard func->name); 1249a4925311SYueHaibing if (!func_item) { 1250a4925311SYueHaibing kfree(pctl->functions); 12510e37f88dSMaxime Ripard return -EINVAL; 1252a4925311SYueHaibing } 12530e37f88dSMaxime Ripard 12540e37f88dSMaxime Ripard if (!func_item->groups) { 12550e37f88dSMaxime Ripard func_item->groups = 1256a86854d0SKees Cook devm_kcalloc(&pdev->dev, 1257a86854d0SKees Cook func_item->ngroups, 1258a86854d0SKees Cook sizeof(*func_item->groups), 12590e37f88dSMaxime Ripard GFP_KERNEL); 1260a4925311SYueHaibing if (!func_item->groups) { 1261a4925311SYueHaibing kfree(pctl->functions); 12620e37f88dSMaxime Ripard return -ENOMEM; 12630e37f88dSMaxime Ripard } 1264a4925311SYueHaibing } 12650e37f88dSMaxime Ripard 12660e37f88dSMaxime Ripard func_grp = func_item->groups; 12670e37f88dSMaxime Ripard while (*func_grp) 12680e37f88dSMaxime Ripard func_grp++; 12690e37f88dSMaxime Ripard 12700e37f88dSMaxime Ripard *func_grp = pin->pin.name; 12710e37f88dSMaxime Ripard } 12720e37f88dSMaxime Ripard } 12730e37f88dSMaxime Ripard 12740e37f88dSMaxime Ripard return 0; 12750e37f88dSMaxime Ripard } 12760e37f88dSMaxime Ripard 12777c926492SMaxime Ripard static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff) 12787c926492SMaxime Ripard { 12797c926492SMaxime Ripard unsigned long clock = clk_get_rate(clk); 1280d8a22212SArnd Bergmann unsigned int best_diff, best_div; 12817c926492SMaxime Ripard int i; 12827c926492SMaxime Ripard 1283d8a22212SArnd Bergmann best_diff = abs(freq - clock); 1284d8a22212SArnd Bergmann best_div = 0; 1285d8a22212SArnd Bergmann 1286d8a22212SArnd Bergmann for (i = 1; i < 8; i++) { 12877c926492SMaxime Ripard int cur_diff = abs(freq - (clock >> i)); 12887c926492SMaxime Ripard 12897c926492SMaxime Ripard if (cur_diff < best_diff) { 12907c926492SMaxime Ripard best_diff = cur_diff; 12917c926492SMaxime Ripard best_div = i; 12927c926492SMaxime Ripard } 12937c926492SMaxime Ripard } 12947c926492SMaxime Ripard 12957c926492SMaxime Ripard *diff = best_diff; 12967c926492SMaxime Ripard return best_div; 12977c926492SMaxime Ripard } 12987c926492SMaxime Ripard 12997c926492SMaxime Ripard static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, 13007c926492SMaxime Ripard struct device_node *node) 13017c926492SMaxime Ripard { 13027c926492SMaxime Ripard unsigned int hosc_diff, losc_diff; 13037c926492SMaxime Ripard unsigned int hosc_div, losc_div; 13047c926492SMaxime Ripard struct clk *hosc, *losc; 13057c926492SMaxime Ripard u8 div, src; 13067c926492SMaxime Ripard int i, ret; 13077c926492SMaxime Ripard 13087c926492SMaxime Ripard /* Deal with old DTs that didn't have the oscillators */ 1309470b73a3SGeert Uytterhoeven if (of_clk_get_parent_count(node) != 3) 13107c926492SMaxime Ripard return 0; 13117c926492SMaxime Ripard 13127c926492SMaxime Ripard /* If we don't have any setup, bail out */ 13137c926492SMaxime Ripard if (!of_find_property(node, "input-debounce", NULL)) 13147c926492SMaxime Ripard return 0; 13157c926492SMaxime Ripard 13167c926492SMaxime Ripard losc = devm_clk_get(pctl->dev, "losc"); 13177c926492SMaxime Ripard if (IS_ERR(losc)) 13187c926492SMaxime Ripard return PTR_ERR(losc); 13197c926492SMaxime Ripard 13207c926492SMaxime Ripard hosc = devm_clk_get(pctl->dev, "hosc"); 13217c926492SMaxime Ripard if (IS_ERR(hosc)) 13227c926492SMaxime Ripard return PTR_ERR(hosc); 13237c926492SMaxime Ripard 13247c926492SMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 13257c926492SMaxime Ripard unsigned long debounce_freq; 13267c926492SMaxime Ripard u32 debounce; 13277c926492SMaxime Ripard 13287c926492SMaxime Ripard ret = of_property_read_u32_index(node, "input-debounce", 13297c926492SMaxime Ripard i, &debounce); 13307c926492SMaxime Ripard if (ret) 13317c926492SMaxime Ripard return ret; 13327c926492SMaxime Ripard 13337c926492SMaxime Ripard if (!debounce) 13347c926492SMaxime Ripard continue; 13357c926492SMaxime Ripard 13367c926492SMaxime Ripard debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce); 13377c926492SMaxime Ripard losc_div = sunxi_pinctrl_get_debounce_div(losc, 13387c926492SMaxime Ripard debounce_freq, 13397c926492SMaxime Ripard &losc_diff); 13407c926492SMaxime Ripard 13417c926492SMaxime Ripard hosc_div = sunxi_pinctrl_get_debounce_div(hosc, 13427c926492SMaxime Ripard debounce_freq, 13437c926492SMaxime Ripard &hosc_diff); 13447c926492SMaxime Ripard 13457c926492SMaxime Ripard if (hosc_diff < losc_diff) { 13467c926492SMaxime Ripard div = hosc_div; 13477c926492SMaxime Ripard src = 1; 13487c926492SMaxime Ripard } else { 13497c926492SMaxime Ripard div = losc_div; 13507c926492SMaxime Ripard src = 0; 13517c926492SMaxime Ripard } 13527c926492SMaxime Ripard 13537c926492SMaxime Ripard writel(src | div << 4, 13547c926492SMaxime Ripard pctl->membase + 13554b0d6c5aSIcenowy Zheng sunxi_irq_debounce_reg_from_bank(pctl->desc, i)); 13567c926492SMaxime Ripard } 13577c926492SMaxime Ripard 13587c926492SMaxime Ripard return 0; 13597c926492SMaxime Ripard } 13607c926492SMaxime Ripard 1361578db85fSMaxime Ripard int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, 1362578db85fSMaxime Ripard const struct sunxi_pinctrl_desc *desc, 1363578db85fSMaxime Ripard unsigned long variant) 13640e37f88dSMaxime Ripard { 13650e37f88dSMaxime Ripard struct device_node *node = pdev->dev.of_node; 1366ba6764d5SMaxime Ripard struct pinctrl_desc *pctrl_desc; 13670e37f88dSMaxime Ripard struct pinctrl_pin_desc *pins; 13680e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl; 1369aae842a3SMaxime Ripard struct pinmux_ops *pmxops; 13704409cafcSMaxime Ripard struct resource *res; 1371578db85fSMaxime Ripard int i, ret, last_pin, pin_idx; 1372950707c0SEmilio López struct clk *clk; 13730e37f88dSMaxime Ripard 13740e37f88dSMaxime Ripard pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 13750e37f88dSMaxime Ripard if (!pctl) 13760e37f88dSMaxime Ripard return -ENOMEM; 13770e37f88dSMaxime Ripard platform_set_drvdata(pdev, pctl); 13780e37f88dSMaxime Ripard 1379f658ed36SJulia Cartwright raw_spin_lock_init(&pctl->lock); 13801bee963dSMaxime Ripard 13814409cafcSMaxime Ripard res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 13824409cafcSMaxime Ripard pctl->membase = devm_ioremap_resource(&pdev->dev, res); 13834409cafcSMaxime Ripard if (IS_ERR(pctl->membase)) 13844409cafcSMaxime Ripard return PTR_ERR(pctl->membase); 13850e37f88dSMaxime Ripard 1386ba6764d5SMaxime Ripard pctl->dev = &pdev->dev; 13872284ba6bSMaxime Ripard pctl->desc = desc; 1388578db85fSMaxime Ripard pctl->variant = variant; 13890e37f88dSMaxime Ripard 1390aebdc8abSMaxime Ripard pctl->irq_array = devm_kcalloc(&pdev->dev, 1391aebdc8abSMaxime Ripard IRQ_PER_BANK * pctl->desc->irq_banks, 1392aebdc8abSMaxime Ripard sizeof(*pctl->irq_array), 1393aebdc8abSMaxime Ripard GFP_KERNEL); 1394aebdc8abSMaxime Ripard if (!pctl->irq_array) 1395aebdc8abSMaxime Ripard return -ENOMEM; 1396aebdc8abSMaxime Ripard 13970e37f88dSMaxime Ripard ret = sunxi_pinctrl_build_state(pdev); 13980e37f88dSMaxime Ripard if (ret) { 13990e37f88dSMaxime Ripard dev_err(&pdev->dev, "dt probe failed: %d\n", ret); 14000e37f88dSMaxime Ripard return ret; 14010e37f88dSMaxime Ripard } 14020e37f88dSMaxime Ripard 1403a86854d0SKees Cook pins = devm_kcalloc(&pdev->dev, 1404a86854d0SKees Cook pctl->desc->npins, sizeof(*pins), 14050e37f88dSMaxime Ripard GFP_KERNEL); 14060e37f88dSMaxime Ripard if (!pins) 14070e37f88dSMaxime Ripard return -ENOMEM; 14080e37f88dSMaxime Ripard 1409578db85fSMaxime Ripard for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { 1410578db85fSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1411578db85fSMaxime Ripard 1412578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1413578db85fSMaxime Ripard continue; 1414578db85fSMaxime Ripard 1415578db85fSMaxime Ripard pins[pin_idx++] = pin->pin; 1416578db85fSMaxime Ripard } 14170e37f88dSMaxime Ripard 1418ba6764d5SMaxime Ripard pctrl_desc = devm_kzalloc(&pdev->dev, 1419ba6764d5SMaxime Ripard sizeof(*pctrl_desc), 1420ba6764d5SMaxime Ripard GFP_KERNEL); 1421ba6764d5SMaxime Ripard if (!pctrl_desc) 1422ba6764d5SMaxime Ripard return -ENOMEM; 1423ba6764d5SMaxime Ripard 1424ba6764d5SMaxime Ripard pctrl_desc->name = dev_name(&pdev->dev); 1425ba6764d5SMaxime Ripard pctrl_desc->owner = THIS_MODULE; 1426ba6764d5SMaxime Ripard pctrl_desc->pins = pins; 1427578db85fSMaxime Ripard pctrl_desc->npins = pctl->ngroups; 1428ba6764d5SMaxime Ripard pctrl_desc->confops = &sunxi_pconf_ops; 1429ba6764d5SMaxime Ripard pctrl_desc->pctlops = &sunxi_pctrl_ops; 1430aae842a3SMaxime Ripard 1431aae842a3SMaxime Ripard pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops), 1432aae842a3SMaxime Ripard GFP_KERNEL); 1433aae842a3SMaxime Ripard if (!pmxops) 1434aae842a3SMaxime Ripard return -ENOMEM; 1435aae842a3SMaxime Ripard 1436aae842a3SMaxime Ripard if (desc->disable_strict_mode) 1437aae842a3SMaxime Ripard pmxops->strict = false; 1438aae842a3SMaxime Ripard 1439aae842a3SMaxime Ripard pctrl_desc->pmxops = pmxops; 1440ba6764d5SMaxime Ripard 144145078ea0SLaxman Dewangan pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); 1442323de9efSMasahiro Yamada if (IS_ERR(pctl->pctl_dev)) { 14430e37f88dSMaxime Ripard dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); 1444323de9efSMasahiro Yamada return PTR_ERR(pctl->pctl_dev); 14450e37f88dSMaxime Ripard } 14460e37f88dSMaxime Ripard 144708e9e614SMaxime Ripard pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); 144845078ea0SLaxman Dewangan if (!pctl->chip) 144945078ea0SLaxman Dewangan return -ENOMEM; 145008e9e614SMaxime Ripard 145108e9e614SMaxime Ripard last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; 1452d83c82ceSBoris BREZILLON pctl->chip->owner = THIS_MODULE; 1453*fb7dea60SMaxime Ripard pctl->chip->request = gpiochip_generic_request; 1454*fb7dea60SMaxime Ripard pctl->chip->free = gpiochip_generic_free; 1455*fb7dea60SMaxime Ripard pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input; 1456*fb7dea60SMaxime Ripard pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output; 1457*fb7dea60SMaxime Ripard pctl->chip->get = sunxi_pinctrl_gpio_get; 1458*fb7dea60SMaxime Ripard pctl->chip->set = sunxi_pinctrl_gpio_set; 1459*fb7dea60SMaxime Ripard pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate; 1460*fb7dea60SMaxime Ripard pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq; 1461*fb7dea60SMaxime Ripard pctl->chip->of_gpio_n_cells = 3; 1462*fb7dea60SMaxime Ripard pctl->chip->can_sleep = false; 1463d83c82ceSBoris BREZILLON pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) - 1464d83c82ceSBoris BREZILLON pctl->desc->pin_base; 146508e9e614SMaxime Ripard pctl->chip->label = dev_name(&pdev->dev); 146658383c78SLinus Walleij pctl->chip->parent = &pdev->dev; 1467d83c82ceSBoris BREZILLON pctl->chip->base = pctl->desc->pin_base; 146808e9e614SMaxime Ripard 146988057d6eSLinus Walleij ret = gpiochip_add_data(pctl->chip, pctl); 147008e9e614SMaxime Ripard if (ret) 147145078ea0SLaxman Dewangan return ret; 147208e9e614SMaxime Ripard 147308e9e614SMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 147408e9e614SMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 147508e9e614SMaxime Ripard 147608e9e614SMaxime Ripard ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), 1477343f1327SChen-Yu Tsai pin->pin.number - pctl->desc->pin_base, 147808e9e614SMaxime Ripard pin->pin.number, 1); 147908e9e614SMaxime Ripard if (ret) 148008e9e614SMaxime Ripard goto gpiochip_error; 148108e9e614SMaxime Ripard } 148208e9e614SMaxime Ripard 148310e3a88bSGeert Uytterhoeven ret = of_clk_get_parent_count(node); 1484a34ea4b4SAndre Przywara clk = devm_clk_get(&pdev->dev, ret == 1 ? NULL : "apb"); 1485d72f88a4SWei Yongjun if (IS_ERR(clk)) { 1486d72f88a4SWei Yongjun ret = PTR_ERR(clk); 1487950707c0SEmilio López goto gpiochip_error; 1488d72f88a4SWei Yongjun } 1489950707c0SEmilio López 14906415093fSBoris BREZILLON ret = clk_prepare_enable(clk); 14916415093fSBoris BREZILLON if (ret) 14926415093fSBoris BREZILLON goto gpiochip_error; 1493950707c0SEmilio López 1494aebdc8abSMaxime Ripard pctl->irq = devm_kcalloc(&pdev->dev, 1495aebdc8abSMaxime Ripard pctl->desc->irq_banks, 1496aebdc8abSMaxime Ripard sizeof(*pctl->irq), 1497aebdc8abSMaxime Ripard GFP_KERNEL); 149860242db1SMaxime Ripard if (!pctl->irq) { 1499aebdc8abSMaxime Ripard ret = -ENOMEM; 1500dc969106SMaxime Ripard goto clk_error; 150160242db1SMaxime Ripard } 150260242db1SMaxime Ripard 1503aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1504aebdc8abSMaxime Ripard pctl->irq[i] = platform_get_irq(pdev, i); 1505aebdc8abSMaxime Ripard if (pctl->irq[i] < 0) { 1506aebdc8abSMaxime Ripard ret = pctl->irq[i]; 1507aebdc8abSMaxime Ripard goto clk_error; 1508aebdc8abSMaxime Ripard } 1509aebdc8abSMaxime Ripard } 1510aebdc8abSMaxime Ripard 1511aebdc8abSMaxime Ripard pctl->domain = irq_domain_add_linear(node, 1512aebdc8abSMaxime Ripard pctl->desc->irq_banks * IRQ_PER_BANK, 1513d8323c6bSMaxime Ripard &sunxi_pinctrl_irq_domain_ops, 1514d8323c6bSMaxime Ripard pctl); 151560242db1SMaxime Ripard if (!pctl->domain) { 151660242db1SMaxime Ripard dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); 151760242db1SMaxime Ripard ret = -ENOMEM; 1518dc969106SMaxime Ripard goto clk_error; 151960242db1SMaxime Ripard } 152060242db1SMaxime Ripard 1521aebdc8abSMaxime Ripard for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) { 152260242db1SMaxime Ripard int irqno = irq_create_mapping(pctl->domain, i); 152360242db1SMaxime Ripard 1524f4c51c10SHans de Goede irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip, 1525f4c51c10SHans de Goede handle_edge_irq); 152660242db1SMaxime Ripard irq_set_chip_data(irqno, pctl); 15275c99c0ffSJavier Martinez Canillas } 152860242db1SMaxime Ripard 1529aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1530f4c51c10SHans de Goede /* Mask and clear all IRQs before registering a handler */ 15314b0d6c5aSIcenowy Zheng writel(0, pctl->membase + 15324b0d6c5aSIcenowy Zheng sunxi_irq_ctrl_reg_from_bank(pctl->desc, i)); 1533f4c51c10SHans de Goede writel(0xffffffff, 15344b0d6c5aSIcenowy Zheng pctl->membase + 15354b0d6c5aSIcenowy Zheng sunxi_irq_status_reg_from_bank(pctl->desc, i)); 1536f4c51c10SHans de Goede 1537ef80e87dSThomas Gleixner irq_set_chained_handler_and_data(pctl->irq[i], 1538ef80e87dSThomas Gleixner sunxi_pinctrl_irq_handler, 1539ef80e87dSThomas Gleixner pctl); 1540aebdc8abSMaxime Ripard } 154160242db1SMaxime Ripard 15427c926492SMaxime Ripard sunxi_pinctrl_setup_debounce(pctl, node); 15437c926492SMaxime Ripard 154408e9e614SMaxime Ripard dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); 15450e37f88dSMaxime Ripard 15460e37f88dSMaxime Ripard return 0; 154708e9e614SMaxime Ripard 1548e2bddc6aSBoris BREZILLON clk_error: 1549e2bddc6aSBoris BREZILLON clk_disable_unprepare(clk); 155008e9e614SMaxime Ripard gpiochip_error: 1551b4e7c55dSabdoulaye berthe gpiochip_remove(pctl->chip); 155208e9e614SMaxime Ripard return ret; 15530e37f88dSMaxime Ripard } 1554