power.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. /*
  2. *viatel_cbp_power.c
  3. *
  4. *VIA CBP driver for Linux
  5. *
  6. *Copyright (C) 2009 VIA TELECOM Corporation, Inc.
  7. *Author: VIA TELECOM Corporation, Inc.
  8. *
  9. *This package is free software; you can redistribute it and/or modify
  10. *it under the terms of the GNU General Public License version 2 as
  11. *published by the Free Software Foundation.
  12. *
  13. *THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14. *IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION,
  15. *THE IMPLIED *WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16. */
  17. #include <linux/ctype.h>
  18. #include <linux/module.h>
  19. #include <linux/fs.h>
  20. #include <linux/fcntl.h>
  21. #include <linux/ioctl.h>
  22. #include <linux/uaccess.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/miscdevice.h>
  25. #include <linux/platform_device.h>
  26. #include <linux/slab.h>
  27. #include <linux/irq.h>
  28. #include <linux/wakelock.h>
  29. #include <linux/delay.h>
  30. #include <linux/gpio.h>
  31. #include <linux/sched.h>
  32. #include <mt-plat/mt_boot.h>
  33. #include <mt-plat/mt_ccci_common.h>
  34. #include "c2k_hw.h"
  35. #include "core.h"
  36. #include "modem_sdio.h"
  37. /*add by yfu to control LDO VGP2*/
  38. /*#include <mach/mt_pm_ldo.h>*/
  39. /*ioctl for vomodem, which must be same as viatelutils.h */
  40. #define CMDM_IOCTL_RESET _IO('c', 0x01)
  41. #define CMDM_IOCTL_POWER _IOW('c', 0x02, int)
  42. #define CMDM_IOCTL_CRL _IOW('c', 0x03, int)
  43. #define CMDM_IOCTL_DIE _IO('c', 0x04)
  44. #define CMDM_IOCTL_WAKE _IO('c', 0x05)
  45. #define CMDM_IOCTL_IGNORE _IOW('c', 0x06, int)
  46. #define CMDM_IOCTL_GET_MD_STATUS _IOR('c', 0x07, int)
  47. #define CMDM_IOCTL_ENTER_FLIGHT_MODE _IO('c', 0x08)
  48. #define CMDM_IOCTL_LEAVE_FLIGHT_MODE _IO('c', 0x09)
  49. #define CMDM_IOCTL_READY _IO('c', 0x0A)
  50. #define CMDM_IOCTL_RESET_PCCIF _IO('c', 0x0B)
  51. #define CMDM_IOCTL_FORCE_ASSERT _IO('c', 0x0C)
  52. #define CMDM_IOCTL_RESET_FROM_RIL _IO('c', 0x0D)
  53. /*reserve some bit*/
  54. #define CMDM_IOCTL_GET_SDIO_STATUS _IO('c', 0x10)
  55. #define CMDM_IOCTL_DUMP_C2K_IRAM _IO('c', 0x11)
  56. /*event for vmodem, which must be same as viatelutilis.h */
  57. enum ASC_USERSPACE_NOTIFIER_CODE {
  58. ASC_USER_USB_WAKE = (__SI_POLL | 100),
  59. ASC_USER_USB_SLEEP,
  60. ASC_USER_UART_WAKE,
  61. ASC_USER_UART_SLEEP,
  62. ASC_USER_SDIO_WAKE,
  63. ASC_USER_SDIO_SLEEP,
  64. ASC_USER_MDM_POWER_ON = (__SI_POLL | 200),
  65. ASC_USER_MDM_POWER_OFF,
  66. ASC_USER_MDM_RESET_ON,
  67. ASC_USER_MDM_RESET_OFF,
  68. ASC_USER_MDM_ERR = (__SI_POLL | 300),
  69. ASC_USER_MDM_ERR_ENHANCE,
  70. ASC_USER_MDM_IPOH = (__SI_POLL | 400),
  71. ASC_USER_MDM_WDT,
  72. ASC_USER_MDM_EXCEPTION,
  73. };
  74. #define MDM_RST_LOCK_TIME (120)
  75. #define MDM_EXCP_LOCK_TIME (120)
  76. #define MDM_RST_HOLD_DELAY (100) /*ms */
  77. #define MDM_PWR_HOLD_DELAY (500) /*ms */
  78. struct c2k_modem_data {
  79. struct fasync_struct *fasync;
  80. struct kobject *modem_kobj;
  81. struct raw_notifier_head ntf;
  82. struct notifier_block rst_ntf;
  83. struct notifier_block pwr_ntf;
  84. struct notifier_block err_ntf;
  85. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  86. struct notifier_block wdt_ntf;
  87. struct notifier_block excp_ntf;
  88. #endif
  89. struct wake_lock wlock;
  90. struct work_struct work;
  91. atomic_t count;
  92. unsigned long ntf_flags;
  93. struct sdio_modem *modem;
  94. };
  95. static struct c2k_modem_data *cmdata;
  96. static unsigned char via_ignore_notifier;
  97. static atomic_t reset_on_going;
  98. static atomic_t modem_not_ready;
  99. int c2k_modem_not_ready(void)
  100. {
  101. return atomic_read(&modem_not_ready);
  102. }
  103. static void modem_signal_user(int event)
  104. {
  105. if (cmdata && cmdata->fasync) {
  106. pr_debug("%s: evnet %d.\n", __func__, (short)event);
  107. kill_fasync(&cmdata->fasync, SIGIO, event);
  108. }
  109. }
  110. /*Protection for the above */
  111. static DEFINE_RAW_SPINLOCK(rslock);
  112. void c2k_reset_modem(void)
  113. {
  114. unsigned long flags;
  115. if (atomic_add_return(1, &reset_on_going) > 1) {
  116. pr_debug("[C2K] %s: one reset on going, %d\n", __func__,
  117. atomic_read(&reset_on_going));
  118. return;
  119. }
  120. atomic_set(&modem_not_ready, 1);
  121. wake_lock_timeout(&cmdata->wlock, MDM_RST_LOCK_TIME * HZ);
  122. pr_debug("[C2K] %s: set md reset.\n", __func__);
  123. spin_lock_irqsave(&cmdata->modem->status_lock, flags);
  124. cmdata->modem->status = MD_OFF;
  125. spin_unlock_irqrestore(&cmdata->modem->status_lock, flags);
  126. atomic_set(&cmdata->modem->tx_fifo_cnt, TX_FIFO_SZ);
  127. wake_up_all(&cmdata->modem->wait_tx_done_q);
  128. modem_pre_stop();
  129. c2k_wake_host(0);
  130. c2k_modem_reset_platform();
  131. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST)) {
  132. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 1);
  133. c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 1);
  134. mdelay(MDM_RST_HOLD_DELAY);
  135. c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 0);
  136. mdelay(MDM_RST_HOLD_DELAY);
  137. }
  138. modem_notify_event(MDM_EVT_NOTIFY_RESET_ON);
  139. pr_debug("[C2K] Warnning: reset vmodem\n");
  140. atomic_set(&reset_on_going, 0);
  141. }
  142. void c2k_power_on_modem(void)
  143. {
  144. /*add by yfu to control LDO VGP2 */
  145. /*turn on VGP2 and set 2.8v */
  146. /*hwPowerOn(MT6323_POWER_LDO_VGP2, VOL_2800,"VIA"); */
  147. c2k_modem_power_on_platform();
  148. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_EN)) {
  149. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST)) {
  150. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 1);
  151. c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 0);
  152. mdelay(MDM_RST_HOLD_DELAY);
  153. }
  154. c2k_gpio_direction_output(GPIO_C2K_MDM_PWR_EN, 1);
  155. mdelay(MDM_PWR_HOLD_DELAY);
  156. }
  157. pr_debug("[C2K] Warnning: power on vmodem\n");
  158. }
  159. void c2k_power_off_modem(void)
  160. {
  161. unsigned long flags;
  162. if (atomic_add_return(1, &reset_on_going) > 1) {
  163. pr_debug("[C2K] %s: one power off on going, %d\n", __func__,
  164. atomic_read(&reset_on_going));
  165. return;
  166. }
  167. atomic_set(&modem_not_ready, 1);
  168. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_EN))
  169. c2k_gpio_direction_output(GPIO_C2K_MDM_PWR_EN, 0);
  170. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST)) {
  171. c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 1);
  172. /*just hold the reset pin if no power enable pin */
  173. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_EN)) {
  174. mdelay(MDM_RST_HOLD_DELAY);
  175. c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 0);
  176. }
  177. }
  178. /*add by yfu to control LDO VGP2 */
  179. /*turn off VGP2 */
  180. /*hwPowerDown(MT6323_POWER_LDO_VGP2, "VIA"); */
  181. pr_debug("[C2K] %s: set md off.\n", __func__);
  182. spin_lock_irqsave(&cmdata->modem->status_lock, flags);
  183. cmdata->modem->status = MD_OFF;
  184. spin_unlock_irqrestore(&cmdata->modem->status_lock, flags);
  185. atomic_set(&cmdata->modem->tx_fifo_cnt, TX_FIFO_SZ);
  186. wake_up_all(&cmdata->modem->wait_tx_done_q);
  187. modem_pre_stop();
  188. c2k_wake_host(0);
  189. c2k_modem_power_off_platform();
  190. pr_debug("[C2K] Warnning: power off vmodem\n");
  191. atomic_set(&reset_on_going, 0);
  192. }
  193. ssize_t modem_power_show(struct kobject *kobj, struct kobj_attribute *attr,
  194. char *buf)
  195. {
  196. int power = 0;
  197. int ret = 0;
  198. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_IND)) {
  199. power = !!c2k_gpio_get_value(GPIO_C2K_MDM_PWR_IND);
  200. } else if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_EN)) {
  201. pr_debug("No MDM_PWR_IND, just detect MDM_PWR_EN\n");
  202. power = !!c2k_gpio_get_value(GPIO_C2K_MDM_PWR_EN);
  203. } else if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST)) {
  204. pr_debug("No MDM_PWR_IND, just detect MDM_PWR_RST\n");
  205. power = !!c2k_gpio_get_value(GPIO_C2K_MDM_RST);
  206. }
  207. if (power)
  208. ret += sprintf(buf + ret, "on\n");
  209. else
  210. ret += sprintf(buf + ret, "off\n");
  211. return ret;
  212. }
  213. ssize_t modem_power_store(struct kobject *kobj, struct kobj_attribute *attr,
  214. const char *buf, size_t n)
  215. {
  216. int power;
  217. /*power the modem */
  218. if (!strncmp(buf, "on", strlen("on")))
  219. power = 1;
  220. else if (!strncmp(buf, "off", strlen("off"))) {
  221. power = 0;
  222. } else {
  223. pr_debug("%s: input %s is invalid.\n", __func__, buf);
  224. return n;
  225. }
  226. if (power) {
  227. c2k_power_on_modem();
  228. modem_notify_event(MDM_EVT_NOTIFY_RESET_ON);
  229. } else {
  230. c2k_power_off_modem();
  231. }
  232. return n;
  233. }
  234. ssize_t modem_reset_show(struct kobject *kobj, struct kobj_attribute *attr,
  235. char *buf)
  236. {
  237. int reset = 0;
  238. int ret = 0;
  239. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST_IND))
  240. reset = !!c2k_gpio_get_value(GPIO_C2K_MDM_RST_IND);
  241. else if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST))
  242. reset = !!c2k_gpio_get_value(GPIO_C2K_MDM_RST);
  243. if (reset)
  244. ret += sprintf(buf + ret, "reset\n");
  245. else
  246. ret += sprintf(buf + ret, "work\n");
  247. return ret;
  248. }
  249. ssize_t modem_reset_store(struct kobject *kobj, struct kobj_attribute *attr,
  250. const char *buf, size_t n)
  251. {
  252. /*reset the modem */
  253. c2k_reset_modem();
  254. return n;
  255. }
  256. ssize_t modem_ets_select_show(struct kobject *kobj,
  257. struct kobj_attribute *attr, char *buf)
  258. {
  259. int level = 0;
  260. int ret = 0;
  261. if (GPIO_C2K_VALID(GPIO_C2K_MDM_ETS_SEL))
  262. level = !!c2k_gpio_get_value(GPIO_C2K_MDM_ETS_SEL);
  263. ret += sprintf(buf, "%d\n", level);
  264. return ret;
  265. }
  266. ssize_t modem_ets_select_store(struct kobject *kobj,
  267. struct kobj_attribute *attr, const char *buf,
  268. size_t n)
  269. {
  270. if (GPIO_C2K_VALID(GPIO_C2K_MDM_ETS_SEL)) {
  271. if (!strncmp(buf, "1", strlen("1")))
  272. c2k_gpio_direction_output(GPIO_C2K_MDM_ETS_SEL, 1);
  273. else if (!strncmp(buf, "0", strlen("0")))
  274. c2k_gpio_direction_output(GPIO_C2K_MDM_ETS_SEL, 0);
  275. else
  276. pr_debug("Unknown command.\n");
  277. }
  278. return n;
  279. }
  280. ssize_t modem_boot_select_show(struct kobject *kobj,
  281. struct kobj_attribute *attr, char *buf)
  282. {
  283. int ret = 0;
  284. int level = 0;
  285. if (GPIO_C2K_VALID(GPIO_C2K_MDM_BOOT_SEL))
  286. level = !!c2k_gpio_get_value(GPIO_C2K_MDM_BOOT_SEL);
  287. ret += sprintf(buf, "%d\n", level);
  288. return ret;
  289. }
  290. ssize_t modem_boot_select_store(struct kobject *kobj,
  291. struct kobj_attribute *attr, const char *buf,
  292. size_t n)
  293. {
  294. if (GPIO_C2K_VALID(GPIO_C2K_MDM_BOOT_SEL)) {
  295. if (!strncmp(buf, "1", strlen("1")))
  296. c2k_gpio_direction_output(GPIO_C2K_MDM_BOOT_SEL, 1);
  297. else if (!strncmp(buf, "0", strlen("0")))
  298. c2k_gpio_direction_output(GPIO_C2K_MDM_BOOT_SEL, 0);
  299. else
  300. pr_debug("Unknown command.\n");
  301. }
  302. return n;
  303. }
  304. int modem_err_indication_usr(int revocery)
  305. {
  306. pr_debug("%s %d revocery=%d\n", __func__, __LINE__, revocery);
  307. if (revocery) {
  308. pr_debug("%s %d MDM_EVT_NOTIFY_HD_ERR\n", __func__, __LINE__);
  309. modem_notify_event(MDM_EVT_NOTIFY_HD_ERR);
  310. } else {
  311. pr_debug("%s %d MDM_EVT_NOTIFY_HD_ENHANCE\n", __func__,
  312. __LINE__);
  313. modem_notify_event(MDM_EVT_NOTIFY_HD_ENHANCE);
  314. }
  315. return 0;
  316. }
  317. int modem_ipoh_indication_usr(void)
  318. {
  319. pr_debug("%s %d MDM_EVT_NOTIFY_IPOH\n", __func__, __LINE__);
  320. /*c2k_gpio_set_irq_type(GPIO_C2K_MDM_RST_IND, IRQF_TRIGGER_FALLING); */
  321. modem_notify_event(MDM_EVT_NOTIFY_IPOH);
  322. return 0;
  323. }
  324. void c2k_let_cbp_die(void)
  325. {
  326. if (GPIO_C2K_VALID(GPIO_C2K_CRASH_CBP)) {
  327. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 0);
  328. mdelay(MDM_RST_HOLD_DELAY);
  329. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 1);
  330. }
  331. pr_debug("let cbp die\n");
  332. }
  333. ssize_t modem_diecbp_show(struct kobject *kobj, struct kobj_attribute *attr,
  334. char *buf)
  335. {
  336. int ret = 0;
  337. int level = 0;
  338. if (GPIO_C2K_VALID(GPIO_C2K_CRASH_CBP))
  339. level = !!c2k_gpio_get_value(GPIO_C2K_CRASH_CBP);
  340. ret += sprintf(buf, "%d\n", level);
  341. return ret;
  342. }
  343. ssize_t modem_diecbp_store(struct kobject *kobj, struct kobj_attribute *attr,
  344. const char *buf, size_t n)
  345. {
  346. if (GPIO_C2K_VALID(GPIO_C2K_CRASH_CBP)) {
  347. if (!strncmp(buf, "1", strlen("1")))
  348. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 1);
  349. else if (!strncmp(buf, "0", strlen("0")))
  350. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 0);
  351. else
  352. pr_debug("Unknown command.\n");
  353. } else
  354. pr_debug("invalid gpio.\n");
  355. return n;
  356. }
  357. ssize_t modem_hderr_show(struct kobject *kobj, struct kobj_attribute *attr,
  358. char *buf)
  359. {
  360. int ret = 0;
  361. int level = 0;
  362. if (GPIO_C2K_VALID(GPIO_C2K_CRASH_CBP))
  363. level = !!c2k_gpio_get_value(GPIO_C2K_CRASH_CBP);
  364. ret += sprintf(buf, "%d\n", level);
  365. return ret;
  366. }
  367. ssize_t modem_hderr_store(struct kobject *kobj, struct kobj_attribute *attr,
  368. const char *buf, size_t n)
  369. {
  370. pr_debug("signal modem_err_indication_usr\n");
  371. if (!strncmp(buf, "1", strlen("1")))
  372. modem_err_indication_usr(1);
  373. else if (!strncmp(buf, "0", strlen("0")))
  374. modem_err_indication_usr(0);
  375. else
  376. pr_debug("Unknown command.\n");
  377. return n;
  378. }
  379. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  380. ssize_t modem_force_assert_store(struct kobject *kobj,
  381. struct kobj_attribute *attr, const char *buf,
  382. size_t n)
  383. {
  384. if (cmdata->modem)
  385. force_c2k_assert(cmdata->modem);
  386. return n;
  387. }
  388. ssize_t modem_force_assert_show(struct kobject *kobj,
  389. struct kobj_attribute *attr, char *buf)
  390. {
  391. int ret = 0;
  392. ret += sprintf(buf + ret, "capable\n");
  393. return ret;
  394. }
  395. #endif
  396. static int modem_reset_notify_misc(struct notifier_block *nb,
  397. unsigned long event, void *ptr)
  398. {
  399. int ret = 0;
  400. if (via_ignore_notifier) {
  401. pr_debug
  402. ("Warnning: via ignore notifer just return NOTIFY_OK.\n");
  403. return NOTIFY_OK;
  404. }
  405. switch (event) {
  406. case MDM_EVT_NOTIFY_RESET_ON:
  407. modem_signal_user(ASC_USER_MDM_RESET_ON);
  408. break;
  409. case MDM_EVT_NOTIFY_RESET_OFF:
  410. modem_signal_user(ASC_USER_MDM_RESET_OFF);
  411. break;
  412. default:
  413. break;
  414. }
  415. return ret ? NOTIFY_DONE : NOTIFY_OK;
  416. }
  417. static int modem_power_notify_misc(struct notifier_block *nb,
  418. unsigned long event, void *ptr)
  419. {
  420. switch (event) {
  421. case MDM_EVT_NOTIFY_POWER_ON:
  422. modem_signal_user(ASC_USER_MDM_POWER_ON);
  423. break;
  424. case MDM_EVT_NOTIFY_POWER_OFF:
  425. modem_signal_user(ASC_USER_MDM_POWER_OFF);
  426. break;
  427. default:
  428. break;
  429. }
  430. return NOTIFY_OK;
  431. }
  432. static int modem_err_notify_misc(struct notifier_block *nb, unsigned long event,
  433. void *ptr)
  434. {
  435. pr_debug("%s %d event=%ld\n", __func__, __LINE__, event);
  436. switch (event) {
  437. case MDM_EVT_NOTIFY_HD_ERR:
  438. pr_debug("%s %d ASC_USER_MDM_ERR\n", __func__, __LINE__);
  439. modem_signal_user(ASC_USER_MDM_ERR);
  440. break;
  441. case MDM_EVT_NOTIFY_HD_ENHANCE:
  442. pr_debug("%s %d ASC_USER_MDM_ERR_ENHANCE\n", __func__,
  443. __LINE__);
  444. modem_signal_user(ASC_USER_MDM_ERR_ENHANCE);
  445. break;
  446. case MDM_EVT_NOTIFY_IPOH:
  447. pr_debug("%s %d MDM_EVT_NOTIFY_IPOH\n", __func__, __LINE__);
  448. modem_signal_user(ASC_USER_MDM_IPOH);
  449. break;
  450. default:
  451. break;
  452. }
  453. return NOTIFY_OK;
  454. }
  455. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  456. static int modem_wdt_notify_misc(struct notifier_block *nb, unsigned long event,
  457. void *ptr)
  458. {
  459. pr_debug("%s %d event=%ld\n", __func__, __LINE__, event);
  460. switch (event) {
  461. case MDM_EVT_NOTIFY_WDT:
  462. pr_debug("%s %d ASC_USER_MDM_WDT\n", __func__, __LINE__);
  463. modem_signal_user(ASC_USER_MDM_WDT);
  464. #ifdef CONFIG_MTK_SVLTE_SUPPORT
  465. exec_ccci_kern_func_by_md_id(0, ID_RESET_MD, NULL, 0);
  466. #endif
  467. break;
  468. default:
  469. break;
  470. }
  471. return NOTIFY_OK;
  472. }
  473. static int modem_excp_notify_misc(struct notifier_block *nb,
  474. unsigned long event, void *ptr)
  475. {
  476. pr_debug("%s %d event=%ld\n", __func__, __LINE__, event);
  477. switch (event) {
  478. case MDM_EVT_NOTIFY_EXCP:
  479. pr_debug("%s %d ASC_USER_MDM_EXCEPTION\n", __func__, __LINE__);
  480. modem_signal_user(ASC_USER_MDM_EXCEPTION);
  481. break;
  482. default:
  483. break;
  484. }
  485. return NOTIFY_OK;
  486. }
  487. #endif
  488. #define modem_attr(_name) \
  489. static struct kobj_attribute _name##_attr = { \
  490. .attr = { \
  491. .name = __stringify(_name), \
  492. .mode = 0640, \
  493. }, \
  494. .show = modem_##_name##_show, \
  495. .store = modem_##_name##_store, \
  496. }
  497. modem_attr(power);
  498. modem_attr(reset);
  499. modem_attr(ets_select);
  500. modem_attr(boot_select);
  501. modem_attr(diecbp);
  502. modem_attr(hderr);
  503. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  504. modem_attr(force_assert);
  505. #endif
  506. static struct attribute *g_attr[] = {
  507. &power_attr.attr,
  508. &reset_attr.attr,
  509. &ets_select_attr.attr,
  510. &boot_select_attr.attr,
  511. &diecbp_attr.attr,
  512. &hderr_attr.attr,
  513. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  514. &force_assert_attr.attr,
  515. #endif
  516. NULL
  517. };
  518. static struct attribute_group g_attr_group = {
  519. .attrs = g_attr,
  520. };
  521. static void modem_shutdown(struct platform_device *dev)
  522. {
  523. /*c2k_power_off_modem();*/
  524. }
  525. /*
  526. *Notify about a modem event change.
  527. *
  528. */
  529. static void modem_notify_task(struct work_struct *work)
  530. {
  531. int i = 0;
  532. for (i = 0; i < MDM_EVT_NOTIFY_NUM; i++) {
  533. if (test_and_clear_bit(i, &cmdata->ntf_flags))
  534. raw_notifier_call_chain(&cmdata->ntf, i, NULL);
  535. }
  536. }
  537. void modem_notify_event(int event)
  538. {
  539. if (cmdata && event < MDM_EVT_NOTIFY_NUM) {
  540. set_bit(event, &cmdata->ntf_flags);
  541. schedule_work(&cmdata->work);
  542. }
  543. }
  544. /*
  545. *register a modem events change listener
  546. */
  547. int modem_register_notifier(struct notifier_block *nb)
  548. {
  549. int ret = -ENODEV;
  550. unsigned long flags;
  551. if (cmdata) {
  552. raw_spin_lock_irqsave(&rslock, flags);
  553. ret = raw_notifier_chain_register(&cmdata->ntf, nb);
  554. raw_spin_unlock_irqrestore(&rslock, flags);
  555. }
  556. return ret;
  557. }
  558. /*
  559. *unregister a modem events change listener
  560. */
  561. int modem_unregister_notifier(struct notifier_block *nb)
  562. {
  563. int ret = -ENODEV;
  564. unsigned long flags;
  565. if (cmdata) {
  566. raw_spin_lock_irqsave(&rslock, flags);
  567. ret = raw_notifier_chain_unregister(&cmdata->ntf, nb);
  568. raw_spin_unlock_irqrestore(&rslock, flags);
  569. }
  570. return ret;
  571. }
  572. static irqreturn_t modem_reset_indication_irq(int irq, void *data)
  573. {
  574. pr_debug("[C2K MODEM] %s %d\n", __func__, __LINE__);
  575. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  576. c2k_gpio_to_ls(GPIO_C2K_MDM_RST_IND);
  577. #endif
  578. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST_IND)) {
  579. /*c2k_gpio_set_irq_type(GPIO_C2K_MDM_RST_IND, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); */
  580. if (c2k_gpio_get_value(GPIO_C2K_MDM_RST_IND)) {
  581. pr_debug("[C2K] %s %d ON, md is off now...\n", __func__,
  582. __LINE__);
  583. wake_lock_timeout(&cmdata->wlock,
  584. MDM_RST_LOCK_TIME * HZ);
  585. /*#ifdef CONFIG_EVDO_DT_VIA_SUPPORT*/
  586. modem_notify_event(MDM_EVT_NOTIFY_RESET_ON);
  587. /*#endif*/
  588. } else {
  589. pr_debug("%s %d OFF, md is on now...\n", __func__,
  590. __LINE__);
  591. /*#ifdef CONFIG_EVDO_DT_VIA_SUPPORT*/
  592. modem_notify_event(MDM_EVT_NOTIFY_RESET_OFF);
  593. /*#endif*/
  594. }
  595. }
  596. gpio_irq_cbp_rst_ind();
  597. #if defined(CONFIG_MTK_LEGACY)
  598. c2k_gpio_irq_unmask(GPIO_C2K_MDM_RST_IND);
  599. #endif
  600. return IRQ_HANDLED;
  601. }
  602. static irqreturn_t modem_power_indication_irq(int irq, void *data)
  603. {
  604. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_IND)) {
  605. c2k_gpio_set_irq_type(GPIO_C2K_MDM_PWR_IND,
  606. IRQF_TRIGGER_RISING |
  607. IRQF_TRIGGER_FALLING);
  608. if (c2k_gpio_get_value(GPIO_C2K_MDM_PWR_IND))
  609. modem_notify_event(MDM_EVT_NOTIFY_POWER_ON);
  610. else
  611. modem_notify_event(MDM_EVT_NOTIFY_POWER_OFF);
  612. }
  613. return IRQ_HANDLED;
  614. }
  615. /*enable if support 4 pin sync in userspace*/
  616. #if 0 /*defined(CONFIG_C2KECOM_SYNC_CBP) */
  617. static int modem_userspace_notifier(int msg, void *data)
  618. {
  619. int ret = 0;
  620. int wake, sleep;
  621. char *hd = (char *)data;
  622. if (!hd) {
  623. pr_debug("%s:error sync user\n", __func__);
  624. return -ENODEV;
  625. }
  626. if (!strncmp(hd, USB_RX_HD_NAME, ASC_NAME_LEN)) {
  627. wake = ASC_USER_USB_WAKE;
  628. sleep = ASC_USER_USB_SLEEP;
  629. } else if (!strncmp(hd, UART_RX_HD_NAME, ASC_NAME_LEN)) {
  630. wake = ASC_USER_UART_WAKE;
  631. sleep = ASC_USER_UART_SLEEP;
  632. } else if (!strncmp(hd, SDIO_RX_HD_NAME, ASC_NAME_LEN)) {
  633. wake = ASC_USER_SDIO_WAKE;
  634. sleep = ASC_USER_SDIO_SLEEP;
  635. } else {
  636. return -ENODEV;
  637. }
  638. if (!atomic_read(&cmdata->count))
  639. return 0;
  640. switch (msg) {
  641. case ASC_NTF_RX_PREPARE:
  642. modem_signal_user(wake);
  643. break;
  644. case ASC_NTF_RX_POST:
  645. modem_signal_user(sleep);
  646. break;
  647. default:
  648. pr_debug("%s Unknown message %d\n", __func__, msg);
  649. }
  650. return ret;
  651. }
  652. static int modem_sync_init(void)
  653. {
  654. int ret = 0;
  655. struct asc_infor user;
  656. struct asc_config cfg;
  657. /*Registe the cbp tx handle */
  658. if (GPIO_C2K_VALID(GPIO_C2K_AP_WAKE_MDM)
  659. && GPIO_c2k_VALID(GPIO_C2K_MDM_RDY)) {
  660. memset(&cfg, 0, sizeof(struct asc_config));
  661. strncpy(cfg.name, CBP_TX_HD_NAME, ASC_NAME_LEN);
  662. cfg.gpio_wake = GPIO_C2K_AP_WAKE_MDM;
  663. cfg.gpio_ready = GPIO_C2K_MDM_RDY;
  664. cfg.polar = 1;
  665. ret = asc_tx_register_handle(&cfg);
  666. if (ret < 0) {
  667. pr_debug("%s: fail to regist tx handle %s\n", __func__,
  668. CBP_TX_HD_NAME);
  669. goto end_sync_init;
  670. }
  671. }
  672. /*Registe the usb rx handle */
  673. if (GPIO_C2K_VALID(GPIO_C2K_USB_MDM_WAKE_AP)
  674. && GPIO_C2K_VALID(GPIO_C2K_USB_AP_RDY)) {
  675. memset(&cfg, 0, sizeof(struct asc_config));
  676. strncpy(cfg.name, USB_RX_HD_NAME, ASC_NAME_LEN);
  677. cfg.gpio_wake = GPIO_C2K_USB_MDM_WAKE_AP;
  678. cfg.gpio_ready = GPIO_C2K_USB_AP_RDY;
  679. cfg.polar = 1;
  680. ret = asc_rx_register_handle(&cfg);
  681. if (ret < 0) {
  682. pr_debug("%s: fail to regist rx handle %s\n", __func__,
  683. USB_RX_HD_NAME);
  684. goto end_sync_init;
  685. }
  686. memset(&user, 0, sizeof(struct asc_infor));
  687. user.notifier = modem_userspace_notifier,
  688. user.data = USB_RX_HD_NAME,
  689. snprintf(user.name, ASC_NAME_LEN, USB_RX_USER_NAME);
  690. ret = asc_rx_add_user(USB_RX_HD_NAME, &user);
  691. if (ret < 0) {
  692. pr_debug("%s: fail to regist rx user %s\n", __func__,
  693. USB_RX_USER_NAME);
  694. goto end_sync_init;
  695. }
  696. }
  697. /*Registe the uart rx handle */
  698. if (GPIO_OEM_VALID(GPIO_C2K_UART_MDM_WAKE_AP)
  699. && GPIO_OEM_VALID(GPIO_C2K_UART_AP_RDY)) {
  700. memset(&cfg, 0, sizeof(struct asc_config));
  701. strncpy(cfg.name, UART_RX_HD_NAME, ASC_NAME_LEN);
  702. cfg.gpio_wake = GPIO_C2K_UART_MDM_WAKE_AP;
  703. cfg.gpio_ready = GPIO_C2K_UART_AP_RDY;
  704. cfg.polar = 1;
  705. ret = asc_rx_register_handle(&cfg);
  706. if (ret < 0) {
  707. pr_debug("%s: fail to regist rx handle %s\n", __func__,
  708. UART_RX_HD_NAME);
  709. goto end_sync_init;
  710. }
  711. memset(&user, 0, sizeof(struct asc_infor));
  712. user.notifier = modem_userspace_notifier,
  713. user.data = UART_RX_HD_NAME,
  714. snprintf(user.name, ASC_NAME_LEN, UART_RX_USER_NAME);
  715. ret = asc_rx_add_user(UART_RX_HD_NAME, &user);
  716. if (ret < 0) {
  717. pr_debug("%s: fail to regist rx user %s\n", __func__,
  718. UART_RX_USER_NAME);
  719. goto end_sync_init;
  720. }
  721. }
  722. end_sync_init:
  723. if (ret)
  724. pr_debug("%s: error\n", __func__);
  725. return ret;
  726. }
  727. late_initcall(modem_sync_init);
  728. #endif
  729. static struct platform_driver platform_modem_driver = {
  730. .driver.name = "c2k_modem",
  731. .shutdown = modem_shutdown,
  732. };
  733. static struct platform_device platform_modem_device = {
  734. .name = "c2k_modem",
  735. };
  736. static int misc_modem_open(struct inode *inode, struct file *filp)
  737. {
  738. int ret = -ENODEV;
  739. if (cmdata) {
  740. filp->private_data = cmdata;
  741. atomic_inc(&cmdata->count);
  742. ret = 0;
  743. }
  744. return ret;
  745. }
  746. static long misc_modem_ioctl(struct file *file, unsigned int
  747. cmd, unsigned long arg)
  748. {
  749. void __user *argp = (void __user *)arg;
  750. int flag, ret = -1;
  751. switch (cmd) {
  752. case CMDM_IOCTL_RESET:
  753. pr_debug("[C2K]Reset C2K.\n");
  754. c2k_reset_modem();
  755. break;
  756. case CMDM_IOCTL_READY:
  757. pr_debug("[C2K SDIO]modem boot up done.\n");
  758. atomic_set(&modem_not_ready, 0);
  759. break;
  760. case CMDM_IOCTL_RESET_PCCIF:
  761. pr_debug("[C2K SDIO]reset PCCIF\n");
  762. c2k_modem_reset_pccif();
  763. break;
  764. case CMDM_IOCTL_RESET_FROM_RIL:
  765. pr_debug("[C2K]Reset C2K from RIL.\n");
  766. c2k_reset_modem();
  767. #ifdef CONFIG_MTK_SVLTE_SUPPORT
  768. exec_ccci_kern_func_by_md_id(0, ID_RESET_MD, NULL, 0);
  769. #endif
  770. break;
  771. case CMDM_IOCTL_POWER:
  772. if (copy_from_user(&flag, argp, sizeof(flag)))
  773. return -EFAULT;
  774. pr_debug("[C2K]power C2K for %d.\n", flag);
  775. switch (flag) {
  776. case 0:
  777. c2k_power_off_modem();
  778. break;
  779. case 1:
  780. c2k_power_on_modem();
  781. break;
  782. case 2:
  783. c2k_power_off_modem();
  784. #ifdef CONFIG_MTK_SVLTE_SUPPORT
  785. exec_ccci_kern_func_by_md_id(0, ID_RESET_MD, NULL, 0);
  786. #endif
  787. break;
  788. default:
  789. return -EINVAL;
  790. }
  791. break;
  792. case CMDM_IOCTL_CRL:
  793. if (copy_from_user(&flag, argp, sizeof(flag)))
  794. return -EFAULT;
  795. if (flag < 0 || flag > 1)
  796. return -EINVAL;
  797. if (flag)
  798. ret = modem_on_off_ctrl_chan(1);
  799. else
  800. ret = modem_on_off_ctrl_chan(0);
  801. break;
  802. case CMDM_IOCTL_DIE:
  803. c2k_let_cbp_die();
  804. break;
  805. case CMDM_IOCTL_WAKE:
  806. if (copy_from_user(&flag, argp, sizeof(flag)))
  807. return -EFAULT;
  808. if (flag < 0 || flag > 1)
  809. return -EINVAL;
  810. if (flag) {
  811. pr_debug("hold on wakelock.\n");
  812. wake_lock(&cmdata->wlock);
  813. } else {
  814. pr_debug("release wakelock.\n");
  815. wake_unlock(&cmdata->wlock);
  816. }
  817. break;
  818. case CMDM_IOCTL_IGNORE:
  819. if (copy_from_user(&flag, argp, sizeof(flag)))
  820. return -EFAULT;
  821. if (flag < 0 || flag > 1)
  822. return -EINVAL;
  823. if (flag) {
  824. pr_debug("Warnning: via ignore notifer.\n");
  825. via_ignore_notifier = 1;
  826. } else {
  827. pr_debug("Warnning: via receive notifer.\n");
  828. via_ignore_notifier = 0;
  829. }
  830. break;
  831. case CMDM_IOCTL_GET_MD_STATUS:
  832. if (cmdata->modem)
  833. ret =
  834. put_user((unsigned int)cmdata->modem->status,
  835. (unsigned int __user *)arg);
  836. else
  837. return -EFAULT;
  838. break;
  839. case CMDM_IOCTL_ENTER_FLIGHT_MODE:
  840. pr_debug("[C2K SDIO]enter flight mode.\n");
  841. if (!GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_IND))
  842. modem_notify_event(MDM_EVT_NOTIFY_POWER_OFF);
  843. c2k_power_off_modem();
  844. asc_rx_reset(SDIO_RX_HD_NAME); /*to let AP release Rx wakelock */
  845. break;
  846. case CMDM_IOCTL_LEAVE_FLIGHT_MODE:
  847. pr_debug("[C2K SDIO]leave flight mode.\n");
  848. c2k_power_on_modem();
  849. modem_notify_event(MDM_EVT_NOTIFY_RESET_ON);
  850. break;
  851. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  852. case CMDM_IOCTL_FORCE_ASSERT:
  853. pr_debug("[C2K SDIO]force C2K assert ioctl.\n");
  854. if (cmdata->modem)
  855. force_c2k_assert(cmdata->modem);
  856. break;
  857. #endif
  858. case CMDM_IOCTL_GET_SDIO_STATUS:
  859. pr_debug("[C2K SDIO]get sdio status.\n");
  860. if (cmdata->modem)
  861. dump_c2k_sdio_status(cmdata->modem);
  862. break;
  863. case CMDM_IOCTL_DUMP_C2K_IRAM:
  864. pr_debug("[C2K SDIO]dump c2k iram.\n");
  865. dump_c2k_iram_seg2();
  866. break;
  867. default:
  868. break;
  869. }
  870. return 0;
  871. }
  872. #ifdef CONFIG_COMPAT
  873. static long misc_modem_compat_ioctl(struct file *filp, unsigned int cmd,
  874. unsigned long arg)
  875. {
  876. if (!filp->f_op || !filp->f_op->unlocked_ioctl) {
  877. printk
  878. ("[SDIO MODEM]!filp->f_op || !filp->f_op->unlocked_ioctl)\n");
  879. return -ENOTTY;
  880. }
  881. pr_debug("[SDIO MODEM] compat ioctl %d\n", cmd);
  882. switch (cmd) {
  883. default:
  884. {
  885. return filp->f_op->unlocked_ioctl(filp, cmd,
  886. (unsigned long)
  887. compat_ptr(arg));
  888. }
  889. }
  890. }
  891. #endif
  892. static int misc_modem_release(struct inode *inode, struct file *filp)
  893. {
  894. struct c2k_modem_data *d =
  895. (struct c2k_modem_data *)(filp->private_data);
  896. if (atomic_read(&cmdata->count) > 0)
  897. atomic_dec(&cmdata->count);
  898. return fasync_helper(-1, filp, 0, &d->fasync);
  899. }
  900. static int misc_modem_fasync(int fd, struct file *filp, int on)
  901. {
  902. struct c2k_modem_data *d =
  903. (struct c2k_modem_data *)(filp->private_data);
  904. return fasync_helper(fd, filp, on, &d->fasync);
  905. }
  906. static const struct file_operations misc_modem_fops = {
  907. .owner = THIS_MODULE,
  908. .open = misc_modem_open,
  909. .unlocked_ioctl = misc_modem_ioctl,
  910. #ifdef CONFIG_COMPAT
  911. .compat_ioctl = &misc_modem_compat_ioctl,
  912. #endif
  913. .release = misc_modem_release,
  914. .fasync = misc_modem_fasync,
  915. };
  916. static struct miscdevice misc_modem_device = {
  917. .minor = MISC_DYNAMIC_MINOR,
  918. .name = "vmodem",
  919. .fops = &misc_modem_fops,
  920. };
  921. static int modem_data_init(struct c2k_modem_data *d)
  922. {
  923. int ret = 0;
  924. d->modem_kobj = c2k_kobject_add("modem");
  925. if (!d->modem_kobj) {
  926. ret = -ENOMEM;
  927. goto end;
  928. }
  929. d->ntf_flags = 0;
  930. RAW_INIT_NOTIFIER_HEAD(&d->ntf);
  931. wake_lock_init(&d->wlock, WAKE_LOCK_SUSPEND, "cbp_rst");
  932. INIT_WORK(&d->work, modem_notify_task);
  933. d->rst_ntf.notifier_call = modem_reset_notify_misc;
  934. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  935. d->wdt_ntf.notifier_call = modem_wdt_notify_misc;
  936. d->excp_ntf.notifier_call = modem_excp_notify_misc;
  937. #endif
  938. d->pwr_ntf.notifier_call = modem_power_notify_misc;
  939. d->err_ntf.notifier_call = modem_err_notify_misc;
  940. atomic_set(&d->count, 0);
  941. d->modem = c2k_modem;
  942. end:
  943. return ret;
  944. }
  945. static int __init modem_init(void)
  946. {
  947. int ret = 0;
  948. cmdata = kzalloc(sizeof(struct c2k_modem_data), GFP_KERNEL);
  949. if (!cmdata) {
  950. ret = -ENOMEM;
  951. pr_debug("No memory to alloc cmdata");
  952. goto err_create_cmdata;
  953. }
  954. ret = modem_data_init(cmdata);
  955. if (ret < 0) {
  956. pr_debug("Fail to init modem data\n");
  957. goto err_init_modem_data;
  958. }
  959. atomic_set(&modem_not_ready, 1);
  960. ret = platform_device_register(&platform_modem_device);
  961. if (ret) {
  962. pr_debug("platform_device_register failed\n");
  963. goto err_platform_device_register;
  964. }
  965. ret = platform_driver_register(&platform_modem_driver);
  966. if (ret) {
  967. pr_debug("platform_driver_register failed\n");
  968. goto err_platform_driver_register;
  969. }
  970. ret = misc_register(&misc_modem_device);
  971. if (ret < 0) {
  972. pr_debug("misc regiser via modem failed\n");
  973. goto err_misc_device_register;
  974. }
  975. /*make the default ETS output through USB */
  976. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  977. if (GPIO_C2K_VALID(GPIO_C2K_MDM_ETS_SEL) &&
  978. (is_meta_mode() || get_boot_mode() == FACTORY_BOOT)) {
  979. set_ets_sel(1);
  980. }
  981. #else
  982. if (GPIO_C2K_VALID(GPIO_C2K_MDM_ETS_SEL))
  983. c2k_gpio_direction_output(GPIO_C2K_MDM_ETS_SEL, 1);
  984. #endif
  985. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_IND)) {
  986. #if defined(CONFIG_MTK_LEGACY)
  987. c2k_gpio_irq_mask(GPIO_C2K_MDM_PWR_IND);
  988. #endif
  989. c2k_gpio_direction_input_for_irq(GPIO_C2K_MDM_PWR_IND);
  990. c2k_gpio_set_irq_type(GPIO_C2K_MDM_PWR_IND,
  991. IRQF_TRIGGER_RISING |
  992. IRQF_TRIGGER_FALLING);
  993. ret =
  994. c2k_gpio_request_irq(GPIO_C2K_MDM_PWR_IND,
  995. modem_power_indication_irq,
  996. IRQF_SHARED | IRQF_NO_SUSPEND |
  997. IRQF_TRIGGER_RISING |
  998. IRQF_TRIGGER_FALLING, "mdm_power_ind",
  999. cmdata);
  1000. #if defined(CONFIG_MTK_LEGACY)
  1001. c2k_gpio_irq_unmask(GPIO_C2K_MDM_PWR_IND);
  1002. #endif
  1003. if (ret < 0)
  1004. pr_debug("fail to request mdm_power_ind irq\n");
  1005. }
  1006. modem_register_notifier(&cmdata->pwr_ntf); /*for SW triggered power state chaning (flight mode) */
  1007. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST_IND)) {
  1008. #if defined(CONFIG_MTK_LEGACY)
  1009. c2k_gpio_irq_mask(GPIO_C2K_MDM_RST_IND);
  1010. #endif
  1011. c2k_gpio_direction_input_for_irq(GPIO_C2K_MDM_RST_IND);
  1012. c2k_gpio_set_irq_type(GPIO_C2K_MDM_RST_IND, IRQF_TRIGGER_FALLING);
  1013. ret =
  1014. c2k_gpio_request_irq(GPIO_C2K_MDM_RST_IND,
  1015. modem_reset_indication_irq,
  1016. IRQF_SHARED | IRQF_NO_SUSPEND |
  1017. IRQF_TRIGGER_FALLING, "mdm_reset_ind",
  1018. cmdata);
  1019. #if defined(CONFIG_MTK_LEGACY)
  1020. c2k_gpio_irq_unmask(GPIO_C2K_MDM_RST_IND);
  1021. #endif
  1022. if (ret < 0)
  1023. pr_debug("fail to request mdm_rst_ind irq\n");
  1024. modem_register_notifier(&cmdata->rst_ntf);
  1025. }
  1026. #ifndef CONFIG_EVDO_DT_VIA_SUPPORT
  1027. modem_register_notifier(&cmdata->wdt_ntf);
  1028. modem_register_notifier(&cmdata->excp_ntf);
  1029. #endif
  1030. if (GPIO_C2K_VALID(GPIO_C2K_CRASH_CBP)) {
  1031. pr_debug("%s %d GPIO_C2K_CRASH_CBP", __func__, __LINE__);
  1032. c2k_gpio_direction_output(GPIO_C2K_CRASH_CBP, 1);
  1033. }
  1034. modem_register_notifier(&cmdata->err_ntf);
  1035. /*c2k_gpio_direction_output(GPIO_C2K_MDM_RST, 0); */
  1036. /*c2k_gpio_direction_output(GPIO_C2K_MDM_PWR_EN, 1); */
  1037. ret = sysfs_create_group(cmdata->modem_kobj, &g_attr_group);
  1038. if (ret) {
  1039. pr_debug("sysfs_create_group failed\n");
  1040. goto err_sysfs_create_group;
  1041. }
  1042. return 0;
  1043. err_sysfs_create_group:
  1044. misc_deregister(&misc_modem_device);
  1045. err_misc_device_register:
  1046. platform_driver_unregister(&platform_modem_driver);
  1047. err_platform_driver_register:
  1048. platform_device_unregister(&platform_modem_device);
  1049. err_platform_device_register:
  1050. err_init_modem_data:
  1051. kfree(cmdata);
  1052. cmdata = NULL;
  1053. err_create_cmdata:
  1054. return ret;
  1055. }
  1056. static void __exit modem_exit(void)
  1057. {
  1058. if (GPIO_C2K_VALID(GPIO_C2K_MDM_PWR_IND))
  1059. modem_unregister_notifier(&cmdata->pwr_ntf);
  1060. if (GPIO_C2K_VALID(GPIO_C2K_MDM_RST_IND))
  1061. modem_unregister_notifier(&cmdata->pwr_ntf);
  1062. modem_unregister_notifier(&cmdata->err_ntf);
  1063. if (cmdata)
  1064. wake_lock_destroy(&cmdata->wlock);
  1065. }
  1066. late_initcall_sync(modem_init);
  1067. module_exit(modem_exit);