diff options
| author | Brian Norris <computersforpeace@gmail.com> | 2015-03-13 03:38:39 -0400 |
|---|---|---|
| committer | Brian Norris <computersforpeace@gmail.com> | 2015-03-27 13:37:38 -0400 |
| commit | 8cc7f33aadc8fb37b5a3f4c46f5fa83748a92a01 (patch) | |
| tree | eae708435c1462bed2bf4d460b36642adf69223b | |
| parent | 73c8aaf43629e83541332f66fd08699e20ea87bc (diff) | |
mtd: spi-nor: factor out replace-able flash_{lock,unlock}
Flash lock/unlock is a flash-specific operations. Factor out a callback
for it to more readily support other vendors.
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Tested-by: VIET NGA DAO <vndao@altera.com>
| -rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 57 | ||||
| -rw-r--r-- | include/linux/mtd/spi-nor.h | 5 |
2 files changed, 43 insertions, 19 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b6a5a0c269e1..60bf3caf1ead 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
| @@ -369,17 +369,13 @@ erase_err: | |||
| 369 | return ret; | 369 | return ret; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 372 | static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) |
| 373 | { | 373 | { |
| 374 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | 374 | struct mtd_info *mtd = nor->mtd; |
| 375 | uint32_t offset = ofs; | 375 | uint32_t offset = ofs; |
| 376 | uint8_t status_old, status_new; | 376 | uint8_t status_old, status_new; |
| 377 | int ret = 0; | 377 | int ret = 0; |
| 378 | 378 | ||
| 379 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); | ||
| 380 | if (ret) | ||
| 381 | return ret; | ||
| 382 | |||
| 383 | status_old = read_sr(nor); | 379 | status_old = read_sr(nor); |
| 384 | 380 | ||
| 385 | if (offset < mtd->size - (mtd->size / 2)) | 381 | if (offset < mtd->size - (mtd->size / 2)) |
| @@ -402,26 +398,18 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 402 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { | 398 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { |
| 403 | write_enable(nor); | 399 | write_enable(nor); |
| 404 | ret = write_sr(nor, status_new); | 400 | ret = write_sr(nor, status_new); |
| 405 | if (ret) | ||
| 406 | goto err; | ||
| 407 | } | 401 | } |
| 408 | 402 | ||
| 409 | err: | ||
| 410 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); | ||
| 411 | return ret; | 403 | return ret; |
| 412 | } | 404 | } |
| 413 | 405 | ||
| 414 | static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 406 | static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) |
| 415 | { | 407 | { |
| 416 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | 408 | struct mtd_info *mtd = nor->mtd; |
| 417 | uint32_t offset = ofs; | 409 | uint32_t offset = ofs; |
| 418 | uint8_t status_old, status_new; | 410 | uint8_t status_old, status_new; |
| 419 | int ret = 0; | 411 | int ret = 0; |
| 420 | 412 | ||
| 421 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); | ||
| 422 | if (ret) | ||
| 423 | return ret; | ||
| 424 | |||
| 425 | status_old = read_sr(nor); | 413 | status_old = read_sr(nor); |
| 426 | 414 | ||
| 427 | if (offset+len > mtd->size - (mtd->size / 64)) | 415 | if (offset+len > mtd->size - (mtd->size / 64)) |
| @@ -444,15 +432,41 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 444 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { | 432 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { |
| 445 | write_enable(nor); | 433 | write_enable(nor); |
| 446 | ret = write_sr(nor, status_new); | 434 | ret = write_sr(nor, status_new); |
| 447 | if (ret) | ||
| 448 | goto err; | ||
| 449 | } | 435 | } |
| 450 | 436 | ||
| 451 | err: | 437 | return ret; |
| 438 | } | ||
| 439 | |||
| 440 | static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
| 441 | { | ||
| 442 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | ||
| 443 | int ret; | ||
| 444 | |||
| 445 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); | ||
| 446 | if (ret) | ||
| 447 | return ret; | ||
| 448 | |||
| 449 | ret = nor->flash_lock(nor, ofs, len); | ||
| 450 | |||
| 452 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); | 451 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); |
| 453 | return ret; | 452 | return ret; |
| 454 | } | 453 | } |
| 455 | 454 | ||
| 455 | static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
| 456 | { | ||
| 457 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | ||
| 458 | int ret; | ||
| 459 | |||
| 460 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); | ||
| 461 | if (ret) | ||
| 462 | return ret; | ||
| 463 | |||
| 464 | ret = nor->flash_unlock(nor, ofs, len); | ||
| 465 | |||
| 466 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); | ||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | |||
| 456 | /* Used when the "_ext_id" is two bytes at most */ | 470 | /* Used when the "_ext_id" is two bytes at most */ |
| 457 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ | 471 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ |
| 458 | ((kernel_ulong_t)&(struct flash_info) { \ | 472 | ((kernel_ulong_t)&(struct flash_info) { \ |
| @@ -1045,6 +1059,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | |||
| 1045 | 1059 | ||
| 1046 | /* nor protection support for STmicro chips */ | 1060 | /* nor protection support for STmicro chips */ |
| 1047 | if (JEDEC_MFR(info) == CFI_MFR_ST) { | 1061 | if (JEDEC_MFR(info) == CFI_MFR_ST) { |
| 1062 | nor->flash_lock = stm_lock; | ||
| 1063 | nor->flash_unlock = stm_unlock; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | if (nor->flash_lock && nor->flash_unlock) { | ||
| 1048 | mtd->_lock = spi_nor_lock; | 1067 | mtd->_lock = spi_nor_lock; |
| 1049 | mtd->_unlock = spi_nor_unlock; | 1068 | mtd->_unlock = spi_nor_unlock; |
| 1050 | } | 1069 | } |
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4720b86ee73d..e5409524bb0a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h | |||
| @@ -155,6 +155,8 @@ enum spi_nor_option_flags { | |||
| 155 | * @write: [DRIVER-SPECIFIC] write data to the SPI NOR | 155 | * @write: [DRIVER-SPECIFIC] write data to the SPI NOR |
| 156 | * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR | 156 | * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR |
| 157 | * at the offset @offs | 157 | * at the offset @offs |
| 158 | * @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR | ||
| 159 | * @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR | ||
| 158 | * @priv: the private data | 160 | * @priv: the private data |
| 159 | */ | 161 | */ |
| 160 | struct spi_nor { | 162 | struct spi_nor { |
| @@ -189,6 +191,9 @@ struct spi_nor { | |||
| 189 | size_t len, size_t *retlen, const u_char *write_buf); | 191 | size_t len, size_t *retlen, const u_char *write_buf); |
| 190 | int (*erase)(struct spi_nor *nor, loff_t offs); | 192 | int (*erase)(struct spi_nor *nor, loff_t offs); |
| 191 | 193 | ||
| 194 | int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | ||
| 195 | int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | ||
| 196 | |||
| 192 | void *priv; | 197 | void *priv; |
| 193 | }; | 198 | }; |
| 194 | 199 | ||
