Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
* 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 {
			...
		};
	};
+56 −1
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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);