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> 147233f7cfSAnson Huang #include <linux/module.h> 15edad3b2aSLinus Walleij #include <linux/of.h> 1626d8cde5SAdrian Alonso #include <linux/of_address.h> 17060f03e9SRob Herring #include <linux/platform_device.h> 186e8bc379SAndy Shevchenko #include <linux/regmap.h> 196e8bc379SAndy Shevchenko #include <linux/seq_file.h> 206e8bc379SAndy Shevchenko #include <linux/slab.h> 216e8bc379SAndy Shevchenko 22edad3b2aSLinus Walleij #include <linux/pinctrl/machine.h> 23edad3b2aSLinus Walleij #include <linux/pinctrl/pinconf.h> 24edad3b2aSLinus Walleij #include <linux/pinctrl/pinctrl.h> 25edad3b2aSLinus Walleij #include <linux/pinctrl/pinmux.h> 26edad3b2aSLinus Walleij 27edad3b2aSLinus Walleij #include "../core.h" 28a5cadbbbSDong Aisheng #include "../pinconf.h" 293fd6d6adSGary Bisson #include "../pinmux.h" 30edad3b2aSLinus Walleij #include "pinctrl-imx.h" 31edad3b2aSLinus Walleij 32edad3b2aSLinus Walleij /* The bits in CONFIG cell defined in binding doc*/ 33edad3b2aSLinus Walleij #define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */ 34edad3b2aSLinus Walleij #define IMX_PAD_SION 0x40000000 /* set SION */ 35edad3b2aSLinus Walleij 36e566fc11SGary Bisson static inline const struct group_desc *imx_pinctrl_find_group_by_name( 37e566fc11SGary Bisson struct pinctrl_dev *pctldev, 38edad3b2aSLinus Walleij const char *name) 39edad3b2aSLinus Walleij { 40e566fc11SGary Bisson const struct group_desc *grp = NULL; 41edad3b2aSLinus Walleij int i; 42edad3b2aSLinus Walleij 43e566fc11SGary Bisson for (i = 0; i < pctldev->num_groups; i++) { 44e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, i); 45a51c158bSGary Bisson if (grp && !strcmp(grp->name, name)) 46edad3b2aSLinus Walleij break; 47edad3b2aSLinus Walleij } 48edad3b2aSLinus Walleij 49edad3b2aSLinus Walleij return grp; 50edad3b2aSLinus Walleij } 51edad3b2aSLinus Walleij 52edad3b2aSLinus Walleij static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 53edad3b2aSLinus Walleij unsigned offset) 54edad3b2aSLinus Walleij { 55edad3b2aSLinus Walleij seq_printf(s, "%s", dev_name(pctldev->dev)); 56edad3b2aSLinus Walleij } 57edad3b2aSLinus Walleij 58edad3b2aSLinus Walleij static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, 59edad3b2aSLinus Walleij struct device_node *np, 60edad3b2aSLinus Walleij struct pinctrl_map **map, unsigned *num_maps) 61edad3b2aSLinus Walleij { 62edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 63b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 64e566fc11SGary Bisson const struct group_desc *grp; 65edad3b2aSLinus Walleij struct pinctrl_map *new_map; 66edad3b2aSLinus Walleij struct device_node *parent; 67b96eea71SA.s. Dong struct imx_pin *pin; 68edad3b2aSLinus Walleij int map_num = 1; 69edad3b2aSLinus Walleij int i, j; 70edad3b2aSLinus Walleij 71edad3b2aSLinus Walleij /* 72edad3b2aSLinus Walleij * first find the group of this node and check if we need create 73edad3b2aSLinus Walleij * config maps for pins 74edad3b2aSLinus Walleij */ 75e566fc11SGary Bisson grp = imx_pinctrl_find_group_by_name(pctldev, np->name); 76edad3b2aSLinus Walleij if (!grp) { 7794f4e54cSRob Herring dev_err(ipctl->dev, "unable to find group for node %pOFn\n", np); 78edad3b2aSLinus Walleij return -EINVAL; 79edad3b2aSLinus Walleij } 80edad3b2aSLinus Walleij 81b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 82b96eea71SA.s. Dong map_num += grp->num_pins; 83b96eea71SA.s. Dong } else { 84e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 85b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 86b96eea71SA.s. Dong if (!(pin->conf.mmio.config & IMX_NO_PAD_CTL)) 87edad3b2aSLinus Walleij map_num++; 88edad3b2aSLinus Walleij } 89b96eea71SA.s. Dong } 90edad3b2aSLinus Walleij 916da2ec56SKees Cook new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), 926da2ec56SKees Cook GFP_KERNEL); 93edad3b2aSLinus Walleij if (!new_map) 94edad3b2aSLinus Walleij return -ENOMEM; 95edad3b2aSLinus Walleij 96edad3b2aSLinus Walleij *map = new_map; 97edad3b2aSLinus Walleij *num_maps = map_num; 98edad3b2aSLinus Walleij 99edad3b2aSLinus Walleij /* create mux map */ 100edad3b2aSLinus Walleij parent = of_get_parent(np); 101edad3b2aSLinus Walleij if (!parent) { 102edad3b2aSLinus Walleij kfree(new_map); 103edad3b2aSLinus Walleij return -EINVAL; 104edad3b2aSLinus Walleij } 105edad3b2aSLinus Walleij new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; 106edad3b2aSLinus Walleij new_map[0].data.mux.function = parent->name; 107edad3b2aSLinus Walleij new_map[0].data.mux.group = np->name; 108edad3b2aSLinus Walleij of_node_put(parent); 109edad3b2aSLinus Walleij 110edad3b2aSLinus Walleij /* create config map */ 111edad3b2aSLinus Walleij new_map++; 112e566fc11SGary Bisson for (i = j = 0; i < grp->num_pins; i++) { 113b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 11457161067SA.s. Dong 11557161067SA.s. Dong /* 11657161067SA.s. Dong * We only create config maps for SCU pads or MMIO pads that 11757161067SA.s. Dong * are not using the default config(a.k.a IMX_NO_PAD_CTL) 11857161067SA.s. Dong */ 11957161067SA.s. Dong if (!(info->flags & IMX_USE_SCU) && 12057161067SA.s. Dong (pin->conf.mmio.config & IMX_NO_PAD_CTL)) 12157161067SA.s. Dong continue; 12257161067SA.s. Dong 123edad3b2aSLinus Walleij new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; 124edad3b2aSLinus Walleij new_map[j].data.configs.group_or_pin = 125e566fc11SGary Bisson pin_get_name(pctldev, pin->pin); 126b96eea71SA.s. Dong 127b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 128b96eea71SA.s. Dong /* 129b96eea71SA.s. Dong * For SCU case, we set mux and conf together 130b96eea71SA.s. Dong * in one IPC call 131b96eea71SA.s. Dong */ 132b96eea71SA.s. Dong new_map[j].data.configs.configs = 133b96eea71SA.s. Dong (unsigned long *)&pin->conf.scu; 134b96eea71SA.s. Dong new_map[j].data.configs.num_configs = 2; 13557161067SA.s. Dong } else { 136b96eea71SA.s. Dong new_map[j].data.configs.configs = 137b96eea71SA.s. Dong &pin->conf.mmio.config; 138edad3b2aSLinus Walleij new_map[j].data.configs.num_configs = 1; 139edad3b2aSLinus Walleij } 140b96eea71SA.s. Dong 141b96eea71SA.s. Dong j++; 142edad3b2aSLinus Walleij } 143edad3b2aSLinus Walleij 144edad3b2aSLinus Walleij dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", 145edad3b2aSLinus Walleij (*map)->data.mux.function, (*map)->data.mux.group, map_num); 146edad3b2aSLinus Walleij 147edad3b2aSLinus Walleij return 0; 148edad3b2aSLinus Walleij } 149edad3b2aSLinus Walleij 150edad3b2aSLinus Walleij static void imx_dt_free_map(struct pinctrl_dev *pctldev, 151edad3b2aSLinus Walleij struct pinctrl_map *map, unsigned num_maps) 152edad3b2aSLinus Walleij { 153edad3b2aSLinus Walleij kfree(map); 154edad3b2aSLinus Walleij } 155edad3b2aSLinus Walleij 156edad3b2aSLinus Walleij static const struct pinctrl_ops imx_pctrl_ops = { 157e566fc11SGary Bisson .get_groups_count = pinctrl_generic_get_group_count, 158e566fc11SGary Bisson .get_group_name = pinctrl_generic_get_group_name, 159e566fc11SGary Bisson .get_group_pins = pinctrl_generic_get_group_pins, 160edad3b2aSLinus Walleij .pin_dbg_show = imx_pin_dbg_show, 161edad3b2aSLinus Walleij .dt_node_to_map = imx_dt_node_to_map, 162edad3b2aSLinus Walleij .dt_free_map = imx_dt_free_map, 163edad3b2aSLinus Walleij }; 164edad3b2aSLinus Walleij 165b96eea71SA.s. Dong static int imx_pmx_set_one_pin_mmio(struct imx_pinctrl *ipctl, 166b96eea71SA.s. Dong struct imx_pin *pin) 167b96eea71SA.s. Dong { 168b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 169b96eea71SA.s. Dong struct imx_pin_mmio *pin_mmio = &pin->conf.mmio; 170b96eea71SA.s. Dong const struct imx_pin_reg *pin_reg; 171b96eea71SA.s. Dong unsigned int pin_id; 172b96eea71SA.s. Dong 173b96eea71SA.s. Dong pin_id = pin->pin; 174b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[pin_id]; 175b96eea71SA.s. Dong 176b96eea71SA.s. Dong if (pin_reg->mux_reg == -1) { 177b96eea71SA.s. Dong dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n", 178b96eea71SA.s. Dong info->pins[pin_id].name); 179b96eea71SA.s. Dong return 0; 180b96eea71SA.s. Dong } 181b96eea71SA.s. Dong 182b96eea71SA.s. Dong if (info->flags & SHARE_MUX_CONF_REG) { 183b96eea71SA.s. Dong u32 reg; 184b96eea71SA.s. Dong 185b96eea71SA.s. Dong reg = readl(ipctl->base + pin_reg->mux_reg); 186b96eea71SA.s. Dong reg &= ~info->mux_mask; 187b96eea71SA.s. Dong reg |= (pin_mmio->mux_mode << info->mux_shift); 188b96eea71SA.s. Dong writel(reg, ipctl->base + pin_reg->mux_reg); 189b96eea71SA.s. Dong dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 190b96eea71SA.s. Dong pin_reg->mux_reg, reg); 191b96eea71SA.s. Dong } else { 192b96eea71SA.s. Dong writel(pin_mmio->mux_mode, ipctl->base + pin_reg->mux_reg); 193b96eea71SA.s. Dong dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 194b96eea71SA.s. Dong pin_reg->mux_reg, pin_mmio->mux_mode); 195b96eea71SA.s. Dong } 196b96eea71SA.s. Dong 197b96eea71SA.s. Dong /* 198b96eea71SA.s. Dong * If the select input value begins with 0xff, it's a quirky 199b96eea71SA.s. Dong * select input and the value should be interpreted as below. 200b96eea71SA.s. Dong * 31 23 15 7 0 201b96eea71SA.s. Dong * | 0xff | shift | width | select | 202b96eea71SA.s. Dong * It's used to work around the problem that the select 203b96eea71SA.s. Dong * input for some pin is not implemented in the select 204b96eea71SA.s. Dong * input register but in some general purpose register. 205b96eea71SA.s. Dong * We encode the select input value, width and shift of 206b96eea71SA.s. Dong * the bit field into input_val cell of pin function ID 207b96eea71SA.s. Dong * in device tree, and then decode them here for setting 208b96eea71SA.s. Dong * up the select input bits in general purpose register. 209b96eea71SA.s. Dong */ 210b96eea71SA.s. Dong if (pin_mmio->input_val >> 24 == 0xff) { 211b96eea71SA.s. Dong u32 val = pin_mmio->input_val; 212b96eea71SA.s. Dong u8 select = val & 0xff; 213b96eea71SA.s. Dong u8 width = (val >> 8) & 0xff; 214b96eea71SA.s. Dong u8 shift = (val >> 16) & 0xff; 215b96eea71SA.s. Dong u32 mask = ((1 << width) - 1) << shift; 216b96eea71SA.s. Dong /* 217b96eea71SA.s. Dong * The input_reg[i] here is actually some IOMUXC general 218b96eea71SA.s. Dong * purpose register, not regular select input register. 219b96eea71SA.s. Dong */ 220b96eea71SA.s. Dong val = readl(ipctl->base + pin_mmio->input_reg); 221b96eea71SA.s. Dong val &= ~mask; 222b96eea71SA.s. Dong val |= select << shift; 223b96eea71SA.s. Dong writel(val, ipctl->base + pin_mmio->input_reg); 224b96eea71SA.s. Dong } else if (pin_mmio->input_reg) { 225b96eea71SA.s. Dong /* 226b96eea71SA.s. Dong * Regular select input register can never be at offset 227b96eea71SA.s. Dong * 0, and we only print register value for regular case. 228b96eea71SA.s. Dong */ 229b96eea71SA.s. Dong if (ipctl->input_sel_base) 230b96eea71SA.s. Dong writel(pin_mmio->input_val, ipctl->input_sel_base + 231b96eea71SA.s. Dong pin_mmio->input_reg); 232b96eea71SA.s. Dong else 233b96eea71SA.s. Dong writel(pin_mmio->input_val, ipctl->base + 234b96eea71SA.s. Dong pin_mmio->input_reg); 235b96eea71SA.s. Dong dev_dbg(ipctl->dev, 236b96eea71SA.s. Dong "==>select_input: offset 0x%x val 0x%x\n", 237b96eea71SA.s. Dong pin_mmio->input_reg, pin_mmio->input_val); 238b96eea71SA.s. Dong } 239b96eea71SA.s. Dong 240b96eea71SA.s. Dong return 0; 241b96eea71SA.s. Dong } 242b96eea71SA.s. Dong 243edad3b2aSLinus Walleij static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, 244edad3b2aSLinus Walleij unsigned group) 245edad3b2aSLinus Walleij { 246edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 247f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 248b96eea71SA.s. Dong struct function_desc *func; 249b96eea71SA.s. Dong struct group_desc *grp; 250b96eea71SA.s. Dong struct imx_pin *pin; 251b96eea71SA.s. Dong unsigned int npins; 252b96eea71SA.s. Dong int i, err; 253edad3b2aSLinus Walleij 254edad3b2aSLinus Walleij /* 255edad3b2aSLinus Walleij * Configure the mux mode for each pin in the group for a specific 256edad3b2aSLinus Walleij * function. 257edad3b2aSLinus Walleij */ 258e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, group); 259a51c158bSGary Bisson if (!grp) 260a51c158bSGary Bisson return -EINVAL; 261a51c158bSGary Bisson 2623fd6d6adSGary Bisson func = pinmux_generic_get_function(pctldev, selector); 263a51c158bSGary Bisson if (!func) 264a51c158bSGary Bisson return -EINVAL; 265a51c158bSGary Bisson 266e566fc11SGary Bisson npins = grp->num_pins; 267edad3b2aSLinus Walleij 268edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "enable function %s group %s\n", 269a51c158bSGary Bisson func->name, grp->name); 270edad3b2aSLinus Walleij 271edad3b2aSLinus Walleij for (i = 0; i < npins; i++) { 272edad3b2aSLinus Walleij /* 273b96eea71SA.s. Dong * For IMX_USE_SCU case, we postpone the mux setting 274b96eea71SA.s. Dong * until config is set as we can set them together 275b96eea71SA.s. Dong * in one IPC call 276edad3b2aSLinus Walleij */ 277b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 278b96eea71SA.s. Dong if (!(info->flags & IMX_USE_SCU)) { 279b96eea71SA.s. Dong err = imx_pmx_set_one_pin_mmio(ipctl, pin); 280b96eea71SA.s. Dong if (err) 281b96eea71SA.s. Dong return err; 282edad3b2aSLinus Walleij } 283edad3b2aSLinus Walleij } 284edad3b2aSLinus Walleij 285edad3b2aSLinus Walleij return 0; 286edad3b2aSLinus Walleij } 287edad3b2aSLinus Walleij 2883be6f651SDong Aisheng struct pinmux_ops imx_pmx_ops = { 2893fd6d6adSGary Bisson .get_functions_count = pinmux_generic_get_function_count, 2903fd6d6adSGary Bisson .get_function_name = pinmux_generic_get_function_name, 2913fd6d6adSGary Bisson .get_function_groups = pinmux_generic_get_function_groups, 292edad3b2aSLinus Walleij .set_mux = imx_pmx_set, 293edad3b2aSLinus Walleij }; 294edad3b2aSLinus Walleij 295b96eea71SA.s. Dong static int imx_pinconf_get_mmio(struct pinctrl_dev *pctldev, unsigned pin_id, 296b96eea71SA.s. Dong unsigned long *config) 297edad3b2aSLinus Walleij { 298edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 299f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 300f5843492SStefan Agner const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; 301edad3b2aSLinus Walleij 3023dac1918SStefan Agner if (pin_reg->conf_reg == -1) { 303f5843492SStefan Agner dev_err(ipctl->dev, "Pin(%s) does not support config function\n", 304edad3b2aSLinus Walleij info->pins[pin_id].name); 305edad3b2aSLinus Walleij return -EINVAL; 306edad3b2aSLinus Walleij } 307edad3b2aSLinus Walleij 308edad3b2aSLinus Walleij *config = readl(ipctl->base + pin_reg->conf_reg); 309edad3b2aSLinus Walleij 310edad3b2aSLinus Walleij if (info->flags & SHARE_MUX_CONF_REG) 3115586ee41SDong Aisheng *config &= ~info->mux_mask; 312edad3b2aSLinus Walleij 313edad3b2aSLinus Walleij return 0; 314edad3b2aSLinus Walleij } 315edad3b2aSLinus Walleij 316b96eea71SA.s. Dong static int imx_pinconf_get(struct pinctrl_dev *pctldev, 317b96eea71SA.s. Dong unsigned pin_id, unsigned long *config) 318b96eea71SA.s. Dong { 319b96eea71SA.s. Dong struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 320b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 321b96eea71SA.s. Dong 322b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 32307ae3f07SAnson Huang return info->imx_pinconf_get(pctldev, pin_id, config); 324b96eea71SA.s. Dong else 325b96eea71SA.s. Dong return imx_pinconf_get_mmio(pctldev, pin_id, config); 326b96eea71SA.s. Dong } 327b96eea71SA.s. Dong 328b96eea71SA.s. Dong static int imx_pinconf_set_mmio(struct pinctrl_dev *pctldev, 329edad3b2aSLinus Walleij unsigned pin_id, unsigned long *configs, 330edad3b2aSLinus Walleij unsigned num_configs) 331edad3b2aSLinus Walleij { 332edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 333f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 334f5843492SStefan Agner const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id]; 335edad3b2aSLinus Walleij int i; 336edad3b2aSLinus Walleij 3373dac1918SStefan Agner if (pin_reg->conf_reg == -1) { 338f5843492SStefan Agner dev_err(ipctl->dev, "Pin(%s) does not support config function\n", 339edad3b2aSLinus Walleij info->pins[pin_id].name); 340edad3b2aSLinus Walleij return -EINVAL; 341edad3b2aSLinus Walleij } 342edad3b2aSLinus Walleij 343edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "pinconf set pin %s\n", 344edad3b2aSLinus Walleij info->pins[pin_id].name); 345edad3b2aSLinus Walleij 346edad3b2aSLinus Walleij for (i = 0; i < num_configs; i++) { 347edad3b2aSLinus Walleij if (info->flags & SHARE_MUX_CONF_REG) { 348edad3b2aSLinus Walleij u32 reg; 349edad3b2aSLinus Walleij reg = readl(ipctl->base + pin_reg->conf_reg); 3505586ee41SDong Aisheng reg &= info->mux_mask; 351edad3b2aSLinus Walleij reg |= configs[i]; 352edad3b2aSLinus Walleij writel(reg, ipctl->base + pin_reg->conf_reg); 35366b54e3aSDong Aisheng dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", 35466b54e3aSDong Aisheng pin_reg->conf_reg, reg); 355edad3b2aSLinus Walleij } else { 356edad3b2aSLinus Walleij writel(configs[i], ipctl->base + pin_reg->conf_reg); 357edad3b2aSLinus Walleij dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", 358edad3b2aSLinus Walleij pin_reg->conf_reg, configs[i]); 35966b54e3aSDong Aisheng } 360edad3b2aSLinus Walleij } /* for each config */ 361edad3b2aSLinus Walleij 362edad3b2aSLinus Walleij return 0; 363edad3b2aSLinus Walleij } 364edad3b2aSLinus Walleij 365b96eea71SA.s. Dong static int imx_pinconf_set(struct pinctrl_dev *pctldev, 366b96eea71SA.s. Dong unsigned pin_id, unsigned long *configs, 367b96eea71SA.s. Dong unsigned num_configs) 368b96eea71SA.s. Dong { 369b96eea71SA.s. Dong struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 370b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 371b96eea71SA.s. Dong 372b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 37307ae3f07SAnson Huang return info->imx_pinconf_set(pctldev, pin_id, 374b96eea71SA.s. Dong configs, num_configs); 375b96eea71SA.s. Dong else 376b96eea71SA.s. Dong return imx_pinconf_set_mmio(pctldev, pin_id, 377b96eea71SA.s. Dong configs, num_configs); 378b96eea71SA.s. Dong } 379b96eea71SA.s. Dong 380edad3b2aSLinus Walleij static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, 381edad3b2aSLinus Walleij struct seq_file *s, unsigned pin_id) 382edad3b2aSLinus Walleij { 383edad3b2aSLinus Walleij struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 384b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 385b96eea71SA.s. Dong const struct imx_pin_reg *pin_reg; 386edad3b2aSLinus Walleij unsigned long config; 387b96eea71SA.s. Dong int ret; 388edad3b2aSLinus Walleij 389b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) { 39007ae3f07SAnson Huang ret = info->imx_pinconf_get(pctldev, pin_id, &config); 391b96eea71SA.s. Dong if (ret) { 392b96eea71SA.s. Dong dev_err(ipctl->dev, "failed to get %s pinconf\n", 393b96eea71SA.s. Dong pin_get_name(pctldev, pin_id)); 394b96eea71SA.s. Dong seq_puts(s, "N/A"); 395b96eea71SA.s. Dong return; 396b96eea71SA.s. Dong } 397b96eea71SA.s. Dong } else { 398b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[pin_id]; 399c7df94c6SDan Carpenter if (pin_reg->conf_reg == -1) { 4007d6989adSDong Aisheng seq_puts(s, "N/A"); 401edad3b2aSLinus Walleij return; 402edad3b2aSLinus Walleij } 403edad3b2aSLinus Walleij 404edad3b2aSLinus Walleij config = readl(ipctl->base + pin_reg->conf_reg); 405b96eea71SA.s. Dong } 406b96eea71SA.s. Dong 407edad3b2aSLinus Walleij seq_printf(s, "0x%lx", config); 408edad3b2aSLinus Walleij } 409edad3b2aSLinus Walleij 410edad3b2aSLinus Walleij static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 411edad3b2aSLinus Walleij struct seq_file *s, unsigned group) 412edad3b2aSLinus Walleij { 413e566fc11SGary Bisson struct group_desc *grp; 414edad3b2aSLinus Walleij unsigned long config; 415edad3b2aSLinus Walleij const char *name; 416edad3b2aSLinus Walleij int i, ret; 417edad3b2aSLinus Walleij 418b4859f3eSDan Carpenter if (group >= pctldev->num_groups) 419edad3b2aSLinus Walleij return; 420edad3b2aSLinus Walleij 4217d6989adSDong Aisheng seq_puts(s, "\n"); 422e566fc11SGary Bisson grp = pinctrl_generic_get_group(pctldev, group); 423a51c158bSGary Bisson if (!grp) 424a51c158bSGary Bisson return; 425a51c158bSGary Bisson 426e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 427e566fc11SGary Bisson struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; 428e566fc11SGary Bisson 429edad3b2aSLinus Walleij name = pin_get_name(pctldev, pin->pin); 430edad3b2aSLinus Walleij ret = imx_pinconf_get(pctldev, pin->pin, &config); 431edad3b2aSLinus Walleij if (ret) 432edad3b2aSLinus Walleij return; 433a2d16a21SVladimir Zapolskiy seq_printf(s, " %s: 0x%lx\n", name, config); 434edad3b2aSLinus Walleij } 435edad3b2aSLinus Walleij } 436edad3b2aSLinus Walleij 437edad3b2aSLinus Walleij static const struct pinconf_ops imx_pinconf_ops = { 438edad3b2aSLinus Walleij .pin_config_get = imx_pinconf_get, 439edad3b2aSLinus Walleij .pin_config_set = imx_pinconf_set, 440edad3b2aSLinus Walleij .pin_config_dbg_show = imx_pinconf_dbg_show, 441edad3b2aSLinus Walleij .pin_config_group_dbg_show = imx_pinconf_group_dbg_show, 442edad3b2aSLinus Walleij }; 443edad3b2aSLinus Walleij 444edad3b2aSLinus Walleij /* 44537c1628fSDong Aisheng * Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID 44637c1628fSDong Aisheng * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin. 44737c1628fSDong Aisheng * 44837c1628fSDong Aisheng * PIN_FUNC_ID format: 44937c1628fSDong Aisheng * Default: 45037c1628fSDong Aisheng * <mux_reg conf_reg input_reg mux_mode input_val> 45137c1628fSDong Aisheng * SHARE_MUX_CONF_REG: 45237c1628fSDong Aisheng * <mux_conf_reg input_reg mux_mode input_val> 453b96eea71SA.s. Dong * IMX_USE_SCU: 454b96eea71SA.s. Dong * <pin_id mux_mode> 455edad3b2aSLinus Walleij */ 456edad3b2aSLinus Walleij #define FSL_PIN_SIZE 24 45737c1628fSDong Aisheng #define FSL_PIN_SHARE_SIZE 20 458b96eea71SA.s. Dong #define FSL_SCU_PIN_SIZE 12 459b96eea71SA.s. Dong 460b96eea71SA.s. Dong static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl, 461b96eea71SA.s. Dong unsigned int *pin_id, struct imx_pin *pin, 462b96eea71SA.s. Dong const __be32 **list_p, 463b96eea71SA.s. Dong struct device_node *np) 464b96eea71SA.s. Dong { 465b96eea71SA.s. Dong const struct imx_pinctrl_soc_info *info = ipctl->info; 466b96eea71SA.s. Dong struct imx_pin_mmio *pin_mmio = &pin->conf.mmio; 467b96eea71SA.s. Dong struct imx_pin_reg *pin_reg; 468b96eea71SA.s. Dong const __be32 *list = *list_p; 469b96eea71SA.s. Dong u32 mux_reg, conf_reg; 470b96eea71SA.s. Dong u32 config; 471b96eea71SA.s. Dong 472b96eea71SA.s. Dong mux_reg = be32_to_cpu(*list++); 473b96eea71SA.s. Dong 474b96eea71SA.s. Dong if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg) 475b96eea71SA.s. Dong mux_reg = -1; 476b96eea71SA.s. Dong 477b96eea71SA.s. Dong if (info->flags & SHARE_MUX_CONF_REG) { 478b96eea71SA.s. Dong conf_reg = mux_reg; 479b96eea71SA.s. Dong } else { 480b96eea71SA.s. Dong conf_reg = be32_to_cpu(*list++); 481b96eea71SA.s. Dong if (!conf_reg) 482b96eea71SA.s. Dong conf_reg = -1; 483b96eea71SA.s. Dong } 484b96eea71SA.s. Dong 485b96eea71SA.s. Dong *pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4; 486b96eea71SA.s. Dong pin_reg = &ipctl->pin_regs[*pin_id]; 487b96eea71SA.s. Dong pin->pin = *pin_id; 488b96eea71SA.s. Dong pin_reg->mux_reg = mux_reg; 489b96eea71SA.s. Dong pin_reg->conf_reg = conf_reg; 490b96eea71SA.s. Dong pin_mmio->input_reg = be32_to_cpu(*list++); 491b96eea71SA.s. Dong pin_mmio->mux_mode = be32_to_cpu(*list++); 492b96eea71SA.s. Dong pin_mmio->input_val = be32_to_cpu(*list++); 493b96eea71SA.s. Dong 494b96eea71SA.s. Dong config = be32_to_cpu(*list++); 495b96eea71SA.s. Dong 496b96eea71SA.s. Dong /* SION bit is in mux register */ 497b96eea71SA.s. Dong if (config & IMX_PAD_SION) 498b96eea71SA.s. Dong pin_mmio->mux_mode |= IOMUXC_CONFIG_SION; 499b96eea71SA.s. Dong pin_mmio->config = config & ~IMX_PAD_SION; 500b96eea71SA.s. Dong 50157161067SA.s. Dong *list_p = list; 50257161067SA.s. Dong 503b96eea71SA.s. Dong dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[*pin_id].name, 504b96eea71SA.s. Dong pin_mmio->mux_mode, pin_mmio->config); 505b96eea71SA.s. Dong } 506edad3b2aSLinus Walleij 507edad3b2aSLinus Walleij static int imx_pinctrl_parse_groups(struct device_node *np, 508e566fc11SGary Bisson struct group_desc *grp, 509a5cadbbbSDong Aisheng struct imx_pinctrl *ipctl, 510edad3b2aSLinus Walleij u32 index) 511edad3b2aSLinus Walleij { 512f5843492SStefan Agner const struct imx_pinctrl_soc_info *info = ipctl->info; 513b96eea71SA.s. Dong struct imx_pin *pin; 514*26ea8229SAndy Shevchenko unsigned int *pins; 515edad3b2aSLinus Walleij int size, pin_size; 516edad3b2aSLinus Walleij const __be32 *list; 517edad3b2aSLinus Walleij int i; 518edad3b2aSLinus Walleij 51994f4e54cSRob Herring dev_dbg(ipctl->dev, "group(%d): %pOFn\n", index, np); 520edad3b2aSLinus Walleij 521b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 522b96eea71SA.s. Dong pin_size = FSL_SCU_PIN_SIZE; 523b96eea71SA.s. Dong else if (info->flags & SHARE_MUX_CONF_REG) 52437c1628fSDong Aisheng pin_size = FSL_PIN_SHARE_SIZE; 525edad3b2aSLinus Walleij else 526edad3b2aSLinus Walleij pin_size = FSL_PIN_SIZE; 527a5cadbbbSDong Aisheng 528edad3b2aSLinus Walleij /* Initialise group */ 529edad3b2aSLinus Walleij grp->name = np->name; 530edad3b2aSLinus Walleij 531edad3b2aSLinus Walleij /* 532edad3b2aSLinus Walleij * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>, 533edad3b2aSLinus Walleij * do sanity check and calculate pins number 534a5cadbbbSDong Aisheng * 535a5cadbbbSDong Aisheng * First try legacy 'fsl,pins' property, then fall back to the 536fc4f351aSDong Aisheng * generic 'pinmux'. 537a5cadbbbSDong Aisheng * 538fc4f351aSDong Aisheng * Note: for generic 'pinmux' case, there's no CONFIG part in 539a5cadbbbSDong Aisheng * the binding format. 540edad3b2aSLinus Walleij */ 541edad3b2aSLinus Walleij list = of_get_property(np, "fsl,pins", &size); 542edad3b2aSLinus Walleij if (!list) { 543fc4f351aSDong Aisheng list = of_get_property(np, "pinmux", &size); 544a5cadbbbSDong Aisheng if (!list) { 545f5843492SStefan Agner dev_err(ipctl->dev, 546f5292d06SRob Herring "no fsl,pins and pins property in node %pOF\n", np); 547edad3b2aSLinus Walleij return -EINVAL; 548edad3b2aSLinus Walleij } 549a5cadbbbSDong Aisheng } 550edad3b2aSLinus Walleij 551edad3b2aSLinus Walleij /* we do not check return since it's safe node passed down */ 552edad3b2aSLinus Walleij if (!size || size % pin_size) { 553f5843492SStefan Agner dev_err(ipctl->dev, "Invalid fsl,pins or pins property in node %pOF\n", np); 554edad3b2aSLinus Walleij return -EINVAL; 555edad3b2aSLinus Walleij } 556edad3b2aSLinus Walleij 557e566fc11SGary Bisson grp->num_pins = size / pin_size; 558a86854d0SKees Cook grp->data = devm_kcalloc(ipctl->dev, 559a86854d0SKees Cook grp->num_pins, sizeof(struct imx_pin), 560a86854d0SKees Cook GFP_KERNEL); 561*26ea8229SAndy Shevchenko if (!grp->data) 562edad3b2aSLinus Walleij return -ENOMEM; 563edad3b2aSLinus Walleij 564*26ea8229SAndy Shevchenko pins = devm_kcalloc(ipctl->dev, grp->num_pins, sizeof(*pins), GFP_KERNEL); 565*26ea8229SAndy Shevchenko if (!pins) 566*26ea8229SAndy Shevchenko return -ENOMEM; 567*26ea8229SAndy Shevchenko grp->pins = pins; 568*26ea8229SAndy Shevchenko 569e566fc11SGary Bisson for (i = 0; i < grp->num_pins; i++) { 570b96eea71SA.s. Dong pin = &((struct imx_pin *)(grp->data))[i]; 571b96eea71SA.s. Dong if (info->flags & IMX_USE_SCU) 572*26ea8229SAndy Shevchenko info->imx_pinctrl_parse_pin(ipctl, &pins[i], pin, &list); 573b96eea71SA.s. Dong else 574*26ea8229SAndy Shevchenko imx_pinctrl_parse_pin_mmio(ipctl, &pins[i], pin, &list, np); 575edad3b2aSLinus Walleij } 576edad3b2aSLinus Walleij 577edad3b2aSLinus Walleij return 0; 578edad3b2aSLinus Walleij } 579edad3b2aSLinus Walleij 580edad3b2aSLinus Walleij static int imx_pinctrl_parse_functions(struct device_node *np, 581e566fc11SGary Bisson struct imx_pinctrl *ipctl, 582edad3b2aSLinus Walleij u32 index) 583edad3b2aSLinus Walleij { 584e566fc11SGary Bisson struct pinctrl_dev *pctl = ipctl->pctl; 585edad3b2aSLinus Walleij struct device_node *child; 5863fd6d6adSGary Bisson struct function_desc *func; 587e566fc11SGary Bisson struct group_desc *grp; 58802f11713SRafał Miłecki const char **group_names; 58974429366SRafał Miłecki u32 i; 590edad3b2aSLinus Walleij 59194f4e54cSRob Herring dev_dbg(pctl->dev, "parse function(%d): %pOFn\n", index, np); 592edad3b2aSLinus Walleij 5933fd6d6adSGary Bisson func = pinmux_generic_get_function(pctl, index); 594a51c158bSGary Bisson if (!func) 595a51c158bSGary Bisson return -EINVAL; 596edad3b2aSLinus Walleij 597edad3b2aSLinus Walleij /* Initialise function */ 598edad3b2aSLinus Walleij func->name = np->name; 5993fd6d6adSGary Bisson func->num_group_names = of_get_child_count(np); 6003fd6d6adSGary Bisson if (func->num_group_names == 0) { 601f5141ae4SAlexander Stein dev_info(ipctl->dev, "no groups defined in %pOF\n", np); 602edad3b2aSLinus Walleij return -EINVAL; 603edad3b2aSLinus Walleij } 60402f11713SRafał Miłecki 60502f11713SRafał Miłecki group_names = devm_kcalloc(ipctl->dev, func->num_group_names, 6063fd6d6adSGary Bisson sizeof(char *), GFP_KERNEL); 607aa63e656SRafał Miłecki if (!group_names) 60849af64e6SChristophe JAILLET return -ENOMEM; 60974429366SRafał Miłecki i = 0; 61002f11713SRafał Miłecki for_each_child_of_node(np, child) 61174429366SRafał Miłecki group_names[i++] = child->name; 61202f11713SRafał Miłecki func->group_names = group_names; 613edad3b2aSLinus Walleij 61474429366SRafał Miłecki i = 0; 615edad3b2aSLinus Walleij for_each_child_of_node(np, child) { 616f5843492SStefan Agner grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc), 617a51c158bSGary Bisson GFP_KERNEL); 618bf4b87b0SNishka Dasgupta if (!grp) { 619bf4b87b0SNishka Dasgupta of_node_put(child); 620a51c158bSGary Bisson return -ENOMEM; 621bf4b87b0SNishka Dasgupta } 622a51c158bSGary Bisson 623f5843492SStefan Agner mutex_lock(&ipctl->mutex); 624e566fc11SGary Bisson radix_tree_insert(&pctl->pin_group_tree, 625f5843492SStefan Agner ipctl->group_index++, grp); 626f5843492SStefan Agner mutex_unlock(&ipctl->mutex); 627a51c158bSGary Bisson 628a5cadbbbSDong Aisheng imx_pinctrl_parse_groups(child, grp, ipctl, i++); 629edad3b2aSLinus Walleij } 630edad3b2aSLinus Walleij 631edad3b2aSLinus Walleij return 0; 632edad3b2aSLinus Walleij } 633edad3b2aSLinus Walleij 6345fcdf6a7SMarkus Pargmann /* 6355fcdf6a7SMarkus Pargmann * Check if the DT contains pins in the direct child nodes. This indicates the 6365fcdf6a7SMarkus Pargmann * newer DT format to store pins. This function returns true if the first found 6375fcdf6a7SMarkus Pargmann * fsl,pins property is in a child of np. Otherwise false is returned. 6385fcdf6a7SMarkus Pargmann */ 6395fcdf6a7SMarkus Pargmann static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) 6405fcdf6a7SMarkus Pargmann { 6415fcdf6a7SMarkus Pargmann struct device_node *function_np; 6425fcdf6a7SMarkus Pargmann struct device_node *pinctrl_np; 6435fcdf6a7SMarkus Pargmann 6445fcdf6a7SMarkus Pargmann for_each_child_of_node(np, function_np) { 645bf4b87b0SNishka Dasgupta if (of_property_read_bool(function_np, "fsl,pins")) { 646bf4b87b0SNishka Dasgupta of_node_put(function_np); 6475fcdf6a7SMarkus Pargmann return true; 648bf4b87b0SNishka Dasgupta } 6495fcdf6a7SMarkus Pargmann 6505fcdf6a7SMarkus Pargmann for_each_child_of_node(function_np, pinctrl_np) { 651bf4b87b0SNishka Dasgupta if (of_property_read_bool(pinctrl_np, "fsl,pins")) { 652bf4b87b0SNishka Dasgupta of_node_put(pinctrl_np); 653bf4b87b0SNishka Dasgupta of_node_put(function_np); 6545fcdf6a7SMarkus Pargmann return false; 6555fcdf6a7SMarkus Pargmann } 6565fcdf6a7SMarkus Pargmann } 657bf4b87b0SNishka Dasgupta } 6585fcdf6a7SMarkus Pargmann 6595fcdf6a7SMarkus Pargmann return true; 6605fcdf6a7SMarkus Pargmann } 6615fcdf6a7SMarkus Pargmann 662edad3b2aSLinus Walleij static int imx_pinctrl_probe_dt(struct platform_device *pdev, 663e566fc11SGary Bisson struct imx_pinctrl *ipctl) 664edad3b2aSLinus Walleij { 665edad3b2aSLinus Walleij struct device_node *np = pdev->dev.of_node; 666edad3b2aSLinus Walleij struct device_node *child; 667e566fc11SGary Bisson struct pinctrl_dev *pctl = ipctl->pctl; 668edad3b2aSLinus Walleij u32 nfuncs = 0; 669edad3b2aSLinus Walleij u32 i = 0; 6705fcdf6a7SMarkus Pargmann bool flat_funcs; 671edad3b2aSLinus Walleij 672edad3b2aSLinus Walleij if (!np) 673edad3b2aSLinus Walleij return -ENODEV; 674edad3b2aSLinus Walleij 6755fcdf6a7SMarkus Pargmann flat_funcs = imx_pinctrl_dt_is_flat_functions(np); 6765fcdf6a7SMarkus Pargmann if (flat_funcs) { 6775fcdf6a7SMarkus Pargmann nfuncs = 1; 6785fcdf6a7SMarkus Pargmann } else { 679edad3b2aSLinus Walleij nfuncs = of_get_child_count(np); 680562088eeSDong Aisheng if (nfuncs == 0) { 681edad3b2aSLinus Walleij dev_err(&pdev->dev, "no functions defined\n"); 682edad3b2aSLinus Walleij return -EINVAL; 683edad3b2aSLinus Walleij } 6845fcdf6a7SMarkus Pargmann } 685edad3b2aSLinus Walleij 686a51c158bSGary Bisson for (i = 0; i < nfuncs; i++) { 6873fd6d6adSGary Bisson struct function_desc *function; 688a51c158bSGary Bisson 689a51c158bSGary Bisson function = devm_kzalloc(&pdev->dev, sizeof(*function), 690edad3b2aSLinus Walleij GFP_KERNEL); 691a51c158bSGary Bisson if (!function) 692edad3b2aSLinus Walleij return -ENOMEM; 693edad3b2aSLinus Walleij 694f5843492SStefan Agner mutex_lock(&ipctl->mutex); 6953fd6d6adSGary Bisson radix_tree_insert(&pctl->pin_function_tree, i, function); 696f5843492SStefan Agner mutex_unlock(&ipctl->mutex); 697a51c158bSGary Bisson } 6983fd6d6adSGary Bisson pctl->num_functions = nfuncs; 699a51c158bSGary Bisson 700f5843492SStefan Agner ipctl->group_index = 0; 7015fcdf6a7SMarkus Pargmann if (flat_funcs) { 702e566fc11SGary Bisson pctl->num_groups = of_get_child_count(np); 7035fcdf6a7SMarkus Pargmann } else { 704e566fc11SGary Bisson pctl->num_groups = 0; 705edad3b2aSLinus Walleij for_each_child_of_node(np, child) 706e566fc11SGary Bisson pctl->num_groups += of_get_child_count(child); 7075fcdf6a7SMarkus Pargmann } 708edad3b2aSLinus Walleij 7095fcdf6a7SMarkus Pargmann if (flat_funcs) { 710e566fc11SGary Bisson imx_pinctrl_parse_functions(np, ipctl, 0); 7115fcdf6a7SMarkus Pargmann } else { 712a51c158bSGary Bisson i = 0; 713edad3b2aSLinus Walleij for_each_child_of_node(np, child) 714e566fc11SGary Bisson imx_pinctrl_parse_functions(child, ipctl, i++); 7155fcdf6a7SMarkus Pargmann } 716edad3b2aSLinus Walleij 717edad3b2aSLinus Walleij return 0; 718edad3b2aSLinus Walleij } 719edad3b2aSLinus Walleij 720edad3b2aSLinus Walleij int imx_pinctrl_probe(struct platform_device *pdev, 721f5843492SStefan Agner const struct imx_pinctrl_soc_info *info) 722edad3b2aSLinus Walleij { 7238626ada8SPhilipp Zabel struct regmap_config config = { .name = "gpr" }; 72426d8cde5SAdrian Alonso struct device_node *dev_np = pdev->dev.of_node; 7256e408ed8SPeng Fan struct pinctrl_desc *imx_pinctrl_desc; 72626d8cde5SAdrian Alonso struct device_node *np; 727edad3b2aSLinus Walleij struct imx_pinctrl *ipctl; 7288626ada8SPhilipp Zabel struct regmap *gpr; 7294691dd01SStefan Agner int ret, i; 730edad3b2aSLinus Walleij 731edad3b2aSLinus Walleij if (!info || !info->pins || !info->npins) { 732edad3b2aSLinus Walleij dev_err(&pdev->dev, "wrong pinctrl info\n"); 733edad3b2aSLinus Walleij return -EINVAL; 734edad3b2aSLinus Walleij } 735edad3b2aSLinus Walleij 7368626ada8SPhilipp Zabel if (info->gpr_compatible) { 7378626ada8SPhilipp Zabel gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible); 7388626ada8SPhilipp Zabel if (!IS_ERR(gpr)) 7398626ada8SPhilipp Zabel regmap_attach_dev(&pdev->dev, gpr, &config); 7408626ada8SPhilipp Zabel } 7418626ada8SPhilipp Zabel 742edad3b2aSLinus Walleij /* Create state holders etc for this driver */ 743edad3b2aSLinus Walleij ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 744edad3b2aSLinus Walleij if (!ipctl) 745edad3b2aSLinus Walleij return -ENOMEM; 746edad3b2aSLinus Walleij 747b96eea71SA.s. Dong if (!(info->flags & IMX_USE_SCU)) { 748b96eea71SA.s. Dong ipctl->pin_regs = devm_kmalloc_array(&pdev->dev, info->npins, 749b96eea71SA.s. Dong sizeof(*ipctl->pin_regs), 7503c4211baSKees Cook GFP_KERNEL); 751f5843492SStefan Agner if (!ipctl->pin_regs) 752edad3b2aSLinus Walleij return -ENOMEM; 7534691dd01SStefan Agner 7544691dd01SStefan Agner for (i = 0; i < info->npins; i++) { 755f5843492SStefan Agner ipctl->pin_regs[i].mux_reg = -1; 756f5843492SStefan Agner ipctl->pin_regs[i].conf_reg = -1; 7574691dd01SStefan Agner } 758edad3b2aSLinus Walleij 759e05487d4SAnson Huang ipctl->base = devm_platform_ioremap_resource(pdev, 0); 760edad3b2aSLinus Walleij if (IS_ERR(ipctl->base)) 761edad3b2aSLinus Walleij return PTR_ERR(ipctl->base); 762edad3b2aSLinus Walleij 76326d8cde5SAdrian Alonso if (of_property_read_bool(dev_np, "fsl,input-sel")) { 76426d8cde5SAdrian Alonso np = of_parse_phandle(dev_np, "fsl,input-sel", 0); 7659a4f4245SVladimir Zapolskiy if (!np) { 76626d8cde5SAdrian Alonso dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); 76726d8cde5SAdrian Alonso return -EINVAL; 76826d8cde5SAdrian Alonso } 7699a4f4245SVladimir Zapolskiy 77013f2d25bSHaibo Chen ipctl->input_sel_base = of_iomap(np, 0); 77126d8cde5SAdrian Alonso of_node_put(np); 77213f2d25bSHaibo Chen if (!ipctl->input_sel_base) { 7739a4f4245SVladimir Zapolskiy dev_err(&pdev->dev, 7749a4f4245SVladimir Zapolskiy "iomuxc input select base address not found\n"); 77513f2d25bSHaibo Chen return -ENOMEM; 7769a4f4245SVladimir Zapolskiy } 77726d8cde5SAdrian Alonso } 778b96eea71SA.s. Dong } 77926d8cde5SAdrian Alonso 7806e408ed8SPeng Fan imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc), 7816e408ed8SPeng Fan GFP_KERNEL); 7826e408ed8SPeng Fan if (!imx_pinctrl_desc) 7836e408ed8SPeng Fan return -ENOMEM; 7846e408ed8SPeng Fan 7856e408ed8SPeng Fan imx_pinctrl_desc->name = dev_name(&pdev->dev); 7866e408ed8SPeng Fan imx_pinctrl_desc->pins = info->pins; 7876e408ed8SPeng Fan imx_pinctrl_desc->npins = info->npins; 7888f5983adSGary Bisson imx_pinctrl_desc->pctlops = &imx_pctrl_ops; 7898f5983adSGary Bisson imx_pinctrl_desc->pmxops = &imx_pmx_ops; 7908f5983adSGary Bisson imx_pinctrl_desc->confops = &imx_pinconf_ops; 7918f5983adSGary Bisson imx_pinctrl_desc->owner = THIS_MODULE; 792edad3b2aSLinus Walleij 7933be6f651SDong Aisheng /* platform specific callback */ 7943be6f651SDong Aisheng imx_pmx_ops.gpio_set_direction = info->gpio_set_direction; 7953be6f651SDong Aisheng 796f5843492SStefan Agner mutex_init(&ipctl->mutex); 797a51c158bSGary Bisson 798edad3b2aSLinus Walleij ipctl->info = info; 799f5843492SStefan Agner ipctl->dev = &pdev->dev; 800edad3b2aSLinus Walleij platform_set_drvdata(pdev, ipctl); 801950b0d91STony Lindgren ret = devm_pinctrl_register_and_init(&pdev->dev, 802950b0d91STony Lindgren imx_pinctrl_desc, ipctl, 803950b0d91STony Lindgren &ipctl->pctl); 804950b0d91STony Lindgren if (ret) { 805edad3b2aSLinus Walleij dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); 80611d8da5cSChristophe JAILLET return ret; 807edad3b2aSLinus Walleij } 808edad3b2aSLinus Walleij 809e566fc11SGary Bisson ret = imx_pinctrl_probe_dt(pdev, ipctl); 810e566fc11SGary Bisson if (ret) { 811e566fc11SGary Bisson dev_err(&pdev->dev, "fail to probe dt properties\n"); 81211d8da5cSChristophe JAILLET return ret; 813e566fc11SGary Bisson } 814e566fc11SGary Bisson 815edad3b2aSLinus Walleij dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); 816edad3b2aSLinus Walleij 81761187142STony Lindgren return pinctrl_enable(ipctl->pctl); 818edad3b2aSLinus Walleij } 819b4554deeSAnson Huang EXPORT_SYMBOL_GPL(imx_pinctrl_probe); 820855811eaSAbel Vesa 821855811eaSAbel Vesa static int __maybe_unused imx_pinctrl_suspend(struct device *dev) 822855811eaSAbel Vesa { 823855811eaSAbel Vesa struct imx_pinctrl *ipctl = dev_get_drvdata(dev); 824855811eaSAbel Vesa 825855811eaSAbel Vesa return pinctrl_force_sleep(ipctl->pctl); 826855811eaSAbel Vesa } 827855811eaSAbel Vesa 828855811eaSAbel Vesa static int __maybe_unused imx_pinctrl_resume(struct device *dev) 829855811eaSAbel Vesa { 830855811eaSAbel Vesa struct imx_pinctrl *ipctl = dev_get_drvdata(dev); 831855811eaSAbel Vesa 832855811eaSAbel Vesa return pinctrl_force_default(ipctl->pctl); 833855811eaSAbel Vesa } 834855811eaSAbel Vesa 835855811eaSAbel Vesa const struct dev_pm_ops imx_pinctrl_pm_ops = { 836855811eaSAbel Vesa SET_LATE_SYSTEM_SLEEP_PM_OPS(imx_pinctrl_suspend, 837855811eaSAbel Vesa imx_pinctrl_resume) 838855811eaSAbel Vesa }; 839b4554deeSAnson Huang EXPORT_SYMBOL_GPL(imx_pinctrl_pm_ops); 8407233f7cfSAnson Huang 8417233f7cfSAnson Huang MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>"); 8427233f7cfSAnson Huang MODULE_DESCRIPTION("NXP i.MX common pinctrl driver"); 8437233f7cfSAnson Huang MODULE_LICENSE("GPL v2"); 844