18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This driver is inspired by: 88c2ecf20Sopenharmony_ci * pinctrl-nomadik.c, please see original file for copyright information 98c2ecf20Sopenharmony_ci * pinctrl-tegra.c, please see original file for copyright information 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 138c2ecf20Sopenharmony_ci#include <linux/bug.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/irq.h> 208c2ecf20Sopenharmony_ci#include <linux/irqdesc.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/of_address.h> 248c2ecf20Sopenharmony_ci#include <linux/of.h> 258c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 268c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 278c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 288c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 298c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 308c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 318c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 328c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 338c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 368c2ecf20Sopenharmony_ci#include <linux/types.h> 378c2ecf20Sopenharmony_ci#include <dt-bindings/pinctrl/bcm2835.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define MODULE_NAME "pinctrl-bcm2835" 408c2ecf20Sopenharmony_ci#define BCM2835_NUM_GPIOS 54 418c2ecf20Sopenharmony_ci#define BCM2711_NUM_GPIOS 58 428c2ecf20Sopenharmony_ci#define BCM2835_NUM_BANKS 2 438c2ecf20Sopenharmony_ci#define BCM2835_NUM_IRQS 3 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* GPIO register offsets */ 468c2ecf20Sopenharmony_ci#define GPFSEL0 0x0 /* Function Select */ 478c2ecf20Sopenharmony_ci#define GPSET0 0x1c /* Pin Output Set */ 488c2ecf20Sopenharmony_ci#define GPCLR0 0x28 /* Pin Output Clear */ 498c2ecf20Sopenharmony_ci#define GPLEV0 0x34 /* Pin Level */ 508c2ecf20Sopenharmony_ci#define GPEDS0 0x40 /* Pin Event Detect Status */ 518c2ecf20Sopenharmony_ci#define GPREN0 0x4c /* Pin Rising Edge Detect Enable */ 528c2ecf20Sopenharmony_ci#define GPFEN0 0x58 /* Pin Falling Edge Detect Enable */ 538c2ecf20Sopenharmony_ci#define GPHEN0 0x64 /* Pin High Detect Enable */ 548c2ecf20Sopenharmony_ci#define GPLEN0 0x70 /* Pin Low Detect Enable */ 558c2ecf20Sopenharmony_ci#define GPAREN0 0x7c /* Pin Async Rising Edge Detect */ 568c2ecf20Sopenharmony_ci#define GPAFEN0 0x88 /* Pin Async Falling Edge Detect */ 578c2ecf20Sopenharmony_ci#define GPPUD 0x94 /* Pin Pull-up/down Enable */ 588c2ecf20Sopenharmony_ci#define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */ 598c2ecf20Sopenharmony_ci#define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4)) 628c2ecf20Sopenharmony_ci#define FSEL_SHIFT(p) (((p) % 10) * 3) 638c2ecf20Sopenharmony_ci#define GPIO_REG_OFFSET(p) ((p) / 32) 648c2ecf20Sopenharmony_ci#define GPIO_REG_SHIFT(p) ((p) % 32) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define PUD_2711_MASK 0x3 678c2ecf20Sopenharmony_ci#define PUD_2711_REG_OFFSET(p) ((p) / 16) 688c2ecf20Sopenharmony_ci#define PUD_2711_REG_SHIFT(p) (((p) % 16) * 2) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* argument: bcm2835_pinconf_pull */ 718c2ecf20Sopenharmony_ci#define BCM2835_PINCONF_PARAM_PULL (PIN_CONFIG_END + 1) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define BCM2711_PULL_NONE 0x0 748c2ecf20Sopenharmony_ci#define BCM2711_PULL_UP 0x1 758c2ecf20Sopenharmony_ci#define BCM2711_PULL_DOWN 0x2 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct bcm2835_pinctrl { 788c2ecf20Sopenharmony_ci struct device *dev; 798c2ecf20Sopenharmony_ci void __iomem *base; 808c2ecf20Sopenharmony_ci int *wake_irq; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* note: locking assumes each bank will have its own unsigned long */ 838c2ecf20Sopenharmony_ci unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; 848c2ecf20Sopenharmony_ci unsigned int irq_type[BCM2711_NUM_GPIOS]; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl_dev; 878c2ecf20Sopenharmony_ci struct gpio_chip gpio_chip; 888c2ecf20Sopenharmony_ci struct pinctrl_desc pctl_desc; 898c2ecf20Sopenharmony_ci struct pinctrl_gpio_range gpio_range; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci raw_spinlock_t irq_lock[BCM2835_NUM_BANKS]; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* pins are just named GPIO0..GPIO53 */ 958c2ecf20Sopenharmony_ci#define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a) 968c2ecf20Sopenharmony_cistatic struct pinctrl_pin_desc bcm2835_gpio_pins[] = { 978c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(0), 988c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(1), 998c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(2), 1008c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(3), 1018c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(4), 1028c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(5), 1038c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(6), 1048c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(7), 1058c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(8), 1068c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(9), 1078c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(10), 1088c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(11), 1098c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(12), 1108c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(13), 1118c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(14), 1128c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(15), 1138c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(16), 1148c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(17), 1158c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(18), 1168c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(19), 1178c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(20), 1188c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(21), 1198c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(22), 1208c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(23), 1218c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(24), 1228c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(25), 1238c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(26), 1248c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(27), 1258c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(28), 1268c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(29), 1278c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(30), 1288c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(31), 1298c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(32), 1308c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(33), 1318c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(34), 1328c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(35), 1338c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(36), 1348c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(37), 1358c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(38), 1368c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(39), 1378c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(40), 1388c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(41), 1398c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(42), 1408c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(43), 1418c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(44), 1428c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(45), 1438c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(46), 1448c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(47), 1458c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(48), 1468c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(49), 1478c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(50), 1488c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(51), 1498c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(52), 1508c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(53), 1518c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(54), 1528c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(55), 1538c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(56), 1548c2ecf20Sopenharmony_ci BCM2835_GPIO_PIN(57), 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* one pin per group */ 1588c2ecf20Sopenharmony_cistatic const char * const bcm2835_gpio_groups[] = { 1598c2ecf20Sopenharmony_ci "gpio0", 1608c2ecf20Sopenharmony_ci "gpio1", 1618c2ecf20Sopenharmony_ci "gpio2", 1628c2ecf20Sopenharmony_ci "gpio3", 1638c2ecf20Sopenharmony_ci "gpio4", 1648c2ecf20Sopenharmony_ci "gpio5", 1658c2ecf20Sopenharmony_ci "gpio6", 1668c2ecf20Sopenharmony_ci "gpio7", 1678c2ecf20Sopenharmony_ci "gpio8", 1688c2ecf20Sopenharmony_ci "gpio9", 1698c2ecf20Sopenharmony_ci "gpio10", 1708c2ecf20Sopenharmony_ci "gpio11", 1718c2ecf20Sopenharmony_ci "gpio12", 1728c2ecf20Sopenharmony_ci "gpio13", 1738c2ecf20Sopenharmony_ci "gpio14", 1748c2ecf20Sopenharmony_ci "gpio15", 1758c2ecf20Sopenharmony_ci "gpio16", 1768c2ecf20Sopenharmony_ci "gpio17", 1778c2ecf20Sopenharmony_ci "gpio18", 1788c2ecf20Sopenharmony_ci "gpio19", 1798c2ecf20Sopenharmony_ci "gpio20", 1808c2ecf20Sopenharmony_ci "gpio21", 1818c2ecf20Sopenharmony_ci "gpio22", 1828c2ecf20Sopenharmony_ci "gpio23", 1838c2ecf20Sopenharmony_ci "gpio24", 1848c2ecf20Sopenharmony_ci "gpio25", 1858c2ecf20Sopenharmony_ci "gpio26", 1868c2ecf20Sopenharmony_ci "gpio27", 1878c2ecf20Sopenharmony_ci "gpio28", 1888c2ecf20Sopenharmony_ci "gpio29", 1898c2ecf20Sopenharmony_ci "gpio30", 1908c2ecf20Sopenharmony_ci "gpio31", 1918c2ecf20Sopenharmony_ci "gpio32", 1928c2ecf20Sopenharmony_ci "gpio33", 1938c2ecf20Sopenharmony_ci "gpio34", 1948c2ecf20Sopenharmony_ci "gpio35", 1958c2ecf20Sopenharmony_ci "gpio36", 1968c2ecf20Sopenharmony_ci "gpio37", 1978c2ecf20Sopenharmony_ci "gpio38", 1988c2ecf20Sopenharmony_ci "gpio39", 1998c2ecf20Sopenharmony_ci "gpio40", 2008c2ecf20Sopenharmony_ci "gpio41", 2018c2ecf20Sopenharmony_ci "gpio42", 2028c2ecf20Sopenharmony_ci "gpio43", 2038c2ecf20Sopenharmony_ci "gpio44", 2048c2ecf20Sopenharmony_ci "gpio45", 2058c2ecf20Sopenharmony_ci "gpio46", 2068c2ecf20Sopenharmony_ci "gpio47", 2078c2ecf20Sopenharmony_ci "gpio48", 2088c2ecf20Sopenharmony_ci "gpio49", 2098c2ecf20Sopenharmony_ci "gpio50", 2108c2ecf20Sopenharmony_ci "gpio51", 2118c2ecf20Sopenharmony_ci "gpio52", 2128c2ecf20Sopenharmony_ci "gpio53", 2138c2ecf20Sopenharmony_ci "gpio54", 2148c2ecf20Sopenharmony_ci "gpio55", 2158c2ecf20Sopenharmony_ci "gpio56", 2168c2ecf20Sopenharmony_ci "gpio57", 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cienum bcm2835_fsel { 2208c2ecf20Sopenharmony_ci BCM2835_FSEL_COUNT = 8, 2218c2ecf20Sopenharmony_ci BCM2835_FSEL_MASK = 0x7, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic const char * const bcm2835_functions[BCM2835_FSEL_COUNT] = { 2258c2ecf20Sopenharmony_ci [BCM2835_FSEL_GPIO_IN] = "gpio_in", 2268c2ecf20Sopenharmony_ci [BCM2835_FSEL_GPIO_OUT] = "gpio_out", 2278c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT0] = "alt0", 2288c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT1] = "alt1", 2298c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT2] = "alt2", 2308c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT3] = "alt3", 2318c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT4] = "alt4", 2328c2ecf20Sopenharmony_ci [BCM2835_FSEL_ALT5] = "alt5", 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic const char * const irq_type_names[] = { 2368c2ecf20Sopenharmony_ci [IRQ_TYPE_NONE] = "none", 2378c2ecf20Sopenharmony_ci [IRQ_TYPE_EDGE_RISING] = "edge-rising", 2388c2ecf20Sopenharmony_ci [IRQ_TYPE_EDGE_FALLING] = "edge-falling", 2398c2ecf20Sopenharmony_ci [IRQ_TYPE_EDGE_BOTH] = "edge-both", 2408c2ecf20Sopenharmony_ci [IRQ_TYPE_LEVEL_HIGH] = "level-high", 2418c2ecf20Sopenharmony_ci [IRQ_TYPE_LEVEL_LOW] = "level-low", 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return readl(pc->base + reg); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline void bcm2835_gpio_wr(struct bcm2835_pinctrl *pc, unsigned reg, 2508c2ecf20Sopenharmony_ci u32 val) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci writel(val, pc->base + reg); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic inline int bcm2835_gpio_get_bit(struct bcm2835_pinctrl *pc, unsigned reg, 2568c2ecf20Sopenharmony_ci unsigned bit) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci reg += GPIO_REG_OFFSET(bit) * 4; 2598c2ecf20Sopenharmony_ci return (bcm2835_gpio_rd(pc, reg) >> GPIO_REG_SHIFT(bit)) & 1; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* note NOT a read/modify/write cycle */ 2638c2ecf20Sopenharmony_cistatic inline void bcm2835_gpio_set_bit(struct bcm2835_pinctrl *pc, 2648c2ecf20Sopenharmony_ci unsigned reg, unsigned bit) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci reg += GPIO_REG_OFFSET(bit) * 4; 2678c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, reg, BIT(GPIO_REG_SHIFT(bit))); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic inline enum bcm2835_fsel bcm2835_pinctrl_fsel_get( 2718c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc, unsigned pin) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); 2748c2ecf20Sopenharmony_ci enum bcm2835_fsel status = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci dev_dbg(pc->dev, "get %08x (%u => %s)\n", val, pin, 2778c2ecf20Sopenharmony_ci bcm2835_functions[status]); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return status; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic inline void bcm2835_pinctrl_fsel_set( 2838c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc, unsigned pin, 2848c2ecf20Sopenharmony_ci enum bcm2835_fsel fsel) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); 2878c2ecf20Sopenharmony_ci enum bcm2835_fsel cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci dev_dbg(pc->dev, "read %08x (%u => %s)\n", val, pin, 2908c2ecf20Sopenharmony_ci bcm2835_functions[cur]); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (cur == fsel) 2938c2ecf20Sopenharmony_ci return; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN) { 2968c2ecf20Sopenharmony_ci /* always transition through GPIO_IN */ 2978c2ecf20Sopenharmony_ci val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); 2988c2ecf20Sopenharmony_ci val |= BCM2835_FSEL_GPIO_IN << FSEL_SHIFT(pin); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci dev_dbg(pc->dev, "trans %08x (%u <= %s)\n", val, pin, 3018c2ecf20Sopenharmony_ci bcm2835_functions[BCM2835_FSEL_GPIO_IN]); 3028c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, FSEL_REG(pin), val); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); 3068c2ecf20Sopenharmony_ci val |= fsel << FSEL_SHIFT(pin); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci dev_dbg(pc->dev, "write %08x (%u <= %s)\n", val, pin, 3098c2ecf20Sopenharmony_ci bcm2835_functions[fsel]); 3108c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, FSEL_REG(pin), val); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return bcm2835_gpio_get_bit(pc, GPLEV0, offset); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 3288c2ecf20Sopenharmony_ci enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Alternative function doesn't clearly provide a direction */ 3318c2ecf20Sopenharmony_ci if (fsel > BCM2835_FSEL_GPIO_OUT) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (fsel == BCM2835_FSEL_GPIO_IN) 3358c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int bcm2835_gpio_direction_output(struct gpio_chip *chip, 3488c2ecf20Sopenharmony_ci unsigned offset, int value) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci bcm2835_gpio_set(chip, offset, value); 3518c2ecf20Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + offset); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int bcm2835_of_gpio_ranges_fallback(struct gpio_chip *gc, 3558c2ecf20Sopenharmony_ci struct device_node *np) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev = of_pinctrl_get(np); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!pctldev) 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return gpiochip_add_pin_range(gc, pinctrl_dev_get_devname(pctldev), 0, 0, 3638c2ecf20Sopenharmony_ci gc->ngpio); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct gpio_chip bcm2835_gpio_chip = { 3678c2ecf20Sopenharmony_ci .label = MODULE_NAME, 3688c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3698c2ecf20Sopenharmony_ci .request = gpiochip_generic_request, 3708c2ecf20Sopenharmony_ci .free = gpiochip_generic_free, 3718c2ecf20Sopenharmony_ci .direction_input = bcm2835_gpio_direction_input, 3728c2ecf20Sopenharmony_ci .direction_output = bcm2835_gpio_direction_output, 3738c2ecf20Sopenharmony_ci .get_direction = bcm2835_gpio_get_direction, 3748c2ecf20Sopenharmony_ci .get = bcm2835_gpio_get, 3758c2ecf20Sopenharmony_ci .set = bcm2835_gpio_set, 3768c2ecf20Sopenharmony_ci .set_config = gpiochip_generic_config, 3778c2ecf20Sopenharmony_ci .base = -1, 3788c2ecf20Sopenharmony_ci .ngpio = BCM2835_NUM_GPIOS, 3798c2ecf20Sopenharmony_ci .can_sleep = false, 3808c2ecf20Sopenharmony_ci .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback, 3818c2ecf20Sopenharmony_ci}; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic const struct gpio_chip bcm2711_gpio_chip = { 3848c2ecf20Sopenharmony_ci .label = "pinctrl-bcm2711", 3858c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3868c2ecf20Sopenharmony_ci .request = gpiochip_generic_request, 3878c2ecf20Sopenharmony_ci .free = gpiochip_generic_free, 3888c2ecf20Sopenharmony_ci .direction_input = bcm2835_gpio_direction_input, 3898c2ecf20Sopenharmony_ci .direction_output = bcm2835_gpio_direction_output, 3908c2ecf20Sopenharmony_ci .get_direction = bcm2835_gpio_get_direction, 3918c2ecf20Sopenharmony_ci .get = bcm2835_gpio_get, 3928c2ecf20Sopenharmony_ci .set = bcm2835_gpio_set, 3938c2ecf20Sopenharmony_ci .set_config = gpiochip_generic_config, 3948c2ecf20Sopenharmony_ci .base = -1, 3958c2ecf20Sopenharmony_ci .ngpio = BCM2711_NUM_GPIOS, 3968c2ecf20Sopenharmony_ci .can_sleep = false, 3978c2ecf20Sopenharmony_ci .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, 4018c2ecf20Sopenharmony_ci unsigned int bank, u32 mask) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci unsigned long events; 4048c2ecf20Sopenharmony_ci unsigned offset; 4058c2ecf20Sopenharmony_ci unsigned gpio; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); 4088c2ecf20Sopenharmony_ci events &= mask; 4098c2ecf20Sopenharmony_ci events &= pc->enabled_irq_map[bank]; 4108c2ecf20Sopenharmony_ci for_each_set_bit(offset, &events, 32) { 4118c2ecf20Sopenharmony_ci gpio = (32 * bank) + offset; 4128c2ecf20Sopenharmony_ci generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain, 4138c2ecf20Sopenharmony_ci gpio)); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_handler(struct irq_desc *desc) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_desc_get_handler_data(desc); 4208c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 4218c2ecf20Sopenharmony_ci struct irq_chip *host_chip = irq_desc_get_chip(desc); 4228c2ecf20Sopenharmony_ci int irq = irq_desc_get_irq(desc); 4238c2ecf20Sopenharmony_ci int group; 4248c2ecf20Sopenharmony_ci int i; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci for (i = 0; i < BCM2835_NUM_IRQS; i++) { 4278c2ecf20Sopenharmony_ci if (chip->irq.parents[i] == irq) { 4288c2ecf20Sopenharmony_ci group = i; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci /* This should not happen, every IRQ has a bank */ 4338c2ecf20Sopenharmony_ci if (i == BCM2835_NUM_IRQS) 4348c2ecf20Sopenharmony_ci BUG(); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci chained_irq_enter(host_chip, desc); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci switch (group) { 4398c2ecf20Sopenharmony_ci case 0: /* IRQ0 covers GPIOs 0-27 */ 4408c2ecf20Sopenharmony_ci bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case 1: /* IRQ1 covers GPIOs 28-45 */ 4438c2ecf20Sopenharmony_ci bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000); 4448c2ecf20Sopenharmony_ci bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff); 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci case 2: /* IRQ2 covers GPIOs 46-57 */ 4478c2ecf20Sopenharmony_ci bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000); 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci chained_irq_exit(host_chip, desc); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, 4608c2ecf20Sopenharmony_ci unsigned reg, unsigned offset, bool enable) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci u32 value; 4638c2ecf20Sopenharmony_ci reg += GPIO_REG_OFFSET(offset) * 4; 4648c2ecf20Sopenharmony_ci value = bcm2835_gpio_rd(pc, reg); 4658c2ecf20Sopenharmony_ci if (enable) 4668c2ecf20Sopenharmony_ci value |= BIT(GPIO_REG_SHIFT(offset)); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci value &= ~(BIT(GPIO_REG_SHIFT(offset))); 4698c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, reg, value); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* fast path for IRQ handler */ 4738c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, 4748c2ecf20Sopenharmony_ci unsigned offset, bool enable) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci switch (pc->irq_type[offset]) { 4778c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 4788c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPREN0, offset, enable); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 4828c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable); 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 4868c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPREN0, offset, enable); 4878c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 4918c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPHEN0, offset, enable); 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 4958c2ecf20Sopenharmony_ci __bcm2835_gpio_irq_config(pc, GPLEN0, offset, enable); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_enable(struct irq_data *data) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 5038c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 5048c2ecf20Sopenharmony_ci unsigned gpio = irqd_to_hwirq(data); 5058c2ecf20Sopenharmony_ci unsigned offset = GPIO_REG_SHIFT(gpio); 5068c2ecf20Sopenharmony_ci unsigned bank = GPIO_REG_OFFSET(gpio); 5078c2ecf20Sopenharmony_ci unsigned long flags; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 5108c2ecf20Sopenharmony_ci set_bit(offset, &pc->enabled_irq_map[bank]); 5118c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, gpio, true); 5128c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_disable(struct irq_data *data) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 5188c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 5198c2ecf20Sopenharmony_ci unsigned gpio = irqd_to_hwirq(data); 5208c2ecf20Sopenharmony_ci unsigned offset = GPIO_REG_SHIFT(gpio); 5218c2ecf20Sopenharmony_ci unsigned bank = GPIO_REG_OFFSET(gpio); 5228c2ecf20Sopenharmony_ci unsigned long flags; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 5258c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, gpio, false); 5268c2ecf20Sopenharmony_ci /* Clear events that were latched prior to clearing event sources */ 5278c2ecf20Sopenharmony_ci bcm2835_gpio_set_bit(pc, GPEDS0, gpio); 5288c2ecf20Sopenharmony_ci clear_bit(offset, &pc->enabled_irq_map[bank]); 5298c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc, 5338c2ecf20Sopenharmony_ci unsigned offset, unsigned int type) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci switch (type) { 5368c2ecf20Sopenharmony_ci case IRQ_TYPE_NONE: 5378c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 5388c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 5398c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 5408c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 5418c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 5428c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci default: 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* slower path for reconfiguring IRQ type */ 5528c2ecf20Sopenharmony_cistatic int __bcm2835_gpio_irq_set_type_enabled(struct bcm2835_pinctrl *pc, 5538c2ecf20Sopenharmony_ci unsigned offset, unsigned int type) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci switch (type) { 5568c2ecf20Sopenharmony_ci case IRQ_TYPE_NONE: 5578c2ecf20Sopenharmony_ci if (pc->irq_type[offset] != type) { 5588c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 5598c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 5648c2ecf20Sopenharmony_ci if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) { 5658c2ecf20Sopenharmony_ci /* RISING already enabled, disable FALLING */ 5668c2ecf20Sopenharmony_ci pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING; 5678c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 5688c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5698c2ecf20Sopenharmony_ci } else if (pc->irq_type[offset] != type) { 5708c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 5718c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5728c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci break; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 5778c2ecf20Sopenharmony_ci if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) { 5788c2ecf20Sopenharmony_ci /* FALLING already enabled, disable RISING */ 5798c2ecf20Sopenharmony_ci pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING; 5808c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 5818c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5828c2ecf20Sopenharmony_ci } else if (pc->irq_type[offset] != type) { 5838c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 5848c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5858c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 5908c2ecf20Sopenharmony_ci if (pc->irq_type[offset] == IRQ_TYPE_EDGE_RISING) { 5918c2ecf20Sopenharmony_ci /* RISING already enabled, enable FALLING too */ 5928c2ecf20Sopenharmony_ci pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING; 5938c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 5948c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 5958c2ecf20Sopenharmony_ci } else if (pc->irq_type[offset] == IRQ_TYPE_EDGE_FALLING) { 5968c2ecf20Sopenharmony_ci /* FALLING already enabled, enable RISING too */ 5978c2ecf20Sopenharmony_ci pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING; 5988c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 5998c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 6008c2ecf20Sopenharmony_ci } else if (pc->irq_type[offset] != type) { 6018c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 6028c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 6038c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 6088c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 6098c2ecf20Sopenharmony_ci if (pc->irq_type[offset] != type) { 6108c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, false); 6118c2ecf20Sopenharmony_ci pc->irq_type[offset] = type; 6128c2ecf20Sopenharmony_ci bcm2835_gpio_irq_config(pc, offset, true); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci default: 6178c2ecf20Sopenharmony_ci return -EINVAL; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 6258c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 6268c2ecf20Sopenharmony_ci unsigned gpio = irqd_to_hwirq(data); 6278c2ecf20Sopenharmony_ci unsigned offset = GPIO_REG_SHIFT(gpio); 6288c2ecf20Sopenharmony_ci unsigned bank = GPIO_REG_OFFSET(gpio); 6298c2ecf20Sopenharmony_ci unsigned long flags; 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pc->irq_lock[bank], flags); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (test_bit(offset, &pc->enabled_irq_map[bank])) 6358c2ecf20Sopenharmony_ci ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type); 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci ret = __bcm2835_gpio_irq_set_type_disabled(pc, gpio, type); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) 6408c2ecf20Sopenharmony_ci irq_set_handler_locked(data, handle_edge_irq); 6418c2ecf20Sopenharmony_ci else 6428c2ecf20Sopenharmony_ci irq_set_handler_locked(data, handle_level_irq); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return ret; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic void bcm2835_gpio_irq_ack(struct irq_data *data) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 6528c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 6538c2ecf20Sopenharmony_ci unsigned gpio = irqd_to_hwirq(data); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci bcm2835_gpio_set_bit(pc, GPEDS0, gpio); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 6618c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); 6628c2ecf20Sopenharmony_ci unsigned gpio = irqd_to_hwirq(data); 6638c2ecf20Sopenharmony_ci unsigned int irqgroup; 6648c2ecf20Sopenharmony_ci int ret = -EINVAL; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!pc->wake_irq) 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (gpio <= 27) 6708c2ecf20Sopenharmony_ci irqgroup = 0; 6718c2ecf20Sopenharmony_ci else if (gpio >= 28 && gpio <= 45) 6728c2ecf20Sopenharmony_ci irqgroup = 1; 6738c2ecf20Sopenharmony_ci else if (gpio >= 46 && gpio <= 57) 6748c2ecf20Sopenharmony_ci irqgroup = 2; 6758c2ecf20Sopenharmony_ci else 6768c2ecf20Sopenharmony_ci return ret; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (on) 6798c2ecf20Sopenharmony_ci ret = enable_irq_wake(pc->wake_irq[irqgroup]); 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci ret = disable_irq_wake(pc->wake_irq[irqgroup]); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return ret; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic struct irq_chip bcm2835_gpio_irq_chip = { 6878c2ecf20Sopenharmony_ci .name = MODULE_NAME, 6888c2ecf20Sopenharmony_ci .irq_enable = bcm2835_gpio_irq_enable, 6898c2ecf20Sopenharmony_ci .irq_disable = bcm2835_gpio_irq_disable, 6908c2ecf20Sopenharmony_ci .irq_set_type = bcm2835_gpio_irq_set_type, 6918c2ecf20Sopenharmony_ci .irq_ack = bcm2835_gpio_irq_ack, 6928c2ecf20Sopenharmony_ci .irq_mask = bcm2835_gpio_irq_disable, 6938c2ecf20Sopenharmony_ci .irq_unmask = bcm2835_gpio_irq_enable, 6948c2ecf20Sopenharmony_ci .irq_set_wake = bcm2835_gpio_irq_set_wake, 6958c2ecf20Sopenharmony_ci .flags = IRQCHIP_MASK_ON_SUSPEND, 6968c2ecf20Sopenharmony_ci}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci return BCM2835_NUM_GPIOS; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic const char *bcm2835_pctl_get_group_name(struct pinctrl_dev *pctldev, 7048c2ecf20Sopenharmony_ci unsigned selector) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci return bcm2835_gpio_groups[selector]; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int bcm2835_pctl_get_group_pins(struct pinctrl_dev *pctldev, 7108c2ecf20Sopenharmony_ci unsigned selector, 7118c2ecf20Sopenharmony_ci const unsigned **pins, 7128c2ecf20Sopenharmony_ci unsigned *num_pins) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci *pins = &bcm2835_gpio_pins[selector].number; 7158c2ecf20Sopenharmony_ci *num_pins = 1; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, 7218c2ecf20Sopenharmony_ci struct seq_file *s, 7228c2ecf20Sopenharmony_ci unsigned offset) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 7258c2ecf20Sopenharmony_ci struct gpio_chip *chip = &pc->gpio_chip; 7268c2ecf20Sopenharmony_ci enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset); 7278c2ecf20Sopenharmony_ci const char *fname = bcm2835_functions[fsel]; 7288c2ecf20Sopenharmony_ci int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset); 7298c2ecf20Sopenharmony_ci int irq = irq_find_mapping(chip->irq.domain, offset); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci seq_printf(s, "function %s in %s; irq %d (%s)", 7328c2ecf20Sopenharmony_ci fname, value ? "hi" : "lo", 7338c2ecf20Sopenharmony_ci irq, irq_type_names[pc->irq_type[offset]]); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic void bcm2835_pctl_dt_free_map(struct pinctrl_dev *pctldev, 7378c2ecf20Sopenharmony_ci struct pinctrl_map *maps, unsigned num_maps) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci int i; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci for (i = 0; i < num_maps; i++) 7428c2ecf20Sopenharmony_ci if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) 7438c2ecf20Sopenharmony_ci kfree(maps[i].data.configs.configs); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci kfree(maps); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic int bcm2835_pctl_dt_node_to_map_func(struct bcm2835_pinctrl *pc, 7498c2ecf20Sopenharmony_ci struct device_node *np, u32 pin, u32 fnum, 7508c2ecf20Sopenharmony_ci struct pinctrl_map **maps) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct pinctrl_map *map = *maps; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (fnum >= ARRAY_SIZE(bcm2835_functions)) { 7558c2ecf20Sopenharmony_ci dev_err(pc->dev, "%pOF: invalid brcm,function %d\n", np, fnum); 7568c2ecf20Sopenharmony_ci return -EINVAL; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci map->type = PIN_MAP_TYPE_MUX_GROUP; 7608c2ecf20Sopenharmony_ci map->data.mux.group = bcm2835_gpio_groups[pin]; 7618c2ecf20Sopenharmony_ci map->data.mux.function = bcm2835_functions[fnum]; 7628c2ecf20Sopenharmony_ci (*maps)++; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc, 7688c2ecf20Sopenharmony_ci struct device_node *np, u32 pin, u32 pull, 7698c2ecf20Sopenharmony_ci struct pinctrl_map **maps) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct pinctrl_map *map = *maps; 7728c2ecf20Sopenharmony_ci unsigned long *configs; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (pull > 2) { 7758c2ecf20Sopenharmony_ci dev_err(pc->dev, "%pOF: invalid brcm,pull %d\n", np, pull); 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci configs = kzalloc(sizeof(*configs), GFP_KERNEL); 7808c2ecf20Sopenharmony_ci if (!configs) 7818c2ecf20Sopenharmony_ci return -ENOMEM; 7828c2ecf20Sopenharmony_ci configs[0] = pinconf_to_config_packed(BCM2835_PINCONF_PARAM_PULL, pull); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci map->type = PIN_MAP_TYPE_CONFIGS_PIN; 7858c2ecf20Sopenharmony_ci map->data.configs.group_or_pin = bcm2835_gpio_pins[pin].name; 7868c2ecf20Sopenharmony_ci map->data.configs.configs = configs; 7878c2ecf20Sopenharmony_ci map->data.configs.num_configs = 1; 7888c2ecf20Sopenharmony_ci (*maps)++; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, 7948c2ecf20Sopenharmony_ci struct device_node *np, 7958c2ecf20Sopenharmony_ci struct pinctrl_map **map, unsigned int *num_maps) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 7988c2ecf20Sopenharmony_ci struct property *pins, *funcs, *pulls; 7998c2ecf20Sopenharmony_ci int num_pins, num_funcs, num_pulls, maps_per_pin; 8008c2ecf20Sopenharmony_ci struct pinctrl_map *maps, *cur_map; 8018c2ecf20Sopenharmony_ci int i, err; 8028c2ecf20Sopenharmony_ci u32 pin, func, pull; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Check for generic binding in this node */ 8058c2ecf20Sopenharmony_ci err = pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps); 8068c2ecf20Sopenharmony_ci if (err || *num_maps) 8078c2ecf20Sopenharmony_ci return err; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Generic binding did not find anything continue with legacy parse */ 8108c2ecf20Sopenharmony_ci pins = of_find_property(np, "brcm,pins", NULL); 8118c2ecf20Sopenharmony_ci if (!pins) { 8128c2ecf20Sopenharmony_ci dev_err(pc->dev, "%pOF: missing brcm,pins property\n", np); 8138c2ecf20Sopenharmony_ci return -EINVAL; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci funcs = of_find_property(np, "brcm,function", NULL); 8178c2ecf20Sopenharmony_ci pulls = of_find_property(np, "brcm,pull", NULL); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (!funcs && !pulls) { 8208c2ecf20Sopenharmony_ci dev_err(pc->dev, 8218c2ecf20Sopenharmony_ci "%pOF: neither brcm,function nor brcm,pull specified\n", 8228c2ecf20Sopenharmony_ci np); 8238c2ecf20Sopenharmony_ci return -EINVAL; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci num_pins = pins->length / 4; 8278c2ecf20Sopenharmony_ci num_funcs = funcs ? (funcs->length / 4) : 0; 8288c2ecf20Sopenharmony_ci num_pulls = pulls ? (pulls->length / 4) : 0; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (num_funcs > 1 && num_funcs != num_pins) { 8318c2ecf20Sopenharmony_ci dev_err(pc->dev, 8328c2ecf20Sopenharmony_ci "%pOF: brcm,function must have 1 or %d entries\n", 8338c2ecf20Sopenharmony_ci np, num_pins); 8348c2ecf20Sopenharmony_ci return -EINVAL; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (num_pulls > 1 && num_pulls != num_pins) { 8388c2ecf20Sopenharmony_ci dev_err(pc->dev, 8398c2ecf20Sopenharmony_ci "%pOF: brcm,pull must have 1 or %d entries\n", 8408c2ecf20Sopenharmony_ci np, num_pins); 8418c2ecf20Sopenharmony_ci return -EINVAL; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci maps_per_pin = 0; 8458c2ecf20Sopenharmony_ci if (num_funcs) 8468c2ecf20Sopenharmony_ci maps_per_pin++; 8478c2ecf20Sopenharmony_ci if (num_pulls) 8488c2ecf20Sopenharmony_ci maps_per_pin++; 8498c2ecf20Sopenharmony_ci cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps), 8508c2ecf20Sopenharmony_ci GFP_KERNEL); 8518c2ecf20Sopenharmony_ci if (!maps) 8528c2ecf20Sopenharmony_ci return -ENOMEM; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 8558c2ecf20Sopenharmony_ci err = of_property_read_u32_index(np, "brcm,pins", i, &pin); 8568c2ecf20Sopenharmony_ci if (err) 8578c2ecf20Sopenharmony_ci goto out; 8588c2ecf20Sopenharmony_ci if (pin >= pc->pctl_desc.npins) { 8598c2ecf20Sopenharmony_ci dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n", 8608c2ecf20Sopenharmony_ci np, pin); 8618c2ecf20Sopenharmony_ci err = -EINVAL; 8628c2ecf20Sopenharmony_ci goto out; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (num_funcs) { 8668c2ecf20Sopenharmony_ci err = of_property_read_u32_index(np, "brcm,function", 8678c2ecf20Sopenharmony_ci (num_funcs > 1) ? i : 0, &func); 8688c2ecf20Sopenharmony_ci if (err) 8698c2ecf20Sopenharmony_ci goto out; 8708c2ecf20Sopenharmony_ci err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin, 8718c2ecf20Sopenharmony_ci func, &cur_map); 8728c2ecf20Sopenharmony_ci if (err) 8738c2ecf20Sopenharmony_ci goto out; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci if (num_pulls) { 8768c2ecf20Sopenharmony_ci err = of_property_read_u32_index(np, "brcm,pull", 8778c2ecf20Sopenharmony_ci (num_pulls > 1) ? i : 0, &pull); 8788c2ecf20Sopenharmony_ci if (err) 8798c2ecf20Sopenharmony_ci goto out; 8808c2ecf20Sopenharmony_ci err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin, 8818c2ecf20Sopenharmony_ci pull, &cur_map); 8828c2ecf20Sopenharmony_ci if (err) 8838c2ecf20Sopenharmony_ci goto out; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci *map = maps; 8888c2ecf20Sopenharmony_ci *num_maps = num_pins * maps_per_pin; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ciout: 8938c2ecf20Sopenharmony_ci bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin); 8948c2ecf20Sopenharmony_ci return err; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic const struct pinctrl_ops bcm2835_pctl_ops = { 8988c2ecf20Sopenharmony_ci .get_groups_count = bcm2835_pctl_get_groups_count, 8998c2ecf20Sopenharmony_ci .get_group_name = bcm2835_pctl_get_group_name, 9008c2ecf20Sopenharmony_ci .get_group_pins = bcm2835_pctl_get_group_pins, 9018c2ecf20Sopenharmony_ci .pin_dbg_show = bcm2835_pctl_pin_dbg_show, 9028c2ecf20Sopenharmony_ci .dt_node_to_map = bcm2835_pctl_dt_node_to_map, 9038c2ecf20Sopenharmony_ci .dt_free_map = bcm2835_pctl_dt_free_map, 9048c2ecf20Sopenharmony_ci}; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int bcm2835_pmx_free(struct pinctrl_dev *pctldev, 9078c2ecf20Sopenharmony_ci unsigned offset) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* disable by setting to GPIO_IN */ 9128c2ecf20Sopenharmony_ci bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int bcm2835_pmx_get_functions_count(struct pinctrl_dev *pctldev) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci return BCM2835_FSEL_COUNT; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic const char *bcm2835_pmx_get_function_name(struct pinctrl_dev *pctldev, 9228c2ecf20Sopenharmony_ci unsigned selector) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci return bcm2835_functions[selector]; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev, 9288c2ecf20Sopenharmony_ci unsigned selector, 9298c2ecf20Sopenharmony_ci const char * const **groups, 9308c2ecf20Sopenharmony_ci unsigned * const num_groups) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci /* every pin can do every function */ 9338c2ecf20Sopenharmony_ci *groups = bcm2835_gpio_groups; 9348c2ecf20Sopenharmony_ci *num_groups = BCM2835_NUM_GPIOS; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic int bcm2835_pmx_set(struct pinctrl_dev *pctldev, 9408c2ecf20Sopenharmony_ci unsigned func_selector, 9418c2ecf20Sopenharmony_ci unsigned group_selector) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci bcm2835_pinctrl_fsel_set(pc, group_selector, func_selector); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, 9518c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 9528c2ecf20Sopenharmony_ci unsigned offset) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* disable by setting to GPIO_IN */ 9578c2ecf20Sopenharmony_ci bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 9618c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 9628c2ecf20Sopenharmony_ci unsigned offset, 9638c2ecf20Sopenharmony_ci bool input) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 9668c2ecf20Sopenharmony_ci enum bcm2835_fsel fsel = input ? 9678c2ecf20Sopenharmony_ci BCM2835_FSEL_GPIO_IN : BCM2835_FSEL_GPIO_OUT; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci bcm2835_pinctrl_fsel_set(pc, offset, fsel); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic const struct pinmux_ops bcm2835_pmx_ops = { 9758c2ecf20Sopenharmony_ci .free = bcm2835_pmx_free, 9768c2ecf20Sopenharmony_ci .get_functions_count = bcm2835_pmx_get_functions_count, 9778c2ecf20Sopenharmony_ci .get_function_name = bcm2835_pmx_get_function_name, 9788c2ecf20Sopenharmony_ci .get_function_groups = bcm2835_pmx_get_function_groups, 9798c2ecf20Sopenharmony_ci .set_mux = bcm2835_pmx_set, 9808c2ecf20Sopenharmony_ci .gpio_disable_free = bcm2835_pmx_gpio_disable_free, 9818c2ecf20Sopenharmony_ci .gpio_set_direction = bcm2835_pmx_gpio_set_direction, 9828c2ecf20Sopenharmony_ci}; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic int bcm2835_pinconf_get(struct pinctrl_dev *pctldev, 9858c2ecf20Sopenharmony_ci unsigned pin, unsigned long *config) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci /* No way to read back config in HW */ 9888c2ecf20Sopenharmony_ci return -ENOTSUPP; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc, 9928c2ecf20Sopenharmony_ci unsigned int pin, unsigned int arg) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci u32 off, bit; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci off = GPIO_REG_OFFSET(pin); 9978c2ecf20Sopenharmony_ci bit = GPIO_REG_SHIFT(pin); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPPUD, arg & 3); 10008c2ecf20Sopenharmony_ci /* 10018c2ecf20Sopenharmony_ci * BCM2835 datasheet say to wait 150 cycles, but not of what. 10028c2ecf20Sopenharmony_ci * But the VideoCore firmware delay for this operation 10038c2ecf20Sopenharmony_ci * based nearly on the same amount of VPU cycles and this clock 10048c2ecf20Sopenharmony_ci * runs at 250 MHz. 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_ci udelay(1); 10078c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit)); 10088c2ecf20Sopenharmony_ci udelay(1); 10098c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int bcm2835_pinconf_set(struct pinctrl_dev *pctldev, 10138c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *configs, 10148c2ecf20Sopenharmony_ci unsigned int num_configs) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 10178c2ecf20Sopenharmony_ci u32 param, arg; 10188c2ecf20Sopenharmony_ci int i; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 10218c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 10228c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci switch (param) { 10258c2ecf20Sopenharmony_ci /* Set legacy brcm,pull */ 10268c2ecf20Sopenharmony_ci case BCM2835_PINCONF_PARAM_PULL: 10278c2ecf20Sopenharmony_ci bcm2835_pull_config_set(pc, pin, arg); 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Set pull generic bindings */ 10318c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 10328c2ecf20Sopenharmony_ci bcm2835_pull_config_set(pc, pin, BCM2835_PUD_OFF); 10338c2ecf20Sopenharmony_ci break; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 10368c2ecf20Sopenharmony_ci bcm2835_pull_config_set(pc, pin, BCM2835_PUD_DOWN); 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 10408c2ecf20Sopenharmony_ci bcm2835_pull_config_set(pc, pin, BCM2835_PUD_UP); 10418c2ecf20Sopenharmony_ci break; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Set output-high or output-low */ 10448c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 10458c2ecf20Sopenharmony_ci bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin); 10468c2ecf20Sopenharmony_ci break; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci default: 10498c2ecf20Sopenharmony_ci return -ENOTSUPP; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci } /* switch param type */ 10528c2ecf20Sopenharmony_ci } /* for each config */ 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic const struct pinconf_ops bcm2835_pinconf_ops = { 10588c2ecf20Sopenharmony_ci .is_generic = true, 10598c2ecf20Sopenharmony_ci .pin_config_get = bcm2835_pinconf_get, 10608c2ecf20Sopenharmony_ci .pin_config_set = bcm2835_pinconf_set, 10618c2ecf20Sopenharmony_ci}; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_cistatic void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc, 10648c2ecf20Sopenharmony_ci unsigned int pin, unsigned int arg) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci u32 shifter; 10678c2ecf20Sopenharmony_ci u32 value; 10688c2ecf20Sopenharmony_ci u32 off; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci off = PUD_2711_REG_OFFSET(pin); 10718c2ecf20Sopenharmony_ci shifter = PUD_2711_REG_SHIFT(pin); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4)); 10748c2ecf20Sopenharmony_ci value &= ~(PUD_2711_MASK << shifter); 10758c2ecf20Sopenharmony_ci value |= (arg << shifter); 10768c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic int bcm2711_pinconf_set(struct pinctrl_dev *pctldev, 10808c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *configs, 10818c2ecf20Sopenharmony_ci unsigned int num_configs) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); 10848c2ecf20Sopenharmony_ci u32 param, arg; 10858c2ecf20Sopenharmony_ci int i; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 10888c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 10898c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci switch (param) { 10928c2ecf20Sopenharmony_ci /* convert legacy brcm,pull */ 10938c2ecf20Sopenharmony_ci case BCM2835_PINCONF_PARAM_PULL: 10948c2ecf20Sopenharmony_ci if (arg == BCM2835_PUD_UP) 10958c2ecf20Sopenharmony_ci arg = BCM2711_PULL_UP; 10968c2ecf20Sopenharmony_ci else if (arg == BCM2835_PUD_DOWN) 10978c2ecf20Sopenharmony_ci arg = BCM2711_PULL_DOWN; 10988c2ecf20Sopenharmony_ci else 10998c2ecf20Sopenharmony_ci arg = BCM2711_PULL_NONE; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci bcm2711_pull_config_set(pc, pin, arg); 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Set pull generic bindings */ 11058c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 11068c2ecf20Sopenharmony_ci bcm2711_pull_config_set(pc, pin, BCM2711_PULL_NONE); 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 11098c2ecf20Sopenharmony_ci bcm2711_pull_config_set(pc, pin, BCM2711_PULL_DOWN); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 11128c2ecf20Sopenharmony_ci bcm2711_pull_config_set(pc, pin, BCM2711_PULL_UP); 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* Set output-high or output-low */ 11168c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 11178c2ecf20Sopenharmony_ci bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin); 11188c2ecf20Sopenharmony_ci break; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci default: 11218c2ecf20Sopenharmony_ci return -ENOTSUPP; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci } /* for each config */ 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci return 0; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic const struct pinconf_ops bcm2711_pinconf_ops = { 11298c2ecf20Sopenharmony_ci .is_generic = true, 11308c2ecf20Sopenharmony_ci .pin_config_get = bcm2835_pinconf_get, 11318c2ecf20Sopenharmony_ci .pin_config_set = bcm2711_pinconf_set, 11328c2ecf20Sopenharmony_ci}; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic const struct pinctrl_desc bcm2835_pinctrl_desc = { 11358c2ecf20Sopenharmony_ci .name = MODULE_NAME, 11368c2ecf20Sopenharmony_ci .pins = bcm2835_gpio_pins, 11378c2ecf20Sopenharmony_ci .npins = BCM2835_NUM_GPIOS, 11388c2ecf20Sopenharmony_ci .pctlops = &bcm2835_pctl_ops, 11398c2ecf20Sopenharmony_ci .pmxops = &bcm2835_pmx_ops, 11408c2ecf20Sopenharmony_ci .confops = &bcm2835_pinconf_ops, 11418c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11428c2ecf20Sopenharmony_ci}; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic const struct pinctrl_desc bcm2711_pinctrl_desc = { 11458c2ecf20Sopenharmony_ci .name = "pinctrl-bcm2711", 11468c2ecf20Sopenharmony_ci .pins = bcm2835_gpio_pins, 11478c2ecf20Sopenharmony_ci .npins = BCM2711_NUM_GPIOS, 11488c2ecf20Sopenharmony_ci .pctlops = &bcm2835_pctl_ops, 11498c2ecf20Sopenharmony_ci .pmxops = &bcm2835_pmx_ops, 11508c2ecf20Sopenharmony_ci .confops = &bcm2711_pinconf_ops, 11518c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11528c2ecf20Sopenharmony_ci}; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cistatic const struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = { 11558c2ecf20Sopenharmony_ci .name = MODULE_NAME, 11568c2ecf20Sopenharmony_ci .npins = BCM2835_NUM_GPIOS, 11578c2ecf20Sopenharmony_ci}; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic const struct pinctrl_gpio_range bcm2711_pinctrl_gpio_range = { 11608c2ecf20Sopenharmony_ci .name = "pinctrl-bcm2711", 11618c2ecf20Sopenharmony_ci .npins = BCM2711_NUM_GPIOS, 11628c2ecf20Sopenharmony_ci}; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistruct bcm_plat_data { 11658c2ecf20Sopenharmony_ci const struct gpio_chip *gpio_chip; 11668c2ecf20Sopenharmony_ci const struct pinctrl_desc *pctl_desc; 11678c2ecf20Sopenharmony_ci const struct pinctrl_gpio_range *gpio_range; 11688c2ecf20Sopenharmony_ci}; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic const struct bcm_plat_data bcm2835_plat_data = { 11718c2ecf20Sopenharmony_ci .gpio_chip = &bcm2835_gpio_chip, 11728c2ecf20Sopenharmony_ci .pctl_desc = &bcm2835_pinctrl_desc, 11738c2ecf20Sopenharmony_ci .gpio_range = &bcm2835_pinctrl_gpio_range, 11748c2ecf20Sopenharmony_ci}; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic const struct bcm_plat_data bcm2711_plat_data = { 11778c2ecf20Sopenharmony_ci .gpio_chip = &bcm2711_gpio_chip, 11788c2ecf20Sopenharmony_ci .pctl_desc = &bcm2711_pinctrl_desc, 11798c2ecf20Sopenharmony_ci .gpio_range = &bcm2711_pinctrl_gpio_range, 11808c2ecf20Sopenharmony_ci}; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic const struct of_device_id bcm2835_pinctrl_match[] = { 11838c2ecf20Sopenharmony_ci { 11848c2ecf20Sopenharmony_ci .compatible = "brcm,bcm2835-gpio", 11858c2ecf20Sopenharmony_ci .data = &bcm2835_plat_data, 11868c2ecf20Sopenharmony_ci }, 11878c2ecf20Sopenharmony_ci { 11888c2ecf20Sopenharmony_ci .compatible = "brcm,bcm2711-gpio", 11898c2ecf20Sopenharmony_ci .data = &bcm2711_plat_data, 11908c2ecf20Sopenharmony_ci }, 11918c2ecf20Sopenharmony_ci { 11928c2ecf20Sopenharmony_ci .compatible = "brcm,bcm7211-gpio", 11938c2ecf20Sopenharmony_ci .data = &bcm2711_plat_data, 11948c2ecf20Sopenharmony_ci }, 11958c2ecf20Sopenharmony_ci {} 11968c2ecf20Sopenharmony_ci}; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int bcm2835_pinctrl_probe(struct platform_device *pdev) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12018c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 12028c2ecf20Sopenharmony_ci const struct bcm_plat_data *pdata; 12038c2ecf20Sopenharmony_ci struct bcm2835_pinctrl *pc; 12048c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 12058c2ecf20Sopenharmony_ci struct resource iomem; 12068c2ecf20Sopenharmony_ci int err, i; 12078c2ecf20Sopenharmony_ci const struct of_device_id *match; 12088c2ecf20Sopenharmony_ci int is_7211 = 0; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS); 12118c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); 12148c2ecf20Sopenharmony_ci if (!pc) 12158c2ecf20Sopenharmony_ci return -ENOMEM; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pc); 12188c2ecf20Sopenharmony_ci pc->dev = dev; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci err = of_address_to_resource(np, 0, &iomem); 12218c2ecf20Sopenharmony_ci if (err) { 12228c2ecf20Sopenharmony_ci dev_err(dev, "could not get IO memory\n"); 12238c2ecf20Sopenharmony_ci return err; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci pc->base = devm_ioremap_resource(dev, &iomem); 12278c2ecf20Sopenharmony_ci if (IS_ERR(pc->base)) 12288c2ecf20Sopenharmony_ci return PTR_ERR(pc->base); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); 12318c2ecf20Sopenharmony_ci if (!match) 12328c2ecf20Sopenharmony_ci return -EINVAL; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci pdata = match->data; 12358c2ecf20Sopenharmony_ci is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio"); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci pc->gpio_chip = *pdata->gpio_chip; 12388c2ecf20Sopenharmony_ci pc->gpio_chip.parent = dev; 12398c2ecf20Sopenharmony_ci pc->gpio_chip.of_node = np; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci for (i = 0; i < BCM2835_NUM_BANKS; i++) { 12428c2ecf20Sopenharmony_ci unsigned long events; 12438c2ecf20Sopenharmony_ci unsigned offset; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* clear event detection flags */ 12468c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0); 12478c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPFEN0 + i * 4, 0); 12488c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPHEN0 + i * 4, 0); 12498c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPLEN0 + i * 4, 0); 12508c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPAREN0 + i * 4, 0); 12518c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPAFEN0 + i * 4, 0); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* clear all the events */ 12548c2ecf20Sopenharmony_ci events = bcm2835_gpio_rd(pc, GPEDS0 + i * 4); 12558c2ecf20Sopenharmony_ci for_each_set_bit(offset, &events, 32) 12568c2ecf20Sopenharmony_ci bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset)); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci raw_spin_lock_init(&pc->irq_lock[i]); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci pc->pctl_desc = *pdata->pctl_desc; 12628c2ecf20Sopenharmony_ci pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); 12638c2ecf20Sopenharmony_ci if (IS_ERR(pc->pctl_dev)) { 12648c2ecf20Sopenharmony_ci gpiochip_remove(&pc->gpio_chip); 12658c2ecf20Sopenharmony_ci return PTR_ERR(pc->pctl_dev); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci pc->gpio_range = *pdata->gpio_range; 12698c2ecf20Sopenharmony_ci pc->gpio_range.base = pc->gpio_chip.base; 12708c2ecf20Sopenharmony_ci pc->gpio_range.gc = &pc->gpio_chip; 12718c2ecf20Sopenharmony_ci pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci girq = &pc->gpio_chip.irq; 12748c2ecf20Sopenharmony_ci girq->chip = &bcm2835_gpio_irq_chip; 12758c2ecf20Sopenharmony_ci girq->parent_handler = bcm2835_gpio_irq_handler; 12768c2ecf20Sopenharmony_ci girq->num_parents = BCM2835_NUM_IRQS; 12778c2ecf20Sopenharmony_ci girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS, 12788c2ecf20Sopenharmony_ci sizeof(*girq->parents), 12798c2ecf20Sopenharmony_ci GFP_KERNEL); 12808c2ecf20Sopenharmony_ci if (!girq->parents) { 12818c2ecf20Sopenharmony_ci err = -ENOMEM; 12828c2ecf20Sopenharmony_ci goto out_remove; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (is_7211) { 12868c2ecf20Sopenharmony_ci pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS, 12878c2ecf20Sopenharmony_ci sizeof(*pc->wake_irq), 12888c2ecf20Sopenharmony_ci GFP_KERNEL); 12898c2ecf20Sopenharmony_ci if (!pc->wake_irq) { 12908c2ecf20Sopenharmony_ci err = -ENOMEM; 12918c2ecf20Sopenharmony_ci goto out_remove; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* 12968c2ecf20Sopenharmony_ci * Use the same handler for all groups: this is necessary 12978c2ecf20Sopenharmony_ci * since we use one gpiochip to cover all lines - the 12988c2ecf20Sopenharmony_ci * irq handler then needs to figure out which group and 12998c2ecf20Sopenharmony_ci * bank that was firing the IRQ and look up the per-group 13008c2ecf20Sopenharmony_ci * and bank data. 13018c2ecf20Sopenharmony_ci */ 13028c2ecf20Sopenharmony_ci for (i = 0; i < BCM2835_NUM_IRQS; i++) { 13038c2ecf20Sopenharmony_ci int len; 13048c2ecf20Sopenharmony_ci char *name; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci girq->parents[i] = irq_of_parse_and_map(np, i); 13078c2ecf20Sopenharmony_ci if (!is_7211) 13088c2ecf20Sopenharmony_ci continue; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* Skip over the all banks interrupts */ 13118c2ecf20Sopenharmony_ci pc->wake_irq[i] = irq_of_parse_and_map(np, i + 13128c2ecf20Sopenharmony_ci BCM2835_NUM_IRQS + 1); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci len = strlen(dev_name(pc->dev)) + 16; 13158c2ecf20Sopenharmony_ci name = devm_kzalloc(pc->dev, len, GFP_KERNEL); 13168c2ecf20Sopenharmony_ci if (!name) { 13178c2ecf20Sopenharmony_ci err = -ENOMEM; 13188c2ecf20Sopenharmony_ci goto out_remove; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* These are optional interrupts */ 13248c2ecf20Sopenharmony_ci err = devm_request_irq(dev, pc->wake_irq[i], 13258c2ecf20Sopenharmony_ci bcm2835_gpio_wake_irq_handler, 13268c2ecf20Sopenharmony_ci IRQF_SHARED, name, pc); 13278c2ecf20Sopenharmony_ci if (err) 13288c2ecf20Sopenharmony_ci dev_warn(dev, "unable to request wake IRQ %d\n", 13298c2ecf20Sopenharmony_ci pc->wake_irq[i]); 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 13338c2ecf20Sopenharmony_ci girq->handler = handle_level_irq; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci err = gpiochip_add_data(&pc->gpio_chip, pc); 13368c2ecf20Sopenharmony_ci if (err) { 13378c2ecf20Sopenharmony_ci dev_err(dev, "could not add GPIO chip\n"); 13388c2ecf20Sopenharmony_ci goto out_remove; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci return 0; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ciout_remove: 13448c2ecf20Sopenharmony_ci pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range); 13458c2ecf20Sopenharmony_ci return err; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic struct platform_driver bcm2835_pinctrl_driver = { 13498c2ecf20Sopenharmony_ci .probe = bcm2835_pinctrl_probe, 13508c2ecf20Sopenharmony_ci .driver = { 13518c2ecf20Sopenharmony_ci .name = MODULE_NAME, 13528c2ecf20Sopenharmony_ci .of_match_table = bcm2835_pinctrl_match, 13538c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 13548c2ecf20Sopenharmony_ci }, 13558c2ecf20Sopenharmony_ci}; 13568c2ecf20Sopenharmony_cibuiltin_platform_driver(bcm2835_pinctrl_driver); 1357