aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mtd/fsmc-nand.txt33
-rw-r--r--drivers/mtd/nand/fsmc_nand.c57
-rw-r--r--include/linux/mtd/fsmc.h4
3 files changed, 91 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
new file mode 100644
index 000000000000..e2c663b354d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
@@ -0,0 +1,33 @@
1* FSMC NAND
2
3Required properties:
4- compatible : "st,spear600-fsmc-nand"
5- reg : Address range of the mtd chip
6- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
7- st,ale-off : Chip specific offset to ALE
8- st,cle-off : Chip specific offset to CLE
9
10Optional properties:
11- bank-width : Width (in bytes) of the device. If not present, the width
12 defaults to 1 byte
13- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
14
15Example:
16
17 fsmc: flash@d1800000 {
18 compatible = "st,spear600-fsmc-nand";
19 #address-cells = <1>;
20 #size-cells = <1>;
21 reg = <0xd1800000 0x1000 /* FSMC Register */
22 0xd2000000 0x4000>; /* NAND Base */
23 reg-names = "fsmc_regs", "nand_data";
24 st,ale-off = <0x20000>;
25 st,cle-off = <0x10000>;
26
27 bank-width = <1>;
28 nand-skip-bbtscan;
29
30 partition@0 {
31 ...
32 };
33 };
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 049018213090..1b8330e1155a 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -31,6 +31,7 @@
31#include <linux/mtd/nand.h> 31#include <linux/mtd/nand.h>
32#include <linux/mtd/nand_ecc.h> 32#include <linux/mtd/nand_ecc.h>
33#include <linux/platform_device.h> 33#include <linux/platform_device.h>
34#include <linux/of.h>
34#include <linux/mtd/partitions.h> 35#include <linux/mtd/partitions.h>
35#include <linux/io.h> 36#include <linux/io.h>
36#include <linux/slab.h> 37#include <linux/slab.h>
@@ -854,6 +855,38 @@ static bool filter(struct dma_chan *chan, void *slave)
854 return true; 855 return true;
855} 856}
856 857
858#ifdef CONFIG_OF
859static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
860 struct device_node *np)
861{
862 struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
863 u32 val;
864
865 /* Set default NAND width to 8 bits */
866 pdata->width = 8;
867 if (!of_property_read_u32(np, "bank-width", &val)) {
868 if (val == 2) {
869 pdata->width = 16;
870 } else if (val != 1) {
871 dev_err(&pdev->dev, "invalid bank-width %u\n", val);
872 return -EINVAL;
873 }
874 }
875 of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
876 of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
877 if (of_get_property(np, "nand-skip-bbtscan", NULL))
878 pdata->options = NAND_SKIP_BBTSCAN;
879
880 return 0;
881}
882#else
883static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
884 struct device_node *np)
885{
886 return -ENOSYS;
887}
888#endif
889
857/* 890/*
858 * fsmc_nand_probe - Probe function 891 * fsmc_nand_probe - Probe function
859 * @pdev: platform device structure 892 * @pdev: platform device structure
@@ -861,6 +894,8 @@ static bool filter(struct dma_chan *chan, void *slave)
861static int __init fsmc_nand_probe(struct platform_device *pdev) 894static int __init fsmc_nand_probe(struct platform_device *pdev)
862{ 895{
863 struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); 896 struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
897 struct device_node __maybe_unused *np = pdev->dev.of_node;
898 struct mtd_part_parser_data ppdata = {};
864 struct fsmc_nand_data *host; 899 struct fsmc_nand_data *host;
865 struct mtd_info *mtd; 900 struct mtd_info *mtd;
866 struct nand_chip *nand; 901 struct nand_chip *nand;
@@ -870,6 +905,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
870 u32 pid; 905 u32 pid;
871 int i; 906 int i;
872 907
908 if (np) {
909 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
910 pdev->dev.platform_data = pdata;
911 ret = fsmc_nand_probe_config_dt(pdev, np);
912 if (ret) {
913 dev_err(&pdev->dev, "no platform data\n");
914 return -ENODEV;
915 }
916 }
917
873 if (!pdata) { 918 if (!pdata) {
874 dev_err(&pdev->dev, "platform data is NULL\n"); 919 dev_err(&pdev->dev, "platform data is NULL\n");
875 return -EINVAL; 920 return -EINVAL;
@@ -1113,7 +1158,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
1113 * Check for partition info passed 1158 * Check for partition info passed
1114 */ 1159 */
1115 host->mtd.name = "nand"; 1160 host->mtd.name = "nand";
1116 ret = mtd_device_parse_register(&host->mtd, NULL, NULL, 1161 ppdata.of_node = np;
1162 ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata,
1117 host->partitions, host->nr_partitions); 1163 host->partitions, host->nr_partitions);
1118 if (ret) 1164 if (ret)
1119 goto err_probe; 1165 goto err_probe;
@@ -1183,11 +1229,20 @@ static int fsmc_nand_resume(struct device *dev)
1183static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); 1229static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
1184#endif 1230#endif
1185 1231
1232#ifdef CONFIG_OF
1233static const struct of_device_id fsmc_nand_id_table[] = {
1234 { .compatible = "st,spear600-fsmc-nand" },
1235 {}
1236};
1237MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
1238#endif
1239
1186static struct platform_driver fsmc_nand_driver = { 1240static struct platform_driver fsmc_nand_driver = {
1187 .remove = fsmc_nand_remove, 1241 .remove = fsmc_nand_remove,
1188 .driver = { 1242 .driver = {
1189 .owner = THIS_MODULE, 1243 .owner = THIS_MODULE,
1190 .name = "fsmc-nand", 1244 .name = "fsmc-nand",
1245 .of_match_table = of_match_ptr(fsmc_nand_id_table),
1191#ifdef CONFIG_PM 1246#ifdef CONFIG_PM
1192 .pm = &fsmc_nand_pm_ops, 1247 .pm = &fsmc_nand_pm_ops,
1193#endif 1248#endif
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
index 823359c0f5a1..b20029221fb1 100644
--- a/include/linux/mtd/fsmc.h
+++ b/include/linux/mtd/fsmc.h
@@ -156,8 +156,8 @@ struct fsmc_nand_platform_data {
156 unsigned int bank; 156 unsigned int bank;
157 157
158 /* CLE, ALE offsets */ 158 /* CLE, ALE offsets */
159 unsigned long cle_off; 159 unsigned int cle_off;
160 unsigned long ale_off; 160 unsigned int ale_off;
161 enum access_mode mode; 161 enum access_mode mode;
162 162
163 void (*select_bank)(uint32_t bank, uint32_t busw); 163 void (*select_bank)(uint32_t bank, uint32_t busw);