/*
 * linux/drivers/pcmcia/pxa/pxa_axim.c
 *
 * 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.
 *
 * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved
 * 
 * Platform specific routines for the Accelent PXA250 axim, based on those
 * first done for the Lubbock.
 *
 * Version 1.0 2002-05-02  Jeff Sutherland <jeffs@accelent.com>
 * TODO: Correct shutdown and power deapply from socket
 *
 */

#include <linux/kernel.h>
#include <linux/sched.h>

#include <pcmcia/ss.h>

#include <asm/delay.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>

#include <asm/mach/irq.h>
#include <asm/arch/irqs.h>
#include <linux/module.h>
#include <asm/hardware/mq1132.h>


#define AXIM_PCMCIA_SOCK0_IRQ 1
#define AXIM_PCMCIA_RDY_GPIO  8
#define AXIM_PCMCIA_INS_GPIO  7


//int test[]={15,16,17,20,21,22,23,24,25,0};
//int test[]={16,19,0};
//int test[]={16,21,22,0};
//int gpio=0;
//MODULE_PARM(gpio, "i");
//int test[]={3,4,5,6,9,10,11,12,13,14,21,25,27,59,61,64,65,66,67,68,69,70,75,76,77,0};
/*int test[]={27,33,0};
int test[]={42,44,0};
int test[]={45,58,0};
int test[]={59,29,0};
int test[]={61,64,0};
int test[]={65,66,0};
int test[]={67,72,0};
int test[]={73,74,0};
int test[]={77,78,0};
int test[]={79,80,0};*/


int no_test[]={
//For sure
//2,3,4,5,6,9,10,11,12,13,14,15,16,17,21,22,23,27,32,33,
//serial and timers
18,19,28,34,35,36,37,38,39,40,41,
//PCMCIA
//46,48,49,50,51,52,53,54,55,56,57,
//perhaps


AXIM_PCMCIA_RDY_GPIO,AXIM_PCMCIA_INS_GPIO,0
};
static int 
pxa_axim_pcmcia_init(struct pcmcia_init *init)
{
	int return_val = 0;
	int i,good,j;



//	GPSR0 = GPIO_bit(26);
//	GPSR1 =	GPIO_bit(63);



/*	set_GPIO_IRQ_edge(AXIM_PCMCIA_RDY_GPIO,
			  GPIO_BOTH_EDGES);
*/
	set_GPIO_IRQ_edge(AXIM_PCMCIA_INS_GPIO,
			  GPIO_BOTH_EDGES);


//	return_val =
#if 0


/*		set_bit (gpio_nr, GPIO_IRQ_falling_edge);
		set_bit (gpio_nr, GPIO_IRQ_rising_edge);*/

	for(i=48;i<=57;i++)
	{
	    if(i==AXIM_PCMCIA_RDY_GPIO) continue;
/*	    good=1; 
	    j=0;
	    while(no_test[j]!=0)
	    {
		if(no_test[j]==i) good=0;
		j++;
	    }	
	    if(!good) continue;*/
	    set_GPIO_IRQ_edge(i,
			     GPIO_BOTH_EDGES);
	    	    
	    printk("hooking to IRQ %d, ret=%d\n",i,request_irq(GPIO_2_80_TO_IRQ(i), init->handler, SA_INTERRUPT,"Pcmcia", NULL));
	}

	set_GPIO_mode(GPIO48_nPOE_MD);
	set_GPIO_mode(GPIO49_nPWE_MD);
	set_GPIO_mode(GPIO50_nPIOR_MD);
	set_GPIO_mode(GPIO51_nPIOW_MD);
	set_GPIO_mode(GPIO52_nPCE_1_MD);
	set_GPIO_mode(GPIO53_nPCE_2_MD);
	set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */
	set_GPIO_mode(GPIO55_nPREG_MD);
	set_GPIO_mode(GPIO56_nPWAIT_MD);
	set_GPIO_mode(GPIO57_nIOIS16_MD);

	
#endif
#if 0
	    i=0;
	    while(test[i]!=0)
	    {
	    set_GPIO_IRQ_edge(test[i],
			     GPIO_BOTH_EDGES);
		printk("hooking to GPIO %d, ret=%d\n",test[i],request_irq(GPIO_2_80_TO_IRQ(test[i]), init->handler, SA_INTERRUPT,"Pcmcia", NULL));
		i++;
	    }	

#endif
#if 0
	if(gpio)
	{
	    set_GPIO_IRQ_edge(gpio,
		     GPIO_BOTH_EDGES);
	    printk("hooking to GPIO %d, ret=%d\n",gpio,request_irq(GPIO_2_80_TO_IRQ(gpio), init->handler, SA_INTERRUPT,"Pcmcia", NULL));
	}
#endif
	printk("IRQ init: return: %d\n",return_val);
	printk("GPIO=%d\nIRQ=%d\n",AXIM_PCMCIA_RDY_GPIO,GPIO_2_80_TO_IRQ(AXIM_PCMCIA_RDY_GPIO));

	return_val=request_irq(GPIO_2_80_TO_IRQ(AXIM_PCMCIA_INS_GPIO), init->handler, SA_INTERRUPT,
			"PXA Pcmcia", NULL);
	if (return_val < 0)
		return -1;
	

	return 1;
}


static int
pxa_axim_pcmcia_shutdown(void)
{
//	if(gpio)
//	free_irq(GPIO_2_80_TO_IRQ(gpio), NULL);
//	free_irq(GPIO_2_80_TO_IRQ(AXIM_PCMCIA_INS_GPIO), NULL);
	return 0;
}

static int
pxa_axim_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{

    state_array->state[0].detect = !((GPLR0>>7)&0x01);
    state_array->state[0].ready  = 1;
    state_array->state[0].bvd1   = 1;
    state_array->state[0].bvd2   = 1;
    state_array->state[0].wrprot = 0;
    state_array->state[0].vs_3v  = 1;
    state_array->state[0].vs_Xv  = 0;

    return 0;
}

static int
pxa_axim_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
	info->irq=IRQ_MEDIAQ_GPIO2;
	printk("irq_info returns: %d\n",info->irq);
	return 0;
}

static int
pxa_axim_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
{
//	GPCR0 = GPIO_bit(26);
//	GPCR1 =	GPIO_bit(63);
	SP08R= (SP08R & ~0x20) + 0x20; // apply power to socket
	return 0;
}

struct pcmcia_low_level axim_pcmcia_ops = { 
  pxa_axim_pcmcia_init,
  pxa_axim_pcmcia_shutdown,
  pxa_axim_pcmcia_socket_state,
  pxa_axim_pcmcia_get_irq_info,
  pxa_axim_pcmcia_configure_socket
};
EXPORT_SYMBOL(axim_pcmcia_ops);
