Core MTD changes:
* dt-bindings: Drop unneeded quotes * mtdblock: Tolerate corrected bit-flips * Use of_property_read_bool() for boolean properties * Avoid magic values * Avoid printing error messages on probe deferrals * Prepare mtd_otp_nvmem_add() to handle -EPROBE_DEFER * Fix error path for nvmem provider * Fix nvmem error reporting * Provide unique name for nvmem device MTD device changes: * lpddr_cmds: Remove unused words variable * bcm63xxpart: Remove MODULE_LICENSE in non-modules SPI NOR core changes: * Introduce Read While Write support for flashes featuring several banks * Set the 4-Byte Address Mode method based on SFDP data * Allow post_sfdp hook to return errors * Parse SCCR MC table and introduce support for multi-chip devices SPI NOR manufacturer drivers changes: * macronix: Add support for mx25uw51245g with RWW * spansion: - Determine current address mode at runtime as it can be changed in a non-volatile way and differ from factory defaults or from what SFDP advertises. - Enable JFFS2 write buffer mode for few ECC'd NOR flashes: S25FS256T, s25hx and s28hx - Add support for s25hl02gt and s25hs02gt Raw NAND core changes: * Convert to platform remove callback returning void * Fix spelling mistake waifunc() -> waitfunc() Raw NAND controller driver changes: * imx: Remove unused is_imx51_nfc and imx53_nfc functions * omap2: Drop obsolete dependency on COMPILE_TEST * orion: Use devm_platform_ioremap_resource() * qcom: - Use of_property_present() for testing DT property presence - Use devm_platform_get_and_ioremap_resource() * stm32_fmc2: Depends on ARCH_STM32 instead of MACH_STM32MP157 * tmio: Remove reference to config MTD_NAND_TMIO in the parsers Raw NAND manufacturer driver changes: * hynix: Fix up bit 0 of sdr_timing_mode SPI-NAND changes: * Add support for ESMT F50x1G41LB -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmRANmIACgkQJWrqGEe9 VoRU2QgAl8XFkLs1h88wGi6ln/MSK0cQJZWUzteGgWuaBQCMNfgGFzqPHyJ7ygO9 l4U4O1L/IvACvJx5QHm/lH5Mig23jym9J8YfV1Kf9aVYOlBKRNysbi+DdktESGG9 6HmpS0nQfkC84qA8ouInOp+AZYjFEPRrBfp5UWkSRHiQJvcYnt2iS2oOLk3LNY6y zduBOno3mric2ZlBbg+ZCURhQzrr3k8c4VXV+LHSslqsmH/2sOFlg78hLJx922Y+ FTfYnx82iLIvFAJttRi2bXWKuE1Yr2XWJ3iEHKxmOA2vPmYi6mDBHTYhnikGSpm+ GhARHH+JhW7qzLbaq5ZC3HGH58aC/g== =aYlo -----END PGP SIGNATURE----- Merge tag 'mtd/for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux Pull mtd updates from Miquel Raynal: "Core MTD changes: - dt-bindings: Drop unneeded quotes - mtdblock: Tolerate corrected bit-flips - Use of_property_read_bool() for boolean properties - Avoid magic values - Avoid printing error messages on probe deferrals - Prepare mtd_otp_nvmem_add() to handle -EPROBE_DEFER - Fix error path for nvmem provider - Fix nvmem error reporting - Provide unique name for nvmem device MTD device changes: - lpddr_cmds: Remove unused words variable - bcm63xxpart: Remove MODULE_LICENSE in non-modules SPI NOR core changes: - Introduce Read While Write support for flashes featuring several banks - Set the 4-Byte Address Mode method based on SFDP data - Allow post_sfdp hook to return errors - Parse SCCR MC table and introduce support for multi-chip devices SPI NOR manufacturer drivers changes: - macronix: Add support for mx25uw51245g with RWW - spansion: - Determine current address mode at runtime as it can be changed in a non-volatile way and differ from factory defaults or from what SFDP advertises. - Enable JFFS2 write buffer mode for few ECC'd NOR flashes: S25FS256T, s25hx and s28hx - Add support for s25hl02gt and s25hs02gt Raw NAND core changes: - Convert to platform remove callback returning void - Fix spelling mistake waifunc() -> waitfunc() Raw NAND controller driver changes: - imx: Remove unused is_imx51_nfc and imx53_nfc functions - omap2: Drop obsolete dependency on COMPILE_TEST - orion: Use devm_platform_ioremap_resource() - qcom: - Use of_property_present() for testing DT property presence - Use devm_platform_get_and_ioremap_resource() - stm32_fmc2: Depends on ARCH_STM32 instead of MACH_STM32MP157 - tmio: Remove reference to config MTD_NAND_TMIO in the parsers Raw NAND manufacturer driver changes: - hynix: Fix up bit 0 of sdr_timing_mode SPI-NAND changes: - Add support for ESMT F50x1G41LB" * tag 'mtd/for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (55 commits) mtd: nand: Convert to platform remove callback returning void mtd: onenand: omap2: Drop obsolete dependency on COMPILE_TEST mtd: spi-nor: spansion: Add support for s25hl02gt and s25hs02gt mtd: spi-nor: spansion: Add a new ->ready() hook for multi-chip device mtd: spi-nor: spansion: Rework cypress_nor_quad_enable_volatile() for multi-chip device support mtd: spi-nor: spansion: Rework cypress_nor_get_page_size() for multi-chip device support mtd: spi-nor: sfdp: Add support for SCCR map for multi-chip device mtd: spi-nor: Extract volatile register offset from SCCR map mtd: spi-nor: Allow post_sfdp hook to return errors mtd: spi-nor: spansion: Rename method to cypress_nor_get_page_size mtd: spi-nor: spansion: Enable JFFS2 write buffer for S25FS256T mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s25hx SEMPER flash mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s28hx SEMPER flash mtd: spi-nor: spansion: Determine current address mode mtd: spi-nor: core: Introduce spi_nor_set_4byte_addr_mode() mtd: spi-nor: core: Update flash's current address mode when changing address mode mtd: spi-nor: Stop exporting spi_nor_restore() mtd: spi-nor: Set the 4-Byte Address Mode method based on SFDP data mtd: spi-nor: core: Make spi_nor_set_4byte_addr_mode_brwr public mtd: spi-nor: core: Update name and description of spi_nor_set_4byte_addr_mode ...
This commit is contained in:
commit
eb8322d714
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Allwinner A10 NAND Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Arasan NAND Flash Controller with ONFI 3.1 support
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: PL353 NAND Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
@ -93,7 +93,7 @@ required:
|
||||
unevaluatedProperties: false
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Intel LGM SoC NAND Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Ramuthevar Vadivel Murugan <vadivel.muruganx.ramuthevar@linux.intel.com>
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Rob Herring <robh@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "mtd.yaml#"
|
||||
- $ref: mtd.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
|
@ -14,7 +14,7 @@ description: |
|
||||
file systems on embedded devices.
|
||||
|
||||
allOf:
|
||||
- $ref: "mtd.yaml#"
|
||||
- $ref: mtd.yaml#
|
||||
- $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "mtd.yaml#"
|
||||
- $ref: mtd.yaml#
|
||||
|
||||
description: |
|
||||
This file covers the generic description of a NAND chip. It implies that the
|
||||
|
@ -51,7 +51,7 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"^nand@[a-f0-9]$":
|
||||
$ref: "nand-chip.yaml#"
|
||||
$ref: nand-chip.yaml#
|
||||
|
||||
properties:
|
||||
reg:
|
||||
|
@ -31,7 +31,7 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"^partition@[0-9a-f]+$":
|
||||
$ref: "partition.yaml#"
|
||||
$ref: partition.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm4908-firmware
|
||||
|
@ -32,7 +32,7 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"^partition@[0-9a-f]+$":
|
||||
$ref: "partition.yaml#"
|
||||
$ref: partition.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
|
@ -46,7 +46,7 @@ patternProperties:
|
||||
- 512
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml#"
|
||||
- $ref: nand-controller.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml"
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Rockchip SoCs NAND FLASH Controller (NFC)
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml#"
|
||||
- $ref: nand-controller.yaml#
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-chip.yaml#"
|
||||
- $ref: nand-chip.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
|
@ -45,7 +45,7 @@ patternProperties:
|
||||
enum: [1, 4, 8]
|
||||
|
||||
allOf:
|
||||
- $ref: "nand-controller.yaml#"
|
||||
- $ref: nand-controller.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
@ -63,10 +63,10 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
$ref: "/schemas/mtd/partitions/partition.yaml"
|
||||
$ref: /schemas/mtd/partitions/partition.yaml
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml"
|
||||
- $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -36,10 +36,10 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
$ref: "/schemas/mtd/partitions/partition.yaml"
|
||||
$ref: /schemas/mtd/partitions/partition.yaml
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml"
|
||||
- $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -63,6 +63,3 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should
|
||||
initialize the necessary fields for spi_nor{}. Please see
|
||||
drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c
|
||||
when you want to write a new driver for a SPI NOR controller.
|
||||
Another API is spi_nor_restore(), this is used to restore the status of SPI
|
||||
flash chip such as addressing mode. Call it whenever detach the driver from
|
||||
device or reboot the system.
|
||||
|
@ -820,8 +820,8 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev,
|
||||
pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]);
|
||||
pdata->board_flash_info->size = be32_to_cpup(&addr[1]);
|
||||
|
||||
if (of_get_property(pp, "st,smi-fast-mode", NULL))
|
||||
pdata->board_flash_info->fast_mode = 1;
|
||||
pdata->board_flash_info->fast_mode =
|
||||
of_property_read_bool(pp, "st,smi-fast-mode");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip,
|
||||
{
|
||||
struct lpddr_private *lpddr = map->fldrv_priv;
|
||||
map_word datum;
|
||||
int ret, wbufsize, word_gap, words;
|
||||
int ret, wbufsize, word_gap;
|
||||
const struct kvec *vec;
|
||||
unsigned long vec_seek;
|
||||
unsigned long prog_buf_ofs;
|
||||
@ -421,10 +421,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip,
|
||||
}
|
||||
/* Figure out the number of words to write */
|
||||
word_gap = (-adr & (map_bankwidth(map)-1));
|
||||
words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
|
||||
if (!word_gap) {
|
||||
words--;
|
||||
} else {
|
||||
if (word_gap) {
|
||||
word_gap = map_bankwidth(map) - word_gap;
|
||||
adr -= word_gap;
|
||||
datum = map_word_ff(map);
|
||||
|
@ -112,7 +112,7 @@ static int uflash_probe(struct platform_device *op)
|
||||
/* Flashprom must have the "user" property in order to
|
||||
* be used by this driver.
|
||||
*/
|
||||
if (!of_find_property(dp, "user", NULL))
|
||||
if (!of_property_read_bool(dp, "user"))
|
||||
return -ENODEV;
|
||||
|
||||
return uflash_devinit(op, dp);
|
||||
|
@ -16,8 +16,10 @@ static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, char *buf)
|
||||
{
|
||||
size_t retlen;
|
||||
int err;
|
||||
|
||||
if (mtd_read(dev->mtd, (block * 512), 512, &retlen, buf))
|
||||
err = mtd_read(dev->mtd, (block * 512), 512, &retlen, buf);
|
||||
if (err && !mtd_is_bitflip(err))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
|
||||
struct device_node *node = mtd_get_of_node(mtd);
|
||||
struct nvmem_config config = {};
|
||||
|
||||
config.id = -1;
|
||||
config.id = NVMEM_DEVID_NONE;
|
||||
config.dev = &mtd->dev;
|
||||
config.name = dev_name(&mtd->dev);
|
||||
config.owner = THIS_MODULE;
|
||||
@ -536,12 +536,11 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
|
||||
mtd->nvmem = nvmem_register(&config);
|
||||
if (IS_ERR(mtd->nvmem)) {
|
||||
/* Just ignore if there is no NVMEM support in the kernel */
|
||||
if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP) {
|
||||
if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP)
|
||||
mtd->nvmem = NULL;
|
||||
} else {
|
||||
dev_err(&mtd->dev, "Failed to register NVMEM device\n");
|
||||
return PTR_ERR(mtd->nvmem);
|
||||
}
|
||||
else
|
||||
return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem),
|
||||
"Failed to register NVMEM device\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -739,7 +738,7 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
|
||||
mutex_unlock(&mtd_table_mutex);
|
||||
|
||||
if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) {
|
||||
if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
|
||||
if (IS_BUILTIN(CONFIG_MTD)) {
|
||||
pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
|
||||
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
|
||||
@ -888,8 +887,8 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
|
||||
|
||||
/* OTP nvmem will be registered on the physical device */
|
||||
config.dev = mtd->dev.parent;
|
||||
config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible);
|
||||
config.id = NVMEM_DEVID_NONE;
|
||||
config.name = compatible;
|
||||
config.id = NVMEM_DEVID_AUTO;
|
||||
config.owner = THIS_MODULE;
|
||||
config.type = NVMEM_TYPE_OTP;
|
||||
config.root_only = true;
|
||||
@ -905,7 +904,6 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
|
||||
nvmem = NULL;
|
||||
|
||||
of_node_put(np);
|
||||
kfree(config.name);
|
||||
|
||||
return nvmem;
|
||||
}
|
||||
@ -940,6 +938,7 @@ static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
|
||||
|
||||
static int mtd_otp_nvmem_add(struct mtd_info *mtd)
|
||||
{
|
||||
struct device *dev = mtd->dev.parent;
|
||||
struct nvmem_device *nvmem;
|
||||
ssize_t size;
|
||||
int err;
|
||||
@ -953,8 +952,8 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
|
||||
nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size,
|
||||
mtd_nvmem_user_otp_reg_read);
|
||||
if (IS_ERR(nvmem)) {
|
||||
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
|
||||
return PTR_ERR(nvmem);
|
||||
err = PTR_ERR(nvmem);
|
||||
goto err;
|
||||
}
|
||||
mtd->otp_user_nvmem = nvmem;
|
||||
}
|
||||
@ -971,7 +970,6 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
|
||||
nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size,
|
||||
mtd_nvmem_fact_otp_reg_read);
|
||||
if (IS_ERR(nvmem)) {
|
||||
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
|
||||
err = PTR_ERR(nvmem);
|
||||
goto err;
|
||||
}
|
||||
@ -983,7 +981,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
|
||||
|
||||
err:
|
||||
nvmem_unregister(mtd->otp_user_nvmem);
|
||||
return err;
|
||||
return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1023,10 +1021,14 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
|
||||
|
||||
mtd_set_dev_defaults(mtd);
|
||||
|
||||
ret = mtd_otp_nvmem_add(mtd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
|
||||
ret = add_mtd_device(mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Prefer parsed partitions over driver-provided fallback */
|
||||
@ -1061,9 +1063,12 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
|
||||
register_reboot_notifier(&mtd->reboot_notifier);
|
||||
}
|
||||
|
||||
ret = mtd_otp_nvmem_add(mtd);
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
nvmem_unregister(mtd->otp_user_nvmem);
|
||||
nvmem_unregister(mtd->otp_factory_nvmem);
|
||||
}
|
||||
|
||||
if (ret && device_is_registered(&mtd->dev))
|
||||
del_mtd_device(mtd);
|
||||
|
||||
|
@ -848,13 +848,11 @@ static int mxic_ecc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxic_ecc_remove(struct platform_device *pdev)
|
||||
static void mxic_ecc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mxic_ecc_engine *mxic = platform_get_drvdata(pdev);
|
||||
|
||||
nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mxic_ecc_of_ids[] = {
|
||||
@ -871,7 +869,7 @@ static struct platform_driver mxic_ecc_driver = {
|
||||
.of_match_table = mxic_ecc_of_ids,
|
||||
},
|
||||
.probe = mxic_ecc_probe,
|
||||
.remove = mxic_ecc_remove,
|
||||
.remove_new = mxic_ecc_remove,
|
||||
};
|
||||
module_platform_driver(mxic_ecc_driver);
|
||||
|
||||
|
@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC
|
||||
config MTD_ONENAND_OMAP2
|
||||
tristate "OneNAND on OMAP2/OMAP3 support"
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM)
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on OMAP_GPMC
|
||||
help
|
||||
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
|
||||
|
@ -85,7 +85,7 @@ out_free_info:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int generic_onenand_remove(struct platform_device *pdev)
|
||||
static void generic_onenand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct onenand_info *info = platform_get_drvdata(pdev);
|
||||
struct resource *res = pdev->resource;
|
||||
@ -97,8 +97,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
|
||||
iounmap(info->onenand.base);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver generic_onenand_driver = {
|
||||
@ -106,7 +104,7 @@ static struct platform_driver generic_onenand_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = generic_onenand_probe,
|
||||
.remove = generic_onenand_remove,
|
||||
.remove_new = generic_onenand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(generic_onenand_driver);
|
||||
|
@ -581,7 +581,7 @@ err_release_dma:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap2_onenand_remove(struct platform_device *pdev)
|
||||
static void omap2_onenand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
@ -589,8 +589,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
|
||||
if (c->dma_chan)
|
||||
dma_release_channel(c->dma_chan);
|
||||
omap2_onenand_shutdown(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id omap2_onenand_id_table[] = {
|
||||
@ -601,7 +599,7 @@ MODULE_DEVICE_TABLE(of, omap2_onenand_id_table);
|
||||
|
||||
static struct platform_driver omap2_onenand_driver = {
|
||||
.probe = omap2_onenand_probe,
|
||||
.remove = omap2_onenand_remove,
|
||||
.remove_new = omap2_onenand_remove,
|
||||
.shutdown = omap2_onenand_shutdown,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
|
@ -943,13 +943,11 @@ static int s3c_onenand_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_onenand_remove(struct platform_device *pdev)
|
||||
static void s3c_onenand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtd_info *mtd = platform_get_drvdata(pdev);
|
||||
|
||||
onenand_release(mtd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_pm_ops_suspend(struct device *dev)
|
||||
@ -996,7 +994,7 @@ static struct platform_driver s3c_onenand_driver = {
|
||||
},
|
||||
.id_table = s3c_onenand_driver_ids,
|
||||
.probe = s3c_onenand_probe,
|
||||
.remove = s3c_onenand_remove,
|
||||
.remove_new = s3c_onenand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(s3c_onenand_driver);
|
||||
|
@ -373,7 +373,7 @@ config MTD_NAND_TEGRA
|
||||
|
||||
config MTD_NAND_STM32_FMC2
|
||||
tristate "Support for NAND controller on STM32MP SoCs"
|
||||
depends on MACH_STM32MP157 || COMPILE_TEST
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Enables support for NAND Flash chips on SoCs containing the FMC2
|
||||
|
@ -397,7 +397,7 @@ err_nand_cleanup:
|
||||
/*
|
||||
* Clean up routine
|
||||
*/
|
||||
static int gpio_nand_remove(struct platform_device *pdev)
|
||||
static void gpio_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_nand *priv = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
|
||||
@ -410,8 +410,6 @@ static int gpio_nand_remove(struct platform_device *pdev)
|
||||
ret = mtd_device_unregister(mtd);
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(mtd_to_nand(mtd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table);
|
||||
|
||||
static struct platform_driver gpio_nand_driver = {
|
||||
.probe = gpio_nand_probe,
|
||||
.remove = gpio_nand_remove,
|
||||
.remove_new = gpio_nand_remove,
|
||||
.id_table = gpio_nand_plat_id_table,
|
||||
.driver = {
|
||||
.name = "ams-delta-nand",
|
||||
|
@ -1496,7 +1496,7 @@ disable_controller_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int anfc_remove(struct platform_device *pdev)
|
||||
static void anfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct arasan_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -1504,8 +1504,6 @@ static int anfc_remove(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(nfc->bus_clk);
|
||||
clk_disable_unprepare(nfc->controller_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id anfc_ids[] = {
|
||||
@ -1525,7 +1523,7 @@ static struct platform_driver anfc_driver = {
|
||||
.of_match_table = anfc_ids,
|
||||
},
|
||||
.probe = anfc_probe,
|
||||
.remove = anfc_remove,
|
||||
.remove_new = anfc_remove,
|
||||
};
|
||||
module_platform_driver(anfc_driver);
|
||||
|
||||
|
@ -2626,13 +2626,11 @@ static int atmel_nand_controller_probe(struct platform_device *pdev)
|
||||
return caps->ops->probe(pdev, caps);
|
||||
}
|
||||
|
||||
static int atmel_nand_controller_remove(struct platform_device *pdev)
|
||||
static void atmel_nand_controller_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
|
||||
|
||||
WARN_ON(nc->caps->ops->remove(nc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
|
||||
@ -2663,7 +2661,7 @@ static struct platform_driver atmel_nand_controller_driver = {
|
||||
.pm = &atmel_nand_controller_pm_ops,
|
||||
},
|
||||
.probe = atmel_nand_controller_probe,
|
||||
.remove = atmel_nand_controller_remove,
|
||||
.remove_new = atmel_nand_controller_remove,
|
||||
};
|
||||
module_platform_driver(atmel_nand_controller_driver);
|
||||
|
||||
|
@ -337,7 +337,7 @@ out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au1550nd_remove(struct platform_device *pdev)
|
||||
static void au1550nd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -350,7 +350,6 @@ static int au1550nd_remove(struct platform_device *pdev)
|
||||
iounmap(ctx->base);
|
||||
release_mem_region(r->start, 0x1000);
|
||||
kfree(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver au1550nd_driver = {
|
||||
@ -358,7 +357,7 @@ static struct platform_driver au1550nd_driver = {
|
||||
.name = "au1550-nand",
|
||||
},
|
||||
.probe = au1550nd_probe,
|
||||
.remove = au1550nd_remove,
|
||||
.remove_new = au1550nd_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(au1550nd_driver);
|
||||
|
@ -57,7 +57,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm47xxnflash_remove(struct platform_device *pdev)
|
||||
static void bcm47xxnflash_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &nflash->nand_chip;
|
||||
@ -66,13 +66,11 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
|
||||
ret = mtd_device_unregister(nand_to_mtd(chip));
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bcm47xxnflash_driver = {
|
||||
.probe = bcm47xxnflash_probe,
|
||||
.remove = bcm47xxnflash_remove,
|
||||
.remove_new = bcm47xxnflash_remove,
|
||||
.driver = {
|
||||
.name = "bcma_nflash",
|
||||
},
|
||||
|
@ -3055,18 +3055,16 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cadence_nand_dt_remove(struct platform_device *ofdev)
|
||||
static void cadence_nand_dt_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct cadence_nand_dt *dt = platform_get_drvdata(ofdev);
|
||||
|
||||
cadence_nand_remove(&dt->cdns_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cadence_nand_dt_driver = {
|
||||
.probe = cadence_nand_dt_probe,
|
||||
.remove = cadence_nand_dt_remove,
|
||||
.remove_new = cadence_nand_dt_remove,
|
||||
.driver = {
|
||||
.name = "cadence-nand-controller",
|
||||
.of_match_table = cadence_nand_dt_ids,
|
||||
|
@ -821,7 +821,7 @@ err_cleanup_nand:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nand_davinci_remove(struct platform_device *pdev)
|
||||
static void nand_davinci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_nand_info *info = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &info->chip;
|
||||
@ -835,13 +835,11 @@ static int nand_davinci_remove(struct platform_device *pdev)
|
||||
ret = mtd_device_unregister(nand_to_mtd(chip));
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nand_davinci_driver = {
|
||||
.probe = nand_davinci_probe,
|
||||
.remove = nand_davinci_remove,
|
||||
.remove_new = nand_davinci_remove,
|
||||
.driver = {
|
||||
.name = "davinci_nand",
|
||||
.of_match_table = of_match_ptr(davinci_nand_of_match),
|
||||
|
@ -233,7 +233,7 @@ out_disable_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int denali_dt_remove(struct platform_device *pdev)
|
||||
static void denali_dt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct denali_dt *dt = platform_get_drvdata(pdev);
|
||||
|
||||
@ -243,13 +243,11 @@ static int denali_dt_remove(struct platform_device *pdev)
|
||||
clk_disable_unprepare(dt->clk_ecc);
|
||||
clk_disable_unprepare(dt->clk_x);
|
||||
clk_disable_unprepare(dt->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver denali_dt_driver = {
|
||||
.probe = denali_dt_probe,
|
||||
.remove = denali_dt_remove,
|
||||
.remove_new = denali_dt_remove,
|
||||
.driver = {
|
||||
.name = "denali-nand-dt",
|
||||
.of_match_table = denali_nand_dt_ids,
|
||||
|
@ -963,7 +963,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsl_elbc_nand_remove(struct platform_device *pdev)
|
||||
static void fsl_elbc_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
|
||||
struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
|
||||
@ -984,8 +984,6 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
|
||||
}
|
||||
mutex_unlock(&fsl_elbc_nand_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static const struct of_device_id fsl_elbc_nand_match[] = {
|
||||
@ -1000,7 +998,7 @@ static struct platform_driver fsl_elbc_nand_driver = {
|
||||
.of_match_table = fsl_elbc_nand_match,
|
||||
},
|
||||
.probe = fsl_elbc_nand_probe,
|
||||
.remove = fsl_elbc_nand_remove,
|
||||
.remove_new = fsl_elbc_nand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fsl_elbc_nand_driver);
|
||||
|
@ -1094,7 +1094,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsl_ifc_nand_remove(struct platform_device *dev)
|
||||
static void fsl_ifc_nand_remove(struct platform_device *dev)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
|
||||
struct nand_chip *chip = &priv->chip;
|
||||
@ -1113,8 +1113,6 @@ static int fsl_ifc_nand_remove(struct platform_device *dev)
|
||||
kfree(ifc_nand_ctrl);
|
||||
}
|
||||
mutex_unlock(&fsl_ifc_nand_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fsl_ifc_nand_match[] = {
|
||||
@ -1131,7 +1129,7 @@ static struct platform_driver fsl_ifc_nand_driver = {
|
||||
.of_match_table = fsl_ifc_nand_match,
|
||||
},
|
||||
.probe = fsl_ifc_nand_probe,
|
||||
.remove = fsl_ifc_nand_remove,
|
||||
.remove_new = fsl_ifc_nand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fsl_ifc_nand_driver);
|
||||
|
@ -235,7 +235,7 @@ static int fun_probe(struct platform_device *ofdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fun_remove(struct platform_device *ofdev)
|
||||
static void fun_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
|
||||
struct nand_chip *chip = &fun->chip;
|
||||
@ -245,8 +245,6 @@ static int fun_remove(struct platform_device *ofdev)
|
||||
ret = mtd_device_unregister(mtd);
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_fun_match[] = {
|
||||
@ -261,7 +259,7 @@ static struct platform_driver of_fun_driver = {
|
||||
.of_match_table = of_fun_match,
|
||||
},
|
||||
.probe = fun_probe,
|
||||
.remove = fun_remove,
|
||||
.remove_new = fun_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(of_fun_driver);
|
||||
|
@ -880,7 +880,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (of_get_property(np, "nand-skip-bbtscan", NULL))
|
||||
if (of_property_read_bool(np, "nand-skip-bbtscan"))
|
||||
nand->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
host->dev_timings = devm_kzalloc(&pdev->dev,
|
||||
@ -1165,7 +1165,7 @@ disable_clk:
|
||||
/*
|
||||
* Clean up routine
|
||||
*/
|
||||
static int fsmc_nand_remove(struct platform_device *pdev)
|
||||
static void fsmc_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fsmc_nand_data *host = platform_get_drvdata(pdev);
|
||||
|
||||
@ -1184,8 +1184,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
|
||||
}
|
||||
clk_disable_unprepare(host->clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -1224,7 +1222,7 @@ static const struct of_device_id fsmc_nand_id_table[] = {
|
||||
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
|
||||
|
||||
static struct platform_driver fsmc_nand_driver = {
|
||||
.remove = fsmc_nand_remove,
|
||||
.remove_new = fsmc_nand_remove,
|
||||
.driver = {
|
||||
.name = "fsmc-nand",
|
||||
.of_match_table = fsmc_nand_id_table,
|
||||
|
@ -265,7 +265,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
|
||||
return platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
}
|
||||
|
||||
static int gpio_nand_remove(struct platform_device *pdev)
|
||||
static void gpio_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &gpiomtd->nand_chip;
|
||||
@ -280,8 +280,6 @@ static int gpio_nand_remove(struct platform_device *pdev)
|
||||
gpiod_set_value(gpiomtd->nwp, 0);
|
||||
if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
|
||||
gpiod_set_value(gpiomtd->nce, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_nand_probe(struct platform_device *pdev)
|
||||
@ -394,7 +392,7 @@ out_ce:
|
||||
|
||||
static struct platform_driver gpio_nand_driver = {
|
||||
.probe = gpio_nand_probe,
|
||||
.remove = gpio_nand_remove,
|
||||
.remove_new = gpio_nand_remove,
|
||||
.driver = {
|
||||
.name = "gpio-nand",
|
||||
.of_match_table = of_match_ptr(gpio_nand_id_table),
|
||||
|
@ -2777,7 +2777,7 @@ exit_acquire_resources:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpmi_nand_remove(struct platform_device *pdev)
|
||||
static void gpmi_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &this->nand;
|
||||
@ -2791,7 +2791,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
|
||||
nand_cleanup(chip);
|
||||
gpmi_free_dma_buffer(this);
|
||||
release_resources(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -2860,7 +2859,7 @@ static struct platform_driver gpmi_nand_driver = {
|
||||
.of_match_table = gpmi_nand_id_table,
|
||||
},
|
||||
.probe = gpmi_nand_probe,
|
||||
.remove = gpmi_nand_remove,
|
||||
.remove_new = gpmi_nand_remove,
|
||||
};
|
||||
module_platform_driver(gpmi_nand_driver);
|
||||
|
||||
|
@ -798,7 +798,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_nfc_remove(struct platform_device *pdev)
|
||||
static void hisi_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hinfc_host *host = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &host->chip;
|
||||
@ -807,8 +807,6 @@ static int hisi_nfc_remove(struct platform_device *pdev)
|
||||
ret = mtd_device_unregister(nand_to_mtd(chip));
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -860,7 +858,7 @@ static struct platform_driver hisi_nfc_driver = {
|
||||
.pm = &hisi_nfc_pm_ops,
|
||||
},
|
||||
.probe = hisi_nfc_probe,
|
||||
.remove = hisi_nfc_remove,
|
||||
.remove_new = hisi_nfc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_nfc_driver);
|
||||
|
@ -522,7 +522,7 @@ static int ingenic_nand_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ingenic_nand_remove(struct platform_device *pdev)
|
||||
static void ingenic_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ingenic_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -530,8 +530,6 @@ static int ingenic_nand_remove(struct platform_device *pdev)
|
||||
ingenic_ecc_release(nfc->ecc);
|
||||
|
||||
ingenic_nand_cleanup_chips(nfc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct jz_soc_info jz4740_soc_info = {
|
||||
@ -564,7 +562,7 @@ MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match);
|
||||
|
||||
static struct platform_driver ingenic_nand_driver = {
|
||||
.probe = ingenic_nand_probe,
|
||||
.remove = ingenic_nand_remove,
|
||||
.remove_new = ingenic_nand_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = ingenic_nand_dt_match,
|
||||
|
@ -706,7 +706,7 @@ err_of_node_put:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ebu_nand_remove(struct platform_device *pdev)
|
||||
static void ebu_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ebu_nand_controller *ebu_host = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
@ -717,8 +717,6 @@ static int ebu_nand_remove(struct platform_device *pdev)
|
||||
ebu_nand_disable(&ebu_host->chip);
|
||||
ebu_dma_cleanup(ebu_host);
|
||||
clk_disable_unprepare(ebu_host->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ebu_nand_match[] = {
|
||||
@ -729,7 +727,7 @@ MODULE_DEVICE_TABLE(of, ebu_nand_match);
|
||||
|
||||
static struct platform_driver ebu_nand_driver = {
|
||||
.probe = ebu_nand_probe,
|
||||
.remove = ebu_nand_remove,
|
||||
.remove_new = ebu_nand_remove,
|
||||
.driver = {
|
||||
.name = "intel-nand-controller",
|
||||
.of_match_table = ebu_nand_match,
|
||||
|
@ -827,7 +827,7 @@ free_gpio:
|
||||
/*
|
||||
* Remove NAND device
|
||||
*/
|
||||
static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
static void lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &host->nand_chip;
|
||||
@ -846,8 +846,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
|
||||
lpc32xx_wp_enable(host);
|
||||
gpiod_put(host->wp_gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_nand_resume(struct platform_device *pdev)
|
||||
@ -889,7 +887,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
|
||||
|
||||
static struct platform_driver lpc32xx_nand_driver = {
|
||||
.probe = lpc32xx_nand_probe,
|
||||
.remove = lpc32xx_nand_remove,
|
||||
.remove_new = lpc32xx_nand_remove,
|
||||
.resume = pm_ptr(lpc32xx_nand_resume),
|
||||
.suspend = pm_ptr(lpc32xx_nand_suspend),
|
||||
.driver = {
|
||||
|
@ -946,7 +946,7 @@ enable_wp:
|
||||
/*
|
||||
* Remove NAND device.
|
||||
*/
|
||||
static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
static void lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
uint32_t tmp;
|
||||
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
|
||||
@ -965,8 +965,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
lpc32xx_wp_enable(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_nand_resume(struct platform_device *pdev)
|
||||
@ -1015,7 +1013,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
|
||||
|
||||
static struct platform_driver lpc32xx_nand_driver = {
|
||||
.probe = lpc32xx_nand_probe,
|
||||
.remove = lpc32xx_nand_remove,
|
||||
.remove_new = lpc32xx_nand_remove,
|
||||
.resume = pm_ptr(lpc32xx_nand_resume),
|
||||
.suspend = pm_ptr(lpc32xx_nand_suspend),
|
||||
.driver = {
|
||||
|
@ -3004,7 +3004,7 @@ unprepare_core_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int marvell_nfc_remove(struct platform_device *pdev)
|
||||
static void marvell_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct marvell_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -3017,8 +3017,6 @@ static int marvell_nfc_remove(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(nfc->reg_clk);
|
||||
clk_disable_unprepare(nfc->core_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused marvell_nfc_suspend(struct device *dev)
|
||||
@ -3154,7 +3152,7 @@ static struct platform_driver marvell_nfc_driver = {
|
||||
},
|
||||
.id_table = marvell_nfc_platform_ids,
|
||||
.probe = marvell_nfc_probe,
|
||||
.remove = marvell_nfc_remove,
|
||||
.remove_new = marvell_nfc_remove,
|
||||
};
|
||||
module_platform_driver(marvell_nfc_driver);
|
||||
|
||||
|
@ -1440,20 +1440,18 @@ err_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int meson_nfc_remove(struct platform_device *pdev)
|
||||
static void meson_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
meson_nfc_nand_chip_cleanup(nfc);
|
||||
|
||||
meson_nfc_disable_clk(nfc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver meson_nfc_driver = {
|
||||
.probe = meson_nfc_probe,
|
||||
.remove = meson_nfc_remove,
|
||||
.remove_new = meson_nfc_remove,
|
||||
.driver = {
|
||||
.name = "meson-nand",
|
||||
.of_match_table = meson_nfc_id_table,
|
||||
|
@ -822,7 +822,7 @@ error:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int mpc5121_nfc_remove(struct platform_device *op)
|
||||
static void mpc5121_nfc_remove(struct platform_device *op)
|
||||
{
|
||||
struct device *dev = &op->dev;
|
||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
@ -832,8 +832,6 @@ static int mpc5121_nfc_remove(struct platform_device *op)
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(mtd_to_nand(mtd));
|
||||
mpc5121_nfc_free(dev, mtd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mpc5121_nfc_match[] = {
|
||||
@ -844,7 +842,7 @@ MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
|
||||
|
||||
static struct platform_driver mpc5121_nfc_driver = {
|
||||
.probe = mpc5121_nfc_probe,
|
||||
.remove = mpc5121_nfc_remove,
|
||||
.remove_new = mpc5121_nfc_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = mpc5121_nfc_match,
|
||||
|
@ -1601,7 +1601,7 @@ release_ecc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_nfc_remove(struct platform_device *pdev)
|
||||
static void mtk_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_nfc *nfc = platform_get_drvdata(pdev);
|
||||
struct mtk_nfc_nand_chip *mtk_chip;
|
||||
@ -1620,8 +1620,6 @@ static int mtk_nfc_remove(struct platform_device *pdev)
|
||||
|
||||
mtk_ecc_release(nfc->ecc);
|
||||
mtk_nfc_disable_clk(&nfc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -1663,7 +1661,7 @@ static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
|
||||
|
||||
static struct platform_driver mtk_nfc_driver = {
|
||||
.probe = mtk_nfc_probe,
|
||||
.remove = mtk_nfc_remove,
|
||||
.remove_new = mtk_nfc_remove,
|
||||
.driver = {
|
||||
.name = MTK_NAME,
|
||||
.of_match_table = mtk_nfc_id_table,
|
||||
|
@ -1599,16 +1599,6 @@ static inline int is_imx25_nfc(struct mxc_nand_host *host)
|
||||
return host->devtype_data == &imx25_nand_devtype_data;
|
||||
}
|
||||
|
||||
static inline int is_imx51_nfc(struct mxc_nand_host *host)
|
||||
{
|
||||
return host->devtype_data == &imx51_nand_devtype_data;
|
||||
}
|
||||
|
||||
static inline int is_imx53_nfc(struct mxc_nand_host *host)
|
||||
{
|
||||
return host->devtype_data == &imx53_nand_devtype_data;
|
||||
}
|
||||
|
||||
static const struct of_device_id mxcnd_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, },
|
||||
{ .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, },
|
||||
@ -1831,7 +1821,7 @@ escan:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mxcnd_remove(struct platform_device *pdev)
|
||||
static void mxcnd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mxc_nand_host *host = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &host->nand;
|
||||
@ -1842,8 +1832,6 @@ static int mxcnd_remove(struct platform_device *pdev)
|
||||
nand_cleanup(chip);
|
||||
if (host->clk_act)
|
||||
clk_disable_unprepare(host->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mxcnd_driver = {
|
||||
@ -1852,7 +1840,7 @@ static struct platform_driver mxcnd_driver = {
|
||||
.of_match_table = mxcnd_dt_ids,
|
||||
},
|
||||
.probe = mxcnd_probe,
|
||||
.remove = mxcnd_remove,
|
||||
.remove_new = mxcnd_remove,
|
||||
};
|
||||
module_platform_driver(mxcnd_driver);
|
||||
|
||||
|
@ -553,7 +553,7 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mxic_nfc_remove(struct platform_device *pdev)
|
||||
static void mxic_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &nfc->chip;
|
||||
@ -564,7 +564,6 @@ static int mxic_nfc_remove(struct platform_device *pdev)
|
||||
nand_cleanup(chip);
|
||||
|
||||
mxic_nfc_clk_disable(nfc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mxic_nfc_of_ids[] = {
|
||||
@ -575,7 +574,7 @@ MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
|
||||
|
||||
static struct platform_driver mxic_nfc_driver = {
|
||||
.probe = mxic_nfc_probe,
|
||||
.remove = mxic_nfc_remove,
|
||||
.remove_new = mxic_nfc_remove,
|
||||
.driver = {
|
||||
.name = "mxic-nfc",
|
||||
.of_match_table = mxic_nfc_of_ids,
|
||||
|
@ -728,8 +728,21 @@ static int hynix_nand_init(struct nand_chip *chip)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hynix_fixup_onfi_param_page(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p)
|
||||
{
|
||||
/*
|
||||
* Certain chips might report a 0 on sdr_timing_mode field
|
||||
* (bytes 129-130). This has been seen on H27U4G8F2GDA-BI.
|
||||
* According to ONFI specification, bit 0 of this field "shall be 1".
|
||||
* Forcibly set this bit.
|
||||
*/
|
||||
p->sdr_timing_modes |= cpu_to_le16(BIT(0));
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
|
||||
.detect = hynix_nand_decode_id,
|
||||
.init = hynix_nand_init,
|
||||
.cleanup = hynix_nand_cleanup,
|
||||
.fixup_onfi_param_page = hynix_fixup_onfi_param_page,
|
||||
};
|
||||
|
@ -93,14 +93,13 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
|
||||
struct nand_parameters *p = &chip->parameters;
|
||||
struct nand_onfi_vendor_macronix *mxic;
|
||||
struct device_node *dn = nand_get_flash_node(chip);
|
||||
int rand_otp = 0;
|
||||
int rand_otp;
|
||||
int ret;
|
||||
|
||||
if (!p->onfi)
|
||||
return;
|
||||
|
||||
if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL))
|
||||
rand_otp = 1;
|
||||
rand_otp = of_property_read_bool(dn, "mxic,enable-randomizer-otp");
|
||||
|
||||
mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
|
||||
/* Subpage write is prohibited in randomizer operatoin */
|
||||
|
@ -240,7 +240,7 @@ static int ndfc_probe(struct platform_device *ofdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndfc_remove(struct platform_device *ofdev)
|
||||
static void ndfc_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
|
||||
struct nand_chip *chip = &ndfc->chip;
|
||||
@ -251,8 +251,6 @@ static int ndfc_remove(struct platform_device *ofdev)
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
kfree(mtd->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ndfc_match[] = {
|
||||
@ -267,7 +265,7 @@ static struct platform_driver ndfc_driver = {
|
||||
.of_match_table = ndfc_match,
|
||||
},
|
||||
.probe = ndfc_probe,
|
||||
.remove = ndfc_remove,
|
||||
.remove_new = ndfc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ndfc_driver);
|
||||
|
@ -2273,7 +2273,7 @@ return_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int omap_nand_remove(struct platform_device *pdev)
|
||||
static void omap_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtd_info *mtd = platform_get_drvdata(pdev);
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
@ -2285,7 +2285,6 @@ static int omap_nand_remove(struct platform_device *pdev)
|
||||
dma_release_channel(info->dma);
|
||||
WARN_ON(mtd_device_unregister(mtd));
|
||||
nand_cleanup(nand_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* omap_nand_ids defined in linux/platform_data/mtd-nand-omap2.h */
|
||||
@ -2293,7 +2292,7 @@ MODULE_DEVICE_TABLE(of, omap_nand_ids);
|
||||
|
||||
static struct platform_driver omap_nand_driver = {
|
||||
.probe = omap_nand_probe,
|
||||
.remove = omap_nand_remove,
|
||||
.remove_new = omap_nand_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = omap_nand_ids,
|
||||
|
@ -422,11 +422,10 @@ static int elm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int elm_remove(struct platform_device *pdev)
|
||||
static void elm_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -561,7 +560,7 @@ static struct platform_driver elm_driver = {
|
||||
.pm = &elm_pm_ops,
|
||||
},
|
||||
.probe = elm_probe,
|
||||
.remove = elm_remove,
|
||||
.remove_new = elm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(elm_driver);
|
||||
|
@ -102,7 +102,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *nc;
|
||||
struct orion_nand_data *board;
|
||||
struct resource *res;
|
||||
void __iomem *io_base;
|
||||
int ret = 0;
|
||||
u32 val = 0;
|
||||
@ -119,8 +118,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
||||
info->controller.ops = &orion_nand_ops;
|
||||
nc->controller = &info->controller;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
io_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
io_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
||||
if (IS_ERR(io_base))
|
||||
return PTR_ERR(io_base);
|
||||
@ -207,7 +205,7 @@ no_dev:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int orion_nand_remove(struct platform_device *pdev)
|
||||
static void orion_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct orion_nand_info *info = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &info->chip;
|
||||
@ -219,8 +217,6 @@ static int orion_nand_remove(struct platform_device *pdev)
|
||||
nand_cleanup(chip);
|
||||
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -232,7 +228,7 @@ MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
|
||||
#endif
|
||||
|
||||
static struct platform_driver orion_nand_driver = {
|
||||
.remove = orion_nand_remove,
|
||||
.remove_new = orion_nand_remove,
|
||||
.driver = {
|
||||
.name = "orion_nand",
|
||||
.of_match_table = of_match_ptr(orion_nand_of_match_table),
|
||||
|
@ -171,7 +171,7 @@ err_clk_unprepare:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int oxnas_nand_remove(struct platform_device *pdev)
|
||||
static void oxnas_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip;
|
||||
@ -184,8 +184,6 @@ static int oxnas_nand_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
clk_disable_unprepare(oxnas->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id oxnas_nand_match[] = {
|
||||
@ -196,7 +194,7 @@ MODULE_DEVICE_TABLE(of, oxnas_nand_match);
|
||||
|
||||
static struct platform_driver oxnas_nand_driver = {
|
||||
.probe = oxnas_nand_probe,
|
||||
.remove = oxnas_nand_remove,
|
||||
.remove_new = oxnas_nand_remove,
|
||||
.driver = {
|
||||
.name = "oxnas_nand",
|
||||
.of_match_table = oxnas_nand_match,
|
||||
|
@ -197,7 +197,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pasemi_nand_remove(struct platform_device *ofdev)
|
||||
static void pasemi_nand_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct pasemi_ddata *ddata = platform_get_drvdata(ofdev);
|
||||
struct mtd_info *pasemi_nand_mtd;
|
||||
@ -218,8 +218,6 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
|
||||
|
||||
/* Free the MTD device structure */
|
||||
kfree(ddata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pasemi_nand_match[] =
|
||||
@ -239,7 +237,7 @@ static struct platform_driver pasemi_nand_driver =
|
||||
.of_match_table = pasemi_nand_match,
|
||||
},
|
||||
.probe = pasemi_nand_probe,
|
||||
.remove = pasemi_nand_remove,
|
||||
.remove_new = pasemi_nand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pasemi_nand_driver);
|
||||
|
@ -1163,13 +1163,11 @@ static int pl35x_nand_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl35x_nand_remove(struct platform_device *pdev)
|
||||
static void pl35x_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pl35x_nandc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
pl35x_nand_chips_cleanup(nfc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pl35x_nand_of_match[] = {
|
||||
@ -1180,7 +1178,7 @@ MODULE_DEVICE_TABLE(of, pl35x_nand_of_match);
|
||||
|
||||
static struct platform_driver pl35x_nandc_driver = {
|
||||
.probe = pl35x_nand_probe,
|
||||
.remove = pl35x_nand_remove,
|
||||
.remove_new = pl35x_nand_remove,
|
||||
.driver = {
|
||||
.name = PL35X_NANDC_DRIVER_NAME,
|
||||
.of_match_table = pl35x_nand_of_match,
|
||||
|
@ -122,7 +122,7 @@ out:
|
||||
/*
|
||||
* Remove a NAND device.
|
||||
*/
|
||||
static int plat_nand_remove(struct platform_device *pdev)
|
||||
static void plat_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_nand_data *data = platform_get_drvdata(pdev);
|
||||
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
@ -134,8 +134,6 @@ static int plat_nand_remove(struct platform_device *pdev)
|
||||
nand_cleanup(chip);
|
||||
if (pdata->ctrl.remove)
|
||||
pdata->ctrl.remove(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id plat_nand_match[] = {
|
||||
@ -146,7 +144,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match);
|
||||
|
||||
static struct platform_driver plat_nand_driver = {
|
||||
.probe = plat_nand_probe,
|
||||
.remove = plat_nand_remove,
|
||||
.remove_new = plat_nand_remove,
|
||||
.driver = {
|
||||
.name = "gen_nand",
|
||||
.of_match_table = plat_nand_match,
|
||||
|
@ -3054,7 +3054,7 @@ static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nan
|
||||
struct device *dev = nandc->dev;
|
||||
int partitions_count, i, j, ret;
|
||||
|
||||
if (!of_find_property(dn, "qcom,boot-partitions", NULL))
|
||||
if (!of_property_present(dn, "qcom,boot-partitions"))
|
||||
return 0;
|
||||
|
||||
partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions");
|
||||
@ -3269,8 +3269,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nandc->base = devm_ioremap_resource(dev, res);
|
||||
nandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(nandc->base))
|
||||
return PTR_ERR(nandc->base);
|
||||
|
||||
@ -3315,7 +3314,7 @@ err_core_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_nandc_remove(struct platform_device *pdev)
|
||||
static void qcom_nandc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -3337,8 +3336,6 @@ static int qcom_nandc_remove(struct platform_device *pdev)
|
||||
|
||||
dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res),
|
||||
DMA_BIDIRECTIONAL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct qcom_nandc_props ipq806x_nandc_props = {
|
||||
@ -3405,7 +3402,7 @@ static struct platform_driver qcom_nandc_driver = {
|
||||
.of_match_table = qcom_nandc_of_match,
|
||||
},
|
||||
.probe = qcom_nandc_probe,
|
||||
.remove = qcom_nandc_remove,
|
||||
.remove_new = qcom_nandc_remove,
|
||||
};
|
||||
module_platform_driver(qcom_nandc_driver);
|
||||
|
||||
|
@ -1386,15 +1386,13 @@ dis_runtime_pm:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rnandc_remove(struct platform_device *pdev)
|
||||
static void rnandc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rnandc *rnandc = platform_get_drvdata(pdev);
|
||||
|
||||
rnandc_chips_cleanup(rnandc);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rnandc_id_table[] = {
|
||||
@ -1410,7 +1408,7 @@ static struct platform_driver rnandc_driver = {
|
||||
.of_match_table = rnandc_id_table,
|
||||
},
|
||||
.probe = rnandc_probe,
|
||||
.remove = rnandc_remove,
|
||||
.remove_new = rnandc_remove,
|
||||
};
|
||||
module_platform_driver(rnandc_driver);
|
||||
|
||||
|
@ -1427,7 +1427,7 @@ release_nfc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_nfc_remove(struct platform_device *pdev)
|
||||
static void rk_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -1435,8 +1435,6 @@ static int rk_nfc_remove(struct platform_device *pdev)
|
||||
kfree(nfc->oob_buf);
|
||||
rk_nfc_chips_cleanup(nfc);
|
||||
rk_nfc_disable_clks(nfc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rk_nfc_suspend(struct device *dev)
|
||||
@ -1476,7 +1474,7 @@ static const struct dev_pm_ops rk_nfc_pm_ops = {
|
||||
|
||||
static struct platform_driver rk_nfc_driver = {
|
||||
.probe = rk_nfc_probe,
|
||||
.remove = rk_nfc_remove,
|
||||
.remove_new = rk_nfc_remove,
|
||||
.driver = {
|
||||
.name = "rockchip-nfc",
|
||||
.of_match_table = rk_nfc_id_table,
|
||||
|
@ -709,12 +709,12 @@ static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
|
||||
|
||||
/* device management functions */
|
||||
|
||||
static int s3c24xx_nand_remove(struct platform_device *pdev)
|
||||
static void s3c24xx_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c2410_nand_info *info = to_nand_info(pdev);
|
||||
|
||||
if (info == NULL)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* Release all our mtds and their partitions, then go through
|
||||
* freeing the resources used
|
||||
@ -735,8 +735,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
|
||||
|
||||
if (!IS_ERR(info->clk))
|
||||
s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
|
||||
@ -1218,7 +1216,7 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
|
||||
|
||||
static struct platform_driver s3c24xx_nand_driver = {
|
||||
.probe = s3c24xx_nand_probe,
|
||||
.remove = s3c24xx_nand_remove,
|
||||
.remove_new = s3c24xx_nand_remove,
|
||||
.suspend = s3c24xx_nand_suspend,
|
||||
.resume = s3c24xx_nand_resume,
|
||||
.id_table = s3c24xx_driver_ids,
|
||||
|
@ -1203,7 +1203,7 @@ err_chip:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flctl_remove(struct platform_device *pdev)
|
||||
static void flctl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_flctl *flctl = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &flctl->chip;
|
||||
@ -1214,12 +1214,10 @@ static int flctl_remove(struct platform_device *pdev)
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver flctl_driver = {
|
||||
.remove = flctl_remove,
|
||||
.remove_new = flctl_remove,
|
||||
.driver = {
|
||||
.name = "sh_flctl",
|
||||
.of_match_table = of_flctl_match,
|
||||
|
@ -210,7 +210,7 @@ err_get_res:
|
||||
/*
|
||||
* Clean up routine
|
||||
*/
|
||||
static int sharpsl_nand_remove(struct platform_device *pdev)
|
||||
static void sharpsl_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &sharpsl->chip;
|
||||
@ -227,8 +227,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
|
||||
|
||||
/* Free the driver's structure */
|
||||
kfree(sharpsl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sharpsl_nand_driver = {
|
||||
@ -236,7 +234,7 @@ static struct platform_driver sharpsl_nand_driver = {
|
||||
.name = "sharpsl-nand",
|
||||
},
|
||||
.probe = sharpsl_nand_probe,
|
||||
.remove = sharpsl_nand_remove,
|
||||
.remove_new = sharpsl_nand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sharpsl_nand_driver);
|
||||
|
@ -201,7 +201,7 @@ out:
|
||||
/*
|
||||
* Remove a NAND device.
|
||||
*/
|
||||
static int socrates_nand_remove(struct platform_device *ofdev)
|
||||
static void socrates_nand_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
|
||||
struct nand_chip *chip = &host->nand_chip;
|
||||
@ -212,8 +212,6 @@ static int socrates_nand_remove(struct platform_device *ofdev)
|
||||
nand_cleanup(chip);
|
||||
|
||||
iounmap(host->io_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id socrates_nand_match[] =
|
||||
@ -232,7 +230,7 @@ static struct platform_driver socrates_nand_driver = {
|
||||
.of_match_table = socrates_nand_match,
|
||||
},
|
||||
.probe = socrates_nand_probe,
|
||||
.remove = socrates_nand_remove,
|
||||
.remove_new = socrates_nand_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(socrates_nand_driver);
|
||||
|
@ -2024,7 +2024,7 @@ err_clk_disable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_fmc2_nfc_remove(struct platform_device *pdev)
|
||||
static void stm32_fmc2_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev);
|
||||
struct stm32_fmc2_nand *nand = &nfc->nand;
|
||||
@ -2048,8 +2048,6 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev)
|
||||
clk_disable_unprepare(nfc->clk);
|
||||
|
||||
stm32_fmc2_nfc_wp_enable(nand);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev)
|
||||
@ -2106,7 +2104,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
|
||||
|
||||
static struct platform_driver stm32_fmc2_nfc_driver = {
|
||||
.probe = stm32_fmc2_nfc_probe,
|
||||
.remove = stm32_fmc2_nfc_remove,
|
||||
.remove_new = stm32_fmc2_nfc_remove,
|
||||
.driver = {
|
||||
.name = "stm32_fmc2_nfc",
|
||||
.of_match_table = stm32_fmc2_nfc_match,
|
||||
|
@ -2173,7 +2173,7 @@ out_ahb_clk_unprepare:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sunxi_nfc_remove(struct platform_device *pdev)
|
||||
static void sunxi_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
|
||||
|
||||
@ -2185,8 +2185,6 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
|
||||
dma_release_channel(nfc->dmac);
|
||||
clk_disable_unprepare(nfc->mod_clk);
|
||||
clk_disable_unprepare(nfc->ahb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
|
||||
@ -2219,7 +2217,7 @@ static struct platform_driver sunxi_nfc_driver = {
|
||||
.of_match_table = sunxi_nfc_ids,
|
||||
},
|
||||
.probe = sunxi_nfc_probe,
|
||||
.remove = sunxi_nfc_remove,
|
||||
.remove_new = sunxi_nfc_remove,
|
||||
};
|
||||
module_platform_driver(sunxi_nfc_driver);
|
||||
|
||||
|
@ -1220,7 +1220,7 @@ err_dis_pm:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_nand_remove(struct platform_device *pdev)
|
||||
static void tegra_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = ctrl->chip;
|
||||
@ -1232,8 +1232,6 @@ static int tegra_nand_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_put_sync_suspend(ctrl->dev);
|
||||
pm_runtime_force_suspend(ctrl->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_nand_runtime_resume(struct device *dev)
|
||||
@ -1277,7 +1275,7 @@ static struct platform_driver tegra_nand_driver = {
|
||||
.pm = &tegra_nand_pm,
|
||||
},
|
||||
.probe = tegra_nand_probe,
|
||||
.remove = tegra_nand_remove,
|
||||
.remove_new = tegra_nand_remove,
|
||||
};
|
||||
module_platform_driver(tegra_nand_driver);
|
||||
|
||||
|
@ -909,7 +909,7 @@ err_disable_clk:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vf610_nfc_remove(struct platform_device *pdev)
|
||||
static void vf610_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vf610_nfc *nfc = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &nfc->chip;
|
||||
@ -919,7 +919,6 @@ static int vf610_nfc_remove(struct platform_device *pdev)
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
clk_disable_unprepare(nfc->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -955,7 +954,7 @@ static struct platform_driver vf610_nfc_driver = {
|
||||
.pm = &vf610_nfc_pm_ops,
|
||||
},
|
||||
.probe = vf610_nfc_probe,
|
||||
.remove = vf610_nfc_remove,
|
||||
.remove_new = vf610_nfc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(vf610_nfc_driver);
|
||||
|
@ -238,7 +238,7 @@ static int xway_nand_probe(struct platform_device *pdev)
|
||||
/*
|
||||
* Remove a NAND device.
|
||||
*/
|
||||
static int xway_nand_remove(struct platform_device *pdev)
|
||||
static void xway_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xway_nand_data *data = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &data->chip;
|
||||
@ -247,8 +247,6 @@ static int xway_nand_remove(struct platform_device *pdev)
|
||||
ret = mtd_device_unregister(nand_to_mtd(chip));
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id xway_nand_match[] = {
|
||||
@ -258,7 +256,7 @@ static const struct of_device_id xway_nand_match[] = {
|
||||
|
||||
static struct platform_driver xway_nand_driver = {
|
||||
.probe = xway_nand_probe,
|
||||
.remove = xway_nand_remove,
|
||||
.remove_new = xway_nand_remove,
|
||||
.driver = {
|
||||
.name = "lantiq,nand-xway",
|
||||
.of_match_table = xway_nand_match,
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
spinand-objs := core.o alliancememory.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
spinand-objs := core.o alliancememory.o ato.o esmt.o gigadevice.o macronix.o
|
||||
spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
|
@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops = {
|
||||
static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
||||
&alliancememory_spinand_manufacturer,
|
||||
&ato_spinand_manufacturer,
|
||||
&esmt_c8_spinand_manufacturer,
|
||||
&gigadevice_spinand_manufacturer,
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
|
135
drivers/mtd/nand/spi/esmt.c
Normal file
135
drivers/mtd/nand/spi/esmt.c
Normal file
@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Author:
|
||||
* Chuanhong Guo <gch981213@gmail.com> - the main driver logic
|
||||
* Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
|
||||
#define SPINAND_MFR_ESMT_C8 0xc8
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
|
||||
/*
|
||||
* OOB spare area map (64 bytes)
|
||||
*
|
||||
* Bad Block Markers
|
||||
* filled by HW and kernel Reserved
|
||||
* | +-----------------------+-----------------------+
|
||||
* | | | |
|
||||
* | | OOB free data Area |non ECC protected |
|
||||
* | +-------------|-----+-----------------|-----+-----------------|-----+
|
||||
* | | | | | | | |
|
||||
* +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
|
||||
* | | | section0 | | | section1 | | | section2 | | | section3 |
|
||||
* +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
|
||||
* | | | | | | | | | | | | | | | | |
|
||||
* |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
|
||||
* | | | | | | | | | | | | | | | | |
|
||||
* +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
|
||||
* | | | | | | | |
|
||||
* | +----------------|-----+-----------------|-----+-----------------|-----+
|
||||
* | ECC Area|(Main + Spare) - filled|by ESMT NAND HW |
|
||||
* | | | |
|
||||
* +---------------------+-----------------------+-----------------------+
|
||||
* OOB ECC protected Area - not used due to
|
||||
* partial programming from some filesystems
|
||||
* (like JFFS2 with cleanmarkers)
|
||||
*/
|
||||
|
||||
#define ESMT_OOB_SECTION_COUNT 4
|
||||
#define ESMT_OOB_SECTION_SIZE(nand) \
|
||||
(nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
|
||||
#define ESMT_OOB_FREE_SIZE(nand) \
|
||||
(ESMT_OOB_SECTION_SIZE(nand) / 2)
|
||||
#define ESMT_OOB_ECC_SIZE(nand) \
|
||||
(ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
|
||||
#define ESMT_OOB_BBM_SIZE 2
|
||||
|
||||
static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
struct nand_device *nand = mtd_to_nanddev(mtd);
|
||||
|
||||
if (section >= ESMT_OOB_SECTION_COUNT)
|
||||
return -ERANGE;
|
||||
|
||||
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
|
||||
ESMT_OOB_FREE_SIZE(nand);
|
||||
region->length = ESMT_OOB_ECC_SIZE(nand);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
struct nand_device *nand = mtd_to_nanddev(mtd);
|
||||
|
||||
if (section >= ESMT_OOB_SECTION_COUNT)
|
||||
return -ERANGE;
|
||||
|
||||
/*
|
||||
* Reserve space for bad blocks markers (section0) and
|
||||
* reserved bytes (sections 1-3)
|
||||
*/
|
||||
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
|
||||
|
||||
/* Use only 2 non-protected ECC bytes per each OOB section */
|
||||
region->length = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
|
||||
.ecc = f50l1g41lb_ooblayout_ecc,
|
||||
.free = f50l1g41lb_ooblayout_free,
|
||||
};
|
||||
|
||||
static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
SPINAND_INFO("F50L1G41LB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||
SPINAND_INFO("F50D1G41LB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
|
||||
};
|
||||
|
||||
const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
|
||||
.id = SPINAND_MFR_ESMT_C8,
|
||||
.name = "ESMT",
|
||||
.chips = esmt_c8_spinand_table,
|
||||
.nchips = ARRAY_SIZE(esmt_c8_spinand_table),
|
||||
.ops = &esmt_spinand_manuf_ops,
|
||||
};
|
@ -149,7 +149,7 @@ config MTD_PARSER_TRX
|
||||
|
||||
config MTD_SHARPSL_PARTS
|
||||
tristate "Sharp SL Series NAND flash partition parser"
|
||||
depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST
|
||||
depends on MTD_NAND_SHARPSL || COMPILE_TEST
|
||||
help
|
||||
This provides the read-only FTL logic necessary to read the partition
|
||||
table from the NAND flash of Sharp SL Series (Zaurus) and the MTD
|
||||
|
@ -164,7 +164,6 @@ static struct mtd_part_parser bcm63xx_cfe_parser = {
|
||||
};
|
||||
module_mtd_part_parser(bcm63xx_cfe_parser);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
|
||||
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
||||
MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
|
||||
|
@ -305,10 +305,10 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
|
||||
}
|
||||
}
|
||||
|
||||
if (of_find_property(np, "spi-cpha", NULL))
|
||||
if (of_property_read_bool(np, "spi-cpha"))
|
||||
mode |= SPI_CPHA;
|
||||
|
||||
if (of_find_property(np, "spi-cpol", NULL))
|
||||
if (of_property_read_bool(np, "spi-cpol"))
|
||||
mode |= SPI_CPOL;
|
||||
|
||||
/* Setup control register defaults */
|
||||
|
@ -508,14 +508,16 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_set_4byte_addr_mode() - Enter/Exit 4-byte address mode.
|
||||
* spi_nor_set_4byte_addr_mode_en4b_ex4b() - Enter/Exit 4-byte address mode
|
||||
* using SPINOR_OP_EN4B/SPINOR_OP_EX4B. Typically used by
|
||||
* Winbond and Macronix.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
|
||||
* address mode.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -539,15 +541,45 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
}
|
||||
|
||||
/**
|
||||
* spansion_set_4byte_addr_mode() - Set 4-byte address mode for Spansion
|
||||
* flashes.
|
||||
* spi_nor_set_4byte_addr_mode_wren_en4b_ex4b() - Set 4-byte address mode using
|
||||
* SPINOR_OP_WREN followed by SPINOR_OP_EN4B or SPINOR_OP_EX4B. Typically used
|
||||
* by ST and Micron flashes.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
|
||||
* address mode.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int spansion_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return spi_nor_write_disable(nor);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_set_4byte_addr_mode_brwr() - Set 4-byte address mode using
|
||||
* SPINOR_OP_BRWR. Typically used by Spansion flashes.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
|
||||
* address mode.
|
||||
*
|
||||
* 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is
|
||||
* used to enable/disable 4-byte address mode. When MSB is set to ‘1’, 4-byte
|
||||
* address mode is active and A[30:24] bits are don’t care. Write instruction is
|
||||
* SPINOR_OP_BRWR(17h) with 1 byte of data.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -588,6 +620,65 @@ int spi_nor_sr_ready(struct spi_nor *nor)
|
||||
return !(nor->bouncebuf[0] & SR_WIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_use_parallel_locking() - Checks if RWW locking scheme shall be used
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*
|
||||
* Return: true if parallel locking is enabled, false otherwise.
|
||||
*/
|
||||
static bool spi_nor_use_parallel_locking(struct spi_nor *nor)
|
||||
{
|
||||
return nor->flags & SNOR_F_RWW;
|
||||
}
|
||||
|
||||
/* Locking helpers for status read operations */
|
||||
static int spi_nor_rww_start_rdst(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
int ret = -EAGAIN;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (rww->ongoing_io || rww->ongoing_rd)
|
||||
goto busy;
|
||||
|
||||
rww->ongoing_io = true;
|
||||
rww->ongoing_rd = true;
|
||||
ret = 0;
|
||||
|
||||
busy:
|
||||
mutex_unlock(&nor->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spi_nor_rww_end_rdst(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
rww->ongoing_io = false;
|
||||
rww->ongoing_rd = false;
|
||||
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
static int spi_nor_lock_rdst(struct spi_nor *nor)
|
||||
{
|
||||
if (spi_nor_use_parallel_locking(nor))
|
||||
return spi_nor_rww_start_rdst(nor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spi_nor_unlock_rdst(struct spi_nor *nor)
|
||||
{
|
||||
if (spi_nor_use_parallel_locking(nor)) {
|
||||
spi_nor_rww_end_rdst(nor);
|
||||
wake_up(&nor->rww.wait);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_ready() - Query the flash to see if it is ready for new commands.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
@ -596,11 +687,21 @@ int spi_nor_sr_ready(struct spi_nor *nor)
|
||||
*/
|
||||
static int spi_nor_ready(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_rdst(nor);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
/* Flashes might override the standard routine. */
|
||||
if (nor->params->ready)
|
||||
return nor->params->ready(nor);
|
||||
ret = nor->params->ready(nor);
|
||||
else
|
||||
ret = spi_nor_sr_ready(nor);
|
||||
|
||||
return spi_nor_sr_ready(nor);
|
||||
spi_nor_unlock_rdst(nor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1070,27 +1171,287 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
|
||||
}
|
||||
}
|
||||
|
||||
int spi_nor_lock_and_prep(struct spi_nor *nor)
|
||||
static int spi_nor_prep(struct spi_nor *nor)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (nor->controller_ops && nor->controller_ops->prepare)
|
||||
ret = nor->controller_ops->prepare(nor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spi_nor_unprep(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->controller_ops && nor->controller_ops->unprepare)
|
||||
nor->controller_ops->unprepare(nor);
|
||||
}
|
||||
|
||||
static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len,
|
||||
u8 *first, u8 *last)
|
||||
{
|
||||
/* This is currently safe, the number of banks being very small */
|
||||
*first = DIV_ROUND_DOWN_ULL(start, bank_size);
|
||||
*last = DIV_ROUND_DOWN_ULL(start + len - 1, bank_size);
|
||||
}
|
||||
|
||||
/* Generic helpers for internal locking and serialization */
|
||||
static bool spi_nor_rww_start_io(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
bool start = false;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (nor->controller_ops && nor->controller_ops->prepare) {
|
||||
ret = nor->controller_ops->prepare(nor);
|
||||
if (ret) {
|
||||
mutex_unlock(&nor->lock);
|
||||
return ret;
|
||||
}
|
||||
if (rww->ongoing_io)
|
||||
goto busy;
|
||||
|
||||
rww->ongoing_io = true;
|
||||
start = true;
|
||||
|
||||
busy:
|
||||
mutex_unlock(&nor->lock);
|
||||
return start;
|
||||
}
|
||||
|
||||
static void spi_nor_rww_end_io(struct spi_nor *nor)
|
||||
{
|
||||
mutex_lock(&nor->lock);
|
||||
nor->rww.ongoing_io = false;
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
static int spi_nor_lock_device(struct spi_nor *nor)
|
||||
{
|
||||
if (!spi_nor_use_parallel_locking(nor))
|
||||
return 0;
|
||||
|
||||
return wait_event_killable(nor->rww.wait, spi_nor_rww_start_io(nor));
|
||||
}
|
||||
|
||||
static void spi_nor_unlock_device(struct spi_nor *nor)
|
||||
{
|
||||
if (spi_nor_use_parallel_locking(nor)) {
|
||||
spi_nor_rww_end_io(nor);
|
||||
wake_up(&nor->rww.wait);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic helpers for internal locking and serialization */
|
||||
static bool spi_nor_rww_start_exclusive(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
bool start = false;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
|
||||
goto busy;
|
||||
|
||||
rww->ongoing_io = true;
|
||||
rww->ongoing_rd = true;
|
||||
rww->ongoing_pe = true;
|
||||
start = true;
|
||||
|
||||
busy:
|
||||
mutex_unlock(&nor->lock);
|
||||
return start;
|
||||
}
|
||||
|
||||
static void spi_nor_rww_end_exclusive(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
rww->ongoing_io = false;
|
||||
rww->ongoing_rd = false;
|
||||
rww->ongoing_pe = false;
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
int spi_nor_prep_and_lock(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!spi_nor_use_parallel_locking(nor))
|
||||
mutex_lock(&nor->lock);
|
||||
else
|
||||
ret = wait_event_killable(nor->rww.wait,
|
||||
spi_nor_rww_start_exclusive(nor));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spi_nor_unlock_and_unprep(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->controller_ops && nor->controller_ops->unprepare)
|
||||
nor->controller_ops->unprepare(nor);
|
||||
if (!spi_nor_use_parallel_locking(nor)) {
|
||||
mutex_unlock(&nor->lock);
|
||||
} else {
|
||||
spi_nor_rww_end_exclusive(nor);
|
||||
wake_up(&nor->rww.wait);
|
||||
}
|
||||
|
||||
spi_nor_unprep(nor);
|
||||
}
|
||||
|
||||
/* Internal locking helpers for program and erase operations */
|
||||
static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
unsigned int used_banks = 0;
|
||||
bool started = false;
|
||||
u8 first, last;
|
||||
int bank;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
|
||||
goto busy;
|
||||
|
||||
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
|
||||
for (bank = first; bank <= last; bank++) {
|
||||
if (rww->used_banks & BIT(bank))
|
||||
goto busy;
|
||||
|
||||
used_banks |= BIT(bank);
|
||||
}
|
||||
|
||||
rww->used_banks |= used_banks;
|
||||
rww->ongoing_pe = true;
|
||||
started = true;
|
||||
|
||||
busy:
|
||||
mutex_unlock(&nor->lock);
|
||||
return started;
|
||||
}
|
||||
|
||||
static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
u8 first, last;
|
||||
int bank;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
|
||||
for (bank = first; bank <= last; bank++)
|
||||
rww->used_banks &= ~BIT(bank);
|
||||
|
||||
rww->ongoing_pe = false;
|
||||
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!spi_nor_use_parallel_locking(nor))
|
||||
mutex_lock(&nor->lock);
|
||||
else
|
||||
ret = wait_event_killable(nor->rww.wait,
|
||||
spi_nor_rww_start_pe(nor, start, len));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spi_nor_unlock_and_unprep_pe(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
if (!spi_nor_use_parallel_locking(nor)) {
|
||||
mutex_unlock(&nor->lock);
|
||||
} else {
|
||||
spi_nor_rww_end_pe(nor, start, len);
|
||||
wake_up(&nor->rww.wait);
|
||||
}
|
||||
|
||||
spi_nor_unprep(nor);
|
||||
}
|
||||
|
||||
/* Internal locking helpers for read operations */
|
||||
static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
unsigned int used_banks = 0;
|
||||
bool started = false;
|
||||
u8 first, last;
|
||||
int bank;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
if (rww->ongoing_io || rww->ongoing_rd)
|
||||
goto busy;
|
||||
|
||||
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
|
||||
for (bank = first; bank <= last; bank++) {
|
||||
if (rww->used_banks & BIT(bank))
|
||||
goto busy;
|
||||
|
||||
used_banks |= BIT(bank);
|
||||
}
|
||||
|
||||
rww->used_banks |= used_banks;
|
||||
rww->ongoing_io = true;
|
||||
rww->ongoing_rd = true;
|
||||
started = true;
|
||||
|
||||
busy:
|
||||
mutex_unlock(&nor->lock);
|
||||
return started;
|
||||
}
|
||||
|
||||
static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
struct spi_nor_rww *rww = &nor->rww;
|
||||
u8 first, last;
|
||||
int bank;
|
||||
|
||||
mutex_lock(&nor->lock);
|
||||
|
||||
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
|
||||
for (bank = first; bank <= last; bank++)
|
||||
nor->rww.used_banks &= ~BIT(bank);
|
||||
|
||||
rww->ongoing_io = false;
|
||||
rww->ongoing_rd = false;
|
||||
|
||||
mutex_unlock(&nor->lock);
|
||||
}
|
||||
|
||||
static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_prep(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!spi_nor_use_parallel_locking(nor))
|
||||
mutex_lock(&nor->lock);
|
||||
else
|
||||
ret = wait_event_killable(nor->rww.wait,
|
||||
spi_nor_rww_start_rd(nor, start, len));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size_t len)
|
||||
{
|
||||
if (!spi_nor_use_parallel_locking(nor)) {
|
||||
mutex_unlock(&nor->lock);
|
||||
} else {
|
||||
spi_nor_rww_end_rd(nor, start, len);
|
||||
wake_up(&nor->rww.wait);
|
||||
}
|
||||
|
||||
spi_nor_unprep(nor);
|
||||
}
|
||||
|
||||
static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr)
|
||||
@ -1397,11 +1758,18 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
|
||||
dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n",
|
||||
cmd->size, cmd->opcode, cmd->count);
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
ret = spi_nor_lock_device(nor);
|
||||
if (ret)
|
||||
goto destroy_erase_cmd_list;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret) {
|
||||
spi_nor_unlock_device(nor);
|
||||
goto destroy_erase_cmd_list;
|
||||
}
|
||||
|
||||
ret = spi_nor_erase_sector(nor, addr);
|
||||
spi_nor_unlock_device(nor);
|
||||
if (ret)
|
||||
goto destroy_erase_cmd_list;
|
||||
|
||||
@ -1446,7 +1814,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
addr = instr->addr;
|
||||
len = instr->len;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1454,11 +1822,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
|
||||
unsigned long timeout;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
ret = spi_nor_lock_device(nor);
|
||||
if (ret)
|
||||
goto erase_err;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret) {
|
||||
spi_nor_unlock_device(nor);
|
||||
goto erase_err;
|
||||
}
|
||||
|
||||
ret = spi_nor_erase_chip(nor);
|
||||
spi_nor_unlock_device(nor);
|
||||
if (ret)
|
||||
goto erase_err;
|
||||
|
||||
@ -1483,11 +1858,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
/* "sector"-at-a-time erase */
|
||||
} else if (spi_nor_has_uniform_erase(nor)) {
|
||||
while (len) {
|
||||
ret = spi_nor_write_enable(nor);
|
||||
ret = spi_nor_lock_device(nor);
|
||||
if (ret)
|
||||
goto erase_err;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret) {
|
||||
spi_nor_unlock_device(nor);
|
||||
goto erase_err;
|
||||
}
|
||||
|
||||
ret = spi_nor_erase_sector(nor, addr);
|
||||
spi_nor_unlock_device(nor);
|
||||
if (ret)
|
||||
goto erase_err;
|
||||
|
||||
@ -1509,7 +1891,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
ret = spi_nor_write_disable(nor);
|
||||
|
||||
erase_err:
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
spi_nor_unlock_and_unprep_pe(nor, instr->addr, instr->len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1702,11 +2084,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
loff_t from_lock = from;
|
||||
size_t len_lock = len;
|
||||
ssize_t ret;
|
||||
|
||||
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock_rd(nor, from_lock, len_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1733,7 +2117,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
ret = 0;
|
||||
|
||||
read_err:
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
spi_nor_unlock_and_unprep_rd(nor, from_lock, len_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1752,7 +2137,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
||||
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock_pe(nor, to, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1777,11 +2162,18 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
||||
addr = spi_nor_convert_addr(nor, addr);
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
ret = spi_nor_lock_device(nor);
|
||||
if (ret)
|
||||
goto write_err;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret) {
|
||||
spi_nor_unlock_device(nor);
|
||||
goto write_err;
|
||||
}
|
||||
|
||||
ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
|
||||
spi_nor_unlock_device(nor);
|
||||
if (ret < 0)
|
||||
goto write_err;
|
||||
written = ret;
|
||||
@ -1794,7 +2186,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
}
|
||||
|
||||
write_err:
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
spi_nor_unlock_and_unprep_pe(nor, to, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2470,6 +2863,10 @@ static void spi_nor_init_flags(struct spi_nor *nor)
|
||||
|
||||
if (flags & NO_CHIP_ERASE)
|
||||
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
|
||||
|
||||
if (flags & SPI_NOR_RWW && nor->info->n_banks > 1 &&
|
||||
!nor->controller_ops)
|
||||
nor->flags |= SNOR_F_RWW;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2501,6 +2898,8 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
|
||||
*/
|
||||
static void spi_nor_late_init_params(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (nor->manufacturer && nor->manufacturer->fixups &&
|
||||
nor->manufacturer->fixups->late_init)
|
||||
nor->manufacturer->fixups->late_init(nor);
|
||||
@ -2508,6 +2907,10 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
|
||||
if (nor->info->fixups && nor->info->fixups->late_init)
|
||||
nor->info->fixups->late_init(nor);
|
||||
|
||||
/* Default method kept for backward compatibility. */
|
||||
if (!params->set_4byte_addr_mode)
|
||||
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
|
||||
|
||||
spi_nor_init_flags(nor);
|
||||
spi_nor_init_fixup_flags(nor);
|
||||
|
||||
@ -2517,6 +2920,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
|
||||
*/
|
||||
if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
|
||||
spi_nor_init_default_locking_ops(nor);
|
||||
|
||||
nor->params->bank_size = div64_u64(nor->params->size, nor->info->n_banks);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2574,7 +2979,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
|
||||
struct device_node *np = spi_nor_get_flash_node(nor);
|
||||
|
||||
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
|
||||
params->set_4byte_addr_mode = spansion_set_4byte_addr_mode;
|
||||
params->otp.org = &info->otp_org;
|
||||
|
||||
/* Default to 16-bit Write Status (01h) Command */
|
||||
@ -2730,6 +3134,33 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
|
||||
return nor->params->quad_enable(nor);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_set_4byte_addr_mode() - Set address mode.
|
||||
* @nor: pointer to a 'struct spi_nor'.
|
||||
* @enable: enable/disable 4 byte address mode.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int ret;
|
||||
|
||||
ret = params->set_4byte_addr_mode(nor, enable);
|
||||
if (ret && ret != -ENOTSUPP)
|
||||
return ret;
|
||||
|
||||
if (enable) {
|
||||
params->addr_nbytes = 4;
|
||||
params->addr_mode_nbytes = 4;
|
||||
} else {
|
||||
params->addr_nbytes = 3;
|
||||
params->addr_mode_nbytes = 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_nor_init(struct spi_nor *nor)
|
||||
{
|
||||
int err;
|
||||
@ -2773,8 +3204,8 @@ static int spi_nor_init(struct spi_nor *nor)
|
||||
*/
|
||||
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
|
||||
"enabling reset hack; may not recover from unexpected reboots\n");
|
||||
err = nor->params->set_4byte_addr_mode(nor, true);
|
||||
if (err && err != -ENOTSUPP)
|
||||
err = spi_nor_set_4byte_addr_mode(nor, true);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2887,14 +3318,14 @@ static void spi_nor_put_device(struct mtd_info *mtd)
|
||||
module_put(dev->driver->owner);
|
||||
}
|
||||
|
||||
void spi_nor_restore(struct spi_nor *nor)
|
||||
static void spi_nor_restore(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* restore the addressing mode */
|
||||
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
|
||||
nor->flags & SNOR_F_BROKEN_RESET) {
|
||||
ret = nor->params->set_4byte_addr_mode(nor, false);
|
||||
ret = spi_nor_set_4byte_addr_mode(nor, false);
|
||||
if (ret)
|
||||
/*
|
||||
* Do not stop the execution in the hope that the flash
|
||||
@ -2907,7 +3338,6 @@ void spi_nor_restore(struct spi_nor *nor)
|
||||
if (nor->flags & SNOR_F_SOFT_RESET)
|
||||
spi_nor_soft_reset(nor);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_nor_restore);
|
||||
|
||||
static const struct flash_info *spi_nor_match_name(struct spi_nor *nor,
|
||||
const char *name)
|
||||
@ -2952,7 +3382,7 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
|
||||
* JEDEC knows better, so overwrite platform ID. We
|
||||
* can't trust partitions any longer, but we'll let
|
||||
* mtd apply them anyway, since some partitions may be
|
||||
* marked read-only, and we don't want to lose that
|
||||
* marked read-only, and we don't want to loose that
|
||||
* information, even if it's not 100% accurate.
|
||||
*/
|
||||
dev_warn(nor->dev, "found %s, expected %s\n",
|
||||
@ -2977,6 +3407,9 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
|
||||
mtd->name = dev_name(dev);
|
||||
mtd->type = MTD_NORFLASH;
|
||||
mtd->flags = MTD_CAP_NORFLASH;
|
||||
/* Unset BIT_WRITEABLE to enable JFFS2 write buffer for ECC'd NOR */
|
||||
if (nor->flags & SNOR_F_ECC)
|
||||
mtd->flags &= ~MTD_BIT_WRITEABLE;
|
||||
if (nor->info->flags & SPI_NOR_NO_ERASE)
|
||||
mtd->flags |= MTD_NO_ERASE;
|
||||
else
|
||||
@ -3064,6 +3497,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi_nor_use_parallel_locking(nor))
|
||||
init_waitqueue_head(&nor->rww.wait);
|
||||
|
||||
/*
|
||||
* Configure the SPI memory:
|
||||
* - select op codes for (Fast) Read, Page Program and Sector Erase.
|
||||
|
@ -130,6 +130,8 @@ enum spi_nor_option_flags {
|
||||
SNOR_F_IO_MODE_EN_VOLATILE = BIT(11),
|
||||
SNOR_F_SOFT_RESET = BIT(12),
|
||||
SNOR_F_SWP_IS_VOLATILE = BIT(13),
|
||||
SNOR_F_RWW = BIT(14),
|
||||
SNOR_F_ECC = BIT(15),
|
||||
};
|
||||
|
||||
struct spi_nor_read_command {
|
||||
@ -336,7 +338,8 @@ struct spi_nor_otp {
|
||||
* by the spi_nor_fixups hooks, or dynamically when parsing the JESD216
|
||||
* Serial Flash Discoverable Parameters (SFDP) tables.
|
||||
*
|
||||
* @size: the flash memory density in bytes.
|
||||
* @bank_size: the flash memory bank density in bytes.
|
||||
* @size: the total flash memory density in bytes.
|
||||
* @writesize Minimal writable flash unit size. Defaults to 1. Set to
|
||||
* ECC unit size for ECC-ed flashes.
|
||||
* @page_size: the page size of the SPI NOR flash memory.
|
||||
@ -349,6 +352,8 @@ struct spi_nor_otp {
|
||||
* in octal DTR mode.
|
||||
* @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register
|
||||
* command in octal DTR mode.
|
||||
* @n_dice: number of dice in the flash memory.
|
||||
* @vreg_offset: volatile register offset for each die.
|
||||
* @hwcaps: describes the read and page program hardware
|
||||
* capabilities.
|
||||
* @reads: read capabilities ordered by priority: the higher index
|
||||
@ -374,6 +379,7 @@ struct spi_nor_otp {
|
||||
* @locking_ops: SPI NOR locking methods.
|
||||
*/
|
||||
struct spi_nor_flash_parameter {
|
||||
u64 bank_size;
|
||||
u64 size;
|
||||
u32 writesize;
|
||||
u32 page_size;
|
||||
@ -381,6 +387,8 @@ struct spi_nor_flash_parameter {
|
||||
u8 addr_mode_nbytes;
|
||||
u8 rdsr_dummy;
|
||||
u8 rdsr_addr_nbytes;
|
||||
u8 n_dice;
|
||||
u32 *vreg_offset;
|
||||
|
||||
struct spi_nor_hwcaps hwcaps;
|
||||
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
|
||||
@ -422,7 +430,7 @@ struct spi_nor_fixups {
|
||||
int (*post_bfpt)(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt);
|
||||
void (*post_sfdp)(struct spi_nor *nor);
|
||||
int (*post_sfdp)(struct spi_nor *nor);
|
||||
void (*late_init)(struct spi_nor *nor);
|
||||
};
|
||||
|
||||
@ -435,6 +443,7 @@ struct spi_nor_fixups {
|
||||
* @sector_size: the size listed here is what works with SPINOR_OP_SE, which
|
||||
* isn't necessarily called a "sector" by the vendor.
|
||||
* @n_sectors: the number of sectors.
|
||||
* @n_banks: the number of banks.
|
||||
* @page_size: the flash's page size.
|
||||
* @addr_nbytes: number of address bytes to send.
|
||||
*
|
||||
@ -459,6 +468,7 @@ struct spi_nor_fixups {
|
||||
* NO_CHIP_ERASE: chip does not support chip erase.
|
||||
* SPI_NOR_NO_FR: can't do fastread.
|
||||
* SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
|
||||
* SPI_NOR_RWW: flash supports reads while write.
|
||||
*
|
||||
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
|
||||
* Used when SFDP tables are not defined in the flash. These
|
||||
@ -495,6 +505,7 @@ struct flash_info {
|
||||
unsigned sector_size;
|
||||
u16 n_sectors;
|
||||
u16 page_size;
|
||||
u8 n_banks;
|
||||
u8 addr_nbytes;
|
||||
|
||||
bool parse_sfdp;
|
||||
@ -509,6 +520,7 @@ struct flash_info {
|
||||
#define NO_CHIP_ERASE BIT(7)
|
||||
#define SPI_NOR_NO_FR BIT(8)
|
||||
#define SPI_NOR_QUAD_PP BIT(9)
|
||||
#define SPI_NOR_RWW BIT(10)
|
||||
|
||||
u8 no_sfdp_flags;
|
||||
#define SPI_NOR_SKIP_SFDP BIT(0)
|
||||
@ -540,24 +552,30 @@ struct flash_info {
|
||||
.id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \
|
||||
.id_len = 6
|
||||
|
||||
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \
|
||||
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors, _n_banks) \
|
||||
.sector_size = (_sector_size), \
|
||||
.n_sectors = (_n_sectors), \
|
||||
.page_size = 256
|
||||
.page_size = 256, \
|
||||
.n_banks = (_n_banks)
|
||||
|
||||
/* Used when the "_ext_id" is two bytes at most */
|
||||
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \
|
||||
SPI_NOR_ID((_jedec_id), (_ext_id)), \
|
||||
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
|
||||
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1),
|
||||
|
||||
#define INFOB(_jedec_id, _ext_id, _sector_size, _n_sectors, _n_banks) \
|
||||
SPI_NOR_ID((_jedec_id), (_ext_id)), \
|
||||
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), (_n_banks)),
|
||||
|
||||
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \
|
||||
SPI_NOR_ID6((_jedec_id), (_ext_id)), \
|
||||
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
|
||||
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1),
|
||||
|
||||
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \
|
||||
.sector_size = (_sector_size), \
|
||||
.n_sectors = (_n_sectors), \
|
||||
.page_size = (_page_size), \
|
||||
.n_banks = 1, \
|
||||
.addr_nbytes = (_addr_nbytes), \
|
||||
.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, \
|
||||
|
||||
@ -634,10 +652,14 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
|
||||
const enum spi_nor_protocol proto);
|
||||
int spi_nor_write_enable(struct spi_nor *nor);
|
||||
int spi_nor_write_disable(struct spi_nor *nor);
|
||||
int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable);
|
||||
int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor,
|
||||
bool enable);
|
||||
int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable);
|
||||
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable);
|
||||
int spi_nor_wait_till_ready(struct spi_nor *nor);
|
||||
int spi_nor_global_block_unlock(struct spi_nor *nor);
|
||||
int spi_nor_lock_and_prep(struct spi_nor *nor);
|
||||
int spi_nor_prep_and_lock(struct spi_nor *nor);
|
||||
void spi_nor_unlock_and_unprep(struct spi_nor *nor);
|
||||
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
|
||||
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
|
||||
|
@ -25,6 +25,8 @@ static const char *const snor_f_names[] = {
|
||||
SNOR_F_NAME(IO_MODE_EN_VOLATILE),
|
||||
SNOR_F_NAME(SOFT_RESET),
|
||||
SNOR_F_NAME(SWP_IS_VOLATILE),
|
||||
SNOR_F_NAME(RWW),
|
||||
SNOR_F_NAME(ECC),
|
||||
};
|
||||
#undef SNOR_F_NAME
|
||||
|
||||
|
@ -82,6 +82,9 @@ static const struct flash_info macronix_nor_parts[] = {
|
||||
{ "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
|
||||
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
|
||||
{ "mx25uw51245g", INFOB(0xc2813a, 0, 0, 0, 4)
|
||||
PARSE_SFDP
|
||||
FLAGS(SPI_NOR_RWW) },
|
||||
{ "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
||||
@ -105,11 +108,17 @@ static const struct flash_info macronix_nor_parts[] = {
|
||||
static void macronix_nor_default_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
|
||||
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode;
|
||||
}
|
||||
|
||||
static void macronix_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
if (!nor->params->set_4byte_addr_mode)
|
||||
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups macronix_nor_fixups = {
|
||||
.default_init = macronix_nor_default_init,
|
||||
.late_init = macronix_nor_late_init,
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_macronix = {
|
||||
|
@ -131,7 +131,7 @@ static void mt35xu512aba_default_init(struct spi_nor *nor)
|
||||
nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable;
|
||||
}
|
||||
|
||||
static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
|
||||
static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
/* Set the Fast Read settings. */
|
||||
nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
|
||||
@ -149,6 +149,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
|
||||
* disable it.
|
||||
*/
|
||||
nor->params->quad_enable = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups mt35xu512aba_fixups = {
|
||||
@ -301,30 +303,6 @@ static const struct flash_info st_nor_parts[] = {
|
||||
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16) },
|
||||
};
|
||||
|
||||
/**
|
||||
* micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and
|
||||
* Micron flashes.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
|
||||
* address mode.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_nor_set_4byte_addr_mode(nor, enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return spi_nor_write_disable(nor);
|
||||
}
|
||||
|
||||
/**
|
||||
* micron_st_nor_read_fsr() - Read the Flag Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'
|
||||
@ -449,13 +427,17 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
|
||||
nor->flags |= SNOR_F_HAS_LOCK;
|
||||
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
nor->params->quad_enable = NULL;
|
||||
nor->params->set_4byte_addr_mode = micron_st_nor_set_4byte_addr_mode;
|
||||
}
|
||||
|
||||
static void micron_st_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (nor->info->mfr_flags & USE_FSR)
|
||||
nor->params->ready = micron_st_nor_ready;
|
||||
params->ready = micron_st_nor_ready;
|
||||
|
||||
if (!params->set_4byte_addr_mode)
|
||||
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups micron_st_nor_fixups = {
|
||||
|
@ -255,7 +255,7 @@ static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len,
|
||||
if (len < n_regions * sizeof(*buf))
|
||||
return -ENOSPC;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -325,7 +325,7 @@ static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
|
||||
if (!total_len)
|
||||
return 0;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -415,7 +415,7 @@ static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
|
||||
return -EINVAL;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -460,7 +460,7 @@ static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
|
||||
return -EINVAL;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -26,6 +26,11 @@
|
||||
* Status, Control and Configuration
|
||||
* Register Map.
|
||||
*/
|
||||
#define SFDP_SCCR_MAP_MC_ID 0xff88 /*
|
||||
* Status, Control and Configuration
|
||||
* Register Map Offsets for Multi-Chip
|
||||
* SPI Memory Devices.
|
||||
*/
|
||||
|
||||
#define SFDP_SIGNATURE 0x50444653U
|
||||
|
||||
@ -438,6 +443,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
||||
size_t len;
|
||||
int i, cmd, err;
|
||||
u32 addr, val;
|
||||
u32 dword;
|
||||
u16 half;
|
||||
u8 erase_mask;
|
||||
|
||||
@ -607,6 +613,16 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
||||
break;
|
||||
}
|
||||
|
||||
dword = bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_4B_ADDR_MODE_MASK;
|
||||
if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_BRWR))
|
||||
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
|
||||
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B))
|
||||
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
|
||||
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B))
|
||||
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
|
||||
else
|
||||
dev_dbg(nor->dev, "BFPT: 4-Byte Address Mode method is not recognized or not implemented\n");
|
||||
|
||||
/* Soft Reset support. */
|
||||
if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
|
||||
nor->flags |= SNOR_F_SOFT_RESET;
|
||||
@ -1215,6 +1231,7 @@ out:
|
||||
static int spi_nor_parse_sccr(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *sccr_header)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u32 *dwords, addr;
|
||||
size_t len;
|
||||
int ret;
|
||||
@ -1231,6 +1248,18 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
|
||||
|
||||
le32_to_cpu_array(dwords, sccr_header->length);
|
||||
|
||||
/* Address offset for volatile registers (die 0) */
|
||||
if (!params->vreg_offset) {
|
||||
params->vreg_offset = devm_kmalloc(nor->dev, sizeof(*dwords),
|
||||
GFP_KERNEL);
|
||||
if (!params->vreg_offset) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
params->vreg_offset[0] = dwords[SFDP_DWORD(1)];
|
||||
params->n_dice = 1;
|
||||
|
||||
if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE,
|
||||
dwords[SFDP_DWORD(22)]))
|
||||
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
|
||||
@ -1240,6 +1269,63 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_parse_sccr_mc() - Parse the Status, Control and Configuration
|
||||
* Register Map Offsets for Multi-Chip SPI Memory
|
||||
* Devices.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* @sccr_mc_header: pointer to the 'struct sfdp_parameter_header' describing
|
||||
* the SCCR Map offsets table length and version.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int spi_nor_parse_sccr_mc(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *sccr_mc_header)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u32 *dwords, addr;
|
||||
u8 i, n_dice;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = sccr_mc_header->length * sizeof(*dwords);
|
||||
dwords = kmalloc(len, GFP_KERNEL);
|
||||
if (!dwords)
|
||||
return -ENOMEM;
|
||||
|
||||
addr = SFDP_PARAM_HEADER_PTP(sccr_mc_header);
|
||||
ret = spi_nor_read_sfdp(nor, addr, len, dwords);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
le32_to_cpu_array(dwords, sccr_mc_header->length);
|
||||
|
||||
/*
|
||||
* Pair of DOWRDs (volatile and non-volatile register offsets) per
|
||||
* additional die. Hence, length = 2 * (number of additional dice).
|
||||
*/
|
||||
n_dice = 1 + sccr_mc_header->length / 2;
|
||||
|
||||
/* Address offset for volatile registers of additional dice */
|
||||
params->vreg_offset =
|
||||
devm_krealloc(nor->dev, params->vreg_offset,
|
||||
n_dice * sizeof(*dwords),
|
||||
GFP_KERNEL);
|
||||
if (!params->vreg_offset) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 1; i < n_dice; i++)
|
||||
params->vreg_offset[i] = dwords[SFDP_DWORD(i) * 2];
|
||||
|
||||
params->n_dice = n_dice;
|
||||
|
||||
out:
|
||||
kfree(dwords);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
|
||||
* after SFDP has been parsed. Called only for flashes that define JESD216 SFDP
|
||||
@ -1249,14 +1335,21 @@ out:
|
||||
* Used to tweak various flash parameters when information provided by the SFDP
|
||||
* tables are wrong.
|
||||
*/
|
||||
static void spi_nor_post_sfdp_fixups(struct spi_nor *nor)
|
||||
static int spi_nor_post_sfdp_fixups(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->manufacturer && nor->manufacturer->fixups &&
|
||||
nor->manufacturer->fixups->post_sfdp)
|
||||
nor->manufacturer->fixups->post_sfdp(nor);
|
||||
nor->manufacturer->fixups->post_sfdp) {
|
||||
ret = nor->manufacturer->fixups->post_sfdp(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (nor->info->fixups && nor->info->fixups->post_sfdp)
|
||||
nor->info->fixups->post_sfdp(nor);
|
||||
return nor->info->fixups->post_sfdp(nor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1449,6 +1542,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
|
||||
err = spi_nor_parse_sccr(nor, param_header);
|
||||
break;
|
||||
|
||||
case SFDP_SCCR_MAP_MC_ID:
|
||||
err = spi_nor_parse_sccr_mc(nor, param_header);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1466,7 +1563,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
|
||||
}
|
||||
}
|
||||
|
||||
spi_nor_post_sfdp_fixups(nor);
|
||||
err = spi_nor_post_sfdp_fixups(nor);
|
||||
exit:
|
||||
kfree(param_headers);
|
||||
return err;
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
|
||||
#define SFDP_DWORD(i) ((i) - 1)
|
||||
#define SFDP_MASK_CHECK(dword, mask) (((dword) & (mask)) == (mask))
|
||||
|
||||
/* Basic Flash Parameter Table */
|
||||
|
||||
@ -89,6 +90,32 @@ struct sfdp_bfpt {
|
||||
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
|
||||
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
|
||||
|
||||
#define BFPT_DWORD16_EN4B_MASK GENMASK(31, 24)
|
||||
#define BFPT_DWORD16_EN4B_ALWAYS_4B BIT(30)
|
||||
#define BFPT_DWORD16_EN4B_4B_OPCODES BIT(29)
|
||||
#define BFPT_DWORD16_EN4B_16BIT_NV_CR BIT(28)
|
||||
#define BFPT_DWORD16_EN4B_BRWR BIT(27)
|
||||
#define BFPT_DWORD16_EN4B_WREAR BIT(26)
|
||||
#define BFPT_DWORD16_EN4B_WREN_EN4B BIT(25)
|
||||
#define BFPT_DWORD16_EN4B_EN4B BIT(24)
|
||||
#define BFPT_DWORD16_EX4B_MASK GENMASK(18, 14)
|
||||
#define BFPT_DWORD16_EX4B_16BIT_NV_CR BIT(18)
|
||||
#define BFPT_DWORD16_EX4B_BRWR BIT(17)
|
||||
#define BFPT_DWORD16_EX4B_WREAR BIT(16)
|
||||
#define BFPT_DWORD16_EX4B_WREN_EX4B BIT(15)
|
||||
#define BFPT_DWORD16_EX4B_EX4B BIT(14)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_MASK \
|
||||
(BFPT_DWORD16_EN4B_MASK | BFPT_DWORD16_EX4B_MASK)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_16BIT_NV_CR \
|
||||
(BFPT_DWORD16_EN4B_16BIT_NV_CR | BFPT_DWORD16_EX4B_16BIT_NV_CR)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_BRWR \
|
||||
(BFPT_DWORD16_EN4B_BRWR | BFPT_DWORD16_EX4B_BRWR)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_WREAR \
|
||||
(BFPT_DWORD16_EN4B_WREAR | BFPT_DWORD16_EX4B_WREAR)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B \
|
||||
(BFPT_DWORD16_EN4B_WREN_EN4B | BFPT_DWORD16_EX4B_WREN_EX4B)
|
||||
#define BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B \
|
||||
(BFPT_DWORD16_EN4B_EN4B | BFPT_DWORD16_EX4B_EX4B)
|
||||
#define BFPT_DWORD16_SWRST_EN_RST BIT(12)
|
||||
|
||||
#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)
|
||||
|
@ -14,13 +14,26 @@
|
||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
|
||||
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
|
||||
#define SPINOR_REG_CYPRESS_CFR1V 0x00800002
|
||||
#define SPINOR_REG_CYPRESS_VREG 0x00800000
|
||||
#define SPINOR_REG_CYPRESS_STR1 0x0
|
||||
#define SPINOR_REG_CYPRESS_STR1V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1)
|
||||
#define SPINOR_REG_CYPRESS_CFR1 0x2
|
||||
#define SPINOR_REG_CYPRESS_CFR1V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1)
|
||||
#define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
|
||||
#define SPINOR_REG_CYPRESS_CFR2V 0x00800003
|
||||
#define SPINOR_REG_CYPRESS_CFR2 0x3
|
||||
#define SPINOR_REG_CYPRESS_CFR2V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
|
||||
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
|
||||
#define SPINOR_REG_CYPRESS_CFR3V 0x00800004
|
||||
#define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7)
|
||||
#define SPINOR_REG_CYPRESS_CFR3 0x4
|
||||
#define SPINOR_REG_CYPRESS_CFR3V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3)
|
||||
#define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
|
||||
#define SPINOR_REG_CYPRESS_CFR5V 0x00800006
|
||||
#define SPINOR_REG_CYPRESS_CFR5 0x6
|
||||
#define SPINOR_REG_CYPRESS_CFR5V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
|
||||
@ -29,6 +42,7 @@
|
||||
SPINOR_REG_CYPRESS_CFR5_OPI)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6
|
||||
#define SPINOR_OP_CYPRESS_RD_FAST 0xee
|
||||
#define SPINOR_REG_CYPRESS_ARCFN 0x00000006
|
||||
|
||||
/* Cypress SPI NOR flash operations. */
|
||||
#define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \
|
||||
@ -37,10 +51,10 @@
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
|
||||
|
||||
#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, buf) \
|
||||
#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, ndummy, buf) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \
|
||||
SPI_MEM_OP_ADDR(naddr, addr, 0), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 0), \
|
||||
SPI_MEM_OP_DATA_IN(1, buf, 0))
|
||||
|
||||
#define SPANSION_CLSR_OP \
|
||||
@ -49,6 +63,84 @@
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
/**
|
||||
* spansion_nor_clear_sr() - Clear the Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*/
|
||||
static void spansion_nor_clear_sr(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op = SPANSION_CLSR_OP;
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
|
||||
}
|
||||
|
||||
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
|
||||
0, nor->bouncebuf);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
|
||||
if (nor->bouncebuf[0] & SR_E_ERR)
|
||||
dev_err(nor->dev, "Erase Error occurred\n");
|
||||
else
|
||||
dev_err(nor->dev, "Programming Error occurred\n");
|
||||
|
||||
spansion_nor_clear_sr(nor);
|
||||
|
||||
ret = spi_nor_write_disable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return !(nor->bouncebuf[0] & SR_WIP);
|
||||
}
|
||||
/**
|
||||
* cypress_nor_sr_ready_and_clear() - Query the Status Register of each die by
|
||||
* using Read Any Register command to see if the whole flash is ready for new
|
||||
* commands and clear it if there are any errors.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*
|
||||
* Return: 1 if ready, 0 if not ready, -errno on errors.
|
||||
*/
|
||||
static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u64 addr;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_STR1;
|
||||
ret = cypress_nor_sr_ready_and_clear_reg(nor, addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
@ -125,6 +217,51 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_quad_enable_volatile_reg(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
|
||||
u8 cfr1v_written;
|
||||
int ret;
|
||||
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
|
||||
nor->bouncebuf);
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
|
||||
return 0;
|
||||
|
||||
/* Update the Quad Enable bit. */
|
||||
nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cfr1v_written = nor->bouncebuf[0];
|
||||
|
||||
/* Read back and check it. */
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] != cfr1v_written) {
|
||||
dev_err(nor->dev, "CFR1: Read back test failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile
|
||||
* register.
|
||||
@ -141,68 +278,141 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
||||
*/
|
||||
static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
|
||||
u8 cfr1v_written;
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u64 addr;
|
||||
u8 i;
|
||||
int ret;
|
||||
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR1V,
|
||||
nor->bouncebuf);
|
||||
if (!params->n_dice)
|
||||
return cypress_nor_quad_enable_volatile_reg(nor,
|
||||
SPINOR_REG_CYPRESS_CFR1V);
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
|
||||
return 0;
|
||||
|
||||
/* Update the Quad Enable bit. */
|
||||
nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR1V, 1,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cfr1v_written = nor->bouncebuf[0];
|
||||
|
||||
/* Read back and check it. */
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR1V,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] != cfr1v_written) {
|
||||
dev_err(nor->dev, "CFR1: Read back test failed\n");
|
||||
return -EIO;
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
|
||||
ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_set_page_size() - Set page size which corresponds to the flash
|
||||
* configuration.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
|
||||
* (3 or 4-byte) by querying status
|
||||
* register 1 (SR1).
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* @addr_mode: ponter to a buffer where we return the determined
|
||||
* address mode.
|
||||
*
|
||||
* The BFPT table advertises a 512B or 256B page size depending on part but the
|
||||
* page size is actually configurable (with the default being 256B). Read from
|
||||
* CFR3V[4] and set the correct size.
|
||||
* This function tries to determine current address mode by comparing SR1 value
|
||||
* from RDSR1(no address), RDAR(3-byte address), and RDAR(4-byte address).
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_set_page_size(struct spi_nor *nor)
|
||||
static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor,
|
||||
u8 *addr_mode)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_STR1V, 0,
|
||||
nor->bouncebuf);
|
||||
bool is3byte, is4byte;
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_read_sr(nor, &nor->bouncebuf[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
is3byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
|
||||
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(4, SPINOR_REG_CYPRESS_STR1V, 0,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
is4byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
|
||||
|
||||
if (is3byte == is4byte)
|
||||
return -EIO;
|
||||
if (is3byte)
|
||||
*addr_mode = 3;
|
||||
else
|
||||
*addr_mode = 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_set_addr_mode_nbytes() - Set the number of address bytes mode of
|
||||
* current address mode.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
*
|
||||
* Determine current address mode by reading SR1 with different methods, then
|
||||
* query CFR2V[7] to confirm. If determination is failed, force enter to 4-byte
|
||||
* address mode.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 addr_mode;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Read SR1 by RDSR1 and RDAR(3- AND 4-byte addr). Use write enable
|
||||
* that sets bit-1 in SR1.
|
||||
*/
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = cypress_nor_determine_addr_mode_by_sr1(nor, &addr_mode);
|
||||
if (ret) {
|
||||
ret = spi_nor_set_4byte_addr_mode(nor, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
return spi_nor_write_disable(nor);
|
||||
}
|
||||
ret = spi_nor_write_disable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Query CFR2V and make sure no contradiction between determined address
|
||||
* mode and CFR2V[7].
|
||||
*/
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode, SPINOR_REG_CYPRESS_CFR2V,
|
||||
0, nor->bouncebuf);
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR2_ADRBYT) {
|
||||
if (addr_mode != 4)
|
||||
return spi_nor_set_4byte_addr_mode(nor, true);
|
||||
} else {
|
||||
if (addr_mode != 3)
|
||||
return spi_nor_set_4byte_addr_mode(nor, true);
|
||||
}
|
||||
|
||||
nor->params->addr_nbytes = addr_mode;
|
||||
nor->params->addr_mode_nbytes = addr_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR3V,
|
||||
SPINOR_REG_CYPRESS_CFR3V, 0,
|
||||
nor->bouncebuf);
|
||||
int ret;
|
||||
|
||||
@ -218,18 +428,135 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
0, 0, nor->bouncebuf);
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
/*
|
||||
* Use the minimum common page size configuration. Programming 256-byte
|
||||
* under 512-byte page size configuration is safe.
|
||||
*/
|
||||
params->page_size = 256;
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
op.addr.val = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR3;
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ))
|
||||
return 0;
|
||||
}
|
||||
|
||||
params->page_size = 512;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_get_page_size() - Get flash page size configuration.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
*
|
||||
* The BFPT table advertises a 512B or 256B page size depending on part but the
|
||||
* page size is actually configurable (with the default being 256B). Read from
|
||||
* CFR3V[4] and set the correct size.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_get_page_size(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->params->n_dice)
|
||||
return cypress_nor_get_page_size_mcp(nor);
|
||||
return cypress_nor_get_page_size_single_chip(nor);
|
||||
}
|
||||
|
||||
static void cypress_nor_ecc_init(struct spi_nor *nor)
|
||||
{
|
||||
/*
|
||||
* Programming is supported only in 16-byte ECC data unit granularity.
|
||||
* Byte-programming, bit-walking, or multiple program operations to the
|
||||
* same ECC data unit without an erase are not allowed.
|
||||
*/
|
||||
nor->params->writesize = 16;
|
||||
nor->flags |= SNOR_F_ECC;
|
||||
}
|
||||
|
||||
static int
|
||||
s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
int ret;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read Architecture Configuration Register (ARCFN) */
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_ARCFN, 1,
|
||||
nor->bouncebuf);
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* ARCFN value must be 0 if uniform sector is selected */
|
||||
if (nor->bouncebuf[0])
|
||||
return -ENODEV;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
||||
static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
/* PP_1_1_4_4B is supported but missing in 4BAIT. */
|
||||
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4],
|
||||
SPINOR_OP_PP_1_1_4_4B,
|
||||
SNOR_PROTO_1_1_4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s25fs256t_late_init(struct spi_nor *nor)
|
||||
{
|
||||
cypress_nor_ecc_init(nor);
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25fs256t_fixups = {
|
||||
.post_bfpt = s25fs256t_post_bfpt_fixup,
|
||||
.post_sfdp = s25fs256t_post_sfdp_fixup,
|
||||
.late_init = s25fs256t_late_init,
|
||||
};
|
||||
|
||||
static int
|
||||
s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Replace Quad Enable with volatile version */
|
||||
nor->params->quad_enable = cypress_nor_quad_enable_volatile;
|
||||
|
||||
return cypress_nor_set_page_size(nor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_erase_type *erase_type =
|
||||
nor->params->erase_map.erase_type;
|
||||
@ -251,6 +578,12 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
|
||||
if (nor->params->size == SZ_256M)
|
||||
nor->params->n_dice = 2;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
||||
static void s25hx_t_late_init(struct spi_nor *nor)
|
||||
@ -260,8 +593,11 @@ static void s25hx_t_late_init(struct spi_nor *nor)
|
||||
/* Fast Read 4B requires mode cycles */
|
||||
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
|
||||
|
||||
/* The writesize should be ECC data unit size */
|
||||
params->writesize = 16;
|
||||
cypress_nor_ecc_init(nor);
|
||||
|
||||
/* Replace ready() with multi die version */
|
||||
if (params->n_dice)
|
||||
params->ready = cypress_nor_sr_ready_and_clear;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25hx_t_fixups = {
|
||||
@ -286,7 +622,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
|
||||
cypress_nor_octal_dtr_dis(nor);
|
||||
}
|
||||
|
||||
static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
/*
|
||||
* On older versions of the flash the xSPI Profile 1.0 table has the
|
||||
@ -312,19 +648,27 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
* actual value for that is 4.
|
||||
*/
|
||||
nor->params->rdsr_addr_nbytes = 4;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
||||
static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
||||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
return cypress_nor_set_page_size(nor);
|
||||
int ret;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s28hx_t_late_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
|
||||
nor->params->writesize = 16;
|
||||
cypress_nor_ecc_init(nor);
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups s28hx_t_fixups = {
|
||||
@ -446,6 +790,9 @@ static const struct flash_info spansion_nor_parts[] = {
|
||||
{ "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
|
||||
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
|
||||
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
|
||||
PARSE_SFDP
|
||||
.fixups = &s25fs256t_fixups },
|
||||
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
@ -454,6 +801,10 @@ static const struct flash_info spansion_nor_parts[] = {
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
|
||||
PARSE_SFDP
|
||||
FLAGS(NO_CHIP_ERASE)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
@ -462,6 +813,10 @@ static const struct flash_info spansion_nor_parts[] = {
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
|
||||
PARSE_SFDP
|
||||
FLAGS(NO_CHIP_ERASE)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
|
||||
FLAGS(SPI_NOR_NO_ERASE) },
|
||||
{ "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256)
|
||||
@ -482,29 +837,6 @@ static const struct flash_info spansion_nor_parts[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* spansion_nor_clear_sr() - Clear the Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*/
|
||||
static void spansion_nor_clear_sr(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op = SPANSION_CLSR_OP;
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
|
||||
* flash is ready for new commands and clear it if there are any errors.
|
||||
|
@ -126,7 +126,7 @@ static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
||||
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -348,7 +348,7 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -363,7 +363,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -378,7 +378,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_lock_and_prep(nor);
|
||||
ret = spi_nor_prep_and_lock(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -188,7 +188,7 @@ static int winbond_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_set_4byte_addr_mode(nor, enable);
|
||||
ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable);
|
||||
if (ret || enable)
|
||||
return ret;
|
||||
|
||||
@ -216,19 +216,25 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
|
||||
.is_locked = spi_nor_otp_is_locked_sr2,
|
||||
};
|
||||
|
||||
static void winbond_nor_default_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
|
||||
}
|
||||
|
||||
static void winbond_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->params->otp.org->n_regions)
|
||||
nor->params->otp.ops = &winbond_nor_otp_ops;
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (params->otp.org->n_regions)
|
||||
params->otp.ops = &winbond_nor_otp_ops;
|
||||
|
||||
/*
|
||||
* Winbond seems to require that the Extended Address Register to be set
|
||||
* to zero when exiting the 4-Byte Address Mode, at least for W25Q256FV.
|
||||
* This requirement is not described in the JESD216 SFDP standard, thus
|
||||
* it is Winbond specific. Since we do not know if other Winbond flashes
|
||||
* have the same requirement, play safe and overwrite the method parsed
|
||||
* from BFPT, if any.
|
||||
*/
|
||||
params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups winbond_nor_fixups = {
|
||||
.default_init = winbond_nor_default_init,
|
||||
.late_init = winbond_nor_late_init,
|
||||
};
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
.sector_size = (8 * (_page_size)), \
|
||||
.n_sectors = (_n_sectors), \
|
||||
.page_size = (_page_size), \
|
||||
.n_banks = 1, \
|
||||
.addr_nbytes = 3, \
|
||||
.flags = SPI_NOR_NO_FR
|
||||
|
||||
|
@ -1075,7 +1075,7 @@ static inline void nand_op_trace(const char *prefix,
|
||||
* @exec_op: controller specific method to execute NAND operations.
|
||||
* This method replaces chip->legacy.cmdfunc(),
|
||||
* chip->legacy.{read,write}_{buf,byte,word}(),
|
||||
* chip->legacy.dev_ready() and chip->legacy.waifunc().
|
||||
* chip->legacy.dev_ready() and chip->legacy.waitfunc().
|
||||
* @setup_interface: setup the data interface and timing. If chipnr is set to
|
||||
* %NAND_DATA_IFACE_CHECK_ONLY this means the configuration
|
||||
* should not be applied but only checked.
|
||||
|
@ -343,6 +343,12 @@ struct spi_nor_flash_parameter;
|
||||
* struct spi_nor - Structure for defining the SPI NOR layer
|
||||
* @mtd: an mtd_info structure
|
||||
* @lock: the lock for the read/write/erase/lock/unlock operations
|
||||
* @rww: Read-While-Write (RWW) sync lock
|
||||
* @rww.wait: wait queue for the RWW sync
|
||||
* @rww.ongoing_io: the bus is busy
|
||||
* @rww.ongoing_rd: a read is ongoing on the chip
|
||||
* @rww.ongoing_pe: a program/erase is ongoing on the chip
|
||||
* @rww.used_banks: bitmap of the banks in use
|
||||
* @dev: pointer to an SPI device or an SPI NOR controller device
|
||||
* @spimem: pointer to the SPI memory device
|
||||
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
|
||||
@ -376,6 +382,13 @@ struct spi_nor_flash_parameter;
|
||||
struct spi_nor {
|
||||
struct mtd_info mtd;
|
||||
struct mutex lock;
|
||||
struct spi_nor_rww {
|
||||
wait_queue_head_t wait;
|
||||
bool ongoing_io;
|
||||
bool ongoing_rd;
|
||||
bool ongoing_pe;
|
||||
unsigned int used_banks;
|
||||
} rww;
|
||||
struct device *dev;
|
||||
struct spi_mem *spimem;
|
||||
u8 *bouncebuf;
|
||||
@ -437,10 +450,4 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
|
||||
int spi_nor_scan(struct spi_nor *nor, const char *name,
|
||||
const struct spi_nor_hwcaps *hwcaps);
|
||||
|
||||
/**
|
||||
* spi_nor_restore_addr_mode() - restore the status of SPI NOR
|
||||
* @nor: the spi_nor structure
|
||||
*/
|
||||
void spi_nor_restore(struct spi_nor *nor);
|
||||
|
||||
#endif
|
||||
|
@ -262,6 +262,7 @@ struct spinand_manufacturer {
|
||||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer ato_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
|
Loading…
Reference in New Issue
Block a user