Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Stefan Roese and committed by
David Woodhouse
eea62819 30053b87

+91 -3
+33
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
··· 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 + };
+56 -1
drivers/mtd/nand/fsmc_nand.c
··· 31 31 #include <linux/mtd/nand.h> 32 32 #include <linux/mtd/nand_ecc.h> 33 33 #include <linux/platform_device.h> 34 + #include <linux/of.h> 34 35 #include <linux/mtd/partitions.h> 35 36 #include <linux/io.h> 36 37 #include <linux/slab.h> ··· 855 854 return true; 856 855 } 857 856 857 + #ifdef CONFIG_OF 858 + static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, 859 + struct device_node *np) 860 + { 861 + struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); 862 + u32 val; 863 + 864 + /* Set default NAND width to 8 bits */ 865 + pdata->width = 8; 866 + if (!of_property_read_u32(np, "bank-width", &val)) { 867 + if (val == 2) { 868 + pdata->width = 16; 869 + } else if (val != 1) { 870 + dev_err(&pdev->dev, "invalid bank-width %u\n", val); 871 + return -EINVAL; 872 + } 873 + } 874 + of_property_read_u32(np, "st,ale-off", &pdata->ale_off); 875 + of_property_read_u32(np, "st,cle-off", &pdata->cle_off); 876 + if (of_get_property(np, "nand-skip-bbtscan", NULL)) 877 + pdata->options = NAND_SKIP_BBTSCAN; 878 + 879 + return 0; 880 + } 881 + #else 882 + static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, 883 + struct device_node *np) 884 + { 885 + return -ENOSYS; 886 + } 887 + #endif 888 + 858 889 /* 859 890 * fsmc_nand_probe - Probe function 860 891 * @pdev: platform device structure ··· 894 861 static int __init fsmc_nand_probe(struct platform_device *pdev) 895 862 { 896 863 struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); 864 + struct device_node __maybe_unused *np = pdev->dev.of_node; 865 + struct mtd_part_parser_data ppdata = {}; 897 866 struct fsmc_nand_data *host; 898 867 struct mtd_info *mtd; 899 868 struct nand_chip *nand; ··· 904 869 int ret = 0; 905 870 u32 pid; 906 871 int i; 872 + 873 + if (np) { 874 + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 875 + pdev->dev.platform_data = pdata; 876 + ret = fsmc_nand_probe_config_dt(pdev, np); 877 + if (ret) { 878 + dev_err(&pdev->dev, "no platform data\n"); 879 + return -ENODEV; 880 + } 881 + } 907 882 908 883 if (!pdata) { 909 884 dev_err(&pdev->dev, "platform data is NULL\n"); ··· 1158 1113 * Check for partition info passed 1159 1114 */ 1160 1115 host->mtd.name = "nand"; 1161 - ret = mtd_device_parse_register(&host->mtd, NULL, NULL, 1116 + ppdata.of_node = np; 1117 + ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata, 1162 1118 host->partitions, host->nr_partitions); 1163 1119 if (ret) 1164 1120 goto err_probe; ··· 1229 1183 static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); 1230 1184 #endif 1231 1185 1186 + #ifdef CONFIG_OF 1187 + static const struct of_device_id fsmc_nand_id_table[] = { 1188 + { .compatible = "st,spear600-fsmc-nand" }, 1189 + {} 1190 + }; 1191 + MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); 1192 + #endif 1193 + 1232 1194 static struct platform_driver fsmc_nand_driver = { 1233 1195 .remove = fsmc_nand_remove, 1234 1196 .driver = { 1235 1197 .owner = THIS_MODULE, 1236 1198 .name = "fsmc-nand", 1199 + .of_match_table = of_match_ptr(fsmc_nand_id_table), 1237 1200 #ifdef CONFIG_PM 1238 1201 .pm = &fsmc_nand_pm_ops, 1239 1202 #endif
+2 -2
include/linux/mtd/fsmc.h
··· 156 156 unsigned int bank; 157 157 158 158 /* CLE, ALE offsets */ 159 - unsigned long cle_off; 160 - unsigned long ale_off; 159 + unsigned int cle_off; 160 + unsigned int ale_off; 161 161 enum access_mode mode; 162 162 163 163 void (*select_bank)(uint32_t bank, uint32_t busw);