orizon_ts.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. // ===========================================================================
  2. // orizon_ts.c
  3. // Copyright (C) 2003-2010 Bookeen - All rights reserved
  4. // ===========================================================================
  5. /* TODO: Verify if all this includes are necessary */
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <asm/atomic.h>
  9. #include <asm/io.h>
  10. #include <asm/arch/irqs.h>
  11. #include <asm/arch/gpio.h>
  12. #include <linux/delay.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/irq.h>
  15. #include <linux/jiffies.h>
  16. #include <linux/i2c.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/kthread.h>
  19. #include <linux/mutex.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/ctype.h>
  22. #include <cybook.h>
  23. #include <linux/cyevent.h>
  24. //#define DEBUG_MESSAGES
  25. //#define DEBUG_TRACEFUNC
  26. #define MODULE_NAME "ORIZON-TS"
  27. #define FINGER_NUM 0x00
  28. #define INT_DELAY 0x64 /* Default 0x64 */
  29. #define INT_MODE 0x01
  30. #define X_SENS 0x22 /* Default 0x14 */
  31. #define Y_SENS 0x22 /* Default 0x14 */
  32. #ifdef DEBUG_MESSAGES
  33. enum InfoLevel
  34. {
  35. INFO_ERROR = 0,
  36. INFO_WARNING,
  37. INFO_NORMAL,
  38. INFO_DEBUG,
  39. INFO_VERBOSE,
  40. };
  41. # ifndef VERBOSE_LEVEL
  42. # define VERBOSE_LEVEL INFO_VERBOSE
  43. # endif
  44. # ifdef DEBUG_TRACEFUNC
  45. static int _dbg_FunctionLevel = 0;
  46. # define MSG(str) {\
  47. int __i;\
  48. printk(KERN_ALERT "+");\
  49. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  50. printk("-");\
  51. printk("||" str "\n");\
  52. }
  53. # define DBG(str, ...) {\
  54. int __i;\
  55. printk(KERN_ALERT "+");\
  56. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  57. printk("-");\
  58. printk("||" str "\n", __VA_ARGS__);\
  59. }
  60. # define INFOL(level, s) do {\
  61. if (level <= VERBOSE_LEVEL) {\
  62. int __i;\
  63. printk(KERN_ALERT "+");\
  64. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  65. printk("-");\
  66. printk("<%d>%s:%s(): ", level, __FILE__, __func__); printk s; printk("\n");\
  67. }\
  68. } while(0)
  69. # define FUNC_IN() {\
  70. int __i;\
  71. _dbg_FunctionLevel++;\
  72. printk(KERN_ALERT "+");\
  73. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  74. printk("-");\
  75. printk(">> %s() >>\n", __func__);\
  76. }
  77. # define FUNC_OUT() {\
  78. int __i;\
  79. printk(KERN_ALERT "+");\
  80. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  81. printk("-");\
  82. printk("<< %s() <<\n", __func__);\
  83. _dbg_FunctionLevel--;\
  84. }
  85. # define FUNC_OUTR(val) {\
  86. int __i;\
  87. printk(KERN_ALERT "+");\
  88. for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
  89. printk("-");\
  90. printk("<< %s() = %d <<\n", __func__, val);\
  91. _dbg_FunctionLevel--;\
  92. }
  93. # else /* DEBUG_TRACEFUNC */
  94. # define MSG(str) do {\
  95. printk(KERN_ALERT MODULE_NAME ": " str "\n");\
  96. } while(0)
  97. # define DBG(str, ...) do {\
  98. printk(KERN_ALERT MODULE_NAME ": " str "\n", __VA_ARGS__);\
  99. } while(0)
  100. # define FUNC_IN() do {\
  101. } while(0)
  102. # define FUNC_OUT() do {\
  103. } while(0)
  104. # define FUNC_OUTR(val) do {\
  105. printk(KERN_ALERT MODULE_NAME ": %s() return %d\n", __func__, val);\
  106. } while(0)
  107. # define INFOL(level, s) do {\
  108. if (level <= VERBOSE_LEVEL) {\
  109. printk("<%d>%s:%s(): ", level, __FILE__, __func__); printk s; printk("\n");\
  110. }\
  111. } while(0)
  112. # endif /* DEBUG_TRACEFUNC */
  113. #else /* DEBUG_MESSAGES */
  114. # define MSG(str)
  115. # define DBG(str, ...)
  116. # define FUNC_IN()
  117. # define FUNC_OUT()
  118. # define FUNC_OUTR(val)
  119. # define INFOL(level, s)
  120. # define INFO(s)
  121. #endif /* DEBUG_MESSAGES */
  122. typedef enum
  123. {
  124. POWER_UNDEFINED = -1,
  125. POWER_OFF = 0,
  126. POWER_ON,
  127. POWER_ONAUTOSTANDBY,
  128. POWER_DEEPSLEEP,
  129. } Ots_PowerModes;
  130. /*============================================================================*/
  131. /*============================= Prototypes ===================================*/
  132. /*============================================================================*/
  133. /**************************** i2c functions ***********************************/
  134. static int ots_attachAdapter (struct i2c_adapter *adapter);
  135. static int ots_detect (struct i2c_adapter *adapter, int address, int kind);
  136. static int ots_detachClient (struct i2c_client *client);
  137. static int ots_suspend (struct device *dev, pm_message_t state);
  138. static int ots_resume (struct device *dev);
  139. //static void ots_dumpI2C(void);
  140. /**************************** irq functions ***********************************/
  141. static void ots_checkWorkFunction (struct work_struct *work);
  142. static irqreturn_t ots_interrupt (int irq, void *dev_id);
  143. /******************************* Chip functions *******************************/
  144. static void ots_setPowerMode (Ots_PowerModes power);
  145. static void ots_setDeviceParameters (unsigned char int_mode,
  146. unsigned char x_sensitivity,
  147. unsigned char y_sensitivity);
  148. static void ots_ackInterrupt (void);
  149. /****************************** Module functions ******************************/
  150. static int __init ots_init (void);
  151. static void __exit ots_exit (void);
  152. /*============================= End of prototypes ============================*/
  153. /*============================================================================*/
  154. /*============================= Variables ====================================*/
  155. /*============================================================================*/
  156. struct workqueue_struct *ots_check_workqueue;
  157. struct work_struct ots_check_work;
  158. static Ots_PowerModes ots_currentPowerMode = POWER_UNDEFINED;
  159. /****************************** i2c configuration *****************************/
  160. #define OTS_ADDR_I2C 0x5C
  161. static unsigned short normal_i2c[] = { OTS_ADDR_I2C, I2C_CLIENT_END };
  162. /* Insmod parameters */
  163. I2C_CLIENT_INSMOD_1 (ots);
  164. struct i2c_client *ots_client;
  165. /* Each client has this additional data */
  166. struct ots_data
  167. {
  168. struct i2c_client client;
  169. };
  170. /* This is the I2C driver that will be inserted */
  171. static struct i2c_driver ots_driver ={
  172. .driver =
  173. {
  174. .name = "orizon_ts",
  175. .suspend = ots_suspend,
  176. .resume = ots_resume,
  177. },
  178. .id = I2C_DRIVERID_EEPROM,
  179. .attach_adapter = ots_attachAdapter,
  180. .detach_client = ots_detachClient,
  181. };
  182. /******************************************************************************/
  183. /**************************** i2c functions ***********************************/
  184. /******************************************************************************/
  185. #if 0
  186. static void ots_dumpI2C(void)
  187. {
  188. int Addr = 0;
  189. unsigned char value;
  190. int I,J;
  191. printk("-------------------------------------------------------------------------------\n");
  192. printk("-------------------------------------I²C TS------------------------------------\n");
  193. for ( J = 0; J < 16; J++ )
  194. {
  195. printk("%04X: ", Addr);
  196. for ( I = 0; I < 16; I++, Addr++ )
  197. {
  198. value = i2c_smbus_read_byte_data(ots_client, Addr);
  199. mdelay(4);
  200. printk("%02X ", value);
  201. }
  202. printk(" | ");
  203. Addr -= 16;
  204. for ( I = 0; I < 16; I++, Addr++ )
  205. {
  206. value = i2c_smbus_read_byte_data(ots_client, Addr);
  207. mdelay(4);
  208. printk("%c", isprint(value) ? value : '.');
  209. }
  210. printk("\n");
  211. }
  212. printk("-------------------------------------------------------------------------------\n");
  213. printk("-------------------------------------------------------------------------------\n");
  214. }
  215. #endif
  216. static int ots_attachAdapter (struct i2c_adapter *adapter)
  217. {
  218. return i2c_probe(adapter, &addr_data, ots_detect);
  219. }
  220. /* This function is called by i2c_probe */
  221. static int ots_detect (struct i2c_adapter *adapter, int address, int kind)
  222. {
  223. struct ots_data *data = NULL;
  224. int err = 0;
  225. FUNC_IN();
  226. //DBG(">>%s(%p, 0x%X, 0x%X)", __func__, adapter, address, kind);
  227. if ( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
  228. | I2C_FUNC_SMBUS_BYTE) )
  229. goto exit;
  230. if ( address == OTS_ADDR_I2C )
  231. {
  232. if ( !(data = kzalloc(sizeof (struct ots_data), GFP_KERNEL)) )
  233. {
  234. err = -ENOMEM;
  235. goto exit;
  236. }
  237. ots_client = &data->client;
  238. i2c_set_clientdata(ots_client, data);
  239. ots_client->addr = address;
  240. ots_client->adapter = adapter;
  241. ots_client->driver = &ots_driver;
  242. ots_client->flags = 0;
  243. /* Fill in the remaining client fields */
  244. strlcpy(ots_client->name, "orizon_ts", I2C_NAME_SIZE);
  245. /* Tell the I2C layer a new client has arrived */
  246. if ( (err = i2c_attach_client(ots_client)) )
  247. {
  248. goto exit_kfree;
  249. }
  250. ots_setPowerMode(POWER_ON/*AUTOSTANDBY*/);
  251. ots_setDeviceParameters(INT_MODE, X_SENS, Y_SENS);
  252. /* Now we are sure that the driver init successfully, then aquire the IRQ */
  253. set_irq_type(IRQ_EINT2, IRQT_FALLING);
  254. if ( request_irq(IRQ_EINT2, ots_interrupt, SA_SHIRQ, "orizon_ts", &ots_client) )
  255. {
  256. printk(KERN_ERR "failed to get interrupt resouce at IRQ_EINT2.\n");
  257. goto exit_kfree;
  258. }
  259. enable_irq_wake(IRQ_EINT2);
  260. }
  261. goto exit;
  262. exit_kfree:
  263. kfree(data);
  264. exit:
  265. FUNC_OUTR(err);
  266. return err;
  267. }
  268. static int ots_detachClient (struct i2c_client *client)
  269. {
  270. int err = 0;
  271. FUNC_IN();
  272. err = i2c_detach_client(client);
  273. if ( err )
  274. goto exit;
  275. kfree(i2c_get_clientdata(client));
  276. exit:
  277. FUNC_OUTR(err);
  278. return err;
  279. }
  280. static int ots_suspend (struct device *dev, pm_message_t state)
  281. {
  282. int ret = 0;
  283. FUNC_IN();
  284. FUNC_OUTR(ret);
  285. return ret;
  286. }
  287. static int ots_resume (struct device *dev)
  288. {
  289. FUNC_IN();
  290. FUNC_OUT();
  291. return 0;
  292. }
  293. /******************************************************************************/
  294. /********************** Interrupt Related functions ***************************/
  295. /******************************************************************************/
  296. static int oldX1 = 0, oldY1 = 0;
  297. static int oldX2 = 0, oldY2 = 0;
  298. enum { FINGER_UP = 0, FINGER_MOVE, FINGER_DOWN };
  299. static void ots_checkWorkFunction (struct work_struct *work)
  300. {
  301. unsigned long x1, y1, x2, y2;
  302. static int status = FINGER_UP;
  303. CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_TOUCH);
  304. FUNC_IN();
  305. /* Here do what the interrupt should... (ie read touch values) */
  306. /* TODO: I reversed the X / Y axis to match old driver and revese the X value */
  307. y1 = i2c_smbus_read_byte_data(ots_client, 0);
  308. y1 |= i2c_smbus_read_byte_data(ots_client, 1) << 8;
  309. x1 = i2c_smbus_read_byte_data(ots_client, 2);
  310. x1 |= i2c_smbus_read_byte_data(ots_client, 3) << 8;
  311. y2 = i2c_smbus_read_byte_data(ots_client, 4);
  312. y2 |= i2c_smbus_read_byte_data(ots_client, 5) << 8;
  313. x2 = i2c_smbus_read_byte_data(ots_client, 6);
  314. x2 |= i2c_smbus_read_byte_data(ots_client, 7) << 8;
  315. DBG("x1: %lu\ty1: %lu\tx2: %lu\ty2: %lu", x1, y1, x2, y2);
  316. if ((x1 == 0) && (y1 == 0) && (x2 == 0) && (y2 == 0))
  317. { /* We assume that this is a finger up event */
  318. if (status != FINGER_UP)
  319. {
  320. event.flags |= CYEVENT_FLAG_TOUCH_UP;
  321. status = FINGER_UP;
  322. }
  323. else
  324. goto exit; /* ignore the event */
  325. }
  326. else
  327. {
  328. oldX1 = 600 - x1;
  329. oldY1 = y1;
  330. if ((x2 != 0) || (y2 != 0))
  331. {
  332. oldX2 = 600 - x2;
  333. oldY2 = y2;
  334. event.data.touch.fingers = 2;
  335. }
  336. else
  337. {
  338. oldX2 = oldY2 = 0;
  339. event.data.touch.fingers = 1;
  340. }
  341. if (status == FINGER_UP)
  342. {
  343. event.flags |= CYEVENT_FLAG_TOUCH_DOWN;
  344. status = FINGER_DOWN;
  345. }
  346. else
  347. {
  348. event.flags |= CYEVENT_FLAG_TOUCH_MOVE;
  349. status = FINGER_MOVE;
  350. }
  351. }
  352. event.data.touch.x1 = oldX1;
  353. event.data.touch.y1 = oldY1;
  354. event.data.touch.x2 = oldX2;
  355. event.data.touch.y2 = oldY2;
  356. if (status == FINGER_UP)
  357. oldX1 = oldY1 = oldX2 = oldY2 = 0;
  358. CyEvent_PushOrUpdateUniqueEventFlaged(&event, false, CYEVENT_FLASH_TOUCH_MASK);
  359. exit:
  360. /* Say I get the data */
  361. ots_ackInterrupt();
  362. FUNC_OUT();
  363. }
  364. static irqreturn_t ots_interrupt (int irq, void *dev_id)
  365. {
  366. irqreturn_t ret = IRQ_HANDLED;
  367. static int initialised = 0;
  368. FUNC_IN();
  369. if (initialised == 0)
  370. {
  371. INIT_WORK(&ots_check_work, ots_checkWorkFunction);
  372. initialised = 1;
  373. }
  374. else
  375. {
  376. PREPARE_WORK(&ots_check_work, ots_checkWorkFunction);
  377. }
  378. schedule_work(&ots_check_work);
  379. //FUNC_OUTR((int)ret);
  380. return ret;
  381. }
  382. /******************************************************************************/
  383. /******************************* Chip functions *******************************/
  384. /******************************************************************************/
  385. static void ots_setPowerMode (Ots_PowerModes power)
  386. {
  387. unsigned char tmpReg;
  388. FUNC_IN();
  389. if (power == ots_currentPowerMode)
  390. return; /* No need to do anything, we are in the same power mode... */
  391. switch(power)
  392. {
  393. default:
  394. case POWER_UNDEFINED:
  395. /* Error */
  396. DBG("Error: invalid power mode #%d", power);
  397. break;
  398. case POWER_ON:
  399. /* Set the power to on */
  400. s3c2410_gpio_setpin(S3C2410_GPD10, 1);
  401. msleep(100);
  402. /* TODO: Does we need to set chip settings? */
  403. tmpReg = 0x0; /* Set in "Active Mode" */
  404. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  405. msleep(400);
  406. break;
  407. case POWER_OFF:
  408. /* Set the power to off */
  409. s3c2410_gpio_setpin(S3C2410_GPD10, 0);
  410. msleep(10);
  411. break;
  412. case POWER_ONAUTOSTANDBY:
  413. if ( (ots_currentPowerMode != POWER_ON) &&
  414. (ots_currentPowerMode != POWER_DEEPSLEEP) )
  415. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  416. //tmpReg = i2c_smbus_read_byte_data(ots_client, 0x24);
  417. tmpReg = (((16) /* timeout in ms for auto sleep */ ) & 0x0F) << 4;
  418. tmpReg |= (1<< 2); /* Activate auto sleep mode */
  419. tmpReg |= 0x1; /* Set in "Sleep Mode" */
  420. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  421. msleep(4);
  422. break;
  423. case POWER_DEEPSLEEP:
  424. if ( (ots_currentPowerMode != POWER_ON) &&
  425. (ots_currentPowerMode != POWER_ONAUTOSTANDBY) )
  426. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  427. tmpReg = 0x02;
  428. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  429. msleep(4);
  430. break;
  431. }
  432. ots_currentPowerMode = power;
  433. FUNC_OUT();
  434. }
  435. static void ots_setDeviceParameters (unsigned char int_mode,
  436. unsigned char x_sensitivity,
  437. unsigned char y_sensitivity)
  438. {
  439. unsigned char tmpReg;
  440. FUNC_IN();
  441. /* Then set INT_WIDTH */
  442. /*
  443. * Interrupt width register @114 [0x72]
  444. * b7-b0: int width
  445. * Default: 0x64
  446. */
  447. i2c_smbus_write_byte_data(ots_client, 0x72, INT_DELAY);
  448. mdelay(4);
  449. /* Now set sensitivity */
  450. i2c_smbus_write_byte_data(ots_client, 0x6F, x_sensitivity);
  451. mdelay(4);
  452. i2c_smbus_write_byte_data(ots_client, 0x70, y_sensitivity);
  453. mdelay(4);
  454. i2c_smbus_write_byte_data(ots_client, 0xBE, 0x01); // TEST
  455. tmpReg = i2c_smbus_read_byte_data(ots_client, 0xBE); // TEST
  456. DBG("0xBE = %02X", tmpReg);
  457. printk("TS Firmware Version = 0x%x\n", i2c_smbus_read_byte_data(ots_client, 0x77));
  458. /* Activate the device ! */
  459. /*
  460. * Interrupt mode Setting register @113 [0x71]
  461. * b7-b6-b5: TP_NUM : How many finger, 000: none, 001: One, 010: Two
  462. * b4: INT_RELEASE: used to ack (1) IRQ in periodical mode
  463. * b3: EN_INT: Enable int (1: enabled, 0: disable)
  464. * b2: INT_POL: 0: active low, 1: active high
  465. * b1-b0: INT_MODE: 00: INT periodicaly, 01: INT assert when coord changes
  466. * 10: TOuch indicate, 11: INT assert when INT_RELEASE modified
  467. *
  468. * Default 0x0C [000 0 1 1 00]
  469. * Qisda: 0x0A [000 0 1 0 10]
  470. * Int periodicaly, Active High, and INT enabled
  471. */
  472. /* 2 Finger Active High Mode */
  473. tmpReg = (FINGER_NUM << 5) | (1 << 3) | (0 << 2) | ((int_mode & 0x03) << 0);
  474. DBG("Settings: 0x%02X", tmpReg);
  475. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  476. mdelay(4);
  477. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71); // TEST
  478. DBG("[0x71] Settings = %02X", tmpReg);
  479. FUNC_OUT();
  480. }
  481. static void ots_ackInterrupt (void)
  482. {
  483. unsigned char tmpReg;
  484. FUNC_IN();
  485. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71);
  486. tmpReg |= (1<<4);
  487. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  488. FUNC_OUT();
  489. }
  490. /******************************************************************************/
  491. /****************************** Module functions ******************************/
  492. /******************************************************************************/
  493. static int __init ots_init (void)
  494. {
  495. FUNC_IN();
  496. /* if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  497. {
  498. }*/
  499. /* Init GPIOs */
  500. s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
  501. s3c2410_gpio_pullup(S3C2410_GPD10, 2);
  502. i2c_add_driver(&ots_driver);
  503. FUNC_OUT();
  504. return 0;
  505. }
  506. // ---------------------------------------------------------------------------
  507. static void __exit ots_exit (void)
  508. {
  509. FUNC_IN();
  510. /*if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  511. {
  512. }*/
  513. /* Deinit GPIOs */
  514. /* Nothing to do, leave it as output is good enought, just set the
  515. * device as power off */
  516. ots_setPowerMode(POWER_OFF);
  517. i2c_del_driver(&ots_driver);
  518. FUNC_OUT();
  519. }
  520. // ---------------------------------------------------------------------------
  521. module_init (ots_init);
  522. module_exit (ots_exit);
  523. // ---------------------------------------------------------------------------
  524. MODULE_LICENSE ("GPL");
  525. MODULE_AUTHOR ("Bookeen <developers@bookeen.com>");
  526. MODULE_VERSION ("1.0");
  527. MODULE_DESCRIPTION ("Cybook Orizon Touchpanel driver");
  528. // ===========================================================================