Commit 1d46f1ae authored by Miquel Raynal's avatar Miquel Raynal

Merge tag 'nand/for-6.2' into mtd/next

Raw NAND core changes:
* Drop obsolete dependencies on COMPILE_TEST
* MAINTAINERS: rectify entry for MESON NAND controller bindings
* Drop EXPORT_SYMBOL_GPL for nanddev_erase()

Raw NAND driver changes:
* marvell: Enable NFC/DEVBUS arbiter
* gpmi: Use pm_runtime_resume_and_get instead of pm_runtime_get_sync
* mpc5121: Replace NO_IRQ by 0
* lpc32xx_{slc,mlc}:
  - Switch to using pm_ptr()
  - Switch to using gpiod API
* lpc32xx_mlc: Switch to using pm_ptr()
* cadence: Support 64-bit slave dma interface
* rockchip: Describe rk3128-nfc in the bindings
* brcmnand: Update interrupts description in the bindings

SPI-NAND driver changes:
* winbond:
  - Add Winbond W25N02KV flash support
  - Fix flash identification

Fix merge conflict with mtd tree regarding the brcm bindings.
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
parents 2399401f 6408cc05
...@@ -86,15 +86,15 @@ properties: ...@@ -86,15 +86,15 @@ properties:
minItems: 1 minItems: 1
items: items:
- description: NAND CTLRDY interrupt - description: NAND CTLRDY interrupt
- description: FLASH_DMA_DONE if flash DMA is available - description: FLASH_DMA_DONE (if flash DMA is available) or FLASH_EDU_DONE (if EDU is available)
- description: FLASH_EDU_DONE if EDU is available
interrupt-names: interrupt-names:
minItems: 1 minItems: 1
items: items:
- const: nand_ctlrdy - const: nand_ctlrdy
- const: flash_dma_done - enum:
- const: flash_edu_done - flash_dma_done
- flash_edu_done
clocks: clocks:
maxItems: 1 maxItems: 1
...@@ -173,6 +173,13 @@ allOf: ...@@ -173,6 +173,13 @@ allOf:
- const: nand - const: nand
- const: iproc-idm - const: iproc-idm
- const: iproc-ext - const: iproc-ext
- if:
properties:
interrupts:
minItems: 2
then:
required:
- interrupt-names
unevaluatedProperties: false unevaluatedProperties: false
...@@ -190,6 +197,7 @@ examples: ...@@ -190,6 +197,7 @@ examples:
reg-names = "nand", "flash-dma"; reg-names = "nand", "flash-dma";
interrupt-parent = <&hif_intr2_intc>; interrupt-parent = <&hif_intr2_intc>;
interrupts = <24>, <4>; interrupts = <24>, <4>;
interrupt-names = "nand_ctlrdy", "flash_dma_done";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -19,7 +19,9 @@ properties: ...@@ -19,7 +19,9 @@ properties:
- const: rockchip,rk2928-nfc - const: rockchip,rk2928-nfc
- const: rockchip,rv1108-nfc - const: rockchip,rv1108-nfc
- items: - items:
- const: rockchip,rk3036-nfc - enum:
- rockchip,rk3036-nfc
- rockchip,rk3128-nfc
- const: rockchip,rk2928-nfc - const: rockchip,rk2928-nfc
- items: - items:
- const: rockchip,rk3308-nfc - const: rockchip,rk3308-nfc
......
...@@ -13382,7 +13382,7 @@ MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS ...@@ -13382,7 +13382,7 @@ MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
M: Liang Yang <liang.yang@amlogic.com> M: Liang Yang <liang.yang@amlogic.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml
F: drivers/mtd/nand/raw/meson_* F: drivers/mtd/nand/raw/meson_*
MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
......
...@@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved); ...@@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved);
* *
* Return: 0 in case of success, a negative error code otherwise. * Return: 0 in case of success, a negative error code otherwise.
*/ */
int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) static int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
{ {
if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) { if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
pr_warn("attempt to erase a bad/reserved block @%llx\n", pr_warn("attempt to erase a bad/reserved block @%llx\n",
...@@ -136,7 +136,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) ...@@ -136,7 +136,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
return nand->ops->erase(nand, pos); return nand->ops->erase(nand, pos);
} }
EXPORT_SYMBOL_GPL(nanddev_erase);
/** /**
* nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
......
...@@ -415,7 +415,7 @@ config MTD_NAND_PLATFORM ...@@ -415,7 +415,7 @@ config MTD_NAND_PLATFORM
config MTD_NAND_CADENCE config MTD_NAND_CADENCE
tristate "Support Cadence NAND (HPNFC) controller" tristate "Support Cadence NAND (HPNFC) controller"
depends on (OF || COMPILE_TEST) && HAS_IOMEM depends on OF && HAS_IOMEM
help help
Enable the driver for NAND flash on platforms using a Cadence NAND Enable the driver for NAND flash on platforms using a Cadence NAND
controller. controller.
...@@ -430,7 +430,7 @@ config MTD_NAND_ARASAN ...@@ -430,7 +430,7 @@ config MTD_NAND_ARASAN
config MTD_NAND_INTEL_LGM config MTD_NAND_INTEL_LGM
tristate "Support for NAND controller on Intel LGM SoC" tristate "Support for NAND controller on Intel LGM SoC"
depends on OF || COMPILE_TEST depends on OF
depends on HAS_IOMEM depends on HAS_IOMEM
help help
Enables support for NAND Flash chips on Intel's LGM SoC. Enables support for NAND Flash chips on Intel's LGM SoC.
...@@ -450,7 +450,7 @@ config MTD_NAND_ROCKCHIP ...@@ -450,7 +450,7 @@ config MTD_NAND_ROCKCHIP
config MTD_NAND_PL35X config MTD_NAND_PL35X
tristate "ARM PL35X NAND controller" tristate "ARM PL35X NAND controller"
depends on OF || COMPILE_TEST depends on OF
depends on PL353_SMC depends on PL353_SMC
help help
Enables support for PrimeCell SMC PL351 and PL353 NAND Enables support for PrimeCell SMC PL351 and PL353 NAND
......
...@@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl) ...@@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl)
if (cadence_nand_read_bch_caps(cdns_ctrl)) if (cadence_nand_read_bch_caps(cdns_ctrl))
return -EIO; return -EIO;
#ifndef CONFIG_64BIT
if (cdns_ctrl->caps2.data_dma_width == 8) {
dev_err(cdns_ctrl->dev,
"cannot access 64-bit dma on !64-bit architectures");
return -EIO;
}
#endif
/* /*
* Set IO width access to 8. * Set IO width access to 8.
* It is because during SW device discovering width access * It is because during SW device discovering width access
...@@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl, ...@@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status; return status;
if (!cdns_ctrl->caps1->has_dma) { if (!cdns_ctrl->caps1->has_dma) {
int len_in_words = len >> 2; u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
/* read alingment data */ /* read alingment data */
if (data_dma_width == 4)
ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
#ifdef CONFIG_64BIT
else
readsq(cdns_ctrl->io.virt, buf, len_in_words);
#endif
if (sdma_size > len) { if (sdma_size > len) {
int read_bytes = (data_dma_width == 4) ?
len_in_words << 2 : len_in_words << 3;
/* read rest data from slave DMA interface if any */ /* read rest data from slave DMA interface if any */
ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, if (data_dma_width == 4)
ioread32_rep(cdns_ctrl->io.virt,
cdns_ctrl->buf,
sdma_size / 4 - len_in_words); sdma_size / 4 - len_in_words);
#ifdef CONFIG_64BIT
else
readsq(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 8 - len_in_words);
#endif
/* copy rest of data */ /* copy rest of data */
memcpy(buf + (len_in_words << 2), cdns_ctrl->buf, memcpy(buf + read_bytes, cdns_ctrl->buf,
len - (len_in_words << 2)); len - read_bytes);
} }
return 0; return 0;
} }
...@@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl, ...@@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl,
return status; return status;
if (!cdns_ctrl->caps1->has_dma) { if (!cdns_ctrl->caps1->has_dma) {
int len_in_words = len >> 2; u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
if (data_dma_width == 4)
iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words); iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
#ifdef CONFIG_64BIT
else
writesq(cdns_ctrl->io.virt, buf, len_in_words);
#endif
if (sdma_size > len) { if (sdma_size > len) {
int written_bytes = (data_dma_width == 4) ?
len_in_words << 2 : len_in_words << 3;
/* copy rest of data */ /* copy rest of data */
memcpy(cdns_ctrl->buf, buf + (len_in_words << 2), memcpy(cdns_ctrl->buf, buf + written_bytes,
len - (len_in_words << 2)); len - written_bytes);
/* write all expected by nand controller data */ /* write all expected by nand controller data */
iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, if (data_dma_width == 4)
iowrite32_rep(cdns_ctrl->io.virt,
cdns_ctrl->buf,
sdma_size / 4 - len_in_words); sdma_size / 4 - len_in_words);
#ifdef CONFIG_64BIT
else
writesq(cdns_ctrl->io.virt, cdns_ctrl->buf,
sdma_size / 8 - len_in_words);
#endif
} }
return 0; return 0;
......
...@@ -148,11 +148,9 @@ static int gpmi_init(struct gpmi_nand_data *this) ...@@ -148,11 +148,9 @@ static int gpmi_init(struct gpmi_nand_data *this)
struct resources *r = &this->resources; struct resources *r = &this->resources;
int ret; int ret;
ret = pm_runtime_get_sync(this->dev); ret = pm_runtime_resume_and_get(this->dev);
if (ret < 0) { if (ret < 0)
pm_runtime_put_noidle(this->dev);
return ret; return ret;
}
ret = gpmi_reset_block(r->gpmi_regs, false); ret = gpmi_reset_block(r->gpmi_regs, false);
if (ret) if (ret)
...@@ -2504,11 +2502,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, ...@@ -2504,11 +2502,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip,
for (i = 0; i < GPMI_MAX_TRANSFERS; i++) for (i = 0; i < GPMI_MAX_TRANSFERS; i++)
this->transfers[i].direction = DMA_NONE; this->transfers[i].direction = DMA_NONE;
ret = pm_runtime_get_sync(this->dev); ret = pm_runtime_resume_and_get(this->dev);
if (ret < 0) { if (ret < 0)
pm_runtime_put_noidle(this->dev);
return ret; return ret;
}
/* /*
* This driver currently supports only one NAND chip. Plus, dies share * This driver currently supports only one NAND chip. Plus, dies share
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/gpio/consumer.h>
#include <linux/mtd/lpc32xx_mlc.h> #include <linux/mtd/lpc32xx_mlc.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -122,7 +122,6 @@ struct lpc32xx_nand_cfg_mlc { ...@@ -122,7 +122,6 @@ struct lpc32xx_nand_cfg_mlc {
uint32_t rd_low; uint32_t rd_low;
uint32_t wr_high; uint32_t wr_high;
uint32_t wr_low; uint32_t wr_low;
int wp_gpio;
struct mtd_partition *parts; struct mtd_partition *parts;
unsigned num_parts; unsigned num_parts;
}; };
...@@ -177,6 +176,7 @@ struct lpc32xx_nand_host { ...@@ -177,6 +176,7 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip; struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata; struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk; struct clk *clk;
struct gpio_desc *wp_gpio;
void __iomem *io_base; void __iomem *io_base;
int irq; int irq;
struct lpc32xx_nand_cfg_mlc *ncfg; struct lpc32xx_nand_cfg_mlc *ncfg;
...@@ -370,8 +370,8 @@ static int lpc32xx_waitfunc(struct nand_chip *chip) ...@@ -370,8 +370,8 @@ static int lpc32xx_waitfunc(struct nand_chip *chip)
*/ */
static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
{ {
if (gpio_is_valid(host->ncfg->wp_gpio)) if (host->wp_gpio)
gpio_set_value(host->ncfg->wp_gpio, 0); gpiod_set_value_cansleep(host->wp_gpio, 1);
} }
/* /*
...@@ -379,8 +379,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) ...@@ -379,8 +379,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
*/ */
static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
{ {
if (gpio_is_valid(host->ncfg->wp_gpio)) if (host->wp_gpio)
gpio_set_value(host->ncfg->wp_gpio, 1); gpiod_set_value_cansleep(host->wp_gpio, 0);
} }
static void lpc32xx_dma_complete_func(void *completion) static void lpc32xx_dma_complete_func(void *completion)
...@@ -636,8 +636,6 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) ...@@ -636,8 +636,6 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
return NULL; return NULL;
} }
ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
return ncfg; return ncfg;
} }
...@@ -713,14 +711,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -713,14 +711,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
"Missing or bad NAND config from device tree\n"); "Missing or bad NAND config from device tree\n");
return -ENOENT; return -ENOENT;
} }
if (host->ncfg->wp_gpio == -EPROBE_DEFER)
return -EPROBE_DEFER; /* Start with WP disabled, if available */
if (gpio_is_valid(host->ncfg->wp_gpio) && host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
gpio_request(host->ncfg->wp_gpio, "NAND WP")) { res = PTR_ERR_OR_ZERO(host->wp_gpio);
dev_err(&pdev->dev, "GPIO not available\n"); if (res) {
return -EBUSY; if (res != -EPROBE_DEFER)
dev_err(&pdev->dev, "WP GPIO is not available: %d\n",
res);
return res;
} }
lpc32xx_wp_disable(host);
gpiod_set_consumer_name(host->wp_gpio, "NAND WP");
host->pdata = dev_get_platdata(&pdev->dev); host->pdata = dev_get_platdata(&pdev->dev);
...@@ -817,7 +819,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -817,7 +819,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
clk_put(host->clk); clk_put(host->clk);
free_gpio: free_gpio:
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpiod_put(host->wp_gpio);
return res; return res;
} }
...@@ -843,12 +845,11 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) ...@@ -843,12 +845,11 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
clk_put(host->clk); clk_put(host->clk);
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpiod_put(host->wp_gpio);
return 0; return 0;
} }
#ifdef CONFIG_PM
static int lpc32xx_nand_resume(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev)
{ {
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
...@@ -880,11 +881,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) ...@@ -880,11 +881,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
return 0; return 0;
} }
#else
#define lpc32xx_nand_resume NULL
#define lpc32xx_nand_suspend NULL
#endif
static const struct of_device_id lpc32xx_nand_match[] = { static const struct of_device_id lpc32xx_nand_match[] = {
{ .compatible = "nxp,lpc3220-mlc" }, { .compatible = "nxp,lpc3220-mlc" },
{ /* sentinel */ }, { /* sentinel */ },
...@@ -894,8 +890,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); ...@@ -894,8 +890,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = { static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe, .probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove, .remove = lpc32xx_nand_remove,
.resume = lpc32xx_nand_resume, .resume = pm_ptr(lpc32xx_nand_resume),
.suspend = lpc32xx_nand_suspend, .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = lpc32xx_nand_match, .of_match_table = lpc32xx_nand_match,
......
...@@ -23,9 +23,8 @@ ...@@ -23,9 +23,8 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mtd/lpc32xx_slc.h> #include <linux/mtd/lpc32xx_slc.h>
#define LPC32XX_MODNAME "lpc32xx-nand" #define LPC32XX_MODNAME "lpc32xx-nand"
...@@ -208,7 +207,6 @@ struct lpc32xx_nand_cfg_slc { ...@@ -208,7 +207,6 @@ struct lpc32xx_nand_cfg_slc {
uint32_t rwidth; uint32_t rwidth;
uint32_t rhold; uint32_t rhold;
uint32_t rsetup; uint32_t rsetup;
int wp_gpio;
struct mtd_partition *parts; struct mtd_partition *parts;
unsigned num_parts; unsigned num_parts;
}; };
...@@ -217,6 +215,7 @@ struct lpc32xx_nand_host { ...@@ -217,6 +215,7 @@ struct lpc32xx_nand_host {
struct nand_chip nand_chip; struct nand_chip nand_chip;
struct lpc32xx_slc_platform_data *pdata; struct lpc32xx_slc_platform_data *pdata;
struct clk *clk; struct clk *clk;
struct gpio_desc *wp_gpio;
void __iomem *io_base; void __iomem *io_base;
struct lpc32xx_nand_cfg_slc *ncfg; struct lpc32xx_nand_cfg_slc *ncfg;
...@@ -309,8 +308,8 @@ static int lpc32xx_nand_device_ready(struct nand_chip *chip) ...@@ -309,8 +308,8 @@ static int lpc32xx_nand_device_ready(struct nand_chip *chip)
*/ */
static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
{ {
if (gpio_is_valid(host->ncfg->wp_gpio)) if (host->wp_gpio)
gpio_set_value(host->ncfg->wp_gpio, 0); gpiod_set_value_cansleep(host->wp_gpio, 1);
} }
/* /*
...@@ -318,8 +317,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) ...@@ -318,8 +317,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
*/ */
static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
{ {
if (gpio_is_valid(host->ncfg->wp_gpio)) if (host->wp_gpio)
gpio_set_value(host->ncfg->wp_gpio, 1); gpiod_set_value_cansleep(host->wp_gpio, 0);
} }
/* /*
...@@ -764,8 +763,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) ...@@ -764,8 +763,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
return NULL; return NULL;
} }
ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
return ncfg; return ncfg;
} }
...@@ -852,14 +849,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -852,14 +849,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
"Missing or bad NAND config from device tree\n"); "Missing or bad NAND config from device tree\n");
return -ENOENT; return -ENOENT;
} }
if (host->ncfg->wp_gpio == -EPROBE_DEFER)
return -EPROBE_DEFER; /* Start with WP disabled, if available */
if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev, host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
host->ncfg->wp_gpio, "NAND WP")) { res = PTR_ERR_OR_ZERO(host->wp_gpio);
dev_err(&pdev->dev, "GPIO not available\n"); if (res) {
return -EBUSY; if (res != -EPROBE_DEFER)
dev_err(&pdev->dev, "WP GPIO is not available: %d\n",
res);
return res;
} }
lpc32xx_wp_disable(host);
gpiod_set_consumer_name(host->wp_gpio, "NAND WP");
host->pdata = dev_get_platdata(&pdev->dev); host->pdata = dev_get_platdata(&pdev->dev);
...@@ -968,7 +969,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) ...@@ -968,7 +969,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int lpc32xx_nand_resume(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev)
{ {
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
...@@ -1007,11 +1007,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) ...@@ -1007,11 +1007,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
return 0; return 0;
} }
#else
#define lpc32xx_nand_resume NULL
#define lpc32xx_nand_suspend NULL
#endif
static const struct of_device_id lpc32xx_nand_match[] = { static const struct of_device_id lpc32xx_nand_match[] = {
{ .compatible = "nxp,lpc3220-slc" }, { .compatible = "nxp,lpc3220-slc" },
{ /* sentinel */ }, { /* sentinel */ },
...@@ -1021,8 +1016,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); ...@@ -1021,8 +1016,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = { static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe, .probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove, .remove = lpc32xx_nand_remove,
.resume = lpc32xx_nand_resume, .resume = pm_ptr(lpc32xx_nand_resume),
.suspend = lpc32xx_nand_suspend, .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = { .driver = {
.name = LPC32XX_MODNAME, .name = LPC32XX_MODNAME,
.of_match_table = lpc32xx_nand_match, .of_match_table = lpc32xx_nand_match,
......
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20) #define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21) #define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25) #define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN BIT(27)
#define GENCONF_CLK_GATING_CTRL 0x220 #define GENCONF_CLK_GATING_CTRL 0x220
#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2) #define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
#define GENCONF_ND_CLK_CTRL 0x700 #define GENCONF_ND_CLK_CTRL 0x700
...@@ -2880,7 +2881,8 @@ static int marvell_nfc_init(struct marvell_nfc *nfc) ...@@ -2880,7 +2881,8 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
GENCONF_SOC_DEVICE_MUX_NFC_EN | GENCONF_SOC_DEVICE_MUX_NFC_EN |
GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST | GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST | GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
GENCONF_SOC_DEVICE_MUX_NFC_INT_EN); GENCONF_SOC_DEVICE_MUX_NFC_INT_EN |
GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN);
regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL, regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
GENCONF_CLK_GATING_CTRL_ND_GATE, GENCONF_CLK_GATING_CTRL_ND_GATE,
......
...@@ -663,7 +663,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) ...@@ -663,7 +663,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
} }
prv->irq = irq_of_parse_and_map(dn, 0); prv->irq = irq_of_parse_and_map(dn, 0);
if (prv->irq == NO_IRQ) { if (!prv->irq) {
dev_err(dev, "Error mapping IRQ!\n"); dev_err(dev, "Error mapping IRQ!\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -74,9 +74,75 @@ static int w25m02gv_select_target(struct spinand_device *spinand, ...@@ -74,9 +74,75 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->spimem, &op); return spi_mem_exec_op(spinand->spimem, &op);
} }
static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = 64 + (16 * section);
region->length = 13;
return 0;
}
static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = (16 * section) + 2;
region->length = 14;
return 0;
}
static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
.ecc = w25n02kv_ooblayout_ecc,
.free = w25n02kv_ooblayout_free,
};
static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 mbf = 0;
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
case STATUS_ECC_HAS_BITFLIPS:
/*
* Let's try to retrieve the real maximum number of bitflips
* in order to avoid forcing the wear-leveling layer to move
* data around if it's not necessary.
*/
if (spi_mem_exec_op(spinand->spimem, &op))
return nanddev_get_ecc_conf(nand)->strength;
mbf >>= 4;
if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
return nanddev_get_ecc_conf(nand)->strength;
return mbf;
default:
break;
}
return -EINVAL;
}
static const struct spinand_info winbond_spinand_table[] = { static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO("W25M02GV", SPINAND_INFO("W25M02GV",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
NAND_ECCREQ(1, 512), NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
...@@ -86,7 +152,7 @@ static const struct spinand_info winbond_spinand_table[] = { ...@@ -86,7 +152,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
SPINAND_SELECT_TARGET(w25m02gv_select_target)), SPINAND_SELECT_TARGET(w25m02gv_select_target)),
SPINAND_INFO("W25N01GV", SPINAND_INFO("W25N01GV",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512), NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
...@@ -94,6 +160,15 @@ static const struct spinand_info winbond_spinand_table[] = { ...@@ -94,6 +160,15 @@ static const struct spinand_info winbond_spinand_table[] = {
&update_cache_variants), &update_cache_variants),
0, 0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
SPINAND_INFO("W25N02KV",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
}; };
static int winbond_spinand_init(struct spinand_device *spinand) static int winbond_spinand_init(struct spinand_device *spinand)
......
...@@ -999,7 +999,6 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand, ...@@ -999,7 +999,6 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
/* ECC related functions */ /* ECC related functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment