diff options
| -rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 56 | ||||
| -rw-r--r-- | include/linux/mtd/spi-nor.h | 10 |
2 files changed, 48 insertions, 18 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 33f6fc1b0eab..04751a73c3fe 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
| @@ -2629,14 +2629,44 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, | |||
| 2629 | /* Enable Quad I/O if needed. */ | 2629 | /* Enable Quad I/O if needed. */ |
| 2630 | enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 || | 2630 | enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 || |
| 2631 | spi_nor_get_protocol_width(nor->write_proto) == 4); | 2631 | spi_nor_get_protocol_width(nor->write_proto) == 4); |
| 2632 | if (enable_quad_io && params->quad_enable) { | 2632 | if (enable_quad_io && params->quad_enable) |
| 2633 | err = params->quad_enable(nor); | 2633 | nor->quad_enable = params->quad_enable; |
| 2634 | else | ||
| 2635 | nor->quad_enable = NULL; | ||
| 2636 | |||
| 2637 | return 0; | ||
| 2638 | } | ||
| 2639 | |||
| 2640 | static int spi_nor_init(struct spi_nor *nor) | ||
| 2641 | { | ||
| 2642 | int err; | ||
| 2643 | |||
| 2644 | /* | ||
| 2645 | * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up | ||
| 2646 | * with the software protection bits set | ||
| 2647 | */ | ||
| 2648 | if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || | ||
| 2649 | JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || | ||
| 2650 | JEDEC_MFR(nor->info) == SNOR_MFR_SST || | ||
| 2651 | nor->info->flags & SPI_NOR_HAS_LOCK) { | ||
| 2652 | write_enable(nor); | ||
| 2653 | write_sr(nor, 0); | ||
| 2654 | spi_nor_wait_till_ready(nor); | ||
| 2655 | } | ||
| 2656 | |||
| 2657 | if (nor->quad_enable) { | ||
| 2658 | err = nor->quad_enable(nor); | ||
| 2634 | if (err) { | 2659 | if (err) { |
| 2635 | dev_err(nor->dev, "quad mode not supported\n"); | 2660 | dev_err(nor->dev, "quad mode not supported\n"); |
| 2636 | return err; | 2661 | return err; |
| 2637 | } | 2662 | } |
| 2638 | } | 2663 | } |
| 2639 | 2664 | ||
| 2665 | if ((nor->addr_width == 4) && | ||
| 2666 | (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && | ||
| 2667 | !(nor->info->flags & SPI_NOR_4B_OPCODES)) | ||
| 2668 | set_4byte(nor, nor->info, 1); | ||
| 2669 | |||
| 2640 | return 0; | 2670 | return 0; |
| 2641 | } | 2671 | } |
| 2642 | 2672 | ||
| @@ -2707,20 +2737,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, | |||
| 2707 | if (ret) | 2737 | if (ret) |
| 2708 | return ret; | 2738 | return ret; |
| 2709 | 2739 | ||
| 2710 | /* | ||
| 2711 | * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up | ||
| 2712 | * with the software protection bits set | ||
| 2713 | */ | ||
| 2714 | |||
| 2715 | if (JEDEC_MFR(info) == SNOR_MFR_ATMEL || | ||
| 2716 | JEDEC_MFR(info) == SNOR_MFR_INTEL || | ||
| 2717 | JEDEC_MFR(info) == SNOR_MFR_SST || | ||
| 2718 | info->flags & SPI_NOR_HAS_LOCK) { | ||
| 2719 | write_enable(nor); | ||
| 2720 | write_sr(nor, 0); | ||
| 2721 | spi_nor_wait_till_ready(nor); | ||
| 2722 | } | ||
| 2723 | |||
| 2724 | if (!mtd->name) | 2740 | if (!mtd->name) |
| 2725 | mtd->name = dev_name(dev); | 2741 | mtd->name = dev_name(dev); |
| 2726 | mtd->priv = nor; | 2742 | mtd->priv = nor; |
| @@ -2803,8 +2819,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, | |||
| 2803 | if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || | 2819 | if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || |
| 2804 | info->flags & SPI_NOR_4B_OPCODES) | 2820 | info->flags & SPI_NOR_4B_OPCODES) |
| 2805 | spi_nor_set_4byte_opcodes(nor, info); | 2821 | spi_nor_set_4byte_opcodes(nor, info); |
| 2806 | else | ||
| 2807 | set_4byte(nor, info, 1); | ||
| 2808 | } else { | 2822 | } else { |
| 2809 | nor->addr_width = 3; | 2823 | nor->addr_width = 3; |
| 2810 | } | 2824 | } |
| @@ -2821,6 +2835,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, | |||
| 2821 | return ret; | 2835 | return ret; |
| 2822 | } | 2836 | } |
| 2823 | 2837 | ||
| 2838 | /* Send all the required SPI flash commands to initialize device */ | ||
| 2839 | nor->info = info; | ||
| 2840 | ret = spi_nor_init(nor); | ||
| 2841 | if (ret) | ||
| 2842 | return ret; | ||
| 2843 | |||
| 2824 | dev_info(dev, "%s (%lld Kbytes)\n", info->name, | 2844 | dev_info(dev, "%s (%lld Kbytes)\n", info->name, |
| 2825 | (long long)mtd->size >> 10); | 2845 | (long long)mtd->size >> 10); |
| 2826 | 2846 | ||
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 1f0a7fc7772f..d0c66a0975cf 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h | |||
| @@ -232,10 +232,17 @@ enum spi_nor_option_flags { | |||
| 232 | }; | 232 | }; |
| 233 | 233 | ||
| 234 | /** | 234 | /** |
| 235 | * struct flash_info - Forward declaration of a structure used internally by | ||
| 236 | * spi_nor_scan() | ||
| 237 | */ | ||
| 238 | struct flash_info; | ||
| 239 | |||
| 240 | /** | ||
| 235 | * struct spi_nor - Structure for defining a the SPI NOR layer | 241 | * struct spi_nor - Structure for defining a the SPI NOR layer |
| 236 | * @mtd: point to a mtd_info structure | 242 | * @mtd: point to a mtd_info structure |
| 237 | * @lock: the lock for the read/write/erase/lock/unlock operations | 243 | * @lock: the lock for the read/write/erase/lock/unlock operations |
| 238 | * @dev: point to a spi device, or a spi nor controller device. | 244 | * @dev: point to a spi device, or a spi nor controller device. |
| 245 | * @info: spi-nor part JDEC MFR id and other info | ||
| 239 | * @page_size: the page size of the SPI NOR | 246 | * @page_size: the page size of the SPI NOR |
| 240 | * @addr_width: number of address bytes | 247 | * @addr_width: number of address bytes |
| 241 | * @erase_opcode: the opcode for erasing a sector | 248 | * @erase_opcode: the opcode for erasing a sector |
| @@ -262,6 +269,7 @@ enum spi_nor_option_flags { | |||
| 262 | * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR | 269 | * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR |
| 263 | * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR | 270 | * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR |
| 264 | * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is | 271 | * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is |
| 272 | * @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode | ||
| 265 | * completely locked | 273 | * completely locked |
| 266 | * @priv: the private data | 274 | * @priv: the private data |
| 267 | */ | 275 | */ |
| @@ -269,6 +277,7 @@ struct spi_nor { | |||
| 269 | struct mtd_info mtd; | 277 | struct mtd_info mtd; |
| 270 | struct mutex lock; | 278 | struct mutex lock; |
| 271 | struct device *dev; | 279 | struct device *dev; |
| 280 | const struct flash_info *info; | ||
| 272 | u32 page_size; | 281 | u32 page_size; |
| 273 | u8 addr_width; | 282 | u8 addr_width; |
| 274 | u8 erase_opcode; | 283 | u8 erase_opcode; |
| @@ -296,6 +305,7 @@ struct spi_nor { | |||
| 296 | int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | 305 | int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); |
| 297 | int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | 306 | int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); |
| 298 | int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len); | 307 | int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len); |
| 308 | int (*quad_enable)(struct spi_nor *nor); | ||
| 299 | 309 | ||
| 300 | void *priv; | 310 | void *priv; |
| 301 | }; | 311 | }; |
