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

« back to all changes in this revision

Viewing changes to arch/powerpc/platforms/512x/mpc5121_ads_cpld.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) 2008 Freescale Semiconductor, Inc. All rights reserved.
 
3
 *
 
4
 * Author: John Rigby, <jrigby@freescale.com>
 
5
 *
 
6
 * Description:
 
7
 * MPC5121ADS CPLD irq handling
 
8
 *
 
9
 * This is free software; you can redistribute it and/or modify it
 
10
 * under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 */
 
14
 
 
15
#undef DEBUG
 
16
 
 
17
#include <linux/kernel.h>
 
18
#include <linux/interrupt.h>
 
19
#include <linux/irq.h>
 
20
#include <linux/io.h>
 
21
#include <asm/prom.h>
 
22
 
 
23
static struct device_node *cpld_pic_node;
 
24
static struct irq_host *cpld_pic_host;
 
25
 
 
26
/*
 
27
 * Bits to ignore in the misc_status register
 
28
 * 0x10 touch screen pendown is hard routed to irq1
 
29
 * 0x02 pci status is read from pci status register
 
30
 */
 
31
#define MISC_IGNORE 0x12
 
32
 
 
33
/*
 
34
 * Nothing to ignore in pci status register
 
35
 */
 
36
#define PCI_IGNORE 0x00
 
37
 
 
38
struct cpld_pic {
 
39
        u8 pci_mask;
 
40
        u8 pci_status;
 
41
        u8 route;
 
42
        u8 misc_mask;
 
43
        u8 misc_status;
 
44
        u8 misc_control;
 
45
};
 
46
 
 
47
static struct cpld_pic __iomem *cpld_regs;
 
48
 
 
49
static void __iomem *
 
50
irq_to_pic_mask(unsigned int irq)
 
51
{
 
52
        return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask;
 
53
}
 
54
 
 
55
static unsigned int
 
56
irq_to_pic_bit(unsigned int irq)
 
57
{
 
58
        return 1 << (irq & 0x7);
 
59
}
 
60
 
 
61
static void
 
62
cpld_mask_irq(struct irq_data *d)
 
63
{
 
64
        unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
 
65
        void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
 
66
 
 
67
        out_8(pic_mask,
 
68
              in_8(pic_mask) | irq_to_pic_bit(cpld_irq));
 
69
}
 
70
 
 
71
static void
 
72
cpld_unmask_irq(struct irq_data *d)
 
73
{
 
74
        unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
 
75
        void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
 
76
 
 
77
        out_8(pic_mask,
 
78
              in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq));
 
79
}
 
80
 
 
81
static struct irq_chip cpld_pic = {
 
82
        .name = "CPLD PIC",
 
83
        .irq_mask = cpld_mask_irq,
 
84
        .irq_ack = cpld_mask_irq,
 
85
        .irq_unmask = cpld_unmask_irq,
 
86
};
 
87
 
 
88
static int
 
89
cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
 
90
                            u8 __iomem *maskp)
 
91
{
 
92
        int cpld_irq;
 
93
        u8 status = in_8(statusp);
 
94
        u8 mask = in_8(maskp);
 
95
 
 
96
        /* ignore don't cares and masked irqs */
 
97
        status |= (ignore | mask);
 
98
 
 
99
        if (status == 0xff)
 
100
                return NO_IRQ;
 
101
 
 
102
        cpld_irq = ffz(status) + offset;
 
103
 
 
104
        return irq_linear_revmap(cpld_pic_host, cpld_irq);
 
105
}
 
106
 
 
107
static void
 
108
cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
 
109
{
 
110
        irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
 
111
                &cpld_regs->pci_mask);
 
112
        if (irq != NO_IRQ) {
 
113
                generic_handle_irq(irq);
 
114
                return;
 
115
        }
 
116
 
 
117
        irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
 
118
                &cpld_regs->misc_mask);
 
119
        if (irq != NO_IRQ) {
 
120
                generic_handle_irq(irq);
 
121
                return;
 
122
        }
 
123
}
 
124
 
 
125
static int
 
126
cpld_pic_host_match(struct irq_host *h, struct device_node *node)
 
127
{
 
128
        return cpld_pic_node == node;
 
129
}
 
130
 
 
131
static int
 
132
cpld_pic_host_map(struct irq_host *h, unsigned int virq,
 
133
                             irq_hw_number_t hw)
 
134
{
 
135
        irq_set_status_flags(virq, IRQ_LEVEL);
 
136
        irq_set_chip_and_handler(virq, &cpld_pic, handle_level_irq);
 
137
        return 0;
 
138
}
 
139
 
 
140
static struct
 
141
irq_host_ops cpld_pic_host_ops = {
 
142
        .match = cpld_pic_host_match,
 
143
        .map = cpld_pic_host_map,
 
144
};
 
145
 
 
146
void __init
 
147
mpc5121_ads_cpld_map(void)
 
148
{
 
149
        struct device_node *np = NULL;
 
150
 
 
151
        np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
 
152
        if (!np) {
 
153
                printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
 
154
                return;
 
155
        }
 
156
 
 
157
        cpld_regs = of_iomap(np, 0);
 
158
        of_node_put(np);
 
159
}
 
160
 
 
161
void __init
 
162
mpc5121_ads_cpld_pic_init(void)
 
163
{
 
164
        unsigned int cascade_irq;
 
165
        struct device_node *np = NULL;
 
166
 
 
167
        pr_debug("cpld_ic_init\n");
 
168
 
 
169
        np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
 
170
        if (!np) {
 
171
                printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
 
172
                return;
 
173
        }
 
174
 
 
175
        if (!cpld_regs)
 
176
                goto end;
 
177
 
 
178
        cascade_irq = irq_of_parse_and_map(np, 0);
 
179
        if (cascade_irq == NO_IRQ)
 
180
                goto end;
 
181
 
 
182
        /*
 
183
         * statically route touch screen pendown through 1
 
184
         * and ignore it here
 
185
         * route all others through our cascade irq
 
186
         */
 
187
        out_8(&cpld_regs->route, 0xfd);
 
188
        out_8(&cpld_regs->pci_mask, 0xff);
 
189
        /* unmask pci ints in misc mask */
 
190
        out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE));
 
191
 
 
192
        cpld_pic_node = of_node_get(np);
 
193
 
 
194
        cpld_pic_host =
 
195
            irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16);
 
196
        if (!cpld_pic_host) {
 
197
                printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
 
198
                goto end;
 
199
        }
 
200
 
 
201
        irq_set_chained_handler(cascade_irq, cpld_pic_cascade);
 
202
end:
 
203
        of_node_put(np);
 
204
}