~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/mach-ux500/modem-irq-db5500.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) ST-Ericsson SA 2010
 
3
 * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
 
4
 * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
 
5
 * License terms: GNU General Public License (GPL), version 2.
 
6
 */
 
7
 
 
8
#include <linux/module.h>
 
9
#include <linux/kernel.h>
 
10
#include <linux/irq.h>
 
11
#include <linux/interrupt.h>
 
12
#include <linux/io.h>
 
13
#include <linux/slab.h>
 
14
 
 
15
#include <mach/id.h>
 
16
 
 
17
#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
 
18
#define MODEM_INTCON_SIZE 0xFFF
 
19
 
 
20
#define DEST_IRQ41_OFFSET 0x2A4
 
21
#define DEST_IRQ43_OFFSET 0x2AC
 
22
#define DEST_IRQ45_OFFSET 0x2B4
 
23
 
 
24
#define PRIO_IRQ41_OFFSET 0x6A4
 
25
#define PRIO_IRQ43_OFFSET 0x6AC
 
26
#define PRIO_IRQ45_OFFSET 0x6B4
 
27
 
 
28
#define ALLOW_IRQ_OFFSET 0x104
 
29
 
 
30
#define MODEM_INTCON_CPU_NBR 0x1
 
31
#define MODEM_INTCON_PRIO_HIGH 0x0
 
32
 
 
33
#define MODEM_INTCON_ALLOW_IRQ41 0x0200
 
34
#define MODEM_INTCON_ALLOW_IRQ43 0x0800
 
35
#define MODEM_INTCON_ALLOW_IRQ45 0x2000
 
36
 
 
37
#define MODEM_IRQ_REG_OFFSET 0x4
 
38
 
 
39
struct modem_irq {
 
40
        void __iomem *modem_intcon_base;
 
41
};
 
42
 
 
43
 
 
44
static void setup_modem_intcon(void __iomem *modem_intcon_base)
 
45
{
 
46
        /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
 
47
        writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
 
48
        writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
 
49
        writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
 
50
 
 
51
        /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
 
52
        writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
 
53
        writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
 
54
        writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
 
55
 
 
56
        /* IC_ALLOW_ARRAY - IRQ enable */
 
57
        writel(MODEM_INTCON_ALLOW_IRQ41 |
 
58
                   MODEM_INTCON_ALLOW_IRQ43 |
 
59
                   MODEM_INTCON_ALLOW_IRQ45,
 
60
                   modem_intcon_base + ALLOW_IRQ_OFFSET);
 
61
}
 
62
 
 
63
static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
 
64
{
 
65
        int real_irq;
 
66
        int virt_irq;
 
67
        struct modem_irq *mi = (struct modem_irq *)data;
 
68
 
 
69
        /* Read modem side IRQ number from modem IRQ controller */
 
70
        real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
 
71
        virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
 
72
 
 
73
        pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
 
74
                 "which will be 0x%X (%d) which translates to "
 
75
                 "virtual IRQ 0x%X (%d)!\n",
 
76
                   (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
 
77
                   real_irq,
 
78
                   real_irq & 0xFF,
 
79
                   real_irq & 0xFF,
 
80
                   virt_irq,
 
81
                   virt_irq);
 
82
 
 
83
        if (virt_irq != 0)
 
84
                generic_handle_irq(virt_irq);
 
85
 
 
86
        pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
 
87
 
 
88
        return IRQ_HANDLED;
 
89
}
 
90
 
 
91
static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
 
92
{
 
93
        irq_set_chip_and_handler(irq, modem_irq_chip, handle_simple_irq);
 
94
        set_irq_flags(irq, IRQF_VALID);
 
95
 
 
96
        pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
 
97
}
 
98
 
 
99
static int modem_irq_init(void)
 
100
{
 
101
        int err;
 
102
        static struct irq_chip  modem_irq_chip;
 
103
        struct modem_irq *mi;
 
104
 
 
105
        if (!cpu_is_u5500())
 
106
                return -ENODEV;
 
107
 
 
108
        pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
 
109
                   IRQ_DB5500_MODEM);
 
110
 
 
111
        mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
 
112
        if (!mi) {
 
113
                pr_err("modem_irq: Could not allocate device\n");
 
114
                return -ENOMEM;
 
115
        }
 
116
 
 
117
        mi->modem_intcon_base =
 
118
                ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
 
119
        pr_debug("modem_irq: ioremapped modem_intcon_base from "
 
120
                 "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
 
121
                 (u32)mi->modem_intcon_base);
 
122
 
 
123
        setup_modem_intcon(mi->modem_intcon_base);
 
124
 
 
125
        modem_irq_chip = dummy_irq_chip;
 
126
        modem_irq_chip.name = "modem_irq";
 
127
 
 
128
        /* Create the virtual IRQ:s needed */
 
129
        create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
 
130
        create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
 
131
        create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
 
132
 
 
133
        err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
 
134
                                   modem_cpu_irq_handler, IRQF_ONESHOT,
 
135
                                   "modem_irq", mi);
 
136
        if (err)
 
137
                pr_err("modem_irq: Could not register IRQ %d\n",
 
138
                       IRQ_DB5500_MODEM);
 
139
 
 
140
        return 0;
 
141
}
 
142
 
 
143
arch_initcall(modem_irq_init);