1c2b39decSFabio Estevam // SPDX-License-Identifier: GPL-2.0+ 2c2b39decSFabio Estevam // 3c2b39decSFabio Estevam // Core driver for the imx pin controller 4c2b39decSFabio Estevam // 5c2b39decSFabio Estevam // Copyright (C) 2012 Freescale Semiconductor, Inc. 6c2b39decSFabio Estevam // Copyright (C) 2012 Linaro Ltd. 7c2b39decSFabio Estevam // 8c2b39decSFabio Estevam // Author: Dong Aisheng <dong.aisheng@linaro.org> 9edad3b2aSLinus Walleij 10edad3b2aSLinus Walleij #include <linux/err.h> 11edad3b2aSLinus Walleij #include <linux/init.h> 12edad3b2aSLinus Walleij #include <linux/io.h> 138626ada8SPhilipp Zabel #include <linux/mfd/syscon.h> 14edad3b2aSLinus Walleij #include <linux/of.h> 15edad3b2aSLinus Walleij #include <linux/of_device.h> 1626d8cde5SAdrian Alonso #include <linux/of_address.h> 17edad3b2aSLinus Walleij #include <linux/pinctrl/machine.h> 18edad3b2aSLinus Walleij #include <linux/pinctrl/pinconf.h> 19edad3b2aSLinus Walleij #include <linux/pinctrl/pinctrl.h> 20edad3b2aSLinus Walleij #include <linux/pinctrl/pinmux.h> 21edad3b2aSLinus Walleij #include <linux/slab.h> 228626ada8SPhilipp Zabel #include <linux/regmap.h> 23edad3b2aSLinus Walleij 24edad3b2aSLinus Walleij #include "../core.h" 25a5cadbbbSDong Aisheng #include "../pinconf.h" 263fd6d6adSGary Bisson #include "../pinmux.h" 27edad3b2aSLinus Walleij #include "pinctrl-imx.h" 28edad3b2aSLinus Walleij 29edad3b2aSLinus Walleij /* The bits in CONFIG cell defined in binding doc*/ 30edad3b2aSLinus Walleij #define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */ 31edad3b2aSLinus Walleij #define IMX_PAD_SION 0x40000000 /* set SION */ 32edad3b2aSLinus Walleij 33e566fc11SGary Bisson static inline const struct group_desc *imx_pinctrl_find_group_by_name( 34e566fc11SGary Bisson struct pinctrl_dev *pctldev, 35edad3b2aSLinus Walleij const char *name) 36edad3b2aSLinus Walleij { 37e566fc11SGary Bisson const struct group_desc *grp = NULL; 38edad3b2aSLinus Walleij int i; 39edad3b2aSLinus Walleij 40e566fc11SGary Bisson for (i = 0; i < pctldev->num_groups; i++) { 41e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, i); 42a51c158bSGary Bisson if (grp && !strcmp(grp->name, name)) 43edad3b2aSLinus Walleij break; 44edad3b2aSLinus Walleij } 45edad3b2aSLinus Walleij 46edad3b2aSLinus Walleij return grp; 47edad3b2aSLinus Walleij } 48edad3b2aSLinus Walleij 49edad3b2aSLinus Walleij static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 50edad3b2aSLinus Walleij unsigned offset) 51edad3b2aSLinus Walleij { 52edad3b2aSLinus Walleij seq_printf(s, "%s", dev_name(pctldev->dev)); 53edad3b2aSLinus Walleij } 54edad3b2aSLinus Walleij 55edad3b2aSLinus Walleij static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, 56edad3b2aSLinus Walleij struct device_node *np, 57edad3b2aSLinus Walleij struct pinctrl_map **map, unsigned *num_maps) 58edad3b2aSLinus Walleij { 59edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 60b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 61e566fc11SGary Bisson const struct group_desc *grp; 62edad3b2aSLinus Walleij struct pinctrl_map *new_map; 63edad3b2aSLinus Walleij struct device_node *parent; 64b96eea71SA.s. Dong struct imx_pin *pin; 65edad3b2aSLinus Walleij int map_num = 1; 66edad3b2aSLinus Walleij int i, j; 67edad3b2aSLinus Walleij 68edad3b2aSLinus Walleij /* 69edad3b2aSLinus Walleij * first find the group of this node and check if we need create 70edad3b2aSLinus Walleij * config maps for pins 71edad3b2aSLinus Walleij */ 72e566fc11SGary Bisson grp = imx_pinctrl_find_group_by_name(pctldev, np->name); 73edad3b2aSLinus Walleij if (!grp) { 7494f4e54cSRob Herring dev_err(ipctl->dev, "unable to find group for node %pOFn\n", np); 75edad3b2aSLinus Walleij return -EINVAL; 76edad3b2aSLinus Walleij } 77edad3b2aSLinus Walleij 78b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 79b96eea71SA.s. Dong map_num += grp->num_pins; 80b96eea71SA.s. Dong } else { 81e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 82b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 83b96eea71SA.s. Dong if (!(pin->conf.mmio.config & IMX_NO_PAD_CTL)) 84edad3b2aSLinus Walleij map_num++; 85edad3b2aSLinus Walleij } 86b96eea71SA.s. Dong } 87edad3b2aSLinus Walleij 886da2ec56SKees Cook new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), 896da2ec56SKees Cook GFP_KERNEL); 90edad3b2aSLinus Walleij if (!new_map) 91edad3b2aSLinus Walleij return -ENOMEM; 92edad3b2aSLinus Walleij 93edad3b2aSLinus Walleij *map = new_map; 94edad3b2aSLinus Walleij *num_maps = map_num; 95edad3b2aSLinus Walleij 96edad3b2aSLinus Walleij /* create mux map */ 97edad3b2aSLinus Walleij parent = of_get_parent(np); 98edad3b2aSLinus Walleij if (!parent) { 99edad3b2aSLinus Walleij kfree(new_map); 100edad3b2aSLinus Walleij return -EINVAL; 101edad3b2aSLinus Walleij } 102edad3b2aSLinus Walleij new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; 103edad3b2aSLinus Walleij new_map[0].data.mux.function = parent->name; 104edad3b2aSLinus Walleij new_map[0].data.mux.group = np->name; 105edad3b2aSLinus Walleij of_node_put(parent); 106edad3b2aSLinus Walleij 107edad3b2aSLinus Walleij /* create config map */ 108edad3b2aSLinus Walleij new_map++; 109e566fc11SGary Bisson for (i = j = 0; i < grp->num_pins; i++) { 110b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 11157161067SA.s. Dong 11257161067SA.s. Dong /* 11357161067SA.s. Dong * We only create config maps for SCU pads or MMIO pads that 11457161067SA.s. Dong * are not using the default config(a.k.a IMX_NO_PAD_CTL) 11557161067SA.s. Dong */ 11657161067SA.s. Dong if (!(info->flags & IMX_USE_SCU) && 11757161067SA.s. Dong (pin->conf.mmio.config & IMX_NO_PAD_CTL)) 11857161067SA.s. Dong continue; 11957161067SA.s. Dong 120edad3b2aSLinus Walleij new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; 121edad3b2aSLinus Walleij new_map[j].data.configs.group_or_pin = 122e566fc11SGary Bisson pin_get_name(pctldev, pin->pin); 123b96eea71SA.s. Dong 124b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 125b96eea71SA.s. Dong /* 126b96eea71SA.s. Dong * For SCU case, we set mux and conf together 127b96eea71SA.s. Dong * in one IPC call 128b96eea71SA.s. Dong */ 129b96eea71SA.s. Dong new_map[j].data.configs.configs = 130b96eea71SA.s. Dong (unsigned long *)&pin->conf.scu; 131b96eea71SA.s. Dong new_map[j].data.configs.num_configs = 2; 13257161067SA.s. Dong } else { 133b96eea71SA.s. Dong new_map[j].data.configs.configs = 134b96eea71SA.s. Dong &pin->conf.mmio.config; 135edad3b2aSLinus Walleij new_map[j].data.configs.num_configs = 1; 136edad3b2aSLinus Walleij } 137b96eea71SA.s. Dong 138b96eea71SA.s. Dong j++; 139edad3b2aSLinus Walleij } 140edad3b2aSLinus Walleij 141edad3b2aSLinus Walleij dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", 142edad3b2aSLinus Walleij (*map)->data.mux.function, (*map)->data.mux.group, map_num); 143edad3b2aSLinus Walleij 144edad3b2aSLinus Walleij return 0; 145edad3b2aSLinus Walleij } 146edad3b2aSLinus Walleij 147edad3b2aSLinus Walleij static void imx_dt_free_map(struct pinctrl_dev *pctldev, 148edad3b2aSLinus Walleij struct pinctrl_map *map, unsigned num_maps) 149edad3b2aSLinus Walleij { 150edad3b2aSLinus Walleij kfree(map); 151edad3b2aSLinus Walleij } 152edad3b2aSLinus Walleij 153edad3b2aSLinus Walleij static const struct pinctrl_ops imx_pctrl_ops = { 154e566fc11SGary Bisson .get_groups_count = pinctrl_generic_get_group_count, 155e566fc11SGary Bisson .get_group_name = pinctrl_generic_get_group_name, 156e566fc11SGary Bisson .get_group_pins = pinctrl_generic_get_group_pins, 157edad3b2aSLinus Walleij .pin_dbg_show = imx_pin_dbg_show, 158edad3b2aSLinus Walleij .dt_node_to_map = imx_dt_node_to_map, 159edad3b2aSLinus Walleij .dt_free_map = imx_dt_free_map, 160edad3b2aSLinus Walleij }; 161edad3b2aSLinus Walleij 162b96eea71SA.s. Dong static int imx_pmx_set_one_pin_mmio(struct imx_pinctrl *ipctl, 163b96eea71SA.s. Dong struct imx_pin *pin) 164b96eea71SA.s. Dong { 165b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 166b96eea71SA.s. Dong struct imx_pin_mmio *pin_mmio = &pin->conf.mmio; 167b96eea71SA.s. Dong const struct imx_pin_reg *pin_reg; 168b96eea71SA.s. Dong unsigned int pin_id; 169b96eea71SA.s. Dong 170b96eea71SA.s. Dong pin_id = pin->pin; 171b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[pin_id]; 172b96eea71SA.s. Dong 173b96eea71SA.s. Dong if (pin_reg->mux_reg == -1) { 174b96eea71SA.s. Dong dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n", 175b96eea71SA.s. Dong info->pins[pin_id].name); 176b96eea71SA.s. Dong return 0; 177b96eea71SA.s. Dong } 178b96eea71SA.s. Dong 179b96eea71SA.s. Dong if (info->flags & SHARE_MUX_CONF_REG) { 180b96eea71SA.s. Dong u32 reg; 181b96eea71SA.s. Dong 182b96eea71SA.s. Dong reg = readl(ipctl->base + pin_reg->mux_reg); 183b96eea71SA.s. Dong reg &= ~info->mux_mask; 184b96eea71SA.s. Dong reg |= (pin_mmio->mux_mode << info->mux_shift); 185b96eea71SA.s. Dong writel(reg, ipctl->base + pin_reg->mux_reg); 186b96eea71SA.s. Dong dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 187b96eea71SA.s. Dong pin_reg->mux_reg, reg); 188b96eea71SA.s. Dong } else { 189b96eea71SA.s. Dong writel(pin_mmio->mux_mode, ipctl->base + pin_reg->mux_reg); 190b96eea71SA.s. Dong dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 191b96eea71SA.s. Dong pin_reg->mux_reg, pin_mmio->mux_mode); 192b96eea71SA.s. Dong } 193b96eea71SA.s. Dong 194b96eea71SA.s. Dong /* 195b96eea71SA.s. Dong * If the select input value begins with 0xff, it's a quirky 196b96eea71SA.s. Dong * select input and the value should be interpreted as below. 197b96eea71SA.s. Dong * 31 23 15 7 0 198b96eea71SA.s. Dong * | 0xff | shift | width | select | 199b96eea71SA.s. Dong * It's used to work around the problem that the select 200b96eea71SA.s. Dong * input for some pin is not implemented in the select 201b96eea71SA.s. Dong * input register but in some general purpose register. 202b96eea71SA.s. Dong * We encode the select input value, width and shift of 203b96eea71SA.s. Dong * the bit field into input_val cell of pin function ID 204b96eea71SA.s. Dong * in device tree, and then decode them here for setting 205b96eea71SA.s. Dong * up the select input bits in general purpose register. 206b96eea71SA.s. Dong */ 207b96eea71SA.s. Dong if (pin_mmio->input_val >> 24 == 0xff) { 208b96eea71SA.s. Dong u32 val = pin_mmio->input_val; 209b96eea71SA.s. Dong u8 select = val & 0xff; 210b96eea71SA.s. Dong u8 width = (val >> 8) & 0xff; 211b96eea71SA.s. Dong u8 shift = (val >> 16) & 0xff; 212b96eea71SA.s. Dong u32 mask = ((1 << width) - 1) << shift; 213b96eea71SA.s. Dong /* 214b96eea71SA.s. Dong * The input_reg[i] here is actually some IOMUXC general 215b96eea71SA.s. Dong * purpose register, not regular select input register. 216b96eea71SA.s. Dong */ 217b96eea71SA.s. Dong val = readl(ipctl->base + pin_mmio->input_reg); 218b96eea71SA.s. Dong val &= ~mask; 219b96eea71SA.s. Dong val |= select << shift; 220b96eea71SA.s. Dong writel(val, ipctl->base + pin_mmio->input_reg); 221b96eea71SA.s. Dong } else if (pin_mmio->input_reg) { 222b96eea71SA.s. Dong /* 223b96eea71SA.s. Dong * Regular select input register can never be at offset 224b96eea71SA.s. Dong * 0, and we only print register value for regular case. 225b96eea71SA.s. Dong */ 226b96eea71SA.s. Dong if (ipctl->input_sel_base) 227b96eea71SA.s. Dong writel(pin_mmio->input_val, ipctl->input_sel_base + 228b96eea71SA.s. Dong pin_mmio->input_reg); 229b96eea71SA.s. Dong else 230b96eea71SA.s. Dong writel(pin_mmio->input_val, ipctl->base + 231b96eea71SA.s. Dong pin_mmio->input_reg); 232b96eea71SA.s. Dong dev_dbg(ipctl->dev, 233b96eea71SA.s. Dong "==>select_input: offset 0x%x val 0x%x\n", 234b96eea71SA.s. Dong pin_mmio->input_reg, pin_mmio->input_val); 235b96eea71SA.s. Dong } 236b96eea71SA.s. Dong 237b96eea71SA.s. Dong return 0; 238b96eea71SA.s. Dong } 239b96eea71SA.s. Dong 240edad3b2aSLinus Walleij static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, 241edad3b2aSLinus Walleij unsigned group) 242edad3b2aSLinus Walleij { 243edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 244f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 245b96eea71SA.s. Dong struct function_desc *func; 246b96eea71SA.s. Dong struct group_desc *grp; 247b96eea71SA.s. Dong struct imx_pin *pin; 248b96eea71SA.s. Dong unsigned int npins; 249b96eea71SA.s. Dong int i, err; 250edad3b2aSLinus Walleij 251edad3b2aSLinus Walleij /* 252edad3b2aSLinus Walleij * Configure the mux mode for each pin in the group for a specific 253edad3b2aSLinus Walleij * function. 254edad3b2aSLinus Walleij */ 255e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, group); 256a51c158bSGary Bisson if (!grp) 257a51c158bSGary Bisson return -EINVAL; 258a51c158bSGary Bisson 2593fd6d6adSGary Bisson func = pinmux_generic_get_function(pctldev, selector); 260a51c158bSGary Bisson if (!func) 261a51c158bSGary Bisson return -EINVAL; 262a51c158bSGary Bisson 263e566fc11SGary Bisson npins = grp->num_pins; 264edad3b2aSLinus Walleij 265edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "enable function %s group %s\n", 266a51c158bSGary Bisson func->name, grp->name); 267edad3b2aSLinus Walleij 268edad3b2aSLinus Walleij for (i = 0; i < npins; i++) { 269edad3b2aSLinus Walleij /* 270b96eea71SA.s. Dong * For IMX_USE_SCU case, we postpone the mux setting 271b96eea71SA.s. Dong * until config is set as we can set them together 272b96eea71SA.s. Dong * in one IPC call 273edad3b2aSLinus Walleij */ 274b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 275b96eea71SA.s. Dong if (!(info->flags & IMX_USE_SCU)) { 276b96eea71SA.s. Dong err = imx_pmx_set_one_pin_mmio(ipctl, pin); 277b96eea71SA.s. Dong if (err) 278b96eea71SA.s. Dong return err; 279edad3b2aSLinus Walleij } 280edad3b2aSLinus Walleij } 281edad3b2aSLinus Walleij 282edad3b2aSLinus Walleij return 0; 283edad3b2aSLinus Walleij } 284edad3b2aSLinus Walleij 2853be6f651SDong Aisheng struct pinmux_ops imx_pmx_ops = { 2863fd6d6adSGary Bisson .get_functions_count = pinmux_generic_get_function_count, 2873fd6d6adSGary Bisson .get_function_name = pinmux_generic_get_function_name, 2883fd6d6adSGary Bisson .get_function_groups = pinmux_generic_get_function_groups, 289edad3b2aSLinus Walleij .set_mux = imx_pmx_set, 290edad3b2aSLinus Walleij }; 291edad3b2aSLinus Walleij 292a5cadbbbSDong Aisheng /* decode generic config into raw register values */ 293a5cadbbbSDong Aisheng static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, 294a5cadbbbSDong Aisheng unsigned long *configs, 295a5cadbbbSDong Aisheng unsigned int num_configs) 296a5cadbbbSDong Aisheng { 297f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 298d6093367SStefan Agner const struct imx_cfg_params_decode *decode; 299a5cadbbbSDong Aisheng enum pin_config_param param; 300a5cadbbbSDong Aisheng u32 raw_config = 0; 301a5cadbbbSDong Aisheng u32 param_val; 302a5cadbbbSDong Aisheng int i, j; 303a5cadbbbSDong Aisheng 304a5cadbbbSDong Aisheng WARN_ON(num_configs > info->num_decodes); 305a5cadbbbSDong Aisheng 306a5cadbbbSDong Aisheng for (i = 0; i < num_configs; i++) { 307a5cadbbbSDong Aisheng param = pinconf_to_config_param(configs[i]); 308a5cadbbbSDong Aisheng param_val = pinconf_to_config_argument(configs[i]); 309a5cadbbbSDong Aisheng decode = info->decodes; 310a5cadbbbSDong Aisheng for (j = 0; j < info->num_decodes; j++) { 311a5cadbbbSDong Aisheng if (param == decode->param) { 312a5cadbbbSDong Aisheng if (decode->invert) 313a5cadbbbSDong Aisheng param_val = !param_val; 314a5cadbbbSDong Aisheng raw_config |= (param_val << decode->shift) 315a5cadbbbSDong Aisheng & decode->mask; 316a5cadbbbSDong Aisheng break; 317a5cadbbbSDong Aisheng } 318a5cadbbbSDong Aisheng decode++; 319a5cadbbbSDong Aisheng } 320a5cadbbbSDong Aisheng } 321a5cadbbbSDong Aisheng 322a5cadbbbSDong Aisheng if (info->fixup) 323a5cadbbbSDong Aisheng info->fixup(configs, num_configs, &raw_config); 324a5cadbbbSDong Aisheng 325a5cadbbbSDong Aisheng return raw_config; 326a5cadbbbSDong Aisheng } 327a5cadbbbSDong Aisheng 328a5cadbbbSDong Aisheng static u32 imx_pinconf_parse_generic_config(struct device_node *np, 329a5cadbbbSDong Aisheng struct imx_pinctrl *ipctl) 330a5cadbbbSDong Aisheng { 331f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 332a5cadbbbSDong Aisheng struct pinctrl_dev *pctl = ipctl->pctl; 333a5cadbbbSDong Aisheng unsigned int num_configs; 334a5cadbbbSDong Aisheng unsigned long *configs; 335a5cadbbbSDong Aisheng int ret; 336a5cadbbbSDong Aisheng 337a5cadbbbSDong Aisheng if (!info->generic_pinconf) 338a5cadbbbSDong Aisheng return 0; 339a5cadbbbSDong Aisheng 340a5cadbbbSDong Aisheng ret = pinconf_generic_parse_dt_config(np, pctl, &configs, 341a5cadbbbSDong Aisheng &num_configs); 342a5cadbbbSDong Aisheng if (ret) 343a5cadbbbSDong Aisheng return 0; 344a5cadbbbSDong Aisheng 345a5cadbbbSDong Aisheng return imx_pinconf_decode_generic_config(ipctl, configs, num_configs); 346a5cadbbbSDong Aisheng } 347a5cadbbbSDong Aisheng 348b96eea71SA.s. Dong static int imx_pinconf_get_mmio(struct pinctrl_dev *pctldev, unsigned pin_id, 349b96eea71SA.s. Dong unsigned long *config) 350edad3b2aSLinus Walleij { 351edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 352f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 353f5843492SStefan Agner const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; 354edad3b2aSLinus Walleij 3553dac1918SStefan Agner if (pin_reg->conf_reg == -1) { 356f5843492SStefan Agner dev_err(ipctl->dev, "Pin(%s) does not support config function\n", 357edad3b2aSLinus Walleij info->pins[pin_id].name); 358edad3b2aSLinus Walleij return -EINVAL; 359edad3b2aSLinus Walleij } 360edad3b2aSLinus Walleij 361edad3b2aSLinus Walleij *config = readl(ipctl->base + pin_reg->conf_reg); 362edad3b2aSLinus Walleij 363edad3b2aSLinus Walleij if (info->flags & SHARE_MUX_CONF_REG) 3645586ee41SDong Aisheng *config &= ~info->mux_mask; 365edad3b2aSLinus Walleij 366edad3b2aSLinus Walleij return 0; 367edad3b2aSLinus Walleij } 368edad3b2aSLinus Walleij 369b96eea71SA.s. Dong static int imx_pinconf_get(struct pinctrl_dev *pctldev, 370b96eea71SA.s. Dong unsigned pin_id, unsigned long *config) 371b96eea71SA.s. Dong { 372b96eea71SA.s. Dong struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 373b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 374b96eea71SA.s. Dong 375b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 376b96eea71SA.s. Dong return imx_pinconf_get_scu(pctldev, pin_id, config); 377b96eea71SA.s. Dong else 378b96eea71SA.s. Dong return imx_pinconf_get_mmio(pctldev, pin_id, config); 379b96eea71SA.s. Dong } 380b96eea71SA.s. Dong 381b96eea71SA.s. Dong static int imx_pinconf_set_mmio(struct pinctrl_dev *pctldev, 382edad3b2aSLinus Walleij unsigned pin_id, unsigned long *configs, 383edad3b2aSLinus Walleij unsigned num_configs) 384edad3b2aSLinus Walleij { 385edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 386f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 387f5843492SStefan Agner const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; 388edad3b2aSLinus Walleij int i; 389edad3b2aSLinus Walleij 3903dac1918SStefan Agner if (pin_reg->conf_reg == -1) { 391f5843492SStefan Agner dev_err(ipctl->dev, "Pin(%s) does not support config function\n", 392edad3b2aSLinus Walleij info->pins[pin_id].name); 393edad3b2aSLinus Walleij return -EINVAL; 394edad3b2aSLinus Walleij } 395edad3b2aSLinus Walleij 396edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "pinconf set pin %s\n", 397edad3b2aSLinus Walleij info->pins[pin_id].name); 398edad3b2aSLinus Walleij 399edad3b2aSLinus Walleij for (i = 0; i < num_configs; i++) { 400edad3b2aSLinus Walleij if (info->flags & SHARE_MUX_CONF_REG) { 401edad3b2aSLinus Walleij u32 reg; 402edad3b2aSLinus Walleij reg = readl(ipctl->base + pin_reg->conf_reg); 4035586ee41SDong Aisheng reg &= info->mux_mask; 404edad3b2aSLinus Walleij reg |= configs[i]; 405edad3b2aSLinus Walleij writel(reg, ipctl->base + pin_reg->conf_reg); 40666b54e3aSDong Aisheng dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 40766b54e3aSDong Aisheng pin_reg->conf_reg, reg); 408edad3b2aSLinus Walleij } else { 409edad3b2aSLinus Walleij writel(configs[i], ipctl->base + pin_reg->conf_reg); 410edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", 411edad3b2aSLinus Walleij pin_reg->conf_reg, configs[i]); 41266b54e3aSDong Aisheng } 413edad3b2aSLinus Walleij } /* for each config */ 414edad3b2aSLinus Walleij 415edad3b2aSLinus Walleij return 0; 416edad3b2aSLinus Walleij } 417edad3b2aSLinus Walleij 418b96eea71SA.s. Dong static int imx_pinconf_set(struct pinctrl_dev *pctldev, 419b96eea71SA.s. Dong unsigned pin_id, unsigned long *configs, 420b96eea71SA.s. Dong unsigned num_configs) 421b96eea71SA.s. Dong { 422b96eea71SA.s. Dong struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 423b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 424b96eea71SA.s. Dong 425b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 426b96eea71SA.s. Dong return imx_pinconf_set_scu(pctldev, pin_id, 427b96eea71SA.s. Dong configs, num_configs); 428b96eea71SA.s. Dong else 429b96eea71SA.s. Dong return imx_pinconf_set_mmio(pctldev, pin_id, 430b96eea71SA.s. Dong configs, num_configs); 431b96eea71SA.s. Dong } 432b96eea71SA.s. Dong 433edad3b2aSLinus Walleij static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, 434edad3b2aSLinus Walleij struct seq_file *s, unsigned pin_id) 435edad3b2aSLinus Walleij { 436edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 437b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 438b96eea71SA.s. Dong const struct imx_pin_reg *pin_reg; 439edad3b2aSLinus Walleij unsigned long config; 440b96eea71SA.s. Dong int ret; 441edad3b2aSLinus Walleij 442b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 443b96eea71SA.s. Dong ret = imx_pinconf_get_scu(pctldev, pin_id, &config); 444b96eea71SA.s. Dong if (ret) { 445b96eea71SA.s. Dong dev_err(ipctl->dev, "failed to get %s pinconf\n", 446b96eea71SA.s. Dong pin_get_name(pctldev, pin_id)); 447b96eea71SA.s. Dong seq_puts(s, "N/A"); 448b96eea71SA.s. Dong return; 449b96eea71SA.s. Dong } 450b96eea71SA.s. Dong } else { 451b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[pin_id]; 452c7df94c6SDan Carpenter if (pin_reg->conf_reg == -1) { 4537d6989adSDong Aisheng seq_puts(s, "N/A"); 454edad3b2aSLinus Walleij return; 455edad3b2aSLinus Walleij } 456edad3b2aSLinus Walleij 457edad3b2aSLinus Walleij config = readl(ipctl->base + pin_reg->conf_reg); 458b96eea71SA.s. Dong } 459b96eea71SA.s. Dong 460edad3b2aSLinus Walleij seq_printf(s, "0x%lx", config); 461edad3b2aSLinus Walleij } 462edad3b2aSLinus Walleij 463edad3b2aSLinus Walleij static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 464edad3b2aSLinus Walleij struct seq_file *s, unsigned group) 465edad3b2aSLinus Walleij { 466e566fc11SGary Bisson struct group_desc *grp; 467edad3b2aSLinus Walleij unsigned long config; 468edad3b2aSLinus Walleij const char *name; 469edad3b2aSLinus Walleij int i, ret; 470edad3b2aSLinus Walleij 471b4859f3eSDan Carpenter if (group >= pctldev->num_groups) 472edad3b2aSLinus Walleij return; 473edad3b2aSLinus Walleij 4747d6989adSDong Aisheng seq_puts(s, "\n"); 475e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, group); 476a51c158bSGary Bisson if (!grp) 477a51c158bSGary Bisson return; 478a51c158bSGary Bisson 479e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 480e566fc11SGary Bisson struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; 481e566fc11SGary Bisson 482edad3b2aSLinus Walleij name = pin_get_name(pctldev, pin->pin); 483edad3b2aSLinus Walleij ret = imx_pinconf_get(pctldev, pin->pin, &config); 484edad3b2aSLinus Walleij if (ret) 485edad3b2aSLinus Walleij return; 486a2d16a21SVladimir Zapolskiy seq_printf(s, " %s: 0x%lx\n", name, config); 487edad3b2aSLinus Walleij } 488edad3b2aSLinus Walleij } 489edad3b2aSLinus Walleij 490edad3b2aSLinus Walleij static const struct pinconf_ops imx_pinconf_ops = { 491edad3b2aSLinus Walleij .pin_config_get = imx_pinconf_get, 492edad3b2aSLinus Walleij .pin_config_set = imx_pinconf_set, 493edad3b2aSLinus Walleij .pin_config_dbg_show = imx_pinconf_dbg_show, 494edad3b2aSLinus Walleij .pin_config_group_dbg_show = imx_pinconf_group_dbg_show, 495edad3b2aSLinus Walleij }; 496edad3b2aSLinus Walleij 497edad3b2aSLinus Walleij /* 49837c1628fSDong Aisheng * Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID 49937c1628fSDong Aisheng * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin. 50037c1628fSDong Aisheng * For generic_pinconf case, there's no extra u32 CONFIG. 50137c1628fSDong Aisheng * 50237c1628fSDong Aisheng * PIN_FUNC_ID format: 50337c1628fSDong Aisheng * Default: 50437c1628fSDong Aisheng * <mux_reg conf_reg input_reg mux_mode input_val> 50537c1628fSDong Aisheng * SHARE_MUX_CONF_REG: 50637c1628fSDong Aisheng * <mux_conf_reg input_reg mux_mode input_val> 507b96eea71SA.s. Dong * IMX_USE_SCU: 508b96eea71SA.s. Dong * <pin_id mux_mode> 509edad3b2aSLinus Walleij */ 510edad3b2aSLinus Walleij #define FSL_PIN_SIZE 24 51137c1628fSDong Aisheng #define FSL_PIN_SHARE_SIZE 20 512b96eea71SA.s. Dong #define FSL_SCU_PIN_SIZE 12 513b96eea71SA.s. Dong 514b96eea71SA.s. Dong static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl, 515b96eea71SA.s. Dong unsigned int *pin_id, struct imx_pin *pin, 516b96eea71SA.s. Dong const __be32 **list_p, 517b96eea71SA.s. Dong struct device_node *np) 518b96eea71SA.s. Dong { 519b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 520b96eea71SA.s. Dong struct imx_pin_mmio *pin_mmio = &pin->conf.mmio; 521b96eea71SA.s. Dong struct imx_pin_reg *pin_reg; 522b96eea71SA.s. Dong const __be32 *list = *list_p; 523b96eea71SA.s. Dong u32 mux_reg, conf_reg; 524b96eea71SA.s. Dong u32 config; 525b96eea71SA.s. Dong 526b96eea71SA.s. Dong mux_reg = be32_to_cpu(*list++); 527b96eea71SA.s. Dong 528b96eea71SA.s. Dong if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg) 529b96eea71SA.s. Dong mux_reg = -1; 530b96eea71SA.s. Dong 531b96eea71SA.s. Dong if (info->flags & SHARE_MUX_CONF_REG) { 532b96eea71SA.s. Dong conf_reg = mux_reg; 533b96eea71SA.s. Dong } else { 534b96eea71SA.s. Dong conf_reg = be32_to_cpu(*list++); 535b96eea71SA.s. Dong if (!conf_reg) 536b96eea71SA.s. Dong conf_reg = -1; 537b96eea71SA.s. Dong } 538b96eea71SA.s. Dong 539b96eea71SA.s. Dong *pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4; 540b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[*pin_id]; 541b96eea71SA.s. Dong pin->pin = *pin_id; 542b96eea71SA.s. Dong pin_reg->mux_reg = mux_reg; 543b96eea71SA.s. Dong pin_reg->conf_reg = conf_reg; 544b96eea71SA.s. Dong pin_mmio->input_reg = be32_to_cpu(*list++); 545b96eea71SA.s. Dong pin_mmio->mux_mode = be32_to_cpu(*list++); 546b96eea71SA.s. Dong pin_mmio->input_val = be32_to_cpu(*list++); 547b96eea71SA.s. Dong 548b96eea71SA.s. Dong if (info->generic_pinconf) { 549b96eea71SA.s. Dong /* generic pin config decoded */ 550b96eea71SA.s. Dong pin_mmio->config = imx_pinconf_parse_generic_config(np, ipctl); 551b96eea71SA.s. Dong } else { 552b96eea71SA.s. Dong /* legacy pin config read from devicetree */ 553b96eea71SA.s. Dong config = be32_to_cpu(*list++); 554b96eea71SA.s. Dong 555b96eea71SA.s. Dong /* SION bit is in mux register */ 556b96eea71SA.s. Dong if (config & IMX_PAD_SION) 557b96eea71SA.s. Dong pin_mmio->mux_mode |= IOMUXC_CONFIG_SION; 558b96eea71SA.s. Dong pin_mmio->config = config & ~IMX_PAD_SION; 559b96eea71SA.s. Dong } 560b96eea71SA.s. Dong 56157161067SA.s. Dong *list_p = list; 56257161067SA.s. Dong 563b96eea71SA.s. Dong dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[*pin_id].name, 564b96eea71SA.s. Dong pin_mmio->mux_mode, pin_mmio->config); 565b96eea71SA.s. Dong } 566edad3b2aSLinus Walleij 567edad3b2aSLinus Walleij static int imx_pinctrl_parse_groups(struct device_node *np, 568e566fc11SGary Bisson struct group_desc *grp, 569a5cadbbbSDong Aisheng struct imx_pinctrl *ipctl, 570edad3b2aSLinus Walleij u32 index) 571edad3b2aSLinus Walleij { 572f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 573b96eea71SA.s. Dong struct imx_pin *pin; 574edad3b2aSLinus Walleij int size, pin_size; 575edad3b2aSLinus Walleij const __be32 *list; 576edad3b2aSLinus Walleij int i; 577edad3b2aSLinus Walleij 57894f4e54cSRob Herring dev_dbg(ipctl->dev, "group(%d): %pOFn\n", index, np); 579edad3b2aSLinus Walleij 580b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 581b96eea71SA.s. Dong pin_size = FSL_SCU_PIN_SIZE; 582b96eea71SA.s. Dong else if (info->flags & SHARE_MUX_CONF_REG) 58337c1628fSDong Aisheng pin_size = FSL_PIN_SHARE_SIZE; 584edad3b2aSLinus Walleij else 585edad3b2aSLinus Walleij pin_size = FSL_PIN_SIZE; 586a5cadbbbSDong Aisheng 587a5cadbbbSDong Aisheng if (info->generic_pinconf) 588a5cadbbbSDong Aisheng pin_size -= 4; 589a5cadbbbSDong Aisheng 590edad3b2aSLinus Walleij /* Initialise group */ 591edad3b2aSLinus Walleij grp->name = np->name; 592edad3b2aSLinus Walleij 593edad3b2aSLinus Walleij /* 594edad3b2aSLinus Walleij * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>, 595edad3b2aSLinus Walleij * do sanity check and calculate pins number 596a5cadbbbSDong Aisheng * 597a5cadbbbSDong Aisheng * First try legacy 'fsl,pins' property, then fall back to the 598fc4f351aSDong Aisheng * generic 'pinmux'. 599a5cadbbbSDong Aisheng * 600fc4f351aSDong Aisheng * Note: for generic 'pinmux' case, there's no CONFIG part in 601a5cadbbbSDong Aisheng * the binding format. 602edad3b2aSLinus Walleij */ 603edad3b2aSLinus Walleij list = of_get_property(np, "fsl,pins", &size); 604edad3b2aSLinus Walleij if (!list) { 605fc4f351aSDong Aisheng list = of_get_property(np, "pinmux", &size); 606a5cadbbbSDong Aisheng if (!list) { 607f5843492SStefan Agner dev_err(ipctl->dev, 608f5292d06SRob Herring "no fsl,pins and pins property in node %pOF\n", np); 609edad3b2aSLinus Walleij return -EINVAL; 610edad3b2aSLinus Walleij } 611a5cadbbbSDong Aisheng } 612edad3b2aSLinus Walleij 613edad3b2aSLinus Walleij /* we do not check return since it's safe node passed down */ 614edad3b2aSLinus Walleij if (!size || size % pin_size) { 615f5843492SStefan Agner dev_err(ipctl->dev, "Invalid fsl,pins or pins property in node %pOF\n", np); 616edad3b2aSLinus Walleij return -EINVAL; 617edad3b2aSLinus Walleij } 618edad3b2aSLinus Walleij 619e566fc11SGary Bisson grp->num_pins = size / pin_size; 620a86854d0SKees Cook grp->data = devm_kcalloc(ipctl->dev, 621a86854d0SKees Cook grp->num_pins, sizeof(struct imx_pin), 622a86854d0SKees Cook GFP_KERNEL); 623a86854d0SKees Cook grp->pins = devm_kcalloc(ipctl->dev, 624a86854d0SKees Cook grp->num_pins, sizeof(unsigned int), 625a86854d0SKees Cook GFP_KERNEL); 626e566fc11SGary Bisson if (!grp->pins || !grp->data) 627edad3b2aSLinus Walleij return -ENOMEM; 628edad3b2aSLinus Walleij 629e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 630b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 631b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 632b96eea71SA.s. Dong imx_pinctrl_parse_pin_scu(ipctl, &grp->pins[i], 633b96eea71SA.s. Dong pin, &list); 634b96eea71SA.s. Dong else 635b96eea71SA.s. Dong imx_pinctrl_parse_pin_mmio(ipctl, &grp->pins[i], 636b96eea71SA.s. Dong pin, &list, np); 637edad3b2aSLinus Walleij } 638edad3b2aSLinus Walleij 639edad3b2aSLinus Walleij return 0; 640edad3b2aSLinus Walleij } 641edad3b2aSLinus Walleij 642edad3b2aSLinus Walleij static int imx_pinctrl_parse_functions(struct device_node *np, 643e566fc11SGary Bisson struct imx_pinctrl *ipctl, 644edad3b2aSLinus Walleij u32 index) 645edad3b2aSLinus Walleij { 646e566fc11SGary Bisson struct pinctrl_dev *pctl = ipctl->pctl; 647edad3b2aSLinus Walleij struct device_node *child; 6483fd6d6adSGary Bisson struct function_desc *func; 649e566fc11SGary Bisson struct group_desc *grp; 650edad3b2aSLinus Walleij u32 i = 0; 651edad3b2aSLinus Walleij 65294f4e54cSRob Herring dev_dbg(pctl->dev, "parse function(%d): %pOFn\n", index, np); 653edad3b2aSLinus Walleij 6543fd6d6adSGary Bisson func = pinmux_generic_get_function(pctl, index); 655a51c158bSGary Bisson if (!func) 656a51c158bSGary Bisson return -EINVAL; 657edad3b2aSLinus Walleij 658edad3b2aSLinus Walleij /* Initialise function */ 659edad3b2aSLinus Walleij func->name = np->name; 6603fd6d6adSGary Bisson func->num_group_names = of_get_child_count(np); 6613fd6d6adSGary Bisson if (func->num_group_names == 0) { 662f5843492SStefan Agner dev_err(ipctl->dev, "no groups defined in %pOF\n", np); 663edad3b2aSLinus Walleij return -EINVAL; 664edad3b2aSLinus Walleij } 665f5843492SStefan Agner func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names, 6663fd6d6adSGary Bisson sizeof(char *), GFP_KERNEL); 66749af64e6SChristophe JAILLET if (!func->group_names) 66849af64e6SChristophe JAILLET return -ENOMEM; 669edad3b2aSLinus Walleij 670edad3b2aSLinus Walleij for_each_child_of_node(np, child) { 6713fd6d6adSGary Bisson func->group_names[i] = child->name; 672a51c158bSGary Bisson 673f5843492SStefan Agner grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc), 674a51c158bSGary Bisson GFP_KERNEL); 675*bf4b87b0SNishka Dasgupta if (!grp) { 676*bf4b87b0SNishka Dasgupta of_node_put(child); 677a51c158bSGary Bisson return -ENOMEM; 678*bf4b87b0SNishka Dasgupta } 679a51c158bSGary Bisson 680f5843492SStefan Agner mutex_lock(&ipctl->mutex); 681e566fc11SGary Bisson radix_tree_insert(&pctl->pin_group_tree, 682f5843492SStefan Agner ipctl->group_index++, grp); 683f5843492SStefan Agner mutex_unlock(&ipctl->mutex); 684a51c158bSGary Bisson 685a5cadbbbSDong Aisheng imx_pinctrl_parse_groups(child, grp, ipctl, i++); 686edad3b2aSLinus Walleij } 687edad3b2aSLinus Walleij 688edad3b2aSLinus Walleij return 0; 689edad3b2aSLinus Walleij } 690edad3b2aSLinus Walleij 6915fcdf6a7SMarkus Pargmann /* 6925fcdf6a7SMarkus Pargmann * Check if the DT contains pins in the direct child nodes. This indicates the 6935fcdf6a7SMarkus Pargmann * newer DT format to store pins. This function returns true if the first found 6945fcdf6a7SMarkus Pargmann * fsl,pins property is in a child of np. Otherwise false is returned. 6955fcdf6a7SMarkus Pargmann */ 6965fcdf6a7SMarkus Pargmann static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) 6975fcdf6a7SMarkus Pargmann { 6985fcdf6a7SMarkus Pargmann struct device_node *function_np; 6995fcdf6a7SMarkus Pargmann struct device_node *pinctrl_np; 7005fcdf6a7SMarkus Pargmann 7015fcdf6a7SMarkus Pargmann for_each_child_of_node(np, function_np) { 702*bf4b87b0SNishka Dasgupta if (of_property_read_bool(function_np, "fsl,pins")) { 703*bf4b87b0SNishka Dasgupta of_node_put(function_np); 7045fcdf6a7SMarkus Pargmann return true; 705*bf4b87b0SNishka Dasgupta } 7065fcdf6a7SMarkus Pargmann 7075fcdf6a7SMarkus Pargmann for_each_child_of_node(function_np, pinctrl_np) { 708*bf4b87b0SNishka Dasgupta if (of_property_read_bool(pinctrl_np, "fsl,pins")) { 709*bf4b87b0SNishka Dasgupta of_node_put(pinctrl_np); 710*bf4b87b0SNishka Dasgupta of_node_put(function_np); 7115fcdf6a7SMarkus Pargmann return false; 7125fcdf6a7SMarkus Pargmann } 7135fcdf6a7SMarkus Pargmann } 714*bf4b87b0SNishka Dasgupta } 7155fcdf6a7SMarkus Pargmann 7165fcdf6a7SMarkus Pargmann return true; 7175fcdf6a7SMarkus Pargmann } 7185fcdf6a7SMarkus Pargmann 719edad3b2aSLinus Walleij static int imx_pinctrl_probe_dt(struct platform_device *pdev, 720e566fc11SGary Bisson struct imx_pinctrl *ipctl) 721edad3b2aSLinus Walleij { 722edad3b2aSLinus Walleij struct device_node *np = pdev->dev.of_node; 723edad3b2aSLinus Walleij struct device_node *child; 724e566fc11SGary Bisson struct pinctrl_dev *pctl = ipctl->pctl; 725edad3b2aSLinus Walleij u32 nfuncs = 0; 726edad3b2aSLinus Walleij u32 i = 0; 7275fcdf6a7SMarkus Pargmann bool flat_funcs; 728edad3b2aSLinus Walleij 729edad3b2aSLinus Walleij if (!np) 730edad3b2aSLinus Walleij return -ENODEV; 731edad3b2aSLinus Walleij 7325fcdf6a7SMarkus Pargmann flat_funcs = imx_pinctrl_dt_is_flat_functions(np); 7335fcdf6a7SMarkus Pargmann if (flat_funcs) { 7345fcdf6a7SMarkus Pargmann nfuncs = 1; 7355fcdf6a7SMarkus Pargmann } else { 736edad3b2aSLinus Walleij nfuncs = of_get_child_count(np); 737562088eeSDong Aisheng if (nfuncs == 0) { 738edad3b2aSLinus Walleij dev_err(&pdev->dev, "no functions defined\n"); 739edad3b2aSLinus Walleij return -EINVAL; 740edad3b2aSLinus Walleij } 7415fcdf6a7SMarkus Pargmann } 742edad3b2aSLinus Walleij 743a51c158bSGary Bisson for (i = 0; i < nfuncs; i++) { 7443fd6d6adSGary Bisson struct function_desc *function; 745a51c158bSGary Bisson 746a51c158bSGary Bisson function = devm_kzalloc(&pdev->dev, sizeof(*function), 747edad3b2aSLinus Walleij GFP_KERNEL); 748a51c158bSGary Bisson if (!function) 749edad3b2aSLinus Walleij return -ENOMEM; 750edad3b2aSLinus Walleij 751f5843492SStefan Agner mutex_lock(&ipctl->mutex); 7523fd6d6adSGary Bisson radix_tree_insert(&pctl->pin_function_tree, i, function); 753f5843492SStefan Agner mutex_unlock(&ipctl->mutex); 754a51c158bSGary Bisson } 7553fd6d6adSGary Bisson pctl->num_functions = nfuncs; 756a51c158bSGary Bisson 757f5843492SStefan Agner ipctl->group_index = 0; 7585fcdf6a7SMarkus Pargmann if (flat_funcs) { 759e566fc11SGary Bisson pctl->num_groups = of_get_child_count(np); 7605fcdf6a7SMarkus Pargmann } else { 761e566fc11SGary Bisson pctl->num_groups = 0; 762edad3b2aSLinus Walleij for_each_child_of_node(np, child) 763e566fc11SGary Bisson pctl->num_groups += of_get_child_count(child); 7645fcdf6a7SMarkus Pargmann } 765edad3b2aSLinus Walleij 7665fcdf6a7SMarkus Pargmann if (flat_funcs) { 767e566fc11SGary Bisson imx_pinctrl_parse_functions(np, ipctl, 0); 7685fcdf6a7SMarkus Pargmann } else { 769a51c158bSGary Bisson i = 0; 770edad3b2aSLinus Walleij for_each_child_of_node(np, child) 771e566fc11SGary Bisson imx_pinctrl_parse_functions(child, ipctl, i++); 7725fcdf6a7SMarkus Pargmann } 773edad3b2aSLinus Walleij 774edad3b2aSLinus Walleij return 0; 775edad3b2aSLinus Walleij } 776edad3b2aSLinus Walleij 777a51c158bSGary Bisson /* 778a51c158bSGary Bisson * imx_free_resources() - free memory used by this driver 779a51c158bSGary Bisson * @info: info driver instance 780a51c158bSGary Bisson */ 781a51c158bSGary Bisson static void imx_free_resources(struct imx_pinctrl *ipctl) 782a51c158bSGary Bisson { 783a51c158bSGary Bisson if (ipctl->pctl) 784a51c158bSGary Bisson pinctrl_unregister(ipctl->pctl); 785a51c158bSGary Bisson } 786a51c158bSGary Bisson 787edad3b2aSLinus Walleij int imx_pinctrl_probe(struct platform_device *pdev, 788f5843492SStefan Agner const struct imx_pinctrl_soc_info *info) 789edad3b2aSLinus Walleij { 7908626ada8SPhilipp Zabel struct regmap_config config = { .name = "gpr" }; 79126d8cde5SAdrian Alonso struct device_node *dev_np = pdev->dev.of_node; 7926e408ed8SPeng Fan struct pinctrl_desc *imx_pinctrl_desc; 79326d8cde5SAdrian Alonso struct device_node *np; 794edad3b2aSLinus Walleij struct imx_pinctrl *ipctl; 7958626ada8SPhilipp Zabel struct regmap *gpr; 7964691dd01SStefan Agner int ret, i; 797edad3b2aSLinus Walleij 798edad3b2aSLinus Walleij if (!info || !info->pins || !info->npins) { 799edad3b2aSLinus Walleij dev_err(&pdev->dev, "wrong pinctrl info\n"); 800edad3b2aSLinus Walleij return -EINVAL; 801edad3b2aSLinus Walleij } 802edad3b2aSLinus Walleij 8038626ada8SPhilipp Zabel if (info->gpr_compatible) { 8048626ada8SPhilipp Zabel gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible); 8058626ada8SPhilipp Zabel if (!IS_ERR(gpr)) 8068626ada8SPhilipp Zabel regmap_attach_dev(&pdev->dev, gpr, &config); 8078626ada8SPhilipp Zabel } 8088626ada8SPhilipp Zabel 809edad3b2aSLinus Walleij /* Create state holders etc for this driver */ 810edad3b2aSLinus Walleij ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 811edad3b2aSLinus Walleij if (!ipctl) 812edad3b2aSLinus Walleij return -ENOMEM; 813edad3b2aSLinus Walleij 814b96eea71SA.s. Dong if (!(info->flags & IMX_USE_SCU)) { 815b96eea71SA.s. Dong ipctl->pin_regs = devm_kmalloc_array(&pdev->dev, info->npins, 816b96eea71SA.s. Dong sizeof(*ipctl->pin_regs), 8173c4211baSKees Cook GFP_KERNEL); 818f5843492SStefan Agner if (!ipctl->pin_regs) 819edad3b2aSLinus Walleij return -ENOMEM; 8204691dd01SStefan Agner 8214691dd01SStefan Agner for (i = 0; i < info->npins; i++) { 822f5843492SStefan Agner ipctl->pin_regs[i].mux_reg = -1; 823f5843492SStefan Agner ipctl->pin_regs[i].conf_reg = -1; 8244691dd01SStefan Agner } 825edad3b2aSLinus Walleij 826e05487d4SAnson Huang ipctl->base = devm_platform_ioremap_resource(pdev, 0); 827edad3b2aSLinus Walleij if (IS_ERR(ipctl->base)) 828edad3b2aSLinus Walleij return PTR_ERR(ipctl->base); 829edad3b2aSLinus Walleij 83026d8cde5SAdrian Alonso if (of_property_read_bool(dev_np, "fsl,input-sel")) { 83126d8cde5SAdrian Alonso np = of_parse_phandle(dev_np, "fsl,input-sel", 0); 8329a4f4245SVladimir Zapolskiy if (!np) { 83326d8cde5SAdrian Alonso dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); 83426d8cde5SAdrian Alonso return -EINVAL; 83526d8cde5SAdrian Alonso } 8369a4f4245SVladimir Zapolskiy 8379a4f4245SVladimir Zapolskiy ipctl->input_sel_base = of_iomap(np, 0); 83826d8cde5SAdrian Alonso of_node_put(np); 8399a4f4245SVladimir Zapolskiy if (!ipctl->input_sel_base) { 8409a4f4245SVladimir Zapolskiy dev_err(&pdev->dev, 8419a4f4245SVladimir Zapolskiy "iomuxc input select base address not found\n"); 8429a4f4245SVladimir Zapolskiy return -ENOMEM; 8439a4f4245SVladimir Zapolskiy } 84426d8cde5SAdrian Alonso } 845b96eea71SA.s. Dong } 84626d8cde5SAdrian Alonso 8476e408ed8SPeng Fan imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc), 8486e408ed8SPeng Fan GFP_KERNEL); 8496e408ed8SPeng Fan if (!imx_pinctrl_desc) 8506e408ed8SPeng Fan return -ENOMEM; 8516e408ed8SPeng Fan 8526e408ed8SPeng Fan imx_pinctrl_desc->name = dev_name(&pdev->dev); 8536e408ed8SPeng Fan imx_pinctrl_desc->pins = info->pins; 8546e408ed8SPeng Fan imx_pinctrl_desc->npins = info->npins; 8558f5983adSGary Bisson imx_pinctrl_desc->pctlops = &imx_pctrl_ops; 8568f5983adSGary Bisson imx_pinctrl_desc->pmxops = &imx_pmx_ops; 8578f5983adSGary Bisson imx_pinctrl_desc->confops = &imx_pinconf_ops; 8588f5983adSGary Bisson imx_pinctrl_desc->owner = THIS_MODULE; 859edad3b2aSLinus Walleij 860a5cadbbbSDong Aisheng /* for generic pinconf */ 861a5cadbbbSDong Aisheng imx_pinctrl_desc->custom_params = info->custom_params; 862a5cadbbbSDong Aisheng imx_pinctrl_desc->num_custom_params = info->num_custom_params; 863a5cadbbbSDong Aisheng 8643be6f651SDong Aisheng /* platform specific callback */ 8653be6f651SDong Aisheng imx_pmx_ops.gpio_set_direction = info->gpio_set_direction; 8663be6f651SDong Aisheng 867f5843492SStefan Agner mutex_init(&ipctl->mutex); 868a51c158bSGary Bisson 869edad3b2aSLinus Walleij ipctl->info = info; 870f5843492SStefan Agner ipctl->dev = &pdev->dev; 871edad3b2aSLinus Walleij platform_set_drvdata(pdev, ipctl); 872950b0d91STony Lindgren ret = devm_pinctrl_register_and_init(&pdev->dev, 873950b0d91STony Lindgren imx_pinctrl_desc, ipctl, 874950b0d91STony Lindgren &ipctl->pctl); 875950b0d91STony Lindgren if (ret) { 876edad3b2aSLinus Walleij dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); 877a51c158bSGary Bisson goto free; 878edad3b2aSLinus Walleij } 879edad3b2aSLinus Walleij 880e566fc11SGary Bisson ret = imx_pinctrl_probe_dt(pdev, ipctl); 881e566fc11SGary Bisson if (ret) { 882e566fc11SGary Bisson dev_err(&pdev->dev, "fail to probe dt properties\n"); 883e566fc11SGary Bisson goto free; 884e566fc11SGary Bisson } 885e566fc11SGary Bisson 886edad3b2aSLinus Walleij dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); 887edad3b2aSLinus Walleij 88861187142STony Lindgren return pinctrl_enable(ipctl->pctl); 889a51c158bSGary Bisson 890a51c158bSGary Bisson free: 891a51c158bSGary Bisson imx_free_resources(ipctl); 892a51c158bSGary Bisson 893a51c158bSGary Bisson return ret; 894edad3b2aSLinus Walleij } 895855811eaSAbel Vesa 896855811eaSAbel Vesa static int __maybe_unused imx_pinctrl_suspend(struct device *dev) 897855811eaSAbel Vesa { 898855811eaSAbel Vesa struct imx_pinctrl *ipctl = dev_get_drvdata(dev); 899855811eaSAbel Vesa 900855811eaSAbel Vesa return pinctrl_force_sleep(ipctl->pctl); 901855811eaSAbel Vesa } 902855811eaSAbel Vesa 903855811eaSAbel Vesa static int __maybe_unused imx_pinctrl_resume(struct device *dev) 904855811eaSAbel Vesa { 905855811eaSAbel Vesa struct imx_pinctrl *ipctl = dev_get_drvdata(dev); 906855811eaSAbel Vesa 907855811eaSAbel Vesa return pinctrl_force_default(ipctl->pctl); 908855811eaSAbel Vesa } 909855811eaSAbel Vesa 910855811eaSAbel Vesa const struct dev_pm_ops imx_pinctrl_pm_ops = { 911855811eaSAbel Vesa SET_LATE_SYSTEM_SLEEP_PM_OPS(imx_pinctrl_suspend, 912855811eaSAbel Vesa imx_pinctrl_resume) 913855811eaSAbel Vesa }; 914