regulator-poweroff.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Force-disables a regulator to power down a device
  4. *
  5. * Michael Klein <[email protected]>
  6. *
  7. * Copyright (C) 2020 Michael Klein
  8. *
  9. * Based on the gpio-poweroff driver.
  10. */
  11. #include <linux/delay.h>
  12. #include <linux/module.h>
  13. #include <linux/of.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/pm.h>
  16. #include <linux/regulator/consumer.h>
  17. #define TIMEOUT_MS 3000
  18. /*
  19. * Hold configuration here, cannot be more than one instance of the driver
  20. * since pm_power_off itself is global.
  21. */
  22. static struct regulator *cpu_regulator;
  23. static void regulator_poweroff_do_poweroff(void)
  24. {
  25. if (cpu_regulator && regulator_is_enabled(cpu_regulator))
  26. regulator_force_disable(cpu_regulator);
  27. /* give it some time */
  28. mdelay(TIMEOUT_MS);
  29. WARN_ON(1);
  30. }
  31. static int regulator_poweroff_probe(struct platform_device *pdev)
  32. {
  33. /* If a pm_power_off function has already been added, leave it alone */
  34. if (pm_power_off != NULL) {
  35. dev_err(&pdev->dev,
  36. "%s: pm_power_off function already registered\n",
  37. __func__);
  38. return -EBUSY;
  39. }
  40. cpu_regulator = devm_regulator_get(&pdev->dev, "cpu");
  41. if (IS_ERR(cpu_regulator))
  42. return PTR_ERR(cpu_regulator);
  43. pm_power_off = &regulator_poweroff_do_poweroff;
  44. return 0;
  45. }
  46. static int regulator_poweroff_remove(__maybe_unused struct platform_device *pdev)
  47. {
  48. if (pm_power_off == &regulator_poweroff_do_poweroff)
  49. pm_power_off = NULL;
  50. return 0;
  51. }
  52. static const struct of_device_id of_regulator_poweroff_match[] = {
  53. { .compatible = "regulator-poweroff", },
  54. {},
  55. };
  56. MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match);
  57. static struct platform_driver regulator_poweroff_driver = {
  58. .probe = regulator_poweroff_probe,
  59. .remove = regulator_poweroff_remove,
  60. .driver = {
  61. .name = "poweroff-regulator",
  62. .of_match_table = of_regulator_poweroff_match,
  63. },
  64. };
  65. module_platform_driver(regulator_poweroff_driver);
  66. MODULE_AUTHOR("Michael Klein <[email protected]>");
  67. MODULE_DESCRIPTION("Regulator poweroff driver");
  68. MODULE_LICENSE("GPL v2");
  69. MODULE_ALIAS("platform:poweroff-regulator");