/*
 *  linux/drivers/serial/tsuart-736.c
 *
 *  TS-UART loader for Technologic Systems TS-736
 *
 *  (c) 2006 Technologic Systems
 *
 * This source code is hereby licensed to the Linux 2.4 kernel under the
 * GPL, and to Technologic Systems customers under the BSD license.
 *
 * 2006-12-7:mos:initial version completed
 *
 */
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
//#include <serial_core.h>
#include <asm/hardware/serial_amba.h>
#include <linux/ts_sbc.h>
#include <asm/uaccess.h>
#include "tsuart.h"

struct uart_driver *dr8=0,*dr9=0;

#define BOARD_ID_736 0x736

static volatile unsigned short *ctrlbits = 0;

static int mdmctrl736(struct tsuart_port *ts,int mctrl) {
  int ctrl=mctrl,port,mask=0;

  port = (((int)ts->u.mapbase) - 0x72000400)/4;
  if (port < 8) {
    mask = 1 << port;
  } else if (port < 16) {
    mask = 1 << (port-8);
  }
   if (mctrl & 0x80000000) { // set
    if ((mctrl & TIOCM_DTR)) {
      if (ctrlbits) {
	*ctrlbits |= mask;
      }
    } else {
      if (ctrlbits) {
	*ctrlbits &= ~mask;
      }
    }
  } else { // get
    if (*ctrlbits & (mask<<8)) {
      ctrl |= TIOCM_CD;
    }
  }
  return ctrl;
}

static int tryInitPort(int base) {
  struct tsuart_port *ts1,*ts2;

  ts1 = kmalloc(sizeof(struct tsuart_port),GFP_KERNEL);
  if (!ts1) {
    printk("Unable to allocate memory for tsuart port\n");
    return 0;
  }
  init_tsuart_port(ts1);
  ts1->rxsize = 1;
  ts1->u.iotype = SERIAL_IO_MEM;
  ts1->get = tsuartGetMEM16;
  ts1->put = tsuartPutMEM16;
  ts1->mdmctrl = mdmctrl736;
  ts1->debugFlags = portDebug;
  ts1->u.mapbase = 0x72000400 + base;
  ts1->portStatus = &ts1->pstatus;
  ts1->pstatus = 0;
  ts1->u.irq = 40;
  ts1->localStatus |= PORT_STATUS_SHIRQ;
  ts1->boardId = BOARD_ID_736;

  ts2 = kmalloc(sizeof(struct tsuart_port),GFP_KERNEL);
  if (!ts2) {
    printk("Unable to allocate memory for tsuart port\n");
    return 0;
  }
  init_tsuart_port(ts2);
  ts2->rxsize = 2;
  ts2->dataMask = 0x1FF;
  ts2->u.iotype = SERIAL_IO_MEM;
  ts2->get = tsuartGetMEM16_9;
  ts2->put = tsuartPutMEM16_9;
  ts2->mdmctrl = mdmctrl736;
  ts2->debugFlags = portDebug;
  ts2->u.mapbase = 0x72000400 + base;
  ts2->portStatus = &ts1->pstatus;
  ts2->u.irq = 40;
  ts2->localStatus |= PORT_STATUS_SHIRQ;
  ts2->boardId = BOARD_ID_736;
  //printk("registering %p,%p\n",ts1,ts2);
  if (tsuart_register_port(dr8,ts1) == 0) {
    //    return 1;
  }
  if (tsuart_register_port(dr9,ts2) == 0) {
    //    return 1;
  }
  if (!ctrlbits) {
    ctrlbits = (volatile unsigned short *)((int) __ioremap(0x72000000, 4096,0) + 0x460);
  }
  //ctrlbits = 0;
  return 1;
}

#define TTY_NAME8 "ttyT8Sy"
#define CUA_NAME8 "cuaT8Sy"
#define TTY_NAME9 "ttyT9Sy"
#define CUA_NAME9 "cuaT9Sy"

static char *tty = TTY_NAME8,*cua = CUA_NAME8;
static char *tty9 = TTY_NAME9,*cua9 = CUA_NAME9;
MODULE_PARM(tty,"s");
MODULE_PARM(cua,"s");
MODULE_PARM(tty9,"s");
MODULE_PARM(cua9,"s");

static int __init tsuart_init(void)
{
  int ports=0;
  int i;

  if (!tty) {
    tty = TTY_NAME8;
  }
  if (!cua) {
    cua = CUA_NAME8;
  }

  printk("TS-UART/736 assuming TS-736 board\n");

  dr8 = kmalloc(sizeof(struct uart_driver),GFP_KERNEL);
  if (!dr8) {
    printk("Unable to allocate memory for tsuart port\n");
    return 0;
  }
  dr9 = kmalloc(sizeof(struct uart_driver),GFP_KERNEL);
  if (!dr9) {
    kfree(dr8);
    printk("Unable to allocate memory for tsuart port\n");
    return 0;
  }
 if (!tsuart_configure_driver(dr8,234,128,tty,cua,24)) {
    kfree(dr8);
    kfree(dr9);
    return 0;    
  }
  if (!tsuart_configure_driver(dr9,234,152,tty9,cua9,24)) {
    kfree(dr8);
    kfree(dr9);
    return 0;    
  }
  for (i=0;i<24*4;i+=4) {
    if (tryInitPort(i)) {
      ports++;
    }
  }
  return (ports > 0) ? 0 : -1;
}

static void __exit tsuart_exit(void)
{
  // This module can be safely unloaded after initialization is complete.
  // We allow module to load only so error conditions can be detected.
}

module_init(tsuart_init);
module_exit(tsuart_exit);

EXPORT_NO_SYMBOLS;
