denali_dt.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * NAND Flash Controller Device Driver for DT
  3. *
  4. * Copyright © 2011, Picochip.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms and conditions of the GNU General Public License,
  8. * version 2, as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. */
  15. #include <linux/clk.h>
  16. #include <linux/err.h>
  17. #include <linux/io.h>
  18. #include <linux/ioport.h>
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. #include <linux/of.h>
  22. #include <linux/of_device.h>
  23. #include <linux/platform_device.h>
  24. #include "denali.h"
  25. struct denali_dt {
  26. struct denali_nand_info denali;
  27. struct clk *clk;
  28. };
  29. struct denali_dt_data {
  30. unsigned int revision;
  31. unsigned int caps;
  32. const struct nand_ecc_caps *ecc_caps;
  33. };
  34. NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
  35. 512, 8, 15);
  36. static const struct denali_dt_data denali_socfpga_data = {
  37. .caps = DENALI_CAP_HW_ECC_FIXUP,
  38. .ecc_caps = &denali_socfpga_ecc_caps,
  39. };
  40. NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
  41. 1024, 8, 16, 24);
  42. static const struct denali_dt_data denali_uniphier_v5a_data = {
  43. .caps = DENALI_CAP_HW_ECC_FIXUP |
  44. DENALI_CAP_DMA_64BIT,
  45. .ecc_caps = &denali_uniphier_v5a_ecc_caps,
  46. };
  47. NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
  48. 1024, 8, 16);
  49. static const struct denali_dt_data denali_uniphier_v5b_data = {
  50. .revision = 0x0501,
  51. .caps = DENALI_CAP_HW_ECC_FIXUP |
  52. DENALI_CAP_DMA_64BIT,
  53. .ecc_caps = &denali_uniphier_v5b_ecc_caps,
  54. };
  55. static const struct of_device_id denali_nand_dt_ids[] = {
  56. {
  57. .compatible = "altr,socfpga-denali-nand",
  58. .data = &denali_socfpga_data,
  59. },
  60. {
  61. .compatible = "socionext,uniphier-denali-nand-v5a",
  62. .data = &denali_uniphier_v5a_data,
  63. },
  64. {
  65. .compatible = "socionext,uniphier-denali-nand-v5b",
  66. .data = &denali_uniphier_v5b_data,
  67. },
  68. { /* sentinel */ }
  69. };
  70. MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
  71. static int denali_dt_probe(struct platform_device *pdev)
  72. {
  73. struct resource *res;
  74. struct denali_dt *dt;
  75. const struct denali_dt_data *data;
  76. struct denali_nand_info *denali;
  77. int ret;
  78. dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
  79. if (!dt)
  80. return -ENOMEM;
  81. denali = &dt->denali;
  82. data = of_device_get_match_data(&pdev->dev);
  83. if (data) {
  84. denali->revision = data->revision;
  85. denali->caps = data->caps;
  86. denali->ecc_caps = data->ecc_caps;
  87. }
  88. denali->dev = &pdev->dev;
  89. denali->irq = platform_get_irq(pdev, 0);
  90. if (denali->irq < 0) {
  91. dev_err(&pdev->dev, "no irq defined\n");
  92. return denali->irq;
  93. }
  94. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
  95. denali->reg = devm_ioremap_resource(&pdev->dev, res);
  96. if (IS_ERR(denali->reg))
  97. return PTR_ERR(denali->reg);
  98. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
  99. denali->host = devm_ioremap_resource(&pdev->dev, res);
  100. if (IS_ERR(denali->host))
  101. return PTR_ERR(denali->host);
  102. dt->clk = devm_clk_get(&pdev->dev, NULL);
  103. if (IS_ERR(dt->clk)) {
  104. dev_err(&pdev->dev, "no clk available\n");
  105. return PTR_ERR(dt->clk);
  106. }
  107. ret = clk_prepare_enable(dt->clk);
  108. if (ret)
  109. return ret;
  110. denali->clk_x_rate = clk_get_rate(dt->clk);
  111. ret = denali_init(denali);
  112. if (ret)
  113. goto out_disable_clk;
  114. platform_set_drvdata(pdev, dt);
  115. return 0;
  116. out_disable_clk:
  117. clk_disable_unprepare(dt->clk);
  118. return ret;
  119. }
  120. static int denali_dt_remove(struct platform_device *pdev)
  121. {
  122. struct denali_dt *dt = platform_get_drvdata(pdev);
  123. denali_remove(&dt->denali);
  124. clk_disable_unprepare(dt->clk);
  125. return 0;
  126. }
  127. static struct platform_driver denali_dt_driver = {
  128. .probe = denali_dt_probe,
  129. .remove = denali_dt_remove,
  130. .driver = {
  131. .name = "denali-nand-dt",
  132. .of_match_table = denali_nand_dt_ids,
  133. },
  134. };
  135. module_platform_driver(denali_dt_driver);
  136. MODULE_LICENSE("GPL");
  137. MODULE_AUTHOR("Jamie Iles");
  138. MODULE_DESCRIPTION("DT driver for Denali NAND controller");