irq-aspeed-i2c-ic.c (2792B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Aspeed 24XX/25XX I2C Interrupt Controller. 4 * 5 * Copyright (C) 2012-2017 ASPEED Technology Inc. 6 * Copyright 2017 IBM Corporation 7 * Copyright 2017 Google, Inc. 8 */ 9 10#include <linux/irq.h> 11#include <linux/irqchip.h> 12#include <linux/irqchip/chained_irq.h> 13#include <linux/irqdomain.h> 14#include <linux/of_address.h> 15#include <linux/of_irq.h> 16#include <linux/io.h> 17 18 19#define ASPEED_I2C_IC_NUM_BUS 14 20 21struct aspeed_i2c_ic { 22 void __iomem *base; 23 int parent_irq; 24 struct irq_domain *irq_domain; 25}; 26 27/* 28 * The aspeed chip provides a single hardware interrupt for all of the I2C 29 * busses, so we use a dummy interrupt chip to translate this single interrupt 30 * into multiple interrupts, each associated with a single I2C bus. 31 */ 32static void aspeed_i2c_ic_irq_handler(struct irq_desc *desc) 33{ 34 struct aspeed_i2c_ic *i2c_ic = irq_desc_get_handler_data(desc); 35 struct irq_chip *chip = irq_desc_get_chip(desc); 36 unsigned long bit, status; 37 38 chained_irq_enter(chip, desc); 39 status = readl(i2c_ic->base); 40 for_each_set_bit(bit, &status, ASPEED_I2C_IC_NUM_BUS) 41 generic_handle_domain_irq(i2c_ic->irq_domain, bit); 42 43 chained_irq_exit(chip, desc); 44} 45 46/* 47 * Set simple handler and mark IRQ as valid. Nothing interesting to do here 48 * since we are using a dummy interrupt chip. 49 */ 50static int aspeed_i2c_ic_map_irq_domain(struct irq_domain *domain, 51 unsigned int irq, irq_hw_number_t hwirq) 52{ 53 irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); 54 irq_set_chip_data(irq, domain->host_data); 55 56 return 0; 57} 58 59static const struct irq_domain_ops aspeed_i2c_ic_irq_domain_ops = { 60 .map = aspeed_i2c_ic_map_irq_domain, 61}; 62 63static int __init aspeed_i2c_ic_of_init(struct device_node *node, 64 struct device_node *parent) 65{ 66 struct aspeed_i2c_ic *i2c_ic; 67 int ret = 0; 68 69 i2c_ic = kzalloc(sizeof(*i2c_ic), GFP_KERNEL); 70 if (!i2c_ic) 71 return -ENOMEM; 72 73 i2c_ic->base = of_iomap(node, 0); 74 if (!i2c_ic->base) { 75 ret = -ENOMEM; 76 goto err_free_ic; 77 } 78 79 i2c_ic->parent_irq = irq_of_parse_and_map(node, 0); 80 if (!i2c_ic->parent_irq) { 81 ret = -EINVAL; 82 goto err_iounmap; 83 } 84 85 i2c_ic->irq_domain = irq_domain_add_linear(node, ASPEED_I2C_IC_NUM_BUS, 86 &aspeed_i2c_ic_irq_domain_ops, 87 NULL); 88 if (!i2c_ic->irq_domain) { 89 ret = -ENOMEM; 90 goto err_iounmap; 91 } 92 93 i2c_ic->irq_domain->name = "aspeed-i2c-domain"; 94 95 irq_set_chained_handler_and_data(i2c_ic->parent_irq, 96 aspeed_i2c_ic_irq_handler, i2c_ic); 97 98 pr_info("i2c controller registered, irq %d\n", i2c_ic->parent_irq); 99 100 return 0; 101 102err_iounmap: 103 iounmap(i2c_ic->base); 104err_free_ic: 105 kfree(i2c_ic); 106 return ret; 107} 108 109IRQCHIP_DECLARE(ast2400_i2c_ic, "aspeed,ast2400-i2c-ic", aspeed_i2c_ic_of_init); 110IRQCHIP_DECLARE(ast2500_i2c_ic, "aspeed,ast2500-i2c-ic", aspeed_i2c_ic_of_init);