18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sl28cpld interrupt controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2020 Kontron Europe GmbH 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/property.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define INTC_IE 0x00 178c2ecf20Sopenharmony_ci#define INTC_IP 0x01 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const struct regmap_irq sl28cpld_irqs[] = { 208c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(0, 8), 218c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(1, 8), 228c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(2, 8), 238c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(3, 8), 248c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(4, 8), 258c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(5, 8), 268c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(6, 8), 278c2ecf20Sopenharmony_ci REGMAP_IRQ_REG_LINE(7, 8), 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct sl28cpld_intc { 318c2ecf20Sopenharmony_ci struct regmap *regmap; 328c2ecf20Sopenharmony_ci struct regmap_irq_chip chip; 338c2ecf20Sopenharmony_ci struct regmap_irq_chip_data *irq_data; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int sl28cpld_intc_probe(struct platform_device *pdev) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 398c2ecf20Sopenharmony_ci struct sl28cpld_intc *irqchip; 408c2ecf20Sopenharmony_ci int irq; 418c2ecf20Sopenharmony_ci u32 base; 428c2ecf20Sopenharmony_ci int ret; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (!dev->parent) 458c2ecf20Sopenharmony_ci return -ENODEV; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL); 488c2ecf20Sopenharmony_ci if (!irqchip) 498c2ecf20Sopenharmony_ci return -ENOMEM; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci irqchip->regmap = dev_get_regmap(dev->parent, NULL); 528c2ecf20Sopenharmony_ci if (!irqchip->regmap) 538c2ecf20Sopenharmony_ci return -ENODEV; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 568c2ecf20Sopenharmony_ci if (irq < 0) 578c2ecf20Sopenharmony_ci return irq; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "reg", &base); 608c2ecf20Sopenharmony_ci if (ret) 618c2ecf20Sopenharmony_ci return -EINVAL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci irqchip->chip.name = "sl28cpld-intc"; 648c2ecf20Sopenharmony_ci irqchip->chip.irqs = sl28cpld_irqs; 658c2ecf20Sopenharmony_ci irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs); 668c2ecf20Sopenharmony_ci irqchip->chip.num_regs = 1; 678c2ecf20Sopenharmony_ci irqchip->chip.status_base = base + INTC_IP; 688c2ecf20Sopenharmony_ci irqchip->chip.mask_base = base + INTC_IE; 698c2ecf20Sopenharmony_ci irqchip->chip.mask_invert = true, 708c2ecf20Sopenharmony_ci irqchip->chip.ack_base = base + INTC_IP; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), 738c2ecf20Sopenharmony_ci irqchip->regmap, irq, 748c2ecf20Sopenharmony_ci IRQF_SHARED | IRQF_ONESHOT, 0, 758c2ecf20Sopenharmony_ci &irqchip->chip, 768c2ecf20Sopenharmony_ci &irqchip->irq_data); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic const struct of_device_id sl28cpld_intc_of_match[] = { 808c2ecf20Sopenharmony_ci { .compatible = "kontron,sl28cpld-intc" }, 818c2ecf20Sopenharmony_ci {} 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sl28cpld_intc_of_match); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic struct platform_driver sl28cpld_intc_driver = { 868c2ecf20Sopenharmony_ci .probe = sl28cpld_intc_probe, 878c2ecf20Sopenharmony_ci .driver = { 888c2ecf20Sopenharmony_ci .name = "sl28cpld-intc", 898c2ecf20Sopenharmony_ci .of_match_table = sl28cpld_intc_of_match, 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_cimodule_platform_driver(sl28cpld_intc_driver); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("sl28cpld Interrupt Controller Driver"); 958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Walle <michael@walle.cc>"); 968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 97