reset-stm32.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
  4. * Author: Gabriel Fernandez <[email protected]> for STMicroelectronics.
  5. */
  6. #include <linux/of.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/regmap.h>
  9. #include <linux/reset-controller.h>
  10. #include <linux/slab.h>
  11. #include <linux/spinlock.h>
  12. #include "clk-stm32-core.h"
  13. #define STM32_RESET_ID_MASK GENMASK(15, 0)
  14. struct stm32_reset_data {
  15. /* reset lock */
  16. spinlock_t lock;
  17. struct reset_controller_dev rcdev;
  18. void __iomem *membase;
  19. u32 clear_offset;
  20. };
  21. static inline struct stm32_reset_data *
  22. to_stm32_reset_data(struct reset_controller_dev *rcdev)
  23. {
  24. return container_of(rcdev, struct stm32_reset_data, rcdev);
  25. }
  26. static int stm32_reset_update(struct reset_controller_dev *rcdev,
  27. unsigned long id, bool assert)
  28. {
  29. struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
  30. int reg_width = sizeof(u32);
  31. int bank = id / (reg_width * BITS_PER_BYTE);
  32. int offset = id % (reg_width * BITS_PER_BYTE);
  33. if (data->clear_offset) {
  34. void __iomem *addr;
  35. addr = data->membase + (bank * reg_width);
  36. if (!assert)
  37. addr += data->clear_offset;
  38. writel(BIT(offset), addr);
  39. } else {
  40. unsigned long flags;
  41. u32 reg;
  42. spin_lock_irqsave(&data->lock, flags);
  43. reg = readl(data->membase + (bank * reg_width));
  44. if (assert)
  45. reg |= BIT(offset);
  46. else
  47. reg &= ~BIT(offset);
  48. writel(reg, data->membase + (bank * reg_width));
  49. spin_unlock_irqrestore(&data->lock, flags);
  50. }
  51. return 0;
  52. }
  53. static int stm32_reset_assert(struct reset_controller_dev *rcdev,
  54. unsigned long id)
  55. {
  56. return stm32_reset_update(rcdev, id, true);
  57. }
  58. static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
  59. unsigned long id)
  60. {
  61. return stm32_reset_update(rcdev, id, false);
  62. }
  63. static int stm32_reset_status(struct reset_controller_dev *rcdev,
  64. unsigned long id)
  65. {
  66. struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
  67. int reg_width = sizeof(u32);
  68. int bank = id / (reg_width * BITS_PER_BYTE);
  69. int offset = id % (reg_width * BITS_PER_BYTE);
  70. u32 reg;
  71. reg = readl(data->membase + (bank * reg_width));
  72. return !!(reg & BIT(offset));
  73. }
  74. static const struct reset_control_ops stm32_reset_ops = {
  75. .assert = stm32_reset_assert,
  76. .deassert = stm32_reset_deassert,
  77. .status = stm32_reset_status,
  78. };
  79. int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
  80. void __iomem *base)
  81. {
  82. const struct stm32_rcc_match_data *data = match->data;
  83. struct stm32_reset_data *reset_data = NULL;
  84. data = match->data;
  85. reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
  86. if (!reset_data)
  87. return -ENOMEM;
  88. spin_lock_init(&reset_data->lock);
  89. reset_data->membase = base;
  90. reset_data->rcdev.owner = THIS_MODULE;
  91. reset_data->rcdev.ops = &stm32_reset_ops;
  92. reset_data->rcdev.of_node = dev_of_node(dev);
  93. reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
  94. reset_data->clear_offset = data->clear_offset;
  95. return reset_controller_register(&reset_data->rcdev);
  96. }