denali_dt.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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; /* core clock */
  28. struct clk *clk_x; /* bus interface clock */
  29. struct clk *clk_ecc; /* ECC circuit clock */
  30. };
  31. struct denali_dt_data {
  32. unsigned int revision;
  33. unsigned int caps;
  34. const struct nand_ecc_caps *ecc_caps;
  35. };
  36. NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
  37. 512, 8, 15);
  38. static const struct denali_dt_data denali_socfpga_data = {
  39. .caps = DENALI_CAP_HW_ECC_FIXUP,
  40. .ecc_caps = &denali_socfpga_ecc_caps,
  41. };
  42. NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
  43. 1024, 8, 16, 24);
  44. static const struct denali_dt_data denali_uniphier_v5a_data = {
  45. .caps = DENALI_CAP_HW_ECC_FIXUP |
  46. DENALI_CAP_DMA_64BIT,
  47. .ecc_caps = &denali_uniphier_v5a_ecc_caps,
  48. };
  49. NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
  50. 1024, 8, 16);
  51. static const struct denali_dt_data denali_uniphier_v5b_data = {
  52. .revision = 0x0501,
  53. .caps = DENALI_CAP_HW_ECC_FIXUP |
  54. DENALI_CAP_DMA_64BIT,
  55. .ecc_caps = &denali_uniphier_v5b_ecc_caps,
  56. };
  57. static const struct of_device_id denali_nand_dt_ids[] = {
  58. {
  59. .compatible = "altr,socfpga-denali-nand",
  60. .data = &denali_socfpga_data,
  61. },
  62. {
  63. .compatible = "socionext,uniphier-denali-nand-v5a",
  64. .data = &denali_uniphier_v5a_data,
  65. },
  66. {
  67. .compatible = "socionext,uniphier-denali-nand-v5b",
  68. .data = &denali_uniphier_v5b_data,
  69. },
  70. { /* sentinel */ }
  71. };
  72. MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
  73. static int denali_dt_probe(struct platform_device *pdev)
  74. {
  75. struct device *dev = &pdev->dev;
  76. struct resource *res;
  77. struct denali_dt *dt;
  78. const struct denali_dt_data *data;
  79. struct denali_nand_info *denali;
  80. int ret;
  81. dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
  82. if (!dt)
  83. return -ENOMEM;
  84. denali = &dt->denali;
  85. data = of_device_get_match_data(dev);
  86. if (data) {
  87. denali->revision = data->revision;
  88. denali->caps = data->caps;
  89. denali->ecc_caps = data->ecc_caps;
  90. }
  91. denali->dev = dev;
  92. denali->irq = platform_get_irq(pdev, 0);
  93. if (denali->irq < 0) {
  94. dev_err(dev, "no irq defined\n");
  95. return denali->irq;
  96. }
  97. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
  98. denali->reg = devm_ioremap_resource(dev, res);
  99. if (IS_ERR(denali->reg))
  100. return PTR_ERR(denali->reg);
  101. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
  102. denali->host = devm_ioremap_resource(dev, res);
  103. if (IS_ERR(denali->host))
  104. return PTR_ERR(denali->host);
  105. /*
  106. * A single anonymous clock is supported for the backward compatibility.
  107. * New platforms should support all the named clocks.
  108. */
  109. dt->clk = devm_clk_get(dev, "nand");
  110. if (IS_ERR(dt->clk))
  111. dt->clk = devm_clk_get(dev, NULL);
  112. if (IS_ERR(dt->clk)) {
  113. dev_err(dev, "no clk available\n");
  114. return PTR_ERR(dt->clk);
  115. }
  116. dt->clk_x = devm_clk_get(dev, "nand_x");
  117. if (IS_ERR(dt->clk_x))
  118. dt->clk_x = NULL;
  119. dt->clk_ecc = devm_clk_get(dev, "ecc");
  120. if (IS_ERR(dt->clk_ecc))
  121. dt->clk_ecc = NULL;
  122. ret = clk_prepare_enable(dt->clk);
  123. if (ret)
  124. return ret;
  125. ret = clk_prepare_enable(dt->clk_x);
  126. if (ret)
  127. goto out_disable_clk;
  128. ret = clk_prepare_enable(dt->clk_ecc);
  129. if (ret)
  130. goto out_disable_clk_x;
  131. if (dt->clk_x) {
  132. denali->clk_rate = clk_get_rate(dt->clk);
  133. denali->clk_x_rate = clk_get_rate(dt->clk_x);
  134. } else {
  135. /*
  136. * Hardcode the clock rates for the backward compatibility.
  137. * This works for both SOCFPGA and UniPhier.
  138. */
  139. dev_notice(dev,
  140. "necessary clock is missing. default clock rates are used.\n");
  141. denali->clk_rate = 50000000;
  142. denali->clk_x_rate = 200000000;
  143. }
  144. ret = denali_init(denali);
  145. if (ret)
  146. goto out_disable_clk_ecc;
  147. platform_set_drvdata(pdev, dt);
  148. return 0;
  149. out_disable_clk_ecc:
  150. clk_disable_unprepare(dt->clk_ecc);
  151. out_disable_clk_x:
  152. clk_disable_unprepare(dt->clk_x);
  153. out_disable_clk:
  154. clk_disable_unprepare(dt->clk);
  155. return ret;
  156. }
  157. static int denali_dt_remove(struct platform_device *pdev)
  158. {
  159. struct denali_dt *dt = platform_get_drvdata(pdev);
  160. denali_remove(&dt->denali);
  161. clk_disable_unprepare(dt->clk_ecc);
  162. clk_disable_unprepare(dt->clk_x);
  163. clk_disable_unprepare(dt->clk);
  164. return 0;
  165. }
  166. static struct platform_driver denali_dt_driver = {
  167. .probe = denali_dt_probe,
  168. .remove = denali_dt_remove,
  169. .driver = {
  170. .name = "denali-nand-dt",
  171. .of_match_table = denali_nand_dt_ids,
  172. },
  173. };
  174. module_platform_driver(denali_dt_driver);
  175. MODULE_LICENSE("GPL");
  176. MODULE_AUTHOR("Jamie Iles");
  177. MODULE_DESCRIPTION("DT driver for Denali NAND controller");