irq-s3c2416.c 8.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
/* 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>
28
#include <linux/device.h>
Y
Yauhen Kharuzhy 已提交
29
#include <linux/io.h>
30
#include <linux/syscore_ops.h>
Y
Yauhen Kharuzhy 已提交
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 80

#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)

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

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

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

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

/* 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)

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

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

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

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

/* 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)


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

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

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

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

/* UART3 sub interrupts */

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

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

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

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

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

static struct irq_chip s3c2416_irq_uart3 = {
191 192 193
	.irq_mask	= s3c2416_irq_uart3_mask,
	.irq_unmask	= s3c2416_irq_uart3_unmask,
	.irq_ack	= s3c2416_irq_uart3_ack,
Y
Yauhen Kharuzhy 已提交
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
/* second interrupt register */

static inline void s3c2416_irq_ack_second(struct irq_data *data)
{
	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);

	__raw_writel(bitval, S3C2416_SRCPND2);
	__raw_writel(bitval, S3C2416_INTPND2);
}

static void s3c2416_irq_mask_second(struct irq_data *data)
{
	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
	unsigned long mask;

	mask = __raw_readl(S3C2416_INTMSK2);
	mask |= bitval;
	__raw_writel(mask, S3C2416_INTMSK2);
}

static void s3c2416_irq_unmask_second(struct irq_data *data)
{
	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
	unsigned long mask;

	mask = __raw_readl(S3C2416_INTMSK2);
	mask &= ~bitval;
	__raw_writel(mask, S3C2416_INTMSK2);
}

struct irq_chip s3c2416_irq_second = {
	.irq_ack	= s3c2416_irq_ack_second,
	.irq_mask	= s3c2416_irq_mask_second,
	.irq_unmask	= s3c2416_irq_unmask_second,
};


Y
Yauhen Kharuzhy 已提交
233 234
/* IRQ initialisation code */

235
static int s3c2416_add_sub(unsigned int base,
Y
Yauhen Kharuzhy 已提交
236 237 238 239 240 241 242
				   void (*demux)(unsigned int,
						 struct irq_desc *),
				   struct irq_chip *chip,
				   unsigned int start, unsigned int end)
{
	unsigned int irqno;

243
	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
T
Thomas Gleixner 已提交
244
	irq_set_chained_handler(base, demux);
Y
Yauhen Kharuzhy 已提交
245 246

	for (irqno = start; irqno <= end; irqno++) {
247
		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
Y
Yauhen Kharuzhy 已提交
248 249 250 251 252 253
		set_irq_flags(irqno, IRQF_VALID);
	}

	return 0;
}

254
static void s3c2416_irq_add_second(void)
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
{
	unsigned long pend;
	unsigned long last;
	int irqno;
	int i;

	/* first, clear all interrupts pending... */
	last = 0;
	for (i = 0; i < 4; i++) {
		pend = __raw_readl(S3C2416_INTPND2);

		if (pend == 0 || pend == last)
			break;

		__raw_writel(pend, S3C2416_SRCPND2);
		__raw_writel(pend, S3C2416_INTPND2);
		printk(KERN_INFO "irq: clearing pending status %08x\n",
		       (int)pend);
		last = pend;
	}

	for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
		switch (irqno) {
		case IRQ_S3C2416_RESERVED2:
		case IRQ_S3C2416_RESERVED3:
			/* no IRQ here */
			break;
		default:
			irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
						 handle_edge_irq);
			set_irq_flags(irqno, IRQF_VALID);
		}
	}
}

290
static int s3c2416_irq_add(struct device *dev,
291
				  struct subsys_interface *sif)
Y
Yauhen Kharuzhy 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
{
	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);

309 310
	s3c2416_irq_add_second();

Y
Yauhen Kharuzhy 已提交
311 312 313
	return 0;
}

314 315 316 317
static struct subsys_interface s3c2416_irq_interface = {
	.name		= "s3c2416_irq",
	.subsys		= &s3c2416_subsys,
	.add_dev	= s3c2416_irq_add,
Y
Yauhen Kharuzhy 已提交
318 319 320 321
};

static int __init s3c2416_irq_init(void)
{
322
	return subsys_interface_register(&s3c2416_irq_interface);
Y
Yauhen Kharuzhy 已提交
323 324 325 326
}

arch_initcall(s3c2416_irq_init);

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
#ifdef CONFIG_PM
static struct sleep_save irq_save[] = {
	SAVE_ITEM(S3C2416_INTMSK2),
};

int s3c2416_irq_suspend(void)
{
	s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));

	return 0;
}

void s3c2416_irq_resume(void)
{
	s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
}

struct syscore_ops s3c2416_irq_syscore_ops = {
	.suspend	= s3c2416_irq_suspend,
	.resume		= s3c2416_irq_resume,
};
#endif