sipc5_modem.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /* linux/drivers/misc/modem_if_v2/sipc5_modem.c
  2. *
  3. * Copyright (C) 2012 Samsung Electronics.
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include <linux/init.h>
  16. #include <linux/module.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/uaccess.h>
  21. #include <linux/fs.h>
  22. #include <linux/io.h>
  23. #include <linux/wait.h>
  24. #include <linux/sched.h>
  25. #include <linux/slab.h>
  26. #include <linux/mutex.h>
  27. #include <linux/irq.h>
  28. #include <linux/gpio.h>
  29. #include <linux/delay.h>
  30. #include <linux/wakelock.h>
  31. #include <linux/platform_data/modem.h>
  32. #include "modem_prj.h"
  33. #include "modem_variation.h"
  34. #include "modem_utils.h"
  35. /* Channel 0, 5, 6, 27, 255 are reserved in SIPC5.
  36. * see SIPC5 spec: 2.2.2 Channel Identification (Ch ID) Field.
  37. * They do not need to store in `iodevs_tree_fmt'
  38. */
  39. #define sipc5_is_not_reserved_channel(ch) \
  40. ((ch) != 0 && (ch) != 5 && (ch) != 6 && (ch) != 27 && (ch) != 255)
  41. static struct modem_shared *create_modem_shared_data(void)
  42. {
  43. struct modem_shared *msd;
  44. msd = kzalloc(sizeof(struct modem_shared), GFP_KERNEL);
  45. if (!msd)
  46. return NULL;
  47. /* initialize link device list */
  48. INIT_LIST_HEAD(&msd->link_dev_list);
  49. /* initialize tree of io devices */
  50. msd->iodevs_tree_chan = RB_ROOT;
  51. msd->iodevs_tree_fmt = RB_ROOT;
  52. return msd;
  53. }
  54. static struct modem_ctl *create_modemctl_device(struct platform_device *pdev,
  55. struct modem_shared *msd)
  56. {
  57. int ret = 0;
  58. struct modem_data *pdata;
  59. struct modem_ctl *modemctl;
  60. struct device *dev = &pdev->dev;
  61. /* create modem control device */
  62. modemctl = kzalloc(sizeof(struct modem_ctl), GFP_KERNEL);
  63. if (!modemctl)
  64. return NULL;
  65. modemctl->msd = msd;
  66. modemctl->dev = dev;
  67. modemctl->phone_state = STATE_OFFLINE;
  68. pdata = pdev->dev.platform_data;
  69. modemctl->mdm_data = pdata;
  70. modemctl->name = pdata->name;
  71. /* init modemctl device for getting modemctl operations */
  72. ret = call_modem_init_func(modemctl, pdata);
  73. if (ret) {
  74. kfree(modemctl);
  75. return NULL;
  76. }
  77. mif_info("%s: create_modemctl_device DONE\n", modemctl->name);
  78. return modemctl;
  79. }
  80. static struct io_device *create_io_device(struct modem_io_t *io_t,
  81. struct modem_shared *msd, struct modem_ctl *modemctl,
  82. struct modem_data *pdata)
  83. {
  84. int ret = 0;
  85. struct io_device *iod = NULL;
  86. iod = kzalloc(sizeof(struct io_device), GFP_KERNEL);
  87. if (!iod) {
  88. mif_err("io device memory alloc fail\n");
  89. return NULL;
  90. }
  91. rb_init_node(&iod->node_chan);
  92. rb_init_node(&iod->node_fmt);
  93. iod->name = io_t->name;
  94. iod->id = io_t->id;
  95. iod->format = io_t->format;
  96. iod->io_typ = io_t->io_type;
  97. iod->link_types = io_t->links;
  98. iod->net_typ = pdata->modem_net;
  99. iod->use_handover = pdata->use_handover;
  100. atomic_set(&iod->opened, 0);
  101. /* link between io device and modem control */
  102. iod->mc = modemctl;
  103. if (iod->format == IPC_FMT)
  104. modemctl->iod = iod;
  105. else if (iod->format == IPC_BOOT)
  106. modemctl->bootd = iod;
  107. /* link between io device and modem shared */
  108. iod->msd = msd;
  109. /* add iod to rb_tree */
  110. if (iod->format != IPC_RAW)
  111. insert_iod_with_format(msd, iod->format, iod);
  112. if (sipc5_is_not_reserved_channel(iod->id))
  113. insert_iod_with_channel(msd, iod->id, iod);
  114. /* register misc device or net device */
  115. ret = sipc5_init_io_device(iod);
  116. if (ret) {
  117. kfree(iod);
  118. mif_err("sipc5_init_io_device fail (%d)\n", ret);
  119. return NULL;
  120. }
  121. mif_debug("%s: create_io_device DONE\n", io_t->name);
  122. return iod;
  123. }
  124. static int attach_devices(struct io_device *iod, enum modem_link tx_link)
  125. {
  126. struct modem_shared *msd = iod->msd;
  127. struct link_device *ld;
  128. /* find link type for this io device */
  129. list_for_each_entry(ld, &msd->link_dev_list, list) {
  130. if (IS_CONNECTED(iod, ld)) {
  131. /* The count 1 bits of iod->link_types is count
  132. * of link devices of this iod.
  133. * If use one link device,
  134. * or, 2+ link devices and this link is tx_link,
  135. * set iod's link device with ld
  136. */
  137. if ((countbits(iod->link_types) <= 1) ||
  138. (tx_link == ld->link_type)) {
  139. mif_debug("set %s->%s\n", iod->name, ld->name);
  140. set_current_link(iod, ld);
  141. }
  142. }
  143. }
  144. /* if use rx dynamic switch, set tx_link at modem_io_t of
  145. * board-*-modems.c
  146. */
  147. if (!get_current_link(iod)) {
  148. mif_err("%s->link == NULL\n", iod->name);
  149. BUG();
  150. }
  151. switch (iod->format) {
  152. case IPC_FMT:
  153. wake_lock_init(&iod->wakelock, WAKE_LOCK_SUSPEND, iod->name);
  154. iod->waketime = FMT_WAKE_TIME;
  155. break;
  156. case IPC_RFS:
  157. wake_lock_init(&iod->wakelock, WAKE_LOCK_SUSPEND, iod->name);
  158. iod->waketime = RFS_WAKE_TIME;
  159. break;
  160. case IPC_MULTI_RAW:
  161. wake_lock_init(&iod->wakelock, WAKE_LOCK_SUSPEND, iod->name);
  162. iod->waketime = RAW_WAKE_TIME;
  163. break;
  164. default:
  165. break;
  166. }
  167. return 0;
  168. }
  169. static int __devinit modem_probe(struct platform_device *pdev)
  170. {
  171. int i;
  172. struct modem_data *pdata = pdev->dev.platform_data;
  173. struct modem_shared *msd = NULL;
  174. struct modem_ctl *modemctl = NULL;
  175. struct io_device *iod[pdata->num_iodevs];
  176. struct link_device *ld;
  177. memset(iod, 0, sizeof(iod));
  178. msd = create_modem_shared_data();
  179. if (!msd) {
  180. mif_err("msd == NULL\n");
  181. goto err_free_modemctl;
  182. }
  183. modemctl = create_modemctl_device(pdev, msd);
  184. if (!modemctl) {
  185. mif_err("modemctl == NULL\n");
  186. goto err_free_modemctl;
  187. }
  188. /* create link device */
  189. /* support multi-link device */
  190. for (i = 0; i < LINKDEV_MAX ; i++) {
  191. /* find matching link type */
  192. if (pdata->link_types & LINKTYPE(i)) {
  193. ld = call_link_init_func(pdev, i);
  194. if (!ld)
  195. goto err_free_modemctl;
  196. ld->link_type = i;
  197. ld->mc = modemctl;
  198. ld->msd = msd;
  199. list_add(&ld->list, &msd->link_dev_list);
  200. }
  201. }
  202. /* create io deivces and connect to modemctl device */
  203. for (i = 0; i < pdata->num_iodevs; i++) {
  204. iod[i] = create_io_device(&pdata->iodevs[i], msd, modemctl,
  205. pdata);
  206. if (!iod[i]) {
  207. mif_err("iod[%d] == NULL\n", i);
  208. goto err_free_modemctl;
  209. }
  210. attach_devices(iod[i], pdata->iodevs[i].tx_link);
  211. }
  212. platform_set_drvdata(pdev, modemctl);
  213. mif_info("modem_probe Done\n");
  214. return 0;
  215. err_free_modemctl:
  216. for (i = 0; i < pdata->num_iodevs; i++)
  217. if (iod[i] != NULL)
  218. kfree(iod[i]);
  219. if (modemctl != NULL)
  220. kfree(modemctl);
  221. if (msd != NULL)
  222. kfree(msd);
  223. return -ENOMEM;
  224. }
  225. static void modem_shutdown(struct platform_device *pdev)
  226. {
  227. struct device *dev = &pdev->dev;
  228. struct modem_ctl *mc = dev_get_drvdata(dev);
  229. if (mc->ops.modem_off)
  230. mc->ops.modem_off(mc);
  231. mc->phone_state = STATE_OFFLINE;
  232. }
  233. static int modem_suspend(struct device *pdev)
  234. {
  235. struct modem_ctl *mc = dev_get_drvdata(pdev);
  236. if (mc->gpio_pda_active)
  237. gpio_set_value(mc->gpio_pda_active, 0);
  238. return 0;
  239. }
  240. static int modem_resume(struct device *pdev)
  241. {
  242. struct modem_ctl *mc = dev_get_drvdata(pdev);
  243. if (mc->gpio_pda_active)
  244. gpio_set_value(mc->gpio_pda_active, 1);
  245. return 0;
  246. }
  247. static const struct dev_pm_ops modem_pm_ops = {
  248. .suspend = modem_suspend,
  249. .resume = modem_resume,
  250. };
  251. static struct platform_driver modem_driver = {
  252. .probe = modem_probe,
  253. .shutdown = modem_shutdown,
  254. .driver = {
  255. .name = "mif_sipc5",
  256. .pm = &modem_pm_ops,
  257. },
  258. };
  259. static int __init modem_init(void)
  260. {
  261. return platform_driver_register(&modem_driver);
  262. }
  263. module_init(modem_init);
  264. MODULE_LICENSE("GPL");
  265. MODULE_DESCRIPTION("Samsung Modem Interface Driver");