s3c-adc.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  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 10 //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 ((( 2U ) << ( ( ( 0 + 8 ) + 8 ) + 14 ) ) |
  370. * (( ( 'S' ) ) << ( 0 + 8 ) ) | (( ( 0x04 ) ) << 0 ) |
  371. * (( ( ((sizeof( unsigned long ) == sizeof( unsigned long [1]) && sizeof( unsigned long ) < (1 << 14 )) ? sizeof( unsigned long ) : __invalid_size_argument_for_IOC) ) ) << ( ( 0 + 8 ) + 8 ) )): */
  372. case ADC_READ_RAW_VAULE:
  373. for(i=0; i<ADC_sample_count ;i++)
  374. {
  375. //udelay(1000);
  376. msleep(1); /*joey modify for asus request 2009/12/18*/
  377. average_adc_value += s3c_adc_read();/*old*/
  378. ////ADC_raw_data[i] = s3c_adc_read(); /*joey modify ADC read method to catch top 5 low value 2009/12/21*/ /*new*/
  379. }
  380. average_adc_value = average_adc_value / ADC_sample_count; /*old*/
  381. //for(i=0; i<ADC_sample_count ;i++)
  382. // printk("Before ADC data = %d\n", (int)ADC_raw_data[i]);
  383. ////bubblesort(ADC_raw_data, ADC_sample_count); /*new*/
  384. //for(i=0; i<ADC_sample_count ;i++)
  385. // printk("After ADC data = %d\n", (int)ADC_raw_data[i]);
  386. ////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*/
  387. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  388. // {
  389. // if(average_adc_value > average_adc_value_keep2) /*joey add to keep ADC will always return lower one 2009/12/28*/
  390. // average_adc_value = average_adc_value_keep2;
  391. // }
  392. printk("ADC data = %d\n", (int)average_adc_value);
  393. put_user(average_adc_value, (unsigned long __user *)arg);
  394. // if((readl(S3C2410_GPGDAT)&(1<<1)) == 0) /*no usb charger */
  395. // average_adc_value_keep2 = average_adc_value; /*joey add to keep ADC will always return lower one 2009/12/28*/
  396. ret = 0;
  397. break;
  398. case ADC_READ_LEVEL_VAULE_TOOL: /*qisda joey add for tool read 20091207*/
  399. for(i=0; i<1000 ;i++) /*qisda joey modify from 20 to 1000 20091202*/
  400. {
  401. udelay(1000);
  402. average_adc_value += s3c_adc_read();
  403. }
  404. average_adc_value = average_adc_value/1000; /*qisda joey modify from 20 to 1000 20091202*/
  405. if (average_adc_value <= LEVEL0_MAX)
  406. {
  407. level = 0;
  408. }
  409. else if (average_adc_value <= LEVEL1_MAX && average_adc_value >= LEVEL1_MIN)
  410. {
  411. level = 1;
  412. }
  413. else if (average_adc_value <= LEVEL2_MAX && average_adc_value >= LEVEL2_MIN)
  414. {
  415. level = 2;
  416. }
  417. else if(average_adc_value <= LEVEL3_MAX && average_adc_value >= LEVEL3_MIN)
  418. {
  419. level = 3;
  420. }
  421. else if(average_adc_value >= BATTERY_FULL)
  422. {
  423. level = 4;
  424. }
  425. // printk("level = %d, ADC data = %d\n", (int)level, (int)average_adc_value);
  426. put_user(level, (unsigned long __user *)arg);
  427. ret = 0;
  428. break;
  429. case ADC_READ_RAW_VAULE_TOOL: /*qisda joey add for tool read 20091207*/
  430. for(i=0; i<1000 ;i++) /*qisda joey modify from 20 to 1000 20091202*/
  431. {
  432. udelay(1000);
  433. average_adc_value += s3c_adc_read();
  434. }
  435. average_adc_value = average_adc_value / 1000; /*qisda joey modify from 20 to 1000 20091202*/
  436. printk("ADC data = %d\n", (int)average_adc_value);
  437. put_user(average_adc_value, (unsigned long __user *)arg);
  438. ret = 0;
  439. break;
  440. case ADC_POWER_OFF:
  441. printk("power off\n");
  442. //writeb(0x0, 0xc8a30029); /*joey shut down SD bus power before p_keep pull low 2010/01/06*/
  443. s3c_moviNAND_power_off();
  444. msleep(100);
  445. #ifdef CONFIG_QISDA_BK060B00
  446. s3c2410_gpio_cfgpin(S3C2410_GPD14, S3C2410_GPD14_OUTP);
  447. s3c2410_gpio_setpin(S3C2410_GPD14, 0);
  448. #else
  449. s3c2410_gpio_cfgpin(S3C2410_GPG0, S3C2410_GPG0_OUTP);
  450. s3c2410_gpio_setpin(S3C2410_GPG0, 0);
  451. #endif
  452. ret = 0;
  453. break;
  454. #ifdef CONFIG_QISDA_AS090B00_EVT1
  455. case ADC_READ_INPUT_POWER_STATUS:
  456. data_mask = readl(S3C2410_GPHDAT);
  457. data_mask &= 0x1<<5;
  458. printk("GPH5 = %d\n", data_mask);
  459. ret = put_user(data_mask, (unsigned long __user *)arg);
  460. break;
  461. #endif
  462. case ADC_READ_CHARGING_STATUS:
  463. data_mask = readl(S3C2410_GPFDAT);
  464. data_mask &= 0x1<<6;
  465. if(data_mask) /*shiyong joey for asus 2009/12/15*/
  466. data_mask = 1;
  467. else
  468. data_mask = 0;
  469. printk("GPF6 = %d\n", data_mask);
  470. ret = put_user(data_mask, (unsigned long __user *)arg);
  471. break;
  472. case ADC_SET_PM_FUNCTION_POWER:
  473. break;
  474. #ifdef CONFIG_PM_CPU_MODE
  475. case ADC_SET_CPU_PM_MODE:
  476. // 0 ADC_CPU_DEVICE_SLEEP:
  477. // 1 ADC_CPU_STOP:
  478. // 2 ADC_CPU_DEEP_STOP:
  479. // 3 ADC_CPU_IDLE:
  480. // 4 ADC_CPU_SLEEP:
  481. pm_cpu_mode = (unsigned char) arg;
  482. // s3c2410_sleep_enter();
  483. printk("cpu_pm_mode parameter = %d\n", pm_cpu_mode);
  484. ret = 0;
  485. break;
  486. #endif
  487. /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  488. case ADC_READ_WAKEUP_SOURCE:
  489. data_mask = readl(S3C2443_WKUPSTAT);
  490. printk("Wakeup source =0x%08lx\n", data_mask);
  491. #ifdef CONFIG_PM_PLATFORM_POWER_SAVING
  492. if (copy_to_user(uarg, &data_mask, sizeof(data_mask)))
  493. return -EFAULT;
  494. /* BenQ, weichen, 2010/1/28, clear the wakeup source of 2416 for MMI */
  495. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  496. writel(0x33, S3C2443_WKUPSTAT);
  497. data_mask = readl(S3C2443_WKUPSTAT);
  498. printk("Wakeup source2 =0x%08lx\n", data_mask);
  499. #endif
  500. #endif
  501. ret = 0;
  502. break;
  503. /* BenQ, weichen, 2009/12/22, check the wakeup source of 2416 for MMI */
  504. case ADC_READ_POWER_FAIL_STATUS:
  505. data_mask = readl(S3C2410_GPGDAT) & (1<<5);
  506. printk("ADC_READ_POWER_FAIL_STATUS GPG5 = %d\n", data_mask);
  507. ret = put_user(data_mask, (unsigned long __user *)arg);
  508. break;
  509. case HIGH_LOW_PULSE: /*joey add for high/low pulse 2010/01/08*/
  510. {
  511. unsigned long percent[3]={0, 0, 0}; /*1:high sec 2:low msec 3:times*/
  512. int i;
  513. copy_from_user(percent, (unsigned long) arg, sizeof(unsigned long)*3);
  514. printk("1st=%d, 2nd=%d, 3rd=%d\n", percent[0], percent[1], percent[2]);
  515. s3c2410_gpio_cfgpin(S3C2410_GPH11, S3C2410_GPH11_OUTP);
  516. s3c2410_gpio_pullup(S3C2410_GPH11, 2);
  517. for(i=0; i<percent[2]; i++)
  518. {
  519. s3c2410_gpio_setpin(S3C2410_GPH11, 0);
  520. printk("GPH11 pull low\n");
  521. msleep(percent[1]);
  522. s3c2410_gpio_setpin(S3C2410_GPH11, 1);
  523. printk("GPH11 pull high\n");
  524. msleep(percent[0]);
  525. }
  526. //ret = put_user(data_mask, (unsigned long __user *)arg);
  527. break;
  528. }
  529. case ADC_GET_ENV: /*joey for ENV ADC read/write 2010/01/13*/
  530. copy_from_user(&env_adc_value, (unsigned long) arg, sizeof(unsigned long));
  531. printk("env_adc_value=%d\n", env_adc_value);
  532. //ret = put_user(data_mask, (unsigned long __user *)arg);
  533. break;
  534. case ADC_READ_ENV: /*joey for ENV ADC read/write 2010/01/13*/
  535. ret = put_user(env_adc_value, (unsigned long __user *)arg);
  536. printk("env_adc_value=%d\n", env_adc_value);
  537. break;
  538. case ADC_READ_VOLTAGE: /*joey for ENV ADC to voltage 2010/01/15*/
  539. if(env_adc_value > 3711 || env_adc_value < 3511)
  540. env_adc_value = 3611;
  541. printk("env_adc_value=%d\n", env_adc_value);
  542. for(i=0; i<ADC_sample_count ;i++)
  543. {
  544. msleep(1); /*joey modify for asus request 2009/12/18*/
  545. average_adc_value += s3c_adc_read();
  546. }
  547. average_adc_value = average_adc_value / ADC_sample_count;
  548. printk("average_adc_value=%d\n", average_adc_value);
  549. if(average_adc_value >= env_adc_value)
  550. env_adc_voltage = ADC_jig_voltage + (average_adc_value-env_adc_value)*100/97;
  551. else
  552. env_adc_voltage = ADC_jig_voltage - (env_adc_value-average_adc_value)*100/97;
  553. ret = put_user(env_adc_voltage, (unsigned long __user *)arg);
  554. printk("env_adc_voltage=%d\n", env_adc_voltage);
  555. break;
  556. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  557. case ADC_CLEAR_WAKEUP_EVENT:
  558. g_wakeup_event_occurs = 0;
  559. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event {
  560. //sleeping_cha_event = 0;
  561. // Qisda, 2010/02/18, TN Wei, sleep mode wakes up for usb event }
  562. printk("ADC_CLEAR_WAKEUP_EVENT: g_wakeup_event_occurs=%d\n", g_wakeup_event_occurs);
  563. ret = 0;
  564. break;
  565. #endif
  566. default:
  567. ret = -ENOIOCTLCMD;
  568. break;
  569. }
  570. return ret;
  571. }
  572. static struct file_operations s3c_adc_fops = {
  573. .owner = THIS_MODULE,
  574. .read = s3c_adc_read,
  575. .open = s3c_adc_open,
  576. .ioctl = s3c_adc_ioctl,
  577. };
  578. static struct miscdevice s3c_adc_miscdev = {
  579. .minor = ADC_MINOR,
  580. .name = "adc",
  581. .fops = &s3c_adc_fops,
  582. };
  583. /*
  584. * The functions for inserting/removing us as a module.
  585. */
  586. static int __init s3c_adc_probe(struct platform_device *pdev)
  587. {
  588. int ret;
  589. printk(KERN_INFO "s3c_adc_probe\n");
  590. adc_clock = clk_get(NULL, "adc");
  591. if (!adc_clock) {
  592. printk(KERN_ERR "failed to get adc clock source\n");
  593. return -ENOENT;
  594. }
  595. clk_enable(adc_clock);
  596. base_addr=ioremap(S3C24XX_PA_ADC, 0x20);
  597. if (base_addr == NULL) {
  598. printk(KERN_ERR "Failed to remap register block\n");
  599. return -ENOMEM;
  600. }
  601. if ((s3c_adc_cfg.presc&0xff) > 0)
  602. writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(s3c_adc_cfg.presc&0xFF), base_addr+S3C2410_ADCCON);
  603. else
  604. writel(0, base_addr+S3C2410_ADCCON);
  605. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  606. #ifdef ADC_TEST //open for debug
  607. tmp = readl(base_addr+S3C2410_ADCCON);
  608. printk("tmp = %04X!\n", tmp);
  609. tmp = tmp | 0x0080;
  610. printk("tmp = %04X!\n", tmp);
  611. writel(tmp, base_addr+S3C2410_ADCCON);
  612. #endif
  613. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status }*/
  614. /* Initialise registers */
  615. if ((s3c_adc_cfg.delay&0xffff) > 0)
  616. writel(s3c_adc_cfg.delay & 0xffff, base_addr+S3C2410_ADCDLY);
  617. ret = misc_register(&s3c_adc_miscdev);
  618. if (ret) {
  619. printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
  620. ADC_MINOR, ret);
  621. return ret;
  622. }
  623. printk(KERN_INFO "S3C ADC driver successfully probed !\n");
  624. return 0;
  625. }
  626. static int s3c_adc_remove(struct device *dev)
  627. {
  628. printk(KERN_INFO "s3c_adc_remove() of TS called !\n");
  629. return 0;
  630. }
  631. #define s3c_adc_suspend NULL
  632. #define s3c_adc_resume NULL
  633. static struct platform_driver s3c_adc_driver = {
  634. .probe = s3c_adc_probe,
  635. .remove = s3c_adc_remove,
  636. .suspend = s3c_adc_suspend,
  637. .resume = s3c_adc_resume,
  638. .driver = {
  639. .owner = THIS_MODULE,
  640. .name = "s3c2410-adc",
  641. },
  642. };
  643. static char banner[] __initdata = KERN_INFO "S3C ADC driver, (c) 2007 Samsung Electronics\n";
  644. int __init s3c_adc_init(void)
  645. {
  646. int ireturn = 0;
  647. int read_pin = -99;
  648. int i = 0;
  649. printk(banner);
  650. ireturn = platform_driver_register(&s3c_adc_driver);
  651. #ifdef CONFIG_QISDA_AS090B00_EVT1
  652. /* Qisda, ShiYong Lin, 2009/09/12, Indication for /PGOOD pin {*/
  653. s3c2410_gpio_cfgpin(S3C2410_GPH5, 0);
  654. s3c2410_gpio_pullup(S3C2410_GPH5, 2);
  655. /* Qisda, ShiYong Lin, 2009/09/12, Indication for /PGOOD pin }*/
  656. #endif
  657. /* Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function {*/
  658. /* Qisda, ShiYong Lin, 2009/09/29, Set En1 and En2 {*/
  659. for(i=0;i<10;++i)
  660. {
  661. read_pin = readl(S3C2410_GPGDAT) & (1<<1);
  662. if(read_pin != 0){
  663. if(IsWallCharger()==0){
  664. charging_source = 0;
  665. //EN2
  666. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  667. s3c2410_gpio_setpin(S3C2410_GPB0, 0);
  668. //EN1
  669. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  670. s3c2410_gpio_setpin(S3C2410_GPB4, 1);
  671. }
  672. else
  673. {
  674. charging_source = 1;
  675. //EN2
  676. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  677. s3c2410_gpio_setpin(S3C2410_GPB0, 1);
  678. //EN1
  679. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  680. s3c2410_gpio_setpin(S3C2410_GPB4, 0);
  681. }
  682. }
  683. else{
  684. charging_source = 2;
  685. //EN2
  686. s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  687. s3c2410_gpio_setpin(S3C2410_GPB0, 0);
  688. //EN1
  689. s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
  690. s3c2410_gpio_setpin(S3C2410_GPB4, 1);
  691. }
  692. }
  693. /*}, Qisda, ShiYong Lin, 2009/09/29, Set En1 and En2 */
  694. /*}, Qisda, ShiYong Lin, 2009/10/27, Modify for exception in IsWallCharger function */
  695. /* Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status {*/
  696. #ifdef ADC_TEST
  697. {
  698. int i=0;
  699. for(i=0; i<10 ;i++)
  700. {
  701. udelay(1000);
  702. s3c_adc_read();
  703. }
  704. printk("Read ADC times = %d\n",i);
  705. }
  706. #else
  707. s3c_adc_read();
  708. #endif
  709. /*}, Qisda, ShiYong Lin, 2009/07/18, ADC and Battery Status */
  710. return ireturn;
  711. }
  712. void __exit s3c_adc_exit(void)
  713. {
  714. platform_driver_unregister(&s3c_adc_driver);
  715. }
  716. module_init(s3c_adc_init);
  717. module_exit(s3c_adc_exit);
  718. MODULE_AUTHOR("alinuxguy@samsung.com>");
  719. MODULE_DESCRIPTION("s3c adc driver");
  720. MODULE_LICENSE("GPL");