1a62c3677SStefan Wahren // SPDX-License-Identifier: GPL-2.0+ 2e1b2dc70SSimon Arlott /* 3e1b2dc70SSimon Arlott * Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO) 4e1b2dc70SSimon Arlott * 5e1b2dc70SSimon Arlott * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren 6e1b2dc70SSimon Arlott * 7e1b2dc70SSimon Arlott * This driver is inspired by: 8e1b2dc70SSimon Arlott * pinctrl-nomadik.c, please see original file for copyright information 9e1b2dc70SSimon Arlott * pinctrl-tegra.c, please see original file for copyright information 10e1b2dc70SSimon Arlott */ 11e1b2dc70SSimon Arlott 12e1b2dc70SSimon Arlott #include <linux/bitmap.h> 13e1b2dc70SSimon Arlott #include <linux/bug.h> 14e1b2dc70SSimon Arlott #include <linux/delay.h> 15e1b2dc70SSimon Arlott #include <linux/device.h> 16e1b2dc70SSimon Arlott #include <linux/err.h> 17e19a5f79SLinus Walleij #include <linux/gpio/driver.h> 18e1b2dc70SSimon Arlott #include <linux/io.h> 19e1b2dc70SSimon Arlott #include <linux/irq.h> 20e1b2dc70SSimon Arlott #include <linux/irqdesc.h> 2134f46848SPaul Gortmaker #include <linux/init.h> 22920fecc1SFlorian Fainelli #include <linux/interrupt.h> 23e1b2dc70SSimon Arlott #include <linux/of_address.h> 24e1b2dc70SSimon Arlott #include <linux/of.h> 25e1b2dc70SSimon Arlott #include <linux/of_irq.h> 26e1b2dc70SSimon Arlott #include <linux/pinctrl/consumer.h> 27e1b2dc70SSimon Arlott #include <linux/pinctrl/machine.h> 28e1b2dc70SSimon Arlott #include <linux/pinctrl/pinconf.h> 29e1b2dc70SSimon Arlott #include <linux/pinctrl/pinctrl.h> 30e1b2dc70SSimon Arlott #include <linux/pinctrl/pinmux.h> 310de70495SMatheus Castello #include <linux/pinctrl/pinconf-generic.h> 32e1b2dc70SSimon Arlott #include <linux/platform_device.h> 33e1b2dc70SSimon Arlott #include <linux/seq_file.h> 34e1b2dc70SSimon Arlott #include <linux/slab.h> 35e1b2dc70SSimon Arlott #include <linux/spinlock.h> 36e1b2dc70SSimon Arlott #include <linux/types.h> 370de70495SMatheus Castello #include <dt-bindings/pinctrl/bcm2835.h> 38e1b2dc70SSimon Arlott 39e1b2dc70SSimon Arlott #define MODULE_NAME "pinctrl-bcm2835" 40e1b2dc70SSimon Arlott #define BCM2835_NUM_GPIOS 54 41b1d84a3dSStefan Wahren #define BCM2711_NUM_GPIOS 58 42e1b2dc70SSimon Arlott #define BCM2835_NUM_BANKS 2 4300445b5dSPhil Elwell #define BCM2835_NUM_IRQS 3 44e1b2dc70SSimon Arlott 45e1b2dc70SSimon Arlott /* GPIO register offsets */ 46e1b2dc70SSimon Arlott #define GPFSEL0 0x0 /* Function Select */ 47e1b2dc70SSimon Arlott #define GPSET0 0x1c /* Pin Output Set */ 48e1b2dc70SSimon Arlott #define GPCLR0 0x28 /* Pin Output Clear */ 49e1b2dc70SSimon Arlott #define GPLEV0 0x34 /* Pin Level */ 50e1b2dc70SSimon Arlott #define GPEDS0 0x40 /* Pin Event Detect Status */ 51e1b2dc70SSimon Arlott #define GPREN0 0x4c /* Pin Rising Edge Detect Enable */ 52e1b2dc70SSimon Arlott #define GPFEN0 0x58 /* Pin Falling Edge Detect Enable */ 53e1b2dc70SSimon Arlott #define GPHEN0 0x64 /* Pin High Detect Enable */ 54e1b2dc70SSimon Arlott #define GPLEN0 0x70 /* Pin Low Detect Enable */ 55e1b2dc70SSimon Arlott #define GPAREN0 0x7c /* Pin Async Rising Edge Detect */ 56e1b2dc70SSimon Arlott #define GPAFEN0 0x88 /* Pin Async Falling Edge Detect */ 57e1b2dc70SSimon Arlott #define GPPUD 0x94 /* Pin Pull-up/down Enable */ 58e1b2dc70SSimon Arlott #define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */ 59e38a9a43SStefan Wahren #define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */ 60e1b2dc70SSimon Arlott 61e1b2dc70SSimon Arlott #define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4)) 62e1b2dc70SSimon Arlott #define FSEL_SHIFT(p) (((p) % 10) * 3) 63e1b2dc70SSimon Arlott #define GPIO_REG_OFFSET(p) ((p) / 32) 64e1b2dc70SSimon Arlott #define GPIO_REG_SHIFT(p) ((p) % 32) 65e1b2dc70SSimon Arlott 66e38a9a43SStefan Wahren #define PUD_2711_MASK 0x3 67e38a9a43SStefan Wahren #define PUD_2711_REG_OFFSET(p) ((p) / 16) 68e38a9a43SStefan Wahren #define PUD_2711_REG_SHIFT(p) (((p) % 16) * 2) 69e38a9a43SStefan Wahren 70e1b2dc70SSimon Arlott /* argument: bcm2835_pinconf_pull */ 71b40ac08fSNathan Chancellor #define BCM2835_PINCONF_PARAM_PULL (PIN_CONFIG_END + 1) 72e1b2dc70SSimon Arlott 73e38a9a43SStefan Wahren #define BCM2711_PULL_NONE 0x0 74e38a9a43SStefan Wahren #define BCM2711_PULL_UP 0x1 75e38a9a43SStefan Wahren #define BCM2711_PULL_DOWN 0x2 76e38a9a43SStefan Wahren 77e1b2dc70SSimon Arlott struct bcm2835_pinctrl { 78e1b2dc70SSimon Arlott struct device *dev; 79e1b2dc70SSimon Arlott void __iomem *base; 80920fecc1SFlorian Fainelli int *wake_irq; 81e1b2dc70SSimon Arlott 82e1b2dc70SSimon Arlott /* note: locking assumes each bank will have its own unsigned long */ 83e1b2dc70SSimon Arlott unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; 84b1d84a3dSStefan Wahren unsigned int irq_type[BCM2711_NUM_GPIOS]; 85e1b2dc70SSimon Arlott 86e1b2dc70SSimon Arlott struct pinctrl_dev *pctl_dev; 87e1b2dc70SSimon Arlott struct gpio_chip gpio_chip; 8890bfaf02SStefan Wahren struct pinctrl_desc pctl_desc; 89e1b2dc70SSimon Arlott struct pinctrl_gpio_range gpio_range; 90e1b2dc70SSimon Arlott 913c7b30f7SLukas Wunner raw_spinlock_t irq_lock[BCM2835_NUM_BANKS]; 92e1b2dc70SSimon Arlott }; 93e1b2dc70SSimon Arlott 94e1b2dc70SSimon Arlott /* pins are just named GPIO0..GPIO53 */ 95e1b2dc70SSimon Arlott #define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) 96e8ed912eSSachin Kamat static struct pinctrl_pin_desc bcm2835_gpio_pins[] = { 97e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(0), 98e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(1), 99e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(2), 100e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(3), 101e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(4), 102e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(5), 103e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(6), 104e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(7), 105e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(8), 106e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(9), 107e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(10), 108e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(11), 109e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(12), 110e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(13), 111e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(14), 112e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(15), 113e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(16), 114e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(17), 115e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(18), 116e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(19), 117e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(20), 118e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(21), 119e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(22), 120e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(23), 121e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(24), 122e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(25), 123e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(26), 124e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(27), 125e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(28), 126e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(29), 127e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(30), 128e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(31), 129e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(32), 130e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(33), 131e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(34), 132e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(35), 133e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(36), 134e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(37), 135e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(38), 136e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(39), 137e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(40), 138e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(41), 139e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(42), 140e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(43), 141e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(44), 142e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(45), 143e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(46), 144e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(47), 145e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(48), 146e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(49), 147e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(50), 148e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(51), 149e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(52), 150e1b2dc70SSimon Arlott BCM2835_GPIO_PIN(53), 151b1d84a3dSStefan Wahren BCM2835_GPIO_PIN(54), 152b1d84a3dSStefan Wahren BCM2835_GPIO_PIN(55), 153b1d84a3dSStefan Wahren BCM2835_GPIO_PIN(56), 154b1d84a3dSStefan Wahren BCM2835_GPIO_PIN(57), 155e1b2dc70SSimon Arlott }; 156e1b2dc70SSimon Arlott 157e1b2dc70SSimon Arlott /* one pin per group */ 158e1b2dc70SSimon Arlott static const char * const bcm2835_gpio_groups[] = { 159e1b2dc70SSimon Arlott "gpio0", 160e1b2dc70SSimon Arlott "gpio1", 161e1b2dc70SSimon Arlott "gpio2", 162e1b2dc70SSimon Arlott "gpio3", 163e1b2dc70SSimon Arlott "gpio4", 164e1b2dc70SSimon Arlott "gpio5", 165e1b2dc70SSimon Arlott "gpio6", 166e1b2dc70SSimon Arlott "gpio7", 167e1b2dc70SSimon Arlott "gpio8", 168e1b2dc70SSimon Arlott "gpio9", 169e1b2dc70SSimon Arlott "gpio10", 170e1b2dc70SSimon Arlott "gpio11", 171e1b2dc70SSimon Arlott "gpio12", 172e1b2dc70SSimon Arlott "gpio13", 173e1b2dc70SSimon Arlott "gpio14", 174e1b2dc70SSimon Arlott "gpio15", 175e1b2dc70SSimon Arlott "gpio16", 176e1b2dc70SSimon Arlott "gpio17", 177e1b2dc70SSimon Arlott "gpio18", 178e1b2dc70SSimon Arlott "gpio19", 179e1b2dc70SSimon Arlott "gpio20", 180e1b2dc70SSimon Arlott "gpio21", 181e1b2dc70SSimon Arlott "gpio22", 182e1b2dc70SSimon Arlott "gpio23", 183e1b2dc70SSimon Arlott "gpio24", 184e1b2dc70SSimon Arlott "gpio25", 185e1b2dc70SSimon Arlott "gpio26", 186e1b2dc70SSimon Arlott "gpio27", 187e1b2dc70SSimon Arlott "gpio28", 188e1b2dc70SSimon Arlott "gpio29", 189e1b2dc70SSimon Arlott "gpio30", 190e1b2dc70SSimon Arlott "gpio31", 191e1b2dc70SSimon Arlott "gpio32", 192e1b2dc70SSimon Arlott "gpio33", 193e1b2dc70SSimon Arlott "gpio34", 194e1b2dc70SSimon Arlott "gpio35", 195e1b2dc70SSimon Arlott "gpio36", 196e1b2dc70SSimon Arlott "gpio37", 197e1b2dc70SSimon Arlott "gpio38", 198e1b2dc70SSimon Arlott "gpio39", 199e1b2dc70SSimon Arlott "gpio40", 200e1b2dc70SSimon Arlott "gpio41", 201e1b2dc70SSimon Arlott "gpio42", 202e1b2dc70SSimon Arlott "gpio43", 203e1b2dc70SSimon Arlott "gpio44", 204e1b2dc70SSimon Arlott "gpio45", 205e1b2dc70SSimon Arlott "gpio46", 206e1b2dc70SSimon Arlott "gpio47", 207e1b2dc70SSimon Arlott "gpio48", 208e1b2dc70SSimon Arlott "gpio49", 209e1b2dc70SSimon Arlott "gpio50", 210e1b2dc70SSimon Arlott "gpio51", 211e1b2dc70SSimon Arlott "gpio52", 212e1b2dc70SSimon Arlott "gpio53", 213b1d84a3dSStefan Wahren "gpio54", 214b1d84a3dSStefan Wahren "gpio55", 215b1d84a3dSStefan Wahren "gpio56", 216b1d84a3dSStefan Wahren "gpio57", 217e1b2dc70SSimon Arlott }; 218e1b2dc70SSimon Arlott 219e1b2dc70SSimon Arlott enum bcm2835_fsel { 220e1b2dc70SSimon Arlott BCM2835_FSEL_COUNT = 8, 221e1b2dc70SSimon Arlott BCM2835_FSEL_MASK = 0x7, 222e1b2dc70SSimon Arlott }; 223e1b2dc70SSimon Arlott 224e1b2dc70SSimon Arlott static const char * const bcm2835_functions[BCM2835_FSEL_COUNT] = { 225e1b2dc70SSimon Arlott [BCM2835_FSEL_GPIO_IN] = "gpio_in", 226e1b2dc70SSimon Arlott [BCM2835_FSEL_GPIO_OUT] = "gpio_out", 227e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT0] = "alt0", 228e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT1] = "alt1", 229e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT2] = "alt2", 230e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT3] = "alt3", 231e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT4] = "alt4", 232e1b2dc70SSimon Arlott [BCM2835_FSEL_ALT5] = "alt5", 233e1b2dc70SSimon Arlott }; 234e1b2dc70SSimon Arlott 235e1b2dc70SSimon Arlott static const char * const irq_type_names[] = { 236e1b2dc70SSimon Arlott [IRQ_TYPE_NONE] = "none", 237e1b2dc70SSimon Arlott [IRQ_TYPE_EDGE_RISING] = "edge-rising", 238e1b2dc70SSimon Arlott [IRQ_TYPE_EDGE_FALLING] = "edge-falling", 239e1b2dc70SSimon Arlott [IRQ_TYPE_EDGE_BOTH] = "edge-both", 240e1b2dc70SSimon Arlott [IRQ_TYPE_LEVEL_HIGH] = "level-high", 241e1b2dc70SSimon Arlott [IRQ_TYPE_LEVEL_LOW] = "level-low", 242e1b2dc70SSimon Arlott }; 243e1b2dc70SSimon Arlott 244e1b2dc70SSimon Arlott static inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg) 245e1b2dc70SSimon Arlott { 246e1b2dc70SSimon Arlott return readl(pc->base + reg); 247e1b2dc70SSimon Arlott } 248e1b2dc70SSimon Arlott 249e1b2dc70SSimon Arlott static inline void bcm2835_gpio_wr(struct bcm2835_pinctrl *pc, unsigned reg, 250e1b2dc70SSimon Arlott u32 val) 251e1b2dc70SSimon Arlott { 252e1b2dc70SSimon Arlott writel(val, pc->base + reg); 253e1b2dc70SSimon Arlott } 254e1b2dc70SSimon Arlott 255e1b2dc70SSimon Arlott static inline int bcm2835_gpio_get_bit(struct bcm2835_pinctrl *pc, unsigned reg, 256e1b2dc70SSimon Arlott unsigned bit) 257e1b2dc70SSimon Arlott { 258e1b2dc70SSimon Arlott reg += GPIO_REG_OFFSET(bit) * 4; 259e1b2dc70SSimon Arlott return (bcm2835_gpio_rd(pc, reg) >> GPIO_REG_SHIFT(bit)) & 1; 260e1b2dc70SSimon Arlott } 261e1b2dc70SSimon Arlott 262e1b2dc70SSimon Arlott /* note NOT a read/modify/write cycle */ 263e1b2dc70SSimon Arlott static inline void bcm2835_gpio_set_bit(struct bcm2835_pinctrl *pc, 264e1b2dc70SSimon Arlott unsigned reg, unsigned bit) 265e1b2dc70SSimon Arlott { 266e1b2dc70SSimon Arlott reg += GPIO_REG_OFFSET(bit) * 4; 267e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, reg, BIT(GPIO_REG_SHIFT(bit))); 268e1b2dc70SSimon Arlott } 269e1b2dc70SSimon Arlott 270e1b2dc70SSimon Arlott static inline enum bcm2835_fsel bcm2835_pinctrl_fsel_get( 271e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc, unsigned pin) 272e1b2dc70SSimon Arlott { 273e1b2dc70SSimon Arlott u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); 274e1b2dc70SSimon Arlott enum bcm2835_fsel status = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; 275e1b2dc70SSimon Arlott 276e1b2dc70SSimon Arlott dev_dbg(pc->dev, "get %08x (%u => %s)\n", val, pin, 277e1b2dc70SSimon Arlott bcm2835_functions[status]); 278e1b2dc70SSimon Arlott 279e1b2dc70SSimon Arlott return status; 280e1b2dc70SSimon Arlott } 281e1b2dc70SSimon Arlott 282e1b2dc70SSimon Arlott static inline void bcm2835_pinctrl_fsel_set( 283e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc, unsigned pin, 284e1b2dc70SSimon Arlott enum bcm2835_fsel fsel) 285e1b2dc70SSimon Arlott { 286e1b2dc70SSimon Arlott u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); 287e1b2dc70SSimon Arlott enum bcm2835_fsel cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; 288e1b2dc70SSimon Arlott 289e1b2dc70SSimon Arlott dev_dbg(pc->dev, "read %08x (%u => %s)\n", val, pin, 290e1b2dc70SSimon Arlott bcm2835_functions[cur]); 291e1b2dc70SSimon Arlott 292e1b2dc70SSimon Arlott if (cur == fsel) 293e1b2dc70SSimon Arlott return; 294e1b2dc70SSimon Arlott 295e1b2dc70SSimon Arlott if (cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN) { 296e1b2dc70SSimon Arlott /* always transition through GPIO_IN */ 297e1b2dc70SSimon Arlott val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); 298e1b2dc70SSimon Arlott val |= BCM2835_FSEL_GPIO_IN << FSEL_SHIFT(pin); 299e1b2dc70SSimon Arlott 300e1b2dc70SSimon Arlott dev_dbg(pc->dev, "trans %08x (%u <= %s)\n", val, pin, 301e1b2dc70SSimon Arlott bcm2835_functions[BCM2835_FSEL_GPIO_IN]); 302e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, FSEL_REG(pin), val); 303e1b2dc70SSimon Arlott } 304e1b2dc70SSimon Arlott 305e1b2dc70SSimon Arlott val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); 306e1b2dc70SSimon Arlott val |= fsel << FSEL_SHIFT(pin); 307e1b2dc70SSimon Arlott 308e1b2dc70SSimon Arlott dev_dbg(pc->dev, "write %08x (%u <= %s)\n", val, pin, 309e1b2dc70SSimon Arlott bcm2835_functions[fsel]); 310e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, FSEL_REG(pin), val); 311e1b2dc70SSimon Arlott } 312e1b2dc70SSimon Arlott 313e1b2dc70SSimon Arlott static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 314e1b2dc70SSimon Arlott { 315e1b2dc70SSimon Arlott return pinctrl_gpio_direction_input(chip->base + offset); 316e1b2dc70SSimon Arlott } 317e1b2dc70SSimon Arlott 318e1b2dc70SSimon Arlott static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset) 319e1b2dc70SSimon Arlott { 320e19a5f79SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 321e1b2dc70SSimon Arlott 322e1b2dc70SSimon Arlott return bcm2835_gpio_get_bit(pc, GPLEV0, offset); 323e1b2dc70SSimon Arlott } 324e1b2dc70SSimon Arlott 32520b3d2a7SStefan Wahren static int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 32620b3d2a7SStefan Wahren { 32720b3d2a7SStefan Wahren struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 32820b3d2a7SStefan Wahren enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); 32920b3d2a7SStefan Wahren 33020b3d2a7SStefan Wahren /* Alternative function doesn't clearly provide a direction */ 33120b3d2a7SStefan Wahren if (fsel > BCM2835_FSEL_GPIO_OUT) 33220b3d2a7SStefan Wahren return -EINVAL; 33320b3d2a7SStefan Wahren 3343c827873SMatti Vaittinen if (fsel == BCM2835_FSEL_GPIO_IN) 3353c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 3363c827873SMatti Vaittinen 3373c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 33820b3d2a7SStefan Wahren } 33920b3d2a7SStefan Wahren 340e1b2dc70SSimon Arlott static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 341e1b2dc70SSimon Arlott { 342e19a5f79SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 343e1b2dc70SSimon Arlott 344e1b2dc70SSimon Arlott bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset); 345e1b2dc70SSimon Arlott } 346e1b2dc70SSimon Arlott 3474c02cba1SStefan Wahren static int bcm2835_gpio_direction_output(struct gpio_chip *chip, 3484c02cba1SStefan Wahren unsigned offset, int value) 3494c02cba1SStefan Wahren { 3504c02cba1SStefan Wahren bcm2835_gpio_set(chip, offset, value); 3514c02cba1SStefan Wahren return pinctrl_gpio_direction_output(chip->base + offset); 3524c02cba1SStefan Wahren } 3534c02cba1SStefan Wahren 354531bcf73SGustavo A. R. Silva static const struct gpio_chip bcm2835_gpio_chip = { 355e1b2dc70SSimon Arlott .label = MODULE_NAME, 356e1b2dc70SSimon Arlott .owner = THIS_MODULE, 35798c85d58SJonas Gorski .request = gpiochip_generic_request, 35898c85d58SJonas Gorski .free = gpiochip_generic_free, 359e1b2dc70SSimon Arlott .direction_input = bcm2835_gpio_direction_input, 360e1b2dc70SSimon Arlott .direction_output = bcm2835_gpio_direction_output, 36120b3d2a7SStefan Wahren .get_direction = bcm2835_gpio_get_direction, 362e1b2dc70SSimon Arlott .get = bcm2835_gpio_get, 363e1b2dc70SSimon Arlott .set = bcm2835_gpio_set, 364b6e5531cSStefan Wahren .set_config = gpiochip_generic_config, 365e1b2dc70SSimon Arlott .base = -1, 366e1b2dc70SSimon Arlott .ngpio = BCM2835_NUM_GPIOS, 3679fb1f39eSLinus Walleij .can_sleep = false, 368e1b2dc70SSimon Arlott }; 369e1b2dc70SSimon Arlott 370b1d84a3dSStefan Wahren static const struct gpio_chip bcm2711_gpio_chip = { 371b1d84a3dSStefan Wahren .label = "pinctrl-bcm2711", 372b1d84a3dSStefan Wahren .owner = THIS_MODULE, 373b1d84a3dSStefan Wahren .request = gpiochip_generic_request, 374b1d84a3dSStefan Wahren .free = gpiochip_generic_free, 375b1d84a3dSStefan Wahren .direction_input = bcm2835_gpio_direction_input, 376b1d84a3dSStefan Wahren .direction_output = bcm2835_gpio_direction_output, 377b1d84a3dSStefan Wahren .get_direction = bcm2835_gpio_get_direction, 378b1d84a3dSStefan Wahren .get = bcm2835_gpio_get, 379b1d84a3dSStefan Wahren .set = bcm2835_gpio_set, 380b1d84a3dSStefan Wahren .set_config = gpiochip_generic_config, 381b1d84a3dSStefan Wahren .base = -1, 382b1d84a3dSStefan Wahren .ngpio = BCM2711_NUM_GPIOS, 383b1d84a3dSStefan Wahren .can_sleep = false, 384b1d84a3dSStefan Wahren }; 385b1d84a3dSStefan Wahren 38685ae9e51SLinus Walleij static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, 38700445b5dSPhil Elwell unsigned int bank, u32 mask) 388e1b2dc70SSimon Arlott { 389e1b2dc70SSimon Arlott unsigned long events; 390e1b2dc70SSimon Arlott unsigned offset; 391e1b2dc70SSimon Arlott unsigned gpio; 392e1b2dc70SSimon Arlott 393e1b2dc70SSimon Arlott events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); 39400445b5dSPhil Elwell events &= mask; 395e1b2dc70SSimon Arlott events &= pc->enabled_irq_map[bank]; 396e1b2dc70SSimon Arlott for_each_set_bit(offset, &events, 32) { 397e1b2dc70SSimon Arlott gpio = (32 * bank) + offset; 3989e9355bbSLinus Walleij generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain, 39985ae9e51SLinus Walleij gpio)); 40085ae9e51SLinus Walleij } 401e1b2dc70SSimon Arlott } 40200445b5dSPhil Elwell 40385ae9e51SLinus Walleij static void bcm2835_gpio_irq_handler(struct irq_desc *desc) 40400445b5dSPhil Elwell { 40585ae9e51SLinus Walleij struct gpio_chip *chip = irq_desc_get_handler_data(desc); 40685ae9e51SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 40785ae9e51SLinus Walleij struct irq_chip *host_chip = irq_desc_get_chip(desc); 40885ae9e51SLinus Walleij int irq = irq_desc_get_irq(desc); 40985ae9e51SLinus Walleij int group; 41085ae9e51SLinus Walleij int i; 41100445b5dSPhil Elwell 41273345a18SLinus Walleij for (i = 0; i < BCM2835_NUM_IRQS; i++) { 41373345a18SLinus Walleij if (chip->irq.parents[i] == irq) { 4140d885e9dSThierry Reding group = i; 41585ae9e51SLinus Walleij break; 41685ae9e51SLinus Walleij } 41785ae9e51SLinus Walleij } 41885ae9e51SLinus Walleij /* This should not happen, every IRQ has a bank */ 41973345a18SLinus Walleij if (i == BCM2835_NUM_IRQS) 42085ae9e51SLinus Walleij BUG(); 42185ae9e51SLinus Walleij 42285ae9e51SLinus Walleij chained_irq_enter(host_chip, desc); 42385ae9e51SLinus Walleij 42485ae9e51SLinus Walleij switch (group) { 42500445b5dSPhil Elwell case 0: /* IRQ0 covers GPIOs 0-27 */ 42685ae9e51SLinus Walleij bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff); 42700445b5dSPhil Elwell break; 42800445b5dSPhil Elwell case 1: /* IRQ1 covers GPIOs 28-45 */ 42985ae9e51SLinus Walleij bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000); 43000445b5dSPhil Elwell bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff); 43100445b5dSPhil Elwell break; 432b1d84a3dSStefan Wahren case 2: /* IRQ2 covers GPIOs 46-57 */ 43385ae9e51SLinus Walleij bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000); 43400445b5dSPhil Elwell break; 43500445b5dSPhil Elwell } 43600445b5dSPhil Elwell 43785ae9e51SLinus Walleij chained_irq_exit(host_chip, desc); 438e1b2dc70SSimon Arlott } 439e1b2dc70SSimon Arlott 440920fecc1SFlorian Fainelli static irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id) 441920fecc1SFlorian Fainelli { 442920fecc1SFlorian Fainelli return IRQ_HANDLED; 443920fecc1SFlorian Fainelli } 444920fecc1SFlorian Fainelli 445e1b2dc70SSimon Arlott static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, 446e1b2dc70SSimon Arlott unsigned reg, unsigned offset, bool enable) 447e1b2dc70SSimon Arlott { 448e1b2dc70SSimon Arlott u32 value; 449e1b2dc70SSimon Arlott reg += GPIO_REG_OFFSET(offset) * 4; 450e1b2dc70SSimon Arlott value = bcm2835_gpio_rd(pc, reg); 451e1b2dc70SSimon Arlott if (enable) 452e1b2dc70SSimon Arlott value |= BIT(GPIO_REG_SHIFT(offset)); 453e1b2dc70SSimon Arlott else 454e1b2dc70SSimon Arlott value &= ~(BIT(GPIO_REG_SHIFT(offset))); 455e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, reg, value); 456e1b2dc70SSimon Arlott } 457e1b2dc70SSimon Arlott 458e1b2dc70SSimon Arlott /* fast path for IRQ handler */ 459e1b2dc70SSimon Arlott static void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, 460e1b2dc70SSimon Arlott unsigned offset, bool enable) 461e1b2dc70SSimon Arlott { 462e1b2dc70SSimon Arlott switch (pc->irq_type[offset]) { 463e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_RISING: 464e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPREN0, offset, enable); 465e1b2dc70SSimon Arlott break; 466e1b2dc70SSimon Arlott 467e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_FALLING: 468e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable); 469e1b2dc70SSimon Arlott break; 470e1b2dc70SSimon Arlott 471e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_BOTH: 472e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPREN0, offset, enable); 473e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable); 474e1b2dc70SSimon Arlott break; 475e1b2dc70SSimon Arlott 476e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_HIGH: 477e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPHEN0, offset, enable); 478e1b2dc70SSimon Arlott break; 479e1b2dc70SSimon Arlott 480e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_LOW: 481e1b2dc70SSimon Arlott __bcm2835_gpio_irq_config(pc, GPLEN0, offset, enable); 482e1b2dc70SSimon Arlott break; 483e1b2dc70SSimon Arlott } 484e1b2dc70SSimon Arlott } 485e1b2dc70SSimon Arlott 486e1b2dc70SSimon Arlott static void bcm2835_gpio_irq_enable(struct irq_data *data) 487e1b2dc70SSimon Arlott { 48885ae9e51SLinus Walleij struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 48985ae9e51SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 490e1b2dc70SSimon Arlott unsigned gpio = irqd_to_hwirq(data); 491e1b2dc70SSimon Arlott unsigned offset = GPIO_REG_SHIFT(gpio); 492e1b2dc70SSimon Arlott unsigned bank = GPIO_REG_OFFSET(gpio); 493e1b2dc70SSimon Arlott unsigned long flags; 494e1b2dc70SSimon Arlott 4953c7b30f7SLukas Wunner raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 496e1b2dc70SSimon Arlott set_bit(offset, &pc->enabled_irq_map[bank]); 497e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, gpio, true); 4983c7b30f7SLukas Wunner raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 499e1b2dc70SSimon Arlott } 500e1b2dc70SSimon Arlott 501e1b2dc70SSimon Arlott static void bcm2835_gpio_irq_disable(struct irq_data *data) 502e1b2dc70SSimon Arlott { 50385ae9e51SLinus Walleij struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 50485ae9e51SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 505e1b2dc70SSimon Arlott unsigned gpio = irqd_to_hwirq(data); 506e1b2dc70SSimon Arlott unsigned offset = GPIO_REG_SHIFT(gpio); 507e1b2dc70SSimon Arlott unsigned bank = GPIO_REG_OFFSET(gpio); 508e1b2dc70SSimon Arlott unsigned long flags; 509e1b2dc70SSimon Arlott 5103c7b30f7SLukas Wunner raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 511e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, gpio, false); 512714b1dd8SJonathan Bell /* Clear events that were latched prior to clearing event sources */ 513714b1dd8SJonathan Bell bcm2835_gpio_set_bit(pc, GPEDS0, gpio); 514e1b2dc70SSimon Arlott clear_bit(offset, &pc->enabled_irq_map[bank]); 5153c7b30f7SLukas Wunner raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 516e1b2dc70SSimon Arlott } 517e1b2dc70SSimon Arlott 518e1b2dc70SSimon Arlott static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc, 519e1b2dc70SSimon Arlott unsigned offset, unsigned int type) 520e1b2dc70SSimon Arlott { 521e1b2dc70SSimon Arlott switch (type) { 522e1b2dc70SSimon Arlott case IRQ_TYPE_NONE: 523e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_RISING: 524e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_FALLING: 525e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_BOTH: 526e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_HIGH: 527e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_LOW: 528e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 529e1b2dc70SSimon Arlott break; 530e1b2dc70SSimon Arlott 531e1b2dc70SSimon Arlott default: 532e1b2dc70SSimon Arlott return -EINVAL; 533e1b2dc70SSimon Arlott } 534e1b2dc70SSimon Arlott return 0; 535e1b2dc70SSimon Arlott } 536e1b2dc70SSimon Arlott 537e1b2dc70SSimon Arlott /* slower path for reconfiguring IRQ type */ 538e1b2dc70SSimon Arlott static int __bcm2835_gpio_irq_set_type_enabled(struct bcm2835_pinctrl *pc, 539e1b2dc70SSimon Arlott unsigned offset, unsigned int type) 540e1b2dc70SSimon Arlott { 541e1b2dc70SSimon Arlott switch (type) { 542e1b2dc70SSimon Arlott case IRQ_TYPE_NONE: 543e1b2dc70SSimon Arlott if (pc->irq_type[offset] != type) { 544e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 545e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 546e1b2dc70SSimon Arlott } 547e1b2dc70SSimon Arlott break; 548e1b2dc70SSimon Arlott 549e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_RISING: 550e1b2dc70SSimon Arlott if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) { 551e1b2dc70SSimon Arlott /* RISING already enabled, disable FALLING */ 552e1b2dc70SSimon Arlott pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING; 553e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 554e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 555e1b2dc70SSimon Arlott } else if (pc->irq_type[offset] != type) { 556e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 557e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 558e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 559e1b2dc70SSimon Arlott } 560e1b2dc70SSimon Arlott break; 561e1b2dc70SSimon Arlott 562e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_FALLING: 563e1b2dc70SSimon Arlott if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) { 564e1b2dc70SSimon Arlott /* FALLING already enabled, disable RISING */ 565e1b2dc70SSimon Arlott pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING; 566e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 567e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 568e1b2dc70SSimon Arlott } else if (pc->irq_type[offset] != type) { 569e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 570e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 571e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 572e1b2dc70SSimon Arlott } 573e1b2dc70SSimon Arlott break; 574e1b2dc70SSimon Arlott 575e1b2dc70SSimon Arlott case IRQ_TYPE_EDGE_BOTH: 576e1b2dc70SSimon Arlott if (pc->irq_type[offset] == IRQ_TYPE_EDGE_RISING) { 577e1b2dc70SSimon Arlott /* RISING already enabled, enable FALLING too */ 578e1b2dc70SSimon Arlott pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING; 579e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 580e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 581e1b2dc70SSimon Arlott } else if (pc->irq_type[offset] == IRQ_TYPE_EDGE_FALLING) { 582e1b2dc70SSimon Arlott /* FALLING already enabled, enable RISING too */ 583e1b2dc70SSimon Arlott pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING; 584e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 585e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 586e1b2dc70SSimon Arlott } else if (pc->irq_type[offset] != type) { 587e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 588e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 589e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 590e1b2dc70SSimon Arlott } 591e1b2dc70SSimon Arlott break; 592e1b2dc70SSimon Arlott 593e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_HIGH: 594e1b2dc70SSimon Arlott case IRQ_TYPE_LEVEL_LOW: 595e1b2dc70SSimon Arlott if (pc->irq_type[offset] != type) { 596e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, false); 597e1b2dc70SSimon Arlott pc->irq_type[offset] = type; 598e1b2dc70SSimon Arlott bcm2835_gpio_irq_config(pc, offset, true); 599e1b2dc70SSimon Arlott } 600e1b2dc70SSimon Arlott break; 601e1b2dc70SSimon Arlott 602e1b2dc70SSimon Arlott default: 603e1b2dc70SSimon Arlott return -EINVAL; 604e1b2dc70SSimon Arlott } 605e1b2dc70SSimon Arlott return 0; 606e1b2dc70SSimon Arlott } 607e1b2dc70SSimon Arlott 608e1b2dc70SSimon Arlott static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) 609e1b2dc70SSimon Arlott { 61085ae9e51SLinus Walleij struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 61185ae9e51SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 612e1b2dc70SSimon Arlott unsigned gpio = irqd_to_hwirq(data); 613e1b2dc70SSimon Arlott unsigned offset = GPIO_REG_SHIFT(gpio); 614e1b2dc70SSimon Arlott unsigned bank = GPIO_REG_OFFSET(gpio); 615e1b2dc70SSimon Arlott unsigned long flags; 616e1b2dc70SSimon Arlott int ret; 617e1b2dc70SSimon Arlott 6183c7b30f7SLukas Wunner raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 619e1b2dc70SSimon Arlott 620e1b2dc70SSimon Arlott if (test_bit(offset, &pc->enabled_irq_map[bank])) 621e1b2dc70SSimon Arlott ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type); 622e1b2dc70SSimon Arlott else 623e1b2dc70SSimon Arlott ret = __bcm2835_gpio_irq_set_type_disabled(pc, gpio, type); 624e1b2dc70SSimon Arlott 625b8a19382SCharles Keepax if (type & IRQ_TYPE_EDGE_BOTH) 6261aa74fd0SThomas Gleixner irq_set_handler_locked(data, handle_edge_irq); 627b8a19382SCharles Keepax else 6281aa74fd0SThomas Gleixner irq_set_handler_locked(data, handle_level_irq); 629b8a19382SCharles Keepax 6303c7b30f7SLukas Wunner raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 631e1b2dc70SSimon Arlott 632e1b2dc70SSimon Arlott return ret; 633e1b2dc70SSimon Arlott } 634e1b2dc70SSimon Arlott 635b8a19382SCharles Keepax static void bcm2835_gpio_irq_ack(struct irq_data *data) 636b8a19382SCharles Keepax { 63785ae9e51SLinus Walleij struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 63885ae9e51SLinus Walleij struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 639b8a19382SCharles Keepax unsigned gpio = irqd_to_hwirq(data); 640b8a19382SCharles Keepax 641b8a19382SCharles Keepax bcm2835_gpio_set_bit(pc, GPEDS0, gpio); 642b8a19382SCharles Keepax } 643b8a19382SCharles Keepax 644920fecc1SFlorian Fainelli static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on) 645920fecc1SFlorian Fainelli { 646920fecc1SFlorian Fainelli struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 647920fecc1SFlorian Fainelli struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 648920fecc1SFlorian Fainelli unsigned gpio = irqd_to_hwirq(data); 649920fecc1SFlorian Fainelli unsigned int irqgroup; 650920fecc1SFlorian Fainelli int ret = -EINVAL; 651920fecc1SFlorian Fainelli 652920fecc1SFlorian Fainelli if (!pc->wake_irq) 653920fecc1SFlorian Fainelli return ret; 654920fecc1SFlorian Fainelli 655920fecc1SFlorian Fainelli if (gpio <= 27) 656920fecc1SFlorian Fainelli irqgroup = 0; 657920fecc1SFlorian Fainelli else if (gpio >= 28 && gpio <= 45) 658920fecc1SFlorian Fainelli irqgroup = 1; 659920fecc1SFlorian Fainelli else if (gpio >= 46 && gpio <= 57) 660920fecc1SFlorian Fainelli irqgroup = 2; 661920fecc1SFlorian Fainelli else 662920fecc1SFlorian Fainelli return ret; 663920fecc1SFlorian Fainelli 664920fecc1SFlorian Fainelli if (on) 665920fecc1SFlorian Fainelli ret = enable_irq_wake(pc->wake_irq[irqgroup]); 666920fecc1SFlorian Fainelli else 667920fecc1SFlorian Fainelli ret = disable_irq_wake(pc->wake_irq[irqgroup]); 668920fecc1SFlorian Fainelli 669920fecc1SFlorian Fainelli return ret; 670920fecc1SFlorian Fainelli } 671920fecc1SFlorian Fainelli 672e1b2dc70SSimon Arlott static struct irq_chip bcm2835_gpio_irq_chip = { 673e1b2dc70SSimon Arlott .name = MODULE_NAME, 674e1b2dc70SSimon Arlott .irq_enable = bcm2835_gpio_irq_enable, 675e1b2dc70SSimon Arlott .irq_disable = bcm2835_gpio_irq_disable, 676e1b2dc70SSimon Arlott .irq_set_type = bcm2835_gpio_irq_set_type, 677b8a19382SCharles Keepax .irq_ack = bcm2835_gpio_irq_ack, 678b8a19382SCharles Keepax .irq_mask = bcm2835_gpio_irq_disable, 679b8a19382SCharles Keepax .irq_unmask = bcm2835_gpio_irq_enable, 680920fecc1SFlorian Fainelli .irq_set_wake = bcm2835_gpio_irq_set_wake, 681920fecc1SFlorian Fainelli .flags = IRQCHIP_MASK_ON_SUSPEND, 682e1b2dc70SSimon Arlott }; 683e1b2dc70SSimon Arlott 684e1b2dc70SSimon Arlott static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev) 685e1b2dc70SSimon Arlott { 686b1d84a3dSStefan Wahren return BCM2835_NUM_GPIOS; 687e1b2dc70SSimon Arlott } 688e1b2dc70SSimon Arlott 689e1b2dc70SSimon Arlott static const char *bcm2835_pctl_get_group_name(struct pinctrl_dev *pctldev, 690e1b2dc70SSimon Arlott unsigned selector) 691e1b2dc70SSimon Arlott { 692e1b2dc70SSimon Arlott return bcm2835_gpio_groups[selector]; 693e1b2dc70SSimon Arlott } 694e1b2dc70SSimon Arlott 695e1b2dc70SSimon Arlott static int bcm2835_pctl_get_group_pins(struct pinctrl_dev *pctldev, 696e1b2dc70SSimon Arlott unsigned selector, 697e1b2dc70SSimon Arlott const unsigned **pins, 698e1b2dc70SSimon Arlott unsigned *num_pins) 699e1b2dc70SSimon Arlott { 700e1b2dc70SSimon Arlott *pins = &bcm2835_gpio_pins[selector].number; 701e1b2dc70SSimon Arlott *num_pins = 1; 702e1b2dc70SSimon Arlott 703e1b2dc70SSimon Arlott return 0; 704e1b2dc70SSimon Arlott } 705e1b2dc70SSimon Arlott 706e1b2dc70SSimon Arlott static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, 707e1b2dc70SSimon Arlott struct seq_file *s, 708e1b2dc70SSimon Arlott unsigned offset) 709e1b2dc70SSimon Arlott { 710e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 71185ae9e51SLinus Walleij struct gpio_chip *chip = &pc->gpio_chip; 712e1b2dc70SSimon Arlott enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); 713e1b2dc70SSimon Arlott const char *fname = bcm2835_functions[fsel]; 714e1b2dc70SSimon Arlott int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset); 715f0fbe7bcSThierry Reding int irq = irq_find_mapping(chip->irq.domain, offset); 716e1b2dc70SSimon Arlott 717e1b2dc70SSimon Arlott seq_printf(s, "function %s in %s; irq %d (%s)", 718e1b2dc70SSimon Arlott fname, value ? "hi" : "lo", 719e1b2dc70SSimon Arlott irq, irq_type_names[pc->irq_type[offset]]); 720e1b2dc70SSimon Arlott } 721e1b2dc70SSimon Arlott 722e1b2dc70SSimon Arlott static void bcm2835_pctl_dt_free_map(struct pinctrl_dev *pctldev, 723e1b2dc70SSimon Arlott struct pinctrl_map *maps, unsigned num_maps) 724e1b2dc70SSimon Arlott { 725e1b2dc70SSimon Arlott int i; 726e1b2dc70SSimon Arlott 727e1b2dc70SSimon Arlott for (i = 0; i < num_maps; i++) 728e1b2dc70SSimon Arlott if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) 729e1b2dc70SSimon Arlott kfree(maps[i].data.configs.configs); 730e1b2dc70SSimon Arlott 731e1b2dc70SSimon Arlott kfree(maps); 732e1b2dc70SSimon Arlott } 733e1b2dc70SSimon Arlott 734e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map_func(struct bcm2835_pinctrl *pc, 735e1b2dc70SSimon Arlott struct device_node *np, u32 pin, u32 fnum, 736e1b2dc70SSimon Arlott struct pinctrl_map **maps) 737e1b2dc70SSimon Arlott { 738e1b2dc70SSimon Arlott struct pinctrl_map *map = *maps; 739e1b2dc70SSimon Arlott 740e1b2dc70SSimon Arlott if (fnum >= ARRAY_SIZE(bcm2835_functions)) { 741f5292d06SRob Herring dev_err(pc->dev, "%pOF: invalid brcm,function %d\n", np, fnum); 742e1b2dc70SSimon Arlott return -EINVAL; 743e1b2dc70SSimon Arlott } 744e1b2dc70SSimon Arlott 745e1b2dc70SSimon Arlott map->type = PIN_MAP_TYPE_MUX_GROUP; 746e1b2dc70SSimon Arlott map->data.mux.group = bcm2835_gpio_groups[pin]; 747e1b2dc70SSimon Arlott map->data.mux.function = bcm2835_functions[fnum]; 748e1b2dc70SSimon Arlott (*maps)++; 749e1b2dc70SSimon Arlott 750e1b2dc70SSimon Arlott return 0; 751e1b2dc70SSimon Arlott } 752e1b2dc70SSimon Arlott 753e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc, 754e1b2dc70SSimon Arlott struct device_node *np, u32 pin, u32 pull, 755e1b2dc70SSimon Arlott struct pinctrl_map **maps) 756e1b2dc70SSimon Arlott { 757e1b2dc70SSimon Arlott struct pinctrl_map *map = *maps; 758e1b2dc70SSimon Arlott unsigned long *configs; 759e1b2dc70SSimon Arlott 760e1b2dc70SSimon Arlott if (pull > 2) { 761f5292d06SRob Herring dev_err(pc->dev, "%pOF: invalid brcm,pull %d\n", np, pull); 762e1b2dc70SSimon Arlott return -EINVAL; 763e1b2dc70SSimon Arlott } 764e1b2dc70SSimon Arlott 765e1b2dc70SSimon Arlott configs = kzalloc(sizeof(*configs), GFP_KERNEL); 766e1b2dc70SSimon Arlott if (!configs) 767e1b2dc70SSimon Arlott return -ENOMEM; 7680de70495SMatheus Castello configs[0] = pinconf_to_config_packed(BCM2835_PINCONF_PARAM_PULL, pull); 769e1b2dc70SSimon Arlott 770e1b2dc70SSimon Arlott map->type = PIN_MAP_TYPE_CONFIGS_PIN; 771e1b2dc70SSimon Arlott map->data.configs.group_or_pin = bcm2835_gpio_pins[pin].name; 772e1b2dc70SSimon Arlott map->data.configs.configs = configs; 773e1b2dc70SSimon Arlott map->data.configs.num_configs = 1; 774e1b2dc70SSimon Arlott (*maps)++; 775e1b2dc70SSimon Arlott 776e1b2dc70SSimon Arlott return 0; 777e1b2dc70SSimon Arlott } 778e1b2dc70SSimon Arlott 779e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, 780e1b2dc70SSimon Arlott struct device_node *np, 7810de70495SMatheus Castello struct pinctrl_map **map, unsigned int *num_maps) 782e1b2dc70SSimon Arlott { 783e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 784e1b2dc70SSimon Arlott struct property *pins, *funcs, *pulls; 785e1b2dc70SSimon Arlott int num_pins, num_funcs, num_pulls, maps_per_pin; 786e1b2dc70SSimon Arlott struct pinctrl_map *maps, *cur_map; 787e1b2dc70SSimon Arlott int i, err; 788e1b2dc70SSimon Arlott u32 pin, func, pull; 789e1b2dc70SSimon Arlott 7900de70495SMatheus Castello /* Check for generic binding in this node */ 7910de70495SMatheus Castello err = pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps); 7920de70495SMatheus Castello if (err || *num_maps) 7930de70495SMatheus Castello return err; 7940de70495SMatheus Castello 7950de70495SMatheus Castello /* Generic binding did not find anything continue with legacy parse */ 796e1b2dc70SSimon Arlott pins = of_find_property(np, "brcm,pins", NULL); 797e1b2dc70SSimon Arlott if (!pins) { 798f5292d06SRob Herring dev_err(pc->dev, "%pOF: missing brcm,pins property\n", np); 799e1b2dc70SSimon Arlott return -EINVAL; 800e1b2dc70SSimon Arlott } 801e1b2dc70SSimon Arlott 802e1b2dc70SSimon Arlott funcs = of_find_property(np, "brcm,function", NULL); 803e1b2dc70SSimon Arlott pulls = of_find_property(np, "brcm,pull", NULL); 804e1b2dc70SSimon Arlott 805e1b2dc70SSimon Arlott if (!funcs && !pulls) { 806e1b2dc70SSimon Arlott dev_err(pc->dev, 807f5292d06SRob Herring "%pOF: neither brcm,function nor brcm,pull specified\n", 808f5292d06SRob Herring np); 809e1b2dc70SSimon Arlott return -EINVAL; 810e1b2dc70SSimon Arlott } 811e1b2dc70SSimon Arlott 812e1b2dc70SSimon Arlott num_pins = pins->length / 4; 813e1b2dc70SSimon Arlott num_funcs = funcs ? (funcs->length / 4) : 0; 814e1b2dc70SSimon Arlott num_pulls = pulls ? (pulls->length / 4) : 0; 815e1b2dc70SSimon Arlott 816e1b2dc70SSimon Arlott if (num_funcs > 1 && num_funcs != num_pins) { 817e1b2dc70SSimon Arlott dev_err(pc->dev, 818f5292d06SRob Herring "%pOF: brcm,function must have 1 or %d entries\n", 819f5292d06SRob Herring np, num_pins); 820e1b2dc70SSimon Arlott return -EINVAL; 821e1b2dc70SSimon Arlott } 822e1b2dc70SSimon Arlott 823e1b2dc70SSimon Arlott if (num_pulls > 1 && num_pulls != num_pins) { 824e1b2dc70SSimon Arlott dev_err(pc->dev, 825f5292d06SRob Herring "%pOF: brcm,pull must have 1 or %d entries\n", 826f5292d06SRob Herring np, num_pins); 827e1b2dc70SSimon Arlott return -EINVAL; 828e1b2dc70SSimon Arlott } 829e1b2dc70SSimon Arlott 830e1b2dc70SSimon Arlott maps_per_pin = 0; 831e1b2dc70SSimon Arlott if (num_funcs) 832e1b2dc70SSimon Arlott maps_per_pin++; 833e1b2dc70SSimon Arlott if (num_pulls) 834e1b2dc70SSimon Arlott maps_per_pin++; 8356396bb22SKees Cook cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps), 836e1b2dc70SSimon Arlott GFP_KERNEL); 837e1b2dc70SSimon Arlott if (!maps) 838e1b2dc70SSimon Arlott return -ENOMEM; 839e1b2dc70SSimon Arlott 840e1b2dc70SSimon Arlott for (i = 0; i < num_pins; i++) { 841ce63d6d4SStephen Warren err = of_property_read_u32_index(np, "brcm,pins", i, &pin); 842ce63d6d4SStephen Warren if (err) 843ce63d6d4SStephen Warren goto out; 844b1d84a3dSStefan Wahren if (pin >= pc->pctl_desc.npins) { 845f5292d06SRob Herring dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n", 846f5292d06SRob Herring np, pin); 847e1b2dc70SSimon Arlott err = -EINVAL; 848e1b2dc70SSimon Arlott goto out; 849e1b2dc70SSimon Arlott } 850e1b2dc70SSimon Arlott 851e1b2dc70SSimon Arlott if (num_funcs) { 852ce63d6d4SStephen Warren err = of_property_read_u32_index(np, "brcm,function", 853ce63d6d4SStephen Warren (num_funcs > 1) ? i : 0, &func); 854ce63d6d4SStephen Warren if (err) 855ce63d6d4SStephen Warren goto out; 856e1b2dc70SSimon Arlott err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin, 857e1b2dc70SSimon Arlott func, &cur_map); 858e1b2dc70SSimon Arlott if (err) 859e1b2dc70SSimon Arlott goto out; 860e1b2dc70SSimon Arlott } 861e1b2dc70SSimon Arlott if (num_pulls) { 862ce63d6d4SStephen Warren err = of_property_read_u32_index(np, "brcm,pull", 8632c7e3306SPhil Elwell (num_pulls > 1) ? i : 0, &pull); 864ce63d6d4SStephen Warren if (err) 865ce63d6d4SStephen Warren goto out; 866e1b2dc70SSimon Arlott err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin, 867e1b2dc70SSimon Arlott pull, &cur_map); 868e1b2dc70SSimon Arlott if (err) 869e1b2dc70SSimon Arlott goto out; 870e1b2dc70SSimon Arlott } 871e1b2dc70SSimon Arlott } 872e1b2dc70SSimon Arlott 873e1b2dc70SSimon Arlott *map = maps; 874e1b2dc70SSimon Arlott *num_maps = num_pins * maps_per_pin; 875e1b2dc70SSimon Arlott 876e1b2dc70SSimon Arlott return 0; 877e1b2dc70SSimon Arlott 878e1b2dc70SSimon Arlott out: 87953653c6bSStefan Wahren bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin); 880e1b2dc70SSimon Arlott return err; 881e1b2dc70SSimon Arlott } 882e1b2dc70SSimon Arlott 883022ab148SLaurent Pinchart static const struct pinctrl_ops bcm2835_pctl_ops = { 884e1b2dc70SSimon Arlott .get_groups_count = bcm2835_pctl_get_groups_count, 885e1b2dc70SSimon Arlott .get_group_name = bcm2835_pctl_get_group_name, 886e1b2dc70SSimon Arlott .get_group_pins = bcm2835_pctl_get_group_pins, 887e1b2dc70SSimon Arlott .pin_dbg_show = bcm2835_pctl_pin_dbg_show, 888e1b2dc70SSimon Arlott .dt_node_to_map = bcm2835_pctl_dt_node_to_map, 889e1b2dc70SSimon Arlott .dt_free_map = bcm2835_pctl_dt_free_map, 890e1b2dc70SSimon Arlott }; 891e1b2dc70SSimon Arlott 892ccca1ad5SPhil Elwell static int bcm2835_pmx_free(struct pinctrl_dev *pctldev, 893ccca1ad5SPhil Elwell unsigned offset) 894ccca1ad5SPhil Elwell { 895ccca1ad5SPhil Elwell struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 896ccca1ad5SPhil Elwell 897ccca1ad5SPhil Elwell /* disable by setting to GPIO_IN */ 898ccca1ad5SPhil Elwell bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); 899ccca1ad5SPhil Elwell return 0; 900ccca1ad5SPhil Elwell } 901ccca1ad5SPhil Elwell 902e1b2dc70SSimon Arlott static int bcm2835_pmx_get_functions_count(struct pinctrl_dev *pctldev) 903e1b2dc70SSimon Arlott { 904e1b2dc70SSimon Arlott return BCM2835_FSEL_COUNT; 905e1b2dc70SSimon Arlott } 906e1b2dc70SSimon Arlott 907e1b2dc70SSimon Arlott static const char *bcm2835_pmx_get_function_name(struct pinctrl_dev *pctldev, 908e1b2dc70SSimon Arlott unsigned selector) 909e1b2dc70SSimon Arlott { 910e1b2dc70SSimon Arlott return bcm2835_functions[selector]; 911e1b2dc70SSimon Arlott } 912e1b2dc70SSimon Arlott 913e1b2dc70SSimon Arlott static int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev, 914e1b2dc70SSimon Arlott unsigned selector, 915e1b2dc70SSimon Arlott const char * const **groups, 916e1b2dc70SSimon Arlott unsigned * const num_groups) 917e1b2dc70SSimon Arlott { 918e1b2dc70SSimon Arlott /* every pin can do every function */ 919e1b2dc70SSimon Arlott *groups = bcm2835_gpio_groups; 920b1d84a3dSStefan Wahren *num_groups = BCM2835_NUM_GPIOS; 921e1b2dc70SSimon Arlott 922e1b2dc70SSimon Arlott return 0; 923e1b2dc70SSimon Arlott } 924e1b2dc70SSimon Arlott 92503e9f0caSLinus Walleij static int bcm2835_pmx_set(struct pinctrl_dev *pctldev, 926e1b2dc70SSimon Arlott unsigned func_selector, 927e1b2dc70SSimon Arlott unsigned group_selector) 928e1b2dc70SSimon Arlott { 929e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 930e1b2dc70SSimon Arlott 931e1b2dc70SSimon Arlott bcm2835_pinctrl_fsel_set(pc, group_selector, func_selector); 932e1b2dc70SSimon Arlott 933e1b2dc70SSimon Arlott return 0; 934e1b2dc70SSimon Arlott } 935e1b2dc70SSimon Arlott 936e1b2dc70SSimon Arlott static void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, 937e1b2dc70SSimon Arlott struct pinctrl_gpio_range *range, 938e1b2dc70SSimon Arlott unsigned offset) 939e1b2dc70SSimon Arlott { 940e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 941e1b2dc70SSimon Arlott 942e1b2dc70SSimon Arlott /* disable by setting to GPIO_IN */ 943e1b2dc70SSimon Arlott bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); 944e1b2dc70SSimon Arlott } 945e1b2dc70SSimon Arlott 946e1b2dc70SSimon Arlott static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 947e1b2dc70SSimon Arlott struct pinctrl_gpio_range *range, 948e1b2dc70SSimon Arlott unsigned offset, 949e1b2dc70SSimon Arlott bool input) 950e1b2dc70SSimon Arlott { 951e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 952e1b2dc70SSimon Arlott enum bcm2835_fsel fsel = input ? 953e1b2dc70SSimon Arlott BCM2835_FSEL_GPIO_IN : BCM2835_FSEL_GPIO_OUT; 954e1b2dc70SSimon Arlott 955e1b2dc70SSimon Arlott bcm2835_pinctrl_fsel_set(pc, offset, fsel); 956e1b2dc70SSimon Arlott 957e1b2dc70SSimon Arlott return 0; 958e1b2dc70SSimon Arlott } 959e1b2dc70SSimon Arlott 960022ab148SLaurent Pinchart static const struct pinmux_ops bcm2835_pmx_ops = { 961ccca1ad5SPhil Elwell .free = bcm2835_pmx_free, 962e1b2dc70SSimon Arlott .get_functions_count = bcm2835_pmx_get_functions_count, 963e1b2dc70SSimon Arlott .get_function_name = bcm2835_pmx_get_function_name, 964e1b2dc70SSimon Arlott .get_function_groups = bcm2835_pmx_get_function_groups, 96503e9f0caSLinus Walleij .set_mux = bcm2835_pmx_set, 966e1b2dc70SSimon Arlott .gpio_disable_free = bcm2835_pmx_gpio_disable_free, 967e1b2dc70SSimon Arlott .gpio_set_direction = bcm2835_pmx_gpio_set_direction, 968e1b2dc70SSimon Arlott }; 969e1b2dc70SSimon Arlott 970e1b2dc70SSimon Arlott static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev, 971e1b2dc70SSimon Arlott unsigned pin, unsigned long *config) 972e1b2dc70SSimon Arlott { 973e1b2dc70SSimon Arlott /* No way to read back config in HW */ 974e1b2dc70SSimon Arlott return -ENOTSUPP; 975e1b2dc70SSimon Arlott } 976e1b2dc70SSimon Arlott 9770de70495SMatheus Castello static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc, 9780de70495SMatheus Castello unsigned int pin, unsigned int arg) 979e1b2dc70SSimon Arlott { 980e1b2dc70SSimon Arlott u32 off, bit; 981e1b2dc70SSimon Arlott 982e1b2dc70SSimon Arlott off = GPIO_REG_OFFSET(pin); 983e1b2dc70SSimon Arlott bit = GPIO_REG_SHIFT(pin); 984e1b2dc70SSimon Arlott 985e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPPUD, arg & 3); 986e1b2dc70SSimon Arlott /* 987b83bd893SStefan Wahren * BCM2835 datasheet say to wait 150 cycles, but not of what. 988b83bd893SStefan Wahren * But the VideoCore firmware delay for this operation 989b83bd893SStefan Wahren * based nearly on the same amount of VPU cycles and this clock 990b83bd893SStefan Wahren * runs at 250 MHz. 991e1b2dc70SSimon Arlott */ 992b83bd893SStefan Wahren udelay(1); 993e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit)); 994b83bd893SStefan Wahren udelay(1); 995e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0); 9960de70495SMatheus Castello } 9970de70495SMatheus Castello 9980de70495SMatheus Castello static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev, 9990de70495SMatheus Castello unsigned int pin, unsigned long *configs, 10000de70495SMatheus Castello unsigned int num_configs) 10010de70495SMatheus Castello { 10020de70495SMatheus Castello struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 10030de70495SMatheus Castello u32 param, arg; 10040de70495SMatheus Castello int i; 10050de70495SMatheus Castello 10060de70495SMatheus Castello for (i = 0; i < num_configs; i++) { 10070de70495SMatheus Castello param = pinconf_to_config_param(configs[i]); 10080de70495SMatheus Castello arg = pinconf_to_config_argument(configs[i]); 10090de70495SMatheus Castello 10100de70495SMatheus Castello switch (param) { 10110de70495SMatheus Castello /* Set legacy brcm,pull */ 10120de70495SMatheus Castello case BCM2835_PINCONF_PARAM_PULL: 10130de70495SMatheus Castello bcm2835_pull_config_set(pc, pin, arg); 10140de70495SMatheus Castello break; 10150de70495SMatheus Castello 10160de70495SMatheus Castello /* Set pull generic bindings */ 10170de70495SMatheus Castello case PIN_CONFIG_BIAS_DISABLE: 10180de70495SMatheus Castello bcm2835_pull_config_set(pc, pin, BCM2835_PUD_OFF); 10190de70495SMatheus Castello break; 10200de70495SMatheus Castello 10210de70495SMatheus Castello case PIN_CONFIG_BIAS_PULL_DOWN: 10220de70495SMatheus Castello bcm2835_pull_config_set(pc, pin, BCM2835_PUD_DOWN); 10230de70495SMatheus Castello break; 10240de70495SMatheus Castello 10250de70495SMatheus Castello case PIN_CONFIG_BIAS_PULL_UP: 10260de70495SMatheus Castello bcm2835_pull_config_set(pc, pin, BCM2835_PUD_UP); 10270de70495SMatheus Castello break; 10280de70495SMatheus Castello 102990b60552SMatheus Castello /* Set output-high or output-low */ 103090b60552SMatheus Castello case PIN_CONFIG_OUTPUT: 103190b60552SMatheus Castello bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin); 103290b60552SMatheus Castello break; 103390b60552SMatheus Castello 10340de70495SMatheus Castello default: 1035b6e5531cSStefan Wahren return -ENOTSUPP; 10360de70495SMatheus Castello 10370de70495SMatheus Castello } /* switch param type */ 103803b054e9SSherman Yin } /* for each config */ 1039e1b2dc70SSimon Arlott 1040e1b2dc70SSimon Arlott return 0; 1041e1b2dc70SSimon Arlott } 1042e1b2dc70SSimon Arlott 1043022ab148SLaurent Pinchart static const struct pinconf_ops bcm2835_pinconf_ops = { 10441cb66f08SStefan Wahren .is_generic = true, 1045e1b2dc70SSimon Arlott .pin_config_get = bcm2835_pinconf_get, 1046e1b2dc70SSimon Arlott .pin_config_set = bcm2835_pinconf_set, 1047e1b2dc70SSimon Arlott }; 1048e1b2dc70SSimon Arlott 1049e38a9a43SStefan Wahren static void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc, 1050e38a9a43SStefan Wahren unsigned int pin, unsigned int arg) 1051e38a9a43SStefan Wahren { 1052e38a9a43SStefan Wahren u32 shifter; 1053e38a9a43SStefan Wahren u32 value; 1054e38a9a43SStefan Wahren u32 off; 1055e38a9a43SStefan Wahren 1056e38a9a43SStefan Wahren off = PUD_2711_REG_OFFSET(pin); 1057e38a9a43SStefan Wahren shifter = PUD_2711_REG_SHIFT(pin); 1058e38a9a43SStefan Wahren 1059e38a9a43SStefan Wahren value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4)); 1060e38a9a43SStefan Wahren value &= ~(PUD_2711_MASK << shifter); 1061e38a9a43SStefan Wahren value |= (arg << shifter); 1062e38a9a43SStefan Wahren bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value); 1063e38a9a43SStefan Wahren } 1064e38a9a43SStefan Wahren 1065e38a9a43SStefan Wahren static int bcm2711_pinconf_set(struct pinctrl_dev *pctldev, 1066e38a9a43SStefan Wahren unsigned int pin, unsigned long *configs, 1067e38a9a43SStefan Wahren unsigned int num_configs) 1068e38a9a43SStefan Wahren { 1069e38a9a43SStefan Wahren struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 1070e38a9a43SStefan Wahren u32 param, arg; 1071e38a9a43SStefan Wahren int i; 1072e38a9a43SStefan Wahren 1073e38a9a43SStefan Wahren for (i = 0; i < num_configs; i++) { 1074e38a9a43SStefan Wahren param = pinconf_to_config_param(configs[i]); 1075e38a9a43SStefan Wahren arg = pinconf_to_config_argument(configs[i]); 1076e38a9a43SStefan Wahren 1077e38a9a43SStefan Wahren switch (param) { 1078e38a9a43SStefan Wahren /* convert legacy brcm,pull */ 1079e38a9a43SStefan Wahren case BCM2835_PINCONF_PARAM_PULL: 1080e38a9a43SStefan Wahren if (arg == BCM2835_PUD_UP) 1081e38a9a43SStefan Wahren arg = BCM2711_PULL_UP; 1082e38a9a43SStefan Wahren else if (arg == BCM2835_PUD_DOWN) 1083e38a9a43SStefan Wahren arg = BCM2711_PULL_DOWN; 1084e38a9a43SStefan Wahren else 1085e38a9a43SStefan Wahren arg = BCM2711_PULL_NONE; 1086e38a9a43SStefan Wahren 1087e38a9a43SStefan Wahren bcm2711_pull_config_set(pc, pin, arg); 1088e38a9a43SStefan Wahren break; 1089e38a9a43SStefan Wahren 1090e38a9a43SStefan Wahren /* Set pull generic bindings */ 1091e38a9a43SStefan Wahren case PIN_CONFIG_BIAS_DISABLE: 1092e38a9a43SStefan Wahren bcm2711_pull_config_set(pc, pin, BCM2711_PULL_NONE); 1093e38a9a43SStefan Wahren break; 1094e38a9a43SStefan Wahren case PIN_CONFIG_BIAS_PULL_DOWN: 1095e38a9a43SStefan Wahren bcm2711_pull_config_set(pc, pin, BCM2711_PULL_DOWN); 1096e38a9a43SStefan Wahren break; 1097e38a9a43SStefan Wahren case PIN_CONFIG_BIAS_PULL_UP: 1098e38a9a43SStefan Wahren bcm2711_pull_config_set(pc, pin, BCM2711_PULL_UP); 1099e38a9a43SStefan Wahren break; 1100e38a9a43SStefan Wahren 1101e38a9a43SStefan Wahren /* Set output-high or output-low */ 1102e38a9a43SStefan Wahren case PIN_CONFIG_OUTPUT: 1103e38a9a43SStefan Wahren bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin); 1104e38a9a43SStefan Wahren break; 1105e38a9a43SStefan Wahren 1106e38a9a43SStefan Wahren default: 1107e38a9a43SStefan Wahren return -ENOTSUPP; 1108e38a9a43SStefan Wahren } 1109e38a9a43SStefan Wahren } /* for each config */ 1110e38a9a43SStefan Wahren 1111e38a9a43SStefan Wahren return 0; 1112e38a9a43SStefan Wahren } 1113e38a9a43SStefan Wahren 1114e38a9a43SStefan Wahren static const struct pinconf_ops bcm2711_pinconf_ops = { 1115e38a9a43SStefan Wahren .is_generic = true, 1116e38a9a43SStefan Wahren .pin_config_get = bcm2835_pinconf_get, 1117e38a9a43SStefan Wahren .pin_config_set = bcm2711_pinconf_set, 1118e38a9a43SStefan Wahren }; 1119e38a9a43SStefan Wahren 112090bfaf02SStefan Wahren static const struct pinctrl_desc bcm2835_pinctrl_desc = { 1121e1b2dc70SSimon Arlott .name = MODULE_NAME, 1122e1b2dc70SSimon Arlott .pins = bcm2835_gpio_pins, 1123b1d84a3dSStefan Wahren .npins = BCM2835_NUM_GPIOS, 1124e1b2dc70SSimon Arlott .pctlops = &bcm2835_pctl_ops, 1125e1b2dc70SSimon Arlott .pmxops = &bcm2835_pmx_ops, 1126e1b2dc70SSimon Arlott .confops = &bcm2835_pinconf_ops, 1127e1b2dc70SSimon Arlott .owner = THIS_MODULE, 1128e1b2dc70SSimon Arlott }; 1129e1b2dc70SSimon Arlott 113090bfaf02SStefan Wahren static const struct pinctrl_desc bcm2711_pinctrl_desc = { 1131b1d84a3dSStefan Wahren .name = "pinctrl-bcm2711", 113290bfaf02SStefan Wahren .pins = bcm2835_gpio_pins, 1133b1d84a3dSStefan Wahren .npins = BCM2711_NUM_GPIOS, 113490bfaf02SStefan Wahren .pctlops = &bcm2835_pctl_ops, 113590bfaf02SStefan Wahren .pmxops = &bcm2835_pmx_ops, 113690bfaf02SStefan Wahren .confops = &bcm2711_pinconf_ops, 113790bfaf02SStefan Wahren .owner = THIS_MODULE, 113890bfaf02SStefan Wahren }; 113990bfaf02SStefan Wahren 114090bfaf02SStefan Wahren static const struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = { 1141e1b2dc70SSimon Arlott .name = MODULE_NAME, 1142e1b2dc70SSimon Arlott .npins = BCM2835_NUM_GPIOS, 1143e1b2dc70SSimon Arlott }; 1144e1b2dc70SSimon Arlott 1145b1d84a3dSStefan Wahren static const struct pinctrl_gpio_range bcm2711_pinctrl_gpio_range = { 1146b1d84a3dSStefan Wahren .name = "pinctrl-bcm2711", 1147b1d84a3dSStefan Wahren .npins = BCM2711_NUM_GPIOS, 1148b1d84a3dSStefan Wahren }; 1149b1d84a3dSStefan Wahren 115090bfaf02SStefan Wahren struct bcm_plat_data { 115190bfaf02SStefan Wahren const struct gpio_chip *gpio_chip; 115290bfaf02SStefan Wahren const struct pinctrl_desc *pctl_desc; 115390bfaf02SStefan Wahren const struct pinctrl_gpio_range *gpio_range; 115490bfaf02SStefan Wahren }; 115590bfaf02SStefan Wahren 115690bfaf02SStefan Wahren static const struct bcm_plat_data bcm2835_plat_data = { 115790bfaf02SStefan Wahren .gpio_chip = &bcm2835_gpio_chip, 115890bfaf02SStefan Wahren .pctl_desc = &bcm2835_pinctrl_desc, 115990bfaf02SStefan Wahren .gpio_range = &bcm2835_pinctrl_gpio_range, 116090bfaf02SStefan Wahren }; 116190bfaf02SStefan Wahren 116290bfaf02SStefan Wahren static const struct bcm_plat_data bcm2711_plat_data = { 1163b1d84a3dSStefan Wahren .gpio_chip = &bcm2711_gpio_chip, 116490bfaf02SStefan Wahren .pctl_desc = &bcm2711_pinctrl_desc, 1165b1d84a3dSStefan Wahren .gpio_range = &bcm2711_pinctrl_gpio_range, 116690bfaf02SStefan Wahren }; 116790bfaf02SStefan Wahren 1168e38a9a43SStefan Wahren static const struct of_device_id bcm2835_pinctrl_match[] = { 1169e38a9a43SStefan Wahren { 1170e38a9a43SStefan Wahren .compatible = "brcm,bcm2835-gpio", 117190bfaf02SStefan Wahren .data = &bcm2835_plat_data, 1172e38a9a43SStefan Wahren }, 1173e38a9a43SStefan Wahren { 1174e38a9a43SStefan Wahren .compatible = "brcm,bcm2711-gpio", 117590bfaf02SStefan Wahren .data = &bcm2711_plat_data, 1176e38a9a43SStefan Wahren }, 1177562c856fSFlorian Fainelli { 1178562c856fSFlorian Fainelli .compatible = "brcm,bcm7211-gpio", 1179562c856fSFlorian Fainelli .data = &bcm2711_plat_data, 1180562c856fSFlorian Fainelli }, 1181e38a9a43SStefan Wahren {} 1182e38a9a43SStefan Wahren }; 1183e38a9a43SStefan Wahren 1184150632b0SGreg Kroah-Hartman static int bcm2835_pinctrl_probe(struct platform_device *pdev) 1185e1b2dc70SSimon Arlott { 1186e1b2dc70SSimon Arlott struct device *dev = &pdev->dev; 1187e1b2dc70SSimon Arlott struct device_node *np = dev->of_node; 118890bfaf02SStefan Wahren const struct bcm_plat_data *pdata; 1189e1b2dc70SSimon Arlott struct bcm2835_pinctrl *pc; 119073345a18SLinus Walleij struct gpio_irq_chip *girq; 1191e1b2dc70SSimon Arlott struct resource iomem; 1192e1b2dc70SSimon Arlott int err, i; 1193e38a9a43SStefan Wahren const struct of_device_id *match; 1194920fecc1SFlorian Fainelli int is_7211 = 0; 1195e38a9a43SStefan Wahren 1196b1d84a3dSStefan Wahren BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS); 1197b1d84a3dSStefan Wahren BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS); 1198e1b2dc70SSimon Arlott 1199e1b2dc70SSimon Arlott pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); 1200e1b2dc70SSimon Arlott if (!pc) 1201e1b2dc70SSimon Arlott return -ENOMEM; 1202e1b2dc70SSimon Arlott 1203e1b2dc70SSimon Arlott platform_set_drvdata(pdev, pc); 1204e1b2dc70SSimon Arlott pc->dev = dev; 1205e1b2dc70SSimon Arlott 1206e1b2dc70SSimon Arlott err = of_address_to_resource(np, 0, &iomem); 1207e1b2dc70SSimon Arlott if (err) { 1208e1b2dc70SSimon Arlott dev_err(dev, "could not get IO memory\n"); 1209e1b2dc70SSimon Arlott return err; 1210e1b2dc70SSimon Arlott } 1211e1b2dc70SSimon Arlott 12129e0c1fb2SThierry Reding pc->base = devm_ioremap_resource(dev, &iomem); 12139e0c1fb2SThierry Reding if (IS_ERR(pc->base)) 12149e0c1fb2SThierry Reding return PTR_ERR(pc->base); 1215e1b2dc70SSimon Arlott 121690bfaf02SStefan Wahren match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); 121790bfaf02SStefan Wahren if (!match) 121890bfaf02SStefan Wahren return -EINVAL; 121990bfaf02SStefan Wahren 122090bfaf02SStefan Wahren pdata = match->data; 1221920fecc1SFlorian Fainelli is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio"); 122290bfaf02SStefan Wahren 122390bfaf02SStefan Wahren pc->gpio_chip = *pdata->gpio_chip; 122458383c78SLinus Walleij pc->gpio_chip.parent = dev; 1225e1b2dc70SSimon Arlott pc->gpio_chip.of_node = np; 1226e1b2dc70SSimon Arlott 1227e1b2dc70SSimon Arlott for (i = 0; i < BCM2835_NUM_BANKS; i++) { 1228e1b2dc70SSimon Arlott unsigned long events; 1229e1b2dc70SSimon Arlott unsigned offset; 1230e1b2dc70SSimon Arlott 1231e1b2dc70SSimon Arlott /* clear event detection flags */ 1232e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0); 1233e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPFEN0 + i * 4, 0); 1234e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPHEN0 + i * 4, 0); 1235e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPLEN0 + i * 4, 0); 1236e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPAREN0 + i * 4, 0); 1237e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPAFEN0 + i * 4, 0); 1238e1b2dc70SSimon Arlott 1239e1b2dc70SSimon Arlott /* clear all the events */ 1240e1b2dc70SSimon Arlott events = bcm2835_gpio_rd(pc, GPEDS0 + i * 4); 1241e1b2dc70SSimon Arlott for_each_set_bit(offset, &events, 32) 1242e1b2dc70SSimon Arlott bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset)); 1243e1b2dc70SSimon Arlott 12443c7b30f7SLukas Wunner raw_spin_lock_init(&pc->irq_lock[i]); 124500445b5dSPhil Elwell } 124600445b5dSPhil Elwell 124773345a18SLinus Walleij girq = &pc->gpio_chip.irq; 124873345a18SLinus Walleij girq->chip = &bcm2835_gpio_irq_chip; 124973345a18SLinus Walleij girq->parent_handler = bcm2835_gpio_irq_handler; 125073345a18SLinus Walleij girq->num_parents = BCM2835_NUM_IRQS; 125173345a18SLinus Walleij girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS, 125273345a18SLinus Walleij sizeof(*girq->parents), 125373345a18SLinus Walleij GFP_KERNEL); 125473345a18SLinus Walleij if (!girq->parents) 125573345a18SLinus Walleij return -ENOMEM; 1256920fecc1SFlorian Fainelli 1257920fecc1SFlorian Fainelli if (is_7211) { 1258920fecc1SFlorian Fainelli pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS, 1259920fecc1SFlorian Fainelli sizeof(*pc->wake_irq), 1260920fecc1SFlorian Fainelli GFP_KERNEL); 1261920fecc1SFlorian Fainelli if (!pc->wake_irq) 1262920fecc1SFlorian Fainelli return -ENOMEM; 1263920fecc1SFlorian Fainelli } 1264920fecc1SFlorian Fainelli 126585ae9e51SLinus Walleij /* 126685ae9e51SLinus Walleij * Use the same handler for all groups: this is necessary 126785ae9e51SLinus Walleij * since we use one gpiochip to cover all lines - the 126885ae9e51SLinus Walleij * irq handler then needs to figure out which group and 126985ae9e51SLinus Walleij * bank that was firing the IRQ and look up the per-group 127085ae9e51SLinus Walleij * and bank data. 127185ae9e51SLinus Walleij */ 1272920fecc1SFlorian Fainelli for (i = 0; i < BCM2835_NUM_IRQS; i++) { 1273920fecc1SFlorian Fainelli int len; 1274920fecc1SFlorian Fainelli char *name; 1275920fecc1SFlorian Fainelli 127673345a18SLinus Walleij girq->parents[i] = irq_of_parse_and_map(np, i); 12774bc80da5SPhil Elwell if (!is_7211) { 12784bc80da5SPhil Elwell if (!girq->parents[i]) { 12794bc80da5SPhil Elwell girq->num_parents = i; 12804bc80da5SPhil Elwell break; 12814bc80da5SPhil Elwell } 1282920fecc1SFlorian Fainelli continue; 12834bc80da5SPhil Elwell } 1284920fecc1SFlorian Fainelli /* Skip over the all banks interrupts */ 1285920fecc1SFlorian Fainelli pc->wake_irq[i] = irq_of_parse_and_map(np, i + 1286920fecc1SFlorian Fainelli BCM2835_NUM_IRQS + 1); 1287920fecc1SFlorian Fainelli 1288920fecc1SFlorian Fainelli len = strlen(dev_name(pc->dev)) + 16; 1289920fecc1SFlorian Fainelli name = devm_kzalloc(pc->dev, len, GFP_KERNEL); 1290920fecc1SFlorian Fainelli if (!name) 1291920fecc1SFlorian Fainelli return -ENOMEM; 1292920fecc1SFlorian Fainelli 1293920fecc1SFlorian Fainelli snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i); 1294920fecc1SFlorian Fainelli 1295920fecc1SFlorian Fainelli /* These are optional interrupts */ 1296920fecc1SFlorian Fainelli err = devm_request_irq(dev, pc->wake_irq[i], 1297920fecc1SFlorian Fainelli bcm2835_gpio_wake_irq_handler, 1298920fecc1SFlorian Fainelli IRQF_SHARED, name, pc); 1299920fecc1SFlorian Fainelli if (err) 1300920fecc1SFlorian Fainelli dev_warn(dev, "unable to request wake IRQ %d\n", 1301920fecc1SFlorian Fainelli pc->wake_irq[i]); 1302920fecc1SFlorian Fainelli } 1303920fecc1SFlorian Fainelli 130473345a18SLinus Walleij girq->default_type = IRQ_TYPE_NONE; 130573345a18SLinus Walleij girq->handler = handle_level_irq; 130673345a18SLinus Walleij 130773345a18SLinus Walleij err = gpiochip_add_data(&pc->gpio_chip, pc); 130873345a18SLinus Walleij if (err) { 130973345a18SLinus Walleij dev_err(dev, "could not add GPIO chip\n"); 131073345a18SLinus Walleij return err; 131185ae9e51SLinus Walleij } 131285ae9e51SLinus Walleij 131390bfaf02SStefan Wahren pc->pctl_desc = *pdata->pctl_desc; 131490bfaf02SStefan Wahren pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); 1315323de9efSMasahiro Yamada if (IS_ERR(pc->pctl_dev)) { 1316e1b2dc70SSimon Arlott gpiochip_remove(&pc->gpio_chip); 1317323de9efSMasahiro Yamada return PTR_ERR(pc->pctl_dev); 1318e1b2dc70SSimon Arlott } 1319e1b2dc70SSimon Arlott 132090bfaf02SStefan Wahren pc->gpio_range = *pdata->gpio_range; 1321e1b2dc70SSimon Arlott pc->gpio_range.base = pc->gpio_chip.base; 1322e1b2dc70SSimon Arlott pc->gpio_range.gc = &pc->gpio_chip; 1323e1b2dc70SSimon Arlott pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); 1324e1b2dc70SSimon Arlott 1325e1b2dc70SSimon Arlott return 0; 1326e1b2dc70SSimon Arlott } 1327e1b2dc70SSimon Arlott 1328e1b2dc70SSimon Arlott static struct platform_driver bcm2835_pinctrl_driver = { 1329e1b2dc70SSimon Arlott .probe = bcm2835_pinctrl_probe, 1330e1b2dc70SSimon Arlott .driver = { 1331e1b2dc70SSimon Arlott .name = MODULE_NAME, 1332e1b2dc70SSimon Arlott .of_match_table = bcm2835_pinctrl_match, 133334f46848SPaul Gortmaker .suppress_bind_attrs = true, 1334e1b2dc70SSimon Arlott }, 1335e1b2dc70SSimon Arlott }; 133634f46848SPaul Gortmaker builtin_platform_driver(bcm2835_pinctrl_driver); 1337