/* linux/drivers/ide/arm/ide-tcf.c
 *
 * Copyright (c) 2007 Daniel Smolik
 *  Mydatex  <marvin@mydatex.cz>
 *
 * 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.
 *
 * 2007-01-03:mos:modified for TS-7800 with TS-RF2-CF daughter card
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <asm/mach-types.h>
#include <asm/io.h>
#include <asm/irq.h>

/*
TS-7800 CF memory map:       
BASE + 0x0 - ID register, must read 0x8E
BASE + 0x6 - CF aux reg #0
BASE + 0x7 - CF aux reg #1
BASE + 0x8-0xf - CF IDE regs #0 - #7
*/
#define TS7800_ISA8_BUS 0xEE000000
#define TSRF2_OFFSET 0x100
#define TS7800_ISA16_BUS 0xEF000000
#define TS7800_CF_CMD_PHYS_BASE         TS7800_ISA8_BUS + TSRF2_OFFSET + 9
#define TS7800_CF_AUX_PHYS_BASE         TS7800_ISA8_BUS + TSRF2_OFFSET + 6
#define TS7800_CF_DATA_PHYS_BASE        TS7800_ISA16_BUS + TSRF2_OFFSET + 8
#define IRQ_EP93XX_EXT0                 64+6

void on104(void) {
  volatile unsigned long *tmp;
  tmp = ((unsigned long *) __ioremap(0xE8000000, 4096,0));
  if (tmp == (unsigned long *)0xE8000000) {
    printk(KERN_ERR "tsuart1: cannot map 0xE8000000\n");
    return;
  }
  tmp[0x30/4] = 0x55555555;
  tmp[0x34/4] = 0x55555555;
  tmp[0x38/4] = 0x55555555;
  tmp[0x3C/4] = 0x55555555;
  __iounmap(tmp);
}

static ide_hwif_t *tscf_find_hwif(unsigned long dataport)
{
       ide_hwif_t *hwif;
       int index;

       for (index = 0; index < MAX_HWIFS; ++index) {
               hwif = &ide_hwifs[index];
               if (hwif->io_ports[IDE_DATA_OFFSET] == dataport)
                       goto found;
       }

       for (index = 0; index < MAX_HWIFS; ++index) {
               hwif = &ide_hwifs[index];
               if (!hwif->io_ports[IDE_DATA_OFFSET])
                       goto found;
       }

       hwif = NULL;
found:
       return hwif;
}

static int __init tcf_register(unsigned long dataport,int irq)
{
       ide_hwif_t *hwif;
       //int i,ret;

       

       hwif = tscf_find_hwif(dataport);
       
       if (hwif) {
               //int i;

               memset(&hwif->hw, 0, sizeof(hw_regs_t));

               /*
                * Ensure we're using MMIO
                */
               default_hwif_mmiops(hwif);
               hwif->mmio = 1;

               hwif->io_ports[IDE_DATA_OFFSET] =    (unsigned long)ioremap(TS7800_CF_DATA_PHYS_BASE,1);

               hwif->io_ports[IDE_ERROR_OFFSET] =   (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE,1);
               hwif->io_ports[IDE_NSECTOR_OFFSET] = (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x1,1);
               hwif->io_ports[IDE_SECTOR_OFFSET] =  (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x2,1);
               hwif->io_ports[IDE_LCYL_OFFSET] =    (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x3,1);
               hwif->io_ports[IDE_HCYL_OFFSET] =    (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x4,1);
               hwif->io_ports[IDE_SELECT_OFFSET] =  (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x5,1);
               hwif->io_ports[IDE_STATUS_OFFSET] =  (unsigned long)ioremap(TS7800_CF_CMD_PHYS_BASE + 0x6,1);
               
               hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ioremap(TS7800_CF_AUX_PHYS_BASE,1);



               

               /*
               * This is the dma channel number assigned to this IDE interface. Until
               * dma is enabled for this interface, we set it to NO_DMA.
               */
               hwif->hw.dma = NO_DMA;
               hwif->dma = NO_DMA;

 
               hwif->hw.irq  = irq;
               hwif->irq     = irq;
               hwif->noprobe = 0;
               hwif->chipset = ide_generic;
               //hwif->chipset = ide_forced;
               
               
               probe_hwif_init(hwif);                                          
                                                                               
               //ide_proc_register_port(hwif);
	       create_proc_ide_interfaces();
	       //ide_register_hw(hwif,NULL);
 
       }

        printk("Technologic Systems TS-7800 IDE initialization - driver version 1.0, 12/27/07. \n");

        return 0;
}


// return IRQ if found, or 0 otherwise
int detect_rf2(int iobase) {
  volatile unsigned char *sh;
  int irq=0;

  sh = ((volatile unsigned char *) __ioremap(0xEE000000, 4096,0));
  if (sh == (volatile unsigned char *)0xEE000000) {
    printk(KERN_ERR "ide-tsrf2: cannot map 0xEE000000\n");
    return 0;
  }
  sh += iobase;
  if (sh[0] == 0x8e) {
    // found board
    printk("TS-RF2 detected at I/O address 0x%X, ",iobase);
    sh[2] = 0xE9; // make sure unused UART is off
    if (sh[1] & (1 << 6)) {
      printk("IRQ 6\n");
      irq = 64+6;
    } else if (sh[1] & (1 << 7)) {
      printk("IRQ 7\n");
      irq = 64+7;
    } else {
      printk("NO IRQ (ignoring!)\n");
    }
  }
  __iounmap(sh);
  return irq;
}

static int __init tcf_init(void)
{
  int irq;

  // Assume we have a TS-7800 board...
  on104();
  if ((irq=detect_rf2(0x100))) {
    tcf_register(TS7800_ISA16_BUS + 0x100 + 8,irq);
  }
  if ((irq=detect_rf2(0x110))) {
    tcf_register(TS7800_ISA16_BUS + 0x110 + 8,irq);
  }
  if ((irq=detect_rf2(0x200))) {
    tcf_register(TS7800_ISA16_BUS + 0x200 + 8,irq);
  }
  if ((irq=detect_rf2(0x210))) {
    tcf_register(TS7800_ISA16_BUS + 0x210 + 8,irq);
  }
  //tcf_register(TS7800_CF_DATA_PHYS_BASE,IRQ_EP93XX_EXT0);
  return 0;
}

module_init(tcf_init);

MODULE_AUTHOR("Dan Smolik <marvin@mydatex.cz>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TS-7800+TS/RF-2 IDE driver");
