/*
 * linux/arch/arm/mach-pxa/mq1132.c
 *
 * MQ1132(+possibly others) support
 *
 * 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.
 *
 * All initialization functions provided here are intended to be called
 * from machine specific code with proper arguments when required.
  
  28/5/03	Martin Demin	Added
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>

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

#include <asm/hardware/mq1132.h>

//#include "mq1132.h"

#define MQ1132_IRQMASK(x)	(1 << (x - IRQ_MEDIAQ_START))


struct resource mq1132_resource = {
	.name	= "MediaQ 1132",
};

EXPORT_SYMBOL(mq1132_resource);


#define GPIO_AXIM_MEDIAQ 2
#define IRQ_NUM GPIO_2_80_TO_IRQ(GPIO_AXIM_MEDIAQ)
#define INT_MASK 0xFFFFFFF0
int gpio1_3_active_level[3]={0,0,0};

unsigned long *mq1132_map=NULL;
EXPORT_SYMBOL(mq1132_map);
/*
 * MediaQ interrupt support
 */
void mq1132_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs)
{
	unsigned long stat0,stat1;
//	printk("MediaQ chip IRQ DEMUX\n");
		int i;
again:
		stat1 = stat0 = IN02R;
#if 0
		if(!(stat0&(~(1<<7)))) goto skip;
		
		for (i = IRQ_MEDIAQ_START; stat0; i++, stat0 >>= 1)
			if (stat0 & 1)
//  Do not process GPIOs 0-2
			    if((i-IRQ_MEDIAQ_START<5)||(i-IRQ_MEDIAQ_START>7))
				do_IRQ(i, regs);
skip:
#endif
		if((stat1>>7)&&1)
		{
		    if(((IN00R>>4)&1)==gpio1_3_active_level[2])
		    {
			if(((CC02R>>11)&1)==((IN00R>>4)&1))
			    IN00R^=0x00000010;
			IN02R = 0xFFFFFFFF;
			IN01R =	INT_MASK;
			do_IRQ(7+IRQ_MEDIAQ_START,regs);
		    }
			else
		    {
			if(((CC02R>>11)&1)==((IN00R>>4)&1))
			{
			    IN00R^= 0x00000010;
			    IN02R = 0xFFFFFFFF;
			    IN01R = INT_MASK;
			}
			else
			{
			    IN02R = 0xFFFFFFFF;
			    IN01R = INT_MASK;
			    do_IRQ(7+IRQ_MEDIAQ_START,regs);
			}
		    }	
		    
		}

		stat1=IN02R & 0x00000080;
		if(stat1) goto again;
		

}

static struct irqaction mq1132_irq = {
	name:     "MediaQ",
	handler:  mq1132_IRQ_demux,
	flags:    SA_INTERRUPT
};

// Dunno what to do ???
static void mq1132_mask_and_ack_irq(unsigned int irq)
{
	unsigned int mask = MQ1132_IRQMASK(irq);

	//INTEN0 &= ~mask;
//	INTSTATCLR0 = mask;
}


static void mq1132_mask_irq(unsigned int irq)
{
//	IN01R &= ~MQ1132_IRQMASK(irq);
}


static void mq1132_unmask_irq(unsigned int irq)
{
//	IN01R |= MQ1132_IRQMASK(irq);
}

int mq1132_init_irq()
{
    int ret=0,irq;
/*    ret = request_irq(IRQ_NUM, mq1132_IRQ_demux, SA_INTERRUPT,
			  "MediaQ", NULL);*/
    set_GPIO_IRQ_edge( GPIO_AXIM_MEDIAQ, GPIO_BOTH_EDGES );
    ret=setup_arm_irq( IRQ_NUM, &mq1132_irq );
    			  
    for (irq = IRQ_MEDIAQ_START; irq <= MEDIAQ_IRQ_MAX; irq++) {
	irq_desc[irq].valid	= 1;
	irq_desc[irq].probe_ok	= 1;
	irq_desc[irq].mask_ack	= mq1132_mask_and_ack_irq;
	irq_desc[irq].mask	= mq1132_mask_irq;
	irq_desc[irq].unmask	= mq1132_unmask_irq;
    }



    IN01R = INT_MASK;
    IN02R = 0xFFFFFFFF;
    return ret;
}

int mq1132_init()
{
    mq1132_map=0xf4000000;
//    printk("MediaQ mapped to 0x%x\n",mq1132_map);

    if(!mq1132_map) return 1;
    if(machine_is_axim())
    {
	// set up GPIOs
	CC00R=0x0; // enable cache that is for some reason disable in PPC
	CC01R=0x3;
	CC02R=0x9a0;
	CC03R=0xaaa02200; // all GPIOs are unknown but one see axim.txt
	SP08R=0x2FFC49;
    }

    if(mq1132_init_irq()) return 1;
    printk("MediaQ chip is initialized: IRQ=%d\tmap=0x%x\n",IRQ_NUM,mq1132_map);
    
    return 0;
}

EXPORT_SYMBOL(mq1132_init);