aml_modem.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Common power driver for Amlogic Devices with one or two external
  3. * power supplies (AC/USB) connected to main and backup batteries,
  4. * and optional builtin charger.
  5. *
  6. * Copyright © 2011-4-27 alex.deng <alex.deng@amlogic.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/err.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/power_supply.h>
  17. #include <linux/regulator/consumer.h>
  18. #include <linux/timer.h>
  19. #include <linux/jiffies.h>
  20. #include <linux/usb/otg.h>
  21. #include <linux/rfkill.h>
  22. #include <linux/aml_modem.h>
  23. #ifdef CONFIG_HAS_EARLYSUSPEND
  24. #include <linux/earlysuspend.h>
  25. static struct early_suspend modem_early_suspend;
  26. #endif
  27. #ifdef CONFIG_HAS_EARLYSUSPEND
  28. static int aml_modem_suspend(struct early_suspend *handler);
  29. static int aml_modem_resume(struct early_suspend *handler);
  30. #else
  31. #define aml_modem_suspend NULL
  32. #define aml_modem_resume NULL
  33. #endif
  34. #define POWER_OFF (0)
  35. #define POWER_ON (1)
  36. static struct device *dev;
  37. static struct aml_modem_pdata *g_pData;
  38. static int g_modemPowerMode = 0x0001 ; // bit 1 controlls usb 0,bit 2 controlls usb 1.
  39. static int g_modemPowerState = POWER_OFF ;
  40. static int g_modemEnableFlag = 0 ;
  41. #ifdef CONFIG_HAS_EARLYSUSPEND
  42. static int aml_modem_suspend(struct early_suspend *handler)
  43. {
  44. //printk("aml_modem_suspend !!!!!!!!!!!!!###################\n");
  45. int ret = -1;
  46. #ifdef CONFIG_AMLOGIC_MODEM_PM
  47. if(handler && 2<=g_modemPowerMode )
  48. {
  49. printk("do aml_modem_suspend \n");
  50. g_modemPowerState = POWER_OFF;
  51. g_pData->power_off();
  52. g_pData->disable();
  53. ret = 0;
  54. }
  55. #endif
  56. return 0 ;
  57. }
  58. static int aml_modem_resume(struct early_suspend *handler)
  59. {
  60. //printk("aml_modem_resume !!!!!!!!!!!!!###################\n");
  61. int ret = -1;
  62. #ifdef CONFIG_AMLOGIC_MODEM_PM
  63. if(handler && 2<=g_modemPowerMode )
  64. {
  65. printk("do aml_modem_resume \n");
  66. g_modemPowerState = POWER_ON;
  67. g_pData->power_on();
  68. g_pData->enable();
  69. // need to reset ??
  70. g_pData->reset();
  71. ret = 0 ;
  72. }
  73. #endif
  74. return 0 ;
  75. }
  76. #endif
  77. static int modem_set_block(void *data, bool blocked)
  78. {
  79. pr_info("modem_RADIO going: %s\n", blocked ? "off" : "on");
  80. if( NULL == data)
  81. {
  82. return -1 ;
  83. }
  84. struct aml_modem_pdata *pData = (struct aml_modem_pdata *)data;
  85. if (!blocked)
  86. {
  87. pr_info("amlogic modem: going ON\n");
  88. if ( pData->power_on && pData->enable && pData->reset)
  89. {
  90. pData->power_on();
  91. pData->enable();
  92. //pData->reset();
  93. }
  94. }
  95. else
  96. {
  97. pr_info("amlogic modem: going OFF\n");
  98. if (NULL != pData->power_off)
  99. {
  100. pData->power_off();
  101. }
  102. }
  103. return 0;
  104. }
  105. static const struct rfkill_ops modem_rfkill_ops = {
  106. .set_block = modem_set_block,
  107. };
  108. int GetModemPowerMode(void)
  109. {
  110. return g_modemPowerMode ;
  111. }
  112. EXPORT_SYMBOL(GetModemPowerMode);
  113. static ssize_t get_modemPowerMode(struct class *cla, struct class_attribute *attr, char *buf)
  114. {
  115. return sprintf(buf, "%d\n", g_modemPowerMode );
  116. }
  117. static ssize_t set_modemPowerMode(struct class *cla, struct class_attribute *attr, char *buf, size_t count)
  118. {
  119. if(!strlen(buf)){
  120. printk("%s parameter is required!\n",__FUNCTION__);
  121. return 0;
  122. }
  123. g_modemPowerMode = (int)(buf[0]-'0');
  124. if(g_modemPowerMode <0 || g_modemPowerMode>3){
  125. printk("%s parameter is invalid! %s \n",__FUNCTION__);
  126. g_modemPowerMode = 3 ;
  127. }
  128. return count;
  129. }
  130. static ssize_t get_modemEnableFlag(struct class *cla, struct class_attribute *attr, char *buf)
  131. {
  132. return sprintf(buf, "%d\n", g_modemEnableFlag );
  133. }
  134. static ssize_t set_modemEnableFlag(struct class *cla, struct class_attribute *attr, char *buf, size_t count)
  135. {
  136. if(!strlen(buf)){
  137. printk("%s parameter is required!\n",__FUNCTION__);
  138. return 0;
  139. }
  140. g_modemEnableFlag = (int)(buf[0]-'0');
  141. g_modemEnableFlag = !!g_modemEnableFlag ;
  142. if(g_modemEnableFlag){
  143. g_pData->enable();
  144. }
  145. else{
  146. g_pData->disable() ;
  147. }
  148. return count;
  149. }
  150. static ssize_t get_modemPowerState(struct class *cla, struct class_attribute *attr, char *buf)
  151. {
  152. return sprintf(buf, "%d\n", g_modemPowerState );
  153. }
  154. static ssize_t set_modemPowerState(struct class *cla, struct class_attribute *attr, char *buf, size_t count)
  155. {
  156. int old_state = g_modemPowerState ;
  157. if(!strlen(buf)){
  158. printk("%s parameter is required!\n",__FUNCTION__);
  159. return 0;
  160. }
  161. g_modemPowerState = (int)(buf[0]-'0');
  162. g_modemPowerState = !!g_modemPowerState ;
  163. if(old_state == g_modemPowerState){
  164. printk("modemPowerState is already %s now \n", g_modemPowerState?"ON":"OFF");
  165. return count ;
  166. }
  167. else
  168. printk("set_modemPowerState %s \n", g_modemPowerState?"ON":"OFF");
  169. if(POWER_ON == g_modemPowerState){
  170. g_pData->power_on();
  171. g_pData->enable();
  172. //g_pData->reset();
  173. }
  174. else{
  175. g_pData->power_off();
  176. g_pData->disable();
  177. }
  178. return count;
  179. }
  180. static ssize_t set_modemReset(struct class *cla, struct class_attribute *attr, char *buf, size_t count)
  181. {
  182. int ret = 0 ;
  183. if(!strlen(buf)){
  184. printk("%s parameter is required!\n",__FUNCTION__);
  185. return 0;
  186. }
  187. ret = (int)(buf[0]-'0');
  188. ret = !!ret ;
  189. if(ret){
  190. printk("set_modemReset \n");
  191. g_pData->reset();
  192. }
  193. return count ;
  194. }
  195. static struct class_attribute AmlModem_class_attrs[] = {
  196. __ATTR(mode,S_IRUGO|S_IWUGO,get_modemPowerMode,set_modemPowerMode),
  197. __ATTR(enable,S_IRUGO|S_IWUGO,get_modemEnableFlag,set_modemEnableFlag),
  198. __ATTR(state,S_IRUGO|S_IWUGO,get_modemPowerState,set_modemPowerState),
  199. __ATTR(reset,S_IWUGO,NULL,set_modemReset),
  200. __ATTR_NULL
  201. };
  202. static struct class AmlModem_class = {
  203. .name = "aml_modem",
  204. .class_attrs = AmlModem_class_attrs,
  205. };
  206. static int __init aml_modem_probe(struct platform_device *pdev)
  207. {
  208. int ret = 0;
  209. struct rfkill *rfk = NULL;
  210. printk(" aml_modem_probe \n");
  211. dev = &pdev->dev;
  212. if (pdev->id != -1) {
  213. dev_err(dev, "it's meaningless to register several "
  214. "pda_powers; use id = -1\n");
  215. ret = -EINVAL;
  216. goto exit;
  217. }
  218. g_pData = pdev->dev.platform_data;
  219. #if 0
  220. rfk = rfkill_alloc("modem-dev", &pdev->dev, RFKILL_TYPE_WWAN,
  221. &modem_rfkill_ops, g_pData);
  222. if (!rfk)
  223. {
  224. printk("aml_modem_probe, rfk alloc fail\n");
  225. ret = -ENOMEM;
  226. goto exit;
  227. }
  228. ret = rfkill_register(rfk);
  229. if (ret)
  230. {
  231. printk("aml_modem_probe, rfkill_register fail\n");
  232. goto err_rfkill;
  233. }
  234. platform_set_drvdata(pdev, rfk);
  235. #else
  236. if(g_pData){
  237. g_modemPowerState = POWER_ON ;
  238. g_pData->power_on();
  239. g_pData->enable();
  240. //g_pData->reset();
  241. }
  242. #endif
  243. #ifdef CONFIG_HAS_EARLYSUSPEND
  244. modem_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
  245. modem_early_suspend.suspend = aml_modem_suspend;
  246. modem_early_suspend.resume = aml_modem_resume;
  247. modem_early_suspend.param = g_pData;
  248. register_early_suspend(&modem_early_suspend);
  249. #endif
  250. return 0 ;
  251. err_rfkill:
  252. rfkill_destroy(rfk);
  253. exit:;
  254. return ret;
  255. }
  256. static int aml_modem_remove(struct platform_device *pdev)
  257. {
  258. int ret = 0;
  259. printk(" aml_modem_remove \n");
  260. dev = &pdev->dev;
  261. if (pdev->id != -1) {
  262. dev_err(dev, "it's meaningless to register several "
  263. "pda_powers; use id = -1\n");
  264. ret = -EINVAL;
  265. goto exit;
  266. }
  267. g_pData = pdev->dev.platform_data;
  268. if (g_pData->power_off) {
  269. ret = g_pData->power_off();
  270. }
  271. struct rfkill *rfk = platform_get_drvdata(pdev);
  272. platform_set_drvdata(pdev, NULL);
  273. if (rfk) {
  274. rfkill_unregister(rfk);
  275. rfkill_destroy(rfk);
  276. }
  277. rfk = NULL;
  278. #ifdef CONFIG_HAS_EARLYSUSPEND
  279. unregister_early_suspend(&modem_early_suspend);
  280. #endif
  281. exit:;
  282. return ret;
  283. }
  284. MODULE_ALIAS("platform:aml-modem");
  285. static struct platform_driver aml_modem_pdrv = {
  286. .driver = {
  287. .name = "aml-modem",
  288. .owner = THIS_MODULE,
  289. },
  290. .probe = aml_modem_probe,
  291. .remove = aml_modem_remove,
  292. .suspend = aml_modem_suspend,
  293. .resume = aml_modem_resume,
  294. };
  295. static int __init aml_modem_init(void)
  296. {
  297. printk("amlogic 3G supply init \n");
  298. class_register(&AmlModem_class);
  299. return platform_driver_register(&aml_modem_pdrv);
  300. }
  301. static void __exit aml_modem_exit(void)
  302. {
  303. platform_driver_unregister(&aml_modem_pdrv);
  304. class_unregister(&AmlModem_class);
  305. }
  306. module_init(aml_modem_init);
  307. module_exit(aml_modem_exit);
  308. MODULE_LICENSE("GPL");
  309. MODULE_AUTHOR("Alex Deng");