1b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* linux/drivers/mtd/nand/bf5xx_nand.c
2b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
3afc4bca63941746f1d49394620d294074150e664Michael Hennerich * Copyright 2006-2008 Analog Devices Inc.
4b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *	http://blackfin.uclinux.org/
5b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *	Bryan Wu <bryan.wu@analog.com>
6b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
78e87d7820a6362b6304924befb22d1ee79b754f3Joe Perches * Blackfin BF5xx on-chip NAND flash controller driver
8b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
9b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Derived from drivers/mtd/nand/s3c2410.c
10b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
11b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
12b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Derived from drivers/mtd/nand/cafe.c
13b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright © 2006 Red Hat, Inc.
14b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
15b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
16b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Changelog:
17b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *	12-Jun-2007  Bryan Wu:  Initial version
18b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *	18-Jul-2007  Bryan Wu:
19b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *		- ECC_HW and ECC_SW supported
20b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *		- DMA supported in ECC_HW
21b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *		- YAFFS tested as rootfs in both ECC_HW and ECC_SW
22b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
23b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * This program is free software; you can redistribute it and/or modify
24b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * it under the terms of the GNU General Public License as published by
25b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * the Free Software Foundation; either version 2 of the License, or
26b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * (at your option) any later version.
27b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
28b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * This program is distributed in the hope that it will be useful,
29b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * but WITHOUT ANY WARRANTY; without even the implied warranty of
30b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * GNU General Public License for more details.
32b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
33b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * You should have received a copy of the GNU General Public License
34b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * along with this program; if not, write to the Free Software
35b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
36b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu*/
37b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
38b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/module.h>
39b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/types.h>
40b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/init.h>
41b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/kernel.h>
42b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/string.h>
43b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/ioport.h>
44b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/platform_device.h>
45b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/delay.h>
46b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/dma-mapping.h>
47b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/err.h>
48b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/slab.h>
49b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/io.h>
50b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/bitops.h>
51b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
52b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/mtd.h>
53b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/nand.h>
54b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/nand_ecc.h>
55b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/partitions.h>
56b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
57b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/blackfin.h>
58b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/dma.h>
59b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/cacheflush.h>
60b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/nand.h>
61b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/portmux.h>
62b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
63b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_NAME	"bf5xx-nand"
64b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_VERSION	"1.2"
65b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_AUTHOR	"Bryan Wu <bryan.wu@analog.com>"
66b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_DESC	"BF5xx on-chip NAND FLash Controller Driver"
67b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
68ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_STAT Masks */
69ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define NBUSY       0x01  /* Not Busy */
70ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_FULL     0x02  /* Write Buffer Full */
71ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_WR_STAT  0x04  /* Page Write Pending */
72ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_RD_STAT  0x08  /* Page Read Pending */
73ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_EMPTY    0x10  /* Write Buffer Empty */
74ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger
75ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_IRQSTAT Masks */
76ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define NBUSYIRQ    0x01  /* Not Busy IRQ */
77ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_OVF      0x02  /* Write Buffer Overflow */
78ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_EDGE     0x04  /* Write Buffer Edge Detect */
79ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define RD_RDY      0x08  /* Read Data Ready */
80ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WR_DONE     0x10  /* Page Write Done */
81ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger
82ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_RST Masks */
83ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define ECC_RST     0x01  /* ECC (and NFC counters) Reset */
84ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger
85ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_PGCTL Masks */
86ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_RD_START 0x01  /* Page Read Start */
87ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_WR_START 0x02  /* Page Write Start */
88ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger
89b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
90b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int hardware_ecc = 1;
91b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#else
92b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int hardware_ecc;
93b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#endif
94b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
95afc4bca63941746f1d49394620d294074150e664Michael Hennerichstatic const unsigned short bfin_nfc_pin_req[] =
96a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	{P_NAND_CE,
97a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_RB,
98a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D0,
99a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D1,
100a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D2,
101a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D3,
102a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D4,
103a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D5,
104a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D6,
105a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_D7,
106a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_WE,
107a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_RE,
108a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_CLE,
109a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 P_NAND_ALE,
110a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich	 0};
111b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
112fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
113fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysingerstatic struct nand_ecclayout bootrom_ecclayout = {
114fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger	.eccbytes = 24,
115fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger	.eccpos = {
116fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2,
117fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2,
118fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2,
119fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2,
120fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2,
121fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2,
122fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2,
123fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2
124fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger	},
125fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger	.oobfree = {
126fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 0 + 3, 5 },
127fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 1 + 3, 5 },
128fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 2 + 3, 5 },
129fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 3 + 3, 5 },
130fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 4 + 3, 5 },
131fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 5 + 3, 5 },
132fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 6 + 3, 5 },
133fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		{ 0x8 * 7 + 3, 5 },
134fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger	}
135fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger};
136fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#endif
137fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger
138b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
139b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Data structures for bf5xx nand flash controller driver
140b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
141b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
142b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* bf5xx nand info */
143b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustruct bf5xx_nand_info {
144b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* mtd info */
145b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct nand_hw_control		controller;
146b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct mtd_info			mtd;
147b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct nand_chip		chip;
148b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
149b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* platform info */
150b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_platform	*platform;
151b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
152b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* device info */
153b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct device			*device;
154b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
155b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* DMA stuff */
156b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct completion		dma_completion;
157b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu};
158b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
159b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
160b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Conversion functions
161b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
162b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
163b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
164b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return container_of(mtd, struct bf5xx_nand_info, mtd);
165b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
166b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
167b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
168b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
169b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return platform_get_drvdata(pdev);
170b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
171b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
172b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
173b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
174b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return pdev->dev.platform_data;
175b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
176b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
177b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
178b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * struct nand_chip interface function pointers
179b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
180b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
181b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
182b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_hwcontrol
183b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
184b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Issue command and address cycles to the chip
185b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
186b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
187b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu				   unsigned int ctrl)
188b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
189b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (cmd == NAND_CMD_NONE)
190b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return;
191b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
192b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	while (bfin_read_NFC_STAT() & WB_FULL)
193b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		cpu_relax();
194b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
195b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (ctrl & NAND_CLE)
196b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_CMD(cmd);
197fd508da2208696db146cd1be2bb2e8b799f6e3a2Barry Song	else if (ctrl & NAND_ALE)
198b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_ADDR(cmd);
199b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
200b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
201b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
202b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
203b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_devready()
204b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
205b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * returns 0 if the nand is busy, 1 if it is ready
206b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
207b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_devready(struct mtd_info *mtd)
208b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
209d2350c2ab51df7088d3db73a4c85ad73ded37a01Barry Song	unsigned short val = bfin_read_NFC_STAT();
210b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
211d2350c2ab51df7088d3db73a4c85ad73ded37a01Barry Song	if ((val & NBUSY) == NBUSY)
212b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 1;
213b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	else
214b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 0;
215b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
216b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
217b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
218b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * ECC functions
219b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * These allow the bf5xx to use the controller's ECC
220b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * generator block to ECC the data as it passes through
221b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
222b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
223b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
224b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * ECC error correction function
225b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
226b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
227b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu					u_char *read_ecc, u_char *calc_ecc)
228b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
229b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
230b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u32 syndrome[5];
231b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u32 calced, stored;
232b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int i;
233b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	unsigned short failing_bit, failing_byte;
234b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u_char data;
235b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
236b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
237b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
238b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
239b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	syndrome[0] = (calced ^ stored);
240b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
241b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
242b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * syndrome 0: all zero
243b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * No error in data
244b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * No action
245b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
246b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (!syndrome[0] || !calced || !stored)
247b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 0;
248b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
249b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
250b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * sysdrome 0: only one bit is one
251b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * ECC data was incorrect
252b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * No action
253b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
254b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (hweight32(syndrome[0]) == 1) {
255b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_err(info->device, "ECC data was incorrect!\n");
256b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 1;
257b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
258b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
259b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
260b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
261b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
262b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	syndrome[4] = syndrome[2] ^ syndrome[3];
263b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
264b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	for (i = 0; i < 5; i++)
265b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
266b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
267b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_info(info->device,
268b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		"calced[0x%08x], stored[0x%08x]\n",
269b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		calced, stored);
270b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
271b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
272b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * sysdrome 0: exactly 11 bits are one, each parity
273b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * and parity' pair is 1 & 0 or 0 & 1.
274b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * 1-bit correctable error
275b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * Correct the error
276b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
277b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
278b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_info(info->device,
279b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			"1-bit correctable error, correct it.\n");
280b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_info(info->device,
281b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			"syndrome[1] 0x%08x\n", syndrome[1]);
282b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
283b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		failing_bit = syndrome[1] & 0x7;
284b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		failing_byte = syndrome[1] >> 0x3;
285b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		data = *(dat + failing_byte);
286b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		data = data ^ (0x1 << failing_bit);
287b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		*(dat + failing_byte) = data;
288b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
289b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 0;
290b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
291b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
292b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
293b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * sysdrome 0: random data
294b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * More than 1-bit error, non-correctable error
295b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * Discard data, mark bad block
296b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
297b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_err(info->device,
298b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		"More than 1-bit error, non-correctable error.\n");
299b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_err(info->device,
300b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		"Please discard data, mark bad block\n");
301b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
302b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 1;
303b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
304b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
305b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
306b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu					u_char *read_ecc, u_char *calc_ecc)
307b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
30844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
309b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int ret;
310b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
311b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
312b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
31344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	/* If ecc size is 512, correct second 256 bytes */
31444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (chip->ecc.size == 512) {
315b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dat += 256;
31644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		read_ecc += 3;
31744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		calc_ecc += 3;
318e274f025e2caaadc1a6dd41adc9c9a19be075110Mike Frysinger		ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
319b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
320b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
321b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return ret;
322b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
323b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
324b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
325b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
326b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return;
327b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
328b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
329b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
330b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		const u_char *dat, u_char *ecc_code)
331b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
332b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
33344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
334b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u16 ecc0, ecc1;
335b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u32 code[2];
336b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u8 *p;
337b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
33844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	/* first 3 bytes ECC code for 256 page size */
339b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	ecc0 = bfin_read_NFC_ECC0();
340b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	ecc1 = bfin_read_NFC_ECC1();
341b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
342cf840392e83914b9fcdbce8a8a2bc17a84cf0353Mike Frysinger	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
343b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
344b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
345b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
3465eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu	p = (u8 *) code;
3475eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu	memcpy(ecc_code, p, 3);
3485eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu
34944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	/* second 3 bytes ECC code for 512 ecc size */
35044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (chip->ecc.size == 512) {
351b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		ecc0 = bfin_read_NFC_ECC2();
352b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		ecc1 = bfin_read_NFC_ECC3();
353cf840392e83914b9fcdbce8a8a2bc17a84cf0353Mike Frysinger		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
3545eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu
3555eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu		/* second 3 bytes in ecc_code for second 256
3565eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu		 * bytes of 512 page size
3575eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu		 */
3585eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu		p = (u8 *) (code + 1);
3595eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu		memcpy((ecc_code + 3), p, 3);
360b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
361b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
362b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
363b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
364b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
365b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
366b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
367b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * PIO mode for buffer writing and reading
368b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
369b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
370b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
371b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int i;
372b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	unsigned short val;
373b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
374b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
375b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * Data reads are requested by first writing to NFC_DATA_RD
376b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * and then reading back from NFC_READ.
377b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
378b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	for (i = 0; i < len; i++) {
379b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		while (bfin_read_NFC_STAT() & WB_FULL)
380b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			cpu_relax();
381b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
382b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		/* Contents do not matter */
383b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_DATA_RD(0x0000);
384b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		SSYNC();
385b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
386b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
387b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			cpu_relax();
388b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
389b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		buf[i] = bfin_read_NFC_READ();
390b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
391b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		val = bfin_read_NFC_IRQSTAT();
392b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		val |= RD_RDY;
393b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_IRQSTAT(val);
394b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		SSYNC();
395b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
396b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
397b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
398b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
399b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
400b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	uint8_t val;
401b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
402b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bf5xx_nand_read_buf(mtd, &val, 1);
403b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
404b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return val;
405b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
406b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
407b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_write_buf(struct mtd_info *mtd,
408b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu				const uint8_t *buf, int len)
409b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
410b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int i;
411b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
412b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	for (i = 0; i < len; i++) {
413b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		while (bfin_read_NFC_STAT() & WB_FULL)
414b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			cpu_relax();
415b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
416b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_DATA_WR(buf[i]);
417b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		SSYNC();
418b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
419b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
420b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
421b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
422b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
423b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int i;
424b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u16 *p = (u16 *) buf;
425b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	len >>= 1;
426b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
427b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
428b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * Data reads are requested by first writing to NFC_DATA_RD
429b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * and then reading back from NFC_READ.
430b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
431b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bfin_write_NFC_DATA_RD(0x5555);
432b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
433b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
434b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
435b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	for (i = 0; i < len; i++)
436b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		p[i] = bfin_read_NFC_READ();
437b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
438b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
439b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_write_buf16(struct mtd_info *mtd,
440b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu				const uint8_t *buf, int len)
441b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
442b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int i;
443b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	u16 *p = (u16 *) buf;
444b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	len >>= 1;
445b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
446b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	for (i = 0; i < len; i++)
447b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bfin_write_NFC_DATA_WR(p[i]);
448b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
449b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
450b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
451b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
452b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
453b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * DMA functions for buffer writing and reading
454b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
455b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
456b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
457b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = dev_id;
458b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
459b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	clear_dma_irqstat(CH_NFC);
460b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	disable_dma(CH_NFC);
461b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	complete(&info->dma_completion);
462b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
463b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return IRQ_HANDLED;
464b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
465b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
466530c3b60658687e2ad7bf98ef83631a8280ae8a6Mike Frysingerstatic void bf5xx_nand_dma_rw(struct mtd_info *mtd,
467b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu				uint8_t *buf, int is_read)
468b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
469b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
47044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
471b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	unsigned short val;
472b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
473b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
474b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu			mtd, buf, is_read);
475b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
476b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
477b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * Before starting a dma transfer, be sure to invalidate/flush
478b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * the cache over the address range of your DMA buffer to
479b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * prevent cache coherency problems. Otherwise very subtle bugs
480b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * can be introduced to your driver.
481b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
482b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (is_read)
483b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		invalidate_dcache_range((unsigned int)buf,
48444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song				(unsigned int)(buf + chip->ecc.size));
485b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	else
486b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		flush_dcache_range((unsigned int)buf,
48744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song				(unsigned int)(buf + chip->ecc.size));
488b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
489b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/*
490b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * This register must be written before each page is
491b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * transferred to generate the correct ECC register
492b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * values.
493b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
494ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger	bfin_write_NFC_RST(ECC_RST);
495b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
496752b957a37ee1cc09fccb39a8bc5843edf32119bBarry Song	while (bfin_read_NFC_RST() & ECC_RST)
497752b957a37ee1cc09fccb39a8bc5843edf32119bBarry Song		cpu_relax();
498b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
499b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	disable_dma(CH_NFC);
500b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	clear_dma_irqstat(CH_NFC);
501b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
502b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* setup DMA register with Blackfin DMA API */
503b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	set_dma_config(CH_NFC, 0x0);
504b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	set_dma_start_addr(CH_NFC, (unsigned long) buf);
505c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai
506ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger	/* The DMAs have different size on BF52x and BF54x */
507c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#ifdef CONFIG_BF52x
50844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
509c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai	set_dma_x_modify(CH_NFC, 2);
510c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai	val = DI_EN | WDSIZE_16;
511c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#endif
512c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai
513c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#ifdef CONFIG_BF54x
51444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
515b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	set_dma_x_modify(CH_NFC, 4);
516b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	val = DI_EN | WDSIZE_32;
517c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#endif
518c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai	/* setup write or read operation */
519b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (is_read)
520b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		val |= WNR;
521b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	set_dma_config(CH_NFC, val);
522b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	enable_dma(CH_NFC);
523b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
524b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* Start PAGE read/write operation */
525b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (is_read)
526ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger		bfin_write_NFC_PGCTL(PG_RD_START);
527b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	else
528ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger		bfin_write_NFC_PGCTL(PG_WR_START);
529b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	wait_for_completion(&info->dma_completion);
530b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
531b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
532b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
533b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu					uint8_t *buf, int len)
534b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
535b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
53644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
537b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
538b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
539b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
54044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (len == chip->ecc.size)
541b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_dma_rw(mtd, buf, 1);
542b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	else
543b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_read_buf(mtd, buf, len);
544b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
545b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
546b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
547b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu				const uint8_t *buf, int len)
548b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
549b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
55044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
551b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
552b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
553b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
55444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (len == chip->ecc.size)
555b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
556b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	else
557b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_write_buf(mtd, buf, len);
558b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
559b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
560085d45fb5216c25b69103e5d861fabdc4389e221Barry Songstatic int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
561085d45fb5216c25b69103e5d861fabdc4389e221Barry Song		uint8_t *buf, int page)
562085d45fb5216c25b69103e5d861fabdc4389e221Barry Song{
563085d45fb5216c25b69103e5d861fabdc4389e221Barry Song	bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
564085d45fb5216c25b69103e5d861fabdc4389e221Barry Song	bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
565085d45fb5216c25b69103e5d861fabdc4389e221Barry Song
566085d45fb5216c25b69103e5d861fabdc4389e221Barry Song	return 0;
567085d45fb5216c25b69103e5d861fabdc4389e221Barry Song}
568085d45fb5216c25b69103e5d861fabdc4389e221Barry Song
569085d45fb5216c25b69103e5d861fabdc4389e221Barry Songstatic void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
570085d45fb5216c25b69103e5d861fabdc4389e221Barry Song		const uint8_t *buf)
571085d45fb5216c25b69103e5d861fabdc4389e221Barry Song{
572085d45fb5216c25b69103e5d861fabdc4389e221Barry Song	bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
573085d45fb5216c25b69103e5d861fabdc4389e221Barry Song	bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
574085d45fb5216c25b69103e5d861fabdc4389e221Barry Song}
575085d45fb5216c25b69103e5d861fabdc4389e221Barry Song
576b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
577b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * System initialization functions
578b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
579b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
580b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
581b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int ret;
582b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
583b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* Do not use dma */
584b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (!hardware_ecc)
585b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return 0;
586b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
587b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	init_completion(&info->dma_completion);
588b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
589b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* Request NFC DMA channel */
590b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	ret = request_dma(CH_NFC, "BF5XX NFC driver");
591b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (ret < 0) {
592b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_err(info->device, " unable to get DMA channel\n");
593b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		return ret;
594b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
595b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
59608d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger#ifdef CONFIG_BF54x
59708d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger	/* Setup DMAC1 channel mux for NFC which shared with SDH */
59808d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
59908d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger	SSYNC();
60008d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger#endif
60108d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger
602bfc492571e7ad1eb4b9fe3ac8ab0a7cdaecf8ecaMike Frysinger	set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
603b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
604b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* Turn off the DMA channel first */
605b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	disable_dma(CH_NFC);
606b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
607b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
608b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
6094f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wustatic void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
6104f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu{
6114f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	/* Free NFC DMA channel */
6124f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	if (hardware_ecc)
6134f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		free_dma(CH_NFC);
6144f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu}
6154f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu
616b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
617b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * BF5XX NFC hardware initialization
618b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *  - pin mux setup
619b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *  - clear interrupt status
620b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
621b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
622b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
623b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int err = 0;
624b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	unsigned short val;
625b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_platform *plat = info->platform;
626b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
627b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* setup NFC_CTL register */
628b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_info(info->device,
62944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		"data_width=%d, wr_dly=%d, rd_dly=%d\n",
630b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		(plat->data_width ? 16 : 8),
631b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		plat->wr_dly, plat->rd_dly);
632b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
63344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	val = (1 << NFC_PG_SIZE_OFFSET) |
634b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		(plat->data_width << NFC_NWIDTH_OFFSET) |
635b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		(plat->rd_dly << NFC_RDDLY_OFFSET) |
63600355b0baadf949f02ab7d3e2bd222e3fbcc72eeBarry Song		(plat->wr_dly << NFC_WRDLY_OFFSET);
637b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
638b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
639b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bfin_write_NFC_CTL(val);
640b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
641b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
642b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* clear interrupt status */
643b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bfin_write_NFC_IRQMASK(0x0);
644b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
645b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	val = bfin_read_NFC_IRQSTAT();
646b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bfin_write_NFC_IRQSTAT(val);
647b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	SSYNC();
648b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
649b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* DMA initialization  */
650b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (bf5xx_nand_dma_init(info))
651b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		err = -ENXIO;
652b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
653b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return err;
654b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
655b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
656b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
657b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Device management interface
658b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
6598d30cab06920f9efb7e089f2c69e451b2a637d8aMike Frysingerstatic int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
660b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
661b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct mtd_info *mtd = &info->mtd;
662b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct mtd_partition *parts = info->platform->partitions;
663b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int nr = info->platform->nr_partitions;
664b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
66588146872f0fbd89e425e3e0db71d42df8db9d932Jamie Iles	return mtd_device_register(mtd, parts, nr);
666b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
667b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
6682445af3853928bf3ee7960e09f548a1b07924091Mike Frysingerstatic int __devexit bf5xx_nand_remove(struct platform_device *pdev)
669b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
670b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = to_nand_info(pdev);
671b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
672b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	platform_set_drvdata(pdev, NULL);
673b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
674b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* first thing we need to do is release all our mtds
675b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * and their partitions, then go through freeing the
676b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 * resources used
677b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	 */
6788b865d5efd9205b131dd9a43a6f450c05d38aaa1Mike Frysinger	nand_release(&info->mtd);
679b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
680b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	peripheral_free_list(bfin_nfc_pin_req);
6814f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	bf5xx_nand_dma_remove(info);
682b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
683b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* free the common resources */
684b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	kfree(info);
685b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
686b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
687b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
688b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
68944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Songstatic int bf5xx_nand_scan(struct mtd_info *mtd)
69044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song{
69144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	struct nand_chip *chip = mtd->priv;
69244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	int ret;
69344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song
694eac15a429a27cb74115daaf4c1127c5e854d50e4Mike Frysinger	ret = nand_scan_ident(mtd, 1, NULL);
69544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (ret)
69644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		return ret;
69744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song
69844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (hardware_ecc) {
69944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		/*
70044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		 * for nand with page size > 512B, think it as several sections with 512B
70144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		 */
70244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		if (likely(mtd->writesize >= 512)) {
70344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			chip->ecc.size = 512;
70444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			chip->ecc.bytes = 6;
7056a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn			chip->ecc.strength = 2;
70644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		} else {
70744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			chip->ecc.size = 256;
70844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			chip->ecc.bytes = 3;
7096a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn			chip->ecc.strength = 1;
71044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
71144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song			SSYNC();
71244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song		}
71344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	}
71444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song
71544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	return	nand_scan_tail(mtd);
71644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song}
71744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song
718b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/*
719b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_probe
720b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *
721b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * called by device layer when it finds a device matching
722b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * one our driver can handled. This code checks to see if
723b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * it can allocate all necessary resources then calls the
724b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * nand layer to look for devices
725b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */
7262445af3853928bf3ee7960e09f548a1b07924091Mike Frysingerstatic int __devinit bf5xx_nand_probe(struct platform_device *pdev)
727b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
728b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
729b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = NULL;
730b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct nand_chip *chip = NULL;
731b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct mtd_info *mtd = NULL;
732b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	int err = 0;
733b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
734b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(&pdev->dev, "(%p)\n", pdev);
735b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
7364f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	if (!plat) {
7374f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		dev_err(&pdev->dev, "no platform specific information\n");
7384f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		return -EINVAL;
7394f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	}
7404f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu
741afc4bca63941746f1d49394620d294074150e664Michael Hennerich	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
7420ee002b041cb45ab3cc5384b86271d41ccf90fe1Mike Frysinger		dev_err(&pdev->dev, "requesting Peripherals failed\n");
743afc4bca63941746f1d49394620d294074150e664Michael Hennerich		return -EFAULT;
744afc4bca63941746f1d49394620d294074150e664Michael Hennerich	}
745afc4bca63941746f1d49394620d294074150e664Michael Hennerich
746b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	info = kzalloc(sizeof(*info), GFP_KERNEL);
747b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (info == NULL) {
748b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		dev_err(&pdev->dev, "no memory for flash info\n");
749b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		err = -ENOMEM;
7504f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		goto out_err_kzalloc;
751b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
752b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
753b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	platform_set_drvdata(pdev, info);
754b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
755b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	spin_lock_init(&info->controller.lock);
756b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	init_waitqueue_head(&info->controller.wq);
757b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
758b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	info->device     = &pdev->dev;
759b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	info->platform   = plat;
760b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
761b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* initialise chip data struct */
762b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip = &info->chip;
763b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
764b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (plat->data_width)
765b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->options |= NAND_BUSWIDTH_16;
766b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
767b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
768b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
769b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->read_buf = (plat->data_width) ?
770b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
771b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->write_buf = (plat->data_width) ?
772b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
773b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
774b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->read_byte    = bf5xx_nand_read_byte;
775b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
776b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
777b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->dev_ready    = bf5xx_nand_devready;
778b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
779b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->priv	   = &info->mtd;
780b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->controller   = &info->controller;
781b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
782b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
783b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
784b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
785b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	chip->chip_delay   = 0;
786b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
787b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* initialise mtd info data struct */
788b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	mtd 		= &info->mtd;
789b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	mtd->priv	= chip;
790b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	mtd->owner	= THIS_MODULE;
791b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
792b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* initialise the hardware */
793b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	err = bf5xx_nand_hw_init(info);
7944f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	if (err)
7954f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		goto out_err_hw_init;
796b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
797b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* setup hardware ECC data struct */
798b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	if (hardware_ecc) {
799fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
800fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger		chip->ecc.layout = &bootrom_ecclayout;
801fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#endif
802b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->read_buf      = bf5xx_nand_dma_read_buf;
803b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->write_buf     = bf5xx_nand_dma_write_buf;
804b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->ecc.calculate = bf5xx_nand_calculate_ecc;
805b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->ecc.correct   = bf5xx_nand_correct_data;
806b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->ecc.mode	    = NAND_ECC_HW;
807b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->ecc.hwctl	    = bf5xx_nand_enable_hwecc;
808085d45fb5216c25b69103e5d861fabdc4389e221Barry Song		chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
809085d45fb5216c25b69103e5d861fabdc4389e221Barry Song		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
810b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	} else {
811b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		chip->ecc.mode	    = NAND_ECC_SOFT;
812b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
813b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
814b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* scan hardware nand chip and setup mtd info data struct */
81544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song	if (bf5xx_nand_scan(mtd)) {
816b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		err = -ENXIO;
8174f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu		goto out_err_nand_scan;
818b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	}
819b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
8205954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
8215954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger	chip->badblockpos = 63;
8225954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger#endif
8235954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger
824b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	/* add NAND partition */
825b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	bf5xx_nand_add_partition(info);
826b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
827b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	dev_dbg(&pdev->dev, "initialised ok\n");
828b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
829b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
8304f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_nand_scan:
8314f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	bf5xx_nand_dma_remove(info);
8324f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_hw_init:
8334f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	platform_set_drvdata(pdev, NULL);
8344f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	kfree(info);
8354f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_kzalloc:
8364f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu	peripheral_free_list(bfin_nfc_pin_req);
837b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
838b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return err;
839b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
840b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
841b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* PM Support */
842b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#ifdef CONFIG_PM
843b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
844b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
845b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
846b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = platform_get_drvdata(dev);
847b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
848b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
849b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
850b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
851b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_resume(struct platform_device *dev)
852b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
853b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	struct bf5xx_nand_info *info = platform_get_drvdata(dev);
854b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
855b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return 0;
856b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
857b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
858b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#else
859b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define bf5xx_nand_suspend NULL
860b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define bf5xx_nand_resume NULL
861b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#endif
862b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
863b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* driver device registration */
864b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct platform_driver bf5xx_nand_driver = {
865b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	.probe		= bf5xx_nand_probe,
8662445af3853928bf3ee7960e09f548a1b07924091Mike Frysinger	.remove		= __devexit_p(bf5xx_nand_remove),
867b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	.suspend	= bf5xx_nand_suspend,
868b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	.resume		= bf5xx_nand_resume,
869b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	.driver		= {
870b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		.name	= DRV_NAME,
871b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		.owner	= THIS_MODULE,
872b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	},
873b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu};
874b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
875b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int __init bf5xx_nand_init(void)
876b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
877b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
878b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu		DRV_DESC, DRV_VERSION);
879b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
880b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	return platform_driver_register(&bf5xx_nand_driver);
881b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
882b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
883b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void __exit bf5xx_nand_exit(void)
884b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{
885b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu	platform_driver_unregister(&bf5xx_nand_driver);
886b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}
887b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
888b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wumodule_init(bf5xx_nand_init);
889b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wumodule_exit(bf5xx_nand_exit);
890b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu
891b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_LICENSE("GPL");
892b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_AUTHOR(DRV_AUTHOR);
893b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_DESCRIPTION(DRV_DESC);
8941ff184225b15930ea118ac2130f074c741d34f08Kay SieversMODULE_ALIAS("platform:" DRV_NAME);
895