setup_ec3104.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
- /*
- * linux/arch/sh/kernel/setup_ec3104.c
- * EC3104 companion chip support
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- */
- /* EC3104 note:
- * This code was written without any documentation about the EC3104 chip. While
- * I hope I got most of the basic functionality right, the register names I use
- * are most likely completely different from those in the chip documentation.
- *
- * If you have any further information about the EC3104, please tell me
- * (prumpf@tux.org).
- */
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/param.h>
- #include <linux/interrupt.h>
- #include <linux/init.h>
- #include <linux/irq.h>
- #include <linux/types.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/ec3104.h>
- /* This is for debugging mostly; here's the table that I intend to keep
- * in here:
- *
- * index function base addr power interrupt bit
- * 0 power b0ec0000 --- 00000001 (unused)
- * 1 irqs b0ec1000 --- 00000002 (unused)
- * 2 ?? b0ec2000 b0ec0008 00000004
- * 3 PS2 (1) b0ec3000 b0ec000c 00000008
- * 4 PS2 (2) b0ec4000 b0ec0010 00000010
- * 5 ?? b0ec5000 b0ec0014 00000020
- * 6 I2C b0ec6000 b0ec0018 00000040
- * 7 serial (1) b0ec7000 b0ec001c 00000080
- * 8 serial (2) b0ec8000 b0ec0020 00000100
- * 9 serial (3) b0ec9000 b0ec0024 00000200
- * 10 serial (4) b0eca000 b0ec0028 00000400
- * 12 GPIO (1) b0ecc000 b0ec0030
- * 13 GPIO (2) b0ecc000 b0ec0030
- * 16 pcmcia (1) b0ed0000 b0ec0040 00010000
- * 17 pcmcia (2) b0ed1000 b0ec0044 00020000
- */
- /* I used the register names from another interrupt controller I worked with,
- * since it seems to be identical to the ec3104 except that all bits are
- * inverted:
- *
- * IRR: Interrupt Request Register (pending and enabled interrupts)
- * IMR: Interrupt Mask Register (which interrupts are enabled)
- * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
- *
- * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all
- * IRQs seem to be level-triggered.
- */
- #define EC3104_IRR (EC3104_BASE + 0x1000)
- #define EC3104_IMR (EC3104_BASE + 0x1004)
- #define EC3104_IPR (EC3104_BASE + 0x1008)
- #define ctrl_readl(addr) (*(volatile u32 *)(addr))
- #define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
- #define ctrl_readb(addr) (*(volatile u8 *)(addr))
- static char *ec3104_name(unsigned index)
- {
- switch(index) {
- case 0:
- return "power management";
- case 1:
- return "interrupts";
- case 3:
- return "PS2 (1)";
- case 4:
- return "PS2 (2)";
- case 5:
- return "I2C (1)";
- case 6:
- return "I2C (2)";
- case 7:
- return "serial (1)";
- case 8:
- return "serial (2)";
- case 9:
- return "serial (3)";
- case 10:
- return "serial (4)";
- case 16:
- return "pcmcia (1)";
- case 17:
- return "pcmcia (2)";
- default: {
- static char buf[32];
-
- sprintf(buf, "unknown (%d)", index);
- return buf;
- }
- }
- }
- int get_pending_interrupts(char *buf)
- {
- u32 ipr;
- u32 bit;
- char *p = buf;
- p += sprintf(p, "pending: (");
-
- ipr = ctrl_inl(EC3104_IPR);
- for (bit = 1; bit < 32; bit++)
- if (!(ipr & (1<<bit)))
- p += sprintf(p, "%s ", ec3104_name(bit));
-
- p += sprintf(p, ")n");
- return p - buf;
- }
-
- static inline u32 ec3104_irq2mask(unsigned int irq)
- {
- return (1 << (irq - EC3104_IRQBASE));
- }
- static inline void mask_ec3104_irq(unsigned int irq)
- {
- u32 mask;
- mask = ctrl_readl(EC3104_IMR);
- mask |= ec3104_irq2mask(irq);
-
- ctrl_writel(mask, EC3104_IMR);
- }
-
- static inline void unmask_ec3104_irq(unsigned int irq)
- {
- u32 mask;
- mask = ctrl_readl(EC3104_IMR);
- mask &= ~ec3104_irq2mask(irq);
-
- ctrl_writel(mask, EC3104_IMR);
- }
-
- static void disable_ec3104_irq(unsigned int irq)
- {
- mask_ec3104_irq(irq);
- }
- static void enable_ec3104_irq(unsigned int irq)
- {
- unmask_ec3104_irq(irq);
- }
- static void mask_and_ack_ec3104_irq(unsigned int irq)
- {
- mask_ec3104_irq(irq);
- }
- static void end_ec3104_irq(unsigned int irq)
- {
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- unmask_ec3104_irq(irq);
- }
- static unsigned int startup_ec3104_irq(unsigned int irq)
- {
- unmask_ec3104_irq(irq);
- return 0;
- }
- static void shutdown_ec3104_irq(unsigned int irq)
- {
- mask_ec3104_irq(irq);
- }
- static struct hw_interrupt_type ec3104_int = {
- typename: "EC3104",
- enable: enable_ec3104_irq,
- disable: disable_ec3104_irq,
- ack: mask_and_ack_ec3104_irq,
- end: end_ec3104_irq,
- startup: startup_ec3104_irq,
- shutdown: shutdown_ec3104_irq,
- };
- /* Yuck. the _demux API is ugly */
- int ec3104_irq_demux(int irq)
- {
- if (irq == EC3104_IRQ) {
- unsigned int mask;
- mask = ctrl_readl(EC3104_IRR);
- if (mask == 0xffffffff)
- return EC3104_IRQ;
- else
- return EC3104_IRQBASE + ffz(mask);
- }
- return irq;
- }
- int __init setup_ec3104(void)
- {
- char str[8];
- int i;
-
- if (!MACH_EC3104)
- printk("!MACH_EC3104n");
- if (0)
- return 0;
- for (i=0; i<8; i++)
- str[i] = ctrl_readb(EC3104_BASE + i);
- for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
- irq_desc[i].handler = &ec3104_int;
- printk("initializing EC3104 "%.8s" at %08x, IRQ %d, IRQ base %dn",
- str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
- /* mask all interrupts. this should have been done by the boot
- * loader for us but we want to be sure ... */
- ctrl_writel(0xffffffff, EC3104_IMR);
-
- return 0;
- }
- module_init(setup_ec3104);