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

mtd: gpio-nand: add device tree bindings

Add device tree bindings so that the gpio-nand driver may be
instantiated from the device tree. This also allows the partitions
to be specified in the device tree.

v7: - restore runtime device tree/non device tree detection
v6: - convert to mtd_device_parse_register()
v5: - fold dt config helpers into a single gpio_nand_of_get_config()
v4: - get io sync address from gpio-control-nand,io-sync-reg
property rather than a resource
- clarified a few details in the binding
v3: - remove redundant cast and a couple of whitespace/naming
changes
v2: - add CONFIG_OF guards for non-dt platforms
- compatible becomes gpio-control-nand
- clarify some binding details

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Jamie Iles and committed by
David Woodhouse
775c3220 f98872fc

+152 -7
+44
Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
··· 1 + GPIO assisted NAND flash 2 + 3 + The GPIO assisted NAND flash uses a memory mapped interface to 4 + read/write the NAND commands and data and GPIO pins for the control 5 + signals. 6 + 7 + Required properties: 8 + - compatible : "gpio-control-nand" 9 + - reg : should specify localbus chip select and size used for the chip. The 10 + resource describes the data bus connected to the NAND flash and all accesses 11 + are made in native endianness. 12 + - #address-cells, #size-cells : Must be present if the device has sub-nodes 13 + representing partitions. 14 + - gpios : specifies the gpio pins to control the NAND device. nwp is an 15 + optional gpio and may be set to 0 if not present. 16 + 17 + Optional properties: 18 + - bank-width : Width (in bytes) of the device. If not present, the width 19 + defaults to 1 byte. 20 + - chip-delay : chip dependent delay for transferring data from array to 21 + read registers (tR). If not present then a default of 20us is used. 22 + - gpio-control-nand,io-sync-reg : A 64-bit physical address for a read 23 + location used to guard against bus reordering with regards to accesses to 24 + the GPIO's and the NAND flash data bus. If present, then after changing 25 + GPIO state and before and after command byte writes, this register will be 26 + read to ensure that the GPIO accesses have completed. 27 + 28 + Examples: 29 + 30 + gpio-nand@1,0 { 31 + compatible = "gpio-control-nand"; 32 + reg = <1 0x0000 0x2>; 33 + #address-cells = <1>; 34 + #size-cells = <1>; 35 + gpios = <&banka 1 0 /* rdy */ 36 + &banka 2 0 /* nce */ 37 + &banka 3 0 /* ale */ 38 + &banka 4 0 /* cle */ 39 + 0 /* nwp */>; 40 + 41 + partition@0 { 42 + ... 43 + }; 44 + };
+108 -7
drivers/mtd/nand/gpio.c
··· 27 27 #include <linux/mtd/nand.h> 28 28 #include <linux/mtd/partitions.h> 29 29 #include <linux/mtd/nand-gpio.h> 30 + #include <linux/of.h> 31 + #include <linux/of_address.h> 32 + #include <linux/of_gpio.h> 30 33 31 34 struct gpiomtd { 32 35 void __iomem *io_sync; ··· 174 171 return gpio_get_value(gpiomtd->plat.gpio_rdy); 175 172 } 176 173 174 + #ifdef CONFIG_OF 175 + static const struct of_device_id gpio_nand_id_table[] = { 176 + { .compatible = "gpio-control-nand" }, 177 + {} 178 + }; 179 + MODULE_DEVICE_TABLE(of, gpio_nand_id_table); 180 + 181 + static int gpio_nand_get_config_of(const struct device *dev, 182 + struct gpio_nand_platdata *plat) 183 + { 184 + u32 val; 185 + 186 + if (!of_property_read_u32(dev->of_node, "bank-width", &val)) { 187 + if (val == 2) { 188 + plat->options |= NAND_BUSWIDTH_16; 189 + } else if (val != 1) { 190 + dev_err(dev, "invalid bank-width %u\n", val); 191 + return -EINVAL; 192 + } 193 + } 194 + 195 + plat->gpio_rdy = of_get_gpio(dev->of_node, 0); 196 + plat->gpio_nce = of_get_gpio(dev->of_node, 1); 197 + plat->gpio_ale = of_get_gpio(dev->of_node, 2); 198 + plat->gpio_cle = of_get_gpio(dev->of_node, 3); 199 + plat->gpio_nwp = of_get_gpio(dev->of_node, 4); 200 + 201 + if (!of_property_read_u32(dev->of_node, "chip-delay", &val)) 202 + plat->chip_delay = val; 203 + 204 + return 0; 205 + } 206 + 207 + static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) 208 + { 209 + struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); 210 + u64 addr; 211 + 212 + if (!r || of_property_read_u64(pdev->dev.of_node, 213 + "gpio-control-nand,io-sync-reg", &addr)) 214 + return NULL; 215 + 216 + r->start = addr; 217 + r->end = r->start + 0x3; 218 + r->flags = IORESOURCE_MEM; 219 + 220 + return r; 221 + } 222 + #else /* CONFIG_OF */ 223 + #define gpio_nand_id_table NULL 224 + static inline int gpio_nand_get_config_of(const struct device *dev, 225 + struct gpio_nand_platdata *plat) 226 + { 227 + return -ENOSYS; 228 + } 229 + 230 + static inline struct resource * 231 + gpio_nand_get_io_sync_of(struct platform_device *pdev) 232 + { 233 + return NULL; 234 + } 235 + #endif /* CONFIG_OF */ 236 + 237 + static inline int gpio_nand_get_config(const struct device *dev, 238 + struct gpio_nand_platdata *plat) 239 + { 240 + int ret = gpio_nand_get_config_of(dev, plat); 241 + 242 + if (!ret) 243 + return ret; 244 + 245 + if (dev->platform_data) { 246 + memcpy(plat, dev->platform_data, sizeof(*plat)); 247 + return 0; 248 + } 249 + 250 + return -EINVAL; 251 + } 252 + 253 + static inline struct resource * 254 + gpio_nand_get_io_sync(struct platform_device *pdev) 255 + { 256 + struct resource *r = gpio_nand_get_io_sync_of(pdev); 257 + 258 + if (r) 259 + return r; 260 + 261 + return platform_get_resource(pdev, IORESOURCE_MEM, 1); 262 + } 263 + 177 264 static int __devexit gpio_nand_remove(struct platform_device *dev) 178 265 { 179 266 struct gpiomtd *gpiomtd = platform_get_drvdata(dev); ··· 271 178 272 179 nand_release(&gpiomtd->mtd_info); 273 180 274 - res = platform_get_resource(dev, IORESOURCE_MEM, 1); 181 + res = gpio_nand_get_io_sync(dev); 275 182 iounmap(gpiomtd->io_sync); 276 183 if (res) 277 184 release_mem_region(res->start, resource_size(res)); ··· 319 226 struct gpiomtd *gpiomtd; 320 227 struct nand_chip *this; 321 228 struct resource *res0, *res1; 322 - int ret; 229 + struct mtd_part_parser_data ppdata = {}; 230 + int ret = 0; 323 231 324 - if (!dev->dev.platform_data) 232 + if (!dev->dev.of_node && !dev->dev.platform_data) 325 233 return -EINVAL; 326 234 327 235 res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); ··· 342 248 goto err_map; 343 249 } 344 250 345 - res1 = platform_get_resource(dev, IORESOURCE_MEM, 1); 251 + res1 = gpio_nand_get_io_sync(dev); 346 252 if (res1) { 347 253 gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); 348 254 if (!gpiomtd->io_sync) { ··· 351 257 } 352 258 } 353 259 354 - memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); 260 + ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat); 261 + if (ret) 262 + goto err_nce; 355 263 356 264 ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); 357 265 if (ret) ··· 412 316 gpiomtd->plat.adjust_parts(&gpiomtd->plat, 413 317 gpiomtd->mtd_info.size); 414 318 415 - mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts, 416 - gpiomtd->plat.num_parts); 319 + ppdata.of_node = dev->dev.of_node; 320 + ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata, 321 + gpiomtd->plat.parts, 322 + gpiomtd->plat.num_parts); 323 + if (ret) 324 + goto err_wp; 417 325 platform_set_drvdata(dev, gpiomtd); 418 326 419 327 return 0; ··· 452 352 .remove = gpio_nand_remove, 453 353 .driver = { 454 354 .name = "gpio-nand", 355 + .of_match_table = gpio_nand_id_table, 455 356 }, 456 357 }; 457 358