18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved. 48c2ecf20Sopenharmony_ci * Author: Jun Ma <majun258@huawei.com> 58c2ecf20Sopenharmony_ci * Author: Yun Wu <wuyun.wu@huawei.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/acpi.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/irqchip.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/msi.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 158c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Interrupt numbers per mbigen node supported */ 208c2ecf20Sopenharmony_ci#define IRQS_PER_MBIGEN_NODE 128 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */ 238c2ecf20Sopenharmony_ci#define RESERVED_IRQ_PER_MBIGEN_CHIP 64 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* The maximum IRQ pin number of mbigen chip(start from 0) */ 268c2ecf20Sopenharmony_ci#define MAXIMUM_IRQ_PIN_NUM 1407 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * In mbigen vector register 308c2ecf20Sopenharmony_ci * bit[21:12]: event id value 318c2ecf20Sopenharmony_ci * bit[11:0]: device id 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci#define IRQ_EVENT_ID_SHIFT 12 348c2ecf20Sopenharmony_ci#define IRQ_EVENT_ID_MASK 0x3ff 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* register range of each mbigen node */ 378c2ecf20Sopenharmony_ci#define MBIGEN_NODE_OFFSET 0x1000 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* offset of vector register in mbigen node */ 408c2ecf20Sopenharmony_ci#define REG_MBIGEN_VEC_OFFSET 0x200 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * offset of clear register in mbigen node 448c2ecf20Sopenharmony_ci * This register is used to clear the status 458c2ecf20Sopenharmony_ci * of interrupt 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define REG_MBIGEN_CLEAR_OFFSET 0xa000 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/** 508c2ecf20Sopenharmony_ci * offset of interrupt type register 518c2ecf20Sopenharmony_ci * This register is used to configure interrupt 528c2ecf20Sopenharmony_ci * trigger type 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define REG_MBIGEN_TYPE_OFFSET 0x0 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/** 578c2ecf20Sopenharmony_ci * struct mbigen_device - holds the information of mbigen device. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * @pdev: pointer to the platform device structure of mbigen chip. 608c2ecf20Sopenharmony_ci * @base: mapped address of this mbigen chip. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistruct mbigen_device { 638c2ecf20Sopenharmony_ci struct platform_device *pdev; 648c2ecf20Sopenharmony_ci void __iomem *base; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci unsigned int nid, pin; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP; 728c2ecf20Sopenharmony_ci nid = hwirq / IRQS_PER_MBIGEN_NODE + 1; 738c2ecf20Sopenharmony_ci pin = hwirq % IRQS_PER_MBIGEN_NODE; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return pin * 4 + nid * MBIGEN_NODE_OFFSET 768c2ecf20Sopenharmony_ci + REG_MBIGEN_VEC_OFFSET; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline void get_mbigen_type_reg(irq_hw_number_t hwirq, 808c2ecf20Sopenharmony_ci u32 *mask, u32 *addr) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci unsigned int nid, irq_ofst, ofst; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP; 858c2ecf20Sopenharmony_ci nid = hwirq / IRQS_PER_MBIGEN_NODE + 1; 868c2ecf20Sopenharmony_ci irq_ofst = hwirq % IRQS_PER_MBIGEN_NODE; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci *mask = 1 << (irq_ofst % 32); 898c2ecf20Sopenharmony_ci ofst = irq_ofst / 32 * 4; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci *addr = ofst + nid * MBIGEN_NODE_OFFSET 928c2ecf20Sopenharmony_ci + REG_MBIGEN_TYPE_OFFSET; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic inline void get_mbigen_clear_reg(irq_hw_number_t hwirq, 968c2ecf20Sopenharmony_ci u32 *mask, u32 *addr) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci unsigned int ofst = (hwirq / 32) * 4; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci *mask = 1 << (hwirq % 32); 1018c2ecf20Sopenharmony_ci *addr = ofst + REG_MBIGEN_CLEAR_OFFSET; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void mbigen_eoi_irq(struct irq_data *data) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci void __iomem *base = data->chip_data; 1078c2ecf20Sopenharmony_ci u32 mask, addr; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci get_mbigen_clear_reg(data->hwirq, &mask, &addr); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci writel_relaxed(mask, base + addr); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci irq_chip_eoi_parent(data); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int mbigen_set_type(struct irq_data *data, unsigned int type) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci void __iomem *base = data->chip_data; 1198c2ecf20Sopenharmony_ci u32 mask, addr, val; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci get_mbigen_type_reg(data->hwirq, &mask, &addr); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci val = readl_relaxed(base + addr); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (type == IRQ_TYPE_LEVEL_HIGH) 1298c2ecf20Sopenharmony_ci val |= mask; 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci val &= ~mask; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci writel_relaxed(val, base + addr); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic struct irq_chip mbigen_irq_chip = { 1398c2ecf20Sopenharmony_ci .name = "mbigen-v2", 1408c2ecf20Sopenharmony_ci .irq_mask = irq_chip_mask_parent, 1418c2ecf20Sopenharmony_ci .irq_unmask = irq_chip_unmask_parent, 1428c2ecf20Sopenharmony_ci .irq_eoi = mbigen_eoi_irq, 1438c2ecf20Sopenharmony_ci .irq_set_type = mbigen_set_type, 1448c2ecf20Sopenharmony_ci .irq_set_affinity = irq_chip_set_affinity_parent, 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct irq_data *d = irq_get_irq_data(desc->irq); 1508c2ecf20Sopenharmony_ci void __iomem *base = d->chip_data; 1518c2ecf20Sopenharmony_ci u32 val; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!msg->address_lo && !msg->address_hi) 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci base += get_mbigen_vec_reg(d->hwirq); 1578c2ecf20Sopenharmony_ci val = readl_relaxed(base); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT); 1608c2ecf20Sopenharmony_ci val |= (msg->data << IRQ_EVENT_ID_SHIFT); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* The address of doorbell is encoded in mbigen register by default 1638c2ecf20Sopenharmony_ci * So,we don't need to program the doorbell address at here 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci writel_relaxed(val, base); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int mbigen_domain_translate(struct irq_domain *d, 1698c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec, 1708c2ecf20Sopenharmony_ci unsigned long *hwirq, 1718c2ecf20Sopenharmony_ci unsigned int *type) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) { 1748c2ecf20Sopenharmony_ci if (fwspec->param_count != 2) 1758c2ecf20Sopenharmony_ci return -EINVAL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) || 1788c2ecf20Sopenharmony_ci (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP)) 1798c2ecf20Sopenharmony_ci return -EINVAL; 1808c2ecf20Sopenharmony_ci else 1818c2ecf20Sopenharmony_ci *hwirq = fwspec->param[0]; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* If there is no valid irq type, just use the default type */ 1848c2ecf20Sopenharmony_ci if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) || 1858c2ecf20Sopenharmony_ci (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH)) 1868c2ecf20Sopenharmony_ci *type = fwspec->param[1]; 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int mbigen_irq_domain_alloc(struct irq_domain *domain, 1968c2ecf20Sopenharmony_ci unsigned int virq, 1978c2ecf20Sopenharmony_ci unsigned int nr_irqs, 1988c2ecf20Sopenharmony_ci void *args) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec = args; 2018c2ecf20Sopenharmony_ci irq_hw_number_t hwirq; 2028c2ecf20Sopenharmony_ci unsigned int type; 2038c2ecf20Sopenharmony_ci struct mbigen_device *mgn_chip; 2048c2ecf20Sopenharmony_ci int i, err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = mbigen_domain_translate(domain, fwspec, &hwirq, &type); 2078c2ecf20Sopenharmony_ci if (err) 2088c2ecf20Sopenharmony_ci return err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci err = platform_msi_domain_alloc(domain, virq, nr_irqs); 2118c2ecf20Sopenharmony_ci if (err) 2128c2ecf20Sopenharmony_ci return err; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci mgn_chip = platform_msi_get_host_data(domain); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci for (i = 0; i < nr_irqs; i++) 2178c2ecf20Sopenharmony_ci irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 2188c2ecf20Sopenharmony_ci &mbigen_irq_chip, mgn_chip->base); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq, 2248c2ecf20Sopenharmony_ci unsigned int nr_irqs) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci platform_msi_domain_free(domain, virq, nr_irqs); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic const struct irq_domain_ops mbigen_domain_ops = { 2308c2ecf20Sopenharmony_ci .translate = mbigen_domain_translate, 2318c2ecf20Sopenharmony_ci .alloc = mbigen_irq_domain_alloc, 2328c2ecf20Sopenharmony_ci .free = mbigen_irq_domain_free, 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int mbigen_of_create_domain(struct platform_device *pdev, 2368c2ecf20Sopenharmony_ci struct mbigen_device *mgn_chip) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct device *parent; 2398c2ecf20Sopenharmony_ci struct platform_device *child; 2408c2ecf20Sopenharmony_ci struct irq_domain *domain; 2418c2ecf20Sopenharmony_ci struct device_node *np; 2428c2ecf20Sopenharmony_ci u32 num_pins; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci for_each_child_of_node(pdev->dev.of_node, np) { 2458c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "interrupt-controller")) 2468c2ecf20Sopenharmony_ci continue; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci parent = platform_bus_type.dev_root; 2498c2ecf20Sopenharmony_ci child = of_platform_device_create(np, NULL, parent); 2508c2ecf20Sopenharmony_ci if (!child) { 2518c2ecf20Sopenharmony_ci of_node_put(np); 2528c2ecf20Sopenharmony_ci return -ENOMEM; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (of_property_read_u32(child->dev.of_node, "num-pins", 2568c2ecf20Sopenharmony_ci &num_pins) < 0) { 2578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No num-pins property\n"); 2588c2ecf20Sopenharmony_ci of_node_put(np); 2598c2ecf20Sopenharmony_ci return -EINVAL; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci domain = platform_msi_create_device_domain(&child->dev, num_pins, 2638c2ecf20Sopenharmony_ci mbigen_write_msg, 2648c2ecf20Sopenharmony_ci &mbigen_domain_ops, 2658c2ecf20Sopenharmony_ci mgn_chip); 2668c2ecf20Sopenharmony_ci if (!domain) { 2678c2ecf20Sopenharmony_ci of_node_put(np); 2688c2ecf20Sopenharmony_ci return -ENOMEM; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 2768c2ecf20Sopenharmony_cistatic int mbigen_acpi_create_domain(struct platform_device *pdev, 2778c2ecf20Sopenharmony_ci struct mbigen_device *mgn_chip) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct irq_domain *domain; 2808c2ecf20Sopenharmony_ci u32 num_pins = 0; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * "num-pins" is the total number of interrupt pins implemented in 2858c2ecf20Sopenharmony_ci * this mbigen instance, and mbigen is an interrupt controller 2868c2ecf20Sopenharmony_ci * connected to ITS converting wired interrupts into MSI, so we 2878c2ecf20Sopenharmony_ci * use "num-pins" to alloc MSI vectors which are needed by client 2888c2ecf20Sopenharmony_ci * devices connected to it. 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * Here is the DSDT device node used for mbigen in firmware: 2918c2ecf20Sopenharmony_ci * Device(MBI0) { 2928c2ecf20Sopenharmony_ci * Name(_HID, "HISI0152") 2938c2ecf20Sopenharmony_ci * Name(_UID, Zero) 2948c2ecf20Sopenharmony_ci * Name(_CRS, ResourceTemplate() { 2958c2ecf20Sopenharmony_ci * Memory32Fixed(ReadWrite, 0xa0080000, 0x10000) 2968c2ecf20Sopenharmony_ci * }) 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * Name(_DSD, Package () { 2998c2ecf20Sopenharmony_ci * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), 3008c2ecf20Sopenharmony_ci * Package () { 3018c2ecf20Sopenharmony_ci * Package () {"num-pins", 378} 3028c2ecf20Sopenharmony_ci * } 3038c2ecf20Sopenharmony_ci * }) 3048c2ecf20Sopenharmony_ci * } 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "num-pins", &num_pins); 3078c2ecf20Sopenharmony_ci if (ret || num_pins == 0) 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci domain = platform_msi_create_device_domain(&pdev->dev, num_pins, 3118c2ecf20Sopenharmony_ci mbigen_write_msg, 3128c2ecf20Sopenharmony_ci &mbigen_domain_ops, 3138c2ecf20Sopenharmony_ci mgn_chip); 3148c2ecf20Sopenharmony_ci if (!domain) 3158c2ecf20Sopenharmony_ci return -ENOMEM; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci#else 3208c2ecf20Sopenharmony_cistatic inline int mbigen_acpi_create_domain(struct platform_device *pdev, 3218c2ecf20Sopenharmony_ci struct mbigen_device *mgn_chip) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci return -ENODEV; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci#endif 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int mbigen_device_probe(struct platform_device *pdev) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct mbigen_device *mgn_chip; 3308c2ecf20Sopenharmony_ci struct resource *res; 3318c2ecf20Sopenharmony_ci int err; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL); 3348c2ecf20Sopenharmony_ci if (!mgn_chip) 3358c2ecf20Sopenharmony_ci return -ENOMEM; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mgn_chip->pdev = pdev; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3408c2ecf20Sopenharmony_ci if (!res) 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mgn_chip->base = devm_ioremap(&pdev->dev, res->start, 3448c2ecf20Sopenharmony_ci resource_size(res)); 3458c2ecf20Sopenharmony_ci if (!mgn_chip->base) { 3468c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap %pR\n", res); 3478c2ecf20Sopenharmony_ci return -ENOMEM; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) 3518c2ecf20Sopenharmony_ci err = mbigen_of_create_domain(pdev, mgn_chip); 3528c2ecf20Sopenharmony_ci else if (ACPI_COMPANION(&pdev->dev)) 3538c2ecf20Sopenharmony_ci err = mbigen_acpi_create_domain(pdev, mgn_chip); 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci err = -EINVAL; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (err) { 3588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n"); 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, mgn_chip); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct of_device_id mbigen_of_match[] = { 3678c2ecf20Sopenharmony_ci { .compatible = "hisilicon,mbigen-v2" }, 3688c2ecf20Sopenharmony_ci { /* END */ } 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mbigen_of_match); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct acpi_device_id mbigen_acpi_match[] = { 3738c2ecf20Sopenharmony_ci { "HISI0152", 0 }, 3748c2ecf20Sopenharmony_ci {} 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, mbigen_acpi_match); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic struct platform_driver mbigen_platform_driver = { 3798c2ecf20Sopenharmony_ci .driver = { 3808c2ecf20Sopenharmony_ci .name = "Hisilicon MBIGEN-V2", 3818c2ecf20Sopenharmony_ci .of_match_table = mbigen_of_match, 3828c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(mbigen_acpi_match), 3838c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci .probe = mbigen_device_probe, 3868c2ecf20Sopenharmony_ci}; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cimodule_platform_driver(mbigen_platform_driver); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jun Ma <majun258@huawei.com>"); 3918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>"); 3928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon MBI Generator driver"); 394