18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2019 SiFive 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/bitops.h> 78c2ecf20Sopenharmony_ci#include <linux/device.h> 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_INPUT_VAL 0x00 188c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_INPUT_EN 0x04 198c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_EN 0x08 208c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_VAL 0x0C 218c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_RISE_IE 0x18 228c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_RISE_IP 0x1C 238c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_FALL_IE 0x20 248c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_FALL_IP 0x24 258c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_HIGH_IE 0x28 268c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_HIGH_IP 0x2C 278c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_LOW_IE 0x30 288c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_LOW_IP 0x34 298c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_XOR 0x40 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_MAX 32 328c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_IRQ_OFFSET 7 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct sifive_gpio { 358c2ecf20Sopenharmony_ci void __iomem *base; 368c2ecf20Sopenharmony_ci struct gpio_chip gc; 378c2ecf20Sopenharmony_ci struct regmap *regs; 388c2ecf20Sopenharmony_ci unsigned long irq_state; 398c2ecf20Sopenharmony_ci unsigned int trigger[SIFIVE_GPIO_MAX]; 408c2ecf20Sopenharmony_ci unsigned int irq_parent[SIFIVE_GPIO_MAX]; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci unsigned long flags; 468c2ecf20Sopenharmony_ci unsigned int trigger; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->gc.bgpio_lock, flags); 498c2ecf20Sopenharmony_ci trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0; 508c2ecf20Sopenharmony_ci regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset), 518c2ecf20Sopenharmony_ci (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0); 528c2ecf20Sopenharmony_ci regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset), 538c2ecf20Sopenharmony_ci (trigger & IRQ_TYPE_EDGE_FALLING) ? BIT(offset) : 0); 548c2ecf20Sopenharmony_ci regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset), 558c2ecf20Sopenharmony_ci (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0); 568c2ecf20Sopenharmony_ci regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset), 578c2ecf20Sopenharmony_ci (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0); 588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 648c2ecf20Sopenharmony_ci struct sifive_gpio *chip = gpiochip_get_data(gc); 658c2ecf20Sopenharmony_ci int offset = irqd_to_hwirq(d); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (offset < 0 || offset >= gc->ngpio) 688c2ecf20Sopenharmony_ci return -EINVAL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci chip->trigger[offset] = trigger; 718c2ecf20Sopenharmony_ci sifive_gpio_set_ie(chip, offset); 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_enable(struct irq_data *d) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 788c2ecf20Sopenharmony_ci struct sifive_gpio *chip = gpiochip_get_data(gc); 798c2ecf20Sopenharmony_ci int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 808c2ecf20Sopenharmony_ci u32 bit = BIT(offset); 818c2ecf20Sopenharmony_ci unsigned long flags; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci irq_chip_enable_parent(d); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Switch to input */ 868c2ecf20Sopenharmony_ci gc->direction_input(gc, offset); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci spin_lock_irqsave(&gc->bgpio_lock, flags); 898c2ecf20Sopenharmony_ci /* Clear any sticky pending interrupts */ 908c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); 918c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); 928c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); 938c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); 948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gc->bgpio_lock, flags); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Enable interrupts */ 978c2ecf20Sopenharmony_ci assign_bit(offset, &chip->irq_state, 1); 988c2ecf20Sopenharmony_ci sifive_gpio_set_ie(chip, offset); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_disable(struct irq_data *d) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 1048c2ecf20Sopenharmony_ci struct sifive_gpio *chip = gpiochip_get_data(gc); 1058c2ecf20Sopenharmony_ci int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci assign_bit(offset, &chip->irq_state, 0); 1088c2ecf20Sopenharmony_ci sifive_gpio_set_ie(chip, offset); 1098c2ecf20Sopenharmony_ci irq_chip_disable_parent(d); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_eoi(struct irq_data *d) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 1158c2ecf20Sopenharmony_ci struct sifive_gpio *chip = gpiochip_get_data(gc); 1168c2ecf20Sopenharmony_ci int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX; 1178c2ecf20Sopenharmony_ci u32 bit = BIT(offset); 1188c2ecf20Sopenharmony_ci unsigned long flags; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci spin_lock_irqsave(&gc->bgpio_lock, flags); 1218c2ecf20Sopenharmony_ci /* Clear all pending interrupts */ 1228c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); 1238c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); 1248c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); 1258c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); 1268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gc->bgpio_lock, flags); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci irq_chip_eoi_parent(d); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct irq_chip sifive_gpio_irqchip = { 1328c2ecf20Sopenharmony_ci .name = "sifive-gpio", 1338c2ecf20Sopenharmony_ci .irq_set_type = sifive_gpio_irq_set_type, 1348c2ecf20Sopenharmony_ci .irq_mask = irq_chip_mask_parent, 1358c2ecf20Sopenharmony_ci .irq_unmask = irq_chip_unmask_parent, 1368c2ecf20Sopenharmony_ci .irq_enable = sifive_gpio_irq_enable, 1378c2ecf20Sopenharmony_ci .irq_disable = sifive_gpio_irq_disable, 1388c2ecf20Sopenharmony_ci .irq_eoi = sifive_gpio_irq_eoi, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc, 1428c2ecf20Sopenharmony_ci unsigned int child, 1438c2ecf20Sopenharmony_ci unsigned int child_type, 1448c2ecf20Sopenharmony_ci unsigned int *parent, 1458c2ecf20Sopenharmony_ci unsigned int *parent_type) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci *parent_type = IRQ_TYPE_NONE; 1488c2ecf20Sopenharmony_ci *parent = child + SIFIVE_GPIO_IRQ_OFFSET; 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct regmap_config sifive_gpio_regmap_config = { 1538c2ecf20Sopenharmony_ci .reg_bits = 32, 1548c2ecf20Sopenharmony_ci .reg_stride = 4, 1558c2ecf20Sopenharmony_ci .val_bits = 32, 1568c2ecf20Sopenharmony_ci .fast_io = true, 1578c2ecf20Sopenharmony_ci .disable_locking = true, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int sifive_gpio_probe(struct platform_device *pdev) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1638c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 1648c2ecf20Sopenharmony_ci struct device_node *irq_parent; 1658c2ecf20Sopenharmony_ci struct irq_domain *parent; 1668c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 1678c2ecf20Sopenharmony_ci struct sifive_gpio *chip; 1688c2ecf20Sopenharmony_ci int ret, ngpio; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 1718c2ecf20Sopenharmony_ci if (!chip) 1728c2ecf20Sopenharmony_ci return -ENOMEM; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci chip->base = devm_platform_ioremap_resource(pdev, 0); 1758c2ecf20Sopenharmony_ci if (IS_ERR(chip->base)) { 1768c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate device memory\n"); 1778c2ecf20Sopenharmony_ci return PTR_ERR(chip->base); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci chip->regs = devm_regmap_init_mmio(dev, chip->base, 1818c2ecf20Sopenharmony_ci &sifive_gpio_regmap_config); 1828c2ecf20Sopenharmony_ci if (IS_ERR(chip->regs)) 1838c2ecf20Sopenharmony_ci return PTR_ERR(chip->regs); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ngpio = of_irq_count(node); 1868c2ecf20Sopenharmony_ci if (ngpio > SIFIVE_GPIO_MAX) { 1878c2ecf20Sopenharmony_ci dev_err(dev, "Too many GPIO interrupts (max=%d)\n", 1888c2ecf20Sopenharmony_ci SIFIVE_GPIO_MAX); 1898c2ecf20Sopenharmony_ci return -ENXIO; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci irq_parent = of_irq_find_parent(node); 1938c2ecf20Sopenharmony_ci if (!irq_parent) { 1948c2ecf20Sopenharmony_ci dev_err(dev, "no IRQ parent node\n"); 1958c2ecf20Sopenharmony_ci return -ENODEV; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci parent = irq_find_host(irq_parent); 1988c2ecf20Sopenharmony_ci of_node_put(irq_parent); 1998c2ecf20Sopenharmony_ci if (!parent) { 2008c2ecf20Sopenharmony_ci dev_err(dev, "no IRQ parent domain\n"); 2018c2ecf20Sopenharmony_ci return -ENODEV; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ret = bgpio_init(&chip->gc, dev, 4, 2058c2ecf20Sopenharmony_ci chip->base + SIFIVE_GPIO_INPUT_VAL, 2068c2ecf20Sopenharmony_ci chip->base + SIFIVE_GPIO_OUTPUT_VAL, 2078c2ecf20Sopenharmony_ci NULL, 2088c2ecf20Sopenharmony_ci chip->base + SIFIVE_GPIO_OUTPUT_EN, 2098c2ecf20Sopenharmony_ci chip->base + SIFIVE_GPIO_INPUT_EN, 2108c2ecf20Sopenharmony_ci BGPIOF_READ_OUTPUT_REG_SET); 2118c2ecf20Sopenharmony_ci if (ret) { 2128c2ecf20Sopenharmony_ci dev_err(dev, "unable to init generic GPIO\n"); 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Disable all GPIO interrupts before enabling parent interrupts */ 2178c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_RISE_IE, 0); 2188c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_FALL_IE, 0); 2198c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IE, 0); 2208c2ecf20Sopenharmony_ci regmap_write(chip->regs, SIFIVE_GPIO_LOW_IE, 0); 2218c2ecf20Sopenharmony_ci chip->irq_state = 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci chip->gc.base = -1; 2248c2ecf20Sopenharmony_ci chip->gc.ngpio = ngpio; 2258c2ecf20Sopenharmony_ci chip->gc.label = dev_name(dev); 2268c2ecf20Sopenharmony_ci chip->gc.parent = dev; 2278c2ecf20Sopenharmony_ci chip->gc.owner = THIS_MODULE; 2288c2ecf20Sopenharmony_ci girq = &chip->gc.irq; 2298c2ecf20Sopenharmony_ci girq->chip = &sifive_gpio_irqchip; 2308c2ecf20Sopenharmony_ci girq->fwnode = of_node_to_fwnode(node); 2318c2ecf20Sopenharmony_ci girq->parent_domain = parent; 2328c2ecf20Sopenharmony_ci girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq; 2338c2ecf20Sopenharmony_ci girq->handler = handle_bad_irq; 2348c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chip); 2378c2ecf20Sopenharmony_ci return gpiochip_add_data(&chip->gc, chip); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic const struct of_device_id sifive_gpio_match[] = { 2418c2ecf20Sopenharmony_ci { .compatible = "sifive,gpio0" }, 2428c2ecf20Sopenharmony_ci { .compatible = "sifive,fu540-c000-gpio" }, 2438c2ecf20Sopenharmony_ci { }, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct platform_driver sifive_gpio_driver = { 2478c2ecf20Sopenharmony_ci .probe = sifive_gpio_probe, 2488c2ecf20Sopenharmony_ci .driver = { 2498c2ecf20Sopenharmony_ci .name = "sifive_gpio", 2508c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sifive_gpio_match), 2518c2ecf20Sopenharmony_ci }, 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_cibuiltin_platform_driver(sifive_gpio_driver) 254