reset-brcmstb-rescal.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (C) 2018-2020 Broadcom */
  3. #include <linux/device.h>
  4. #include <linux/iopoll.h>
  5. #include <linux/module.h>
  6. #include <linux/of.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/reset-controller.h>
  9. #define BRCM_RESCAL_START 0x0
  10. #define BRCM_RESCAL_START_BIT BIT(0)
  11. #define BRCM_RESCAL_CTRL 0x4
  12. #define BRCM_RESCAL_STATUS 0x8
  13. #define BRCM_RESCAL_STATUS_BIT BIT(0)
  14. struct brcm_rescal_reset {
  15. void __iomem *base;
  16. struct device *dev;
  17. struct reset_controller_dev rcdev;
  18. };
  19. static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev,
  20. unsigned long id)
  21. {
  22. struct brcm_rescal_reset *data =
  23. container_of(rcdev, struct brcm_rescal_reset, rcdev);
  24. void __iomem *base = data->base;
  25. u32 reg;
  26. int ret;
  27. reg = readl(base + BRCM_RESCAL_START);
  28. writel(reg | BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START);
  29. reg = readl(base + BRCM_RESCAL_START);
  30. if (!(reg & BRCM_RESCAL_START_BIT)) {
  31. dev_err(data->dev, "failed to start SATA/PCIe rescal\n");
  32. return -EIO;
  33. }
  34. ret = readl_poll_timeout(base + BRCM_RESCAL_STATUS, reg,
  35. (reg & BRCM_RESCAL_STATUS_BIT), 100, 1000);
  36. if (ret) {
  37. dev_err(data->dev, "time out on SATA/PCIe rescal\n");
  38. return ret;
  39. }
  40. reg = readl(base + BRCM_RESCAL_START);
  41. writel(reg & ~BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START);
  42. dev_dbg(data->dev, "SATA/PCIe rescal success\n");
  43. return 0;
  44. }
  45. static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev,
  46. const struct of_phandle_args *reset_spec)
  47. {
  48. /* This is needed if #reset-cells == 0. */
  49. return 0;
  50. }
  51. static const struct reset_control_ops brcm_rescal_reset_ops = {
  52. .reset = brcm_rescal_reset_set,
  53. };
  54. static int brcm_rescal_reset_probe(struct platform_device *pdev)
  55. {
  56. struct brcm_rescal_reset *data;
  57. struct resource *res;
  58. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  59. if (!data)
  60. return -ENOMEM;
  61. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  62. data->base = devm_ioremap_resource(&pdev->dev, res);
  63. if (IS_ERR(data->base))
  64. return PTR_ERR(data->base);
  65. data->rcdev.owner = THIS_MODULE;
  66. data->rcdev.nr_resets = 1;
  67. data->rcdev.ops = &brcm_rescal_reset_ops;
  68. data->rcdev.of_node = pdev->dev.of_node;
  69. data->rcdev.of_xlate = brcm_rescal_reset_xlate;
  70. data->dev = &pdev->dev;
  71. return devm_reset_controller_register(&pdev->dev, &data->rcdev);
  72. }
  73. static const struct of_device_id brcm_rescal_reset_of_match[] = {
  74. { .compatible = "brcm,bcm7216-pcie-sata-rescal" },
  75. { },
  76. };
  77. MODULE_DEVICE_TABLE(of, brcm_rescal_reset_of_match);
  78. static struct platform_driver brcm_rescal_reset_driver = {
  79. .probe = brcm_rescal_reset_probe,
  80. .driver = {
  81. .name = "brcm-rescal-reset",
  82. .of_match_table = brcm_rescal_reset_of_match,
  83. }
  84. };
  85. module_platform_driver(brcm_rescal_reset_driver);
  86. MODULE_AUTHOR("Broadcom");
  87. MODULE_DESCRIPTION("Broadcom SATA/PCIe rescal reset controller");
  88. MODULE_LICENSE("GPL v2");