OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [sh/] [kernel/] [setup_ec3104.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/arch/sh/kernel/setup_ec3104.c
3
 *  EC3104 companion chip support
4
 *
5
 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
6
 *
7
 */
8
/* EC3104 note:
9
 * This code was written without any documentation about the EC3104 chip.  While
10
 * I hope I got most of the basic functionality right, the register names I use
11
 * are most likely completely different from those in the chip documentation.
12
 *
13
 * If you have any further information about the EC3104, please tell me
14
 * (prumpf@tux.org).
15
 */
16
 
17
#include <linux/sched.h>
18
#include <linux/kernel.h>
19
#include <linux/param.h>
20
#include <linux/interrupt.h>
21
#include <linux/init.h>
22
#include <linux/irq.h>
23
#include <linux/types.h>
24
 
25
#include <asm/io.h>
26
#include <asm/irq.h>
27
#include <asm/ec3104.h>
28
 
29
/* This is for debugging mostly;  here's the table that I intend to keep
30
 * in here:
31
 *
32
 *   index      function        base addr       power           interrupt bit
33
 *       0      power           b0ec0000        ---             00000001 (unused)
34
 *       1      irqs            b0ec1000        ---             00000002 (unused)
35
 *       2      ??              b0ec2000        b0ec0008        00000004
36
 *       3      PS2 (1)         b0ec3000        b0ec000c        00000008
37
 *       4      PS2 (2)         b0ec4000        b0ec0010        00000010
38
 *       5      ??              b0ec5000        b0ec0014        00000020
39
 *       6      I2C             b0ec6000        b0ec0018        00000040
40
 *       7      serial (1)      b0ec7000        b0ec001c        00000080
41
 *       8      serial (2)      b0ec8000        b0ec0020        00000100
42
 *       9      serial (3)      b0ec9000        b0ec0024        00000200
43
 *      10      serial (4)      b0eca000        b0ec0028        00000400
44
 *      12      GPIO (1)        b0ecc000        b0ec0030
45
 *      13      GPIO (2)        b0ecc000        b0ec0030
46
 *      16      pcmcia (1)      b0ed0000        b0ec0040        00010000
47
 *      17      pcmcia (2)      b0ed1000        b0ec0044        00020000
48
 */
49
 
50
/* I used the register names from another interrupt controller I worked with,
51
 * since it seems to be identical to the ec3104 except that all bits are
52
 * inverted:
53
 *
54
 * IRR: Interrupt Request Register (pending and enabled interrupts)
55
 * IMR: Interrupt Mask Register (which interrupts are enabled)
56
 * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
57
 *
58
 * 0 bits mean pending or enabled, 1 bits mean not pending or disabled.  all
59
 * IRQs seem to be level-triggered.
60
 */
61
 
62
#define EC3104_IRR (EC3104_BASE + 0x1000)
63
#define EC3104_IMR (EC3104_BASE + 0x1004)
64
#define EC3104_IPR (EC3104_BASE + 0x1008)
65
 
66
#define ctrl_readl(addr) (*(volatile u32 *)(addr))
67
#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
68
#define ctrl_readb(addr) (*(volatile u8 *)(addr))
69
 
70
static char *ec3104_name(unsigned index)
71
{
72
        switch(index) {
73
        case 0:
74
                return "power management";
75
        case 1:
76
                return "interrupts";
77
        case 3:
78
                return "PS2 (1)";
79
        case 4:
80
                return "PS2 (2)";
81
        case 5:
82
                return "I2C (1)";
83
        case 6:
84
                return "I2C (2)";
85
        case 7:
86
                return "serial (1)";
87
        case 8:
88
                return "serial (2)";
89
        case 9:
90
                return "serial (3)";
91
        case 10:
92
                return "serial (4)";
93
        case 16:
94
                return "pcmcia (1)";
95
        case 17:
96
                return "pcmcia (2)";
97
        default: {
98
                static char buf[32];
99
 
100
                sprintf(buf, "unknown (%d)", index);
101
 
102
                return buf;
103
                }
104
        }
105
}
106
 
107
int get_pending_interrupts(char *buf)
108
{
109
        u32 ipr;
110
        u32 bit;
111
        char *p = buf;
112
 
113
        p += sprintf(p, "pending: (");
114
 
115
        ipr = ctrl_inl(EC3104_IPR);
116
 
117
        for (bit = 1; bit < 32; bit++)
118
                if (!(ipr & (1<<bit)))
119
                        p += sprintf(p, "%s ", ec3104_name(bit));
120
 
121
        p += sprintf(p, ")\n");
122
 
123
        return p - buf;
124
}
125
 
126
static inline u32 ec3104_irq2mask(unsigned int irq)
127
{
128
        return (1 << (irq - EC3104_IRQBASE));
129
}
130
 
131
static inline void mask_ec3104_irq(unsigned int irq)
132
{
133
        u32 mask;
134
 
135
        mask = ctrl_readl(EC3104_IMR);
136
 
137
        mask |= ec3104_irq2mask(irq);
138
 
139
        ctrl_writel(mask, EC3104_IMR);
140
}
141
 
142
static inline void unmask_ec3104_irq(unsigned int irq)
143
{
144
        u32 mask;
145
 
146
        mask = ctrl_readl(EC3104_IMR);
147
 
148
        mask &= ~ec3104_irq2mask(irq);
149
 
150
        ctrl_writel(mask, EC3104_IMR);
151
}
152
 
153
static void disable_ec3104_irq(unsigned int irq)
154
{
155
        mask_ec3104_irq(irq);
156
}
157
 
158
static void enable_ec3104_irq(unsigned int irq)
159
{
160
        unmask_ec3104_irq(irq);
161
}
162
 
163
static void mask_and_ack_ec3104_irq(unsigned int irq)
164
{
165
        mask_ec3104_irq(irq);
166
}
167
 
168
static void end_ec3104_irq(unsigned int irq)
169
{
170
        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
171
                unmask_ec3104_irq(irq);
172
}
173
 
174
static unsigned int startup_ec3104_irq(unsigned int irq)
175
{
176
        unmask_ec3104_irq(irq);
177
 
178
        return 0;
179
}
180
 
181
static void shutdown_ec3104_irq(unsigned int irq)
182
{
183
        mask_ec3104_irq(irq);
184
 
185
}
186
 
187
static struct hw_interrupt_type ec3104_int = {
188
        typename:       "EC3104",
189
        enable:         enable_ec3104_irq,
190
        disable:        disable_ec3104_irq,
191
        ack:            mask_and_ack_ec3104_irq,
192
        end:            end_ec3104_irq,
193
        startup:        startup_ec3104_irq,
194
        shutdown:       shutdown_ec3104_irq,
195
};
196
 
197
/* Yuck.  the _demux API is ugly */
198
int ec3104_irq_demux(int irq)
199
{
200
        if (irq == EC3104_IRQ) {
201
                unsigned int mask;
202
 
203
                mask = ctrl_readl(EC3104_IRR);
204
 
205
                if (mask == 0xffffffff)
206
                        return EC3104_IRQ;
207
                else
208
                        return EC3104_IRQBASE + ffz(mask);
209
        }
210
 
211
        return irq;
212
}
213
 
214
int __init setup_ec3104(void)
215
{
216
        char str[8];
217
        int i;
218
 
219
        if (!MACH_EC3104)
220
                printk("!MACH_EC3104\n");
221
 
222
        if (0)
223
                return 0;
224
 
225
        for (i=0; i<8; i++)
226
                str[i] = ctrl_readb(EC3104_BASE + i);
227
 
228
        for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
229
                irq_desc[i].handler = &ec3104_int;
230
 
231
        printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
232
               str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
233
 
234
 
235
        /* mask all interrupts.  this should have been done by the boot
236
         * loader for us but we want to be sure ... */
237
        ctrl_writel(0xffffffff, EC3104_IMR);
238
 
239
        return 0;
240
}
241
 
242
module_init(setup_ec3104);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.