summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/diskonchip.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 11:25:54 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 11:25:54 -0800
commitac53b2e053fffc74372da94e734b92f37e70d32c (patch)
treecda82af0fcded5d230e9f56104d3988b7a75c8aa /drivers/mtd/nand/diskonchip.c
parentcf09112d160e6db21ff8427ce696f819b957423b (diff)
parent9146cbd52b11d4ade62dba8f238ec5e421c3fa2b (diff)
downloadlinux-rt-ac53b2e053fffc74372da94e734b92f37e70d32c.tar.gz
Merge tag 'for-linus-20160112' of git://git.infradead.org/linux-mtd
Pull MTD updates from Brian Norris: "Generic MTD: - populate the MTD device 'of_node' field (and get a proper 'of_node' symlink in sysfs) This yielded some new helper functions, and changes across a variety of drivers - partitioning cleanups, to prepare for better device-tree based partitioning in the future Eliminate a lot of boilerplate for drivers that want to use OF-based partition parsing The DT bindings for this didn't settle yet, so most non-cleanup portions are deferred for a future release NAND: - embed a struct mtd_info inside struct nand_chip This is really long overdue; too many drivers have to do the same silly boilerplate to allocate and link up two "independent" structs, when in fact, everyone is assuming there is an exact 1:1 relationship between a NAND chips struct and its underlying MTD. This aids improved helpers and should make certain abstractions easier in the future. Also causes a lot of churn, helped along by some automated code transformations - add more core support for detecting (and "correcting") bitflips in erased pages; requires opt-in by drivers, but at least we kill a few bad implementations and hopefully stave off future ones - pxa3xx_nand: cleanups, a few fixes, and PM improvements - new JZ4780 NAND driver SPI NOR: - provide default erase function, for controllers that just want to send the SECTOR_ERASE command directly - fix some module auto-loading issues with device tree ("jedec,spi-nor") - error handling fixes - new Mediatek QSPI flash driver Other: - cfi: force valid geometry Kconfig (finally!) This one used to trip up randconfigs occasionally, since bots aren't deterred by big scary "advanced configuration" menus More? Probably. See the commit logs" * tag 'for-linus-20160112' of git://git.infradead.org/linux-mtd: (168 commits) mtd: jz4780_nand: replace if/else blocks with switch/case mtd: nand: jz4780: Update ecc correction error codes mtd: nandsim: use nand_get_controller_data() mtd: jz4780_nand: remove useless mtd->priv = chip assignment staging: mt29f_spinand: make use of nand_set/get_controller_data() helpers mtd: nand: make use of nand_set/get_controller_data() helpers ARM: make use of nand_set/get_controller_data() helpers mtd: nand: add helpers to access ->priv mtd: nand: jz4780: driver for NAND devices on JZ4780 SoCs mtd: nand: jz4740: remove custom 'erased check' implementation mtd: nand: diskonchip: remove custom 'erased check' implementation mtd: nand: davinci: remove custom 'erased check' implementation mtd: nand: use nand_check_erased_ecc_chunk in default ECC read functions mtd: nand: return consistent error codes in ecc.correct() implementations doc: dt: mtd: new binding for jz4780-{nand,bch} mtd: cfi_cmdset_0001: fixing memory leak and handling failed kmalloc mtd: spi-nor: wait until lock/unlock operations are ready mtd: tests: consolidate kmalloc/memset 0 call to kzalloc jffs2: use to_delayed_work mtd: nand: assign reasonable default name for NAND drivers ...
Diffstat (limited to 'drivers/mtd/nand/diskonchip.c')
-rw-r--r--drivers/mtd/nand/diskonchip.c189
1 files changed, 78 insertions, 111 deletions
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 0802158a3f75..f170f3c31b34 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -74,10 +74,6 @@ struct doc_priv {
int (*late_init)(struct mtd_info *mtd);
};
-/* This is the syndrome computed by the HW ecc generator upon reading an empty
- page, one with all 0xff for data and stored ecc code. */
-static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
-
/* This is the ecc value computed by the HW ecc generator upon writing an empty
page, one with all 0xff for data. */
static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
@@ -299,8 +295,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (debug)
@@ -311,8 +307,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
static u_char doc2000_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -326,8 +322,8 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
if (debug)
@@ -343,8 +339,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -358,8 +354,8 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -379,8 +375,8 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
uint16_t ret;
doc200x_select_chip(mtd, nr);
@@ -425,8 +421,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
static void __init doc2000_count_chips(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
uint16_t mfrid;
int i;
@@ -447,7 +443,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
{
- struct doc_priv *doc = this->priv;
+ struct doc_priv *doc = nand_get_controller_data(this);
int status;
@@ -461,8 +457,8 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
WriteDOC(datum, docptr, CDSNSlowIO);
@@ -472,8 +468,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
static u_char doc2001_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
//ReadDOC(docptr, CDSNSlowIO);
@@ -486,8 +482,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -499,8 +495,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -516,8 +512,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static u_char doc2001plus_read_byte(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -531,8 +527,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -549,8 +545,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -580,8 +576,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -607,8 +603,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
static void doc200x_select_chip(struct mtd_info *mtd, int chip)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -638,8 +634,8 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (ctrl & NAND_CTRL_CHANGE) {
@@ -661,8 +657,8 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/*
@@ -767,8 +763,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
static int doc200x_dev_ready(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
if (DoC_is_MillenniumPlus(doc)) {
@@ -807,8 +803,8 @@ static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -826,8 +822,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -846,8 +842,8 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
/* This code is only called on write */
static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
int emptymatch = 1;
@@ -907,12 +903,11 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
uint8_t calc_ecc[6];
volatile u_char dummy;
- int emptymatch = 1;
/* flush the pipeline */
if (DoC_is_2000(doc)) {
@@ -936,37 +931,9 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
else
calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
- if (calc_ecc[i] != empty_read_syndrome[i])
- emptymatch = 0;
- }
- /* If emptymatch=1, the read syndrome is consistent with an
- all-0xff data and stored ecc block. Check the stored ecc. */
- if (emptymatch) {
- for (i = 0; i < 6; i++) {
- if (read_ecc[i] == 0xff)
- continue;
- emptymatch = 0;
- break;
- }
}
- /* If emptymatch still =1, check the data block. */
- if (emptymatch) {
- /* Note: this somewhat expensive test should not be triggered
- often. It could be optimized away by examining the data in
- the readbuf routine, and remembering the result. */
- for (i = 0; i < 512; i++) {
- if (dat[i] == 0xff)
- continue;
- emptymatch = 0;
- break;
- }
- }
- /* If emptymatch still =1, this is almost certainly a freshly-
- erased block, in which case the ECC will not come out right.
- We'll suppress the error and tell the caller everything's
- OK. Because it is. */
- if (!emptymatch)
- ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
+
+ ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
}
@@ -1007,8 +974,8 @@ static struct nand_ecclayout doc200x_oobinfo = {
mh1_page in the DOC private structure. */
static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
unsigned offs;
int ret;
size_t retlen;
@@ -1050,8 +1017,8 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
int ret = 0;
u_char *buf;
struct NFTLMediaHeader *mh;
@@ -1152,8 +1119,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
/* This is a stripped-down copy of the code in inftlmount.c */
static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
int ret = 0;
u_char *buf;
struct INFTLMediaHeader *mh;
@@ -1272,8 +1239,8 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
static int __init nftl_scan_bbt(struct mtd_info *mtd)
{
int ret, numparts;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
struct mtd_partition parts[2];
memset((char *)parts, 0, sizeof(parts));
@@ -1307,8 +1274,8 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
static int __init inftl_scan_bbt(struct mtd_info *mtd)
{
int ret, numparts;
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
struct mtd_partition parts[5];
if (this->numchips > doc->chips_per_floor) {
@@ -1360,8 +1327,8 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
static inline int __init doc2000_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
@@ -1376,8 +1343,8 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
static inline int __init doc2001_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf;
@@ -1406,8 +1373,8 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
static inline int __init doc2001plus_init(struct mtd_info *mtd)
{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct doc_priv *doc = nand_get_controller_data(this);
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
@@ -1523,8 +1490,8 @@ static int __init doc_probe(unsigned long physadr)
for (mtd = doclist; mtd; mtd = doc->nextdoc) {
unsigned char oldval;
unsigned char newval;
- nand = mtd->priv;
- doc = nand->priv;
+ nand = mtd_to_nand(mtd);
+ doc = nand_get_controller_data(nand);
/* Use the alias resolution register to determine if this is
in fact the same DOC aliased to a new address. If writes
to one chip's alias resolution register change the value on
@@ -1556,23 +1523,22 @@ static int __init doc_probe(unsigned long physadr)
printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
- len = sizeof(struct mtd_info) +
- sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
- mtd = kzalloc(len, GFP_KERNEL);
- if (!mtd) {
+ len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
+ (2 * sizeof(struct nand_bbt_descr));
+ nand = kzalloc(len, GFP_KERNEL);
+ if (!nand) {
ret = -ENOMEM;
goto fail;
}
- nand = (struct nand_chip *) (mtd + 1);
+ mtd = nand_to_mtd(nand);
doc = (struct doc_priv *) (nand + 1);
nand->bbt_td = (struct nand_bbt_descr *) (doc + 1);
nand->bbt_md = nand->bbt_td + 1;
- mtd->priv = nand;
mtd->owner = THIS_MODULE;
- nand->priv = doc;
+ nand_set_controller_data(nand, doc);
nand->select_chip = doc200x_select_chip;
nand->cmd_ctrl = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready;
@@ -1587,6 +1553,7 @@ static int __init doc_probe(unsigned long physadr)
nand->ecc.size = 512;
nand->ecc.bytes = 6;
nand->ecc.strength = 2;
+ nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
nand->bbt_options = NAND_BBT_USE_FLASH;
/* Skip the automatic BBT scan so we can run it manually */
nand->options |= NAND_SKIP_BBTSCAN;
@@ -1615,7 +1582,7 @@ static int __init doc_probe(unsigned long physadr)
haven't yet added it. This is handled without incident by
mtd_device_unregister, as far as I can tell. */
nand_release(mtd);
- kfree(mtd);
+ kfree(nand);
goto fail;
}
@@ -1643,14 +1610,14 @@ static void release_nanddoc(void)
struct doc_priv *doc;
for (mtd = doclist; mtd; mtd = nextmtd) {
- nand = mtd->priv;
- doc = nand->priv;
+ nand = mtd_to_nand(mtd);
+ doc = nand_get_controller_data(nand);
nextmtd = doc->nextdoc;
nand_release(mtd);
iounmap(doc->virtadr);
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
- kfree(mtd);
+ kfree(nand);
}
}