s3c-adc.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. *
  16. * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
  17. * iPAQ H1940 touchscreen support
  18. *
  19. * ChangeLog
  20. *
  21. * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
  22. * - added clock (de-)allocation code
  23. *
  24. * 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
  25. * - h1940_ -> s3c24xx (this driver is now also used on the n30
  26. * machines :P)
  27. * - Debug messages are now enabled with the config option
  28. * TOUCHSCREEN_S3C_DEBUG
  29. * - Changed the way the value are read
  30. * - Input subsystem should now work
  31. * - Use ioremap and readl/writel
  32. *
  33. * 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
  34. * - Make use of some undocumented features of the touchscreen
  35. * controller
  36. *
  37. */
  38. #include <linux/errno.h>
  39. #include <linux/kernel.h>
  40. #include <linux/module.h>
  41. #include <linux/slab.h>
  42. #include <linux/input.h>
  43. #include <linux/init.h>
  44. #include <linux/serio.h>
  45. #include <linux/delay.h>
  46. #include <linux/platform_device.h>
  47. #include <linux/miscdevice.h>
  48. #include <linux/clk.h>
  49. #include <linux/mutex.h>
  50. #include <asm/io.h>
  51. #include <asm/irq.h>
  52. #include <asm/hardware.h>
  53. #include <asm/uaccess.h>
  54. #include <asm/arch/regs-adc.h>
  55. #include <asm/arch/irqs.h>
  56. #include <asm/arch/regs-s3c2416-clock.h>
  57. #include <asm/arch/regs-gpio.h>
  58. //#define USE_12BITS_ADC
  59. //#define USE_10BITS_ADC
  60. #define LEVEL0_MIN 2980 /*0%~25%*/
  61. #define LEVEL0_MAX 3581
  62. #define LEVEL1_MIN 3582 /*25%~50%*/ /*3.67V*/ /*3582*/
  63. #define LEVEL1_MAX 3666
  64. #define LEVEL2_MIN 3667 /*50%~75%*/ /*3.78V*/ /*3692*/ /*-25*/
  65. #define LEVEL2_MAX 3778
  66. #define LEVEL3_MIN 3779 /*75%~99%*/ /*3.92V*/ /*3829*/ /*-50*/
  67. #define LEVEL3_MAX 4004
  68. #define BATTERY_FULL 4005 /*100%*/ /*4.1V*/ /*4005*/
  69. #define ADC_sample_count 100 //25 /*joey modify ADC read method to catch top 5 low value 2009/12/21*/
  70. #define ADC_jig_voltage 3700 /*joey for ENV ADC to voltage 2010/01/15*/
  71. #define ADC_READ_LEVEL_VAULE _IOR('S', 0x01, unsigned long)
  72. #define ADC_READ_INPUT_SOURCE_STATUS _IOR('S', 0x02, unsigned long)
  73. #define ADC_SET_PM_WKUP_SOURCE _IOW('S', 0x03, unsigned long)
  74. #define ADC_READ_RAW_VAULE _IOR('S', 0x04, unsigned long)
  75. #define ADC_POWER_OFF _IO ('S', 0x05)
  76. #define ADC_READ_INPUT_POWER_STATUS _IOR('S', 0x06, unsigned long)
  77. #define ADC_READ_CHARGING_STATUS _IOR('S', 0x07, unsigned long)
  78. #define ADC_SET_PM_FUNCTION_POWER _IOW('S', 0x08, unsigned long)
  79. #ifdef CONFIG_PM_CPU_MODE
  80. #define ADC_SET_CPU_PM_MODE _IOW('S', 0x09, unsigned long)
  81. #endif
  82. #define ADC_READ_WAKEUP_SOURCE _IOR('S', 0x0A, unsigned long)
  83. #define ADC_READ_POWER_FAIL_STATUS _IOR('S', 0x0B, unsigned long)
  84. #define ADC_READ_LEVEL_VAULE_TOOL _IOR('S', 0x10, unsigned long) /*qisda joey add for tool read 20091207*/
  85. #define ADC_READ_RAW_VAULE_TOOL _IOR('S', 0x11, unsigned long) /*qisda joey add for tool read 20091207*/
  86. #define HIGH_LOW_PULSE _IOR('S', 0x12, unsigned long)
  87. #define ADC_READ_ENV _IOR('S', 0x13, unsigned long) /*joey for ENV ADC read/write 2010/01/13*/
  88. #define ADC_GET_ENV _IOR('S', 0x14, unsigned long) /*joey for ENV ADC read/write 2010/01/13*/
  89. #define ADC_READ_VOLTAGE _IOR('S', 0x15, unsigned long) /*joey for ENV ADC to voltage 2010/01/15*/
  90. /* 2010/1/21, weichen, for handling events during suspend */
  91. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  92. #define ADC_CLEAR_WAKEUP_EVENT _IOW('S', 0x20, unsigned long)
  93. #endif
  94. //#define ADC_INPUT_PIN _IOW('S', 0x0c, unsigned long)
  95. /*Qisda Qube 20091103 for Smart card power control*/
  96. #define ADC_SMARTCARD_PWR _IOR('S', 0x8F, unsigned long)
  97. /*Qisda Qube 20091103 for Smart card power control*/
  98. #define NON_ZERO_VALUE 0xFF
  99. #define INPUT_SOURCE_USB 0
  100. #define INPUT_SOURCE_CHARGER 1
  101. #define INPUT_SOURCE_NOTHING 2
  102. unsigned int wkup_srce = NON_ZERO_VALUE;
  103. #ifdef CONFIG_PM_CPU_MODE
  104. unsigned char pm_cpu_mode = 0;
  105. #endif
  106. /* 2010/1/21, weichen, for handling events during suspend */
  107. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  108. unsigned int g_wakeup_event_occurs = 0;
  109. #endif
  110. #define ADC_PM_DEBUG_PORT (0x00000003)
  111. #define ADC_PM_WIFI (0x0000000C)
  112. #define ADC_PM_AUDIO (0x00000030)
  113. #define ADC_PM_SD (0x000000C0)
  114. #define ADC_PM_TCON (0x00000300)
  115. #define ADC_PM_USB (0x00000C00)
  116. #define ADC_PM_TOUCH (0x0000F000)
  117. #define ADC_PM_SMART_CARD (0x00030000)
  118. #define ADC_PM_3G_MODULE (0x000C0000)
  119. #define ADC_PM_I2C (0x00300000)
  120. extern int IsWallCharger(void);
  121. /* Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function {*/
  122. extern int charging_source;
  123. /* } Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function */
  124. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event {
  125. //extern int sleeping_cha_event;
  126. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event }
  127. #define ADC_MINOR 131
  128. #if defined(CONFIG_CPU_S3C2443)
  129. #define ADC_ENV(x) (S3C2410_ADCCON_PRSCVL(49))
  130. #else
  131. #define ADC_ENV(x) (S3C2410_ADCCON_PRSCVL(49) | S3C2410_ADCCON_SELMUX(x))
  132. #endif
  133. struct s3c_adc_mach_info {
  134. int delay;
  135. int presc;
  136. int resol_bit;
  137. };
  138. /* ADC default configuration */
  139. struct s3c_adc_mach_info s3c_adc_cfg __initdata = {
  140. .delay = 10000,
  141. .presc = 49,
  142. //#if defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C6410)
  143. //.resol_bit = 12,
  144. //#else
  145. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  146. .resol_bit = 12,
  147. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status }*/
  148. //#endif
  149. };
  150. int average_adc_value_keep1 = 9999; /*joey add to keep ADC will always return lower one 2009/12/28*/
  151. int average_adc_value_keep2 = 9999; /*joey add to keep ADC will always return lower one 2009/12/28*/
  152. static struct clk *adc_clock;
  153. static void __iomem *base_addr;
  154. static DEFINE_MUTEX(adc_mutex);
  155. static unsigned long data_for_ADCCON;
  156. static unsigned long data_for_ADCTSC;
  157. static int adc_port = 0;
  158. static unsigned long env_adc_value; /*joey for ENV ADC to voltage 2010/01/15*/
  159. static void s3c_adc_save_SFR_on_ADC(void) {
  160. data_for_ADCCON = readl(base_addr+S3C2410_ADCCON);
  161. data_for_ADCTSC = readl(base_addr+S3C2410_ADCTSC);
  162. }
  163. static void s3c_adc_restore_SFR_on_ADC(void) {
  164. writel(data_for_ADCCON, base_addr+S3C2410_ADCCON);
  165. writel(data_for_ADCTSC, base_addr+S3C2410_ADCTSC);
  166. }
  167. static int s3c_adc_open(struct inode *inode, struct file *file)
  168. {
  169. return 0;
  170. }
  171. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  172. #ifdef USE_10BITS_ADC
  173. static ssize_t
  174. s3c_adc_read(struct file *file, char __user * buffer,
  175. size_t size, loff_t * pos)
  176. {
  177. unsigned long data0;
  178. unsigned long data1;
  179. int adc_value = 0;
  180. // printk(KERN_INFO " s3c_adc_read() entered\n");
  181. mutex_lock(&adc_mutex);
  182. s3c_adc_save_SFR_on_ADC();
  183. writel(0x0, base_addr+S3C2410_ADCCON);
  184. writel(0x58, base_addr+S3C2410_ADCTSC);
  185. udelay(10);
  186. writel(ADC_ENV(adc_port)|S3C2410_ADCCON_STDBM, base_addr+S3C2410_ADCCON);
  187. #if defined(CONFIG_CPU_S3C2443)
  188. writel(S3C2410_ADCCON_SELMUX(adc_port), base_addr+S3C2410_ADCMUX);
  189. #endif
  190. udelay(10);
  191. writel(S3C2410_ADCCON_PRSCEN|ADC_ENV(adc_port)|S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
  192. do{
  193. data0 = readl(base_addr+S3C2410_ADCCON);
  194. }
  195. while(!(data0 & S3C2410_ADCCON_ECFLG));
  196. data1 = readl(base_addr+S3C2410_ADCDAT0);
  197. adc_value = data1 & S3C2410_ADCDAT0_XPDATA_MASK;
  198. s3c_adc_restore_SFR_on_ADC();
  199. mutex_unlock(&adc_mutex);
  200. // printk(KERN_INFO " Converted Value: %03d\n", adc_value);
  201. if (copy_to_user(buffer, &adc_value, sizeof(unsigned int))) {
  202. return -EFAULT;
  203. }
  204. return sizeof(unsigned int);
  205. }
  206. #else
  207. unsigned long
  208. s3c_adc_read(void)
  209. {
  210. unsigned long data0;
  211. unsigned long data1;
  212. int adc_value = 0;
  213. // printk("s3c_adc_read entered\n");
  214. mutex_lock(&adc_mutex);
  215. s3c_adc_save_SFR_on_ADC();
  216. writel(0x0, base_addr+S3C2410_ADCCON);
  217. writel(0x58, base_addr+S3C2410_ADCTSC);
  218. udelay(10);
  219. writel(ADC_ENV(adc_port)|S3C2410_ADCCON_STDBM, base_addr+S3C2410_ADCCON);
  220. #if defined(CONFIG_CPU_S3C2443)
  221. writel(S3C2410_ADCCON_SELMUX(adc_port), base_addr+S3C2410_ADCMUX);
  222. #else
  223. writel(0, base_addr+0x18);
  224. #endif
  225. udelay(10);
  226. writel(S3C2410_ADCCON_PRSCEN|ADC_ENV(adc_port)|S3C2410_ADCCON_ENABLE_START|S3C2450_ADCCON_RESSEL_12BIT, base_addr+S3C2410_ADCCON);
  227. do{
  228. data0 = readl(base_addr+S3C2410_ADCCON);
  229. }
  230. while(!(data0 & S3C2410_ADCCON_ECFLG));
  231. data1 = readl(base_addr+S3C2410_ADCDAT0);
  232. adc_value = data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT;
  233. s3c_adc_restore_SFR_on_ADC();
  234. mutex_unlock(&adc_mutex);
  235. // printk("Converted Value: %05d\n", adc_value);
  236. return adc_value;
  237. }
  238. #endif
  239. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status }*/
  240. void bubblesort(int *data, int n) /*joey modify ADC read method to catch top 5 low value 2009/12/21*/
  241. {
  242. int i, j, temp;
  243. for (i = n - 1; i > 0; i--)
  244. {
  245. for (j = 0; j <= i - 1; j++)
  246. {
  247. if (data[j] > data[j + 1])
  248. {
  249. temp = data[j];
  250. data[j] = data[j + 1];
  251. data[j + 1] = temp;
  252. }
  253. }
  254. }
  255. }
  256. static int s3c_adc_ioctl(struct inode *inode, struct file *file,
  257. unsigned int cmd, unsigned long arg)
  258. {
  259. int i = 0;
  260. int average_adc_value = 0;
  261. int env_adc_voltage; /*joey for ENV ADC to voltage 2010/01/15*/
  262. #ifdef CONFIG_PM_PLATFORM_POWER_SAVING
  263. unsigned long data_mask = 0; /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  264. #else
  265. int data_mask = 0;
  266. #endif
  267. unsigned int ret = -ENOIOCTLCMD;
  268. unsigned long level = NON_ZERO_VALUE;
  269. unsigned long input_source = NON_ZERO_VALUE;
  270. int ADC_raw_data[ADC_sample_count]; /*joey modify ADC read method to catch top 5 low value 2009/12/21*/
  271. #ifdef CONFIG_PM_PLATFORM_POWER_SAVING
  272. /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  273. void __user *uarg = (void __user *) arg;
  274. #endif
  275. switch (cmd) {
  276. /*Qisda Qube 20091103 for Smart card power control*/
  277. case ADC_SMARTCARD_PWR:
  278. if(arg==0)
  279. {
  280. printk("Enable smard card power\n");
  281. s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
  282. s3c2410_gpio_setpin(S3C2410_GPC3,1);
  283. s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPH2_TXD0);
  284. s3c2410_gpio_cfgpin(S3C2410_GPH3, S3C2410_GPH3_RXD0);
  285. }
  286. else if(arg==3)
  287. {
  288. printk("Disable smard card power\n");
  289. s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
  290. s3c2410_gpio_setpin(S3C2410_GPC3,0);
  291. s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPH2_OUTP);
  292. s3c2410_gpio_setpin(S3C2410_GPH2,0);
  293. s3c2410_gpio_cfgpin(S3C2410_GPH3, S3C2410_GPH3_OUTP);
  294. s3c2410_gpio_setpin(S3C2410_GPH3,0);
  295. }
  296. return 0;
  297. /*Qisda Qube 20091103 for Smart card power control*/
  298. /*
  299. case ADC_INPUT_PIN:
  300. adc_port = (unsigned int) arg;
  301. if (adc_port >= 4)
  302. printk(" %d is already reserved for TouchScreen\n", adc_port);
  303. return 0;
  304. */
  305. case ADC_READ_INPUT_SOURCE_STATUS:
  306. //Read the level data from GPG1
  307. //CHG_STA: 0 => no andy insertion source
  308. // 1 => There is an insertion existing in GPG
  309. /* Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function {*/
  310. input_source = charging_source;
  311. put_user(input_source, (unsigned long __user *)arg);
  312. ret = 0;
  313. /* } Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function */
  314. break;
  315. case ADC_SET_PM_WKUP_SOURCE:
  316. wkup_srce = (unsigned long) arg;
  317. printk("Wakeup parameter = %d\n", wkup_srce);
  318. /* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/
  319. //s3c_keypad_pm_sleep_message_to_ap(1);
  320. /* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */
  321. ret = 0;
  322. break;
  323. case ADC_READ_LEVEL_VAULE:
  324. for(i=0; i<ADC_sample_count ;i++)
  325. {
  326. //udelay(1000);
  327. msleep(1); /*joey modify for asus request 2009/12/18*/
  328. average_adc_value += s3c_adc_read(); /*old*/
  329. ////ADC_raw_data[i] = s3c_adc_read(); /*joey modify ADC read method to catch top 5 low value 2009/12/21*/ /*new*/
  330. }
  331. average_adc_value = average_adc_value/ADC_sample_count; /*old*/
  332. //for(i=0; i<ADC_sample_count ;i++)
  333. // printk("Before ADC data = %d\n", (int)ADC_raw_data[i]);
  334. ////bubblesort(ADC_raw_data, ADC_sample_count); /*new*/
  335. //for(i=0; i<ADC_sample_count ;i++)
  336. // printk("After ADC data = %d\n", (int)ADC_raw_data[i]);
  337. ////average_adc_value = (ADC_raw_data[1]+ADC_raw_data[2]+ADC_raw_data[3]+ADC_raw_data[4]+ADC_raw_data[5])/5; /*new*/
  338. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  339. // {
  340. // if(average_adc_value > average_adc_value_keep1) /*joey add to keep ADC will always return lower one 2009/12/28*/
  341. // average_adc_value = average_adc_value_keep1;
  342. // }
  343. if (average_adc_value <= LEVEL0_MAX)
  344. {
  345. level = 0;
  346. }
  347. else if (average_adc_value <= LEVEL1_MAX && average_adc_value >= LEVEL1_MIN)
  348. {
  349. level = 1;
  350. }
  351. else if (average_adc_value <= LEVEL2_MAX && average_adc_value >= LEVEL2_MIN)
  352. {
  353. level = 2;
  354. }
  355. else if(average_adc_value <= LEVEL3_MAX && average_adc_value >= LEVEL3_MIN)
  356. {
  357. level = 3;
  358. }
  359. else if(average_adc_value >= BATTERY_FULL)
  360. {
  361. level = 4;
  362. }
  363. // printk("level = %d, ADC data = %d\n", (int)level, (int)average_adc_value);
  364. put_user(level, (unsigned long __user *)arg);
  365. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  366. // average_adc_value_keep1 = average_adc_value; /*joey add to keep ADC will always return lower one 2009/12/28*/
  367. ret = 0;
  368. break;
  369. case ADC_READ_RAW_VAULE:
  370. for(i=0; i<ADC_sample_count ;i++)
  371. {
  372. //udelay(1000);
  373. msleep(1); /*joey modify for asus request 2009/12/18*/
  374. average_adc_value += s3c_adc_read();/*old*/
  375. ////ADC_raw_data[i] = s3c_adc_read(); /*joey modify ADC read method to catch top 5 low value 2009/12/21*/ /*new*/
  376. }
  377. average_adc_value = average_adc_value / ADC_sample_count; /*old*/
  378. //for(i=0; i<ADC_sample_count ;i++)
  379. // printk("Before ADC data = %d\n", (int)ADC_raw_data[i]);
  380. ////bubblesort(ADC_raw_data, ADC_sample_count); /*new*/
  381. //for(i=0; i<ADC_sample_count ;i++)
  382. // printk("After ADC data = %d\n", (int)ADC_raw_data[i]);
  383. ////average_adc_value = (ADC_raw_data[1]+ADC_raw_data[2]+ADC_raw_data[3]+ADC_raw_data[4]+ADC_raw_data[5])/5; /*new*/
  384. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  385. // {
  386. // if(average_adc_value > average_adc_value_keep2) /*joey add to keep ADC will always return lower one 2009/12/28*/
  387. // average_adc_value = average_adc_value_keep2;
  388. // }
  389. printk("ADC data = %d\n", (int)average_adc_value);
  390. put_user(average_adc_value, (unsigned long __user *)arg);
  391. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  392. // average_adc_value_keep2 = average_adc_value; /*joey add to keep ADC will always return lower one 2009/12/28*/
  393. ret = 0;
  394. break;
  395. case ADC_READ_LEVEL_VAULE_TOOL: /*qisda joey add for tool read 20091207*/
  396. for(i=0; i<1000 ;i++) /*qisda joey modify from 20 to 1000 20091202*/
  397. {
  398. udelay(1000);
  399. average_adc_value += s3c_adc_read();
  400. }
  401. average_adc_value = average_adc_value/1000; /*qisda joey modify from 20 to 1000 20091202*/
  402. if (average_adc_value <= LEVEL0_MAX)
  403. {
  404. level = 0;
  405. }
  406. else if (average_adc_value <= LEVEL1_MAX && average_adc_value >= LEVEL1_MIN)
  407. {
  408. level = 1;
  409. }
  410. else if (average_adc_value <= LEVEL2_MAX && average_adc_value >= LEVEL2_MIN)
  411. {
  412. level = 2;
  413. }
  414. else if(average_adc_value <= LEVEL3_MAX && average_adc_value >= LEVEL3_MIN)
  415. {
  416. level = 3;
  417. }
  418. else if(average_adc_value >= BATTERY_FULL)
  419. {
  420. level = 4;
  421. }
  422. // printk("level = %d, ADC data = %d\n", (int)level, (int)average_adc_value);
  423. put_user(level, (unsigned long __user *)arg);
  424. ret = 0;
  425. break;
  426. case ADC_READ_RAW_VAULE_TOOL: /*qisda joey add for tool read 20091207*/
  427. for(i=0; i<1000 ;i++) /*qisda joey modify from 20 to 1000 20091202*/
  428. {
  429. udelay(1000);
  430. average_adc_value += s3c_adc_read();
  431. }
  432. average_adc_value = average_adc_value / 1000; /*qisda joey modify from 20 to 1000 20091202*/
  433. printk("ADC data = %d\n", (int)average_adc_value);
  434. put_user(average_adc_value, (unsigned long __user *)arg);
  435. ret = 0;
  436. break;
  437. case ADC_POWER_OFF:
  438. printk("power off\n");
  439. //writeb(0x0, 0xc8a30029); /*joey shut down SD bus power before p_keep pull low 2010/01/06*/
  440. s3c_moviNAND_power_off();
  441. msleep(100);
  442. #ifdef CONFIG_QISDA_BK060B00
  443. s3c2410_gpio_cfgpin(S3C2410_GPD14, S3C2410_GPD14_OUTP);
  444. s3c2410_gpio_setpin(S3C2410_GPD14, 0);
  445. #else
  446. s3c2410_gpio_cfgpin(S3C2410_GPG0, S3C2410_GPG0_OUTP);
  447. s3c2410_gpio_setpin(S3C2410_GPG0, 0);
  448. #endif
  449. ret = 0;
  450. break;
  451. #ifdef CONFIG_QISDA_AS090B00_EVT1
  452. case ADC_READ_INPUT_POWER_STATUS:
  453. data_mask = readl(S3C2410_GPHDAT);
  454. data_mask &= 0x1<<5;
  455. printk("GPH5 = %d\n", data_mask);
  456. ret = put_user(data_mask, (unsigned long __user *)arg);
  457. break;
  458. #endif
  459. case ADC_READ_CHARGING_STATUS:
  460. data_mask = readl(S3C2410_GPFDAT);
  461. data_mask &= 0x1<<6;
  462. if(data_mask) /*shiyong joey for asus 2009/12/15*/
  463. data_mask = 1;
  464. else
  465. data_mask = 0;
  466. printk("GPF6 = %d\n", data_mask);
  467. ret = put_user(data_mask, (unsigned long __user *)arg);
  468. break;
  469. case ADC_SET_PM_FUNCTION_POWER:
  470. break;
  471. #ifdef CONFIG_PM_CPU_MODE
  472. case ADC_SET_CPU_PM_MODE:
  473. // 0 ADC_CPU_DEVICE_SLEEP:
  474. // 1 ADC_CPU_STOP:
  475. // 2 ADC_CPU_DEEP_STOP:
  476. // 3 ADC_CPU_IDLE:
  477. // 4 ADC_CPU_SLEEP:
  478. pm_cpu_mode = (unsigned char) arg;
  479. // s3c2410_sleep_enter();
  480. printk("cpu_pm_mode parameter = %d\n", pm_cpu_mode);
  481. ret = 0;
  482. break;
  483. #endif
  484. /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  485. case ADC_READ_WAKEUP_SOURCE:
  486. data_mask = readl(S3C2443_WKUPSTAT);
  487. printk("Wakeup source =0x%08lx\n", data_mask);
  488. #ifdef CONFIG_PM_PLATFORM_POWER_SAVING
  489. if (copy_to_user(uarg, &data_mask, sizeof(data_mask)))
  490. return -EFAULT;
  491. /* BenQ, weichen, 2010/1/28, clear the wakeup source of 2416 for MMI */
  492. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  493. writel(0x33, S3C2443_WKUPSTAT);
  494. data_mask = readl(S3C2443_WKUPSTAT);
  495. printk("Wakeup source2 =0x%08lx\n", data_mask);
  496. #endif
  497. #endif
  498. ret = 0;
  499. break;
  500. /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  501. case ADC_READ_POWER_FAIL_STATUS:
  502. data_mask = readl(S3C2410_GPGDAT) & (1<<5);
  503. printk("ADC_READ_POWER_FAIL_STATUS GPG5 = %d\n", data_mask);
  504. ret = put_user(data_mask, (unsigned long __user *)arg);
  505. break;
  506. case HIGH_LOW_PULSE: /*joey add for high/low pulse 2010/01/08*/
  507. {
  508. unsigned long percent[3]={0, 0, 0}; /*1:high sec 2:low msec 3:times*/
  509. int i;
  510. copy_from_user(percent, (unsigned long) arg, sizeof(unsigned long)*3);
  511. printk("1st=%d, 2nd=%d, 3rd=%d\n", percent[0], percent[1], percent[2]);
  512. s3c2410_gpio_cfgpin(S3C2410_GPH11, S3C2410_GPH11_OUTP);
  513. s3c2410_gpio_pullup(S3C2410_GPH11, 2);
  514. for(i=0; i<percent[2]; i++)
  515. {
  516. s3c2410_gpio_setpin(S3C2410_GPH11, 0);
  517. printk("GPH11 pull low\n");
  518. msleep(percent[1]);
  519. s3c2410_gpio_setpin(S3C2410_GPH11, 1);
  520. printk("GPH11 pull high\n");
  521. msleep(percent[0]);
  522. }
  523. //ret = put_user(data_mask, (unsigned long __user *)arg);
  524. break;
  525. }
  526. case ADC_GET_ENV: /*joey for ENV ADC read/write 2010/01/13*/
  527. copy_from_user(&env_adc_value, (unsigned long) arg, sizeof(unsigned long));
  528. printk("env_adc_value=%d\n", env_adc_value);
  529. //ret = put_user(data_mask, (unsigned long __user *)arg);
  530. break;
  531. case ADC_READ_ENV: /*joey for ENV ADC read/write 2010/01/13*/
  532. ret = put_user(env_adc_value, (unsigned long __user *)arg);
  533. printk("env_adc_value=%d\n", env_adc_value);
  534. break;
  535. case ADC_READ_VOLTAGE: /*joey for ENV ADC to voltage 2010/01/15*/
  536. if(env_adc_value > 3711 || env_adc_value < 3511)
  537. env_adc_value = 3611;
  538. printk("env_adc_value=%d\n", env_adc_value);
  539. for(i=0; i<ADC_sample_count ;i++)
  540. {
  541. msleep(1); /*joey modify for asus request 2009/12/18*/
  542. average_adc_value += s3c_adc_read();
  543. }
  544. average_adc_value = average_adc_value / ADC_sample_count;
  545. printk("average_adc_value=%d\n", average_adc_value);
  546. if(average_adc_value >= env_adc_value)
  547. env_adc_voltage = ADC_jig_voltage + (average_adc_value-env_adc_value)*100/97;
  548. else
  549. env_adc_voltage = ADC_jig_voltage - (env_adc_value-average_adc_value)*100/97;
  550. ret = put_user(env_adc_voltage, (unsigned long __user *)arg);
  551. printk("env_adc_voltage=%d\n", env_adc_voltage);
  552. break;
  553. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  554. case ADC_CLEAR_WAKEUP_EVENT:
  555. g_wakeup_event_occurs = 0;
  556. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event {
  557. //sleeping_cha_event = 0;
  558. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event }
  559. printk("ADC_CLEAR_WAKEUP_EVENT: g_wakeup_event_occurs=%d\n", g_wakeup_event_occurs);
  560. ret = 0;
  561. break;
  562. #endif
  563. default:
  564. ret = -ENOIOCTLCMD;
  565. break;
  566. }
  567. return ret;
  568. }
  569. static struct file_operations s3c_adc_fops = {
  570. .owner = THIS_MODULE,
  571. .read = s3c_adc_read,
  572. .open = s3c_adc_open,
  573. .ioctl = s3c_adc_ioctl,
  574. };
  575. static struct miscdevice s3c_adc_miscdev = {
  576. .minor = ADC_MINOR,
  577. .name = "adc",
  578. .fops = &s3c_adc_fops,
  579. };
  580. /*
  581. * The functions for inserting/removing us as a module.
  582. */
  583. static int __init s3c_adc_probe(struct platform_device *pdev)
  584. {
  585. int ret;
  586. printk(KERN_INFO "s3c_adc_probe\n");
  587. adc_clock = clk_get(NULL, "adc");
  588. if (!adc_clock) {
  589. printk(KERN_ERR "failed to get adc clock source\n");
  590. return -ENOENT;
  591. }
  592. clk_enable(adc_clock);
  593. base_addr=ioremap(S3C24XX_PA_ADC, 0x20);
  594. if (base_addr == NULL) {
  595. printk(KERN_ERR "Failed to remap register block\n");
  596. return -ENOMEM;
  597. }
  598. if ((s3c_adc_cfg.presc&0xff) > 0)
  599. writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(s3c_adc_cfg.presc&0xFF), base_addr+S3C2410_ADCCON);
  600. else
  601. writel(0, base_addr+S3C2410_ADCCON);
  602. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  603. #ifdef ADC_TEST //open for debug
  604. tmp = readl(base_addr+S3C2410_ADCCON);
  605. printk("tmp = %04X!\n", tmp);
  606. tmp = tmp | 0x0080;
  607. printk("tmp = %04X!\n", tmp);
  608. writel(tmp, base_addr+S3C2410_ADCCON);
  609. #endif
  610. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status }*/
  611. /* Initialise registers */
  612. if ((s3c_adc_cfg.delay&0xffff) > 0)
  613. writel(s3c_adc_cfg.delay & 0xffff, base_addr+S3C2410_ADCDLY);
  614. ret = misc_register(&s3c_adc_miscdev);
  615. if (ret) {
  616. printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
  617. ADC_MINOR, ret);
  618. return ret;
  619. }
  620. printk(KERN_INFO "S3C ADC driver successfully probed !\n");
  621. return 0;
  622. }
  623. static int s3c_adc_remove(struct device *dev)
  624. {
  625. printk(KERN_INFO "s3c_adc_remove() of TS called !\n");
  626. return 0;
  627. }
  628. #define s3c_adc_suspend NULL
  629. #define s3c_adc_resume NULL
  630. static struct platform_driver s3c_adc_driver = {
  631. .probe = s3c_adc_probe,
  632. .remove = s3c_adc_remove,
  633. .suspend = s3c_adc_suspend,
  634. .resume = s3c_adc_resume,
  635. .driver = {
  636. .owner = THIS_MODULE,
  637. .name = "s3c2410-adc",
  638. },
  639. };
  640. static char banner[] __initdata = KERN_INFO "S3C ADC driver, (c) 2007 Samsung Electronics\n";
  641. int __init s3c_adc_init(void)
  642. {
  643. int ireturn = 0;
  644. int read_pin = -99;
  645. int i = 0;
  646. printk(banner);
  647. ireturn = platform_driver_register(&s3c_adc_driver);
  648. #ifdef CONFIG_QISDA_AS090B00_EVT1
  649. /* Qisda, ShiYong Lin, 2009/09/12, Indication for /PGOOD pin {*/
  650. s3c2410_gpio_cfgpin(S3C2410_GPH5, 0);
  651. s3c2410_gpio_pullup(S3C2410_GPH5, 2);
  652. /* Qisda, ShiYong Lin, 2009/09/12, Indication for /PGOOD pin }*/
  653. #endif
  654. /* Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function {*/
  655. /* Qisda, ShiYong Lin, 2009/09/29, Set En1 and En2 {*/
  656. for(i=0;i<10;++i)
  657. {
  658. read_pin = readl(S3C2410_GPGDAT) & (1<<1);
  659. if(read_pin != 0){
  660. if(IsWallCharger()==0){
  661. charging_source = 0;
  662. //EN2
  663. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  664. s3c2410_gpio_setpin(S3C2410_GPB0, 0);
  665. //EN1
  666. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  667. s3c2410_gpio_setpin(S3C2410_GPB4, 1);
  668. }
  669. else
  670. {
  671. charging_source = 1;
  672. //EN2
  673. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  674. s3c2410_gpio_setpin(S3C2410_GPB0, 1);
  675. //EN1
  676. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  677. s3c2410_gpio_setpin(S3C2410_GPB4, 0);
  678. }
  679. }
  680. else{
  681. charging_source = 2;
  682. //EN2
  683. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  684. s3c2410_gpio_setpin(S3C2410_GPB0, 0);
  685. //EN1
  686. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  687. s3c2410_gpio_setpin(S3C2410_GPB4, 1);
  688. }
  689. }
  690. /*}, Qisda, ShiYong Lin, 2009/09/29, Set En1 and En2 */
  691. /*}, Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function */
  692. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  693. #ifdef ADC_TEST
  694. {
  695. int i=0;
  696. for(i=0; i<10 ;i++)
  697. {
  698. udelay(1000);
  699. s3c_adc_read();
  700. }
  701. printk("Read ADC times = %d\n",i);
  702. }
  703. #else
  704. s3c_adc_read();
  705. #endif
  706. /*}, Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status */
  707. return ireturn;
  708. }
  709. void __exit s3c_adc_exit(void)
  710. {
  711. platform_driver_unregister(&s3c_adc_driver);
  712. }
  713. module_init(s3c_adc_init);
  714. module_exit(s3c_adc_exit);
  715. MODULE_AUTHOR("alinuxguy@samsung.com>");
  716. MODULE_DESCRIPTION("s3c adc driver");
  717. MODULE_LICENSE("GPL");