irq.c 6.3 KB
Newer Older
Y
Yauhen Kharuzhy 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
/* linux/arch/arm/mach-s3c2416/irq.c
 *
 * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
 *	as part of OpenInkpot project
 * Copyright (c) 2009 Promwad Innovation Company
 *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
*/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/sysdev.h>
#include <linux/io.h>

#include <mach/hardware.h>
#include <asm/irq.h>

#include <asm/mach/irq.h>

#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>

#include <plat/cpu.h>
#include <plat/pm.h>
#include <plat/irq.h>

#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)

static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
{
	unsigned int subsrc, submsk;
	unsigned int end;

	/* read the current pending interrupts, and the mask
	 * for what it is available */

	subsrc = __raw_readl(S3C2410_SUBSRCPND);
	submsk = __raw_readl(S3C2410_INTSUBMSK);

	subsrc  &= ~submsk;
	subsrc >>= (irq - S3C2410_IRQSUB(0));
	subsrc  &= (1 << len)-1;

	end = len + irq;

	for (; irq < end && subsrc; irq++) {
		if (subsrc & 1)
			generic_handle_irq(irq);

		subsrc >>= 1;
	}
}

/* WDT/AC97 sub interrupts */

static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
{
	s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
}

#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)

80
static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
81
{
82
	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
Y
Yauhen Kharuzhy 已提交
83 84
}

85
static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
86
{
87
	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
Y
Yauhen Kharuzhy 已提交
88 89
}

90
static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
91
{
92
	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
Y
Yauhen Kharuzhy 已提交
93 94 95
}

static struct irq_chip s3c2416_irq_wdtac97 = {
96 97 98
	.irq_mask	= s3c2416_irq_wdtac97_mask,
	.irq_unmask	= s3c2416_irq_wdtac97_unmask,
	.irq_ack	= s3c2416_irq_wdtac97_ack,
Y
Yauhen Kharuzhy 已提交
99 100 101 102 103 104 105 106 107 108 109 110
};

/* LCD sub interrupts */

static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
{
	s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
}

#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)

111
static void s3c2416_irq_lcd_mask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
112
{
113
	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
Y
Yauhen Kharuzhy 已提交
114 115
}

116
static void s3c2416_irq_lcd_unmask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
117
{
118
	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
Y
Yauhen Kharuzhy 已提交
119 120
}

121
static void s3c2416_irq_lcd_ack(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
122
{
123
	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
Y
Yauhen Kharuzhy 已提交
124 125 126
}

static struct irq_chip s3c2416_irq_lcd = {
127 128 129
	.irq_mask	= s3c2416_irq_lcd_mask,
	.irq_unmask	= s3c2416_irq_lcd_unmask,
	.irq_ack	= s3c2416_irq_lcd_ack,
Y
Yauhen Kharuzhy 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142
};

/* DMA sub interrupts */

static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
{
	s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
}

#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)


143
static void s3c2416_irq_dma_mask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
144
{
145
	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
Y
Yauhen Kharuzhy 已提交
146 147
}

148
static void s3c2416_irq_dma_unmask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
149
{
150
	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
Y
Yauhen Kharuzhy 已提交
151 152
}

153
static void s3c2416_irq_dma_ack(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
154
{
155
	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
Y
Yauhen Kharuzhy 已提交
156 157 158
}

static struct irq_chip s3c2416_irq_dma = {
159 160 161
	.irq_mask	= s3c2416_irq_dma_mask,
	.irq_unmask	= s3c2416_irq_dma_unmask,
	.irq_ack	= s3c2416_irq_dma_ack,
Y
Yauhen Kharuzhy 已提交
162 163 164 165 166 167
};

/* UART3 sub interrupts */

static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
{
168
	s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
Y
Yauhen Kharuzhy 已提交
169 170 171
}

#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
172
#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
Y
Yauhen Kharuzhy 已提交
173

174
static void s3c2416_irq_uart3_mask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
175
{
176
	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
Y
Yauhen Kharuzhy 已提交
177 178
}

179
static void s3c2416_irq_uart3_unmask(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
180
{
181
	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
Y
Yauhen Kharuzhy 已提交
182 183
}

184
static void s3c2416_irq_uart3_ack(struct irq_data *data)
Y
Yauhen Kharuzhy 已提交
185
{
186
	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
Y
Yauhen Kharuzhy 已提交
187 188 189
}

static struct irq_chip s3c2416_irq_uart3 = {
190 191 192
	.irq_mask	= s3c2416_irq_uart3_mask,
	.irq_unmask	= s3c2416_irq_uart3_unmask,
	.irq_ack	= s3c2416_irq_uart3_ack,
Y
Yauhen Kharuzhy 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
};

/* IRQ initialisation code */

static int __init s3c2416_add_sub(unsigned int base,
				   void (*demux)(unsigned int,
						 struct irq_desc *),
				   struct irq_chip *chip,
				   unsigned int start, unsigned int end)
{
	unsigned int irqno;

	set_irq_chip(base, &s3c_irq_level_chip);
	set_irq_handler(base, handle_level_irq);
	set_irq_chained_handler(base, demux);

	for (irqno = start; irqno <= end; irqno++) {
		set_irq_chip(irqno, chip);
		set_irq_handler(irqno, handle_level_irq);
		set_irq_flags(irqno, IRQF_VALID);
	}

	return 0;
}

static int __init s3c2416_irq_add(struct sys_device *sysdev)
{
	printk(KERN_INFO "S3C2416: IRQ Support\n");

	s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
			IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);

	s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
			&s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);

	s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
			&s3c2416_irq_uart3,
			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);

	s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
			&s3c2416_irq_wdtac97,
			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);

	return 0;
}

static struct sysdev_driver s3c2416_irq_driver = {
	.add		= s3c2416_irq_add,
241 242
	.suspend	= s3c24xx_irq_suspend,
	.resume		= s3c24xx_irq_resume,
Y
Yauhen Kharuzhy 已提交
243 244 245 246 247 248 249 250 251
};

static int __init s3c2416_irq_init(void)
{
	return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_irq_driver);
}

arch_initcall(s3c2416_irq_init);