• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/plat-spear/
1/*
2 * arch/arm/plat-spear/shirq.c
3 *
4 * SPEAr platform shared irq layer source file
5 *
6 * Copyright (C) 2009 ST Microelectronics
7 * Viresh Kumar<viresh.kumar@st.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/irq.h>
17#include <linux/spinlock.h>
18#include <plat/shirq.h>
19
20struct spear_shirq *shirq;
21static DEFINE_SPINLOCK(lock);
22
23static void shirq_irq_mask(unsigned irq)
24{
25	struct spear_shirq *shirq = get_irq_chip_data(irq);
26	u32 val, id = irq - shirq->dev_config[0].virq;
27	unsigned long flags;
28
29	if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
30		return;
31
32	spin_lock_irqsave(&lock, flags);
33	val = readl(shirq->regs.base + shirq->regs.enb_reg);
34	if (shirq->regs.reset_to_enb)
35		val |= shirq->dev_config[id].enb_mask;
36	else
37		val &= ~(shirq->dev_config[id].enb_mask);
38	writel(val, shirq->regs.base + shirq->regs.enb_reg);
39	spin_unlock_irqrestore(&lock, flags);
40}
41
42static void shirq_irq_unmask(unsigned irq)
43{
44	struct spear_shirq *shirq = get_irq_chip_data(irq);
45	u32 val, id = irq - shirq->dev_config[0].virq;
46	unsigned long flags;
47
48	if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
49		return;
50
51	spin_lock_irqsave(&lock, flags);
52	val = readl(shirq->regs.base + shirq->regs.enb_reg);
53	if (shirq->regs.reset_to_enb)
54		val &= ~(shirq->dev_config[id].enb_mask);
55	else
56		val |= shirq->dev_config[id].enb_mask;
57	writel(val, shirq->regs.base + shirq->regs.enb_reg);
58	spin_unlock_irqrestore(&lock, flags);
59}
60
61static struct irq_chip shirq_chip = {
62	.name		= "spear_shirq",
63	.ack		= shirq_irq_mask,
64	.mask		= shirq_irq_mask,
65	.unmask		= shirq_irq_unmask,
66};
67
68static void shirq_handler(unsigned irq, struct irq_desc *desc)
69{
70	u32 i, val, mask;
71	struct spear_shirq *shirq = get_irq_data(irq);
72
73	desc->chip->ack(irq);
74	while ((val = readl(shirq->regs.base + shirq->regs.status_reg) &
75				shirq->regs.status_reg_mask)) {
76		for (i = 0; (i < shirq->dev_count) && val; i++) {
77			if (!(shirq->dev_config[i].status_mask & val))
78				continue;
79
80			generic_handle_irq(shirq->dev_config[i].virq);
81
82			/* clear interrupt */
83			val &= ~shirq->dev_config[i].status_mask;
84			if ((shirq->regs.clear_reg == -1) ||
85					shirq->dev_config[i].clear_mask == -1)
86				continue;
87			mask = readl(shirq->regs.base + shirq->regs.clear_reg);
88			if (shirq->regs.reset_to_clear)
89				mask &= ~shirq->dev_config[i].clear_mask;
90			else
91				mask |= shirq->dev_config[i].clear_mask;
92			writel(mask, shirq->regs.base + shirq->regs.clear_reg);
93		}
94	}
95	desc->chip->unmask(irq);
96}
97
98int spear_shirq_register(struct spear_shirq *shirq)
99{
100	int i;
101
102	if (!shirq || !shirq->dev_config || !shirq->regs.base)
103		return -EFAULT;
104
105	if (!shirq->dev_count)
106		return -EINVAL;
107
108	set_irq_chained_handler(shirq->irq, shirq_handler);
109	for (i = 0; i < shirq->dev_count; i++) {
110		set_irq_chip(shirq->dev_config[i].virq, &shirq_chip);
111		set_irq_handler(shirq->dev_config[i].virq, handle_simple_irq);
112		set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID);
113		set_irq_chip_data(shirq->dev_config[i].virq, shirq);
114	}
115
116	set_irq_data(shirq->irq, shirq);
117	return 0;
118}
119