khadas_mcu_fan.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Khadas MCU Controlled FAN driver
  4. *
  5. * Copyright (C) 2020 BayLibre SAS
  6. * Author(s): Neil Armstrong <[email protected]>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/mfd/khadas-mcu.h>
  12. #include <linux/regmap.h>
  13. #include <linux/sysfs.h>
  14. #include <linux/thermal.h>
  15. #define MAX_LEVEL 3
  16. struct khadas_mcu_fan_ctx {
  17. struct khadas_mcu *mcu;
  18. unsigned int level;
  19. struct thermal_cooling_device *cdev;
  20. };
  21. static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
  22. unsigned int level)
  23. {
  24. int ret;
  25. ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
  26. level);
  27. if (ret)
  28. return ret;
  29. ctx->level = level;
  30. return 0;
  31. }
  32. static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
  33. unsigned long *state)
  34. {
  35. *state = MAX_LEVEL;
  36. return 0;
  37. }
  38. static int khadas_mcu_fan_get_cur_state(struct thermal_cooling_device *cdev,
  39. unsigned long *state)
  40. {
  41. struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
  42. *state = ctx->level;
  43. return 0;
  44. }
  45. static int
  46. khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
  47. unsigned long state)
  48. {
  49. struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
  50. if (state > MAX_LEVEL)
  51. return -EINVAL;
  52. if (state == ctx->level)
  53. return 0;
  54. return khadas_mcu_fan_set_level(ctx, state);
  55. }
  56. static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = {
  57. .get_max_state = khadas_mcu_fan_get_max_state,
  58. .get_cur_state = khadas_mcu_fan_get_cur_state,
  59. .set_cur_state = khadas_mcu_fan_set_cur_state,
  60. };
  61. static int khadas_mcu_fan_probe(struct platform_device *pdev)
  62. {
  63. struct khadas_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
  64. struct thermal_cooling_device *cdev;
  65. struct device *dev = &pdev->dev;
  66. struct khadas_mcu_fan_ctx *ctx;
  67. int ret;
  68. ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
  69. if (!ctx)
  70. return -ENOMEM;
  71. ctx->mcu = mcu;
  72. platform_set_drvdata(pdev, ctx);
  73. cdev = devm_thermal_of_cooling_device_register(dev->parent,
  74. dev->parent->of_node, "khadas-mcu-fan", ctx,
  75. &khadas_mcu_fan_cooling_ops);
  76. if (IS_ERR(cdev)) {
  77. ret = PTR_ERR(cdev);
  78. dev_err(dev, "Failed to register khadas-mcu-fan as cooling device: %d\n",
  79. ret);
  80. return ret;
  81. }
  82. ctx->cdev = cdev;
  83. return 0;
  84. }
  85. static void khadas_mcu_fan_shutdown(struct platform_device *pdev)
  86. {
  87. struct khadas_mcu_fan_ctx *ctx = platform_get_drvdata(pdev);
  88. khadas_mcu_fan_set_level(ctx, 0);
  89. }
  90. #ifdef CONFIG_PM_SLEEP
  91. static int khadas_mcu_fan_suspend(struct device *dev)
  92. {
  93. struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
  94. unsigned int level_save = ctx->level;
  95. int ret;
  96. ret = khadas_mcu_fan_set_level(ctx, 0);
  97. if (ret)
  98. return ret;
  99. ctx->level = level_save;
  100. return 0;
  101. }
  102. static int khadas_mcu_fan_resume(struct device *dev)
  103. {
  104. struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
  105. return khadas_mcu_fan_set_level(ctx, ctx->level);
  106. }
  107. #endif
  108. static SIMPLE_DEV_PM_OPS(khadas_mcu_fan_pm, khadas_mcu_fan_suspend,
  109. khadas_mcu_fan_resume);
  110. static const struct platform_device_id khadas_mcu_fan_id_table[] = {
  111. { .name = "khadas-mcu-fan-ctrl", },
  112. {},
  113. };
  114. MODULE_DEVICE_TABLE(platform, khadas_mcu_fan_id_table);
  115. static struct platform_driver khadas_mcu_fan_driver = {
  116. .probe = khadas_mcu_fan_probe,
  117. .shutdown = khadas_mcu_fan_shutdown,
  118. .driver = {
  119. .name = "khadas-mcu-fan-ctrl",
  120. .pm = &khadas_mcu_fan_pm,
  121. },
  122. .id_table = khadas_mcu_fan_id_table,
  123. };
  124. module_platform_driver(khadas_mcu_fan_driver);
  125. MODULE_AUTHOR("Neil Armstrong <[email protected]>");
  126. MODULE_DESCRIPTION("Khadas MCU FAN driver");
  127. MODULE_LICENSE("GPL");