1*657cbf9bSIvan T. Ivanov // SPDX-License-Identifier: GPL-2.0+ 2*657cbf9bSIvan T. Ivanov /* 3*657cbf9bSIvan T. Ivanov * Driver for Broadcom brcmstb GPIO units (pinctrl only) 4*657cbf9bSIvan T. Ivanov * 5*657cbf9bSIvan T. Ivanov * Copyright (C) 2024-2025 Ivan T. Ivanov, Andrea della Porta 6*657cbf9bSIvan T. Ivanov * Copyright (C) 2021-3 Raspberry Pi Ltd. 7*657cbf9bSIvan T. Ivanov * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren 8*657cbf9bSIvan T. Ivanov * 9*657cbf9bSIvan T. Ivanov * Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by: 10*657cbf9bSIvan T. Ivanov * pinctrl-nomadik.c, please see original file for copyright information 11*657cbf9bSIvan T. Ivanov * pinctrl-tegra.c, please see original file for copyright information 12*657cbf9bSIvan T. Ivanov */ 13*657cbf9bSIvan T. Ivanov 14*657cbf9bSIvan T. Ivanov #include <linux/device.h> 15*657cbf9bSIvan T. Ivanov #include <linux/err.h> 16*657cbf9bSIvan T. Ivanov #include <linux/init.h> 17*657cbf9bSIvan T. Ivanov #include <linux/io.h> 18*657cbf9bSIvan T. Ivanov #include <linux/of.h> 19*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinconf.h> 20*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinctrl.h> 21*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinmux.h> 22*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinconf-generic.h> 23*657cbf9bSIvan T. Ivanov #include <linux/seq_file.h> 24*657cbf9bSIvan T. Ivanov #include <linux/slab.h> 25*657cbf9bSIvan T. Ivanov #include <linux/spinlock.h> 26*657cbf9bSIvan T. Ivanov #include <linux/cleanup.h> 27*657cbf9bSIvan T. Ivanov 28*657cbf9bSIvan T. Ivanov #include "pinctrl-brcmstb.h" 29*657cbf9bSIvan T. Ivanov 30*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_NONE 0 31*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_DOWN 1 32*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_UP 2 33*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_MASK 0x3 34*657cbf9bSIvan T. Ivanov 35*657cbf9bSIvan T. Ivanov #define BIT_TO_REG(b) (((b) >> 5) << 2) 36*657cbf9bSIvan T. Ivanov #define BIT_TO_SHIFT(b) ((b) & 0x1f) 37*657cbf9bSIvan T. Ivanov 38*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl { 39*657cbf9bSIvan T. Ivanov struct device *dev; 40*657cbf9bSIvan T. Ivanov void __iomem *base; 41*657cbf9bSIvan T. Ivanov struct pinctrl_dev *pctl_dev; 42*657cbf9bSIvan T. Ivanov struct pinctrl_desc pctl_desc; 43*657cbf9bSIvan T. Ivanov const struct pin_regs *pin_regs; 44*657cbf9bSIvan T. Ivanov const struct brcmstb_pin_funcs *pin_funcs; 45*657cbf9bSIvan T. Ivanov const char * const *func_names; 46*657cbf9bSIvan T. Ivanov unsigned int func_count; 47*657cbf9bSIvan T. Ivanov unsigned int func_gpio; 48*657cbf9bSIvan T. Ivanov const char *const *gpio_groups; 49*657cbf9bSIvan T. Ivanov struct pinctrl_gpio_range gpio_range; 50*657cbf9bSIvan T. Ivanov /* Protect FSEL registers */ 51*657cbf9bSIvan T. Ivanov spinlock_t fsel_lock; 52*657cbf9bSIvan T. Ivanov }; 53*657cbf9bSIvan T. Ivanov 54*657cbf9bSIvan T. Ivanov static unsigned int brcmstb_pinctrl_fsel_get(struct brcmstb_pinctrl *pc, 55*657cbf9bSIvan T. Ivanov unsigned int pin) 56*657cbf9bSIvan T. Ivanov { 57*657cbf9bSIvan T. Ivanov u32 bit = pc->pin_regs[pin].mux_bit; 58*657cbf9bSIvan T. Ivanov unsigned int func; 59*657cbf9bSIvan T. Ivanov int fsel; 60*657cbf9bSIvan T. Ivanov u32 val; 61*657cbf9bSIvan T. Ivanov 62*657cbf9bSIvan T. Ivanov if (!bit) 63*657cbf9bSIvan T. Ivanov return pc->func_gpio; 64*657cbf9bSIvan T. Ivanov 65*657cbf9bSIvan T. Ivanov bit &= ~MUX_BIT_VALID; 66*657cbf9bSIvan T. Ivanov 67*657cbf9bSIvan T. Ivanov val = readl(pc->base + BIT_TO_REG(bit)); 68*657cbf9bSIvan T. Ivanov fsel = (val >> BIT_TO_SHIFT(bit)) & pc->pin_funcs[pin].func_mask; 69*657cbf9bSIvan T. Ivanov func = pc->pin_funcs[pin].funcs[fsel]; 70*657cbf9bSIvan T. Ivanov 71*657cbf9bSIvan T. Ivanov if (func >= pc->func_count) 72*657cbf9bSIvan T. Ivanov func = fsel; 73*657cbf9bSIvan T. Ivanov 74*657cbf9bSIvan T. Ivanov dev_dbg(pc->dev, "get %04x: %08x (%u => %s)\n", 75*657cbf9bSIvan T. Ivanov BIT_TO_REG(bit), val, pin, 76*657cbf9bSIvan T. Ivanov pc->func_names[func]); 77*657cbf9bSIvan T. Ivanov 78*657cbf9bSIvan T. Ivanov return func; 79*657cbf9bSIvan T. Ivanov } 80*657cbf9bSIvan T. Ivanov 81*657cbf9bSIvan T. Ivanov static int brcmstb_pinctrl_fsel_set(struct brcmstb_pinctrl *pc, 82*657cbf9bSIvan T. Ivanov unsigned int pin, unsigned int func) 83*657cbf9bSIvan T. Ivanov { 84*657cbf9bSIvan T. Ivanov u32 bit = pc->pin_regs[pin].mux_bit, val, fsel_mask; 85*657cbf9bSIvan T. Ivanov const u8 *pin_funcs; 86*657cbf9bSIvan T. Ivanov int fsel; 87*657cbf9bSIvan T. Ivanov int cur; 88*657cbf9bSIvan T. Ivanov int i; 89*657cbf9bSIvan T. Ivanov 90*657cbf9bSIvan T. Ivanov if (!bit || func >= pc->func_count) 91*657cbf9bSIvan T. Ivanov return -EINVAL; 92*657cbf9bSIvan T. Ivanov 93*657cbf9bSIvan T. Ivanov bit &= ~MUX_BIT_VALID; 94*657cbf9bSIvan T. Ivanov 95*657cbf9bSIvan T. Ivanov fsel = pc->pin_funcs[pin].n_funcs + 1; 96*657cbf9bSIvan T. Ivanov fsel_mask = pc->pin_funcs[pin].func_mask; 97*657cbf9bSIvan T. Ivanov 98*657cbf9bSIvan T. Ivanov if (func >= fsel) { 99*657cbf9bSIvan T. Ivanov /* Convert to an fsel number */ 100*657cbf9bSIvan T. Ivanov pin_funcs = pc->pin_funcs[pin].funcs; 101*657cbf9bSIvan T. Ivanov for (i = 1; i < fsel; i++) { 102*657cbf9bSIvan T. Ivanov if (pin_funcs[i - 1] == func) { 103*657cbf9bSIvan T. Ivanov fsel = i; 104*657cbf9bSIvan T. Ivanov break; 105*657cbf9bSIvan T. Ivanov } 106*657cbf9bSIvan T. Ivanov } 107*657cbf9bSIvan T. Ivanov } else { 108*657cbf9bSIvan T. Ivanov fsel = func; 109*657cbf9bSIvan T. Ivanov } 110*657cbf9bSIvan T. Ivanov 111*657cbf9bSIvan T. Ivanov if (fsel >= pc->pin_funcs[pin].n_funcs + 1) 112*657cbf9bSIvan T. Ivanov return -EINVAL; 113*657cbf9bSIvan T. Ivanov 114*657cbf9bSIvan T. Ivanov guard(spinlock_irqsave)(&pc->fsel_lock); 115*657cbf9bSIvan T. Ivanov 116*657cbf9bSIvan T. Ivanov val = readl(pc->base + BIT_TO_REG(bit)); 117*657cbf9bSIvan T. Ivanov cur = (val >> BIT_TO_SHIFT(bit)) & fsel_mask; 118*657cbf9bSIvan T. Ivanov 119*657cbf9bSIvan T. Ivanov dev_dbg(pc->dev, "read %04x: %08x (%u => %s)\n", 120*657cbf9bSIvan T. Ivanov BIT_TO_REG(bit), val, pin, 121*657cbf9bSIvan T. Ivanov pc->func_names[cur]); 122*657cbf9bSIvan T. Ivanov 123*657cbf9bSIvan T. Ivanov if (cur != fsel) { 124*657cbf9bSIvan T. Ivanov val &= ~(fsel_mask << BIT_TO_SHIFT(bit)); 125*657cbf9bSIvan T. Ivanov val |= fsel << BIT_TO_SHIFT(bit); 126*657cbf9bSIvan T. Ivanov 127*657cbf9bSIvan T. Ivanov dev_dbg(pc->dev, "write %04x: %08x (%u <= %s)\n", 128*657cbf9bSIvan T. Ivanov BIT_TO_REG(bit), val, pin, 129*657cbf9bSIvan T. Ivanov pc->func_names[fsel]); 130*657cbf9bSIvan T. Ivanov writel(val, pc->base + BIT_TO_REG(bit)); 131*657cbf9bSIvan T. Ivanov } 132*657cbf9bSIvan T. Ivanov 133*657cbf9bSIvan T. Ivanov return 0; 134*657cbf9bSIvan T. Ivanov } 135*657cbf9bSIvan T. Ivanov 136*657cbf9bSIvan T. Ivanov static int brcmstb_pctl_get_groups_count(struct pinctrl_dev *pctldev) 137*657cbf9bSIvan T. Ivanov { 138*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 139*657cbf9bSIvan T. Ivanov 140*657cbf9bSIvan T. Ivanov return pc->pctl_desc.npins; 141*657cbf9bSIvan T. Ivanov } 142*657cbf9bSIvan T. Ivanov 143*657cbf9bSIvan T. Ivanov static const char *brcmstb_pctl_get_group_name(struct pinctrl_dev *pctldev, 144*657cbf9bSIvan T. Ivanov unsigned int selector) 145*657cbf9bSIvan T. Ivanov { 146*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 147*657cbf9bSIvan T. Ivanov 148*657cbf9bSIvan T. Ivanov return pc->gpio_groups[selector]; 149*657cbf9bSIvan T. Ivanov } 150*657cbf9bSIvan T. Ivanov 151*657cbf9bSIvan T. Ivanov static int brcmstb_pctl_get_group_pins(struct pinctrl_dev *pctldev, 152*657cbf9bSIvan T. Ivanov unsigned int selector, 153*657cbf9bSIvan T. Ivanov const unsigned int **pins, 154*657cbf9bSIvan T. Ivanov unsigned int *num_pins) 155*657cbf9bSIvan T. Ivanov { 156*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 157*657cbf9bSIvan T. Ivanov 158*657cbf9bSIvan T. Ivanov *pins = &pc->pctl_desc.pins[selector].number; 159*657cbf9bSIvan T. Ivanov *num_pins = 1; 160*657cbf9bSIvan T. Ivanov 161*657cbf9bSIvan T. Ivanov return 0; 162*657cbf9bSIvan T. Ivanov } 163*657cbf9bSIvan T. Ivanov 164*657cbf9bSIvan T. Ivanov static void brcmstb_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, 165*657cbf9bSIvan T. Ivanov struct seq_file *s, unsigned int offset) 166*657cbf9bSIvan T. Ivanov { 167*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 168*657cbf9bSIvan T. Ivanov unsigned int fsel = brcmstb_pinctrl_fsel_get(pc, offset); 169*657cbf9bSIvan T. Ivanov const char *fname = pc->func_names[fsel]; 170*657cbf9bSIvan T. Ivanov 171*657cbf9bSIvan T. Ivanov seq_printf(s, "function %s", fname); 172*657cbf9bSIvan T. Ivanov } 173*657cbf9bSIvan T. Ivanov 174*657cbf9bSIvan T. Ivanov static void brcmstb_pctl_dt_free_map(struct pinctrl_dev *pctldev, 175*657cbf9bSIvan T. Ivanov struct pinctrl_map *maps, 176*657cbf9bSIvan T. Ivanov unsigned int num_maps) 177*657cbf9bSIvan T. Ivanov { 178*657cbf9bSIvan T. Ivanov int i; 179*657cbf9bSIvan T. Ivanov 180*657cbf9bSIvan T. Ivanov for (i = 0; i < num_maps; i++) 181*657cbf9bSIvan T. Ivanov if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) 182*657cbf9bSIvan T. Ivanov kfree(maps[i].data.configs.configs); 183*657cbf9bSIvan T. Ivanov 184*657cbf9bSIvan T. Ivanov kfree(maps); 185*657cbf9bSIvan T. Ivanov } 186*657cbf9bSIvan T. Ivanov 187*657cbf9bSIvan T. Ivanov static const struct pinctrl_ops brcmstb_pctl_ops = { 188*657cbf9bSIvan T. Ivanov .get_groups_count = brcmstb_pctl_get_groups_count, 189*657cbf9bSIvan T. Ivanov .get_group_name = brcmstb_pctl_get_group_name, 190*657cbf9bSIvan T. Ivanov .get_group_pins = brcmstb_pctl_get_group_pins, 191*657cbf9bSIvan T. Ivanov .pin_dbg_show = brcmstb_pctl_pin_dbg_show, 192*657cbf9bSIvan T. Ivanov .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 193*657cbf9bSIvan T. Ivanov .dt_free_map = brcmstb_pctl_dt_free_map, 194*657cbf9bSIvan T. Ivanov }; 195*657cbf9bSIvan T. Ivanov 196*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_free(struct pinctrl_dev *pctldev, unsigned int offset) 197*657cbf9bSIvan T. Ivanov { 198*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 199*657cbf9bSIvan T. Ivanov 200*657cbf9bSIvan T. Ivanov /* disable by setting to GPIO */ 201*657cbf9bSIvan T. Ivanov return brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio); 202*657cbf9bSIvan T. Ivanov } 203*657cbf9bSIvan T. Ivanov 204*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_get_functions_count(struct pinctrl_dev *pctldev) 205*657cbf9bSIvan T. Ivanov { 206*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 207*657cbf9bSIvan T. Ivanov 208*657cbf9bSIvan T. Ivanov return pc->func_count; 209*657cbf9bSIvan T. Ivanov } 210*657cbf9bSIvan T. Ivanov 211*657cbf9bSIvan T. Ivanov static const char *brcmstb_pmx_get_function_name(struct pinctrl_dev *pctldev, 212*657cbf9bSIvan T. Ivanov unsigned int selector) 213*657cbf9bSIvan T. Ivanov { 214*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 215*657cbf9bSIvan T. Ivanov 216*657cbf9bSIvan T. Ivanov return (selector < pc->func_count) ? pc->func_names[selector] : NULL; 217*657cbf9bSIvan T. Ivanov } 218*657cbf9bSIvan T. Ivanov 219*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_get_function_groups(struct pinctrl_dev *pctldev, 220*657cbf9bSIvan T. Ivanov unsigned int selector, 221*657cbf9bSIvan T. Ivanov const char *const **groups, 222*657cbf9bSIvan T. Ivanov unsigned *const num_groups) 223*657cbf9bSIvan T. Ivanov { 224*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 225*657cbf9bSIvan T. Ivanov 226*657cbf9bSIvan T. Ivanov *groups = pc->gpio_groups; 227*657cbf9bSIvan T. Ivanov *num_groups = pc->pctl_desc.npins; 228*657cbf9bSIvan T. Ivanov 229*657cbf9bSIvan T. Ivanov return 0; 230*657cbf9bSIvan T. Ivanov } 231*657cbf9bSIvan T. Ivanov 232*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_set(struct pinctrl_dev *pctldev, 233*657cbf9bSIvan T. Ivanov unsigned int func_selector, 234*657cbf9bSIvan T. Ivanov unsigned int group_selector) 235*657cbf9bSIvan T. Ivanov { 236*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 237*657cbf9bSIvan T. Ivanov const struct pinctrl_desc *pctldesc = &pc->pctl_desc; 238*657cbf9bSIvan T. Ivanov const struct pinctrl_pin_desc *pindesc; 239*657cbf9bSIvan T. Ivanov 240*657cbf9bSIvan T. Ivanov if (group_selector >= pctldesc->npins) 241*657cbf9bSIvan T. Ivanov return -EINVAL; 242*657cbf9bSIvan T. Ivanov 243*657cbf9bSIvan T. Ivanov pindesc = &pctldesc->pins[group_selector]; 244*657cbf9bSIvan T. Ivanov return brcmstb_pinctrl_fsel_set(pc, pindesc->number, func_selector); 245*657cbf9bSIvan T. Ivanov } 246*657cbf9bSIvan T. Ivanov 247*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, 248*657cbf9bSIvan T. Ivanov struct pinctrl_gpio_range *range, 249*657cbf9bSIvan T. Ivanov unsigned int pin) 250*657cbf9bSIvan T. Ivanov { 251*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 252*657cbf9bSIvan T. Ivanov 253*657cbf9bSIvan T. Ivanov return brcmstb_pinctrl_fsel_set(pc, pin, pc->func_gpio); 254*657cbf9bSIvan T. Ivanov } 255*657cbf9bSIvan T. Ivanov 256*657cbf9bSIvan T. Ivanov static void brcmstb_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, 257*657cbf9bSIvan T. Ivanov struct pinctrl_gpio_range *range, 258*657cbf9bSIvan T. Ivanov unsigned int offset) 259*657cbf9bSIvan T. Ivanov { 260*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 261*657cbf9bSIvan T. Ivanov 262*657cbf9bSIvan T. Ivanov /* disable by setting to GPIO */ 263*657cbf9bSIvan T. Ivanov (void)brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio); 264*657cbf9bSIvan T. Ivanov } 265*657cbf9bSIvan T. Ivanov 266*657cbf9bSIvan T. Ivanov static bool brcmstb_pmx_function_is_gpio(struct pinctrl_dev *pctldev, 267*657cbf9bSIvan T. Ivanov unsigned int selector) 268*657cbf9bSIvan T. Ivanov { 269*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 270*657cbf9bSIvan T. Ivanov 271*657cbf9bSIvan T. Ivanov return pc->func_gpio == selector; 272*657cbf9bSIvan T. Ivanov } 273*657cbf9bSIvan T. Ivanov 274*657cbf9bSIvan T. Ivanov static const struct pinmux_ops brcmstb_pmx_ops = { 275*657cbf9bSIvan T. Ivanov .free = brcmstb_pmx_free, 276*657cbf9bSIvan T. Ivanov .get_functions_count = brcmstb_pmx_get_functions_count, 277*657cbf9bSIvan T. Ivanov .get_function_name = brcmstb_pmx_get_function_name, 278*657cbf9bSIvan T. Ivanov .get_function_groups = brcmstb_pmx_get_function_groups, 279*657cbf9bSIvan T. Ivanov .set_mux = brcmstb_pmx_set, 280*657cbf9bSIvan T. Ivanov .gpio_request_enable = brcmstb_pmx_gpio_request_enable, 281*657cbf9bSIvan T. Ivanov .gpio_disable_free = brcmstb_pmx_gpio_disable_free, 282*657cbf9bSIvan T. Ivanov .function_is_gpio = brcmstb_pmx_function_is_gpio, 283*657cbf9bSIvan T. Ivanov .strict = true, 284*657cbf9bSIvan T. Ivanov }; 285*657cbf9bSIvan T. Ivanov 286*657cbf9bSIvan T. Ivanov static unsigned int brcmstb_pull_config_get(struct brcmstb_pinctrl *pc, 287*657cbf9bSIvan T. Ivanov unsigned int pin) 288*657cbf9bSIvan T. Ivanov { 289*657cbf9bSIvan T. Ivanov u32 bit = pc->pin_regs[pin].pad_bit, val; 290*657cbf9bSIvan T. Ivanov 291*657cbf9bSIvan T. Ivanov if (bit == PAD_BIT_INVALID) 292*657cbf9bSIvan T. Ivanov return BRCMSTB_PULL_NONE; 293*657cbf9bSIvan T. Ivanov 294*657cbf9bSIvan T. Ivanov val = readl(pc->base + BIT_TO_REG(bit)); 295*657cbf9bSIvan T. Ivanov return (val >> BIT_TO_SHIFT(bit)) & BRCMSTB_PULL_MASK; 296*657cbf9bSIvan T. Ivanov } 297*657cbf9bSIvan T. Ivanov 298*657cbf9bSIvan T. Ivanov static int brcmstb_pull_config_set(struct brcmstb_pinctrl *pc, 299*657cbf9bSIvan T. Ivanov unsigned int pin, unsigned int arg) 300*657cbf9bSIvan T. Ivanov { 301*657cbf9bSIvan T. Ivanov u32 bit = pc->pin_regs[pin].pad_bit, val; 302*657cbf9bSIvan T. Ivanov 303*657cbf9bSIvan T. Ivanov if (bit == PAD_BIT_INVALID) { 304*657cbf9bSIvan T. Ivanov dev_warn(pc->dev, "Can't set pulls for %s\n", 305*657cbf9bSIvan T. Ivanov pc->gpio_groups[pin]); 306*657cbf9bSIvan T. Ivanov return -EINVAL; 307*657cbf9bSIvan T. Ivanov } 308*657cbf9bSIvan T. Ivanov 309*657cbf9bSIvan T. Ivanov guard(spinlock_irqsave)(&pc->fsel_lock); 310*657cbf9bSIvan T. Ivanov 311*657cbf9bSIvan T. Ivanov val = readl(pc->base + BIT_TO_REG(bit)); 312*657cbf9bSIvan T. Ivanov val &= ~(BRCMSTB_PULL_MASK << BIT_TO_SHIFT(bit)); 313*657cbf9bSIvan T. Ivanov val |= (arg << BIT_TO_SHIFT(bit)); 314*657cbf9bSIvan T. Ivanov writel(val, pc->base + BIT_TO_REG(bit)); 315*657cbf9bSIvan T. Ivanov 316*657cbf9bSIvan T. Ivanov return 0; 317*657cbf9bSIvan T. Ivanov } 318*657cbf9bSIvan T. Ivanov 319*657cbf9bSIvan T. Ivanov static int brcmstb_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, 320*657cbf9bSIvan T. Ivanov unsigned long *config) 321*657cbf9bSIvan T. Ivanov { 322*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 323*657cbf9bSIvan T. Ivanov enum pin_config_param param = pinconf_to_config_param(*config); 324*657cbf9bSIvan T. Ivanov u32 arg; 325*657cbf9bSIvan T. Ivanov 326*657cbf9bSIvan T. Ivanov switch (param) { 327*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE: 328*657cbf9bSIvan T. Ivanov arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_NONE); 329*657cbf9bSIvan T. Ivanov break; 330*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN: 331*657cbf9bSIvan T. Ivanov arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_DOWN); 332*657cbf9bSIvan T. Ivanov break; 333*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP: 334*657cbf9bSIvan T. Ivanov arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_UP); 335*657cbf9bSIvan T. Ivanov break; 336*657cbf9bSIvan T. Ivanov default: 337*657cbf9bSIvan T. Ivanov return -ENOTSUPP; 338*657cbf9bSIvan T. Ivanov } 339*657cbf9bSIvan T. Ivanov 340*657cbf9bSIvan T. Ivanov *config = pinconf_to_config_packed(param, arg); 341*657cbf9bSIvan T. Ivanov 342*657cbf9bSIvan T. Ivanov return 0; 343*657cbf9bSIvan T. Ivanov } 344*657cbf9bSIvan T. Ivanov 345*657cbf9bSIvan T. Ivanov static int brcmstb_pinconf_set(struct pinctrl_dev *pctldev, 346*657cbf9bSIvan T. Ivanov unsigned int pin, unsigned long *configs, 347*657cbf9bSIvan T. Ivanov unsigned int num_configs) 348*657cbf9bSIvan T. Ivanov { 349*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 350*657cbf9bSIvan T. Ivanov int ret = 0; 351*657cbf9bSIvan T. Ivanov u32 param; 352*657cbf9bSIvan T. Ivanov int i; 353*657cbf9bSIvan T. Ivanov 354*657cbf9bSIvan T. Ivanov for (i = 0; i < num_configs; i++) { 355*657cbf9bSIvan T. Ivanov param = pinconf_to_config_param(configs[i]); 356*657cbf9bSIvan T. Ivanov 357*657cbf9bSIvan T. Ivanov switch (param) { 358*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE: 359*657cbf9bSIvan T. Ivanov ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_NONE); 360*657cbf9bSIvan T. Ivanov break; 361*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN: 362*657cbf9bSIvan T. Ivanov ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_DOWN); 363*657cbf9bSIvan T. Ivanov break; 364*657cbf9bSIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP: 365*657cbf9bSIvan T. Ivanov ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_UP); 366*657cbf9bSIvan T. Ivanov break; 367*657cbf9bSIvan T. Ivanov default: 368*657cbf9bSIvan T. Ivanov return -ENOTSUPP; 369*657cbf9bSIvan T. Ivanov } 370*657cbf9bSIvan T. Ivanov } 371*657cbf9bSIvan T. Ivanov 372*657cbf9bSIvan T. Ivanov return ret; 373*657cbf9bSIvan T. Ivanov } 374*657cbf9bSIvan T. Ivanov 375*657cbf9bSIvan T. Ivanov static const struct pinconf_ops brcmstb_pinconf_ops = { 376*657cbf9bSIvan T. Ivanov .is_generic = true, 377*657cbf9bSIvan T. Ivanov .pin_config_get = brcmstb_pinconf_get, 378*657cbf9bSIvan T. Ivanov .pin_config_set = brcmstb_pinconf_set, 379*657cbf9bSIvan T. Ivanov }; 380*657cbf9bSIvan T. Ivanov 381*657cbf9bSIvan T. Ivanov int brcmstb_pinctrl_probe(struct platform_device *pdev) 382*657cbf9bSIvan T. Ivanov { 383*657cbf9bSIvan T. Ivanov struct device *dev = &pdev->dev; 384*657cbf9bSIvan T. Ivanov struct device_node *np = dev->of_node; 385*657cbf9bSIvan T. Ivanov const struct brcmstb_pdata *pdata; 386*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl *pc; 387*657cbf9bSIvan T. Ivanov const char **names; 388*657cbf9bSIvan T. Ivanov int num_pins, i; 389*657cbf9bSIvan T. Ivanov 390*657cbf9bSIvan T. Ivanov pdata = of_device_get_match_data(dev); 391*657cbf9bSIvan T. Ivanov 392*657cbf9bSIvan T. Ivanov pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); 393*657cbf9bSIvan T. Ivanov if (!pc) 394*657cbf9bSIvan T. Ivanov return -ENOMEM; 395*657cbf9bSIvan T. Ivanov 396*657cbf9bSIvan T. Ivanov platform_set_drvdata(pdev, pc); 397*657cbf9bSIvan T. Ivanov pc->dev = dev; 398*657cbf9bSIvan T. Ivanov spin_lock_init(&pc->fsel_lock); 399*657cbf9bSIvan T. Ivanov 400*657cbf9bSIvan T. Ivanov pc->base = devm_of_iomap(dev, np, 0, NULL); 401*657cbf9bSIvan T. Ivanov if (IS_ERR(pc->base)) 402*657cbf9bSIvan T. Ivanov return dev_err_probe(&pdev->dev, PTR_ERR(pc->base), 403*657cbf9bSIvan T. Ivanov "Could not get IO memory\n"); 404*657cbf9bSIvan T. Ivanov 405*657cbf9bSIvan T. Ivanov pc->pctl_desc = *pdata->pctl_desc; 406*657cbf9bSIvan T. Ivanov pc->pctl_desc.pctlops = &brcmstb_pctl_ops; 407*657cbf9bSIvan T. Ivanov pc->pctl_desc.pmxops = &brcmstb_pmx_ops; 408*657cbf9bSIvan T. Ivanov pc->pctl_desc.confops = &brcmstb_pinconf_ops; 409*657cbf9bSIvan T. Ivanov pc->pctl_desc.owner = THIS_MODULE; 410*657cbf9bSIvan T. Ivanov num_pins = pc->pctl_desc.npins; 411*657cbf9bSIvan T. Ivanov names = devm_kmalloc_array(dev, num_pins, sizeof(const char *), 412*657cbf9bSIvan T. Ivanov GFP_KERNEL); 413*657cbf9bSIvan T. Ivanov if (!names) 414*657cbf9bSIvan T. Ivanov return -ENOMEM; 415*657cbf9bSIvan T. Ivanov 416*657cbf9bSIvan T. Ivanov for (i = 0; i < num_pins; i++) 417*657cbf9bSIvan T. Ivanov names[i] = pc->pctl_desc.pins[i].name; 418*657cbf9bSIvan T. Ivanov 419*657cbf9bSIvan T. Ivanov pc->gpio_groups = names; 420*657cbf9bSIvan T. Ivanov pc->pin_regs = pdata->pin_regs; 421*657cbf9bSIvan T. Ivanov pc->pin_funcs = pdata->pin_funcs; 422*657cbf9bSIvan T. Ivanov pc->func_count = pdata->func_count; 423*657cbf9bSIvan T. Ivanov pc->func_names = pdata->func_names; 424*657cbf9bSIvan T. Ivanov 425*657cbf9bSIvan T. Ivanov pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); 426*657cbf9bSIvan T. Ivanov if (IS_ERR(pc->pctl_dev)) 427*657cbf9bSIvan T. Ivanov return dev_err_probe(&pdev->dev, PTR_ERR(pc->pctl_dev), 428*657cbf9bSIvan T. Ivanov "Failed to register pinctrl device\n"); 429*657cbf9bSIvan T. Ivanov 430*657cbf9bSIvan T. Ivanov pc->gpio_range = *pdata->gpio_range; 431*657cbf9bSIvan T. Ivanov pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); 432*657cbf9bSIvan T. Ivanov 433*657cbf9bSIvan T. Ivanov return 0; 434*657cbf9bSIvan T. Ivanov } 435*657cbf9bSIvan T. Ivanov EXPORT_SYMBOL(brcmstb_pinctrl_probe); 436*657cbf9bSIvan T. Ivanov 437*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Phil Elwell"); 438*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Jonathan Bell"); 439*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov"); 440*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Andrea della Porta"); 441*657cbf9bSIvan T. Ivanov MODULE_DESCRIPTION("Broadcom brcmstb pinctrl driver"); 442*657cbf9bSIvan T. Ivanov MODULE_LICENSE("GPL"); 443