/*
 *  linux/arch/arm/mach-dm310/irq.c
 *
 *  Copyright (C) 2002 Matthias Welwarsky
 *
 * 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/types.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach/irq.h>
#include <asm/arch/irq.h>


void __init irq_init_irq(void)
{
	int irq;

	/* disable all */
	outw(0, DM310_FIQ_ENABLE);
	outw(0, DM310_IRQ0_ENABLE);
	outw(0, DM310_IRQ1_ENABLE);
	outw(0, DM310_IRQ2_ENABLE);
	
	/* clear all status */
	outw(0xffff, DM310_IRQ0_STATUS);
	outw(0xffff, DM310_IRQ1_STATUS);
	outw(0xffff, DM310_IRQ2_STATUS);
	
	for (irq = 0; irq < NR_IRQS; irq++) {
		irq_desc[irq].valid	= 1;
		irq_desc[irq].probe_ok	= 1;
		irq_desc[irq].mask_ack	= dm310_mask_ack_irq;
		irq_desc[irq].mask	= dm310_mask_irq;
		irq_desc[irq].unmask	= dm310_unmask_irq;
	}

	/* INTIDIR only reflects pending interrupts */
	outw(0, DM310_MINTIDIR);
}

/* tables to map IRQ numbers to registers / bit positions */
 
u32 irq_status_map[NR_IRQS] = {
        DM310_IRQ1_STATUS, 
        DM310_IRQ1_STATUS, 
        DM310_IRQ1_STATUS, 
        DM310_IRQ1_STATUS, 
        DM310_IRQ1_STATUS, 
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS,
        DM310_IRQ1_STATUS, /* DM310_IRQ_USB     */
        0,                 /* reserved          */
	DM310_IRQ1_STATUS, /* DM310_IRQ_EXBC    */
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS,
        DM310_IRQ0_STATUS, /* DM310_IRQ_FLRDY  */
        DM310_IRQ2_STATUS, /* DM310_IRQ_USBHOST */
        DM310_IRQ2_STATUS, /* DM310_IRQ_PREVIEW */
        DM310_IRQ2_STATUS, /* DM310_IRQ_MMCSD  */
        DM310_IRQ2_STATUS  /* DM310_IRQ_MSTICK */
};

u32 irq_enable_map[NR_IRQS] = {
        DM310_IRQ1_ENABLE, 
        DM310_IRQ1_ENABLE, 
        DM310_IRQ1_ENABLE, 
        DM310_IRQ1_ENABLE, 
        DM310_IRQ1_ENABLE, 
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE,
        DM310_IRQ1_ENABLE, /* DM310_IRQ_USB     */
	0, 		   /* reserved          */
        DM310_IRQ1_ENABLE, /* DM310_IRQ_EXBC    */
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE,
        DM310_IRQ0_ENABLE, /* DM310_IRQ_FLRDY  */
        DM310_IRQ2_ENABLE, /* DM310_IRQ_USBHOST */
        DM310_IRQ2_ENABLE, /* DM310_IRQ_PREVIEW */
        DM310_IRQ2_ENABLE, /* DM310_IRQ_MMCSD  */
        DM310_IRQ2_ENABLE  /* DM310_IRQ_MSTICK */
};

u32 irq_bitpos_map[NR_IRQS] = {
        DM310_IRQ1POS_TIMER0 ,
        DM310_IRQ1POS_TIMER1 ,
        DM310_IRQ1POS_TIMER2 , 
        DM310_IRQ1POS_TIMER3 ,
        DM310_IRQ1POS_CCDVD0 ,
        DM310_IRQ1POS_CCDVD1 ,
        DM310_IRQ1POS_CCDVD2 ,
        DM310_IRQ1POS_ENCVD  ,
        DM310_IRQ1POS_SERIAL0,
        DM310_IRQ1POS_SERIAL1,
        DM310_IRQ1POS_DSP    ,
        DM310_IRQ1POS_UART0  ,
        DM310_IRQ1POS_UART1  ,
        DM310_IRQ1POS_USB    ,
	0		     , /* reserved */
        DM310_IRQ1POS_EXBC   ,
        DM310_IRQ0POS_EXT0   ,
        DM310_IRQ0POS_EXT1   ,
        DM310_IRQ0POS_EXT2   ,
        DM310_IRQ0POS_EXT3   ,
        DM310_IRQ0POS_EXT4   ,
        DM310_IRQ0POS_EXT5   ,
        DM310_IRQ0POS_EXT6   ,
        DM310_IRQ0POS_EXT7   ,
        DM310_IRQ0POS_EXDMA  ,
        DM310_IRQ0POS_FLRDY  ,
        DM310_IRQ2POS_USBHOST,
        DM310_IRQ2POS_PREVIEW,
        DM310_IRQ2POS_MMCSD  ,
        DM310_IRQ2POS_MSTICK
};

void dm310_mask_irq(unsigned int irq)
{
        register u32 reg, pos;
	
	reg = irq_enable_map[irq];
	pos = irq_bitpos_map[irq];
	
        outw(inw(reg) & ~pos, reg);
// 	if (irq)
// 	 	printk("mask_irq(%u), %08x<-%08x\n", irq, reg, inw(reg));
}	

void dm310_unmask_irq(unsigned int irq)
{
        register u32 reg, pos;
	
	reg = irq_enable_map[irq];
	pos = irq_bitpos_map[irq];
	
        outw(inw(reg) | pos, reg);
// 	if (irq)
// 		printk("unmask_irq(%u), %08x<-%08x\n", irq, reg, inw(reg));
}

void dm310_mask_ack_irq(unsigned int irq)
{
	register u32 reg, pos;
	
	reg = irq_status_map[irq];
	pos = irq_bitpos_map[irq];
		
	dm310_mask_irq(irq);
	outw(pos, reg);
// 	if (irq)
// 		printk("mask_ack_irq(%u), %08x<-%08x\n", irq, reg, inw(reg));
}
