[PATCH] mtd onenand driver: check correct manufacturer
[linux-3.10.git] / drivers / mtd / onenand / onenand_base.c
index 75d7578..33d6f5c 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
@@ -84,25 +86,23 @@ static void onenand_writew(unsigned short value, void __iomem *addr)
 
 /**
  * onenand_block_address - [DEFAULT] Get block address
- * @param device       the device id
+ * @param this         onenand chip data structure
  * @param block                the block
  * @return             translated block address if DDP, otherwise same
  *
  * Setup Start Address 1 Register (F100h)
  */
-static int onenand_block_address(int device, int block)
+static int onenand_block_address(struct onenand_chip *this, int block)
 {
-       if (device & ONENAND_DEVICE_IS_DDP) {
+       if (this->device_id & ONENAND_DEVICE_IS_DDP) {
                /* Device Flash Core select, NAND Flash Block Address */
-               int dfs = 0, density, mask;
+               int dfs = 0;
 
-               density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
-               mask = (1 << (density + 6));
-
-               if (block & mask)
+               if (block & this->density_mask)
                        dfs = 1;
 
-               return (dfs << ONENAND_DDP_SHIFT) | (block & (mask - 1));
+               return (dfs << ONENAND_DDP_SHIFT) |
+                       (block & (this->density_mask - 1));
        }
 
        return block;
@@ -110,22 +110,19 @@ static int onenand_block_address(int device, int block)
 
 /**
  * onenand_bufferram_address - [DEFAULT] Get bufferram address
- * @param device       the device id
+ * @param this         onenand chip data structure
  * @param block                the block
  * @return             set DBS value if DDP, otherwise 0
  *
  * Setup Start Address 2 Register (F101h) for DDP
  */
-static int onenand_bufferram_address(int device, int block)
+static int onenand_bufferram_address(struct onenand_chip *this, int block)
 {
-       if (device & ONENAND_DEVICE_IS_DDP) {
+       if (this->device_id & ONENAND_DEVICE_IS_DDP) {
                /* Device BufferRAM Select */
-               int dbs = 0, density, mask;
-
-               density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
-               mask = (1 << (density + 6));
+               int dbs = 0;
 
-               if (block & mask)
+               if (block & this->density_mask)
                        dbs = 1;
 
                return (dbs << ONENAND_DDP_SHIFT);
@@ -223,7 +220,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
        /* NOTE: The setting order of the registers is very important! */
        if (cmd == ONENAND_CMD_BUFFERRAM) {
                /* Select DataRAM for DDP */
-               value = onenand_bufferram_address(this->device_id, block);
+               value = onenand_bufferram_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
 
                /* Switch to the next data buffer */
@@ -234,7 +231,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
 
        if (block != -1) {
                /* Write 'DFS, FBA' of Flash */
-               value = onenand_block_address(this->device_id, block);
+               value = onenand_block_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
        }
 
@@ -260,10 +257,10 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
                /* Write 'BSA, BSC' of DataRAM */
                value = onenand_buffer_address(dataram, sectors, count);
                this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
-                       
+
                if (readcmd) {
                        /* Select DataRAM for DDP */
-                       value = onenand_bufferram_address(this->device_id, block);
+                       value = onenand_bufferram_address(this, block);
                        this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
                }
        }
@@ -438,7 +435,7 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
  * onenand_check_bufferram - [GENERIC] Check BufferRAM information
  * @param mtd          MTD data structure
  * @param addr         address to check
- * @return             1 if there are valid data, otherwise 0 
+ * @return             1 if there are valid data, otherwise 0
  *
  * Check bufferram if there is data we required
  */
@@ -447,7 +444,7 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
        struct onenand_chip *this = mtd->priv;
        int block, page;
        int i;
-       
+
        block = (int) (addr >> this->erase_shift);
        page = (int) (addr >> this->page_shift);
        page &= this->page_mask;
@@ -477,7 +474,7 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
        struct onenand_chip *this = mtd->priv;
        int block, page;
        int i;
-       
+
        block = (int) (addr >> this->erase_shift);
        page = (int) (addr >> this->page_shift);
        page &= this->page_mask;
@@ -505,7 +502,7 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
  *
  * Get the device and lock it for exclusive access
  */
-static void onenand_get_device(struct mtd_info *mtd, int new_state)
+static int onenand_get_device(struct mtd_info *mtd, int new_state)
 {
        struct onenand_chip *this = mtd->priv;
        DECLARE_WAITQUEUE(wait, current);
@@ -520,12 +517,18 @@ static void onenand_get_device(struct mtd_info *mtd, int new_state)
                        spin_unlock(&this->chip_lock);
                        break;
                }
+               if (new_state == FL_PM_SUSPENDED) {
+                       spin_unlock(&this->chip_lock);
+                       return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
+               }
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&this->wq, &wait);
                spin_unlock(&this->chip_lock);
                schedule();
                remove_wait_queue(&this->wq, &wait);
        }
+
+       return 0;
 }
 
 /**
@@ -742,7 +745,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
 
        if (memcmp(dataram0, dataram1, mtd->oobblock))
                return -EBADMSG;
-       
+
        return 0;
 }
 #else
@@ -831,7 +834,7 @@ out:
        onenand_release_device(mtd);
 
        *retlen = written;
-       
+
        return ret;
 }
 
@@ -916,7 +919,7 @@ out:
        onenand_release_device(mtd);
 
        *retlen = written;
-       
+
        return 0;
 }
 
@@ -968,12 +971,12 @@ static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
        onenand_get_device(mtd, FL_WRITING);
 
        /* TODO handling oob */
-       
+
        /* Loop until all keve's data has been written */
        len = 0;
        while (count) {
                pbuf = buffer;
-               /* 
+               /*
                 * If the given tuple is >= pagesize then
                 * write it out from the iov
                 */
@@ -1307,7 +1310,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
                        continue;
 
                /* Set block address for read block status */
-               value = onenand_block_address(this->device_id, block);
+               value = onenand_block_address(this, block);
                this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
 
                /* Check lock status */
@@ -1315,7 +1318,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
                if (!(status & ONENAND_WP_US))
                        printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
        }
-       
+
        return 0;
 }
 
@@ -1343,7 +1346,6 @@ static void onenand_print_device_info(int device)
 
 static const struct onenand_manufacturers onenand_manuf_ids[] = {
         {ONENAND_MFR_SAMSUNG, "Samsung"},
-        {ONENAND_MFR_UNKNOWN, "Unknown"}
 };
 
 /**
@@ -1354,17 +1356,22 @@ static const struct onenand_manufacturers onenand_manuf_ids[] = {
  */
 static int onenand_check_maf(int manuf)
 {
+       int size = ARRAY_SIZE(onenand_manuf_ids);
+       char *name;
         int i;
 
-        for (i = 0; onenand_manuf_ids[i].id; i++) {
+       for (i = 0; i < size; i++)
                 if (manuf == onenand_manuf_ids[i].id)
                         break;
-        }
 
-        printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n",
-                onenand_manuf_ids[i].name, manuf);
+       if (i < size)
+               name = onenand_manuf_ids[i].name;
+       else
+               name = "Unknown";
+
+       printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
 
-        return (i != ONENAND_MFR_UNKNOWN);
+       return (i == size);
 }
 
 /**
@@ -1409,6 +1416,8 @@ static int onenand_probe(struct mtd_info *mtd)
 
        density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
        this->chipsize = (16 << density) << 20;
+       /* Set density mask. it is used for DDP */
+       this->density_mask = (1 << (density + 6));
 
        /* OneNAND page size & block size */
        /* The data buffer size is equal to page size */
@@ -1436,10 +1445,34 @@ static int onenand_probe(struct mtd_info *mtd)
                printk(KERN_INFO "Lock scheme is Continues Lock\n");
                this->options |= ONENAND_CONT_LOCK;
        }
-       
+
        return 0;
 }
 
+/**
+ * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
+ * @param mtd          MTD device structure
+ */
+static int onenand_suspend(struct mtd_info *mtd)
+{
+       return onenand_get_device(mtd, FL_PM_SUSPENDED);
+}
+
+/**
+ * onenand_resume - [MTD Interface] Resume the OneNAND flash
+ * @param mtd          MTD device structure
+ */
+static void onenand_resume(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       if (this->state == FL_PM_SUSPENDED)
+               onenand_release_device(mtd);
+       else
+               printk(KERN_ERR "resume() called for the chip which is not"
+                               "in suspended state\n");
+}
+
 
 /**
  * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
@@ -1506,7 +1539,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        }
 
        memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
-       
+
        /* Fill in remaining MTD driver data */
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
@@ -1527,8 +1560,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        mtd->sync = onenand_sync;
        mtd->lock = NULL;
        mtd->unlock = onenand_unlock;
-       mtd->suspend = NULL;
-       mtd->resume = NULL;
+       mtd->suspend = onenand_suspend;
+       mtd->resume = onenand_resume;
        mtd->block_isbad = onenand_block_isbad;
        mtd->block_markbad = onenand_block_markbad;
        mtd->owner = THIS_MODULE;