devfreq_vdd_cdev.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/devfreq.h>
  7. #include <linux/slab.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/pm_opp.h>
  11. #include <linux/pm_qos.h>
  12. #include <linux/thermal.h>
  13. #define MAX_RETRY_CNT 20
  14. #define RETRY_DELAY msecs_to_jiffies(1000)
  15. #define DEVFREQ_VDD_CDEV_DRIVER "devfreq-vdd-cdev"
  16. struct devfreq_vdd_cdev {
  17. char dev_name[THERMAL_NAME_LENGTH];
  18. struct thermal_cooling_device *cdev;
  19. struct devfreq *devfreq;
  20. unsigned long cur_state;
  21. u32 *freq_table;
  22. size_t freq_table_size;
  23. int retry_cnt;
  24. struct dev_pm_qos_request qos_min_freq_req;
  25. struct delayed_work register_work;
  26. struct device_node *np;
  27. struct platform_device *pdev;
  28. };
  29. static int devfreq_vdd_cdev_get_max_state(struct thermal_cooling_device *cdev,
  30. unsigned long *state)
  31. {
  32. struct devfreq_vdd_cdev *dfc = cdev->devdata;
  33. *state = dfc->freq_table_size - 1;
  34. return 0;
  35. }
  36. static int devfreq_vdd_cdev_get_min_state(struct thermal_cooling_device *cdev,
  37. unsigned long *state)
  38. {
  39. struct devfreq_vdd_cdev *dfc = cdev->devdata;
  40. *state = dfc->cur_state;
  41. return 0;
  42. }
  43. static int devfreq_vdd_cdev_set_min_state(struct thermal_cooling_device *cdev,
  44. unsigned long state)
  45. {
  46. struct devfreq_vdd_cdev *dfc = cdev->devdata;
  47. struct devfreq *df = dfc->devfreq;
  48. struct device *dev = df->dev.parent;
  49. unsigned long freq;
  50. int ret;
  51. if (state == dfc->cur_state)
  52. return 0;
  53. dev_dbg(dev, "Setting cooling min state %lu\n", state);
  54. if (state >= dfc->freq_table_size)
  55. return -EINVAL;
  56. freq = dfc->freq_table[dfc->freq_table_size - state - 1];
  57. ret = dev_pm_qos_update_request(&dfc->qos_min_freq_req, freq);
  58. if (ret < 0) {
  59. pr_err("Error placing qos request:%u. err:%d\n",
  60. freq, ret);
  61. return ret;
  62. }
  63. dfc->cur_state = state;
  64. return 0;
  65. }
  66. static struct thermal_cooling_device_ops devfreq_vdd_cdev_ops = {
  67. .get_max_state = devfreq_vdd_cdev_get_max_state,
  68. .get_cur_state = devfreq_vdd_cdev_get_min_state,
  69. .set_cur_state = devfreq_vdd_cdev_set_min_state,
  70. };
  71. static int devfreq_vdd_cdev_gen_tables(struct platform_device *pdev,
  72. struct devfreq_vdd_cdev *dfc)
  73. {
  74. struct devfreq *df = dfc->devfreq;
  75. struct device *dev = df->dev.parent;
  76. struct dev_pm_opp *opp;
  77. int ret, num_opps;
  78. unsigned long freq;
  79. u32 *freq_table;
  80. int i;
  81. num_opps = dev_pm_opp_get_opp_count(dev);
  82. freq_table = devm_kcalloc(&pdev->dev, num_opps, sizeof(*freq_table),
  83. GFP_KERNEL);
  84. if (!freq_table) {
  85. ret = -ENOMEM;
  86. return ret;
  87. }
  88. for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) {
  89. opp = dev_pm_opp_find_freq_floor(dev, &freq);
  90. if (IS_ERR(opp))
  91. ret = PTR_ERR(opp);
  92. dev_pm_opp_put(opp);
  93. freq_table[i] = freq;
  94. }
  95. dfc->freq_table = freq_table;
  96. dfc->freq_table_size = num_opps;
  97. return ret;
  98. }
  99. static void devfreq_vdd_cdev_work(struct work_struct *work)
  100. {
  101. int ret = 0;
  102. struct devfreq_vdd_cdev *dfc = container_of(work,
  103. struct devfreq_vdd_cdev,
  104. register_work.work);
  105. struct device_node *np = dfc->pdev->dev.of_node;
  106. dfc->devfreq = devfreq_get_devfreq_by_phandle(&dfc->pdev->dev, "devfreq", 0);
  107. if (IS_ERR_OR_NULL(dfc->devfreq)) {
  108. ret = PTR_ERR(dfc->devfreq);
  109. if (--dfc->retry_cnt) {
  110. pr_debug("Devfreq not available:%d\n", ret);
  111. queue_delayed_work(system_highpri_wq, &dfc->register_work, RETRY_DELAY);
  112. }
  113. return;
  114. }
  115. ret = devfreq_vdd_cdev_gen_tables(dfc->pdev, dfc);
  116. if (ret) {
  117. dev_err(&dfc->pdev->dev,
  118. "Failed to get create table for min state cdev (%d)\n",
  119. ret);
  120. return;
  121. }
  122. ret = dev_pm_qos_add_request(&dfc->pdev->dev,
  123. &dfc->qos_min_freq_req,
  124. DEV_PM_QOS_MIN_FREQUENCY,
  125. PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
  126. if (ret < 0)
  127. goto qos_exit;
  128. strscpy(dfc->dev_name, np->name, THERMAL_NAME_LENGTH);
  129. dfc->cdev = thermal_of_cooling_device_register(np, dfc->dev_name, dfc,
  130. &devfreq_vdd_cdev_ops);
  131. if (IS_ERR(dfc->cdev)) {
  132. ret = PTR_ERR(dfc->cdev);
  133. dev_err(&dfc->pdev->dev,
  134. "Failed to register devfreq cooling device (%d)\n",
  135. ret);
  136. dfc->cdev = NULL;
  137. goto qos_exit;
  138. }
  139. dev_set_drvdata(&dfc->pdev->dev, dfc);
  140. return;
  141. qos_exit:
  142. kfree(dfc->freq_table);
  143. dev_pm_qos_remove_request(&dfc->qos_min_freq_req);
  144. }
  145. static int devfreq_vdd_cdev_probe(struct platform_device *pdev)
  146. {
  147. struct devfreq_vdd_cdev *dfc = NULL;
  148. dfc = devm_kzalloc(&pdev->dev, sizeof(*dfc), GFP_KERNEL);
  149. if (!dfc)
  150. return -ENOMEM;
  151. dfc->retry_cnt = MAX_RETRY_CNT;
  152. dfc->pdev = pdev;
  153. INIT_DEFERRABLE_WORK(&dfc->register_work, devfreq_vdd_cdev_work);
  154. queue_delayed_work(system_highpri_wq, &dfc->register_work, 0);
  155. return 0;
  156. }
  157. static int devfreq_vdd_cdev_remove(struct platform_device *pdev)
  158. {
  159. struct devfreq_vdd_cdev *dfc =
  160. (struct devfreq_vdd_cdev *)dev_get_drvdata(&pdev->dev);
  161. if (dfc->cdev)
  162. thermal_cooling_device_unregister(dfc->cdev);
  163. return 0;
  164. };
  165. static const struct of_device_id devfreq_vdd_cdev_match[] = {
  166. { .compatible = "qcom,devfreq-vdd-cooling-device", },
  167. {},
  168. };
  169. static struct platform_driver devfreq_vdd_cdev_driver = {
  170. .probe = devfreq_vdd_cdev_probe,
  171. .remove = devfreq_vdd_cdev_remove,
  172. .driver = {
  173. .name = DEVFREQ_VDD_CDEV_DRIVER,
  174. .of_match_table = devfreq_vdd_cdev_match,
  175. },
  176. };
  177. module_platform_driver(devfreq_vdd_cdev_driver);
  178. MODULE_LICENSE("GPL");