Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
shirq.c
Go to the documentation of this file.
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 <[email protected]>
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 
21 static DEFINE_SPINLOCK(lock);
22 
23 static void shirq_irq_mask(struct irq_data *d)
24 {
25  struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
26  u32 val, id = d->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 
42 static void shirq_irq_unmask(struct irq_data *d)
43 {
44  struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
45  u32 val, id = d->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 
61 static struct irq_chip shirq_chip = {
62  .name = "spear_shirq",
63  .irq_ack = shirq_irq_mask,
64  .irq_mask = shirq_irq_mask,
65  .irq_unmask = shirq_irq_unmask,
66 };
67 
68 static void shirq_handler(unsigned irq, struct irq_desc *desc)
69 {
70  u32 i, val, mask;
71  struct spear_shirq *shirq = irq_get_handler_data(irq);
72 
73  desc->irq_data.chip->irq_ack(&desc->irq_data);
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->irq_data.chip->irq_unmask(&desc->irq_data);
96 }
97 
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  irq_set_chained_handler(shirq->irq, shirq_handler);
109  for (i = 0; i < shirq->dev_count; i++) {
110  irq_set_chip_and_handler(shirq->dev_config[i].virq,
111  &shirq_chip, handle_simple_irq);
112  set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID);
113  irq_set_chip_data(shirq->dev_config[i].virq, shirq);
114  }
115 
116  irq_set_handler_data(shirq->irq, shirq);
117  return 0;
118 }