| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * Toshiba TMIO NAND flash controller driver | 
 | 3 |  * | 
 | 4 |  * Slightly murky pre-git history of the driver: | 
 | 5 |  * | 
 | 6 |  * Copyright (c) Ian Molton 2004, 2005, 2008 | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 7 |  *    Original work, independent of sharps code. Included hardware ECC support. | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 8 |  *    Hard ECC did not work for writes in the early revisions. | 
 | 9 |  * Copyright (c) Dirk Opfer 2005. | 
 | 10 |  *    Modifications developed from sharps code but | 
 | 11 |  *    NOT containing any, ported onto Ians base. | 
 | 12 |  * Copyright (c) Chris Humbert 2005 | 
 | 13 |  * Copyright (c) Dmitry Baryshkov 2008 | 
 | 14 |  *    Minor fixes | 
 | 15 |  * | 
 | 16 |  * Parts copyright Sebastian Carlier | 
 | 17 |  * | 
 | 18 |  * This file is licensed under | 
 | 19 |  * the terms of the GNU General Public License version 2. This program | 
 | 20 |  * is licensed "as is" without any warranty of any kind, whether express | 
 | 21 |  * or implied. | 
 | 22 |  * | 
 | 23 |  */ | 
 | 24 |  | 
 | 25 |  | 
 | 26 | #include <linux/kernel.h> | 
 | 27 | #include <linux/module.h> | 
 | 28 | #include <linux/platform_device.h> | 
 | 29 | #include <linux/mfd/core.h> | 
 | 30 | #include <linux/mfd/tmio.h> | 
 | 31 | #include <linux/delay.h> | 
 | 32 | #include <linux/io.h> | 
 | 33 | #include <linux/irq.h> | 
 | 34 | #include <linux/interrupt.h> | 
 | 35 | #include <linux/ioport.h> | 
 | 36 | #include <linux/mtd/mtd.h> | 
 | 37 | #include <linux/mtd/nand.h> | 
 | 38 | #include <linux/mtd/nand_ecc.h> | 
 | 39 | #include <linux/mtd/partitions.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 40 | #include <linux/slab.h> | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 41 |  | 
 | 42 | /*--------------------------------------------------------------------------*/ | 
 | 43 |  | 
 | 44 | /* | 
 | 45 |  * NAND Flash Host Controller Configuration Register | 
 | 46 |  */ | 
 | 47 | #define CCR_COMMAND	0x04	/* w Command				*/ | 
 | 48 | #define CCR_BASE	0x10	/* l NAND Flash Control Reg Base Addr	*/ | 
 | 49 | #define CCR_INTP	0x3d	/* b Interrupt Pin			*/ | 
 | 50 | #define CCR_INTE	0x48	/* b Interrupt Enable			*/ | 
 | 51 | #define CCR_EC		0x4a	/* b Event Control			*/ | 
 | 52 | #define CCR_ICC		0x4c	/* b Internal Clock Control		*/ | 
 | 53 | #define CCR_ECCC	0x5b	/* b ECC Control			*/ | 
 | 54 | #define CCR_NFTC	0x60	/* b NAND Flash Transaction Control	*/ | 
 | 55 | #define CCR_NFM		0x61	/* b NAND Flash Monitor			*/ | 
 | 56 | #define CCR_NFPSC	0x62	/* b NAND Flash Power Supply Control	*/ | 
 | 57 | #define CCR_NFDC	0x63	/* b NAND Flash Detect Control		*/ | 
 | 58 |  | 
 | 59 | /* | 
 | 60 |  * NAND Flash Control Register | 
 | 61 |  */ | 
 | 62 | #define FCR_DATA	0x00	/* bwl Data Register			*/ | 
 | 63 | #define FCR_MODE	0x04	/* b Mode Register			*/ | 
 | 64 | #define FCR_STATUS	0x05	/* b Status Register			*/ | 
 | 65 | #define FCR_ISR		0x06	/* b Interrupt Status Register		*/ | 
 | 66 | #define FCR_IMR		0x07	/* b Interrupt Mask Register		*/ | 
 | 67 |  | 
 | 68 | /* FCR_MODE Register Command List */ | 
 | 69 | #define FCR_MODE_DATA	0x94	/* Data Data_Mode */ | 
 | 70 | #define FCR_MODE_COMMAND 0x95	/* Data Command_Mode */ | 
 | 71 | #define FCR_MODE_ADDRESS 0x96	/* Data Address_Mode */ | 
 | 72 |  | 
 | 73 | #define FCR_MODE_HWECC_CALC	0xB4	/* HW-ECC Data */ | 
 | 74 | #define FCR_MODE_HWECC_RESULT	0xD4	/* HW-ECC Calc result Read_Mode */ | 
 | 75 | #define FCR_MODE_HWECC_RESET	0xF4	/* HW-ECC Reset */ | 
 | 76 |  | 
 | 77 | #define FCR_MODE_POWER_ON	0x0C	/* Power Supply ON  to SSFDC card */ | 
 | 78 | #define FCR_MODE_POWER_OFF	0x08	/* Power Supply OFF to SSFDC card */ | 
 | 79 |  | 
 | 80 | #define FCR_MODE_LED_OFF	0x00	/* LED OFF */ | 
 | 81 | #define FCR_MODE_LED_ON		0x04	/* LED ON */ | 
 | 82 |  | 
 | 83 | #define FCR_MODE_EJECT_ON	0x68	/* Ejection events active  */ | 
 | 84 | #define FCR_MODE_EJECT_OFF	0x08	/* Ejection events ignored */ | 
 | 85 |  | 
 | 86 | #define FCR_MODE_LOCK		0x6C	/* Lock_Mode. Eject Switch Invalid */ | 
 | 87 | #define FCR_MODE_UNLOCK		0x0C	/* UnLock_Mode. Eject Switch is valid */ | 
 | 88 |  | 
 | 89 | #define FCR_MODE_CONTROLLER_ID	0x40	/* Controller ID Read */ | 
 | 90 | #define FCR_MODE_STANDBY	0x00	/* SSFDC card Changes Standby State */ | 
 | 91 |  | 
 | 92 | #define FCR_MODE_WE		0x80 | 
 | 93 | #define FCR_MODE_ECC1		0x40 | 
 | 94 | #define FCR_MODE_ECC0		0x20 | 
 | 95 | #define FCR_MODE_CE		0x10 | 
 | 96 | #define FCR_MODE_PCNT1		0x08 | 
 | 97 | #define FCR_MODE_PCNT0		0x04 | 
 | 98 | #define FCR_MODE_ALE		0x02 | 
 | 99 | #define FCR_MODE_CLE		0x01 | 
 | 100 |  | 
 | 101 | #define FCR_STATUS_BUSY		0x80 | 
 | 102 |  | 
 | 103 | /*--------------------------------------------------------------------------*/ | 
 | 104 |  | 
 | 105 | struct tmio_nand { | 
 | 106 | 	struct mtd_info mtd; | 
 | 107 | 	struct nand_chip chip; | 
 | 108 |  | 
 | 109 | 	struct platform_device *dev; | 
 | 110 |  | 
 | 111 | 	void __iomem *ccr; | 
 | 112 | 	void __iomem *fcr; | 
| Dmitry Baryshkov | 076c7f4 | 2008-09-04 13:28:33 +0400 | [diff] [blame] | 113 | 	unsigned long fcr_base; | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 114 |  | 
 | 115 | 	unsigned int irq; | 
 | 116 |  | 
 | 117 | 	/* for tmio_nand_read_byte */ | 
 | 118 | 	u8			read; | 
 | 119 | 	unsigned read_good:1; | 
 | 120 | }; | 
 | 121 |  | 
 | 122 | #define mtd_to_tmio(m)			container_of(m, struct tmio_nand, mtd) | 
 | 123 |  | 
 | 124 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 
 | 125 | static const char *part_probes[] = { "cmdlinepart", NULL }; | 
 | 126 | #endif | 
 | 127 |  | 
 | 128 | /*--------------------------------------------------------------------------*/ | 
 | 129 |  | 
 | 130 | static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, | 
 | 131 | 				   unsigned int ctrl) | 
 | 132 | { | 
 | 133 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 134 | 	struct nand_chip *chip = mtd->priv; | 
 | 135 |  | 
 | 136 | 	if (ctrl & NAND_CTRL_CHANGE) { | 
 | 137 | 		u8 mode; | 
 | 138 |  | 
 | 139 | 		if (ctrl & NAND_NCE) { | 
 | 140 | 			mode = FCR_MODE_DATA; | 
 | 141 |  | 
 | 142 | 			if (ctrl & NAND_CLE) | 
 | 143 | 				mode |=  FCR_MODE_CLE; | 
 | 144 | 			else | 
 | 145 | 				mode &= ~FCR_MODE_CLE; | 
 | 146 |  | 
 | 147 | 			if (ctrl & NAND_ALE) | 
 | 148 | 				mode |=  FCR_MODE_ALE; | 
 | 149 | 			else | 
 | 150 | 				mode &= ~FCR_MODE_ALE; | 
 | 151 | 		} else { | 
 | 152 | 			mode = FCR_MODE_STANDBY; | 
 | 153 | 		} | 
 | 154 |  | 
 | 155 | 		tmio_iowrite8(mode, tmio->fcr + FCR_MODE); | 
 | 156 | 		tmio->read_good = 0; | 
 | 157 | 	} | 
 | 158 |  | 
 | 159 | 	if (cmd != NAND_CMD_NONE) | 
 | 160 | 		tmio_iowrite8(cmd, chip->IO_ADDR_W); | 
 | 161 | } | 
 | 162 |  | 
 | 163 | static int tmio_nand_dev_ready(struct mtd_info *mtd) | 
 | 164 | { | 
 | 165 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 166 |  | 
 | 167 | 	return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY); | 
 | 168 | } | 
 | 169 |  | 
 | 170 | static irqreturn_t tmio_irq(int irq, void *__tmio) | 
 | 171 | { | 
 | 172 | 	struct tmio_nand *tmio = __tmio; | 
 | 173 | 	struct nand_chip *nand_chip = &tmio->chip; | 
 | 174 |  | 
 | 175 | 	/* disable RDYREQ interrupt */ | 
 | 176 | 	tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); | 
 | 177 |  | 
 | 178 | 	if (unlikely(!waitqueue_active(&nand_chip->controller->wq))) | 
 | 179 | 		dev_warn(&tmio->dev->dev, "spurious interrupt\n"); | 
 | 180 |  | 
 | 181 | 	wake_up(&nand_chip->controller->wq); | 
 | 182 | 	return IRQ_HANDLED; | 
 | 183 | } | 
 | 184 |  | 
 | 185 | /* | 
 | 186 |   *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. | 
 | 187 |   *This interrupt is normally disabled, but for long operations like | 
 | 188 |   *erase and write, we enable it to wake us up.  The irq handler | 
 | 189 |   *disables the interrupt. | 
 | 190 |  */ | 
 | 191 | static int | 
 | 192 | tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) | 
 | 193 | { | 
 | 194 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 195 | 	long timeout; | 
 | 196 |  | 
 | 197 | 	/* enable RDYREQ interrupt */ | 
 | 198 | 	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); | 
 | 199 | 	tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); | 
 | 200 |  | 
 | 201 | 	timeout = wait_event_timeout(nand_chip->controller->wq, | 
 | 202 | 		tmio_nand_dev_ready(mtd), | 
 | 203 | 		msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); | 
 | 204 |  | 
 | 205 | 	if (unlikely(!tmio_nand_dev_ready(mtd))) { | 
 | 206 | 		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); | 
 | 207 | 		dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", | 
 | 208 | 			nand_chip->state == FL_ERASING ? "erase" : "program", | 
 | 209 | 			nand_chip->state == FL_ERASING ? 400 : 20); | 
 | 210 |  | 
 | 211 | 	} else if (unlikely(!timeout)) { | 
 | 212 | 		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); | 
 | 213 | 		dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); | 
 | 214 | 	} | 
 | 215 |  | 
 | 216 | 	nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 
 | 217 | 	return nand_chip->read_byte(mtd); | 
 | 218 | } | 
 | 219 |  | 
 | 220 | /* | 
 | 221 |   *The TMIO controller combines two 8-bit data bytes into one 16-bit | 
 | 222 |   *word. This function separates them so nand_base.c works as expected, | 
 | 223 |   *especially its NAND_CMD_READID routines. | 
 | 224 |  * | 
 | 225 |   *To prevent stale data from being read, tmio_nand_hwcontrol() clears | 
 | 226 |   *tmio->read_good. | 
 | 227 |  */ | 
 | 228 | static u_char tmio_nand_read_byte(struct mtd_info *mtd) | 
 | 229 | { | 
 | 230 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 231 | 	unsigned int data; | 
 | 232 |  | 
 | 233 | 	if (tmio->read_good--) | 
 | 234 | 		return tmio->read; | 
 | 235 |  | 
 | 236 | 	data = tmio_ioread16(tmio->fcr + FCR_DATA); | 
 | 237 | 	tmio->read = data >> 8; | 
 | 238 | 	return data; | 
 | 239 | } | 
 | 240 |  | 
 | 241 | /* | 
 | 242 |   *The TMIO controller converts an 8-bit NAND interface to a 16-bit | 
 | 243 |   *bus interface, so all data reads and writes must be 16-bit wide. | 
 | 244 |   *Thus, we implement 16-bit versions of the read, write, and verify | 
 | 245 |   *buffer functions. | 
 | 246 |  */ | 
 | 247 | static void | 
 | 248 | tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 
 | 249 | { | 
 | 250 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 251 |  | 
 | 252 | 	tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); | 
 | 253 | } | 
 | 254 |  | 
 | 255 | static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | 
 | 256 | { | 
 | 257 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 258 |  | 
 | 259 | 	tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); | 
 | 260 | } | 
 | 261 |  | 
 | 262 | static int | 
 | 263 | tmio_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | 
 | 264 | { | 
 | 265 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 266 | 	u16				*p = (u16 *) buf; | 
 | 267 |  | 
 | 268 | 	for (len >>= 1; len; len--) | 
 | 269 | 		if (*(p++) != tmio_ioread16(tmio->fcr + FCR_DATA)) | 
 | 270 | 			return -EFAULT; | 
 | 271 | 	return 0; | 
 | 272 | } | 
 | 273 |  | 
 | 274 | static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode) | 
 | 275 | { | 
 | 276 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 277 |  | 
 | 278 | 	tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE); | 
 | 279 | 	tmio_ioread8(tmio->fcr + FCR_DATA);	/* dummy read */ | 
 | 280 | 	tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE); | 
 | 281 | } | 
 | 282 |  | 
 | 283 | static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | 
 | 284 | 							u_char *ecc_code) | 
 | 285 | { | 
 | 286 | 	struct tmio_nand *tmio = mtd_to_tmio(mtd); | 
 | 287 | 	unsigned int ecc; | 
 | 288 |  | 
 | 289 | 	tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE); | 
 | 290 |  | 
 | 291 | 	ecc = tmio_ioread16(tmio->fcr + FCR_DATA); | 
 | 292 | 	ecc_code[1] = ecc;	/* 000-255 LP7-0 */ | 
 | 293 | 	ecc_code[0] = ecc >> 8;	/* 000-255 LP15-8 */ | 
 | 294 | 	ecc = tmio_ioread16(tmio->fcr + FCR_DATA); | 
 | 295 | 	ecc_code[2] = ecc;	/* 000-255 CP5-0,11b */ | 
 | 296 | 	ecc_code[4] = ecc >> 8;	/* 256-511 LP7-0 */ | 
 | 297 | 	ecc = tmio_ioread16(tmio->fcr + FCR_DATA); | 
 | 298 | 	ecc_code[3] = ecc;	/* 256-511 LP15-8 */ | 
 | 299 | 	ecc_code[5] = ecc >> 8;	/* 256-511 CP5-0,11b */ | 
 | 300 |  | 
 | 301 | 	tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE); | 
 | 302 | 	return 0; | 
 | 303 | } | 
 | 304 |  | 
| Atsushi Nemoto | 0f777fb | 2009-09-05 01:20:44 +0900 | [diff] [blame] | 305 | static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | 
 | 306 | 		unsigned char *read_ecc, unsigned char *calc_ecc) | 
 | 307 | { | 
 | 308 | 	int r0, r1; | 
 | 309 |  | 
 | 310 | 	/* assume ecc.size = 512 and ecc.bytes = 6 */ | 
 | 311 | 	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256); | 
 | 312 | 	if (r0 < 0) | 
 | 313 | 		return r0; | 
 | 314 | 	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256); | 
 | 315 | 	if (r1 < 0) | 
 | 316 | 		return r1; | 
 | 317 | 	return r0 + r1; | 
 | 318 | } | 
 | 319 |  | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 320 | static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) | 
 | 321 | { | 
| Andres Salomon | 944dc03 | 2011-03-01 12:32:20 -0800 | [diff] [blame] | 322 | 	const struct mfd_cell *cell = mfd_get_cell(dev); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 323 | 	int ret; | 
 | 324 |  | 
 | 325 | 	if (cell->enable) { | 
 | 326 | 		ret = cell->enable(dev); | 
 | 327 | 		if (ret) | 
 | 328 | 			return ret; | 
 | 329 | 	} | 
 | 330 |  | 
 | 331 | 	/* (4Ch) CLKRUN Enable    1st spcrunc */ | 
 | 332 | 	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); | 
 | 333 |  | 
 | 334 | 	/* (10h)BaseAddress    0x1000 spba.spba2 */ | 
| Dmitry Baryshkov | 076c7f4 | 2008-09-04 13:28:33 +0400 | [diff] [blame] | 335 | 	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE); | 
 | 336 | 	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 337 |  | 
 | 338 | 	/* (04h)Command Register I/O spcmd */ | 
 | 339 | 	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); | 
 | 340 |  | 
 | 341 | 	/* (62h) Power Supply Control ssmpwc */ | 
 | 342 | 	/* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ | 
 | 343 | 	tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC); | 
 | 344 |  | 
 | 345 | 	/* (63h) Detect Control ssmdtc */ | 
 | 346 | 	tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC); | 
 | 347 |  | 
 | 348 | 	/* Interrupt status register clear sintst */ | 
 | 349 | 	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); | 
 | 350 |  | 
 | 351 | 	/* After power supply, Media are reset smode */ | 
 | 352 | 	tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE); | 
 | 353 | 	tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE); | 
 | 354 | 	tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA); | 
 | 355 |  | 
 | 356 | 	/* Standby Mode smode */ | 
 | 357 | 	tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE); | 
 | 358 |  | 
 | 359 | 	mdelay(5); | 
 | 360 |  | 
 | 361 | 	return 0; | 
 | 362 | } | 
 | 363 |  | 
 | 364 | static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) | 
 | 365 | { | 
| Andres Salomon | 944dc03 | 2011-03-01 12:32:20 -0800 | [diff] [blame] | 366 | 	const struct mfd_cell *cell = mfd_get_cell(dev); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 367 |  | 
 | 368 | 	tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); | 
 | 369 | 	if (cell->disable) | 
 | 370 | 		cell->disable(dev); | 
 | 371 | } | 
 | 372 |  | 
 | 373 | static int tmio_probe(struct platform_device *dev) | 
 | 374 | { | 
| Samuel Ortiz | 7dc00a0 | 2011-04-06 12:20:49 +0200 | [diff] [blame] | 375 | 	struct tmio_nand_data *data = dev->dev.platform_data; | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 376 | 	struct resource *fcr = platform_get_resource(dev, | 
 | 377 | 			IORESOURCE_MEM, 0); | 
 | 378 | 	struct resource *ccr = platform_get_resource(dev, | 
 | 379 | 			IORESOURCE_MEM, 1); | 
 | 380 | 	int irq = platform_get_irq(dev, 0); | 
 | 381 | 	struct tmio_nand *tmio; | 
 | 382 | 	struct mtd_info *mtd; | 
 | 383 | 	struct nand_chip *nand_chip; | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 384 | 	struct mtd_partition *parts; | 
 | 385 | 	int nbparts = 0; | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 386 | 	int retval; | 
 | 387 |  | 
 | 388 | 	if (data == NULL) | 
 | 389 | 		dev_warn(&dev->dev, "NULL platform data!\n"); | 
 | 390 |  | 
 | 391 | 	tmio = kzalloc(sizeof *tmio, GFP_KERNEL); | 
 | 392 | 	if (!tmio) { | 
 | 393 | 		retval = -ENOMEM; | 
 | 394 | 		goto err_kzalloc; | 
 | 395 | 	} | 
 | 396 |  | 
 | 397 | 	tmio->dev = dev; | 
 | 398 |  | 
 | 399 | 	platform_set_drvdata(dev, tmio); | 
 | 400 | 	mtd = &tmio->mtd; | 
 | 401 | 	nand_chip = &tmio->chip; | 
 | 402 | 	mtd->priv = nand_chip; | 
 | 403 | 	mtd->name = "tmio-nand"; | 
 | 404 |  | 
| H Hartley Sweeten | 448791a | 2009-12-14 17:11:44 -0500 | [diff] [blame] | 405 | 	tmio->ccr = ioremap(ccr->start, resource_size(ccr)); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 406 | 	if (!tmio->ccr) { | 
 | 407 | 		retval = -EIO; | 
 | 408 | 		goto err_iomap_ccr; | 
 | 409 | 	} | 
 | 410 |  | 
| Dmitry Baryshkov | 076c7f4 | 2008-09-04 13:28:33 +0400 | [diff] [blame] | 411 | 	tmio->fcr_base = fcr->start & 0xfffff; | 
| H Hartley Sweeten | 448791a | 2009-12-14 17:11:44 -0500 | [diff] [blame] | 412 | 	tmio->fcr = ioremap(fcr->start, resource_size(fcr)); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 413 | 	if (!tmio->fcr) { | 
 | 414 | 		retval = -EIO; | 
 | 415 | 		goto err_iomap_fcr; | 
 | 416 | 	} | 
 | 417 |  | 
 | 418 | 	retval = tmio_hw_init(dev, tmio); | 
 | 419 | 	if (retval) | 
 | 420 | 		goto err_hwinit; | 
 | 421 |  | 
 | 422 | 	/* Set address of NAND IO lines */ | 
 | 423 | 	nand_chip->IO_ADDR_R = tmio->fcr; | 
 | 424 | 	nand_chip->IO_ADDR_W = tmio->fcr; | 
 | 425 |  | 
 | 426 | 	/* Set address of hardware control function */ | 
 | 427 | 	nand_chip->cmd_ctrl = tmio_nand_hwcontrol; | 
 | 428 | 	nand_chip->dev_ready = tmio_nand_dev_ready; | 
 | 429 | 	nand_chip->read_byte = tmio_nand_read_byte; | 
 | 430 | 	nand_chip->write_buf = tmio_nand_write_buf; | 
 | 431 | 	nand_chip->read_buf = tmio_nand_read_buf; | 
 | 432 | 	nand_chip->verify_buf = tmio_nand_verify_buf; | 
 | 433 |  | 
 | 434 | 	/* set eccmode using hardware ECC */ | 
 | 435 | 	nand_chip->ecc.mode = NAND_ECC_HW; | 
 | 436 | 	nand_chip->ecc.size = 512; | 
 | 437 | 	nand_chip->ecc.bytes = 6; | 
 | 438 | 	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; | 
 | 439 | 	nand_chip->ecc.calculate = tmio_nand_calculate_ecc; | 
| Atsushi Nemoto | 0f777fb | 2009-09-05 01:20:44 +0900 | [diff] [blame] | 440 | 	nand_chip->ecc.correct = tmio_nand_correct_data; | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 441 |  | 
 | 442 | 	if (data) | 
 | 443 | 		nand_chip->badblock_pattern = data->badblock_pattern; | 
 | 444 |  | 
 | 445 | 	/* 15 us command delay time */ | 
 | 446 | 	nand_chip->chip_delay = 15; | 
 | 447 |  | 
 | 448 | 	retval = request_irq(irq, &tmio_irq, | 
| Kay Sievers | 475b44c | 2009-01-06 10:44:38 -0800 | [diff] [blame] | 449 | 				IRQF_DISABLED, dev_name(&dev->dev), tmio); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 450 | 	if (retval) { | 
 | 451 | 		dev_err(&dev->dev, "request_irq error %d\n", retval); | 
 | 452 | 		goto err_irq; | 
 | 453 | 	} | 
 | 454 |  | 
 | 455 | 	tmio->irq = irq; | 
 | 456 | 	nand_chip->waitfunc = tmio_nand_wait; | 
 | 457 |  | 
 | 458 | 	/* Scan to find existence of the device */ | 
 | 459 | 	if (nand_scan(mtd, 1)) { | 
 | 460 | 		retval = -ENODEV; | 
 | 461 | 		goto err_scan; | 
 | 462 | 	} | 
 | 463 | 	/* Register the partitions */ | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 464 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 
 | 465 | 	nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); | 
 | 466 | #endif | 
 | 467 | 	if (nbparts <= 0 && data) { | 
 | 468 | 		parts = data->partition; | 
 | 469 | 		nbparts = data->num_partitions; | 
 | 470 | 	} | 
 | 471 |  | 
| Jamie Iles | d1e084e | 2011-05-23 10:23:36 +0100 | [diff] [blame] | 472 | 	retval = mtd_device_register(mtd, parts, nbparts); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 473 | 	if (!retval) | 
 | 474 | 		return retval; | 
 | 475 |  | 
 | 476 | 	nand_release(mtd); | 
 | 477 |  | 
 | 478 | err_scan: | 
 | 479 | 	if (tmio->irq) | 
 | 480 | 		free_irq(tmio->irq, tmio); | 
 | 481 | err_irq: | 
 | 482 | 	tmio_hw_stop(dev, tmio); | 
 | 483 | err_hwinit: | 
 | 484 | 	iounmap(tmio->fcr); | 
 | 485 | err_iomap_fcr: | 
 | 486 | 	iounmap(tmio->ccr); | 
 | 487 | err_iomap_ccr: | 
 | 488 | 	kfree(tmio); | 
 | 489 | err_kzalloc: | 
 | 490 | 	return retval; | 
 | 491 | } | 
 | 492 |  | 
 | 493 | static int tmio_remove(struct platform_device *dev) | 
 | 494 | { | 
 | 495 | 	struct tmio_nand *tmio = platform_get_drvdata(dev); | 
 | 496 |  | 
 | 497 | 	nand_release(&tmio->mtd); | 
 | 498 | 	if (tmio->irq) | 
 | 499 | 		free_irq(tmio->irq, tmio); | 
 | 500 | 	tmio_hw_stop(dev, tmio); | 
 | 501 | 	iounmap(tmio->fcr); | 
 | 502 | 	iounmap(tmio->ccr); | 
 | 503 | 	kfree(tmio); | 
 | 504 | 	return 0; | 
 | 505 | } | 
 | 506 |  | 
 | 507 | #ifdef CONFIG_PM | 
 | 508 | static int tmio_suspend(struct platform_device *dev, pm_message_t state) | 
 | 509 | { | 
| Andres Salomon | 944dc03 | 2011-03-01 12:32:20 -0800 | [diff] [blame] | 510 | 	const struct mfd_cell *cell = mfd_get_cell(dev); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 511 |  | 
 | 512 | 	if (cell->suspend) | 
 | 513 | 		cell->suspend(dev); | 
 | 514 |  | 
 | 515 | 	tmio_hw_stop(dev, platform_get_drvdata(dev)); | 
 | 516 | 	return 0; | 
 | 517 | } | 
 | 518 |  | 
 | 519 | static int tmio_resume(struct platform_device *dev) | 
 | 520 | { | 
| Andres Salomon | 944dc03 | 2011-03-01 12:32:20 -0800 | [diff] [blame] | 521 | 	const struct mfd_cell *cell = mfd_get_cell(dev); | 
| Ian Molton | ec43b81 | 2008-07-15 16:04:22 +0100 | [diff] [blame] | 522 |  | 
 | 523 | 	/* FIXME - is this required or merely another attack of the broken | 
 | 524 | 	 * SHARP platform? Looks suspicious. | 
 | 525 | 	 */ | 
 | 526 | 	tmio_hw_init(dev, platform_get_drvdata(dev)); | 
 | 527 |  | 
 | 528 | 	if (cell->resume) | 
 | 529 | 		cell->resume(dev); | 
 | 530 |  | 
 | 531 | 	return 0; | 
 | 532 | } | 
 | 533 | #else | 
 | 534 | #define tmio_suspend NULL | 
 | 535 | #define tmio_resume NULL | 
 | 536 | #endif | 
 | 537 |  | 
 | 538 | static struct platform_driver tmio_driver = { | 
 | 539 | 	.driver.name	= "tmio-nand", | 
 | 540 | 	.driver.owner	= THIS_MODULE, | 
 | 541 | 	.probe		= tmio_probe, | 
 | 542 | 	.remove		= tmio_remove, | 
 | 543 | 	.suspend	= tmio_suspend, | 
 | 544 | 	.resume		= tmio_resume, | 
 | 545 | }; | 
 | 546 |  | 
 | 547 | static int __init tmio_init(void) | 
 | 548 | { | 
 | 549 | 	return platform_driver_register(&tmio_driver); | 
 | 550 | } | 
 | 551 |  | 
 | 552 | static void __exit tmio_exit(void) | 
 | 553 | { | 
 | 554 | 	platform_driver_unregister(&tmio_driver); | 
 | 555 | } | 
 | 556 |  | 
 | 557 | module_init(tmio_init); | 
 | 558 | module_exit(tmio_exit); | 
 | 559 |  | 
 | 560 | MODULE_LICENSE("GPL v2"); | 
 | 561 | MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov"); | 
 | 562 | MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller"); | 
 | 563 | MODULE_ALIAS("platform:tmio-nand"); |