hgsl_tcsr.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 and
  7. * only version 2 as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include <linux/interrupt.h>
  16. #include <linux/mfd/syscon.h>
  17. #include <linux/module.h>
  18. #include <linux/of.h>
  19. #include <linux/of_irq.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/regmap.h>
  22. #include "hgsl_tcsr.h"
  23. /* Sender registers */
  24. #define TCSR_GLB_CFG_COMPUTE_SIGNALING_REG 0x000
  25. #define TCSR_COMPUTE_SIGNALING_REG 0x000
  26. /* Receiver registers */
  27. #define TCSR_COMPUTE_SIGNAL_STATUS_REG 0x000
  28. #define TCSR_COMPUTE_SIGNAL_CLEAR_REG 0x400
  29. #define TCSR_COMPUTE_SIGNAL_MASK_REG 0x800
  30. struct hgsl_tcsr {
  31. struct platform_device *pdev;
  32. struct device *client_dev;
  33. struct regmap *regmap;
  34. struct regmap *glb_regmap;
  35. enum hgsl_tcsr_role role;
  36. unsigned int enable_count;
  37. struct mutex dev_mutex;
  38. unsigned int irq_num;
  39. irqreturn_t (*isr)(struct device *dev, u32 status);
  40. };
  41. static irqreturn_t hgsl_tcsr_isr(int irq, void *ptr)
  42. {
  43. struct hgsl_tcsr *tcsr = ptr;
  44. u32 status;
  45. regmap_read(tcsr->regmap, TCSR_COMPUTE_SIGNAL_STATUS_REG, &status);
  46. regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNAL_CLEAR_REG, status);
  47. if (tcsr->isr)
  48. return tcsr->isr(tcsr->client_dev, status);
  49. else
  50. return IRQ_HANDLED;
  51. }
  52. static int hgsl_tcsr_init_sender(struct hgsl_tcsr *tcsr)
  53. {
  54. struct device *dev = &tcsr->pdev->dev;
  55. struct device_node *np = dev->of_node;
  56. if (tcsr->glb_regmap != NULL)
  57. return 0;
  58. tcsr->regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
  59. if (IS_ERR_OR_NULL(tcsr->regmap)) {
  60. dev_err(dev, "failed to map sender register\n");
  61. return -ENODEV;
  62. }
  63. tcsr->glb_regmap = syscon_regmap_lookup_by_phandle(np, "syscon-glb");
  64. if (IS_ERR_OR_NULL(tcsr->glb_regmap)) {
  65. dev_err(dev, "failed to map sender global register\n");
  66. tcsr->glb_regmap = NULL;
  67. return -ENODEV;
  68. }
  69. return 0;
  70. }
  71. static int hgsl_tcsr_init_receiver(struct hgsl_tcsr *tcsr)
  72. {
  73. struct device *dev = &tcsr->pdev->dev;
  74. struct device_node *np = dev->of_node;
  75. int ret;
  76. if (tcsr->irq_num != 0)
  77. return 0;
  78. tcsr->regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
  79. if (IS_ERR_OR_NULL(tcsr->regmap)) {
  80. dev_err(dev, "failed to map receiver register\n");
  81. return -ENODEV;
  82. }
  83. tcsr->irq_num = irq_of_parse_and_map(np, 0);
  84. if (tcsr->irq_num == 0) {
  85. dev_err(dev, "failed to get irq\n");
  86. return -ENODEV;
  87. }
  88. ret = request_irq(tcsr->irq_num, hgsl_tcsr_isr,
  89. IRQF_TRIGGER_HIGH, "hgsl-tcsr", tcsr);
  90. if (ret < 0) {
  91. dev_err(dev, "failed to request IRQ%u: %d\n",
  92. tcsr->irq_num, ret);
  93. tcsr->irq_num = 0;
  94. return ret;
  95. }
  96. disable_irq(tcsr->irq_num);
  97. return 0;
  98. }
  99. #if IS_ENABLED(CONFIG_QCOM_HGSL_TCSR_SIGNAL)
  100. struct hgsl_tcsr *hgsl_tcsr_request(struct platform_device *pdev,
  101. enum hgsl_tcsr_role role,
  102. struct device *client,
  103. irqreturn_t (*isr)(struct device *, u32))
  104. {
  105. struct hgsl_tcsr *tcsr = platform_get_drvdata(pdev);
  106. int ret = -EINVAL;
  107. if (!tcsr)
  108. return ERR_PTR(-ENODEV);
  109. else if (tcsr->role != role)
  110. return ERR_PTR(-EINVAL);
  111. else if (tcsr->client_dev)
  112. return ERR_PTR(-EBUSY);
  113. if (role == HGSL_TCSR_ROLE_RECEIVER) {
  114. if (tcsr->isr)
  115. return ERR_PTR(-EBUSY);
  116. else if (!isr)
  117. return ERR_PTR(-EINVAL);
  118. tcsr->client_dev = client;
  119. tcsr->isr = isr;
  120. ret = hgsl_tcsr_init_receiver(tcsr);
  121. } else { /* HGSL_TCSR_ROLE_SENDER */
  122. if (isr)
  123. return ERR_PTR(-EINVAL);
  124. tcsr->client_dev = client;
  125. ret = hgsl_tcsr_init_sender(tcsr);
  126. }
  127. if (ret) {
  128. tcsr = ERR_PTR(ret);
  129. tcsr->client_dev = NULL;
  130. tcsr->isr = NULL;
  131. }
  132. return tcsr;
  133. }
  134. void hgsl_tcsr_free(struct hgsl_tcsr *tcsr)
  135. {
  136. if ((tcsr->role == HGSL_TCSR_ROLE_RECEIVER) &&
  137. (tcsr->irq_num != 0) && (tcsr->isr != NULL))
  138. free_irq(tcsr->irq_num, tcsr);
  139. tcsr->client_dev = NULL;
  140. tcsr->isr = NULL;
  141. }
  142. int hgsl_tcsr_enable(struct hgsl_tcsr *tcsr)
  143. {
  144. mutex_lock(&tcsr->dev_mutex);
  145. if (tcsr->enable_count > 0)
  146. goto done;
  147. if (tcsr->irq_num)
  148. enable_irq(tcsr->irq_num);
  149. done:
  150. tcsr->enable_count++;
  151. mutex_unlock(&tcsr->dev_mutex);
  152. return 0;
  153. }
  154. void hgsl_tcsr_disable(struct hgsl_tcsr *tcsr)
  155. {
  156. mutex_lock(&tcsr->dev_mutex);
  157. if (--tcsr->enable_count > 0)
  158. goto done;
  159. if (tcsr->irq_num)
  160. disable_irq(tcsr->irq_num);
  161. done:
  162. mutex_unlock(&tcsr->dev_mutex);
  163. }
  164. bool hgsl_tcsr_is_enabled(struct hgsl_tcsr *tcsr)
  165. {
  166. return (tcsr->enable_count > 0);
  167. }
  168. void hgsl_tcsr_irq_trigger(struct hgsl_tcsr *tcsr, int irq_id)
  169. {
  170. u32 reg;
  171. /*
  172. * Read back this global config register in case
  173. * it has been modified by others.
  174. */
  175. regmap_read(tcsr->glb_regmap,
  176. TCSR_GLB_CFG_COMPUTE_SIGNALING_REG, &reg);
  177. reg = irq_id << reg;
  178. regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNALING_REG, reg);
  179. }
  180. void hgsl_tcsr_irq_enable(struct hgsl_tcsr *tcsr, u32 mask, bool enable)
  181. {
  182. u32 reg;
  183. regmap_read(tcsr->regmap, TCSR_COMPUTE_SIGNAL_MASK_REG, &reg);
  184. reg = enable ? (reg | mask) : (reg & ~mask);
  185. regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNAL_MASK_REG, reg);
  186. }
  187. #endif
  188. static const struct of_device_id hgsl_tcsr_match_table[] = {
  189. { .compatible = "qcom,hgsl-tcsr-sender" },
  190. { .compatible = "qcom,hgsl-tcsr-receiver" },
  191. {}
  192. };
  193. static int hgsl_tcsr_probe(struct platform_device *pdev)
  194. {
  195. struct device *dev = &pdev->dev;
  196. struct device_node *np = dev->of_node;
  197. struct hgsl_tcsr *tcsr = devm_kzalloc(dev, sizeof(*tcsr),
  198. GFP_KERNEL);
  199. if (!tcsr)
  200. return -ENOMEM;
  201. if (of_device_is_compatible(np, "qcom,hgsl-tcsr-receiver")) {
  202. tcsr->role = HGSL_TCSR_ROLE_RECEIVER;
  203. } else if (of_device_is_compatible(np, "qcom,hgsl-tcsr-sender")) {
  204. tcsr->role = HGSL_TCSR_ROLE_SENDER;
  205. } else {
  206. dev_err(dev, "Not compatible device\n");
  207. return -ENODEV;
  208. }
  209. mutex_init(&tcsr->dev_mutex);
  210. tcsr->pdev = pdev;
  211. platform_set_drvdata(pdev, tcsr);
  212. return 0;
  213. }
  214. static int hgsl_tcsr_remove(struct platform_device *pdev)
  215. {
  216. struct hgsl_tcsr *tcsr = platform_get_drvdata(pdev);
  217. mutex_destroy(&tcsr->dev_mutex);
  218. return 0;
  219. }
  220. struct platform_driver hgsl_tcsr_driver = {
  221. .probe = hgsl_tcsr_probe,
  222. .remove = hgsl_tcsr_remove,
  223. .driver = {
  224. .name = "hgsl-tcsr",
  225. .of_match_table = hgsl_tcsr_match_table,
  226. }
  227. };