cpuidle-mtk_acao.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (C) 2018 MediaTek Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
  12. */
  13. #include <linux/cpuidle.h>
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/of.h>
  17. #include <linux/slab.h>
  18. #include <asm/cpuidle.h>
  19. #include <asm/suspend.h>
  20. #define CREATE_TRACE_POINTS
  21. #include <trace/events/mtk_idle_event.h>
  22. int __attribute__((weak)) mtk_cpuidle_register_driver(void)
  23. {
  24. return -ENODEV;
  25. }
  26. void __attribute__((weak)) mtk_cpuidle_unregister_driver(void)
  27. {
  28. }
  29. int __init mtk_acao_cpuidle_init(void)
  30. {
  31. int cpu, ret;
  32. struct cpuidle_device *dev;
  33. /*
  34. * Initialize idle states data, starting at index 1.
  35. * This driver is DT only, if no DT idle states are detected (ret == 0)
  36. * let the driver initialization fail accordingly since there is no
  37. * reason to initialize the idle driver if only wfi is supported.
  38. */
  39. #if 0
  40. ret = dt_init_idle_driver(drv, mtk_idle_state_match, 1);
  41. if (ret <= 0)
  42. return ret ? : -ENODEV;
  43. #endif
  44. ret = mtk_cpuidle_register_driver();
  45. if (ret) {
  46. pr_info("Failed to register mtk cpuidle driver (%d)\n", ret);
  47. return ret;
  48. }
  49. /*
  50. * Call arch CPU operations in order to initialize
  51. * idle states suspend back-end specific data
  52. */
  53. for_each_possible_cpu(cpu) {
  54. ret = arm_cpuidle_init(cpu);
  55. /*
  56. * Skip the cpuidle device initialization if the reported
  57. * failure is a HW misconfiguration/breakage (-ENXIO).
  58. */
  59. if (ret == -ENXIO)
  60. continue;
  61. if (ret) {
  62. pr_info("CPU %d failed to init idle CPU ops\n", cpu);
  63. goto out_fail;
  64. }
  65. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  66. if (!dev)
  67. goto out_fail;
  68. dev->cpu = cpu;
  69. ret = cpuidle_register_device(dev);
  70. if (ret) {
  71. pr_info("Failed to register cpuidle device for CPU %d\n",
  72. cpu);
  73. kfree(dev);
  74. goto out_fail;
  75. }
  76. }
  77. return 0;
  78. out_fail:
  79. while (cpu > 0) {
  80. cpu--;
  81. dev = per_cpu(cpuidle_devices, cpu);
  82. cpuidle_unregister_device(dev);
  83. kfree(dev);
  84. }
  85. mtk_cpuidle_unregister_driver();
  86. return ret;
  87. }
  88. device_initcall(mtk_acao_cpuidle_init);