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> 16a59c99d9SSamuel Holland #include <linux/interrupt.h> 1760242db1SMaxime Ripard #include <linux/irqdomain.h> 18905a5117SChen-Yu Tsai #include <linux/irqchip/chained_irq.h> 19bcc76199SPaul Gortmaker #include <linux/export.h> 200e37f88dSMaxime Ripard #include <linux/of.h> 2110e3a88bSGeert Uytterhoeven #include <linux/of_clk.h> 220e37f88dSMaxime Ripard #include <linux/of_address.h> 230e37f88dSMaxime Ripard #include <linux/of_device.h> 2460242db1SMaxime Ripard #include <linux/of_irq.h> 250e37f88dSMaxime Ripard #include <linux/pinctrl/consumer.h> 260e37f88dSMaxime Ripard #include <linux/pinctrl/machine.h> 270e37f88dSMaxime Ripard #include <linux/pinctrl/pinctrl.h> 280e37f88dSMaxime Ripard #include <linux/pinctrl/pinconf-generic.h> 290e37f88dSMaxime Ripard #include <linux/pinctrl/pinmux.h> 309a2a566aSMaxime Ripard #include <linux/regulator/consumer.h> 310e37f88dSMaxime Ripard #include <linux/platform_device.h> 320e37f88dSMaxime Ripard #include <linux/slab.h> 330e37f88dSMaxime Ripard 3442676fa4SMaxime Ripard #include <dt-bindings/pinctrl/sun4i-a10.h> 3542676fa4SMaxime Ripard 365f910777SMaxime Ripard #include "../core.h" 370e37f88dSMaxime Ripard #include "pinctrl-sunxi.h" 38eaa3d848SMaxime Ripard 39f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip; 40f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip; 41f4c51c10SHans de Goede 420e37f88dSMaxime Ripard static struct sunxi_pinctrl_group * 430e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group) 440e37f88dSMaxime Ripard { 450e37f88dSMaxime Ripard int i; 460e37f88dSMaxime Ripard 470e37f88dSMaxime Ripard for (i = 0; i < pctl->ngroups; i++) { 480e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = pctl->groups + i; 490e37f88dSMaxime Ripard 500e37f88dSMaxime Ripard if (!strcmp(grp->name, group)) 510e37f88dSMaxime Ripard return grp; 520e37f88dSMaxime Ripard } 530e37f88dSMaxime Ripard 540e37f88dSMaxime Ripard return NULL; 550e37f88dSMaxime Ripard } 560e37f88dSMaxime Ripard 570e37f88dSMaxime Ripard static struct sunxi_pinctrl_function * 580e37f88dSMaxime Ripard sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl, 590e37f88dSMaxime Ripard const char *name) 600e37f88dSMaxime Ripard { 610e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 620e37f88dSMaxime Ripard int i; 630e37f88dSMaxime Ripard 640e37f88dSMaxime Ripard for (i = 0; i < pctl->nfunctions; i++) { 650e37f88dSMaxime Ripard if (!func[i].name) 660e37f88dSMaxime Ripard break; 670e37f88dSMaxime Ripard 680e37f88dSMaxime Ripard if (!strcmp(func[i].name, name)) 690e37f88dSMaxime Ripard return func + i; 700e37f88dSMaxime Ripard } 710e37f88dSMaxime Ripard 720e37f88dSMaxime Ripard return NULL; 730e37f88dSMaxime Ripard } 740e37f88dSMaxime Ripard 750e37f88dSMaxime Ripard static struct sunxi_desc_function * 760e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, 770e37f88dSMaxime Ripard const char *pin_name, 780e37f88dSMaxime Ripard const char *func_name) 790e37f88dSMaxime Ripard { 800e37f88dSMaxime Ripard int i; 810e37f88dSMaxime Ripard 820e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 830e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 840e37f88dSMaxime Ripard 850e37f88dSMaxime Ripard if (!strcmp(pin->pin.name, pin_name)) { 860e37f88dSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 870e37f88dSMaxime Ripard 880e37f88dSMaxime Ripard while (func->name) { 8932e21f08Shao_zhang if (!strcmp(func->name, func_name) && 9032e21f08Shao_zhang (!func->variant || 9132e21f08Shao_zhang func->variant & pctl->variant)) 920e37f88dSMaxime Ripard return func; 930e37f88dSMaxime Ripard 940e37f88dSMaxime Ripard func++; 950e37f88dSMaxime Ripard } 960e37f88dSMaxime Ripard } 970e37f88dSMaxime Ripard } 980e37f88dSMaxime Ripard 990e37f88dSMaxime Ripard return NULL; 1000e37f88dSMaxime Ripard } 1010e37f88dSMaxime Ripard 102814d4f2eSMaxime Ripard static struct sunxi_desc_function * 103814d4f2eSMaxime Ripard sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl, 104814d4f2eSMaxime Ripard const u16 pin_num, 105814d4f2eSMaxime Ripard const char *func_name) 106814d4f2eSMaxime Ripard { 107814d4f2eSMaxime Ripard int i; 108814d4f2eSMaxime Ripard 109814d4f2eSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 110814d4f2eSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 111814d4f2eSMaxime Ripard 112814d4f2eSMaxime Ripard if (pin->pin.number == pin_num) { 113814d4f2eSMaxime Ripard struct sunxi_desc_function *func = pin->functions; 114814d4f2eSMaxime Ripard 115814d4f2eSMaxime Ripard while (func->name) { 116814d4f2eSMaxime Ripard if (!strcmp(func->name, func_name)) 117814d4f2eSMaxime Ripard return func; 118814d4f2eSMaxime Ripard 119814d4f2eSMaxime Ripard func++; 120814d4f2eSMaxime Ripard } 121814d4f2eSMaxime Ripard } 122814d4f2eSMaxime Ripard } 123814d4f2eSMaxime Ripard 124814d4f2eSMaxime Ripard return NULL; 125814d4f2eSMaxime Ripard } 126814d4f2eSMaxime Ripard 1270e37f88dSMaxime Ripard static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 1280e37f88dSMaxime Ripard { 1290e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1300e37f88dSMaxime Ripard 1310e37f88dSMaxime Ripard return pctl->ngroups; 1320e37f88dSMaxime Ripard } 1330e37f88dSMaxime Ripard 1340e37f88dSMaxime Ripard static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev, 1350e37f88dSMaxime Ripard unsigned group) 1360e37f88dSMaxime Ripard { 1370e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1380e37f88dSMaxime Ripard 1390e37f88dSMaxime Ripard return pctl->groups[group].name; 1400e37f88dSMaxime Ripard } 1410e37f88dSMaxime Ripard 1420e37f88dSMaxime Ripard static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 1430e37f88dSMaxime Ripard unsigned group, 1440e37f88dSMaxime Ripard const unsigned **pins, 1450e37f88dSMaxime Ripard unsigned *num_pins) 1460e37f88dSMaxime Ripard { 1470e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1480e37f88dSMaxime Ripard 1490e37f88dSMaxime Ripard *pins = (unsigned *)&pctl->groups[group].pin; 1500e37f88dSMaxime Ripard *num_pins = 1; 1510e37f88dSMaxime Ripard 1520e37f88dSMaxime Ripard return 0; 1530e37f88dSMaxime Ripard } 1540e37f88dSMaxime Ripard 155f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_bias_prop(struct device_node *node) 156f233dbcaSMaxime Ripard { 157cefbf1a1SMaxime Ripard return of_find_property(node, "bias-pull-up", NULL) || 158cefbf1a1SMaxime Ripard of_find_property(node, "bias-pull-down", NULL) || 159cefbf1a1SMaxime Ripard of_find_property(node, "bias-disable", NULL) || 160cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,pull", NULL); 161f233dbcaSMaxime Ripard } 162f233dbcaSMaxime Ripard 163f233dbcaSMaxime Ripard static bool sunxi_pctrl_has_drive_prop(struct device_node *node) 164f233dbcaSMaxime Ripard { 165cefbf1a1SMaxime Ripard return of_find_property(node, "drive-strength", NULL) || 166cefbf1a1SMaxime Ripard of_find_property(node, "allwinner,drive", NULL); 167f233dbcaSMaxime Ripard } 168f233dbcaSMaxime Ripard 169f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_bias_prop(struct device_node *node) 170f233dbcaSMaxime Ripard { 171f233dbcaSMaxime Ripard u32 val; 172f233dbcaSMaxime Ripard 173cefbf1a1SMaxime Ripard /* Try the new style binding */ 174cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-up", NULL)) 175cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 176cefbf1a1SMaxime Ripard 177cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-pull-down", NULL)) 178cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 179cefbf1a1SMaxime Ripard 180cefbf1a1SMaxime Ripard if (of_find_property(node, "bias-disable", NULL)) 181cefbf1a1SMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 182cefbf1a1SMaxime Ripard 183cefbf1a1SMaxime Ripard /* And fall back to the old binding */ 184f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,pull", &val)) 185f233dbcaSMaxime Ripard return -EINVAL; 186f233dbcaSMaxime Ripard 187f233dbcaSMaxime Ripard switch (val) { 18807fe64baSMaxime Ripard case SUN4I_PINCTRL_NO_PULL: 18907fe64baSMaxime Ripard return PIN_CONFIG_BIAS_DISABLE; 19042676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_UP: 191f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_UP; 19242676fa4SMaxime Ripard case SUN4I_PINCTRL_PULL_DOWN: 193f233dbcaSMaxime Ripard return PIN_CONFIG_BIAS_PULL_DOWN; 194f233dbcaSMaxime Ripard } 195f233dbcaSMaxime Ripard 196f233dbcaSMaxime Ripard return -EINVAL; 197f233dbcaSMaxime Ripard } 198f233dbcaSMaxime Ripard 199f233dbcaSMaxime Ripard static int sunxi_pctrl_parse_drive_prop(struct device_node *node) 200f233dbcaSMaxime Ripard { 201f233dbcaSMaxime Ripard u32 val; 202f233dbcaSMaxime Ripard 203cefbf1a1SMaxime Ripard /* Try the new style binding */ 204cefbf1a1SMaxime Ripard if (!of_property_read_u32(node, "drive-strength", &val)) { 205cefbf1a1SMaxime Ripard /* We can't go below 10mA ... */ 206cefbf1a1SMaxime Ripard if (val < 10) 207cefbf1a1SMaxime Ripard return -EINVAL; 208cefbf1a1SMaxime Ripard 209cefbf1a1SMaxime Ripard /* ... and only up to 40 mA ... */ 210cefbf1a1SMaxime Ripard if (val > 40) 211cefbf1a1SMaxime Ripard val = 40; 212cefbf1a1SMaxime Ripard 213cefbf1a1SMaxime Ripard /* by steps of 10 mA */ 214cefbf1a1SMaxime Ripard return rounddown(val, 10); 215cefbf1a1SMaxime Ripard } 216cefbf1a1SMaxime Ripard 217cefbf1a1SMaxime Ripard /* And then fall back to the old binding */ 218f233dbcaSMaxime Ripard if (of_property_read_u32(node, "allwinner,drive", &val)) 219f233dbcaSMaxime Ripard return -EINVAL; 220f233dbcaSMaxime Ripard 221f233dbcaSMaxime Ripard return (val + 1) * 10; 222f233dbcaSMaxime Ripard } 223f233dbcaSMaxime Ripard 224f233dbcaSMaxime Ripard static const char *sunxi_pctrl_parse_function_prop(struct device_node *node) 225f233dbcaSMaxime Ripard { 226f233dbcaSMaxime Ripard const char *function; 227f233dbcaSMaxime Ripard int ret; 228f233dbcaSMaxime Ripard 229cefbf1a1SMaxime Ripard /* Try the generic binding */ 230cefbf1a1SMaxime Ripard ret = of_property_read_string(node, "function", &function); 231cefbf1a1SMaxime Ripard if (!ret) 232cefbf1a1SMaxime Ripard return function; 233cefbf1a1SMaxime Ripard 234cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 235f233dbcaSMaxime Ripard ret = of_property_read_string(node, "allwinner,function", &function); 236f233dbcaSMaxime Ripard if (!ret) 237f233dbcaSMaxime Ripard return function; 238f233dbcaSMaxime Ripard 239f233dbcaSMaxime Ripard return NULL; 240f233dbcaSMaxime Ripard } 241f233dbcaSMaxime Ripard 242f233dbcaSMaxime Ripard static const char *sunxi_pctrl_find_pins_prop(struct device_node *node, 243f233dbcaSMaxime Ripard int *npins) 244f233dbcaSMaxime Ripard { 245f233dbcaSMaxime Ripard int count; 246f233dbcaSMaxime Ripard 247cefbf1a1SMaxime Ripard /* Try the generic binding */ 248cefbf1a1SMaxime Ripard count = of_property_count_strings(node, "pins"); 249cefbf1a1SMaxime Ripard if (count > 0) { 250cefbf1a1SMaxime Ripard *npins = count; 251cefbf1a1SMaxime Ripard return "pins"; 252cefbf1a1SMaxime Ripard } 253cefbf1a1SMaxime Ripard 254cefbf1a1SMaxime Ripard /* And fall back to our legacy one */ 255f233dbcaSMaxime Ripard count = of_property_count_strings(node, "allwinner,pins"); 256f233dbcaSMaxime Ripard if (count > 0) { 257f233dbcaSMaxime Ripard *npins = count; 258f233dbcaSMaxime Ripard return "allwinner,pins"; 259f233dbcaSMaxime Ripard } 260f233dbcaSMaxime Ripard 261f233dbcaSMaxime Ripard return NULL; 262f233dbcaSMaxime Ripard } 263f233dbcaSMaxime Ripard 264f233dbcaSMaxime Ripard static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node, 265f233dbcaSMaxime Ripard unsigned int *len) 266f233dbcaSMaxime Ripard { 267f233dbcaSMaxime Ripard unsigned long *pinconfig; 268f233dbcaSMaxime Ripard unsigned int configlen = 0, idx = 0; 269e11dee2eSMaxime Ripard int ret; 270f233dbcaSMaxime Ripard 271f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) 272f233dbcaSMaxime Ripard configlen++; 273f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) 274f233dbcaSMaxime Ripard configlen++; 275f233dbcaSMaxime Ripard 276e11dee2eSMaxime Ripard /* 277e11dee2eSMaxime Ripard * If we don't have any configuration, bail out 278e11dee2eSMaxime Ripard */ 279e11dee2eSMaxime Ripard if (!configlen) 280e11dee2eSMaxime Ripard return NULL; 281e11dee2eSMaxime Ripard 2826396bb22SKees Cook pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL); 283f233dbcaSMaxime Ripard if (!pinconfig) 284e11dee2eSMaxime Ripard return ERR_PTR(-ENOMEM); 285f233dbcaSMaxime Ripard 286f233dbcaSMaxime Ripard if (sunxi_pctrl_has_drive_prop(node)) { 287f233dbcaSMaxime Ripard int drive = sunxi_pctrl_parse_drive_prop(node); 288e11dee2eSMaxime Ripard if (drive < 0) { 289e11dee2eSMaxime Ripard ret = drive; 290f233dbcaSMaxime Ripard goto err_free; 291e11dee2eSMaxime Ripard } 292f233dbcaSMaxime Ripard 293f233dbcaSMaxime Ripard pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, 294f233dbcaSMaxime Ripard drive); 295f233dbcaSMaxime Ripard } 296f233dbcaSMaxime Ripard 297f233dbcaSMaxime Ripard if (sunxi_pctrl_has_bias_prop(node)) { 298f233dbcaSMaxime Ripard int pull = sunxi_pctrl_parse_bias_prop(node); 299223dba00SChen-Yu Tsai int arg = 0; 300e11dee2eSMaxime Ripard if (pull < 0) { 301e11dee2eSMaxime Ripard ret = pull; 302f233dbcaSMaxime Ripard goto err_free; 303e11dee2eSMaxime Ripard } 304f233dbcaSMaxime Ripard 305223dba00SChen-Yu Tsai if (pull != PIN_CONFIG_BIAS_DISABLE) 306223dba00SChen-Yu Tsai arg = 1; /* hardware uses weak pull resistors */ 307223dba00SChen-Yu Tsai 308223dba00SChen-Yu Tsai pinconfig[idx++] = pinconf_to_config_packed(pull, arg); 309f233dbcaSMaxime Ripard } 310f233dbcaSMaxime Ripard 311f233dbcaSMaxime Ripard 312f233dbcaSMaxime Ripard *len = configlen; 313f233dbcaSMaxime Ripard return pinconfig; 314f233dbcaSMaxime Ripard 315f233dbcaSMaxime Ripard err_free: 316f233dbcaSMaxime Ripard kfree(pinconfig); 317e11dee2eSMaxime Ripard return ERR_PTR(ret); 318f233dbcaSMaxime Ripard } 319f233dbcaSMaxime Ripard 3200e37f88dSMaxime Ripard static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 3210e37f88dSMaxime Ripard struct device_node *node, 3220e37f88dSMaxime Ripard struct pinctrl_map **map, 3230e37f88dSMaxime Ripard unsigned *num_maps) 3240e37f88dSMaxime Ripard { 3250e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 3260e37f88dSMaxime Ripard unsigned long *pinconfig; 3270e37f88dSMaxime Ripard struct property *prop; 328f233dbcaSMaxime Ripard const char *function, *pin_prop; 3290e37f88dSMaxime Ripard const char *group; 330f233dbcaSMaxime Ripard int ret, npins, nmaps, configlen = 0, i = 0; 3310e37f88dSMaxime Ripard 3320e37f88dSMaxime Ripard *map = NULL; 3330e37f88dSMaxime Ripard *num_maps = 0; 3340e37f88dSMaxime Ripard 335f233dbcaSMaxime Ripard function = sunxi_pctrl_parse_function_prop(node); 336f233dbcaSMaxime Ripard if (!function) { 33794f4e54cSRob Herring dev_err(pctl->dev, "missing function property in node %pOFn\n", 33894f4e54cSRob Herring node); 3390e37f88dSMaxime Ripard return -EINVAL; 3400e37f88dSMaxime Ripard } 3410e37f88dSMaxime Ripard 342f233dbcaSMaxime Ripard pin_prop = sunxi_pctrl_find_pins_prop(node, &npins); 343f233dbcaSMaxime Ripard if (!pin_prop) { 34494f4e54cSRob Herring dev_err(pctl->dev, "missing pins property in node %pOFn\n", 34594f4e54cSRob Herring node); 3460e37f88dSMaxime Ripard return -EINVAL; 3470e37f88dSMaxime Ripard } 3480e37f88dSMaxime Ripard 349f233dbcaSMaxime Ripard /* 350f233dbcaSMaxime Ripard * We have two maps for each pin: one for the function, one 351e11dee2eSMaxime Ripard * for the configuration (bias, strength, etc). 352e11dee2eSMaxime Ripard * 353e11dee2eSMaxime Ripard * We might be slightly overshooting, since we might not have 354e11dee2eSMaxime Ripard * any configuration. 355f233dbcaSMaxime Ripard */ 356f233dbcaSMaxime Ripard nmaps = npins * 2; 3576da2ec56SKees Cook *map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL); 3583efa921dSSachin Kamat if (!*map) 3590e37f88dSMaxime Ripard return -ENOMEM; 3600e37f88dSMaxime Ripard 361f233dbcaSMaxime Ripard pinconfig = sunxi_pctrl_build_pin_config(node, &configlen); 362e11dee2eSMaxime Ripard if (IS_ERR(pinconfig)) { 363e11dee2eSMaxime Ripard ret = PTR_ERR(pinconfig); 364f233dbcaSMaxime Ripard goto err_free_map; 365f233dbcaSMaxime Ripard } 366f233dbcaSMaxime Ripard 367f233dbcaSMaxime Ripard of_property_for_each_string(node, pin_prop, prop, group) { 3680e37f88dSMaxime Ripard struct sunxi_pinctrl_group *grp = 3690e37f88dSMaxime Ripard sunxi_pinctrl_find_group_by_name(pctl, group); 3700e37f88dSMaxime Ripard 3710e37f88dSMaxime Ripard if (!grp) { 3720e37f88dSMaxime Ripard dev_err(pctl->dev, "unknown pin %s", group); 3730e37f88dSMaxime Ripard continue; 3740e37f88dSMaxime Ripard } 3750e37f88dSMaxime Ripard 3760e37f88dSMaxime Ripard if (!sunxi_pinctrl_desc_find_function_by_name(pctl, 3770e37f88dSMaxime Ripard grp->name, 3780e37f88dSMaxime Ripard function)) { 3790e37f88dSMaxime Ripard dev_err(pctl->dev, "unsupported function %s on pin %s", 3800e37f88dSMaxime Ripard function, group); 3810e37f88dSMaxime Ripard continue; 3820e37f88dSMaxime Ripard } 3830e37f88dSMaxime Ripard 3840e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP; 3850e37f88dSMaxime Ripard (*map)[i].data.mux.group = group; 3860e37f88dSMaxime Ripard (*map)[i].data.mux.function = function; 3870e37f88dSMaxime Ripard 3880e37f88dSMaxime Ripard i++; 3890e37f88dSMaxime Ripard 390e11dee2eSMaxime Ripard if (pinconfig) { 3910e37f88dSMaxime Ripard (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP; 3920e37f88dSMaxime Ripard (*map)[i].data.configs.group_or_pin = group; 3930e37f88dSMaxime Ripard (*map)[i].data.configs.configs = pinconfig; 3940e37f88dSMaxime Ripard (*map)[i].data.configs.num_configs = configlen; 3950e37f88dSMaxime Ripard i++; 3960e37f88dSMaxime Ripard } 397e11dee2eSMaxime Ripard } 3980e37f88dSMaxime Ripard 399e11dee2eSMaxime Ripard *num_maps = i; 400e11dee2eSMaxime Ripard 401e11dee2eSMaxime Ripard /* 402e11dee2eSMaxime Ripard * We know have the number of maps we need, we can resize our 403e11dee2eSMaxime Ripard * map array 404e11dee2eSMaxime Ripard */ 405e11dee2eSMaxime Ripard *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL); 406b3cde198SDan Carpenter if (!*map) 407e11dee2eSMaxime Ripard return -ENOMEM; 4080e37f88dSMaxime Ripard 4090e37f88dSMaxime Ripard return 0; 410f233dbcaSMaxime Ripard 411f233dbcaSMaxime Ripard err_free_map: 412b3cde198SDan Carpenter kfree(*map); 413b3cde198SDan Carpenter *map = NULL; 414f233dbcaSMaxime Ripard return ret; 4150e37f88dSMaxime Ripard } 4160e37f88dSMaxime Ripard 4170e37f88dSMaxime Ripard static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev, 4180e37f88dSMaxime Ripard struct pinctrl_map *map, 4190e37f88dSMaxime Ripard unsigned num_maps) 4200e37f88dSMaxime Ripard { 42188f01a1bSChen-Yu Tsai int i; 42288f01a1bSChen-Yu Tsai 42388f01a1bSChen-Yu Tsai /* pin config is never in the first map */ 42488f01a1bSChen-Yu Tsai for (i = 1; i < num_maps; i++) { 42588f01a1bSChen-Yu Tsai if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP) 42688f01a1bSChen-Yu Tsai continue; 42788f01a1bSChen-Yu Tsai 42888f01a1bSChen-Yu Tsai /* 42988f01a1bSChen-Yu Tsai * All the maps share the same pin config, 43088f01a1bSChen-Yu Tsai * free only the first one we find. 43188f01a1bSChen-Yu Tsai */ 43288f01a1bSChen-Yu Tsai kfree(map[i].data.configs.configs); 43388f01a1bSChen-Yu Tsai break; 43488f01a1bSChen-Yu Tsai } 43588f01a1bSChen-Yu Tsai 4360e37f88dSMaxime Ripard kfree(map); 4370e37f88dSMaxime Ripard } 4380e37f88dSMaxime Ripard 439022ab148SLaurent Pinchart static const struct pinctrl_ops sunxi_pctrl_ops = { 4400e37f88dSMaxime Ripard .dt_node_to_map = sunxi_pctrl_dt_node_to_map, 4410e37f88dSMaxime Ripard .dt_free_map = sunxi_pctrl_dt_free_map, 4420e37f88dSMaxime Ripard .get_groups_count = sunxi_pctrl_get_groups_count, 4430e37f88dSMaxime Ripard .get_group_name = sunxi_pctrl_get_group_name, 4440e37f88dSMaxime Ripard .get_group_pins = sunxi_pctrl_get_group_pins, 4450e37f88dSMaxime Ripard }; 4460e37f88dSMaxime Ripard 447c5fda170SChen-Yu Tsai static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param, 448c5fda170SChen-Yu Tsai u32 *offset, u32 *shift, u32 *mask) 449c5fda170SChen-Yu Tsai { 450c5fda170SChen-Yu Tsai switch (param) { 451c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 452c5fda170SChen-Yu Tsai *offset = sunxi_dlevel_reg(pin); 453c5fda170SChen-Yu Tsai *shift = sunxi_dlevel_offset(pin); 454c5fda170SChen-Yu Tsai *mask = DLEVEL_PINS_MASK; 455c5fda170SChen-Yu Tsai break; 456c5fda170SChen-Yu Tsai 457c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 458c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 459c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 460c5fda170SChen-Yu Tsai *offset = sunxi_pull_reg(pin); 461c5fda170SChen-Yu Tsai *shift = sunxi_pull_offset(pin); 462c5fda170SChen-Yu Tsai *mask = PULL_PINS_MASK; 463c5fda170SChen-Yu Tsai break; 464c5fda170SChen-Yu Tsai 465c5fda170SChen-Yu Tsai default: 466c5fda170SChen-Yu Tsai return -ENOTSUPP; 467c5fda170SChen-Yu Tsai } 468c5fda170SChen-Yu Tsai 469c5fda170SChen-Yu Tsai return 0; 470c5fda170SChen-Yu Tsai } 471c5fda170SChen-Yu Tsai 472c5fda170SChen-Yu Tsai static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin, 473c5fda170SChen-Yu Tsai unsigned long *config) 474c5fda170SChen-Yu Tsai { 475c5fda170SChen-Yu Tsai struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 476c5fda170SChen-Yu Tsai enum pin_config_param param = pinconf_to_config_param(*config); 477c5fda170SChen-Yu Tsai u32 offset, shift, mask, val; 478c5fda170SChen-Yu Tsai u16 arg; 479c5fda170SChen-Yu Tsai int ret; 480c5fda170SChen-Yu Tsai 481c5fda170SChen-Yu Tsai pin -= pctl->desc->pin_base; 482c5fda170SChen-Yu Tsai 483c5fda170SChen-Yu Tsai ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); 484c5fda170SChen-Yu Tsai if (ret < 0) 485c5fda170SChen-Yu Tsai return ret; 486c5fda170SChen-Yu Tsai 487c5fda170SChen-Yu Tsai val = (readl(pctl->membase + offset) >> shift) & mask; 488c5fda170SChen-Yu Tsai 489c5fda170SChen-Yu Tsai switch (pinconf_to_config_param(*config)) { 490c5fda170SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH: 491c5fda170SChen-Yu Tsai arg = (val + 1) * 10; 492c5fda170SChen-Yu Tsai break; 493c5fda170SChen-Yu Tsai 494c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_UP: 495c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_UP) 496c5fda170SChen-Yu Tsai return -EINVAL; 497c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-up */ 498c5fda170SChen-Yu Tsai break; 499c5fda170SChen-Yu Tsai 500c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_PULL_DOWN: 501c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_PULL_DOWN) 502c5fda170SChen-Yu Tsai return -EINVAL; 503c5fda170SChen-Yu Tsai arg = 1; /* hardware is weak pull-down */ 504c5fda170SChen-Yu Tsai break; 505c5fda170SChen-Yu Tsai 506c5fda170SChen-Yu Tsai case PIN_CONFIG_BIAS_DISABLE: 507c5fda170SChen-Yu Tsai if (val != SUN4I_PINCTRL_NO_PULL) 508c5fda170SChen-Yu Tsai return -EINVAL; 509c5fda170SChen-Yu Tsai arg = 0; 510c5fda170SChen-Yu Tsai break; 511c5fda170SChen-Yu Tsai 512c5fda170SChen-Yu Tsai default: 513c5fda170SChen-Yu Tsai /* sunxi_pconf_reg should catch anything unsupported */ 514c5fda170SChen-Yu Tsai WARN_ON(1); 515c5fda170SChen-Yu Tsai return -ENOTSUPP; 516c5fda170SChen-Yu Tsai } 517c5fda170SChen-Yu Tsai 518c5fda170SChen-Yu Tsai *config = pinconf_to_config_packed(param, arg); 519c5fda170SChen-Yu Tsai 520c5fda170SChen-Yu Tsai return 0; 521c5fda170SChen-Yu Tsai } 522c5fda170SChen-Yu Tsai 5230e37f88dSMaxime Ripard static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev, 5240e37f88dSMaxime Ripard unsigned group, 5250e37f88dSMaxime Ripard unsigned long *config) 5260e37f88dSMaxime Ripard { 5270e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 528c5fda170SChen-Yu Tsai struct sunxi_pinctrl_group *g = &pctl->groups[group]; 5290e37f88dSMaxime Ripard 530c5fda170SChen-Yu Tsai /* We only support 1 pin per group. Chain it to the pin callback */ 531c5fda170SChen-Yu Tsai return sunxi_pconf_get(pctldev, g->pin, config); 5320e37f88dSMaxime Ripard } 5330e37f88dSMaxime Ripard 53490be64e2SMaxime Ripard static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin, 53590be64e2SMaxime Ripard unsigned long *configs, unsigned num_configs) 5360e37f88dSMaxime Ripard { 5370e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 53803b054e9SSherman Yin int i; 5390e37f88dSMaxime Ripard 54003b054e9SSherman Yin for (i = 0; i < num_configs; i++) { 54151814827SChen-Yu Tsai enum pin_config_param param; 54251814827SChen-Yu Tsai unsigned long flags; 54351814827SChen-Yu Tsai u32 offset, shift, mask, reg; 54458957d2eSMika Westerberg u32 arg, val; 54551814827SChen-Yu Tsai int ret; 54651814827SChen-Yu Tsai 54751814827SChen-Yu Tsai param = pinconf_to_config_param(configs[i]); 54851814827SChen-Yu Tsai arg = pinconf_to_config_argument(configs[i]); 54951814827SChen-Yu Tsai 55051814827SChen-Yu Tsai ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); 55151814827SChen-Yu Tsai if (ret < 0) 55251814827SChen-Yu Tsai return ret; 55351814827SChen-Yu Tsai 55451814827SChen-Yu Tsai switch (param) { 5550e37f88dSMaxime Ripard case PIN_CONFIG_DRIVE_STRENGTH: 55651814827SChen-Yu Tsai if (arg < 10 || arg > 40) 5570e37f88dSMaxime Ripard return -EINVAL; 5580e37f88dSMaxime Ripard /* 5590e37f88dSMaxime Ripard * We convert from mA to what the register expects: 5600e37f88dSMaxime Ripard * 0: 10mA 5610e37f88dSMaxime Ripard * 1: 20mA 5620e37f88dSMaxime Ripard * 2: 30mA 5630e37f88dSMaxime Ripard * 3: 40mA 5640e37f88dSMaxime Ripard */ 56551814827SChen-Yu Tsai val = arg / 10 - 1; 5660e37f88dSMaxime Ripard break; 56707fe64baSMaxime Ripard case PIN_CONFIG_BIAS_DISABLE: 568ac059e2aSPriit Laes val = 0; 569ac059e2aSPriit Laes break; 5700e37f88dSMaxime Ripard case PIN_CONFIG_BIAS_PULL_UP: 57151814827SChen-Yu Tsai if (arg == 0) 57251814827SChen-Yu Tsai return -EINVAL; 57351814827SChen-Yu Tsai val = 1; 5740e37f88dSMaxime Ripard break; 5750e37f88dSMaxime Ripard case PIN_CONFIG_BIAS_PULL_DOWN: 57651814827SChen-Yu Tsai if (arg == 0) 57751814827SChen-Yu Tsai return -EINVAL; 57851814827SChen-Yu Tsai val = 2; 5790e37f88dSMaxime Ripard break; 5800e37f88dSMaxime Ripard default: 58151814827SChen-Yu Tsai /* sunxi_pconf_reg should catch anything unsupported */ 58251814827SChen-Yu Tsai WARN_ON(1); 58351814827SChen-Yu Tsai return -ENOTSUPP; 5840e37f88dSMaxime Ripard } 5850e37f88dSMaxime Ripard 586f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 58751814827SChen-Yu Tsai reg = readl(pctl->membase + offset); 58851814827SChen-Yu Tsai reg &= ~(mask << shift); 58951814827SChen-Yu Tsai writel(reg | val << shift, pctl->membase + offset); 590f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 59151814827SChen-Yu Tsai } /* for each config */ 5920e37f88dSMaxime Ripard 5930e37f88dSMaxime Ripard return 0; 5940e37f88dSMaxime Ripard } 5950e37f88dSMaxime Ripard 59690be64e2SMaxime Ripard static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 59790be64e2SMaxime Ripard unsigned long *configs, unsigned num_configs) 59890be64e2SMaxime Ripard { 59990be64e2SMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 60090be64e2SMaxime Ripard struct sunxi_pinctrl_group *g = &pctl->groups[group]; 60190be64e2SMaxime Ripard 60290be64e2SMaxime Ripard /* We only support 1 pin per group. Chain it to the pin callback */ 60390be64e2SMaxime Ripard return sunxi_pconf_set(pctldev, g->pin, configs, num_configs); 60490be64e2SMaxime Ripard } 60590be64e2SMaxime Ripard 606022ab148SLaurent Pinchart static const struct pinconf_ops sunxi_pconf_ops = { 607c5fda170SChen-Yu Tsai .is_generic = true, 608c5fda170SChen-Yu Tsai .pin_config_get = sunxi_pconf_get, 60990be64e2SMaxime Ripard .pin_config_set = sunxi_pconf_set, 6100e37f88dSMaxime Ripard .pin_config_group_get = sunxi_pconf_group_get, 6110e37f88dSMaxime Ripard .pin_config_group_set = sunxi_pconf_group_set, 6120e37f88dSMaxime Ripard }; 6130e37f88dSMaxime Ripard 614402bfb3cSChen-Yu Tsai static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, 615402bfb3cSChen-Yu Tsai unsigned pin, 616402bfb3cSChen-Yu Tsai struct regulator *supply) 617402bfb3cSChen-Yu Tsai { 618cc62383fSOndrej Jirman unsigned short bank = pin / PINS_PER_BANK; 619cc62383fSOndrej Jirman unsigned long flags; 620402bfb3cSChen-Yu Tsai u32 val, reg; 621402bfb3cSChen-Yu Tsai int uV; 622402bfb3cSChen-Yu Tsai 623f7275345SOndrej Jirman if (!pctl->desc->io_bias_cfg_variant) 624402bfb3cSChen-Yu Tsai return 0; 625402bfb3cSChen-Yu Tsai 626402bfb3cSChen-Yu Tsai uV = regulator_get_voltage(supply); 627402bfb3cSChen-Yu Tsai if (uV < 0) 628402bfb3cSChen-Yu Tsai return uV; 629402bfb3cSChen-Yu Tsai 630402bfb3cSChen-Yu Tsai /* Might be dummy regulator with no voltage set */ 631402bfb3cSChen-Yu Tsai if (uV == 0) 632402bfb3cSChen-Yu Tsai return 0; 633402bfb3cSChen-Yu Tsai 634f7275345SOndrej Jirman switch (pctl->desc->io_bias_cfg_variant) { 635f7275345SOndrej Jirman case BIAS_VOLTAGE_GRP_CONFIG: 636f7275345SOndrej Jirman /* 637f7275345SOndrej Jirman * Configured value must be equal or greater to actual 638f7275345SOndrej Jirman * voltage. 639f7275345SOndrej Jirman */ 640402bfb3cSChen-Yu Tsai if (uV <= 1800000) 641402bfb3cSChen-Yu Tsai val = 0x0; /* 1.8V */ 642402bfb3cSChen-Yu Tsai else if (uV <= 2500000) 643402bfb3cSChen-Yu Tsai val = 0x6; /* 2.5V */ 644402bfb3cSChen-Yu Tsai else if (uV <= 2800000) 645402bfb3cSChen-Yu Tsai val = 0x9; /* 2.8V */ 646402bfb3cSChen-Yu Tsai else if (uV <= 3000000) 647402bfb3cSChen-Yu Tsai val = 0xA; /* 3.0V */ 648402bfb3cSChen-Yu Tsai else 649402bfb3cSChen-Yu Tsai val = 0xD; /* 3.3V */ 650402bfb3cSChen-Yu Tsai 651402bfb3cSChen-Yu Tsai pin -= pctl->desc->pin_base; 652402bfb3cSChen-Yu Tsai 653402bfb3cSChen-Yu Tsai reg = readl(pctl->membase + sunxi_grp_config_reg(pin)); 654402bfb3cSChen-Yu Tsai reg &= ~IO_BIAS_MASK; 655402bfb3cSChen-Yu Tsai writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin)); 656402bfb3cSChen-Yu Tsai return 0; 657cc62383fSOndrej Jirman case BIAS_VOLTAGE_PIO_POW_MODE_SEL: 658cc62383fSOndrej Jirman val = uV <= 1800000 ? 1 : 0; 659cc62383fSOndrej Jirman 660cc62383fSOndrej Jirman raw_spin_lock_irqsave(&pctl->lock, flags); 661cc62383fSOndrej Jirman reg = readl(pctl->membase + PIO_POW_MOD_SEL_REG); 662cc62383fSOndrej Jirman reg &= ~(1 << bank); 663cc62383fSOndrej Jirman writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG); 664cc62383fSOndrej Jirman raw_spin_unlock_irqrestore(&pctl->lock, flags); 665cc62383fSOndrej Jirman return 0; 666f7275345SOndrej Jirman default: 667f7275345SOndrej Jirman return -EINVAL; 668f7275345SOndrej Jirman } 669402bfb3cSChen-Yu Tsai } 670402bfb3cSChen-Yu Tsai 6710e37f88dSMaxime Ripard static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 6720e37f88dSMaxime Ripard { 6730e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6740e37f88dSMaxime Ripard 6750e37f88dSMaxime Ripard return pctl->nfunctions; 6760e37f88dSMaxime Ripard } 6770e37f88dSMaxime Ripard 6780e37f88dSMaxime Ripard static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev, 6790e37f88dSMaxime Ripard unsigned function) 6800e37f88dSMaxime Ripard { 6810e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6820e37f88dSMaxime Ripard 6830e37f88dSMaxime Ripard return pctl->functions[function].name; 6840e37f88dSMaxime Ripard } 6850e37f88dSMaxime Ripard 6860e37f88dSMaxime Ripard static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev, 6870e37f88dSMaxime Ripard unsigned function, 6880e37f88dSMaxime Ripard const char * const **groups, 6890e37f88dSMaxime Ripard unsigned * const num_groups) 6900e37f88dSMaxime Ripard { 6910e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 6920e37f88dSMaxime Ripard 6930e37f88dSMaxime Ripard *groups = pctl->functions[function].groups; 6940e37f88dSMaxime Ripard *num_groups = pctl->functions[function].ngroups; 6950e37f88dSMaxime Ripard 6960e37f88dSMaxime Ripard return 0; 6970e37f88dSMaxime Ripard } 6980e37f88dSMaxime Ripard 6990e37f88dSMaxime Ripard static void sunxi_pmx_set(struct pinctrl_dev *pctldev, 7000e37f88dSMaxime Ripard unsigned pin, 7010e37f88dSMaxime Ripard u8 config) 7020e37f88dSMaxime Ripard { 7030e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7041bee963dSMaxime Ripard unsigned long flags; 7051bee963dSMaxime Ripard u32 val, mask; 7060e37f88dSMaxime Ripard 707f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 7081bee963dSMaxime Ripard 709b4575c69SChen-Yu Tsai pin -= pctl->desc->pin_base; 7101bee963dSMaxime Ripard val = readl(pctl->membase + sunxi_mux_reg(pin)); 7111bee963dSMaxime Ripard mask = MUX_PINS_MASK << sunxi_mux_offset(pin); 7120e37f88dSMaxime Ripard writel((val & ~mask) | config << sunxi_mux_offset(pin), 7130e37f88dSMaxime Ripard pctl->membase + sunxi_mux_reg(pin)); 7141bee963dSMaxime Ripard 715f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 7160e37f88dSMaxime Ripard } 7170e37f88dSMaxime Ripard 71803e9f0caSLinus Walleij static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev, 7190e37f88dSMaxime Ripard unsigned function, 7200e37f88dSMaxime Ripard unsigned group) 7210e37f88dSMaxime Ripard { 7220e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7230e37f88dSMaxime Ripard struct sunxi_pinctrl_group *g = pctl->groups + group; 7240e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions + function; 7250e37f88dSMaxime Ripard struct sunxi_desc_function *desc = 7260e37f88dSMaxime Ripard sunxi_pinctrl_desc_find_function_by_name(pctl, 7270e37f88dSMaxime Ripard g->name, 7280e37f88dSMaxime Ripard func->name); 7290e37f88dSMaxime Ripard 7300e37f88dSMaxime Ripard if (!desc) 7310e37f88dSMaxime Ripard return -EINVAL; 7320e37f88dSMaxime Ripard 7330e37f88dSMaxime Ripard sunxi_pmx_set(pctldev, g->pin, desc->muxval); 7340e37f88dSMaxime Ripard 7350e37f88dSMaxime Ripard return 0; 7360e37f88dSMaxime Ripard } 7370e37f88dSMaxime Ripard 73808e9e614SMaxime Ripard static int 73908e9e614SMaxime Ripard sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 74008e9e614SMaxime Ripard struct pinctrl_gpio_range *range, 74108e9e614SMaxime Ripard unsigned offset, 74208e9e614SMaxime Ripard bool input) 74308e9e614SMaxime Ripard { 74408e9e614SMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 74508e9e614SMaxime Ripard struct sunxi_desc_function *desc; 74608e9e614SMaxime Ripard const char *func; 74708e9e614SMaxime Ripard 74808e9e614SMaxime Ripard if (input) 74908e9e614SMaxime Ripard func = "gpio_in"; 75008e9e614SMaxime Ripard else 75108e9e614SMaxime Ripard func = "gpio_out"; 75208e9e614SMaxime Ripard 753814d4f2eSMaxime Ripard desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func); 754814d4f2eSMaxime Ripard if (!desc) 755814d4f2eSMaxime Ripard return -EINVAL; 75608e9e614SMaxime Ripard 75708e9e614SMaxime Ripard sunxi_pmx_set(pctldev, offset, desc->muxval); 75808e9e614SMaxime Ripard 759814d4f2eSMaxime Ripard return 0; 76008e9e614SMaxime Ripard } 76108e9e614SMaxime Ripard 7629a2a566aSMaxime Ripard static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) 7639a2a566aSMaxime Ripard { 7649a2a566aSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7659a2a566aSMaxime Ripard unsigned short bank = offset / PINS_PER_BANK; 766ca443844SChen-Yu Tsai unsigned short bank_offset = bank - pctl->desc->pin_base / 767ca443844SChen-Yu Tsai PINS_PER_BANK; 768ca443844SChen-Yu Tsai struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; 769dc144558SChen-Yu Tsai struct regulator *reg = s_reg->regulator; 770dc144558SChen-Yu Tsai char supply[16]; 7719a2a566aSMaxime Ripard int ret; 7729a2a566aSMaxime Ripard 773dc144558SChen-Yu Tsai if (reg) { 774dc144558SChen-Yu Tsai refcount_inc(&s_reg->refcount); 775dc144558SChen-Yu Tsai return 0; 776dc144558SChen-Yu Tsai } 7779a2a566aSMaxime Ripard 7789a2a566aSMaxime Ripard snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); 7799a2a566aSMaxime Ripard reg = regulator_get(pctl->dev, supply); 7809a2a566aSMaxime Ripard if (IS_ERR(reg)) { 7819a2a566aSMaxime Ripard dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", 7829a2a566aSMaxime Ripard 'A' + bank); 7839a2a566aSMaxime Ripard return PTR_ERR(reg); 7849a2a566aSMaxime Ripard } 7859a2a566aSMaxime Ripard 7869a2a566aSMaxime Ripard ret = regulator_enable(reg); 7879a2a566aSMaxime Ripard if (ret) { 7889a2a566aSMaxime Ripard dev_err(pctl->dev, 7899a2a566aSMaxime Ripard "Couldn't enable bank P%c regulator\n", 'A' + bank); 7909a2a566aSMaxime Ripard goto out; 7919a2a566aSMaxime Ripard } 7929a2a566aSMaxime Ripard 793402bfb3cSChen-Yu Tsai sunxi_pinctrl_set_io_bias_cfg(pctl, offset, reg); 794402bfb3cSChen-Yu Tsai 795dc144558SChen-Yu Tsai s_reg->regulator = reg; 796dc144558SChen-Yu Tsai refcount_set(&s_reg->refcount, 1); 797dc144558SChen-Yu Tsai 7989a2a566aSMaxime Ripard return 0; 7999a2a566aSMaxime Ripard 8009a2a566aSMaxime Ripard out: 8019a2a566aSMaxime Ripard regulator_put(s_reg->regulator); 8029a2a566aSMaxime Ripard 8039a2a566aSMaxime Ripard return ret; 8049a2a566aSMaxime Ripard } 8059a2a566aSMaxime Ripard 8069a2a566aSMaxime Ripard static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) 8079a2a566aSMaxime Ripard { 8089a2a566aSMaxime Ripard struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 8099a2a566aSMaxime Ripard unsigned short bank = offset / PINS_PER_BANK; 810ca443844SChen-Yu Tsai unsigned short bank_offset = bank - pctl->desc->pin_base / 811ca443844SChen-Yu Tsai PINS_PER_BANK; 812ca443844SChen-Yu Tsai struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; 8139a2a566aSMaxime Ripard 8149a2a566aSMaxime Ripard if (!refcount_dec_and_test(&s_reg->refcount)) 8159a2a566aSMaxime Ripard return 0; 8169a2a566aSMaxime Ripard 8179a2a566aSMaxime Ripard regulator_disable(s_reg->regulator); 8189a2a566aSMaxime Ripard regulator_put(s_reg->regulator); 8199a2a566aSMaxime Ripard s_reg->regulator = NULL; 8209a2a566aSMaxime Ripard 8219a2a566aSMaxime Ripard return 0; 8229a2a566aSMaxime Ripard } 8239a2a566aSMaxime Ripard 824022ab148SLaurent Pinchart static const struct pinmux_ops sunxi_pmx_ops = { 8250e37f88dSMaxime Ripard .get_functions_count = sunxi_pmx_get_funcs_cnt, 8260e37f88dSMaxime Ripard .get_function_name = sunxi_pmx_get_func_name, 8270e37f88dSMaxime Ripard .get_function_groups = sunxi_pmx_get_func_groups, 82803e9f0caSLinus Walleij .set_mux = sunxi_pmx_set_mux, 82908e9e614SMaxime Ripard .gpio_set_direction = sunxi_pmx_gpio_set_direction, 8309a2a566aSMaxime Ripard .request = sunxi_pmx_request, 8319a2a566aSMaxime Ripard .free = sunxi_pmx_free, 83213960072SMaxime Ripard .strict = true, 8330e37f88dSMaxime Ripard }; 8340e37f88dSMaxime Ripard 83508e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, 83608e9e614SMaxime Ripard unsigned offset) 83708e9e614SMaxime Ripard { 83808e9e614SMaxime Ripard return pinctrl_gpio_direction_input(chip->base + offset); 83908e9e614SMaxime Ripard } 84008e9e614SMaxime Ripard 84108e9e614SMaxime Ripard static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) 84208e9e614SMaxime Ripard { 84388057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 84408e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 84508e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 8466cee3821SLinus Walleij bool set_mux = pctl->desc->irq_read_needs_mux && 8476cee3821SLinus Walleij gpiochip_line_is_irq(chip, offset); 848be2d107fSKrzysztof Adamski u32 pin = offset + chip->base; 849ef6d24ccSHans de Goede u32 val; 850ef6d24ccSHans de Goede 851ef6d24ccSHans de Goede if (set_mux) 852be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT); 853ef6d24ccSHans de Goede 854ef6d24ccSHans de Goede val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; 855ef6d24ccSHans de Goede 856ef6d24ccSHans de Goede if (set_mux) 857be2d107fSKrzysztof Adamski sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ); 85808e9e614SMaxime Ripard 85939e24ac3SLinus Walleij return !!val; 86008e9e614SMaxime Ripard } 86108e9e614SMaxime Ripard 86208e9e614SMaxime Ripard static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, 86308e9e614SMaxime Ripard unsigned offset, int value) 86408e9e614SMaxime Ripard { 86588057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 86608e9e614SMaxime Ripard u32 reg = sunxi_data_reg(offset); 86708e9e614SMaxime Ripard u8 index = sunxi_data_offset(offset); 8681bee963dSMaxime Ripard unsigned long flags; 8691bee963dSMaxime Ripard u32 regval; 87008e9e614SMaxime Ripard 871f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 8721bee963dSMaxime Ripard 8731bee963dSMaxime Ripard regval = readl(pctl->membase + reg); 87408e9e614SMaxime Ripard 875df7b34f4SMaxime Ripard if (value) 876df7b34f4SMaxime Ripard regval |= BIT(index); 877df7b34f4SMaxime Ripard else 878df7b34f4SMaxime Ripard regval &= ~(BIT(index)); 879df7b34f4SMaxime Ripard 880df7b34f4SMaxime Ripard writel(regval, pctl->membase + reg); 8811bee963dSMaxime Ripard 882f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 88308e9e614SMaxime Ripard } 88408e9e614SMaxime Ripard 885fa8cf57cSChen-Yu Tsai static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, 886fa8cf57cSChen-Yu Tsai unsigned offset, int value) 887fa8cf57cSChen-Yu Tsai { 888fa8cf57cSChen-Yu Tsai sunxi_pinctrl_gpio_set(chip, offset, value); 889fa8cf57cSChen-Yu Tsai return pinctrl_gpio_direction_output(chip->base + offset); 890fa8cf57cSChen-Yu Tsai } 891fa8cf57cSChen-Yu Tsai 892a0d72094SMaxime Ripard static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, 893a0d72094SMaxime Ripard const struct of_phandle_args *gpiospec, 894a0d72094SMaxime Ripard u32 *flags) 895a0d72094SMaxime Ripard { 896a0d72094SMaxime Ripard int pin, base; 897a0d72094SMaxime Ripard 898a0d72094SMaxime Ripard base = PINS_PER_BANK * gpiospec->args[0]; 899a0d72094SMaxime Ripard pin = base + gpiospec->args[1]; 900a0d72094SMaxime Ripard 901343f1327SChen-Yu Tsai if (pin > gc->ngpio) 902a0d72094SMaxime Ripard return -EINVAL; 903a0d72094SMaxime Ripard 904a0d72094SMaxime Ripard if (flags) 905a0d72094SMaxime Ripard *flags = gpiospec->args[2]; 906a0d72094SMaxime Ripard 907a0d72094SMaxime Ripard return pin; 908a0d72094SMaxime Ripard } 909a0d72094SMaxime Ripard 91060242db1SMaxime Ripard static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 91160242db1SMaxime Ripard { 91288057d6eSLinus Walleij struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); 91360242db1SMaxime Ripard struct sunxi_desc_function *desc; 914343f1327SChen-Yu Tsai unsigned pinnum = pctl->desc->pin_base + offset; 9150d3bafacSChen-Yu Tsai unsigned irqnum; 91660242db1SMaxime Ripard 917c9e3b2d8SAxel Lin if (offset >= chip->ngpio) 91860242db1SMaxime Ripard return -ENXIO; 91960242db1SMaxime Ripard 920343f1327SChen-Yu Tsai desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq"); 92160242db1SMaxime Ripard if (!desc) 92260242db1SMaxime Ripard return -EINVAL; 92360242db1SMaxime Ripard 9240d3bafacSChen-Yu Tsai irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum; 92560242db1SMaxime Ripard 92658383c78SLinus Walleij dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n", 9270d3bafacSChen-Yu Tsai chip->label, offset + chip->base, irqnum); 9280d3bafacSChen-Yu Tsai 9290d3bafacSChen-Yu Tsai return irq_find_mapping(pctl->domain, irqnum); 93060242db1SMaxime Ripard } 93160242db1SMaxime Ripard 932fea6d8efSHans de Goede static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) 93360242db1SMaxime Ripard { 93460242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 935fea6d8efSHans de Goede struct sunxi_desc_function *func; 936f83549d6SChen-Yu Tsai int ret; 937fea6d8efSHans de Goede 938fea6d8efSHans de Goede func = sunxi_pinctrl_desc_find_function_by_pin(pctl, 939fea6d8efSHans de Goede pctl->irq_array[d->hwirq], "irq"); 940fea6d8efSHans de Goede if (!func) 941fea6d8efSHans de Goede return -EINVAL; 942fea6d8efSHans de Goede 943e3a2e878SAlexandre Courbot ret = gpiochip_lock_as_irq(pctl->chip, 944343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 945f83549d6SChen-Yu Tsai if (ret) { 946f83549d6SChen-Yu Tsai dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", 947f83549d6SChen-Yu Tsai irqd_to_hwirq(d)); 948f83549d6SChen-Yu Tsai return ret; 949f83549d6SChen-Yu Tsai } 950f83549d6SChen-Yu Tsai 951fea6d8efSHans de Goede /* Change muxing to INT mode */ 952fea6d8efSHans de Goede sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); 953fea6d8efSHans de Goede 954fea6d8efSHans de Goede return 0; 955fea6d8efSHans de Goede } 95608e9e614SMaxime Ripard 957f83549d6SChen-Yu Tsai static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) 958f83549d6SChen-Yu Tsai { 959f83549d6SChen-Yu Tsai struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 960f83549d6SChen-Yu Tsai 961e3a2e878SAlexandre Courbot gpiochip_unlock_as_irq(pctl->chip, 962343f1327SChen-Yu Tsai pctl->irq_array[d->hwirq] - pctl->desc->pin_base); 963f83549d6SChen-Yu Tsai } 964f83549d6SChen-Yu Tsai 965f4c51c10SHans de Goede static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) 96660242db1SMaxime Ripard { 96760242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 9684b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_cfg_reg(pctl->desc, d->hwirq); 96960242db1SMaxime Ripard u8 index = sunxi_irq_cfg_offset(d->hwirq); 9701bee963dSMaxime Ripard unsigned long flags; 9712aaaddffSMaxime Ripard u32 regval; 97260242db1SMaxime Ripard u8 mode; 97360242db1SMaxime Ripard 97460242db1SMaxime Ripard switch (type) { 97560242db1SMaxime Ripard case IRQ_TYPE_EDGE_RISING: 97660242db1SMaxime Ripard mode = IRQ_EDGE_RISING; 97760242db1SMaxime Ripard break; 97860242db1SMaxime Ripard case IRQ_TYPE_EDGE_FALLING: 97960242db1SMaxime Ripard mode = IRQ_EDGE_FALLING; 98060242db1SMaxime Ripard break; 98160242db1SMaxime Ripard case IRQ_TYPE_EDGE_BOTH: 98260242db1SMaxime Ripard mode = IRQ_EDGE_BOTH; 98360242db1SMaxime Ripard break; 98460242db1SMaxime Ripard case IRQ_TYPE_LEVEL_HIGH: 98560242db1SMaxime Ripard mode = IRQ_LEVEL_HIGH; 98660242db1SMaxime Ripard break; 98760242db1SMaxime Ripard case IRQ_TYPE_LEVEL_LOW: 98860242db1SMaxime Ripard mode = IRQ_LEVEL_LOW; 98960242db1SMaxime Ripard break; 99060242db1SMaxime Ripard default: 99160242db1SMaxime Ripard return -EINVAL; 99260242db1SMaxime Ripard } 99360242db1SMaxime Ripard 994f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 9951bee963dSMaxime Ripard 996a0d6de9bSMaxime Ripard if (type & IRQ_TYPE_LEVEL_MASK) 997b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip, 998a0d6de9bSMaxime Ripard handle_fasteoi_irq, NULL); 999a0d6de9bSMaxime Ripard else 1000b9a5ec33SThomas Gleixner irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip, 1001a0d6de9bSMaxime Ripard handle_edge_irq, NULL); 1002a0d6de9bSMaxime Ripard 10032aaaddffSMaxime Ripard regval = readl(pctl->membase + reg); 1004d82f9401SHans de Goede regval &= ~(IRQ_CFG_IRQ_MASK << index); 10052aaaddffSMaxime Ripard writel(regval | (mode << index), pctl->membase + reg); 100660242db1SMaxime Ripard 1007f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 100860242db1SMaxime Ripard 100960242db1SMaxime Ripard return 0; 101060242db1SMaxime Ripard } 101160242db1SMaxime Ripard 1012645ec714SMaxime Ripard static void sunxi_pinctrl_irq_ack(struct irq_data *d) 101360242db1SMaxime Ripard { 101460242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 10154b0d6c5aSIcenowy Zheng u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq); 101660242db1SMaxime Ripard u8 status_idx = sunxi_irq_status_offset(d->hwirq); 101760242db1SMaxime Ripard 101860242db1SMaxime Ripard /* Clear the IRQ */ 101960242db1SMaxime Ripard writel(1 << status_idx, pctl->membase + status_reg); 102060242db1SMaxime Ripard } 102160242db1SMaxime Ripard 102260242db1SMaxime Ripard static void sunxi_pinctrl_irq_mask(struct irq_data *d) 102360242db1SMaxime Ripard { 102460242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 10254b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); 102660242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 10271bee963dSMaxime Ripard unsigned long flags; 102860242db1SMaxime Ripard u32 val; 102960242db1SMaxime Ripard 1030f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 10311bee963dSMaxime Ripard 103260242db1SMaxime Ripard /* Mask the IRQ */ 103360242db1SMaxime Ripard val = readl(pctl->membase + reg); 103460242db1SMaxime Ripard writel(val & ~(1 << idx), pctl->membase + reg); 10351bee963dSMaxime Ripard 1036f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 103760242db1SMaxime Ripard } 103860242db1SMaxime Ripard 103960242db1SMaxime Ripard static void sunxi_pinctrl_irq_unmask(struct irq_data *d) 104060242db1SMaxime Ripard { 104160242db1SMaxime Ripard struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 10424b0d6c5aSIcenowy Zheng u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); 104360242db1SMaxime Ripard u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 10441bee963dSMaxime Ripard unsigned long flags; 104560242db1SMaxime Ripard u32 val; 104660242db1SMaxime Ripard 1047f658ed36SJulia Cartwright raw_spin_lock_irqsave(&pctl->lock, flags); 10481bee963dSMaxime Ripard 104960242db1SMaxime Ripard /* Unmask the IRQ */ 105060242db1SMaxime Ripard val = readl(pctl->membase + reg); 105160242db1SMaxime Ripard writel(val | (1 << idx), pctl->membase + reg); 10521bee963dSMaxime Ripard 1053f658ed36SJulia Cartwright raw_spin_unlock_irqrestore(&pctl->lock, flags); 105460242db1SMaxime Ripard } 105560242db1SMaxime Ripard 1056d61e23e5SHans de Goede static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) 1057d61e23e5SHans de Goede { 1058d61e23e5SHans de Goede sunxi_pinctrl_irq_ack(d); 1059d61e23e5SHans de Goede sunxi_pinctrl_irq_unmask(d); 1060d61e23e5SHans de Goede } 1061d61e23e5SHans de Goede 1062a59c99d9SSamuel Holland static int sunxi_pinctrl_irq_set_wake(struct irq_data *d, unsigned int on) 1063a59c99d9SSamuel Holland { 1064a59c99d9SSamuel Holland struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 1065a59c99d9SSamuel Holland u8 bank = d->hwirq / IRQ_PER_BANK; 1066a59c99d9SSamuel Holland 1067a59c99d9SSamuel Holland return irq_set_irq_wake(pctl->irq[bank], on); 1068a59c99d9SSamuel Holland } 1069a59c99d9SSamuel Holland 1070f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_edge_irq_chip = { 1071fb5b7788SMaxime Ripard .name = "sunxi_pio_edge", 1072645ec714SMaxime Ripard .irq_ack = sunxi_pinctrl_irq_ack, 107360242db1SMaxime Ripard .irq_mask = sunxi_pinctrl_irq_mask, 107460242db1SMaxime Ripard .irq_unmask = sunxi_pinctrl_irq_unmask, 1075fea6d8efSHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 1076f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 107760242db1SMaxime Ripard .irq_set_type = sunxi_pinctrl_irq_set_type, 1078a59c99d9SSamuel Holland .irq_set_wake = sunxi_pinctrl_irq_set_wake, 10798587b21cSSamuel Holland .flags = IRQCHIP_MASK_ON_SUSPEND, 108060242db1SMaxime Ripard }; 108160242db1SMaxime Ripard 1082f4c51c10SHans de Goede static struct irq_chip sunxi_pinctrl_level_irq_chip = { 1083fb5b7788SMaxime Ripard .name = "sunxi_pio_level", 1084f4c51c10SHans de Goede .irq_eoi = sunxi_pinctrl_irq_ack, 1085f4c51c10SHans de Goede .irq_mask = sunxi_pinctrl_irq_mask, 1086f4c51c10SHans de Goede .irq_unmask = sunxi_pinctrl_irq_unmask, 1087d61e23e5SHans de Goede /* Define irq_enable / disable to avoid spurious irqs for drivers 1088d61e23e5SHans de Goede * using these to suppress irqs while they clear the irq source */ 1089d61e23e5SHans de Goede .irq_enable = sunxi_pinctrl_irq_ack_unmask, 1090d61e23e5SHans de Goede .irq_disable = sunxi_pinctrl_irq_mask, 1091f4c51c10SHans de Goede .irq_request_resources = sunxi_pinctrl_irq_request_resources, 1092f83549d6SChen-Yu Tsai .irq_release_resources = sunxi_pinctrl_irq_release_resources, 1093f4c51c10SHans de Goede .irq_set_type = sunxi_pinctrl_irq_set_type, 1094a59c99d9SSamuel Holland .irq_set_wake = sunxi_pinctrl_irq_set_wake, 1095a59c99d9SSamuel Holland .flags = IRQCHIP_EOI_THREADED | 10968587b21cSSamuel Holland IRQCHIP_MASK_ON_SUSPEND | 1097f4c51c10SHans de Goede IRQCHIP_EOI_IF_HANDLED, 109860242db1SMaxime Ripard }; 109960242db1SMaxime Ripard 1100d8323c6bSMaxime Ripard static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, 1101d8323c6bSMaxime Ripard struct device_node *node, 1102d8323c6bSMaxime Ripard const u32 *intspec, 1103d8323c6bSMaxime Ripard unsigned int intsize, 1104d8323c6bSMaxime Ripard unsigned long *out_hwirq, 1105d8323c6bSMaxime Ripard unsigned int *out_type) 1106d8323c6bSMaxime Ripard { 11078297992cSHans de Goede struct sunxi_pinctrl *pctl = d->host_data; 1108d8323c6bSMaxime Ripard struct sunxi_desc_function *desc; 1109d8323c6bSMaxime Ripard int pin, base; 1110d8323c6bSMaxime Ripard 1111d8323c6bSMaxime Ripard if (intsize < 3) 1112d8323c6bSMaxime Ripard return -EINVAL; 1113d8323c6bSMaxime Ripard 1114d8323c6bSMaxime Ripard base = PINS_PER_BANK * intspec[0]; 11158297992cSHans de Goede pin = pctl->desc->pin_base + base + intspec[1]; 1116d8323c6bSMaxime Ripard 11178297992cSHans de Goede desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq"); 1118d8323c6bSMaxime Ripard if (!desc) 1119d8323c6bSMaxime Ripard return -EINVAL; 1120d8323c6bSMaxime Ripard 1121d8323c6bSMaxime Ripard *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; 1122d8323c6bSMaxime Ripard *out_type = intspec[2]; 1123d8323c6bSMaxime Ripard 1124d8323c6bSMaxime Ripard return 0; 1125d8323c6bSMaxime Ripard } 1126d8323c6bSMaxime Ripard 11272421dfd6STobias Klauser static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { 1128d8323c6bSMaxime Ripard .xlate = sunxi_pinctrl_irq_of_xlate, 1129d8323c6bSMaxime Ripard }; 1130d8323c6bSMaxime Ripard 1131bd0b9ac4SThomas Gleixner static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) 113260242db1SMaxime Ripard { 1133eeef97b1SThomas Gleixner unsigned int irq = irq_desc_get_irq(desc); 11345663bb27SJiang Liu struct irq_chip *chip = irq_desc_get_chip(desc); 11355663bb27SJiang Liu struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); 1136aebdc8abSMaxime Ripard unsigned long bank, reg, val; 113760242db1SMaxime Ripard 1138aebdc8abSMaxime Ripard for (bank = 0; bank < pctl->desc->irq_banks; bank++) 1139aebdc8abSMaxime Ripard if (irq == pctl->irq[bank]) 1140aebdc8abSMaxime Ripard break; 114160242db1SMaxime Ripard 1142fd5198ddSYangtao Li WARN_ON(bank == pctl->desc->irq_banks); 1143aebdc8abSMaxime Ripard 1144a1158e36SYangtao Li chained_irq_enter(chip, desc); 1145a1158e36SYangtao Li 11464b0d6c5aSIcenowy Zheng reg = sunxi_irq_status_reg_from_bank(pctl->desc, bank); 1147aebdc8abSMaxime Ripard val = readl(pctl->membase + reg); 114860242db1SMaxime Ripard 1149aebdc8abSMaxime Ripard if (val) { 115060242db1SMaxime Ripard int irqoffset; 115160242db1SMaxime Ripard 1152aebdc8abSMaxime Ripard for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) { 1153aebdc8abSMaxime Ripard int pin_irq = irq_find_mapping(pctl->domain, 1154aebdc8abSMaxime Ripard bank * IRQ_PER_BANK + irqoffset); 115560242db1SMaxime Ripard generic_handle_irq(pin_irq); 115660242db1SMaxime Ripard } 115760242db1SMaxime Ripard } 1158a1158e36SYangtao Li 1159a1158e36SYangtao Li chained_irq_exit(chip, desc); 116060242db1SMaxime Ripard } 116160242db1SMaxime Ripard 11620e37f88dSMaxime Ripard static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, 11630e37f88dSMaxime Ripard const char *name) 11640e37f88dSMaxime Ripard { 11650e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func = pctl->functions; 11660e37f88dSMaxime Ripard 11670e37f88dSMaxime Ripard while (func->name) { 11680e37f88dSMaxime Ripard /* function already there */ 11690e37f88dSMaxime Ripard if (strcmp(func->name, name) == 0) { 11700e37f88dSMaxime Ripard func->ngroups++; 11710e37f88dSMaxime Ripard return -EEXIST; 11720e37f88dSMaxime Ripard } 11730e37f88dSMaxime Ripard func++; 11740e37f88dSMaxime Ripard } 11750e37f88dSMaxime Ripard 11760e37f88dSMaxime Ripard func->name = name; 11770e37f88dSMaxime Ripard func->ngroups = 1; 11780e37f88dSMaxime Ripard 11790e37f88dSMaxime Ripard pctl->nfunctions++; 11800e37f88dSMaxime Ripard 11810e37f88dSMaxime Ripard return 0; 11820e37f88dSMaxime Ripard } 11830e37f88dSMaxime Ripard 11840e37f88dSMaxime Ripard static int sunxi_pinctrl_build_state(struct platform_device *pdev) 11850e37f88dSMaxime Ripard { 11860e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); 1187a93a676bSChristophe JAILLET void *ptr; 11880e37f88dSMaxime Ripard int i; 11890e37f88dSMaxime Ripard 1190578db85fSMaxime Ripard /* 1191578db85fSMaxime Ripard * Allocate groups 1192578db85fSMaxime Ripard * 1193578db85fSMaxime Ripard * We assume that the number of groups is the number of pins 1194578db85fSMaxime Ripard * given in the data array. 11950e37f88dSMaxime Ripard 1196578db85fSMaxime Ripard * This will not always be true, since some pins might not be 1197578db85fSMaxime Ripard * available in the current variant, but fortunately for us, 1198578db85fSMaxime Ripard * this means that the number of pins is the maximum group 1199578db85fSMaxime Ripard * number we will ever see. 1200578db85fSMaxime Ripard */ 1201a86854d0SKees Cook pctl->groups = devm_kcalloc(&pdev->dev, 1202a86854d0SKees Cook pctl->desc->npins, sizeof(*pctl->groups), 12030e37f88dSMaxime Ripard GFP_KERNEL); 12040e37f88dSMaxime Ripard if (!pctl->groups) 12050e37f88dSMaxime Ripard return -ENOMEM; 12060e37f88dSMaxime Ripard 12070e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 12080e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1209578db85fSMaxime Ripard struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; 1210578db85fSMaxime Ripard 1211578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1212578db85fSMaxime Ripard continue; 12130e37f88dSMaxime Ripard 12140e37f88dSMaxime Ripard group->name = pin->pin.name; 12150e37f88dSMaxime Ripard group->pin = pin->pin.number; 1216578db85fSMaxime Ripard 1217578db85fSMaxime Ripard /* And now we count the actual number of pins / groups */ 1218578db85fSMaxime Ripard pctl->ngroups++; 12190e37f88dSMaxime Ripard } 12200e37f88dSMaxime Ripard 12210e37f88dSMaxime Ripard /* 1222*d1dee814SAndre Przywara * Find an upper bound for the maximum number of functions: in 1223*d1dee814SAndre Przywara * the worst case we have gpio_in, gpio_out, irq and up to four 1224*d1dee814SAndre Przywara * special functions per pin, plus one entry for the sentinel. 1225*d1dee814SAndre Przywara * We'll reallocate that later anyway. 12260e37f88dSMaxime Ripard */ 1227*d1dee814SAndre Przywara pctl->functions = kcalloc(4 * pctl->ngroups + 4, 1228a86854d0SKees Cook sizeof(*pctl->functions), 12290e37f88dSMaxime Ripard GFP_KERNEL); 12300e37f88dSMaxime Ripard if (!pctl->functions) 12310e37f88dSMaxime Ripard return -ENOMEM; 12320e37f88dSMaxime Ripard 12330e37f88dSMaxime Ripard /* Count functions and their associated groups */ 12340e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 12350e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1236578db85fSMaxime Ripard struct sunxi_desc_function *func; 12370e37f88dSMaxime Ripard 1238578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1239578db85fSMaxime Ripard continue; 1240578db85fSMaxime Ripard 1241578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 1242578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1243578db85fSMaxime Ripard continue; 1244578db85fSMaxime Ripard 1245d54e9a28SChen-Yu Tsai /* Create interrupt mapping while we're at it */ 1246aebdc8abSMaxime Ripard if (!strcmp(func->name, "irq")) { 1247aebdc8abSMaxime Ripard int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; 1248aebdc8abSMaxime Ripard pctl->irq_array[irqnum] = pin->pin.number; 1249aebdc8abSMaxime Ripard } 1250aebdc8abSMaxime Ripard 12510e37f88dSMaxime Ripard sunxi_pinctrl_add_function(pctl, func->name); 12520e37f88dSMaxime Ripard } 12530e37f88dSMaxime Ripard } 12540e37f88dSMaxime Ripard 1255578db85fSMaxime Ripard /* And now allocated and fill the array for real */ 1256a93a676bSChristophe JAILLET ptr = krealloc(pctl->functions, 12570e37f88dSMaxime Ripard pctl->nfunctions * sizeof(*pctl->functions), 12580e37f88dSMaxime Ripard GFP_KERNEL); 1259a93a676bSChristophe JAILLET if (!ptr) { 1260578db85fSMaxime Ripard kfree(pctl->functions); 1261a93a676bSChristophe JAILLET pctl->functions = NULL; 1262578db85fSMaxime Ripard return -ENOMEM; 1263578db85fSMaxime Ripard } 1264a93a676bSChristophe JAILLET pctl->functions = ptr; 12650e37f88dSMaxime Ripard 12660e37f88dSMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 12670e37f88dSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1268578db85fSMaxime Ripard struct sunxi_desc_function *func; 12690e37f88dSMaxime Ripard 1270578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1271578db85fSMaxime Ripard continue; 1272578db85fSMaxime Ripard 1273578db85fSMaxime Ripard for (func = pin->functions; func->name; func++) { 12740e37f88dSMaxime Ripard struct sunxi_pinctrl_function *func_item; 12750e37f88dSMaxime Ripard const char **func_grp; 12760e37f88dSMaxime Ripard 1277578db85fSMaxime Ripard if (func->variant && !(pctl->variant & func->variant)) 1278578db85fSMaxime Ripard continue; 1279578db85fSMaxime Ripard 12800e37f88dSMaxime Ripard func_item = sunxi_pinctrl_find_function_by_name(pctl, 12810e37f88dSMaxime Ripard func->name); 1282a4925311SYueHaibing if (!func_item) { 1283a4925311SYueHaibing kfree(pctl->functions); 12840e37f88dSMaxime Ripard return -EINVAL; 1285a4925311SYueHaibing } 12860e37f88dSMaxime Ripard 12870e37f88dSMaxime Ripard if (!func_item->groups) { 12880e37f88dSMaxime Ripard func_item->groups = 1289a86854d0SKees Cook devm_kcalloc(&pdev->dev, 1290a86854d0SKees Cook func_item->ngroups, 1291a86854d0SKees Cook sizeof(*func_item->groups), 12920e37f88dSMaxime Ripard GFP_KERNEL); 1293a4925311SYueHaibing if (!func_item->groups) { 1294a4925311SYueHaibing kfree(pctl->functions); 12950e37f88dSMaxime Ripard return -ENOMEM; 12960e37f88dSMaxime Ripard } 1297a4925311SYueHaibing } 12980e37f88dSMaxime Ripard 12990e37f88dSMaxime Ripard func_grp = func_item->groups; 13000e37f88dSMaxime Ripard while (*func_grp) 13010e37f88dSMaxime Ripard func_grp++; 13020e37f88dSMaxime Ripard 13030e37f88dSMaxime Ripard *func_grp = pin->pin.name; 13040e37f88dSMaxime Ripard } 13050e37f88dSMaxime Ripard } 13060e37f88dSMaxime Ripard 13070e37f88dSMaxime Ripard return 0; 13080e37f88dSMaxime Ripard } 13090e37f88dSMaxime Ripard 13107c926492SMaxime Ripard static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff) 13117c926492SMaxime Ripard { 13127c926492SMaxime Ripard unsigned long clock = clk_get_rate(clk); 1313d8a22212SArnd Bergmann unsigned int best_diff, best_div; 13147c926492SMaxime Ripard int i; 13157c926492SMaxime Ripard 1316d8a22212SArnd Bergmann best_diff = abs(freq - clock); 1317d8a22212SArnd Bergmann best_div = 0; 1318d8a22212SArnd Bergmann 1319d8a22212SArnd Bergmann for (i = 1; i < 8; i++) { 13207c926492SMaxime Ripard int cur_diff = abs(freq - (clock >> i)); 13217c926492SMaxime Ripard 13227c926492SMaxime Ripard if (cur_diff < best_diff) { 13237c926492SMaxime Ripard best_diff = cur_diff; 13247c926492SMaxime Ripard best_div = i; 13257c926492SMaxime Ripard } 13267c926492SMaxime Ripard } 13277c926492SMaxime Ripard 13287c926492SMaxime Ripard *diff = best_diff; 13297c926492SMaxime Ripard return best_div; 13307c926492SMaxime Ripard } 13317c926492SMaxime Ripard 13327c926492SMaxime Ripard static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, 13337c926492SMaxime Ripard struct device_node *node) 13347c926492SMaxime Ripard { 13357c926492SMaxime Ripard unsigned int hosc_diff, losc_diff; 13367c926492SMaxime Ripard unsigned int hosc_div, losc_div; 13377c926492SMaxime Ripard struct clk *hosc, *losc; 13387c926492SMaxime Ripard u8 div, src; 13397c926492SMaxime Ripard int i, ret; 13407c926492SMaxime Ripard 13417c926492SMaxime Ripard /* Deal with old DTs that didn't have the oscillators */ 1342470b73a3SGeert Uytterhoeven if (of_clk_get_parent_count(node) != 3) 13437c926492SMaxime Ripard return 0; 13447c926492SMaxime Ripard 13457c926492SMaxime Ripard /* If we don't have any setup, bail out */ 13467c926492SMaxime Ripard if (!of_find_property(node, "input-debounce", NULL)) 13477c926492SMaxime Ripard return 0; 13487c926492SMaxime Ripard 13497c926492SMaxime Ripard losc = devm_clk_get(pctl->dev, "losc"); 13507c926492SMaxime Ripard if (IS_ERR(losc)) 13517c926492SMaxime Ripard return PTR_ERR(losc); 13527c926492SMaxime Ripard 13537c926492SMaxime Ripard hosc = devm_clk_get(pctl->dev, "hosc"); 13547c926492SMaxime Ripard if (IS_ERR(hosc)) 13557c926492SMaxime Ripard return PTR_ERR(hosc); 13567c926492SMaxime Ripard 13577c926492SMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 13587c926492SMaxime Ripard unsigned long debounce_freq; 13597c926492SMaxime Ripard u32 debounce; 13607c926492SMaxime Ripard 13617c926492SMaxime Ripard ret = of_property_read_u32_index(node, "input-debounce", 13627c926492SMaxime Ripard i, &debounce); 13637c926492SMaxime Ripard if (ret) 13647c926492SMaxime Ripard return ret; 13657c926492SMaxime Ripard 13667c926492SMaxime Ripard if (!debounce) 13677c926492SMaxime Ripard continue; 13687c926492SMaxime Ripard 13697c926492SMaxime Ripard debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce); 13707c926492SMaxime Ripard losc_div = sunxi_pinctrl_get_debounce_div(losc, 13717c926492SMaxime Ripard debounce_freq, 13727c926492SMaxime Ripard &losc_diff); 13737c926492SMaxime Ripard 13747c926492SMaxime Ripard hosc_div = sunxi_pinctrl_get_debounce_div(hosc, 13757c926492SMaxime Ripard debounce_freq, 13767c926492SMaxime Ripard &hosc_diff); 13777c926492SMaxime Ripard 13787c926492SMaxime Ripard if (hosc_diff < losc_diff) { 13797c926492SMaxime Ripard div = hosc_div; 13807c926492SMaxime Ripard src = 1; 13817c926492SMaxime Ripard } else { 13827c926492SMaxime Ripard div = losc_div; 13837c926492SMaxime Ripard src = 0; 13847c926492SMaxime Ripard } 13857c926492SMaxime Ripard 13867c926492SMaxime Ripard writel(src | div << 4, 13877c926492SMaxime Ripard pctl->membase + 13884b0d6c5aSIcenowy Zheng sunxi_irq_debounce_reg_from_bank(pctl->desc, i)); 13897c926492SMaxime Ripard } 13907c926492SMaxime Ripard 13917c926492SMaxime Ripard return 0; 13927c926492SMaxime Ripard } 13937c926492SMaxime Ripard 1394578db85fSMaxime Ripard int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, 1395578db85fSMaxime Ripard const struct sunxi_pinctrl_desc *desc, 1396578db85fSMaxime Ripard unsigned long variant) 13970e37f88dSMaxime Ripard { 13980e37f88dSMaxime Ripard struct device_node *node = pdev->dev.of_node; 1399ba6764d5SMaxime Ripard struct pinctrl_desc *pctrl_desc; 14000e37f88dSMaxime Ripard struct pinctrl_pin_desc *pins; 14010e37f88dSMaxime Ripard struct sunxi_pinctrl *pctl; 1402aae842a3SMaxime Ripard struct pinmux_ops *pmxops; 1403578db85fSMaxime Ripard int i, ret, last_pin, pin_idx; 1404950707c0SEmilio López struct clk *clk; 14050e37f88dSMaxime Ripard 14060e37f88dSMaxime Ripard pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 14070e37f88dSMaxime Ripard if (!pctl) 14080e37f88dSMaxime Ripard return -ENOMEM; 14090e37f88dSMaxime Ripard platform_set_drvdata(pdev, pctl); 14100e37f88dSMaxime Ripard 1411f658ed36SJulia Cartwright raw_spin_lock_init(&pctl->lock); 14121bee963dSMaxime Ripard 14134b024225SYueHaibing pctl->membase = devm_platform_ioremap_resource(pdev, 0); 14144409cafcSMaxime Ripard if (IS_ERR(pctl->membase)) 14154409cafcSMaxime Ripard return PTR_ERR(pctl->membase); 14160e37f88dSMaxime Ripard 1417ba6764d5SMaxime Ripard pctl->dev = &pdev->dev; 14182284ba6bSMaxime Ripard pctl->desc = desc; 1419578db85fSMaxime Ripard pctl->variant = variant; 14200e37f88dSMaxime Ripard 1421aebdc8abSMaxime Ripard pctl->irq_array = devm_kcalloc(&pdev->dev, 1422aebdc8abSMaxime Ripard IRQ_PER_BANK * pctl->desc->irq_banks, 1423aebdc8abSMaxime Ripard sizeof(*pctl->irq_array), 1424aebdc8abSMaxime Ripard GFP_KERNEL); 1425aebdc8abSMaxime Ripard if (!pctl->irq_array) 1426aebdc8abSMaxime Ripard return -ENOMEM; 1427aebdc8abSMaxime Ripard 14280e37f88dSMaxime Ripard ret = sunxi_pinctrl_build_state(pdev); 14290e37f88dSMaxime Ripard if (ret) { 14300e37f88dSMaxime Ripard dev_err(&pdev->dev, "dt probe failed: %d\n", ret); 14310e37f88dSMaxime Ripard return ret; 14320e37f88dSMaxime Ripard } 14330e37f88dSMaxime Ripard 1434a86854d0SKees Cook pins = devm_kcalloc(&pdev->dev, 1435a86854d0SKees Cook pctl->desc->npins, sizeof(*pins), 14360e37f88dSMaxime Ripard GFP_KERNEL); 14370e37f88dSMaxime Ripard if (!pins) 14380e37f88dSMaxime Ripard return -ENOMEM; 14390e37f88dSMaxime Ripard 1440578db85fSMaxime Ripard for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { 1441578db85fSMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 1442578db85fSMaxime Ripard 1443578db85fSMaxime Ripard if (pin->variant && !(pctl->variant & pin->variant)) 1444578db85fSMaxime Ripard continue; 1445578db85fSMaxime Ripard 1446578db85fSMaxime Ripard pins[pin_idx++] = pin->pin; 1447578db85fSMaxime Ripard } 14480e37f88dSMaxime Ripard 1449ba6764d5SMaxime Ripard pctrl_desc = devm_kzalloc(&pdev->dev, 1450ba6764d5SMaxime Ripard sizeof(*pctrl_desc), 1451ba6764d5SMaxime Ripard GFP_KERNEL); 1452ba6764d5SMaxime Ripard if (!pctrl_desc) 1453ba6764d5SMaxime Ripard return -ENOMEM; 1454ba6764d5SMaxime Ripard 1455ba6764d5SMaxime Ripard pctrl_desc->name = dev_name(&pdev->dev); 1456ba6764d5SMaxime Ripard pctrl_desc->owner = THIS_MODULE; 1457ba6764d5SMaxime Ripard pctrl_desc->pins = pins; 1458578db85fSMaxime Ripard pctrl_desc->npins = pctl->ngroups; 1459ba6764d5SMaxime Ripard pctrl_desc->confops = &sunxi_pconf_ops; 1460ba6764d5SMaxime Ripard pctrl_desc->pctlops = &sunxi_pctrl_ops; 1461aae842a3SMaxime Ripard 1462aae842a3SMaxime Ripard pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops), 1463aae842a3SMaxime Ripard GFP_KERNEL); 1464aae842a3SMaxime Ripard if (!pmxops) 1465aae842a3SMaxime Ripard return -ENOMEM; 1466aae842a3SMaxime Ripard 1467aae842a3SMaxime Ripard if (desc->disable_strict_mode) 1468aae842a3SMaxime Ripard pmxops->strict = false; 1469aae842a3SMaxime Ripard 1470aae842a3SMaxime Ripard pctrl_desc->pmxops = pmxops; 1471ba6764d5SMaxime Ripard 147245078ea0SLaxman Dewangan pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); 1473323de9efSMasahiro Yamada if (IS_ERR(pctl->pctl_dev)) { 14740e37f88dSMaxime Ripard dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); 1475323de9efSMasahiro Yamada return PTR_ERR(pctl->pctl_dev); 14760e37f88dSMaxime Ripard } 14770e37f88dSMaxime Ripard 147808e9e614SMaxime Ripard pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); 147945078ea0SLaxman Dewangan if (!pctl->chip) 148045078ea0SLaxman Dewangan return -ENOMEM; 148108e9e614SMaxime Ripard 148208e9e614SMaxime Ripard last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; 1483d83c82ceSBoris BREZILLON pctl->chip->owner = THIS_MODULE; 1484fb7dea60SMaxime Ripard pctl->chip->request = gpiochip_generic_request; 1485fb7dea60SMaxime Ripard pctl->chip->free = gpiochip_generic_free; 148604ed8c0cSMaxime Ripard pctl->chip->set_config = gpiochip_generic_config; 1487fb7dea60SMaxime Ripard pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input; 1488fb7dea60SMaxime Ripard pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output; 1489fb7dea60SMaxime Ripard pctl->chip->get = sunxi_pinctrl_gpio_get; 1490fb7dea60SMaxime Ripard pctl->chip->set = sunxi_pinctrl_gpio_set; 1491fb7dea60SMaxime Ripard pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate; 1492fb7dea60SMaxime Ripard pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq; 1493fb7dea60SMaxime Ripard pctl->chip->of_gpio_n_cells = 3; 1494fb7dea60SMaxime Ripard pctl->chip->can_sleep = false; 1495d83c82ceSBoris BREZILLON pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) - 1496d83c82ceSBoris BREZILLON pctl->desc->pin_base; 149708e9e614SMaxime Ripard pctl->chip->label = dev_name(&pdev->dev); 149858383c78SLinus Walleij pctl->chip->parent = &pdev->dev; 1499d83c82ceSBoris BREZILLON pctl->chip->base = pctl->desc->pin_base; 150008e9e614SMaxime Ripard 150188057d6eSLinus Walleij ret = gpiochip_add_data(pctl->chip, pctl); 150208e9e614SMaxime Ripard if (ret) 150345078ea0SLaxman Dewangan return ret; 150408e9e614SMaxime Ripard 150508e9e614SMaxime Ripard for (i = 0; i < pctl->desc->npins; i++) { 150608e9e614SMaxime Ripard const struct sunxi_desc_pin *pin = pctl->desc->pins + i; 150708e9e614SMaxime Ripard 150808e9e614SMaxime Ripard ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), 1509343f1327SChen-Yu Tsai pin->pin.number - pctl->desc->pin_base, 151008e9e614SMaxime Ripard pin->pin.number, 1); 151108e9e614SMaxime Ripard if (ret) 151208e9e614SMaxime Ripard goto gpiochip_error; 151308e9e614SMaxime Ripard } 151408e9e614SMaxime Ripard 151510e3a88bSGeert Uytterhoeven ret = of_clk_get_parent_count(node); 1516a34ea4b4SAndre Przywara clk = devm_clk_get(&pdev->dev, ret == 1 ? NULL : "apb"); 1517d72f88a4SWei Yongjun if (IS_ERR(clk)) { 1518d72f88a4SWei Yongjun ret = PTR_ERR(clk); 1519950707c0SEmilio López goto gpiochip_error; 1520d72f88a4SWei Yongjun } 1521950707c0SEmilio López 15226415093fSBoris BREZILLON ret = clk_prepare_enable(clk); 15236415093fSBoris BREZILLON if (ret) 15246415093fSBoris BREZILLON goto gpiochip_error; 1525950707c0SEmilio López 1526aebdc8abSMaxime Ripard pctl->irq = devm_kcalloc(&pdev->dev, 1527aebdc8abSMaxime Ripard pctl->desc->irq_banks, 1528aebdc8abSMaxime Ripard sizeof(*pctl->irq), 1529aebdc8abSMaxime Ripard GFP_KERNEL); 153060242db1SMaxime Ripard if (!pctl->irq) { 1531aebdc8abSMaxime Ripard ret = -ENOMEM; 1532dc969106SMaxime Ripard goto clk_error; 153360242db1SMaxime Ripard } 153460242db1SMaxime Ripard 1535aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1536aebdc8abSMaxime Ripard pctl->irq[i] = platform_get_irq(pdev, i); 1537aebdc8abSMaxime Ripard if (pctl->irq[i] < 0) { 1538aebdc8abSMaxime Ripard ret = pctl->irq[i]; 1539aebdc8abSMaxime Ripard goto clk_error; 1540aebdc8abSMaxime Ripard } 1541aebdc8abSMaxime Ripard } 1542aebdc8abSMaxime Ripard 1543aebdc8abSMaxime Ripard pctl->domain = irq_domain_add_linear(node, 1544aebdc8abSMaxime Ripard pctl->desc->irq_banks * IRQ_PER_BANK, 1545d8323c6bSMaxime Ripard &sunxi_pinctrl_irq_domain_ops, 1546d8323c6bSMaxime Ripard pctl); 154760242db1SMaxime Ripard if (!pctl->domain) { 154860242db1SMaxime Ripard dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); 154960242db1SMaxime Ripard ret = -ENOMEM; 1550dc969106SMaxime Ripard goto clk_error; 155160242db1SMaxime Ripard } 155260242db1SMaxime Ripard 1553aebdc8abSMaxime Ripard for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) { 155460242db1SMaxime Ripard int irqno = irq_create_mapping(pctl->domain, i); 155560242db1SMaxime Ripard 1556f4c51c10SHans de Goede irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip, 1557f4c51c10SHans de Goede handle_edge_irq); 155860242db1SMaxime Ripard irq_set_chip_data(irqno, pctl); 15595c99c0ffSJavier Martinez Canillas } 156060242db1SMaxime Ripard 1561aebdc8abSMaxime Ripard for (i = 0; i < pctl->desc->irq_banks; i++) { 1562f4c51c10SHans de Goede /* Mask and clear all IRQs before registering a handler */ 15634b0d6c5aSIcenowy Zheng writel(0, pctl->membase + 15644b0d6c5aSIcenowy Zheng sunxi_irq_ctrl_reg_from_bank(pctl->desc, i)); 1565f4c51c10SHans de Goede writel(0xffffffff, 15664b0d6c5aSIcenowy Zheng pctl->membase + 15674b0d6c5aSIcenowy Zheng sunxi_irq_status_reg_from_bank(pctl->desc, i)); 1568f4c51c10SHans de Goede 1569ef80e87dSThomas Gleixner irq_set_chained_handler_and_data(pctl->irq[i], 1570ef80e87dSThomas Gleixner sunxi_pinctrl_irq_handler, 1571ef80e87dSThomas Gleixner pctl); 1572aebdc8abSMaxime Ripard } 157360242db1SMaxime Ripard 15747c926492SMaxime Ripard sunxi_pinctrl_setup_debounce(pctl, node); 15757c926492SMaxime Ripard 157608e9e614SMaxime Ripard dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); 15770e37f88dSMaxime Ripard 15780e37f88dSMaxime Ripard return 0; 157908e9e614SMaxime Ripard 1580e2bddc6aSBoris BREZILLON clk_error: 1581e2bddc6aSBoris BREZILLON clk_disable_unprepare(clk); 158208e9e614SMaxime Ripard gpiochip_error: 1583b4e7c55dSabdoulaye berthe gpiochip_remove(pctl->chip); 158408e9e614SMaxime Ripard return ret; 15850e37f88dSMaxime Ripard } 1586