gpio-beeper.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Generic GPIO beeper driver
  4. *
  5. * Copyright (C) 2013-2014 Alexander Shiyan <[email protected]>
  6. */
  7. #include <linux/input.h>
  8. #include <linux/module.h>
  9. #include <linux/gpio/consumer.h>
  10. #include <linux/of.h>
  11. #include <linux/workqueue.h>
  12. #include <linux/platform_device.h>
  13. #define BEEPER_MODNAME "gpio-beeper"
  14. struct gpio_beeper {
  15. struct work_struct work;
  16. struct gpio_desc *desc;
  17. bool beeping;
  18. };
  19. static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
  20. {
  21. gpiod_set_value_cansleep(beep->desc, on);
  22. }
  23. static void gpio_beeper_work(struct work_struct *work)
  24. {
  25. struct gpio_beeper *beep = container_of(work, struct gpio_beeper, work);
  26. gpio_beeper_toggle(beep, beep->beeping);
  27. }
  28. static int gpio_beeper_event(struct input_dev *dev, unsigned int type,
  29. unsigned int code, int value)
  30. {
  31. struct gpio_beeper *beep = input_get_drvdata(dev);
  32. if (type != EV_SND || code != SND_BELL)
  33. return -ENOTSUPP;
  34. if (value < 0)
  35. return -EINVAL;
  36. beep->beeping = value;
  37. /* Schedule work to actually turn the beeper on or off */
  38. schedule_work(&beep->work);
  39. return 0;
  40. }
  41. static void gpio_beeper_close(struct input_dev *input)
  42. {
  43. struct gpio_beeper *beep = input_get_drvdata(input);
  44. cancel_work_sync(&beep->work);
  45. gpio_beeper_toggle(beep, false);
  46. }
  47. static int gpio_beeper_probe(struct platform_device *pdev)
  48. {
  49. struct gpio_beeper *beep;
  50. struct input_dev *input;
  51. beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
  52. if (!beep)
  53. return -ENOMEM;
  54. beep->desc = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
  55. if (IS_ERR(beep->desc))
  56. return PTR_ERR(beep->desc);
  57. input = devm_input_allocate_device(&pdev->dev);
  58. if (!input)
  59. return -ENOMEM;
  60. INIT_WORK(&beep->work, gpio_beeper_work);
  61. input->name = pdev->name;
  62. input->id.bustype = BUS_HOST;
  63. input->id.vendor = 0x0001;
  64. input->id.product = 0x0001;
  65. input->id.version = 0x0100;
  66. input->close = gpio_beeper_close;
  67. input->event = gpio_beeper_event;
  68. input_set_capability(input, EV_SND, SND_BELL);
  69. input_set_drvdata(input, beep);
  70. return input_register_device(input);
  71. }
  72. #ifdef CONFIG_OF
  73. static const struct of_device_id gpio_beeper_of_match[] = {
  74. { .compatible = BEEPER_MODNAME, },
  75. { }
  76. };
  77. MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
  78. #endif
  79. static struct platform_driver gpio_beeper_platform_driver = {
  80. .driver = {
  81. .name = BEEPER_MODNAME,
  82. .of_match_table = of_match_ptr(gpio_beeper_of_match),
  83. },
  84. .probe = gpio_beeper_probe,
  85. };
  86. module_platform_driver(gpio_beeper_platform_driver);
  87. MODULE_LICENSE("GPL");
  88. MODULE_AUTHOR("Alexander Shiyan <[email protected]>");
  89. MODULE_DESCRIPTION("Generic GPIO beeper driver");