qcom-pon.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2017-18 Linaro Limited
  3. #include <linux/delay.h>
  4. #include <linux/errno.h>
  5. #include <linux/kernel.h>
  6. #include <linux/module.h>
  7. #include <linux/of.h>
  8. #include <linux/of_platform.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/reboot.h>
  11. #include <linux/reboot-mode.h>
  12. #include <linux/regmap.h>
  13. #define PON_SOFT_RB_SPARE 0x8f
  14. #define GEN1_REASON_SHIFT 2
  15. #define GEN2_REASON_SHIFT 1
  16. struct pm8916_pon {
  17. struct device *dev;
  18. struct regmap *regmap;
  19. u32 baseaddr;
  20. struct reboot_mode_driver reboot_mode;
  21. long reason_shift;
  22. };
  23. static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
  24. unsigned int magic)
  25. {
  26. struct pm8916_pon *pon = container_of
  27. (reboot, struct pm8916_pon, reboot_mode);
  28. int ret;
  29. ret = regmap_update_bits(pon->regmap,
  30. pon->baseaddr + PON_SOFT_RB_SPARE,
  31. GENMASK(7, pon->reason_shift),
  32. magic << pon->reason_shift);
  33. if (ret < 0)
  34. dev_err(pon->dev, "update reboot mode bits failed\n");
  35. return ret;
  36. }
  37. static int pm8916_pon_probe(struct platform_device *pdev)
  38. {
  39. struct pm8916_pon *pon;
  40. int error;
  41. pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL);
  42. if (!pon)
  43. return -ENOMEM;
  44. pon->dev = &pdev->dev;
  45. pon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  46. if (!pon->regmap) {
  47. dev_err(&pdev->dev, "failed to locate regmap\n");
  48. return -ENODEV;
  49. }
  50. error = of_property_read_u32(pdev->dev.of_node, "reg",
  51. &pon->baseaddr);
  52. if (error)
  53. return error;
  54. pon->reboot_mode.dev = &pdev->dev;
  55. pon->reason_shift = (long)of_device_get_match_data(&pdev->dev);
  56. pon->reboot_mode.write = pm8916_reboot_mode_write;
  57. error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
  58. if (error) {
  59. dev_err(&pdev->dev, "can't register reboot mode\n");
  60. return error;
  61. }
  62. platform_set_drvdata(pdev, pon);
  63. return devm_of_platform_populate(&pdev->dev);
  64. }
  65. static const struct of_device_id pm8916_pon_id_table[] = {
  66. { .compatible = "qcom,pm8916-pon", .data = (void *)GEN1_REASON_SHIFT },
  67. { .compatible = "qcom,pms405-pon", .data = (void *)GEN1_REASON_SHIFT },
  68. { .compatible = "qcom,pm8998-pon", .data = (void *)GEN2_REASON_SHIFT },
  69. { }
  70. };
  71. MODULE_DEVICE_TABLE(of, pm8916_pon_id_table);
  72. static struct platform_driver pm8916_pon_driver = {
  73. .probe = pm8916_pon_probe,
  74. .driver = {
  75. .name = "pm8916-pon",
  76. .of_match_table = of_match_ptr(pm8916_pon_id_table),
  77. },
  78. };
  79. module_platform_driver(pm8916_pon_driver);
  80. MODULE_DESCRIPTION("pm8916 Power On driver");
  81. MODULE_LICENSE("GPL v2");