aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/davinci_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/davinci_nand.c')
-rw-r--r--drivers/mtd/nand/davinci_nand.c93
1 files changed, 50 insertions, 43 deletions
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index b77a01efb483..a4989ec6292e 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of.h>
+#include <linux/of_mtd.h>
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
@@ -487,7 +488,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
* ten ECC bytes plus the manufacturer's bad block marker byte, and
* and not overlapping the default BBT markers.
*/
-static struct nand_ecclayout hwecc4_small __initconst = {
+static struct nand_ecclayout hwecc4_small = {
.eccbytes = 10,
.eccpos = { 0, 1, 2, 3, 4,
/* offset 5 holds the badblock marker */
@@ -503,7 +504,7 @@ static struct nand_ecclayout hwecc4_small __initconst = {
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers.
*/
-static struct nand_ecclayout hwecc4_2048 __initconst = {
+static struct nand_ecclayout hwecc4_2048 = {
.eccbytes = 40,
.eccpos = {
/* at the end of spare sector */
@@ -534,17 +535,19 @@ static struct davinci_nand_pdata
struct davinci_nand_pdata *pdata;
const char *mode;
u32 prop;
- int len;
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct davinci_nand_pdata),
GFP_KERNEL);
pdev->dev.platform_data = pdata;
if (!pdata)
- return NULL;
+ return ERR_PTR(-ENOMEM);
if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-chipselect", &prop))
pdev->id = prop;
+ else
+ return ERR_PTR(-EINVAL);
+
if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-mask-ale", &prop))
pdata->mask_ale = prop;
@@ -555,6 +558,8 @@ static struct davinci_nand_pdata
"ti,davinci-mask-chipsel", &prop))
pdata->mask_chipsel = prop;
if (!of_property_read_string(pdev->dev.of_node,
+ "nand-ecc-mode", &mode) ||
+ !of_property_read_string(pdev->dev.of_node,
"ti,davinci-ecc-mode", &mode)) {
if (!strncmp("none", mode, 4))
pdata->ecc_mode = NAND_ECC_NONE;
@@ -566,12 +571,16 @@ static struct davinci_nand_pdata
if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-ecc-bits", &prop))
pdata->ecc_bits = prop;
- if (!of_property_read_u32(pdev->dev.of_node,
+
+ prop = of_get_nand_bus_width(pdev->dev.of_node);
+ if (0 < prop || !of_property_read_u32(pdev->dev.of_node,
"ti,davinci-nand-buswidth", &prop))
if (prop == 16)
pdata->options |= NAND_BUSWIDTH_16;
- if (of_find_property(pdev->dev.of_node,
- "ti,davinci-nand-use-bbt", &len))
+ if (of_property_read_bool(pdev->dev.of_node,
+ "nand-on-flash-bbt") ||
+ of_property_read_bool(pdev->dev.of_node,
+ "ti,davinci-nand-use-bbt"))
pdata->bbt_options = NAND_BBT_USE_FLASH;
}
@@ -585,7 +594,7 @@ static struct davinci_nand_pdata
}
#endif
-static int __init nand_davinci_probe(struct platform_device *pdev)
+static int nand_davinci_probe(struct platform_device *pdev)
{
struct davinci_nand_pdata *pdata;
struct davinci_nand_info *info;
@@ -598,6 +607,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
nand_ecc_modes_t ecc_mode;
pdata = nand_davinci_get_pdata(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
/* insist on board-specific configuration */
if (!pdata)
return -ENODEV;
@@ -607,11 +619,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
return -ENODEV;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
- if (!info) {
- dev_err(&pdev->dev, "unable to allocate memory\n");
- ret = -ENOMEM;
- goto err_nomem;
- }
+ if (!info)
+ return -ENOMEM;
platform_set_drvdata(pdev, info);
@@ -619,19 +628,23 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res1 || !res2) {
dev_err(&pdev->dev, "resource missing\n");
- ret = -EINVAL;
- goto err_nomem;
+ return -EINVAL;
}
vaddr = devm_ioremap_resource(&pdev->dev, res1);
- if (IS_ERR(vaddr)) {
- ret = PTR_ERR(vaddr);
- goto err_ioremap;
- }
- base = devm_ioremap_resource(&pdev->dev, res2);
- if (IS_ERR(base)) {
- ret = PTR_ERR(base);
- goto err_ioremap;
+ if (IS_ERR(vaddr))
+ return PTR_ERR(vaddr);
+
+ /*
+ * This registers range is used to setup NAND settings. In case with
+ * TI AEMIF driver, the same memory address range is requested already
+ * by AEMIF, so we cannot request it twice, just ioremap.
+ * The AEMIF and NAND drivers not use the same registers in this range.
+ */
+ base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
+ return -EADDRNOTAVAIL;
}
info->dev = &pdev->dev;
@@ -699,7 +712,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
spin_unlock_irq(&davinci_nand_lock);
if (ret == -EBUSY)
- goto err_ecc;
+ return ret;
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
info->chip.ecc.correct = nand_davinci_correct_4bit;
@@ -715,8 +728,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->chip.ecc.strength = pdata->ecc_bits;
break;
default:
- ret = -EINVAL;
- goto err_ecc;
+ return -EINVAL;
}
info->chip.ecc.mode = ecc_mode;
@@ -724,7 +736,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk);
dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
- goto err_clk;
+ return ret;
}
ret = clk_prepare_enable(info->clk);
@@ -753,7 +765,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->core_chipsel);
if (ret < 0) {
dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
- goto err_timing;
+ goto err;
}
spin_lock_irq(&davinci_nand_lock);
@@ -769,7 +781,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
- goto err_scan;
+ goto err;
}
/* Update ECC layout if needed ... for 1-bit HW ECC, the default
@@ -783,7 +795,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
if (!chunks || info->mtd.oobsize < 16) {
dev_dbg(&pdev->dev, "too small\n");
ret = -EINVAL;
- goto err_scan;
+ goto err;
}
/* For small page chips, preserve the manufacturer's
@@ -814,7 +826,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "no 4-bit ECC support yet "
"for 4KiB-page NAND\n");
ret = -EIO;
- goto err_scan;
+ goto err;
syndrome_done:
info->chip.ecc.layout = &info->ecclayout;
@@ -822,7 +834,7 @@ syndrome_done:
ret = nand_scan_tail(&info->mtd);
if (ret < 0)
- goto err_scan;
+ goto err;
if (pdata->parts)
ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
@@ -835,7 +847,7 @@ syndrome_done:
NULL, 0);
}
if (ret < 0)
- goto err_scan;
+ goto err;
val = davinci_nand_readl(info, NRCSR_OFFSET);
dev_info(&pdev->dev, "controller rev. %d.%d\n",
@@ -843,8 +855,7 @@ syndrome_done:
return 0;
-err_scan:
-err_timing:
+err:
clk_disable_unprepare(info->clk);
err_clk_enable:
@@ -852,15 +863,10 @@ err_clk_enable:
if (ecc_mode == NAND_ECC_HW_SYNDROME)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
-
-err_ecc:
-err_clk:
-err_ioremap:
-err_nomem:
return ret;
}
-static int __exit nand_davinci_remove(struct platform_device *pdev)
+static int nand_davinci_remove(struct platform_device *pdev)
{
struct davinci_nand_info *info = platform_get_drvdata(pdev);
@@ -877,7 +883,8 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
}
static struct platform_driver nand_davinci_driver = {
- .remove = __exit_p(nand_davinci_remove),
+ .probe = nand_davinci_probe,
+ .remove = nand_davinci_remove,
.driver = {
.name = "davinci_nand",
.owner = THIS_MODULE,
@@ -886,7 +893,7 @@ static struct platform_driver nand_davinci_driver = {
};
MODULE_ALIAS("platform:davinci_nand");
-module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe);
+module_platform_driver(nand_davinci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Texas Instruments");