1/* 2 * drivers/mtd/nand/ams-delta.c 3 * 4 * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> 5 * 6 * Derived from drivers/mtd/toto.c 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 * Overview: 13 * This is a device driver for the NAND flash device found on the 14 * Amstrad E3 (Delta). 15 */ 16 17#include <linux/slab.h> 18#include <linux/init.h> 19#include <linux/module.h> 20#include <linux/delay.h> 21#include <linux/mtd/mtd.h> 22#include <linux/mtd/nand.h> 23#include <linux/mtd/partitions.h> 24#include <asm/io.h> 25#include <mach/hardware.h> 26#include <asm/sizes.h> 27#include <mach/gpio.h> 28#include <plat/board-ams-delta.h> 29 30/* 31 * MTD structure for E3 (Delta) 32 */ 33static struct mtd_info *ams_delta_mtd = NULL; 34 35#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP) 36 37/* 38 * Define partitions for flash devices 39 */ 40 41static struct mtd_partition partition_info[] = { 42 { .name = "Kernel", 43 .offset = 0, 44 .size = 3 * SZ_1M + SZ_512K }, 45 { .name = "u-boot", 46 .offset = 3 * SZ_1M + SZ_512K, 47 .size = SZ_256K }, 48 { .name = "u-boot params", 49 .offset = 3 * SZ_1M + SZ_512K + SZ_256K, 50 .size = SZ_256K }, 51 { .name = "Amstrad LDR", 52 .offset = 4 * SZ_1M, 53 .size = SZ_256K }, 54 { .name = "File system", 55 .offset = 4 * SZ_1M + 1 * SZ_256K, 56 .size = 27 * SZ_1M }, 57 { .name = "PBL reserved", 58 .offset = 32 * SZ_1M - 3 * SZ_256K, 59 .size = 3 * SZ_256K }, 60}; 61 62static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) 63{ 64 struct nand_chip *this = mtd->priv; 65 66 omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); 67 omap_writew(byte, this->IO_ADDR_W); 68 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); 69 ndelay(40); 70 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 71 AMS_DELTA_LATCH2_NAND_NWE); 72} 73 74static u_char ams_delta_read_byte(struct mtd_info *mtd) 75{ 76 u_char res; 77 struct nand_chip *this = mtd->priv; 78 79 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); 80 ndelay(40); 81 omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); 82 res = omap_readw(this->IO_ADDR_R); 83 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 84 AMS_DELTA_LATCH2_NAND_NRE); 85 86 return res; 87} 88 89static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf, 90 int len) 91{ 92 int i; 93 94 for (i=0; i<len; i++) 95 ams_delta_write_byte(mtd, buf[i]); 96} 97 98static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len) 99{ 100 int i; 101 102 for (i=0; i<len; i++) 103 buf[i] = ams_delta_read_byte(mtd); 104} 105 106static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf, 107 int len) 108{ 109 int i; 110 111 for (i=0; i<len; i++) 112 if (buf[i] != ams_delta_read_byte(mtd)) 113 return -EFAULT; 114 115 return 0; 116} 117 118/* 119 * Command control function 120 * 121 * ctrl: 122 * NAND_NCE: bit 0 -> bit 2 123 * NAND_CLE: bit 1 -> bit 7 124 * NAND_ALE: bit 2 -> bit 6 125 */ 126static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, 127 unsigned int ctrl) 128{ 129 130 if (ctrl & NAND_CTRL_CHANGE) { 131 unsigned long bits; 132 133 bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0; 134 bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0; 135 bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0; 136 137 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE | 138 AMS_DELTA_LATCH2_NAND_ALE | 139 AMS_DELTA_LATCH2_NAND_NCE, bits); 140 } 141 142 if (cmd != NAND_CMD_NONE) 143 ams_delta_write_byte(mtd, cmd); 144} 145 146static int ams_delta_nand_ready(struct mtd_info *mtd) 147{ 148 return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB); 149} 150 151/* 152 * Main initialization routine 153 */ 154static int __init ams_delta_init(void) 155{ 156 struct nand_chip *this; 157 int err = 0; 158 159 /* Allocate memory for MTD device structure and private data */ 160 ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + 161 sizeof(struct nand_chip), GFP_KERNEL); 162 if (!ams_delta_mtd) { 163 printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n"); 164 err = -ENOMEM; 165 goto out; 166 } 167 168 ams_delta_mtd->owner = THIS_MODULE; 169 170 /* Get pointer to private data */ 171 this = (struct nand_chip *) (&ams_delta_mtd[1]); 172 173 /* Initialize structures */ 174 memset(ams_delta_mtd, 0, sizeof(struct mtd_info)); 175 memset(this, 0, sizeof(struct nand_chip)); 176 177 /* Link the private data with the MTD structure */ 178 ams_delta_mtd->priv = this; 179 180 /* Set address of NAND IO lines */ 181 this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); 182 this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT); 183 this->read_byte = ams_delta_read_byte; 184 this->write_buf = ams_delta_write_buf; 185 this->read_buf = ams_delta_read_buf; 186 this->verify_buf = ams_delta_verify_buf; 187 this->cmd_ctrl = ams_delta_hwcontrol; 188 if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) { 189 this->dev_ready = ams_delta_nand_ready; 190 } else { 191 this->dev_ready = NULL; 192 printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n"); 193 } 194 /* 25 us command delay time */ 195 this->chip_delay = 30; 196 this->ecc.mode = NAND_ECC_SOFT; 197 198 /* Set chip enabled, but */ 199 ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | 200 AMS_DELTA_LATCH2_NAND_NWE | 201 AMS_DELTA_LATCH2_NAND_NCE | 202 AMS_DELTA_LATCH2_NAND_NWP); 203 204 /* Scan to find existance of the device */ 205 if (nand_scan(ams_delta_mtd, 1)) { 206 err = -ENXIO; 207 goto out_mtd; 208 } 209 210 /* Register the partitions */ 211 add_mtd_partitions(ams_delta_mtd, partition_info, 212 ARRAY_SIZE(partition_info)); 213 214 goto out; 215 216 out_mtd: 217 kfree(ams_delta_mtd); 218 out: 219 return err; 220} 221 222module_init(ams_delta_init); 223 224/* 225 * Clean up routine 226 */ 227static void __exit ams_delta_cleanup(void) 228{ 229 /* Release resources, unregister device */ 230 nand_release(ams_delta_mtd); 231 232 /* Free the MTD device structure */ 233 kfree(ams_delta_mtd); 234} 235module_exit(ams_delta_cleanup); 236 237MODULE_LICENSE("GPL"); 238MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); 239MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)"); 240