1/*
2 *  drivers/mtd/nand/h1910.c
3 *
4 *  Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
5 *
6 *  Derived from drivers/mtd/nand/edb7312.c
7 *       Copyright (C) 2002 Marius Gr��ger (mag@sysgo.de)
8 *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
9 *
10 * $Id: h1910.c,v 1.1.1.1 2007/08/03 18:52:44 Exp $
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 *  Overview:
17 *   This is a device driver for the NAND flash device found on the
18 *   iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is
19 *   a 128Mibit (16MiB x 8 bits) NAND flash device.
20 */
21
22#include <linux/slab.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/nand.h>
27#include <linux/mtd/partitions.h>
28#include <asm/io.h>
29#include <asm/arch/hardware.h>	/* for CLPS7111_VIRT_BASE */
30#include <asm/sizes.h>
31#include <asm/arch/h1900-gpio.h>
32#include <asm/arch/ipaq.h>
33
34/*
35 * MTD structure for EDB7312 board
36 */
37static struct mtd_info *h1910_nand_mtd = NULL;
38
39/*
40 * Module stuff
41 */
42
43#ifdef CONFIG_MTD_PARTITIONS
44/*
45 * Define static partitions for flash device
46 */
47static struct mtd_partition partition_info[] = {
48      {name:"h1910 NAND Flash",
49	      offset:0,
50      size:16 * 1024 * 1024}
51};
52
53#define NUM_PARTITIONS 1
54
55#endif
56
57/*
58 *	hardware specific access to control-lines
59 *
60 *	NAND_NCE: bit 0 - don't care
61 *	NAND_CLE: bit 1 - address bit 2
62 *	NAND_ALE: bit 2 - address bit 3
63 */
64static void h1910_hwcontrol(struct mtd_info *mtd, int cmd,
65			    unsigned int ctrl)
66{
67	struct nand_chip *chip = mtd->priv;
68
69	if (cmd != NAND_CMD_NONE)
70		writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1));
71}
72
73/*
74 *	read device ready pin
75 */
76
77/*
78 * Main initialization routine
79 */
80static int __init h1910_init(void)
81{
82	struct nand_chip *this;
83	const char *part_type = 0;
84	int mtd_parts_nb = 0;
85	struct mtd_partition *mtd_parts = 0;
86	void __iomem *nandaddr;
87
88	if (!machine_is_h1900())
89		return -ENODEV;
90
91	nandaddr = ioremap(0x08000000, 0x1000);
92	if (!nandaddr) {
93		printk("Failed to ioremap nand flash.\n");
94		return -ENOMEM;
95	}
96
97	/* Allocate memory for MTD device structure and private data */
98	h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
99	if (!h1910_nand_mtd) {
100		printk("Unable to allocate h1910 NAND MTD device structure.\n");
101		iounmap((void *)nandaddr);
102		return -ENOMEM;
103	}
104
105	/* Get pointer to private data */
106	this = (struct nand_chip *)(&h1910_nand_mtd[1]);
107
108	/* Initialize structures */
109	memset(h1910_nand_mtd, 0, sizeof(struct mtd_info));
110	memset(this, 0, sizeof(struct nand_chip));
111
112	/* Link the private data with the MTD structure */
113	h1910_nand_mtd->priv = this;
114	h1910_nand_mtd->owner = THIS_MODULE;
115
116	/*
117	 * Enable VPEN
118	 */
119	GPSR(37) = GPIO_bit(37);
120
121	/* insert callbacks */
122	this->IO_ADDR_R = nandaddr;
123	this->IO_ADDR_W = nandaddr;
124	this->cmd_ctrl = h1910_hwcontrol;
125	this->dev_ready = NULL;	/* unknown whether that was correct or not so we will just do it like this */
126	/* 15 us command delay time */
127	this->chip_delay = 50;
128	this->ecc.mode = NAND_ECC_SOFT;
129	this->options = NAND_NO_AUTOINCR;
130
131	/* Scan to find existence of the device */
132	if (nand_scan(h1910_nand_mtd, 1)) {
133		printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
134		kfree(h1910_nand_mtd);
135		iounmap((void *)nandaddr);
136		return -ENXIO;
137	}
138#ifdef CONFIG_MTD_CMDLINE_PARTS
139	mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand");
140	if (mtd_parts_nb > 0)
141		part_type = "command line";
142	else
143		mtd_parts_nb = 0;
144#endif
145	if (mtd_parts_nb == 0) {
146		mtd_parts = partition_info;
147		mtd_parts_nb = NUM_PARTITIONS;
148		part_type = "static";
149	}
150
151	/* Register the partitions */
152	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
153	add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
154
155	/* Return happy */
156	return 0;
157}
158
159module_init(h1910_init);
160
161/*
162 * Clean up routine
163 */
164static void __exit h1910_cleanup(void)
165{
166	struct nand_chip *this = (struct nand_chip *)&h1910_nand_mtd[1];
167
168	/* Release resources, unregister device */
169	nand_release(h1910_nand_mtd);
170
171	/* Release io resource */
172	iounmap((void *)this->IO_ADDR_W);
173
174	/* Free the MTD device structure */
175	kfree(h1910_nand_mtd);
176}
177
178module_exit(h1910_cleanup);
179
180MODULE_LICENSE("GPL");
181MODULE_AUTHOR("Joshua Wise <joshua at joshuawise dot com>");
182MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910");
183