extcon-gpio.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * extcon_gpio.c - Single-state GPIO extcon driver based on extcon class
  3. *
  4. * Copyright (C) 2008 Google, Inc.
  5. * Author: Mike Lockwood <lockwood@android.com>
  6. *
  7. * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
  8. * (originally switch class is supported)
  9. *
  10. * This software is licensed under the terms of the GNU General Public
  11. * License version 2, as published by the Free Software Foundation, and
  12. * may be copied, distributed, and modified under those terms.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include <linux/extcon-provider.h>
  20. #include <linux/gpio.h>
  21. #include <linux/gpio/consumer.h>
  22. #include <linux/init.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/kernel.h>
  25. #include <linux/module.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/slab.h>
  28. #include <linux/workqueue.h>
  29. /**
  30. * struct gpio_extcon_data - A simple GPIO-controlled extcon device state container.
  31. * @edev: Extcon device.
  32. * @irq: Interrupt line for the external connector.
  33. * @work: Work fired by the interrupt.
  34. * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce
  35. * value.
  36. * @id_gpiod: GPIO descriptor for this external connector.
  37. * @extcon_id: The unique id of specific external connector.
  38. * @gpio: Corresponding GPIO.
  39. * @gpio_active_low: Boolean describing whether gpio active state is 1 or 0
  40. * If true, low state of gpio means active.
  41. * If false, high state of gpio means active.
  42. * @debounce: Debounce time for GPIO IRQ in ms.
  43. * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
  44. * @check_on_resume: Boolean describing whether to check the state of gpio
  45. * while resuming from sleep.
  46. */
  47. struct gpio_extcon_data {
  48. struct extcon_dev *edev;
  49. int irq;
  50. struct delayed_work work;
  51. unsigned long debounce_jiffies;
  52. struct gpio_desc *id_gpiod;
  53. unsigned int extcon_id;
  54. unsigned gpio;
  55. bool gpio_active_low;
  56. unsigned long debounce;
  57. unsigned long irq_flags;
  58. bool check_on_resume;
  59. };
  60. static void gpio_extcon_work(struct work_struct *work)
  61. {
  62. int state;
  63. struct gpio_extcon_data *data =
  64. container_of(to_delayed_work(work), struct gpio_extcon_data,
  65. work);
  66. state = gpiod_get_value_cansleep(data->id_gpiod);
  67. if (data->gpio_active_low)
  68. state = !state;
  69. extcon_set_state_sync(data->edev, data->extcon_id, state);
  70. }
  71. static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
  72. {
  73. struct gpio_extcon_data *data = dev_id;
  74. queue_delayed_work(system_power_efficient_wq, &data->work,
  75. data->debounce_jiffies);
  76. return IRQ_HANDLED;
  77. }
  78. static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data)
  79. {
  80. int ret;
  81. ret = devm_gpio_request_one(dev, data->gpio, GPIOF_DIR_IN,
  82. dev_name(dev));
  83. if (ret < 0)
  84. return ret;
  85. data->id_gpiod = gpio_to_desc(data->gpio);
  86. if (!data->id_gpiod)
  87. return -EINVAL;
  88. if (data->debounce) {
  89. ret = gpiod_set_debounce(data->id_gpiod,
  90. data->debounce * 1000);
  91. if (ret < 0)
  92. data->debounce_jiffies =
  93. msecs_to_jiffies(data->debounce);
  94. }
  95. data->irq = gpiod_to_irq(data->id_gpiod);
  96. if (data->irq < 0)
  97. return data->irq;
  98. return 0;
  99. }
  100. static int gpio_extcon_probe(struct platform_device *pdev)
  101. {
  102. struct gpio_extcon_data *data;
  103. int ret;
  104. data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
  105. GFP_KERNEL);
  106. if (!data)
  107. return -ENOMEM;
  108. /*
  109. * FIXME: extcon_id represents the unique identifier of external
  110. * connectors such as EXTCON_USB, EXTCON_DISP_HDMI and so on. extcon_id
  111. * is necessary to register the extcon device. But, it's not yet
  112. * developed to get the extcon id from device-tree or others.
  113. * On later, it have to be solved.
  114. */
  115. if (!data->irq_flags || data->extcon_id > EXTCON_NONE)
  116. return -EINVAL;
  117. /* Initialize the gpio */
  118. ret = gpio_extcon_init(&pdev->dev, data);
  119. if (ret < 0)
  120. return ret;
  121. /* Allocate the memory of extcon devie and register extcon device */
  122. data->edev = devm_extcon_dev_allocate(&pdev->dev, &data->extcon_id);
  123. if (IS_ERR(data->edev)) {
  124. dev_err(&pdev->dev, "failed to allocate extcon device\n");
  125. return -ENOMEM;
  126. }
  127. ret = devm_extcon_dev_register(&pdev->dev, data->edev);
  128. if (ret < 0)
  129. return ret;
  130. INIT_DELAYED_WORK(&data->work, gpio_extcon_work);
  131. /*
  132. * Request the interrupt of gpio to detect whether external connector
  133. * is attached or detached.
  134. */
  135. ret = devm_request_any_context_irq(&pdev->dev, data->irq,
  136. gpio_irq_handler, data->irq_flags,
  137. pdev->name, data);
  138. if (ret < 0)
  139. return ret;
  140. platform_set_drvdata(pdev, data);
  141. /* Perform initial detection */
  142. gpio_extcon_work(&data->work.work);
  143. return 0;
  144. }
  145. static int gpio_extcon_remove(struct platform_device *pdev)
  146. {
  147. struct gpio_extcon_data *data = platform_get_drvdata(pdev);
  148. cancel_delayed_work_sync(&data->work);
  149. return 0;
  150. }
  151. #ifdef CONFIG_PM_SLEEP
  152. static int gpio_extcon_resume(struct device *dev)
  153. {
  154. struct gpio_extcon_data *data;
  155. data = dev_get_drvdata(dev);
  156. if (data->check_on_resume)
  157. queue_delayed_work(system_power_efficient_wq,
  158. &data->work, data->debounce_jiffies);
  159. return 0;
  160. }
  161. #endif
  162. static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume);
  163. static struct platform_driver gpio_extcon_driver = {
  164. .probe = gpio_extcon_probe,
  165. .remove = gpio_extcon_remove,
  166. .driver = {
  167. .name = "extcon-gpio",
  168. .pm = &gpio_extcon_pm_ops,
  169. },
  170. };
  171. module_platform_driver(gpio_extcon_driver);
  172. MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
  173. MODULE_DESCRIPTION("GPIO extcon driver");
  174. MODULE_LICENSE("GPL");