oxnas_nand.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. * This program is free software; you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License version 2 as published
  4. * by the Free Software Foundation.
  5. *
  6. * based on xway_nand.c
  7. * Copyright © 2012 John Crispin <blogic@openwrt.org>
  8. * and oxnas_nand.c "NAND glue for Oxnas platforms"
  9. * written by Ma Haijun <mahaijuns@gmail.com>
  10. */
  11. #include <linux/mtd/nand.h>
  12. #include <linux/of_gpio.h>
  13. #include <linux/of_platform.h>
  14. #include <linux/clk.h>
  15. #include <linux/reset.h>
  16. /* nand commands */
  17. #define NAND_CMD_ALE BIT(18)
  18. #define NAND_CMD_CLE BIT(19)
  19. #define NAND_CMD_CS 0
  20. #define NAND_CMD_RESET 0xff
  21. #define NAND_CMD (NAND_CMD_CS | NAND_CMD_CLE)
  22. #define NAND_ADDR (NAND_CMD_CS | NAND_CMD_ALE)
  23. #define NAND_DATA (NAND_CMD_CS)
  24. static void oxnas_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  25. {
  26. struct nand_chip *this = mtd->priv;
  27. unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
  28. if (ctrl & NAND_CTRL_CHANGE) {
  29. nandaddr &= ~(NAND_CMD | NAND_ADDR);
  30. if (ctrl & NAND_CLE)
  31. nandaddr |= NAND_CMD;
  32. else if (ctrl & NAND_ALE)
  33. nandaddr |= NAND_ADDR;
  34. this->IO_ADDR_W = (void __iomem *) nandaddr;
  35. }
  36. if (cmd != NAND_CMD_NONE)
  37. writeb(cmd, (void __iomem *) nandaddr);
  38. }
  39. static int oxnas_nand_probe(struct platform_device *pdev)
  40. {
  41. /* enable clock and release static block reset */
  42. struct clk *clk = of_clk_get(pdev->dev.of_node, 0);
  43. if (IS_ERR(clk))
  44. return PTR_ERR(clk);
  45. clk_prepare_enable(clk);
  46. device_reset(&pdev->dev);
  47. return 0;
  48. }
  49. static struct platform_nand_data oxnas_nand_data = {
  50. .chip = {
  51. .nr_chips = 1,
  52. .chip_delay = 30,
  53. },
  54. .ctrl = {
  55. .probe = oxnas_nand_probe,
  56. .cmd_ctrl = oxnas_cmd_ctrl,
  57. }
  58. };
  59. /*
  60. * Try to find the node inside the DT. If it is available attach out
  61. * platform_nand_data
  62. */
  63. static int __init oxnas_register_nand(void)
  64. {
  65. struct device_node *node;
  66. struct platform_device *pdev;
  67. node = of_find_compatible_node(NULL, NULL, "plxtech,nand-nas782x");
  68. if (!node)
  69. return -ENOENT;
  70. pdev = of_find_device_by_node(node);
  71. if (!pdev)
  72. return -EINVAL;
  73. pdev->dev.platform_data = &oxnas_nand_data;
  74. of_node_put(node);
  75. return 0;
  76. }
  77. subsys_initcall(oxnas_register_nand);