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: Stefan Roese <sr@denx.de> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
30053b87d5
commit
eea628199d
|
@ -0,0 +1,33 @@
|
|||
* 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 @@
|
|||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -854,6 +855,38 @@ static bool filter(struct dma_chan *chan, void *slave)
|
|||
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
|
||||
* @pdev: platform device structure
|
||||
|
@ -861,6 +894,8 @@ static bool filter(struct dma_chan *chan, void *slave)
|
|||
static int __init fsmc_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
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 mtd_info *mtd;
|
||||
struct nand_chip *nand;
|
||||
|
@ -870,6 +905,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
|||
u32 pid;
|
||||
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) {
|
||||
dev_err(&pdev->dev, "platform data is NULL\n");
|
||||
return -EINVAL;
|
||||
|
@ -1113,7 +1158,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
|||
* Check for partition info passed
|
||||
*/
|
||||
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);
|
||||
if (ret)
|
||||
goto err_probe;
|
||||
|
@ -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);
|
||||
#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 = {
|
||||
.remove = fsmc_nand_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "fsmc-nand",
|
||||
.of_match_table = of_match_ptr(fsmc_nand_id_table),
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &fsmc_nand_pm_ops,
|
||||
#endif
|
||||
|
|
|
@ -156,8 +156,8 @@ struct fsmc_nand_platform_data {
|
|||
unsigned int bank;
|
||||
|
||||
/* CLE, ALE offsets */
|
||||
unsigned long cle_off;
|
||||
unsigned long ale_off;
|
||||
unsigned int cle_off;
|
||||
unsigned int ale_off;
|
||||
enum access_mode mode;
|
||||
|
||||
void (*select_bank)(uint32_t bank, uint32_t busw);
|
||||
|
|
Loading…
Reference in New Issue