Linux Audio

Check our new training course

Loading...
v4.6
  1/*
  2 *  Atheros AR71xx/AR724x/AR913x MISC interrupt controller
  3 *
  4 *  Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  5 *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
  6 *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  7 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  8 *
  9 *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
 10 *
 11 *  This program is free software; you can redistribute it and/or modify it
 12 *  under the terms of the GNU General Public License version 2 as published
 13 *  by the Free Software Foundation.
 14 */
 15
 16#include <linux/irqchip.h>
 17#include <linux/irqchip/chained_irq.h>
 18#include <linux/of_address.h>
 19#include <linux/of_irq.h>
 20
 21#define AR71XX_RESET_REG_MISC_INT_STATUS	0
 22#define AR71XX_RESET_REG_MISC_INT_ENABLE	4
 23
 24#define ATH79_MISC_IRQ_COUNT			32
 25
 26static void ath79_misc_irq_handler(struct irq_desc *desc)
 27{
 28	struct irq_domain *domain = irq_desc_get_handler_data(desc);
 29	struct irq_chip *chip = irq_desc_get_chip(desc);
 30	void __iomem *base = domain->host_data;
 31	u32 pending;
 32
 33	chained_irq_enter(chip, desc);
 34
 35	pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
 36		  __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 37
 38	if (!pending) {
 39		spurious_interrupt();
 40		chained_irq_exit(chip, desc);
 41		return;
 42	}
 43
 44	while (pending) {
 45		int bit = __ffs(pending);
 46
 47		generic_handle_irq(irq_linear_revmap(domain, bit));
 48		pending &= ~BIT(bit);
 49	}
 50
 51	chained_irq_exit(chip, desc);
 52}
 53
 54static void ar71xx_misc_irq_unmask(struct irq_data *d)
 55{
 56	void __iomem *base = irq_data_get_irq_chip_data(d);
 57	unsigned int irq = d->hwirq;
 58	u32 t;
 59
 60	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 61	__raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 62
 63	/* flush write */
 64	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 65}
 66
 67static void ar71xx_misc_irq_mask(struct irq_data *d)
 68{
 69	void __iomem *base = irq_data_get_irq_chip_data(d);
 70	unsigned int irq = d->hwirq;
 71	u32 t;
 72
 73	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 74	__raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 75
 76	/* flush write */
 77	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 78}
 79
 80static void ar724x_misc_irq_ack(struct irq_data *d)
 81{
 82	void __iomem *base = irq_data_get_irq_chip_data(d);
 83	unsigned int irq = d->hwirq;
 84	u32 t;
 85
 86	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
 87	__raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
 88
 89	/* flush write */
 90	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
 91}
 92
 93static struct irq_chip ath79_misc_irq_chip = {
 94	.name		= "MISC",
 95	.irq_unmask	= ar71xx_misc_irq_unmask,
 96	.irq_mask	= ar71xx_misc_irq_mask,
 97};
 98
 99static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
100{
101	irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);
102	irq_set_chip_data(irq, d->host_data);
103	return 0;
104}
105
106static const struct irq_domain_ops misc_irq_domain_ops = {
107	.xlate = irq_domain_xlate_onecell,
108	.map = misc_map,
109};
110
111static void __init ath79_misc_intc_domain_init(
112	struct irq_domain *domain, int irq)
113{
114	void __iomem *base = domain->host_data;
115
116	/* Disable and clear all interrupts */
117	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
118	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
119
120	irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);
121}
122
123static int __init ath79_misc_intc_of_init(
124	struct device_node *node, struct device_node *parent)
125{
126	struct irq_domain *domain;
127	void __iomem *base;
128	int irq;
129
130	irq = irq_of_parse_and_map(node, 0);
131	if (!irq) {
132		pr_err("Failed to get MISC IRQ\n");
133		return -EINVAL;
134	}
135
136	base = of_iomap(node, 0);
137	if (!base) {
138		pr_err("Failed to get MISC IRQ registers\n");
139		return -ENOMEM;
140	}
141
142	domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,
143				&misc_irq_domain_ops, base);
144	if (!domain) {
145		pr_err("Failed to add MISC irqdomain\n");
146		return -EINVAL;
147	}
148
149	ath79_misc_intc_domain_init(domain, irq);
150	return 0;
151}
152
153static int __init ar7100_misc_intc_of_init(
154	struct device_node *node, struct device_node *parent)
155{
156	ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
157	return ath79_misc_intc_of_init(node, parent);
158}
159
160IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
161		ar7100_misc_intc_of_init);
162
163static int __init ar7240_misc_intc_of_init(
164	struct device_node *node, struct device_node *parent)
165{
166	ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
167	return ath79_misc_intc_of_init(node, parent);
168}
169
170IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
171		ar7240_misc_intc_of_init);
172
173void __init ath79_misc_irq_init(void __iomem *regs, int irq,
174				int irq_base, bool is_ar71xx)
175{
176	struct irq_domain *domain;
177
178	if (is_ar71xx)
179		ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
180	else
181		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
182
183	domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,
184			irq_base, 0, &misc_irq_domain_ops, regs);
185	if (!domain)
186		panic("Failed to create MISC irqdomain");
187
188	ath79_misc_intc_domain_init(domain, irq);
189}
v4.17
  1/*
  2 *  Atheros AR71xx/AR724x/AR913x MISC interrupt controller
  3 *
  4 *  Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  5 *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
  6 *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  7 *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  8 *
  9 *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
 10 *
 11 *  This program is free software; you can redistribute it and/or modify it
 12 *  under the terms of the GNU General Public License version 2 as published
 13 *  by the Free Software Foundation.
 14 */
 15
 16#include <linux/irqchip.h>
 17#include <linux/irqchip/chained_irq.h>
 18#include <linux/of_address.h>
 19#include <linux/of_irq.h>
 20
 21#define AR71XX_RESET_REG_MISC_INT_STATUS	0
 22#define AR71XX_RESET_REG_MISC_INT_ENABLE	4
 23
 24#define ATH79_MISC_IRQ_COUNT			32
 25
 26static void ath79_misc_irq_handler(struct irq_desc *desc)
 27{
 28	struct irq_domain *domain = irq_desc_get_handler_data(desc);
 29	struct irq_chip *chip = irq_desc_get_chip(desc);
 30	void __iomem *base = domain->host_data;
 31	u32 pending;
 32
 33	chained_irq_enter(chip, desc);
 34
 35	pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
 36		  __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 37
 38	if (!pending) {
 39		spurious_interrupt();
 40		chained_irq_exit(chip, desc);
 41		return;
 42	}
 43
 44	while (pending) {
 45		int bit = __ffs(pending);
 46
 47		generic_handle_irq(irq_linear_revmap(domain, bit));
 48		pending &= ~BIT(bit);
 49	}
 50
 51	chained_irq_exit(chip, desc);
 52}
 53
 54static void ar71xx_misc_irq_unmask(struct irq_data *d)
 55{
 56	void __iomem *base = irq_data_get_irq_chip_data(d);
 57	unsigned int irq = d->hwirq;
 58	u32 t;
 59
 60	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 61	__raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 62
 63	/* flush write */
 64	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 65}
 66
 67static void ar71xx_misc_irq_mask(struct irq_data *d)
 68{
 69	void __iomem *base = irq_data_get_irq_chip_data(d);
 70	unsigned int irq = d->hwirq;
 71	u32 t;
 72
 73	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 74	__raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 75
 76	/* flush write */
 77	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 78}
 79
 80static void ar724x_misc_irq_ack(struct irq_data *d)
 81{
 82	void __iomem *base = irq_data_get_irq_chip_data(d);
 83	unsigned int irq = d->hwirq;
 84	u32 t;
 85
 86	t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
 87	__raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
 88
 89	/* flush write */
 90	__raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
 91}
 92
 93static struct irq_chip ath79_misc_irq_chip = {
 94	.name		= "MISC",
 95	.irq_unmask	= ar71xx_misc_irq_unmask,
 96	.irq_mask	= ar71xx_misc_irq_mask,
 97};
 98
 99static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
100{
101	irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);
102	irq_set_chip_data(irq, d->host_data);
103	return 0;
104}
105
106static const struct irq_domain_ops misc_irq_domain_ops = {
107	.xlate = irq_domain_xlate_onecell,
108	.map = misc_map,
109};
110
111static void __init ath79_misc_intc_domain_init(
112	struct irq_domain *domain, int irq)
113{
114	void __iomem *base = domain->host_data;
115
116	/* Disable and clear all interrupts */
117	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
118	__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
119
120	irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);
121}
122
123static int __init ath79_misc_intc_of_init(
124	struct device_node *node, struct device_node *parent)
125{
126	struct irq_domain *domain;
127	void __iomem *base;
128	int irq;
129
130	irq = irq_of_parse_and_map(node, 0);
131	if (!irq) {
132		pr_err("Failed to get MISC IRQ\n");
133		return -EINVAL;
134	}
135
136	base = of_iomap(node, 0);
137	if (!base) {
138		pr_err("Failed to get MISC IRQ registers\n");
139		return -ENOMEM;
140	}
141
142	domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,
143				&misc_irq_domain_ops, base);
144	if (!domain) {
145		pr_err("Failed to add MISC irqdomain\n");
146		return -EINVAL;
147	}
148
149	ath79_misc_intc_domain_init(domain, irq);
150	return 0;
151}
152
153static int __init ar7100_misc_intc_of_init(
154	struct device_node *node, struct device_node *parent)
155{
156	ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
157	return ath79_misc_intc_of_init(node, parent);
158}
159
160IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
161		ar7100_misc_intc_of_init);
162
163static int __init ar7240_misc_intc_of_init(
164	struct device_node *node, struct device_node *parent)
165{
166	ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
167	return ath79_misc_intc_of_init(node, parent);
168}
169
170IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
171		ar7240_misc_intc_of_init);
172
173void __init ath79_misc_irq_init(void __iomem *regs, int irq,
174				int irq_base, bool is_ar71xx)
175{
176	struct irq_domain *domain;
177
178	if (is_ar71xx)
179		ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
180	else
181		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
182
183	domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,
184			irq_base, 0, &misc_irq_domain_ops, regs);
185	if (!domain)
186		panic("Failed to create MISC irqdomain");
187
188	ath79_misc_intc_domain_init(domain, irq);
189}