Commit eea62819 authored by Stefan Roese's avatar Stefan Roese Committed by David Woodhouse

mtd: Add device-tree support to fsmc_nand

This patch adds support to configure the FSMC NAND driver (used amongst
others on SPEAr platforms) via device-tree instead of platform_data.
Signed-off-by: default avatarStefan Roese <sr@denx.de>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 30053b87
* FSMC NAND
Required properties:
- compatible : "st,spear600-fsmc-nand"
- reg : Address range of the mtd chip
- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
- st,ale-off : Chip specific offset to ALE
- st,cle-off : Chip specific offset to CLE
Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width
defaults to 1 byte
- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
Example:
fsmc: flash@d1800000 {
compatible = "st,spear600-fsmc-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd1800000 0x1000 /* FSMC Register */
0xd2000000 0x4000>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
bank-width = <1>;
nand-skip-bbtscan;
partition@0 {
...
};
};
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -854,6 +855,38 @@ static bool filter(struct dma_chan *chan, void *slave) ...@@ -854,6 +855,38 @@ static bool filter(struct dma_chan *chan, void *slave)
return true; return true;
} }
#ifdef CONFIG_OF
static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
u32 val;
/* Set default NAND width to 8 bits */
pdata->width = 8;
if (!of_property_read_u32(np, "bank-width", &val)) {
if (val == 2) {
pdata->width = 16;
} else if (val != 1) {
dev_err(&pdev->dev, "invalid bank-width %u\n", val);
return -EINVAL;
}
}
of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
if (of_get_property(np, "nand-skip-bbtscan", NULL))
pdata->options = NAND_SKIP_BBTSCAN;
return 0;
}
#else
static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
return -ENOSYS;
}
#endif
/* /*
* fsmc_nand_probe - Probe function * fsmc_nand_probe - Probe function
* @pdev: platform device structure * @pdev: platform device structure
...@@ -861,6 +894,8 @@ static bool filter(struct dma_chan *chan, void *slave) ...@@ -861,6 +894,8 @@ static bool filter(struct dma_chan *chan, void *slave)
static int __init fsmc_nand_probe(struct platform_device *pdev) static int __init fsmc_nand_probe(struct platform_device *pdev)
{ {
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node __maybe_unused *np = pdev->dev.of_node;
struct mtd_part_parser_data ppdata = {};
struct fsmc_nand_data *host; struct fsmc_nand_data *host;
struct mtd_info *mtd; struct mtd_info *mtd;
struct nand_chip *nand; struct nand_chip *nand;
...@@ -870,6 +905,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -870,6 +905,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
u32 pid; u32 pid;
int i; int i;
if (np) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
pdev->dev.platform_data = pdata;
ret = fsmc_nand_probe_config_dt(pdev, np);
if (ret) {
dev_err(&pdev->dev, "no platform data\n");
return -ENODEV;
}
}
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "platform data is NULL\n"); dev_err(&pdev->dev, "platform data is NULL\n");
return -EINVAL; return -EINVAL;
...@@ -1113,7 +1158,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -1113,7 +1158,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* Check for partition info passed * Check for partition info passed
*/ */
host->mtd.name = "nand"; host->mtd.name = "nand";
ret = mtd_device_parse_register(&host->mtd, NULL, NULL, ppdata.of_node = np;
ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata,
host->partitions, host->nr_partitions); host->partitions, host->nr_partitions);
if (ret) if (ret)
goto err_probe; goto err_probe;
...@@ -1183,11 +1229,20 @@ static int fsmc_nand_resume(struct device *dev) ...@@ -1183,11 +1229,20 @@ static int fsmc_nand_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
#endif #endif
#ifdef CONFIG_OF
static const struct of_device_id fsmc_nand_id_table[] = {
{ .compatible = "st,spear600-fsmc-nand" },
{}
};
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
#endif
static struct platform_driver fsmc_nand_driver = { static struct platform_driver fsmc_nand_driver = {
.remove = fsmc_nand_remove, .remove = fsmc_nand_remove,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "fsmc-nand", .name = "fsmc-nand",
.of_match_table = of_match_ptr(fsmc_nand_id_table),
#ifdef CONFIG_PM #ifdef CONFIG_PM
.pm = &fsmc_nand_pm_ops, .pm = &fsmc_nand_pm_ops,
#endif #endif
......
...@@ -156,8 +156,8 @@ struct fsmc_nand_platform_data { ...@@ -156,8 +156,8 @@ struct fsmc_nand_platform_data {
unsigned int bank; unsigned int bank;
/* CLE, ALE offsets */ /* CLE, ALE offsets */
unsigned long cle_off; unsigned int cle_off;
unsigned long ale_off; unsigned int ale_off;
enum access_mode mode; enum access_mode mode;
void (*select_bank)(uint32_t bank, uint32_t busw); void (*select_bank)(uint32_t bank, uint32_t busw);
......
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