PageRenderTime 31ms CodeModel.GetById 25ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/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
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