/*
 * linux/arch/arm/mach-sa1100/simpad.c
 *
 */


#define CONFIG_SA1100_SIMPAD_128M

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/proc_fs.h>
#include <linux/string.h> 
#include <linux/pm.h> 

#include <asm/hardware.h>
#include <asm/setup.h>

#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h>
#include <linux/serial_core.h>

#include "generic.h"

#undef SIMPAD_UART_USE_IRQ  // irq handling on CTS/DCD doesn't work yet

long cs3_shadow;

long get_cs3_shadow(void)
{
	return cs3_shadow;
}

void set_cs3(long value)
{
        *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow = value;
}

void set_cs3_bit(int value)
{
	cs3_shadow |= value;
	*(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
}

void clear_cs3_bit(int value)
{
	cs3_shadow &= ~value;
	*(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
}

EXPORT_SYMBOL(set_cs3_bit);
EXPORT_SYMBOL(clear_cs3_bit);

static void simpad_power_off(void)
{
    cli();
    set_cs3(0x800);        /* only SD_MEDIAQ */

    /* disable internal oscillator, float CS lines */
    PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
    /* enable wake-up on GPIO0 (Assabet...) */
    PWER = GFER = GRER = 1;
    /*
     * set scratchpad to zero, just in case it is used as a
     * restart address by the bootloader.
     */
    PSPR = 0;
    PGSR = 0;
    /* enter sleep mode */
    PMCR = PMCR_SF;
    while(1);
}
           
static int __init simpad_init(void)
{
    pm_power_off = simpad_power_off;
    return 0;
}

__initcall(simpad_init);

static void __init
fixup_simpad(struct machine_desc *desc, struct param_struct *params,
		   char **cmdline, struct meminfo *mi)
{
	int numbanks=1;

#ifdef CONFIG_SA1100_SIMPAD_SINUSPAD
	SET_BANK( 0, 0xc0000000, 32*1024*1024 );
#else
	SET_BANK( 0, 0xc0000000, 64*1024*1024 );
#endif

#ifdef CONFIG_SA1100_SIMPAD_128M
	SET_BANK( 1, 0xc8000000, 64*1024*1024 );
	numbanks=2;
#endif
	
	mi->nr_banks = numbanks;

	setup_ramdisk( 1, 0, 0, 8192 );
	setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
}

static struct map_desc simpad_io_desc[] __initdata = {
  /* virtual    physical    length      domain     r  w  c  b */
  { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 },
  { 0xe9000000, 0x08000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 },
  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CS3, write only */
  { 0xf2000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CS4, tda8007 */
  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
  LAST_DESC
};

#define SER_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)

static void simpad_uart_set_mctrl(struct uart_port *port, u_int mctrl)
{
	if (port->mapbase == _Ser1UTCR0) {
	        /* internal serial port (ttySA1, DECT/Bluetooth) */
		if (mctrl & TIOCM_RTS)	GPCR = GPIO_UART1_RTS;
		else			GPSR = GPIO_UART1_RTS;

		if (mctrl & TIOCM_DTR)	GPCR = GPIO_UART1_DTR;
		else			GPSR = GPIO_UART1_DTR;
	}

	else if (port->mapbase == _Ser3UTCR0) {
	        /* external serial port (ttySA0, RS232) */
	        if (mctrl & TIOCM_RTS)  GPCR = GPIO_UART3_RTS;
		else			GPSR = GPIO_UART3_RTS;

	        if (mctrl & TIOCM_DTR)  GPCR = GPIO_UART3_DTR;
		else			GPSR = GPIO_UART3_DTR;
	}
}

static u_int simpad_uart_get_mctrl(struct uart_port *port)
{
	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;

	if (port->mapbase == _Ser1UTCR0) {
	        /* internal serial port (ttySA1, DECT/Bluetooth) */
		int gplr = GPLR;
		if (gplr & GPIO_UART1_DCD) ret &= ~TIOCM_CD;
		if (gplr & GPIO_UART1_CTS) ret &= ~TIOCM_CTS;
		if (gplr & GPIO_UART1_DSR) ret &= ~TIOCM_DSR;
	}

	else if (port->mapbase == _Ser3UTCR0) {
	        /* external serial port (ttySA0, RS232) */
		int gplr = GPLR;
		if (gplr & GPIO_UART3_DCD) ret &= ~TIOCM_CD;
		if (gplr & GPIO_UART3_CTS) ret &= ~TIOCM_CTS;
		if (gplr & GPIO_UART3_DSR) ret &= ~TIOCM_DSR;
	}
	return ret;
}

static void simpad_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
{
	if (port->mapbase == (u_int)&Ser3UTCR0) {
		if (state)
			clear_cs3_bit(RS232_ON);
		else
			set_cs3_bit(RS232_ON);
	}
}
/*
 * Enable/Disable wake up events for this serial port.
 * Obviously, we only support this on the normal COM port.
 */
static int simpad_uart_set_wake(struct uart_port *port, u_int enable)
{
	int err = -EINVAL;

#if 0  // TODO: port management
	if (port->mapbase == _Ser3UTCR0) {
		if (enable)
			PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */
		else
			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
		err = 0;
	}
#endif

	return err;
}

#ifdef SIMPAD_UART_USE_IRQ
static void simpad_uart1_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	/* Note: should only call this if something has changed */
	uart_handle_dcd_change(port, !(GPLR & GPIO_UART1_DCD));
}

static void simpad_uart1_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	/* Note: should only call this if something has changed */
	uart_handle_cts_change(port, !(GPLR & GPIO_UART1_CTS));
}

static void simpad_uart3_dcd_intr(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	/* Note: should only call this if something has changed */
	uart_handle_dcd_change(port, !(GPLR & GPIO_UART3_DCD));
}

static void simpad_uart3_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	/* Note: should only call this if something has changed */
	uart_handle_cts_change(port, !(GPLR & GPIO_UART3_CTS));
}
#endif

static int simpad_uart_open(struct uart_port *port)
{
	int ret = 0;
#ifdef SIMPAD_UART_USE_IRQ
	if (port->mapbase == _Ser1UTCR0) {
		set_GPIO_IRQ_edge(GPIO_UART1_DCD|GPIO_UART1_CTS,
				  GPIO_BOTH_EDGES);

		ret = request_irq(IRQ_GPIO_UART1_DCD, simpad_uart1_dcd_intr,
				  0, "UART1 DCD", port);
		if (ret)
			return ret;

		ret = request_irq(IRQ_GPIO_UART1_CTS, simpad_uart1_cts_intr,
				  0, "UART1 CTS", port);
		if (ret)
			free_irq(IRQ_GPIO_UART1_DCD, port);
	}

	else if (port->mapbase == _Ser3UTCR0) {
		set_GPIO_IRQ_edge(GPIO_UART3_DCD|GPIO_UART3_CTS,
				  GPIO_BOTH_EDGES);

		ret = request_irq(IRQ_GPIO_UART3_DCD, simpad_uart3_dcd_intr,
				  0, "UART3 DCD", port);
		if (ret)
			return ret;

		ret = request_irq(IRQ_GPIO_UART3_CTS, simpad_uart3_cts_intr,
				  0, "UART3 CTS", port);
		if (ret)
			free_irq(IRQ_GPIO_UART3_DCD, port);
	}
#endif
	return ret;
}

static void simpad_uart_close(struct uart_port *port)
{
#ifdef SIMPAD_UART_USE_IRQ
	if (port->mapbase == _Ser1UTCR0) {
		free_irq(IRQ_GPIO_UART1_DCD, port);
		free_irq(IRQ_GPIO_UART1_CTS, port);
	}

	else if (port->mapbase == _Ser3UTCR0) {
		free_irq(IRQ_GPIO_UART3_DCD, port);
		free_irq(IRQ_GPIO_UART3_CTS, port);
	}
#endif
}

static struct sa1100_port_fns simpad_port_fns __initdata = {
	.set_mctrl	= simpad_uart_set_mctrl,
	.get_mctrl	= simpad_uart_get_mctrl,
	.pm	        = simpad_uart_pm,
	.set_wake	= simpad_uart_set_wake,
	.open		= simpad_uart_open,
	.close		= simpad_uart_close,
};

static void __init simpad_map_io(void)
{
        sa1100_map_io();
        iotable_init(simpad_io_desc);

        set_cs3_bit (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON |
                      ENABLE_5V | nRESET_SIMCARD);

	sa1100_register_uart_fns(&simpad_port_fns);

        //It is only possible to register 3 UART in serial_sa1100.c
        sa1100_register_uart(0, 3);
        sa1100_register_uart(1, 1);

	// txd and rxd use their alternate function
	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);

	// the control lines are gpio
	GAFR &= ~(GPIO_UART1_RTS | GPIO_UART1_CTS | GPIO_UART1_DCD);
	GAFR &= ~(GPIO_UART1_DSR | GPIO_UART1_DTR);
	GAFR &= ~(GPIO_UART3_RTS | GPIO_UART3_CTS | GPIO_UART3_DCD);
	GAFR &= ~(GPIO_UART3_DSR | GPIO_UART3_DTR);

	// txd, rts and dtr are outputs
	GPDR |= GPIO_UART_TXD;
	GPDR |= GPIO_UART1_RTS | GPIO_UART3_RTS;
	GPDR |= GPIO_UART1_DTR | GPIO_UART3_DTR;

	// cts, dcd, dsr and rxd are inputs
	GPDR &= ~(GPIO_UART1_CTS | GPIO_UART3_CTS);
	GPDR &= ~(GPIO_UART1_DCD | GPIO_UART3_DCD);
	GPDR &= ~(GPIO_UART1_DSR | GPIO_UART3_DSR);
	GPDR &= ~GPIO_UART_RXD;

	PPAR |= PPAR_UPR;

        set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE);
        set_GPIO_IRQ_edge(GPIO_POWER_BUTTON, GPIO_FALLING_EDGE);

        /*
         * Set up registers for sleep mode.
         */

        PWER = PWER_GPIO0;
        PGSR = 0x818;
        PCFR = 0;
        PSDR = 0;
}

#ifdef CONFIG_PROC_FS

static char* name[]={
  "VCC_5V_EN",
  "VCC_3V_EN",
  "EN1",
  "EN0",
  "DISPLAY_ON",
  "PCMCIA_BUFF_DIS",
  "MQ_RESET",
  "PCMCIA_RESET",
  "DECT_POWER_ON",
  "IRDA_SD",
  "RS232_ON",
  "SD_MEDIAQ",
  "LED2_ON",
  "IRDA_MODE",
  "ENABLE_5V",
  "RESET_SIMCARD"
};

static int proc_cs3_read(char *page, char **start, off_t off,
			  int count, int *eof, void *data)
{
	char *p = page;
	int len, i;
        
	p += sprintf(p, "Chipselect3 : %x\n", cs3_shadow);
	for (i = 0; i <= 15; i++) {
		if(cs3_shadow & (1<<i)) {
			p += sprintf(p, "%s\t: TRUE \n",name[i]);
		} else
			p += sprintf(p, "%s\t: FALSE \n",name[i]);
	}
	len = (p - page) - off;
	if (len < 0)
		len = 0;
 
	*eof = (len <= count) ? 1 : 0;
	*start = page + off;
 
	return len;
}

static int proc_cs3_write(struct file * file, const char * buffer,
                size_t count, loff_t *ppos)
{
        unsigned long newRegValue;
        char *endp;

        newRegValue = simple_strtoul(buffer,&endp,0);
        set_cs3( newRegValue );
        return (count+endp-buffer);
}
 
static struct proc_dir_entry *proc_cs3;
 
static int __init cs3_init(void)
{
	proc_cs3 = create_proc_entry("cs3", 0, 0);
	if (proc_cs3)
	{
		proc_cs3->read_proc = proc_cs3_read;
		proc_cs3->write_proc = (void*)proc_cs3_write;
	}
	return 0;
}
 
static int __exit cs3_exit(void)
{
	if (proc_cs3)
		remove_proc_entry( "cs3", 0);
	return 0;
}		   
__initcall(cs3_init);

#endif // CONFIG_PROC_FS

MACHINE_START(SIMPAD, "Simpad")
	MAINTAINER("Juergen Messerer")
	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
	BOOT_PARAMS(0xc0000100)
	FIXUP(fixup_simpad)
	MAPIO(simpad_map_io)
	INITIRQ(sa1100_init_irq)
MACHINE_END
This page was last modified 07:27, 13 October 2007. | This page has been accessed 1,178 times. | About OpenSIMpad.org
Designed by Anna Boheim | Powerd by mediawiki