regulator_aop_cdev.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/thermal.h>
  15. #include <linux/err.h>
  16. #include <linux/slab.h>
  17. #include <linux/mailbox_client.h>
  18. #define REG_CDEV_DRIVER "reg-aop-cooling-device"
  19. #define REG_MSG_FORMAT "{class:volt_flr, event:zero_temp, res:%s, value:%s}"
  20. #define REG_CDEV_MAX_STATE 1
  21. #define MBOX_TOUT_MS 1000
  22. #define REG_MSG_MAX_LEN 100
  23. struct reg_cooling_device {
  24. struct thermal_cooling_device *cdev;
  25. unsigned int min_state;
  26. const char *resource_name;
  27. struct mbox_chan *qmp_chan;
  28. struct mbox_client *client;
  29. };
  30. struct aop_msg {
  31. uint32_t len;
  32. void *msg;
  33. };
  34. enum regulator_rail_type {
  35. REG_COOLING_CX,
  36. REG_COOLING_MX,
  37. REG_COOLING_EBI,
  38. REG_COOLING_NR,
  39. };
  40. static char *regulator_rail[REG_COOLING_NR] = {
  41. "cx",
  42. "mx",
  43. "ebi",
  44. };
  45. static int aop_send_msg(struct reg_cooling_device *reg_dev, int min_state)
  46. {
  47. char msg_buf[REG_MSG_MAX_LEN] = {0};
  48. int ret = 0;
  49. struct aop_msg msg;
  50. if (!reg_dev->qmp_chan) {
  51. pr_err("mbox not initialized for resource:%s\n",
  52. reg_dev->resource_name);
  53. return -EINVAL;
  54. }
  55. ret = snprintf(msg_buf, REG_MSG_MAX_LEN, REG_MSG_FORMAT,
  56. reg_dev->resource_name,
  57. (min_state == REG_CDEV_MAX_STATE) ? "off" : "on");
  58. if (ret >= REG_MSG_MAX_LEN) {
  59. pr_err("Message too long for resource:%s\n",
  60. reg_dev->resource_name);
  61. return -E2BIG;
  62. }
  63. msg.len = REG_MSG_MAX_LEN;
  64. msg.msg = msg_buf;
  65. ret = mbox_send_message(reg_dev->qmp_chan, &msg);
  66. return (ret < 0) ? ret : 0;
  67. }
  68. static int reg_get_max_state(struct thermal_cooling_device *cdev,
  69. unsigned long *state)
  70. {
  71. *state = REG_CDEV_MAX_STATE;
  72. return 0;
  73. }
  74. static int reg_get_min_state(struct thermal_cooling_device *cdev,
  75. unsigned long *state)
  76. {
  77. struct reg_cooling_device *reg_dev = cdev->devdata;
  78. *state = reg_dev->min_state;
  79. return 0;
  80. }
  81. static int reg_send_min_state(struct thermal_cooling_device *cdev,
  82. unsigned long state)
  83. {
  84. struct reg_cooling_device *reg_dev = cdev->devdata;
  85. int ret = 0;
  86. if (state > REG_CDEV_MAX_STATE)
  87. state = REG_CDEV_MAX_STATE;
  88. if (reg_dev->min_state == state)
  89. return ret;
  90. ret = aop_send_msg(reg_dev, state);
  91. if (ret) {
  92. pr_err("regulator:%s switching to floor %lu error. err:%d\n",
  93. reg_dev->resource_name, state, ret);
  94. } else {
  95. pr_debug("regulator:%s switched to %lu from %d\n",
  96. reg_dev->resource_name, state, reg_dev->min_state);
  97. reg_dev->min_state = state;
  98. }
  99. return ret;
  100. }
  101. static int reg_get_cur_state(struct thermal_cooling_device *cdev,
  102. unsigned long *state)
  103. {
  104. *state = 0;
  105. return 0;
  106. }
  107. static int reg_send_cur_state(struct thermal_cooling_device *cdev,
  108. unsigned long state)
  109. {
  110. return 0;
  111. }
  112. static struct thermal_cooling_device_ops reg_dev_ops = {
  113. .get_max_state = reg_get_max_state,
  114. .get_cur_state = reg_get_cur_state,
  115. .set_cur_state = reg_send_cur_state,
  116. .set_min_state = reg_send_min_state,
  117. .get_min_state = reg_get_min_state,
  118. };
  119. static int reg_init_mbox(struct platform_device *pdev,
  120. struct reg_cooling_device *reg_dev)
  121. {
  122. reg_dev->client = devm_kzalloc(&pdev->dev, sizeof(*reg_dev->client),
  123. GFP_KERNEL);
  124. if (!reg_dev->client)
  125. return -ENOMEM;
  126. reg_dev->client->dev = &pdev->dev;
  127. reg_dev->client->tx_block = true;
  128. reg_dev->client->tx_tout = MBOX_TOUT_MS;
  129. reg_dev->client->knows_txdone = false;
  130. reg_dev->qmp_chan = mbox_request_channel(reg_dev->client, 0);
  131. if (IS_ERR(reg_dev->qmp_chan)) {
  132. dev_err(&pdev->dev, "Mbox request failed. err:%ld\n",
  133. PTR_ERR(reg_dev->qmp_chan));
  134. return PTR_ERR(reg_dev->qmp_chan);
  135. }
  136. return 0;
  137. }
  138. static int reg_dev_probe(struct platform_device *pdev)
  139. {
  140. int ret = 0, idx = 0;
  141. struct reg_cooling_device *reg_dev = NULL;
  142. reg_dev = devm_kzalloc(&pdev->dev, sizeof(*reg_dev), GFP_KERNEL);
  143. if (!reg_dev)
  144. return -ENOMEM;
  145. ret = reg_init_mbox(pdev, reg_dev);
  146. if (ret)
  147. return ret;
  148. ret = of_property_read_string(pdev->dev.of_node,
  149. "qcom,reg-resource-name",
  150. &reg_dev->resource_name);
  151. if (ret) {
  152. dev_err(&pdev->dev, "Error reading resource name. err:%d\n",
  153. ret);
  154. goto mbox_free;
  155. }
  156. for (idx = 0; idx < REG_COOLING_NR; idx++) {
  157. if (!strcmp(reg_dev->resource_name, regulator_rail[idx]))
  158. break;
  159. }
  160. if (idx == REG_COOLING_NR) {
  161. dev_err(&pdev->dev, "Invalid regulator resource name:%s\n",
  162. reg_dev->resource_name);
  163. ret = -EINVAL;
  164. goto mbox_free;
  165. }
  166. reg_dev->min_state = REG_CDEV_MAX_STATE;
  167. reg_dev->cdev = thermal_of_cooling_device_register(
  168. pdev->dev.of_node,
  169. (char *)reg_dev->resource_name,
  170. reg_dev, &reg_dev_ops);
  171. if (IS_ERR(reg_dev->cdev))
  172. goto mbox_free;
  173. return ret;
  174. mbox_free:
  175. mbox_free_channel(reg_dev->qmp_chan);
  176. return ret;
  177. }
  178. static const struct of_device_id reg_dev_of_match[] = {
  179. {.compatible = "qcom,rpmh-reg-cdev", },
  180. {}
  181. };
  182. static struct platform_driver reg_dev_driver = {
  183. .driver = {
  184. .name = REG_CDEV_DRIVER,
  185. .of_match_table = reg_dev_of_match,
  186. },
  187. .probe = reg_dev_probe,
  188. };
  189. builtin_platform_driver(reg_dev_driver);