/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

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