/drivers/ril/ril_proximity.c
C | 183 lines | 117 code | 51 blank | 15 comment | 17 complexity | 2e0db79285095e4f03d1ab6a9779bbff MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
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 9#include <mach/board-cardhu-misc.h> 10 11#include "baseband-xmm-power.h" 12#include "ril.h" 13#include "ril_proximity.h" 14 15#define NAME_RIL_PROX "ril_proximity" 16 17//**** external symbols 18 19 20//**** constants 21 22#define _ATTR_MODE S_IRUSR | S_IWUSR | S_IRGRP 23 24 25//**** local variable declaration 26 27static DEFINE_MUTEX(prox_enable_mtx); 28 29static struct device *dev; 30 31static struct workqueue_struct *workqueue; 32static struct work_struct prox_task; 33 34static struct switch_dev prox_sdev; 35 36static int proximity_enabled; 37 38//**** callbacks for switch device 39 40static ssize_t print_prox_name(struct switch_dev *sdev, char *buf) 41{ 42 return sprintf(buf, "%s\n", "prox_sar_det"); 43} 44 45static ssize_t print_prox_state(struct switch_dev *sdev, char *buf) 46{ 47 int state = -1; 48 if (switch_get_state(sdev)) 49 state = 1; 50 else 51 state = 0; 52 53 return sprintf(buf, "%d\n", state); 54} 55 56 57//**** IRQ event handler 58 59static void ril_proximity_work_handle(struct work_struct *work) 60{ 61 int value; 62 63 value = gpio_get_value(SAR_DET_3G); 64 if (!value) 65 switch_set_state(&prox_sdev, 1); 66 else 67 switch_set_state(&prox_sdev, 0); 68} 69 70irqreturn_t ril_proximity_interrupt_handle(int irq, void *dev_id) 71{ 72 queue_work(workqueue, &prox_task); 73 74 return IRQ_HANDLED; 75} 76 77//**** sysfs callback functions 78 79static ssize_t show_prox_enabled(struct device *class, 80 struct device_attribute *attr, char *buf) 81{ 82 return sprintf(buf, "%d\n", proximity_enabled); 83} 84 85static ssize_t store_prox_enabled(struct device *class, struct device_attribute *attr, 86 const char *buf, size_t count) 87{ 88 int enable; 89 90 if (sscanf(buf, "%u", &enable) != 1) 91 return -EINVAL; 92 93 if ((enable != 1) && (enable != 0)) 94 return -EINVAL; 95 96 RIL_INFO("enable: %d\n", enable); 97 98 /* when enabled, report the current status immediately. 99 when disabled, set state to 0 to sync with RIL */ 100 mutex_lock(&prox_enable_mtx); 101 if (enable != proximity_enabled) { 102 if (enable) { 103 enable_irq(gpio_to_irq(SAR_DET_3G)); 104 queue_work(workqueue, &prox_task); 105 } else { 106 disable_irq(gpio_to_irq(SAR_DET_3G)); 107 switch_set_state(&prox_sdev, 0); 108 } 109 proximity_enabled = enable; 110 } 111 mutex_unlock(&prox_enable_mtx); 112 113 return strnlen(buf, count); 114} 115 116 117//**** sysfs list 118 119static struct device_attribute device_attr_list[] = { 120 __ATTR(prox_onoff, _ATTR_MODE, show_prox_enabled, store_prox_enabled), 121 __ATTR_NULL, 122}; 123 124 125//**** initialize and finalize 126 127int ril_proximity_init(struct device *target_device, struct workqueue_struct *queue) 128{ 129 u32 project = tegra3_get_project_id(); 130 int rc = 0, i = 0; 131 132 dev = target_device; 133 134 proximity_enabled = 0; 135 136 // init work queue and works 137 workqueue = queue; 138 INIT_WORK(&prox_task, ril_proximity_work_handle); 139 140 // create sysfses 141 for (i = 0; i < (ARRAY_SIZE(device_attr_list) - 1); ++i) { 142 rc = device_create_file(dev, &device_attr_list[i]); 143 if (rc < 0) { 144 RIL_ERR("%s: create file of [%d] failed, err = %d\n", 145 __func__, i, rc); 146 goto failed_create_sysfs; 147 } 148 } 149 150 /* register switch class */ 151 prox_sdev.name = NAME_RIL_PROX; 152 prox_sdev.print_name = print_prox_name; 153 prox_sdev.print_state = print_prox_state; 154 155 rc = switch_dev_register(&prox_sdev); 156 157 if (rc < 0) 158 goto failed_register_switch_class; 159 160 return 0; 161 162failed_register_switch_class: 163failed_create_sysfs: 164 while (i >= 0) { 165 device_remove_file(dev, &device_attr_list[i]); 166 --i; 167 } 168 return rc; 169} 170 171void ril_proximity_exit(void) 172{ 173 int i = 0; 174 175 // destroy switch devices 176 switch_dev_unregister(&prox_sdev); 177 178 // destroy sysfses 179 for (i = 0; i < (ARRAY_SIZE(device_attr_list) - 1); ++i) { 180 device_remove_file(dev, &device_attr_list[i]); 181 } 182} 183