irq.c 3.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *  linux/arch/arm/mach-pxa/irq.c
 *
4
 *  Generic PXA IRQ handling
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 *  Author:	Nicolas Pitre
 *  Created:	Jun 15, 2001
 *  Copyright:	MontaVista Software Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
18
#include <linux/sysdev.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/arch/pxa-regs.h>

#include "generic.h"


/*
 * This is for peripheral IRQs internal to the PXA chip.
 */

static void pxa_mask_low_irq(unsigned int irq)
{
34
	ICMR &= ~(1 << irq);
L
Linus Torvalds 已提交
35 36 37 38
}

static void pxa_unmask_low_irq(unsigned int irq)
{
39
	ICMR |= (1 << irq);
L
Linus Torvalds 已提交
40 41
}

42 43
static struct irq_chip pxa_internal_chip_low = {
	.name		= "SC",
L
Linus Torvalds 已提交
44 45 46 47 48
	.ack		= pxa_mask_low_irq,
	.mask		= pxa_mask_low_irq,
	.unmask		= pxa_unmask_low_irq,
};

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
void __init pxa_init_irq_low(void)
{
	int irq;

	/* disable all IRQs */
	ICMR = 0;

	/* all IRQs are IRQ, not FIQ */
	ICLR = 0;

	/* only unmasked interrupts kick us out of idle */
	ICCR = 1;

	for (irq = PXA_IRQ(0); irq <= PXA_IRQ(31); irq++) {
		set_irq_chip(irq, &pxa_internal_chip_low);
		set_irq_handler(irq, handle_level_irq);
		set_irq_flags(irq, IRQF_VALID);
	}
}

E
eric miao 已提交
69
#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
L
Linus Torvalds 已提交
70 71 72 73 74 75 76

/*
 * This is for the second set of internal IRQs as found on the PXA27x.
 */

static void pxa_mask_high_irq(unsigned int irq)
{
77
	ICMR2 &= ~(1 << (irq - 32));
L
Linus Torvalds 已提交
78 79 80 81
}

static void pxa_unmask_high_irq(unsigned int irq)
{
82
	ICMR2 |= (1 << (irq - 32));
L
Linus Torvalds 已提交
83 84
}

85 86
static struct irq_chip pxa_internal_chip_high = {
	.name		= "SC-hi",
L
Linus Torvalds 已提交
87 88 89 90 91
	.ack		= pxa_mask_high_irq,
	.mask		= pxa_mask_high_irq,
	.unmask		= pxa_unmask_high_irq,
};

92 93 94 95 96 97 98 99 100 101 102 103 104
void __init pxa_init_irq_high(void)
{
	int irq;

	ICMR2 = 0;
	ICLR2 = 0;

	for (irq = PXA_IRQ(32); irq < PXA_IRQ(64); irq++) {
		set_irq_chip(irq, &pxa_internal_chip_high);
		set_irq_handler(irq, handle_level_irq);
		set_irq_flags(irq, IRQF_VALID);
	}
}
L
Linus Torvalds 已提交
105 106
#endif

107 108 109 110 111 112
void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
{
	pxa_internal_chip_low.set_wake = set_wake;
#ifdef CONFIG_PXA27x
	pxa_internal_chip_high.set_wake = set_wake;
#endif
113
	pxa_init_gpio_set_wake(set_wake);
114
}
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

#ifdef CONFIG_PM
static unsigned long saved_icmr[2];

static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
{
	switch (dev->id) {
	case 0:
		saved_icmr[0] = ICMR;
		ICMR = 0;
		break;
#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
	case 1:
		saved_icmr[1] = ICMR2;
		ICMR2 = 0;
		break;
#endif
	default:
		return -EINVAL;
	}

	return 0;
}

static int pxa_irq_resume(struct sys_device *dev)
{
	switch (dev->id) {
	case 0:
		ICMR = saved_icmr[0];
		ICLR = 0;
		ICCR = 1;
		break;
#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
	case 1:
		ICMR2 = saved_icmr[1];
		ICLR2 = 0;
		break;
#endif
	default:
		return -EINVAL;
	}

	return 0;
}
#else
#define pxa_irq_suspend		NULL
#define pxa_irq_resume		NULL
#endif

struct sysdev_class pxa_irq_sysclass = {
	.name		= "irq",
	.suspend	= pxa_irq_suspend,
	.resume		= pxa_irq_resume,
};

static int __init pxa_irq_init(void)
{
	return sysdev_class_register(&pxa_irq_sysclass);
}

core_initcall(pxa_irq_init);