PageRenderTime 33ms CodeModel.GetById 16ms app.highlight 15ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/ril/ril.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 423 lines | 337 code | 61 blank | 25 comment | 62 complexity | 397e7a141fa701e23ac50759b04a065e MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1#include <linux/delay.h>
  2#include <linux/fs.h>
  3#include <linux/gpio.h>
  4#include <linux/init.h>
  5#include <linux/interrupt.h>
  6#include <linux/module.h>
  7#include <linux/platform_device.h>
  8#include <linux/switch.h>
  9#include <linux/uaccess.h>
 10#include <linux/workqueue.h>
 11#include <../../arch/arm/mach-tegra/include/mach/board-cardhu-misc.h>
 12
 13#include "pm-irq.h"
 14#include "ril.h"
 15#include "ril_proximity.h"
 16#include "ril_wakeup.h"
 17
 18MODULE_DESCRIPTION(DRIVER_DESC);
 19MODULE_LICENSE("GPL");
 20
 21//**** external symbols
 22
 23
 24//**** constants
 25
 26#define _ATTR_MODE S_IRUSR | S_IWUSR | S_IRGRP
 27
 28
 29//**** local variable declaration
 30
 31static struct workqueue_struct *workqueue;
 32static struct device *dev;
 33static struct class *ril_class;
 34static dev_t ril_dev;
 35static int ril_major = 0;
 36static int ril_minor = 0;
 37int project_id = 0;
 38
 39static struct gpio ril_gpios_TF300TG[] = {
 40	{ MOD_VBUS_ON,    GPIOF_OUT_INIT_LOW,  "BB_VBUS"    },
 41	{ USB_SW_SEL,     GPIOF_OUT_INIT_LOW,  "BB_SW_SEL"  },
 42	{ SAR_DET_3G,     GPIOF_IN,            "BB_SAR_DET" },
 43	{ SIM_CARD_DET,   GPIOF_IN,            "BB_SIM_DET" },
 44};
 45
 46static struct gpio ril_gpios_TF300TL[] = {
 47	{ MOD_VBAT_ON,    GPIOF_OUT_INIT_LOW,  "BB_VBAT"},
 48	{ MOD_VBUS_ON,    GPIOF_OUT_INIT_LOW,  "BB_VBUS"},
 49	{ USB_SW_SEL,     GPIOF_OUT_INIT_LOW,  "BB_SW_SEL"},
 50	{ SAR_DET_3G,     GPIOF_IN,            "BB_SAR_DET" },
 51	{ SIM_CARD_DET,   GPIOF_IN,            "BB_SIM_DET" },
 52	{ MOD_POWER_KEY,  GPIOF_OUT_INIT_LOW,  "BB_MOD_PWR"},
 53	{ DL_MODE,        GPIOF_OUT_INIT_LOW,  "BB_DL_MODE"},
 54	{ AP_TO_MOD_RST,  GPIOF_OUT_INIT_LOW,  "BB_MOD_RST"},
 55	{ MOD_WAKE_AP,    GPIOF_IN,            "BB_MOD_WAKE_AP"},
 56	{ MOD_WAKE_IND,   GPIOF_OUT_INIT_HIGH, "BB_MOD_WAKE_IND"},
 57	{ MOD_HANG,       GPIOF_IN,            "BB_MOD_HANG"},
 58	/* no use now */
 59	{ DL_COMPLETE,    GPIOF_OUT_INIT_LOW,  "BB_DL_COMPLETE"},
 60	{ MOD_SUS_REQ,    GPIOF_OUT_INIT_LOW,  "BB_MOD_SUS_REQ"},
 61	{ AP_WAKE_IND,    GPIOF_OUT_INIT_LOW,  "BB_AP_WAKE_IND"},
 62	{ AP_WAKE_MOD,    GPIOF_OUT_INIT_LOW,  "BB_AP_WAKE_MOD"},
 63};
 64
 65//**** IRQ event handler
 66
 67irqreturn_t ril_ipc_sar_det_irq(int irq, void *dev_id)
 68{
 69	return ril_proximity_interrupt_handle(irq, dev_id);
 70}
 71
 72irqreturn_t ril_ipc_sim_det_irq(int irq, void *dev_id)
 73{
 74	// TODO: implement SIM hot-plug here
 75	return IRQ_HANDLED;
 76}
 77
 78//**** sysfs callback functions
 79static int store_gpio(size_t count, const char *buf, int gpio, char *gpio_name)
 80{
 81	int enable;
 82
 83	if (sscanf(buf, "%u", &enable) != 1)
 84		return -EINVAL;
 85
 86	if ((enable != 1) && (enable != 0))
 87		return -EINVAL;
 88
 89	gpio_set_value(gpio, enable);
 90	RIL_INFO("Set %s to %d\n", gpio_name, enable);
 91	return count;
 92}
 93
 94/* TF300TG sysfs functions */
 95static ssize_t show_vbus_state(struct device *class,
 96		struct device_attribute *attr, char *buf)
 97{
 98	return sprintf(buf, "%d\n", gpio_get_value(MOD_VBUS_ON));
 99}
100
101static ssize_t store_vbus_state(struct device *class, struct device_attribute *attr,
102		const char *buf, size_t count)
103{
104	return store_gpio(count, buf, MOD_VBUS_ON, "MOD_VBUS_ON");
105}
106
107/* TF300TL sysfs functions */
108static ssize_t show_power_state(struct device *class, struct device_attribute *attr,
109		char *buf)
110{
111	return sprintf(buf, "%d\n", gpio_get_value(MOD_POWER_KEY));
112}
113
114static ssize_t store_power_state(struct device *class, struct device_attribute *attr,
115		const char *buf, size_t count)
116{
117	return store_gpio(count, buf, MOD_POWER_KEY, "MOD_POWER_KEY");
118}
119
120static ssize_t show_vbat_state(struct device *class, struct device_attribute *attr,
121		char *buf)
122{
123	return sprintf(buf, "%d\n", gpio_get_value(MOD_VBAT_ON));
124}
125
126static ssize_t store_vbat_state(struct device *class, struct device_attribute *attr,
127		const char *buf, size_t count)
128{
129	return store_gpio(count, buf, MOD_VBAT_ON, "MOD_VBAT_ON");
130}
131
132static ssize_t show_reset_state(struct device *class, struct device_attribute *attr,
133		char *buf)
134{
135	return sprintf(buf, "%d\n", gpio_get_value(AP_TO_MOD_RST));
136}
137
138static ssize_t store_reset_state(struct device *class, struct device_attribute *attr,
139		const char *buf, size_t count)
140{
141	return store_gpio(count, buf, AP_TO_MOD_RST, "AP_TO_MOD_RST");
142}
143
144static ssize_t show_download_state(struct device *class, struct device_attribute *attr,
145		char *buf)
146{
147	return sprintf(buf, "%d\n", gpio_get_value(DL_MODE));
148}
149
150static ssize_t store_download_state(struct device *class, struct device_attribute *attr,
151		const char *buf, size_t count)
152{
153	return store_gpio(count, buf, DL_MODE, "DL_MODE");
154}
155
156
157//**** sysfs list
158/* TF300TG sysfs array */
159static struct device_attribute device_attr_TF300TG[] = {
160	__ATTR(bb_vbus, _ATTR_MODE, show_vbus_state, store_vbus_state),
161	__ATTR_NULL,
162};
163
164/* TF300TL sysfs array */
165static struct device_attribute device_attr_TF300TL[] = {
166	__ATTR(mod_power, _ATTR_MODE, show_power_state, store_power_state),
167	__ATTR(vbat, _ATTR_MODE, show_vbat_state, store_vbat_state),
168	__ATTR(mod_rst, _ATTR_MODE, show_reset_state, store_reset_state),
169	__ATTR(dl_mode, _ATTR_MODE, show_download_state, store_download_state),
170	__ATTR_NULL,
171};
172
173//**** initialize and finalize
174
175static int create_ril_files(void)
176{
177	int rc = 0, i = 0;
178
179	rc = alloc_chrdev_region(&ril_dev, ril_minor, 1, "ril");
180	ril_major = MAJOR(ril_dev);
181	if (rc < 0) {
182		RIL_ERR("allocate char device failed\n");
183		goto failed;
184	}
185	RIL_INFO("rc = %d, ril_major = %d\n", rc, ril_major);
186
187	ril_class = class_create(THIS_MODULE, "ril");
188	if (IS_ERR(ril_class)) {
189		RIL_ERR("ril_class create fail\n");
190		rc = PTR_ERR(ril_class);
191		goto create_class_failed;
192	}
193
194	dev = device_create(ril_class, NULL, MKDEV(ril_major, ril_minor),
195			NULL, "files");
196	if (IS_ERR(dev)) {
197		RIL_ERR("dev create fail\n");
198		rc = PTR_ERR(dev);
199		goto create_device_failed;
200	}
201
202	if (project_id == TEGRA3_PROJECT_TF300TG) {
203		for (i = 0; i < (ARRAY_SIZE(device_attr_TF300TG) - 1); i++) {
204			rc = device_create_file(dev, &device_attr_TF300TG[i]);
205			if (rc < 0) {
206				RIL_ERR("create file of [%d] failed, err = %d\n", i, rc);
207				goto create_files_failed;
208			}
209		}
210	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
211		for (i = 0; i < (ARRAY_SIZE(device_attr_TF300TL) - 1); i++) {
212			rc = device_create_file(dev, &device_attr_TF300TL[i]);
213			if (rc < 0) {
214				RIL_ERR("create file of [%d] failed, err = %d\n", i, rc);
215				goto create_files_failed;
216			}
217		}
218	}
219
220	RIL_INFO("add_ril_dev success\n");
221	return 0;
222
223create_files_failed:
224	if (project_id == TEGRA3_PROJECT_TF300TG) {
225		while (i--)
226			device_remove_file(dev, &device_attr_TF300TG[i]);
227	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
228		while (i--)
229			device_remove_file(dev, &device_attr_TF300TL[i]);
230	}
231create_device_failed:
232	class_destroy(ril_class);
233create_class_failed:
234	unregister_chrdev_region(ril_dev, 1);
235failed:
236	return rc;
237}
238
239static void remove_ril_files(void)
240{
241	int i;
242	if (project_id == TEGRA3_PROJECT_TF300TG) {
243		for (i = 0; i < (ARRAY_SIZE(device_attr_TF300TG) - 1); i++)
244			device_remove_file(dev, &device_attr_TF300TG[i]);
245	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
246		for (i = 0; i < (ARRAY_SIZE(device_attr_TF300TL) - 1); i++)
247			device_remove_file(dev, &device_attr_TF300TL[i]);
248	}
249	device_destroy(ril_class, MKDEV(ril_major, ril_minor));
250	class_destroy(ril_class);
251	unregister_chrdev_region(ril_dev, 1);
252}
253
254static void power_on_TF300TL(void)
255{
256	RIL_INFO("TF300TL power_on\n");
257	gpio_set_value(MOD_VBAT_ON, 1);
258	RIL_INFO("Set MOD_VBAT_ON to %d\n", gpio_get_value(MOD_VBAT_ON));
259	mdelay(100);
260	gpio_set_value(MOD_POWER_KEY, 1);
261	RIL_INFO("Set MOD_POWER_KEY to %d\n", gpio_get_value(MOD_POWER_KEY));
262	msleep(200);
263	gpio_set_value(USB_SW_SEL, 1);
264	RIL_INFO("Set USB_SW_SEL to %d\n", gpio_get_value(USB_SW_SEL));
265	mdelay(50);
266	gpio_set_value(MOD_VBUS_ON, 1);
267	RIL_INFO("Set MOD_VBUS_ON to %d\n", gpio_get_value(MOD_VBUS_ON));
268}
269
270static int __init ril_init(void)
271{
272	int err, i;
273	RIL_INFO("RIL init\n");
274
275	project_id = tegra3_get_project_id();
276
277	/* enable and request gpio(s) */
278	if (project_id == TEGRA3_PROJECT_TF300TG) {
279		RIL_INFO("project_id = TF300TG\n");
280		for (i = 0; i < ARRAY_SIZE(ril_gpios_TF300TG); i++) {
281			tegra_gpio_enable(ril_gpios_TF300TG[i].gpio);
282		}
283		err = gpio_request_array(ril_gpios_TF300TG,
284				ARRAY_SIZE(ril_gpios_TF300TG));
285		if (err < 0) {
286			pr_err("%s - request gpio(s) failed\n", __func__);
287			return err;
288		}
289	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
290		RIL_INFO("project_id = TF300TL\n");
291		for (i = 0; i < ARRAY_SIZE(ril_gpios_TF300TL); i++) {
292			tegra_gpio_enable(ril_gpios_TF300TL[i].gpio);
293		}
294		err = gpio_request_array(ril_gpios_TF300TL,
295				ARRAY_SIZE(ril_gpios_TF300TL));
296		if (err < 0) {
297			pr_err("%s - request gpio(s) failed\n", __func__);
298			return err;
299		}
300		mdelay(100);
301		power_on_TF300TL();
302	} else {
303		RIL_ERR("Ril driver doesn't support this project\n");
304		return -1;
305	}
306
307	/* create device file(s) */
308	err = create_ril_files();
309	if (err < 0)
310		goto failed1;
311
312	/* request ril irq(s) */
313	err = request_irq(gpio_to_irq(SAR_DET_3G),
314		ril_ipc_sar_det_irq,
315		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
316		"IPC_SAR_DET_3G",
317		NULL);
318	if (err < 0) {
319		pr_err("%s - request irq IPC_SAR_DET_3G failed\n",
320			__func__);
321		goto failed2;
322	}
323	disable_irq(gpio_to_irq(SAR_DET_3G));
324
325	err = request_irq(gpio_to_irq(SIM_CARD_DET),
326		ril_ipc_sim_det_irq,
327		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
328		"IPC_SIM_CARD_DET",
329		NULL);
330	if (err < 0) {
331		pr_err("%s - request irq IPC_SIM_CARD_DET failed\n",
332			__func__);
333		goto failed3;
334	}
335	tegra_pm_irq_set_wake_type(gpio_to_irq(SIM_CARD_DET),
336		IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING);
337	enable_irq_wake(gpio_to_irq(SIM_CARD_DET));
338
339	/* init work queue */
340	workqueue = create_singlethread_workqueue
341		("ril_workqueue");
342	if (!workqueue) {
343		pr_err("%s - cannot create workqueue\n", __func__);
344		err = -1;
345		goto failed4;
346	}
347
348	/* register proximity switch */
349	err = ril_proximity_init(dev, workqueue);
350	if (err < 0) {
351		pr_err("%s - register proximity switch failed\n",
352			__func__);
353		goto failed5;
354	}
355
356	/* wakeup control (TF-300TL only) */
357	if (TEGRA3_PROJECT_TF300TL == project_id) {
358		err = init_wakeup_control(workqueue);
359		if (err < 0) {
360			RIL_ERR("init wakeup_control failed\n");
361			goto failed6;
362		}
363	}
364
365	RIL_INFO("RIL init successfully\n");
366	return 0;
367
368failed6:
369	ril_proximity_exit();
370failed5:
371	destroy_workqueue(workqueue);
372failed4:
373	free_irq(gpio_to_irq(SIM_CARD_DET), NULL);
374failed3:
375	free_irq(gpio_to_irq(SAR_DET_3G), NULL);
376failed2:
377	remove_ril_files();
378failed1:
379	if (project_id == TEGRA3_PROJECT_TF300TG) {
380		gpio_free_array(ril_gpios_TF300TG,
381				ARRAY_SIZE(ril_gpios_TF300TG));
382	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
383		gpio_free_array(ril_gpios_TF300TL,
384				ARRAY_SIZE(ril_gpios_TF300TL));
385	}
386	return err;
387}
388
389static void __exit ril_exit(void)
390{
391	RIL_INFO("RIL exit\n");
392
393	/* free irq(s) */
394	free_irq(gpio_to_irq(SAR_DET_3G), NULL);
395	free_irq(gpio_to_irq(SIM_CARD_DET), NULL);
396
397	/* free gpio(s) */
398	if (project_id == TEGRA3_PROJECT_TF300TG) {
399		gpio_free_array(ril_gpios_TF300TG,
400				ARRAY_SIZE(ril_gpios_TF300TG));
401	} else if (project_id == TEGRA3_PROJECT_TF300TL) {
402		gpio_free_array(ril_gpios_TF300TL,
403				ARRAY_SIZE(ril_gpios_TF300TL));
404	}
405
406	/* delete device file(s) */
407	remove_ril_files();
408
409	/* unregister proximity switch */
410	ril_proximity_exit();
411
412	/* destroy workqueue */
413	destroy_workqueue(workqueue);
414
415	/* free resources for wakeup control*/
416	if (TEGRA3_PROJECT_TF300TL == project_id) {
417		free_wakeup_control();
418	}
419
420}
421
422module_init(ril_init);
423module_exit(ril_exit);