diff options
| -rw-r--r-- | Documentation/devicetree/bindings/mtd/fsmc-nand.txt | 33 | ||||
| -rw-r--r-- | drivers/mtd/nand/fsmc_nand.c | 57 | ||||
| -rw-r--r-- | include/linux/mtd/fsmc.h | 4 |
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 | |||
| 3 | Required 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 | |||
| 10 | Optional 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 | |||
| 15 | Example: | ||
| 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 | ||
| 859 | static 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 | ||
| 883 | static 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) | |||
| 861 | static int __init fsmc_nand_probe(struct platform_device *pdev) | 894 | static 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) | |||
| 1183 | static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); | 1229 | static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); |
| 1184 | #endif | 1230 | #endif |
| 1185 | 1231 | ||
| 1232 | #ifdef CONFIG_OF | ||
| 1233 | static const struct of_device_id fsmc_nand_id_table[] = { | ||
| 1234 | { .compatible = "st,spear600-fsmc-nand" }, | ||
| 1235 | {} | ||
| 1236 | }; | ||
| 1237 | MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); | ||
| 1238 | #endif | ||
| 1239 | |||
| 1186 | static struct platform_driver fsmc_nand_driver = { | 1240 | static 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); |
