/*
 * $Id: ts7xxx.c,v 1.1 2006/02/09 21:52:47 michael Exp $
 *
 * Mapping for the Technologic Systems TS-7200 board
 *
 * Author:	Nicolas Pitre
 * Copyright:	(C) 2001 MontaVista Software Inc.
 * 
 * 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.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>

#define BUSWIDTH 	2

static struct mtd_info *mymtd;

static struct map_info hiflash_map = {
	.name = "TS-7200 high flash",
	.size = 0x01000000,
	.bankwidth = BUSWIDTH,
	.phys = 0x61000000
};

static struct map_info loflash_map = {
	.name = "TS-7200 flash",
	.size = 0x01000000,
	.bankwidth = BUSWIDTH,
	.phys = 0x60000000
};

static struct mtd_partition ts7xxx_parts[3] = {
        {
                name:           "TS-BOOTROM",
                size:           0x00020000,
                offset:         0,
        },
        {
                name:           "Linux",
                size:           0x00600000,
                offset:         0x00020000,
        },
        {
                name:           "RedBoot",
                size:           0x001e0000,
                offset:         0x00620000,
        }
};

static struct mtd_partition ts7xxx_16mb_parts[3] = {
        {
                name:           "TS-BOOTROM",
                size:           0x00020000,
                offset:         0,
        },
        {
                name:           "Linux",
                size:           0x00e00000,
                offset:         0x00020000,
        },
        {
                name:           "RedBoot",
                size:           0x001e0000,
                offset:         0x00e20000,
        }
};

#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))

static struct mtd_info *lomtd, *himtd;
static struct mtd_partition *loparsed_parts = 0, *hiparsed_parts = 0;

extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);

static int __init init_ts7xxx(void)
{

	loflash_map.virt = (void *)IO_ADDRESS(TS7XXX_FLASH_BASE);
	simple_map_init(&loflash_map);
	lomtd = do_map_probe("cfi_probe", &loflash_map);
	if (!lomtd) {
		return -ENXIO;
	}
	lomtd->owner = THIS_MODULE;
	if (inb(TS7XXX_STATUS2) & 0x4) {
		hiflash_map.virt = (void *)IO_ADDRESS(TS7XXX_FLASH2_BASE);
		simple_map_init(&hiflash_map);
		himtd = do_map_probe("cfi_probe", &hiflash_map);
		if (himtd) {
			himtd->owner = THIS_MODULE;
		}
	}


#ifdef CONFIG_MTD_REDBOOT_PARTS
	ret = parse_redboot_partitions(lomtd, &loparsed_parts);

	if (ret > 0) {
		printk(KERN_NOTICE "Using RedBoot partition definition\n");
		add_mtd_partitions(lomtd, loparsed_parts, ret);
	}
	if (himtd) {
		ret = parse_redboot_partitions(himtd, &hiparsed_parts);

		if (ret > 0) {
			printk(KERN_NOTICE "Using RedBoot partition definition\n");
			add_mtd_partitions(himtd, hiparsed_parts, ret);
		}
	}
#else
	if (lomtd->size > 0x800000)
	  add_mtd_partitions(lomtd, ts7xxx_16mb_parts, NB_OF(ts7xxx_16mb_parts));
	else
	  add_mtd_partitions(lomtd, ts7xxx_parts, NB_OF(ts7xxx_parts));

	if (himtd) {
		if (himtd->size > 0x800000)
		  add_mtd_partitions(himtd, ts7xxx_16mb_parts, NB_OF(ts7xxx_16mb_parts));
		else
		  add_mtd_partitions(himtd, ts7xxx_parts, NB_OF(ts7xxx_parts));
	}
#endif

	return 0;
}

static void __exit cleanup_ts7xxx(void)
{
	if (mymtd) {
		del_mtd_partitions(lomtd);
		if (himtd) del_mtd_partitions(himtd);
		map_destroy(lomtd);
		if (himtd) map_destroy(himtd);
		if (loparsed_parts)
			kfree(loparsed_parts);
		if (hiparsed_parts)
			kfree(hiparsed_parts);
	}
}

module_init(init_ts7xxx);
module_exit(cleanup_ts7xxx);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jesse Off <joff@embeddedx86.com>");
MODULE_DESCRIPTION("MTD map driver for TS-7XXX");
