hyperbus-core.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
  4. // Author: Vignesh Raghavendra <vigneshr@ti.com>
  5. #include <linux/err.h>
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/mtd/hyperbus.h>
  9. #include <linux/mtd/map.h>
  10. #include <linux/mtd/mtd.h>
  11. #include <linux/of.h>
  12. #include <linux/types.h>
  13. static struct hyperbus_device *map_to_hbdev(struct map_info *map)
  14. {
  15. return container_of(map, struct hyperbus_device, map);
  16. }
  17. static map_word hyperbus_read16(struct map_info *map, unsigned long addr)
  18. {
  19. struct hyperbus_device *hbdev = map_to_hbdev(map);
  20. struct hyperbus_ctlr *ctlr = hbdev->ctlr;
  21. map_word read_data;
  22. read_data.x[0] = ctlr->ops->read16(hbdev, addr);
  23. return read_data;
  24. }
  25. static void hyperbus_write16(struct map_info *map, map_word d,
  26. unsigned long addr)
  27. {
  28. struct hyperbus_device *hbdev = map_to_hbdev(map);
  29. struct hyperbus_ctlr *ctlr = hbdev->ctlr;
  30. ctlr->ops->write16(hbdev, addr, d.x[0]);
  31. }
  32. static void hyperbus_copy_from(struct map_info *map, void *to,
  33. unsigned long from, ssize_t len)
  34. {
  35. struct hyperbus_device *hbdev = map_to_hbdev(map);
  36. struct hyperbus_ctlr *ctlr = hbdev->ctlr;
  37. ctlr->ops->copy_from(hbdev, to, from, len);
  38. }
  39. static void hyperbus_copy_to(struct map_info *map, unsigned long to,
  40. const void *from, ssize_t len)
  41. {
  42. struct hyperbus_device *hbdev = map_to_hbdev(map);
  43. struct hyperbus_ctlr *ctlr = hbdev->ctlr;
  44. ctlr->ops->copy_to(hbdev, to, from, len);
  45. }
  46. int hyperbus_register_device(struct hyperbus_device *hbdev)
  47. {
  48. const struct hyperbus_ops *ops;
  49. struct hyperbus_ctlr *ctlr;
  50. struct device_node *np;
  51. struct map_info *map;
  52. struct device *dev;
  53. int ret;
  54. if (!hbdev || !hbdev->np || !hbdev->ctlr || !hbdev->ctlr->dev) {
  55. pr_err("hyperbus: please fill all the necessary fields!\n");
  56. return -EINVAL;
  57. }
  58. np = hbdev->np;
  59. ctlr = hbdev->ctlr;
  60. if (!of_device_is_compatible(np, "cypress,hyperflash")) {
  61. dev_err(ctlr->dev, "\"cypress,hyperflash\" compatible missing\n");
  62. return -ENODEV;
  63. }
  64. hbdev->memtype = HYPERFLASH;
  65. dev = ctlr->dev;
  66. map = &hbdev->map;
  67. map->name = dev_name(dev);
  68. map->bankwidth = 2;
  69. map->device_node = np;
  70. simple_map_init(map);
  71. ops = ctlr->ops;
  72. if (ops) {
  73. if (ops->read16)
  74. map->read = hyperbus_read16;
  75. if (ops->write16)
  76. map->write = hyperbus_write16;
  77. if (ops->copy_to)
  78. map->copy_to = hyperbus_copy_to;
  79. if (ops->copy_from)
  80. map->copy_from = hyperbus_copy_from;
  81. if (ops->calibrate && !ctlr->calibrated) {
  82. ret = ops->calibrate(hbdev);
  83. if (!ret) {
  84. dev_err(dev, "Calibration failed\n");
  85. return -ENODEV;
  86. }
  87. ctlr->calibrated = true;
  88. }
  89. }
  90. hbdev->mtd = do_map_probe("cfi_probe", map);
  91. if (!hbdev->mtd) {
  92. dev_err(dev, "probing of hyperbus device failed\n");
  93. return -ENODEV;
  94. }
  95. hbdev->mtd->dev.parent = dev;
  96. mtd_set_of_node(hbdev->mtd, np);
  97. ret = mtd_device_register(hbdev->mtd, NULL, 0);
  98. if (ret) {
  99. dev_err(dev, "failed to register mtd device\n");
  100. map_destroy(hbdev->mtd);
  101. return ret;
  102. }
  103. return 0;
  104. }
  105. EXPORT_SYMBOL_GPL(hyperbus_register_device);
  106. int hyperbus_unregister_device(struct hyperbus_device *hbdev)
  107. {
  108. int ret = 0;
  109. if (hbdev && hbdev->mtd) {
  110. ret = mtd_device_unregister(hbdev->mtd);
  111. map_destroy(hbdev->mtd);
  112. }
  113. return ret;
  114. }
  115. EXPORT_SYMBOL_GPL(hyperbus_unregister_device);
  116. MODULE_DESCRIPTION("HyperBus Framework");
  117. MODULE_LICENSE("GPL v2");
  118. MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");