/drivers/ril/ril_proximity.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 183 lines · 117 code · 51 blank · 15 comment · 17 complexity · 2e0db79285095e4f03d1ab6a9779bbff MD5 · raw file

  1. #include <linux/module.h>
  2. #include <linux/platform_device.h>
  3. #include <linux/gpio.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/workqueue.h>
  6. #include <linux/irq.h>
  7. #include <linux/switch.h>
  8. #include <mach/board-cardhu-misc.h>
  9. #include "baseband-xmm-power.h"
  10. #include "ril.h"
  11. #include "ril_proximity.h"
  12. #define NAME_RIL_PROX "ril_proximity"
  13. //**** external symbols
  14. //**** constants
  15. #define _ATTR_MODE S_IRUSR | S_IWUSR | S_IRGRP
  16. //**** local variable declaration
  17. static DEFINE_MUTEX(prox_enable_mtx);
  18. static struct device *dev;
  19. static struct workqueue_struct *workqueue;
  20. static struct work_struct prox_task;
  21. static struct switch_dev prox_sdev;
  22. static int proximity_enabled;
  23. //**** callbacks for switch device
  24. static ssize_t print_prox_name(struct switch_dev *sdev, char *buf)
  25. {
  26. return sprintf(buf, "%s\n", "prox_sar_det");
  27. }
  28. static ssize_t print_prox_state(struct switch_dev *sdev, char *buf)
  29. {
  30. int state = -1;
  31. if (switch_get_state(sdev))
  32. state = 1;
  33. else
  34. state = 0;
  35. return sprintf(buf, "%d\n", state);
  36. }
  37. //**** IRQ event handler
  38. static void ril_proximity_work_handle(struct work_struct *work)
  39. {
  40. int value;
  41. value = gpio_get_value(SAR_DET_3G);
  42. if (!value)
  43. switch_set_state(&prox_sdev, 1);
  44. else
  45. switch_set_state(&prox_sdev, 0);
  46. }
  47. irqreturn_t ril_proximity_interrupt_handle(int irq, void *dev_id)
  48. {
  49. queue_work(workqueue, &prox_task);
  50. return IRQ_HANDLED;
  51. }
  52. //**** sysfs callback functions
  53. static ssize_t show_prox_enabled(struct device *class,
  54. struct device_attribute *attr, char *buf)
  55. {
  56. return sprintf(buf, "%d\n", proximity_enabled);
  57. }
  58. static ssize_t store_prox_enabled(struct device *class, struct device_attribute *attr,
  59. const char *buf, size_t count)
  60. {
  61. int enable;
  62. if (sscanf(buf, "%u", &enable) != 1)
  63. return -EINVAL;
  64. if ((enable != 1) && (enable != 0))
  65. return -EINVAL;
  66. RIL_INFO("enable: %d\n", enable);
  67. /* when enabled, report the current status immediately.
  68. when disabled, set state to 0 to sync with RIL */
  69. mutex_lock(&prox_enable_mtx);
  70. if (enable != proximity_enabled) {
  71. if (enable) {
  72. enable_irq(gpio_to_irq(SAR_DET_3G));
  73. queue_work(workqueue, &prox_task);
  74. } else {
  75. disable_irq(gpio_to_irq(SAR_DET_3G));
  76. switch_set_state(&prox_sdev, 0);
  77. }
  78. proximity_enabled = enable;
  79. }
  80. mutex_unlock(&prox_enable_mtx);
  81. return strnlen(buf, count);
  82. }
  83. //**** sysfs list
  84. static struct device_attribute device_attr_list[] = {
  85. __ATTR(prox_onoff, _ATTR_MODE, show_prox_enabled, store_prox_enabled),
  86. __ATTR_NULL,
  87. };
  88. //**** initialize and finalize
  89. int ril_proximity_init(struct device *target_device, struct workqueue_struct *queue)
  90. {
  91. u32 project = tegra3_get_project_id();
  92. int rc = 0, i = 0;
  93. dev = target_device;
  94. proximity_enabled = 0;
  95. // init work queue and works
  96. workqueue = queue;
  97. INIT_WORK(&prox_task, ril_proximity_work_handle);
  98. // create sysfses
  99. for (i = 0; i < (ARRAY_SIZE(device_attr_list) - 1); ++i) {
  100. rc = device_create_file(dev, &device_attr_list[i]);
  101. if (rc < 0) {
  102. RIL_ERR("%s: create file of [%d] failed, err = %d\n",
  103. __func__, i, rc);
  104. goto failed_create_sysfs;
  105. }
  106. }
  107. /* register switch class */
  108. prox_sdev.name = NAME_RIL_PROX;
  109. prox_sdev.print_name = print_prox_name;
  110. prox_sdev.print_state = print_prox_state;
  111. rc = switch_dev_register(&prox_sdev);
  112. if (rc < 0)
  113. goto failed_register_switch_class;
  114. return 0;
  115. failed_register_switch_class:
  116. failed_create_sysfs:
  117. while (i >= 0) {
  118. device_remove_file(dev, &device_attr_list[i]);
  119. --i;
  120. }
  121. return rc;
  122. }
  123. void ril_proximity_exit(void)
  124. {
  125. int i = 0;
  126. // destroy switch devices
  127. switch_dev_unregister(&prox_sdev);
  128. // destroy sysfses
  129. for (i = 0; i < (ARRAY_SIZE(device_attr_list) - 1); ++i) {
  130. device_remove_file(dev, &device_attr_list[i]);
  131. }
  132. }