]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/commitdiff
mtd: spi-nor: Changed spi-nor.c and spi.h for dual parallel support
authorAnurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
Tue, 5 May 2015 15:05:37 +0000 (20:35 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Thu, 7 May 2015 13:02:33 +0000 (15:02 +0200)
Added dual parallel support for spi-nor

Signed-off-by: Anurag Kumar Vulisha <anuragku@xilinx.com>
Reviewed-by: Harini Katakam <harinik@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/mtd/spi-nor/spi-nor.c
include/linux/spi/spi.h

index 9aee560ef1e51bd75c714469536c8b9a0dc5906c..1080b97dfea5504e57a0589967780d419308b0ed 100644 (file)
@@ -72,15 +72,24 @@ static const struct spi_device_id *spi_nor_match_id(const char *name);
 static int read_sr(struct spi_nor *nor)
 {
        int ret;
-       u8 val;
+       u8 val[2];
 
-       ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
-       if (ret < 0) {
-               pr_err("error %d reading SR\n", (int) ret);
-               return ret;
+       if (nor->isparallel) {
+               ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2);
+               if (ret < 0) {
+                       pr_err("error %d reading SR\n", (int) ret);
+                       return ret;
+               }
+               val[0] |= val[1];
+       } else {
+               ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1);
+               if (ret < 0) {
+                       pr_err("error %d reading SR\n", (int) ret);
+                       return ret;
+               }
        }
 
-       return val;
+       return val[0];
 }
 
 /*
@@ -91,15 +100,24 @@ static int read_sr(struct spi_nor *nor)
 static int read_fsr(struct spi_nor *nor)
 {
        int ret;
-       u8 val;
+       u8 val[2];
 
-       ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
-       if (ret < 0) {
-               pr_err("error %d reading FSR\n", ret);
-               return ret;
+       if (nor->isparallel) {
+               ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2);
+               if (ret < 0) {
+                       pr_err("error %d reading FSR\n", ret);
+                       return ret;
+               }
+               val[0] &= val[1];
+       } else {
+               ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1);
+               if (ret < 0) {
+                       pr_err("error %d reading FSR\n", ret);
+                       return ret;
+               }
        }
 
-       return val;
+       return val[0];
 }
 
 /*
@@ -427,6 +445,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
        if (ret)
                return ret;
 
+       if (nor->isparallel)
+               nor->spi->master->flags |= SPI_DATA_STRIPE;
        /* whole-chip erase? */
        if (len == mtd->size) {
                write_enable(nor);
@@ -500,11 +520,15 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
 
+       if (nor->isparallel)
+               nor->spi->master->flags &= ~SPI_DATA_STRIPE;
        return ret;
 
 erase_err:
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
        instr->state = MTD_ERASE_FAILED;
+       if (nor->isparallel)
+               nor->spi->master->flags &= ~SPI_DATA_STRIPE;
        return ret;
 }
 
@@ -951,7 +975,9 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
        int                     tmp;
        u8                      id[SPI_NOR_MAX_ID_LEN];
        struct flash_info       *info;
+       nor->spi->master->flags &= ~SPI_BOTH_FLASH;
 
+       /* If more than one flash are present,need to read id of second flash */
        tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
        if (tmp < 0) {
                dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
@@ -1001,11 +1027,16 @@ static int spi_nor_read_ext(struct mtd_info *mtd, loff_t from, size_t len,
        ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
        if (ret)
                return ret;
+       if (nor->isparallel)
+               nor->spi->master->flags |= SPI_DATA_STRIPE;
        if (nor->addr_width == 4) {
                /* Wait till previous write/erase is done. */
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
                        goto read_err;
+               /* Die cross over issue is not handled */
+               if (nor->isparallel)
+                       from /= 2;
                ret = nor->read(nor, from, len, retlen, buf);
                goto read_err;
        }
@@ -1043,6 +1074,8 @@ static int spi_nor_read_ext(struct mtd_info *mtd, loff_t from, size_t len,
        *retlen = read_count;
 
 read_err:
+       if (nor->isparallel)
+               nor->spi->master->flags &= ~SPI_DATA_STRIPE;
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
        return ret;
 }
@@ -1182,7 +1215,10 @@ static int spi_nor_write_ext(struct mtd_info *mtd, loff_t to, size_t len,
        ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
        if (ret)
                return ret;
+       if (nor->isparallel)
+               nor->spi->master->flags |= SPI_DATA_STRIPE;
        if (nor->addr_width == 4) {
+               /* Die cross over issue is not handled */
                ret = spi_nor_write(mtd, offset, len, retlen, buf);
                goto write_err;
        }
@@ -1220,6 +1256,8 @@ static int spi_nor_write_ext(struct mtd_info *mtd, loff_t to, size_t len,
        *retlen = write_count;
 
 write_err:
+       if (nor->isparallel)
+               nor->spi->master->flags &= ~SPI_DATA_STRIPE;
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
        return ret;
 }
@@ -1398,8 +1436,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
                u32 is_dual;
 
                np_spi = of_get_next_parent(np);
-               if (of_property_match_string(np_spi, "compatible",
-                   "xlnx,zynq-qspi-1.0") >= 0) {
+               if ((of_property_match_string(np_spi, "compatible",
+                   "xlnx,zynq-qspi-1.0") >= 0) ||
+                       (of_property_match_string(np_spi, "compatible",
+                                       "xlnx,zynqmp-qspi-1.0") >= 0)) {
                        if (of_property_read_u32(np_spi, "is-dual",
                                                 &is_dual) < 0) {
                                /* Default to single if prop not defined */
@@ -1415,6 +1455,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
                                        mtd->size <<= nor->shift;
                                        nor->isparallel = 1;
                                        nor->isstacked = 0;
+                                       nor->spi->master->flags |=
+                                                       SPI_BOTH_FLASH;
                                } else {
 #ifdef CONFIG_SPI_ZYNQ_QSPI_DUAL_STACKED
                                        /* dual stacked */
index e86e96bc3034bb8afee5bceb04d47edb6e4a7392..864966d674e058eb4c553a7598a2829f25d8b147 100644 (file)
@@ -362,6 +362,8 @@ struct spi_master {
 #define SPI_MASTER_MUST_TX      BIT(4)         /* requires tx */
 #define SPI_MASTER_U_PAGE      BIT(5)          /* select upper flash */
 #define SPI_MASTER_QUAD_MODE   BIT(6)          /* support quad mode */
+#define SPI_DATA_STRIPE                BIT(7)          /* support data stripe */
+#define SPI_BOTH_FLASH         BIT(8)          /* enable both flashes */
 
        /* lock and mutex for SPI bus locking */
        spinlock_t              bus_lock_spinlock;