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

mtd: sh_flctl: Add device tree support

The flctl can now be probed via device tree setup in addition to the
existing platform data way.

SoC specific setup data is set in the .data member of the OF match, so
kept within the driver itself, while board/user specific setup - like
partitioning - is taken from the device tree.

Actual configuration is added for the SoC sh7372.

Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

authored by

Bastian Hecht and committed by
Artem Bityutskiy
7c8f680e 83738d87

+136 -7
+49
Documentation/devicetree/bindings/mtd/flctl-nand.txt
··· 1 + FLCTL NAND controller 2 + 3 + Required properties: 4 + - compatible : "renesas,shmobile-flctl-sh7372" 5 + - reg : Address range of the FLCTL 6 + - interrupts : flste IRQ number 7 + - nand-bus-width : bus width to NAND chip 8 + 9 + Optional properties: 10 + - dmas: DMA specifier(s) 11 + - dma-names: name for each DMA specifier. Valid names are 12 + "data_tx", "data_rx", "ecc_tx", "ecc_rx" 13 + 14 + The DMA fields are not used yet in the driver but are listed here for 15 + completing the bindings. 16 + 17 + The device tree may optionally contain sub-nodes describing partitions of the 18 + address space. See partition.txt for more detail. 19 + 20 + Example: 21 + 22 + flctl@e6a30000 { 23 + #address-cells = <1>; 24 + #size-cells = <1>; 25 + compatible = "renesas,shmobile-flctl-sh7372"; 26 + reg = <0xe6a30000 0x100>; 27 + interrupts = <0x0d80>; 28 + 29 + nand-bus-width = <16>; 30 + 31 + dmas = <&dmac 1 /* data_tx */ 32 + &dmac 2;> /* data_rx */ 33 + dma-names = "data_tx", "data_rx"; 34 + 35 + system@0 { 36 + label = "system"; 37 + reg = <0x0 0x8000000>; 38 + }; 39 + 40 + userdata@8000000 { 41 + label = "userdata"; 42 + reg = <0x8000000 0x10000000>; 43 + }; 44 + 45 + cache@18000000 { 46 + label = "cache"; 47 + reg = <0x18000000 0x8000000>; 48 + }; 49 + };
+87 -7
drivers/mtd/nand/sh_flctl.c
··· 29 29 #include <linux/dma-mapping.h> 30 30 #include <linux/interrupt.h> 31 31 #include <linux/io.h> 32 + #include <linux/of.h> 33 + #include <linux/of_device.h> 34 + #include <linux/of_mtd.h> 32 35 #include <linux/platform_device.h> 33 36 #include <linux/pm_runtime.h> 34 37 #include <linux/sh_dma.h> ··· 1019 1016 return IRQ_HANDLED; 1020 1017 } 1021 1018 1019 + #ifdef CONFIG_OF 1020 + struct flctl_soc_config { 1021 + unsigned long flcmncr_val; 1022 + unsigned has_hwecc:1; 1023 + unsigned use_holden:1; 1024 + }; 1025 + 1026 + static struct flctl_soc_config flctl_sh7372_config = { 1027 + .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL, 1028 + .has_hwecc = 1, 1029 + .use_holden = 1, 1030 + }; 1031 + 1032 + static const struct of_device_id of_flctl_match[] = { 1033 + { .compatible = "renesas,shmobile-flctl-sh7372", 1034 + .data = &flctl_sh7372_config }, 1035 + {}, 1036 + }; 1037 + MODULE_DEVICE_TABLE(of, of_flctl_match); 1038 + 1039 + static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) 1040 + { 1041 + const struct of_device_id *match; 1042 + struct flctl_soc_config *config; 1043 + struct sh_flctl_platform_data *pdata; 1044 + struct device_node *dn = dev->of_node; 1045 + int ret; 1046 + 1047 + match = of_match_device(of_flctl_match, dev); 1048 + if (match) 1049 + config = (struct flctl_soc_config *)match->data; 1050 + else { 1051 + dev_err(dev, "%s: no OF configuration attached\n", __func__); 1052 + return NULL; 1053 + } 1054 + 1055 + pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data), 1056 + GFP_KERNEL); 1057 + if (!pdata) { 1058 + dev_err(dev, "%s: failed to allocate config data\n", __func__); 1059 + return NULL; 1060 + } 1061 + 1062 + /* set SoC specific options */ 1063 + pdata->flcmncr_val = config->flcmncr_val; 1064 + pdata->has_hwecc = config->has_hwecc; 1065 + pdata->use_holden = config->use_holden; 1066 + 1067 + /* parse user defined options */ 1068 + ret = of_get_nand_bus_width(dn); 1069 + if (ret == 16) 1070 + pdata->flcmncr_val |= SEL_16BIT; 1071 + else if (ret != 8) { 1072 + dev_err(dev, "%s: invalid bus width\n", __func__); 1073 + return NULL; 1074 + } 1075 + 1076 + return pdata; 1077 + } 1078 + #else /* CONFIG_OF */ 1079 + #define of_flctl_match NULL 1080 + static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) 1081 + { 1082 + return NULL; 1083 + } 1084 + #endif /* CONFIG_OF */ 1085 + 1022 1086 static int __devinit flctl_probe(struct platform_device *pdev) 1023 1087 { 1024 1088 struct resource *res; ··· 1095 1025 struct sh_flctl_platform_data *pdata; 1096 1026 int ret = -ENXIO; 1097 1027 int irq; 1098 - 1099 - pdata = pdev->dev.platform_data; 1100 - if (pdata == NULL) { 1101 - dev_err(&pdev->dev, "no platform data defined\n"); 1102 - return -EINVAL; 1103 - } 1028 + struct mtd_part_parser_data ppdata = {}; 1104 1029 1105 1030 flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); 1106 1031 if (!flctl) { ··· 1125 1060 if (ret) { 1126 1061 dev_err(&pdev->dev, "request interrupt failed.\n"); 1127 1062 goto err_flste; 1063 + } 1064 + 1065 + if (pdev->dev.of_node) 1066 + pdata = flctl_parse_dt(&pdev->dev); 1067 + else 1068 + pdata = pdev->dev.platform_data; 1069 + 1070 + if (!pdata) { 1071 + dev_err(&pdev->dev, "no setup data defined\n"); 1072 + ret = -EINVAL; 1073 + goto err_pdata; 1128 1074 } 1129 1075 1130 1076 platform_set_drvdata(pdev, flctl); ··· 1180 1104 if (ret) 1181 1105 goto err_chip; 1182 1106 1183 - mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); 1107 + ppdata.of_node = pdev->dev.of_node; 1108 + ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts, 1109 + pdata->nr_parts); 1184 1110 1185 1111 return 0; 1186 1112 1187 1113 err_chip: 1188 1114 flctl_release_dma(flctl); 1189 1115 pm_runtime_disable(&pdev->dev); 1116 + err_pdata: 1190 1117 free_irq(irq, flctl); 1191 1118 err_flste: 1192 1119 iounmap(flctl->reg); ··· 1217 1138 .driver = { 1218 1139 .name = "sh_flctl", 1219 1140 .owner = THIS_MODULE, 1141 + .of_match_table = of_flctl_match, 1220 1142 }, 1221 1143 }; 1222 1144