switch_gpio.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * drivers/switch/switch_gpio.c
  3. *
  4. * Copyright (C) 2008 Google, Inc.
  5. * Copyright (C) 2021 XiaoMi, Inc.
  6. * Author: Mike Lockwood <lockwood@android.com>
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #include <linux/module.h>
  19. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/slab.h>
  24. #include <linux/switch.h>
  25. #include <linux/workqueue.h>
  26. #include <linux/gpio.h>
  27. struct gpio_switch_data {
  28. struct switch_dev sdev;
  29. unsigned gpio;
  30. const char *name_on;
  31. const char *name_off;
  32. const char *state_on;
  33. const char *state_off;
  34. int irq;
  35. struct work_struct work;
  36. };
  37. static void gpio_switch_work(struct work_struct *work)
  38. {
  39. int state;
  40. struct gpio_switch_data *data =
  41. container_of(work, struct gpio_switch_data, work);
  42. state = gpio_get_value(data->gpio);
  43. switch_set_state(&data->sdev, state);
  44. }
  45. static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
  46. {
  47. struct gpio_switch_data *switch_data =
  48. (struct gpio_switch_data *)dev_id;
  49. schedule_work(&switch_data->work);
  50. return IRQ_HANDLED;
  51. }
  52. static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
  53. {
  54. struct gpio_switch_data *switch_data =
  55. container_of(sdev, struct gpio_switch_data, sdev);
  56. const char *state;
  57. if (switch_get_state(sdev))
  58. state = switch_data->state_on;
  59. else
  60. state = switch_data->state_off;
  61. if (state)
  62. return sprintf(buf, "%s\n", state);
  63. return -1;
  64. }
  65. static int gpio_switch_probe(struct platform_device *pdev)
  66. {
  67. struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
  68. struct gpio_switch_data *switch_data;
  69. int ret = 0;
  70. if (!pdata)
  71. return -EBUSY;
  72. switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
  73. if (!switch_data)
  74. return -ENOMEM;
  75. switch_data->sdev.name = pdata->name;
  76. switch_data->gpio = pdata->gpio;
  77. switch_data->name_on = pdata->name_on;
  78. switch_data->name_off = pdata->name_off;
  79. switch_data->state_on = pdata->state_on;
  80. switch_data->state_off = pdata->state_off;
  81. switch_data->sdev.print_state = switch_gpio_print_state;
  82. ret = switch_dev_register(&switch_data->sdev);
  83. if (ret < 0)
  84. goto err_switch_dev_register;
  85. ret = gpio_request(switch_data->gpio, pdev->name);
  86. if (ret < 0)
  87. goto err_request_gpio;
  88. ret = gpio_direction_input(switch_data->gpio);
  89. if (ret < 0)
  90. goto err_set_gpio_input;
  91. INIT_WORK(&switch_data->work, gpio_switch_work);
  92. switch_data->irq = gpio_to_irq(switch_data->gpio);
  93. if (switch_data->irq < 0) {
  94. ret = switch_data->irq;
  95. goto err_detect_irq_num_failed;
  96. }
  97. ret = request_irq(switch_data->irq, gpio_irq_handler,
  98. IRQF_TRIGGER_LOW, pdev->name, switch_data);
  99. if (ret < 0)
  100. goto err_request_irq;
  101. /* Perform initial detection */
  102. gpio_switch_work(&switch_data->work);
  103. return 0;
  104. err_request_irq:
  105. err_detect_irq_num_failed:
  106. err_set_gpio_input:
  107. gpio_free(switch_data->gpio);
  108. err_request_gpio:
  109. switch_dev_unregister(&switch_data->sdev);
  110. err_switch_dev_register:
  111. kfree(switch_data);
  112. return ret;
  113. }
  114. static int gpio_switch_remove(struct platform_device *pdev)
  115. {
  116. struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
  117. cancel_work_sync(&switch_data->work);
  118. gpio_free(switch_data->gpio);
  119. switch_dev_unregister(&switch_data->sdev);
  120. kfree(switch_data);
  121. return 0;
  122. }
  123. static struct platform_driver gpio_switch_driver = {
  124. .probe = gpio_switch_probe,
  125. .remove = gpio_switch_remove,
  126. .driver = {
  127. .name = "switch-gpio",
  128. .owner = THIS_MODULE,
  129. },
  130. };
  131. static int __init gpio_switch_init(void)
  132. {
  133. return platform_driver_register(&gpio_switch_driver);
  134. }
  135. static void __exit gpio_switch_exit(void)
  136. {
  137. platform_driver_unregister(&gpio_switch_driver);
  138. }
  139. module_init(gpio_switch_init);
  140. module_exit(gpio_switch_exit);
  141. MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
  142. MODULE_DESCRIPTION("GPIO Switch driver");
  143. MODULE_LICENSE("GPL");