Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio/sifive: Add GPIO driver for SiFive SoCs

Adds the GPIO driver for SiFive RISC-V SoCs.

Signed-off-by: Wesley W. Terpstra <wesley@sifive.com>
[Atish: Various fixes and code cleanup]
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Signed-off-by: Yash Shah <yash.shah@sifive.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/1575976274-13487-6-git-send-email-yash.shah@sifive.com

authored by

Yash Shah and committed by
Marc Zyngier
96868dce 7875f824

+262
+9
drivers/gpio/Kconfig
··· 479 479 The difference from regular GPIOs is that they 480 480 maintain their value during backup/self-refresh. 481 481 482 + config GPIO_SIFIVE 483 + bool "SiFive GPIO support" 484 + depends on OF_GPIO && IRQ_DOMAIN_HIERARCHY 485 + select GPIO_GENERIC 486 + select GPIOLIB_IRQCHIP 487 + select REGMAP_MMIO 488 + help 489 + Say yes here to support the GPIO device on SiFive SoCs. 490 + 482 491 config GPIO_SIOX 483 492 tristate "SIOX GPIO support" 484 493 depends on SIOX
+1
drivers/gpio/Makefile
··· 124 124 obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o 125 125 obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o 126 126 obj-$(CONFIG_GPIO_SCH) += gpio-sch.o 127 + obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o 127 128 obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o 128 129 obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o 129 130 obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
+252
drivers/gpio/gpio-sifive.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 SiFive 4 + */ 5 + 6 + #include <linux/bitops.h> 7 + #include <linux/device.h> 8 + #include <linux/errno.h> 9 + #include <linux/of_irq.h> 10 + #include <linux/gpio/driver.h> 11 + #include <linux/init.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/slab.h> 14 + #include <linux/spinlock.h> 15 + #include <linux/regmap.h> 16 + 17 + #define SIFIVE_GPIO_INPUT_VAL 0x00 18 + #define SIFIVE_GPIO_INPUT_EN 0x04 19 + #define SIFIVE_GPIO_OUTPUT_EN 0x08 20 + #define SIFIVE_GPIO_OUTPUT_VAL 0x0C 21 + #define SIFIVE_GPIO_RISE_IE 0x18 22 + #define SIFIVE_GPIO_RISE_IP 0x1C 23 + #define SIFIVE_GPIO_FALL_IE 0x20 24 + #define SIFIVE_GPIO_FALL_IP 0x24 25 + #define SIFIVE_GPIO_HIGH_IE 0x28 26 + #define SIFIVE_GPIO_HIGH_IP 0x2C 27 + #define SIFIVE_GPIO_LOW_IE 0x30 28 + #define SIFIVE_GPIO_LOW_IP 0x34 29 + #define SIFIVE_GPIO_OUTPUT_XOR 0x40 30 + 31 + #define SIFIVE_GPIO_MAX 32 32 + #define SIFIVE_GPIO_IRQ_OFFSET 7 33 + 34 + struct sifive_gpio { 35 + void __iomem *base; 36 + struct gpio_chip gc; 37 + struct regmap *regs; 38 + u32 irq_state; 39 + unsigned int trigger[SIFIVE_GPIO_MAX]; 40 + unsigned int irq_parent[SIFIVE_GPIO_MAX]; 41 + }; 42 + 43 + static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset) 44 + { 45 + unsigned long flags; 46 + unsigned int trigger; 47 + 48 + spin_lock_irqsave(&chip->gc.bgpio_lock, flags); 49 + trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0; 50 + regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset), 51 + (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0); 52 + regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset), 53 + (trigger & IRQ_TYPE_EDGE_FALLING) ? BIT(offset) : 0); 54 + regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset), 55 + (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0); 56 + regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset), 57 + (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0); 58 + spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags); 59 + } 60 + 61 + static int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger) 62 + { 63 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 64 + struct sifive_gpio *chip = gpiochip_get_data(gc); 65 + int offset = irqd_to_hwirq(d); 66 + 67 + if (offset < 0 || offset >= gc->ngpio) 68 + return -EINVAL; 69 + 70 + chip->trigger[offset] = trigger; 71 + sifive_gpio_set_ie(chip, offset); 72 + return 0; 73 + } 74 + 75 + static void sifive_gpio_irq_enable(struct irq_data *d) 76 + { 77 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 78 + struct sifive_gpio *chip = gpiochip_get_data(gc); 79 + int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 80 + u32 bit = BIT(offset); 81 + unsigned long flags; 82 + 83 + irq_chip_enable_parent(d); 84 + 85 + /* Switch to input */ 86 + gc->direction_input(gc, offset); 87 + 88 + spin_lock_irqsave(&gc->bgpio_lock, flags); 89 + /* Clear any sticky pending interrupts */ 90 + regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); 91 + regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); 92 + regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); 93 + regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); 94 + spin_unlock_irqrestore(&gc->bgpio_lock, flags); 95 + 96 + /* Enable interrupts */ 97 + assign_bit(offset, (unsigned long *)&chip->irq_state, 1); 98 + sifive_gpio_set_ie(chip, offset); 99 + } 100 + 101 + static void sifive_gpio_irq_disable(struct irq_data *d) 102 + { 103 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 104 + struct sifive_gpio *chip = gpiochip_get_data(gc); 105 + int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 106 + 107 + assign_bit(offset, (unsigned long *)&chip->irq_state, 0); 108 + sifive_gpio_set_ie(chip, offset); 109 + irq_chip_disable_parent(d); 110 + } 111 + 112 + static void sifive_gpio_irq_eoi(struct irq_data *d) 113 + { 114 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 115 + struct sifive_gpio *chip = gpiochip_get_data(gc); 116 + int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 117 + u32 bit = BIT(offset); 118 + unsigned long flags; 119 + 120 + spin_lock_irqsave(&gc->bgpio_lock, flags); 121 + /* Clear all pending interrupts */ 122 + regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); 123 + regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); 124 + regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); 125 + regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); 126 + spin_unlock_irqrestore(&gc->bgpio_lock, flags); 127 + 128 + irq_chip_eoi_parent(d); 129 + } 130 + 131 + static struct irq_chip sifive_gpio_irqchip = { 132 + .name = "sifive-gpio", 133 + .irq_set_type = sifive_gpio_irq_set_type, 134 + .irq_mask = irq_chip_mask_parent, 135 + .irq_unmask = irq_chip_unmask_parent, 136 + .irq_enable = sifive_gpio_irq_enable, 137 + .irq_disable = sifive_gpio_irq_disable, 138 + .irq_eoi = sifive_gpio_irq_eoi, 139 + }; 140 + 141 + static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc, 142 + unsigned int child, 143 + unsigned int child_type, 144 + unsigned int *parent, 145 + unsigned int *parent_type) 146 + { 147 + *parent_type = IRQ_TYPE_NONE; 148 + *parent = child + SIFIVE_GPIO_IRQ_OFFSET; 149 + return 0; 150 + } 151 + 152 + static const struct regmap_config sifive_gpio_regmap_config = { 153 + .reg_bits = 32, 154 + .reg_stride = 4, 155 + .val_bits = 32, 156 + .fast_io = true, 157 + .disable_locking = true, 158 + }; 159 + 160 + static int sifive_gpio_probe(struct platform_device *pdev) 161 + { 162 + struct device *dev = &pdev->dev; 163 + struct device_node *node = pdev->dev.of_node; 164 + struct device_node *irq_parent; 165 + struct irq_domain *parent; 166 + struct gpio_irq_chip *girq; 167 + struct sifive_gpio *chip; 168 + int ret, ngpio; 169 + 170 + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 171 + if (!chip) 172 + return -ENOMEM; 173 + 174 + chip->base = devm_platform_ioremap_resource(pdev, 0); 175 + if (IS_ERR(chip->base)) { 176 + dev_err(dev, "failed to allocate device memory\n"); 177 + return PTR_ERR(chip->base); 178 + } 179 + 180 + chip->regs = devm_regmap_init_mmio(dev, chip->base, 181 + &sifive_gpio_regmap_config); 182 + if (IS_ERR(chip->regs)) 183 + return PTR_ERR(chip->regs); 184 + 185 + ngpio = of_irq_count(node); 186 + if (ngpio >= SIFIVE_GPIO_MAX) { 187 + dev_err(dev, "Too many GPIO interrupts (max=%d)\n", 188 + SIFIVE_GPIO_MAX); 189 + return -ENXIO; 190 + } 191 + 192 + irq_parent = of_irq_find_parent(node); 193 + if (!irq_parent) { 194 + dev_err(dev, "no IRQ parent node\n"); 195 + return -ENODEV; 196 + } 197 + parent = irq_find_host(irq_parent); 198 + if (!parent) { 199 + dev_err(dev, "no IRQ parent domain\n"); 200 + return -ENODEV; 201 + } 202 + 203 + ret = bgpio_init(&chip->gc, dev, 4, 204 + chip->base + SIFIVE_GPIO_INPUT_VAL, 205 + chip->base + SIFIVE_GPIO_OUTPUT_VAL, 206 + NULL, 207 + chip->base + SIFIVE_GPIO_OUTPUT_EN, 208 + chip->base + SIFIVE_GPIO_INPUT_EN, 209 + 0); 210 + if (ret) { 211 + dev_err(dev, "unable to init generic GPIO\n"); 212 + return ret; 213 + } 214 + 215 + /* Disable all GPIO interrupts before enabling parent interrupts */ 216 + regmap_write(chip->regs, SIFIVE_GPIO_RISE_IE, 0); 217 + regmap_write(chip->regs, SIFIVE_GPIO_FALL_IE, 0); 218 + regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IE, 0); 219 + regmap_write(chip->regs, SIFIVE_GPIO_LOW_IE, 0); 220 + chip->irq_state = 0; 221 + 222 + chip->gc.base = -1; 223 + chip->gc.ngpio = ngpio; 224 + chip->gc.label = dev_name(dev); 225 + chip->gc.parent = dev; 226 + chip->gc.owner = THIS_MODULE; 227 + girq = &chip->gc.irq; 228 + girq->chip = &sifive_gpio_irqchip; 229 + girq->fwnode = of_node_to_fwnode(node); 230 + girq->parent_domain = parent; 231 + girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq; 232 + girq->handler = handle_bad_irq; 233 + girq->default_type = IRQ_TYPE_NONE; 234 + 235 + platform_set_drvdata(pdev, chip); 236 + return gpiochip_add_data(&chip->gc, chip); 237 + } 238 + 239 + static const struct of_device_id sifive_gpio_match[] = { 240 + { .compatible = "sifive,gpio0" }, 241 + { .compatible = "sifive,fu540-c000-gpio" }, 242 + { }, 243 + }; 244 + 245 + static struct platform_driver sifive_gpio_driver = { 246 + .probe = sifive_gpio_probe, 247 + .driver = { 248 + .name = "sifive_gpio", 249 + .of_match_table = of_match_ptr(sifive_gpio_match), 250 + }, 251 + }; 252 + builtin_platform_driver(sifive_gpio_driver)