tps65219-pwrbutton.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Driver for TPS65219 Push Button
  4. //
  5. // Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/
  6. #include <linux/init.h>
  7. #include <linux/input.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/kernel.h>
  10. #include <linux/mfd/tps65219.h>
  11. #include <linux/module.h>
  12. #include <linux/of.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/regmap.h>
  15. #include <linux/slab.h>
  16. struct tps65219_pwrbutton {
  17. struct device *dev;
  18. struct input_dev *idev;
  19. char phys[32];
  20. };
  21. static irqreturn_t tps65219_pb_push_irq(int irq, void *_pwr)
  22. {
  23. struct tps65219_pwrbutton *pwr = _pwr;
  24. input_report_key(pwr->idev, KEY_POWER, 1);
  25. pm_wakeup_event(pwr->dev, 0);
  26. input_sync(pwr->idev);
  27. return IRQ_HANDLED;
  28. }
  29. static irqreturn_t tps65219_pb_release_irq(int irq, void *_pwr)
  30. {
  31. struct tps65219_pwrbutton *pwr = _pwr;
  32. input_report_key(pwr->idev, KEY_POWER, 0);
  33. input_sync(pwr->idev);
  34. return IRQ_HANDLED;
  35. }
  36. static int tps65219_pb_probe(struct platform_device *pdev)
  37. {
  38. struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
  39. struct device *dev = &pdev->dev;
  40. struct tps65219_pwrbutton *pwr;
  41. struct input_dev *idev;
  42. int error;
  43. int push_irq;
  44. int release_irq;
  45. pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
  46. if (!pwr)
  47. return -ENOMEM;
  48. idev = devm_input_allocate_device(dev);
  49. if (!idev)
  50. return -ENOMEM;
  51. idev->name = pdev->name;
  52. snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
  53. pdev->name);
  54. idev->phys = pwr->phys;
  55. idev->id.bustype = BUS_I2C;
  56. input_set_capability(idev, EV_KEY, KEY_POWER);
  57. pwr->dev = dev;
  58. pwr->idev = idev;
  59. device_init_wakeup(dev, true);
  60. push_irq = platform_get_irq(pdev, 0);
  61. if (push_irq < 0)
  62. return -EINVAL;
  63. release_irq = platform_get_irq(pdev, 1);
  64. if (release_irq < 0)
  65. return -EINVAL;
  66. error = devm_request_threaded_irq(dev, push_irq, NULL,
  67. tps65219_pb_push_irq,
  68. IRQF_ONESHOT,
  69. dev->init_name, pwr);
  70. if (error) {
  71. dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq,
  72. error);
  73. return error;
  74. }
  75. error = devm_request_threaded_irq(dev, release_irq, NULL,
  76. tps65219_pb_release_irq,
  77. IRQF_ONESHOT,
  78. dev->init_name, pwr);
  79. if (error) {
  80. dev_err(dev, "failed to request release IRQ #%d: %d\n",
  81. release_irq, error);
  82. return error;
  83. }
  84. error = input_register_device(idev);
  85. if (error) {
  86. dev_err(dev, "Can't register power button: %d\n", error);
  87. return error;
  88. }
  89. /* Enable interrupts for the pushbutton */
  90. regmap_clear_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
  91. TPS65219_REG_MASK_INT_FOR_PB_MASK);
  92. /* Set PB/EN/VSENSE pin to be a pushbutton */
  93. regmap_update_bits(tps->regmap, TPS65219_REG_MFP_2_CONFIG,
  94. TPS65219_MFP_2_EN_PB_VSENSE_MASK, TPS65219_MFP_2_PB);
  95. return 0;
  96. }
  97. static void tps65219_pb_remove(struct platform_device *pdev)
  98. {
  99. struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
  100. int ret;
  101. /* Disable interrupt for the pushbutton */
  102. ret = regmap_set_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
  103. TPS65219_REG_MASK_INT_FOR_PB_MASK);
  104. if (ret)
  105. dev_warn(&pdev->dev, "Failed to disable irq (%pe)\n", ERR_PTR(ret));
  106. }
  107. static const struct platform_device_id tps65219_pwrbtn_id_table[] = {
  108. { "tps65219-pwrbutton", },
  109. { /* sentinel */ }
  110. };
  111. MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table);
  112. static struct platform_driver tps65219_pb_driver = {
  113. .probe = tps65219_pb_probe,
  114. .remove = tps65219_pb_remove,
  115. .driver = {
  116. .name = "tps65219_pwrbutton",
  117. },
  118. .id_table = tps65219_pwrbtn_id_table,
  119. };
  120. module_platform_driver(tps65219_pb_driver);
  121. MODULE_DESCRIPTION("TPS65219 Power Button");
  122. MODULE_LICENSE("GPL");
  123. MODULE_AUTHOR("Markus Schneider-Pargmann <msp@baylibre.com");