orizon_ts.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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/cyio.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,
  162. I2C_CLIENT_END };
  163. /* Insmod parameters */
  164. I2C_CLIENT_INSMOD_1 (ots);
  165. struct i2c_client *ots_client;
  166. /* Each client has this additional data */
  167. struct ots_data
  168. {
  169. struct i2c_client client;
  170. };
  171. /* This is the I2C driver that will be inserted */
  172. static struct i2c_driver ots_driver ={
  173. .driver =
  174. {
  175. .name = "orizon_ts",
  176. .suspend = ots_suspend,
  177. .resume = ots_resume,
  178. },
  179. .id = I2C_DRIVERID_EEPROM,
  180. .attach_adapter = ots_attachAdapter,
  181. .detach_client = ots_detachClient,
  182. };
  183. /******************************************************************************/
  184. /**************************** i2c functions ***********************************/
  185. /******************************************************************************/
  186. #if 0
  187. static void ots_dumpI2C(void)
  188. {
  189. int Addr = 0;
  190. unsigned char value;
  191. int I,J;
  192. printk("-------------------------------------------------------------------------------\n");
  193. printk("-------------------------------------I²C TS------------------------------------\n");
  194. for ( J = 0; J < 16; J++ )
  195. {
  196. printk("%04X: ", Addr);
  197. for ( I = 0; I < 16; I++, Addr++ )
  198. {
  199. value = i2c_smbus_read_byte_data(ots_client, Addr);
  200. mdelay(4);
  201. printk("%02X ", value);
  202. }
  203. printk(" | ");
  204. Addr -= 16;
  205. for ( I = 0; I < 16; I++, Addr++ )
  206. {
  207. value = i2c_smbus_read_byte_data(ots_client, Addr);
  208. mdelay(4);
  209. printk("%c", isprint(value) ? value : '.');
  210. }
  211. printk("\n");
  212. }
  213. printk("-------------------------------------------------------------------------------\n");
  214. printk("-------------------------------------------------------------------------------\n");
  215. }
  216. #endif
  217. static int ots_attachAdapter (struct i2c_adapter *adapter)
  218. {
  219. return i2c_probe(adapter, &addr_data, ots_detect);
  220. }
  221. /* This function is called by i2c_probe */
  222. static int ots_detect (struct i2c_adapter *adapter, int address, int kind)
  223. {
  224. struct ots_data *data = NULL;
  225. int err = 0;
  226. FUNC_IN();
  227. //DBG(">>%s(%p, 0x%X, 0x%X)", __func__, adapter, address, kind);
  228. if ( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
  229. | I2C_FUNC_SMBUS_BYTE) )
  230. goto exit;
  231. if ( address == OTS_ADDR_I2C )
  232. {
  233. if ( !(data = kzalloc(sizeof (struct ots_data), GFP_KERNEL)) )
  234. {
  235. err = -ENOMEM;
  236. goto exit;
  237. }
  238. ots_client = &data->client;
  239. i2c_set_clientdata(ots_client, data);
  240. ots_client->addr = address;
  241. ots_client->adapter = adapter;
  242. ots_client->driver = &ots_driver;
  243. ots_client->flags = 0;
  244. /* Fill in the remaining client fields */
  245. strlcpy(ots_client->name, "orizon_ts", I2C_NAME_SIZE);
  246. /* Tell the I2C layer a new client has arrived */
  247. if ( (err = i2c_attach_client(ots_client)) )
  248. {
  249. goto exit_kfree;
  250. }
  251. ots_setPowerMode(POWER_ONAUTOSTANDBY);
  252. ots_setDeviceParameters(INT_MODE, X_SENS, Y_SENS);
  253. /* Now we are sure that the driver init successfully, then aquire the IRQ */
  254. set_irq_type(IRQ_EINT2, IRQT_FALLING);
  255. if ( request_irq(IRQ_EINT2, ots_interrupt, SA_SHIRQ, "orizon_ts", &ots_client) )
  256. {
  257. printk(KERN_ERR "failed to get interrupt resouce at IRQ_EINT2.\n");
  258. goto exit_kfree;
  259. }
  260. enable_irq_wake(IRQ_EINT2);
  261. }
  262. goto exit;
  263. exit_kfree:
  264. kfree(data);
  265. exit:
  266. FUNC_OUTR(err);
  267. return err;
  268. }
  269. static int ots_detachClient (struct i2c_client *client)
  270. {
  271. int err = 0;
  272. FUNC_IN();
  273. err = i2c_detach_client(client);
  274. if ( err )
  275. goto exit;
  276. kfree(i2c_get_clientdata(client));
  277. exit:
  278. FUNC_OUTR(err);
  279. return err;
  280. }
  281. static int ots_suspend (struct device *dev, pm_message_t state)
  282. {
  283. int ret = 0;
  284. FUNC_IN();
  285. FUNC_OUTR(ret);
  286. return ret;
  287. }
  288. static int ots_resume (struct device *dev)
  289. {
  290. FUNC_IN();
  291. FUNC_OUT();
  292. return 0;
  293. }
  294. /******************************************************************************/
  295. /********************** Interrupt Related functions ***************************/
  296. /******************************************************************************/
  297. static int oldX = 0, oldY = 0;
  298. static void ots_checkWorkFunction (struct work_struct *work)
  299. {
  300. unsigned long x1, y1, x2, y2;
  301. FUNC_IN();
  302. /* Here do what the interrupt should... (ie read touch values) */
  303. /* TODO: I reversed the X / Y axis to match old driver and revese the X value */
  304. y1 = i2c_smbus_read_byte_data(ots_client, 0);
  305. y1 |= i2c_smbus_read_byte_data(ots_client, 1) << 8;
  306. x1 = i2c_smbus_read_byte_data(ots_client, 2);
  307. x1 |= i2c_smbus_read_byte_data(ots_client, 3) << 8;
  308. y2 = i2c_smbus_read_byte_data(ots_client, 4);
  309. y2 |= i2c_smbus_read_byte_data(ots_client, 5) << 8;
  310. x2 = i2c_smbus_read_byte_data(ots_client, 6);
  311. x2 |= i2c_smbus_read_byte_data(ots_client, 7) << 8;
  312. DBG("x1: %lu\ty1: %lu\tx2: %lu\ty2: %lu", x1, y1, x2, y2);
  313. if ((x1 == 0) && (y1 == 0))
  314. { /* We assume that this is a finger up event */
  315. if ( Cyio_PushEvent('R', 1) >= 0 )
  316. {
  317. Cyio_PushEvent((oldX >> 8) & 0xFF, 0);
  318. Cyio_PushEvent((oldX >> 0) & 0xFF, 0);
  319. Cyio_PushEvent((oldY >> 8) & 0xFF, 0);
  320. Cyio_PushEvent((oldY >> 0) & 0xFF, 0);
  321. }
  322. }
  323. else
  324. {
  325. oldX = 600 - x1;
  326. oldY = y1;
  327. }
  328. /* Say I get the data */
  329. ots_ackInterrupt();
  330. FUNC_OUT();
  331. }
  332. static irqreturn_t ots_interrupt (int irq, void *dev_id)
  333. {
  334. irqreturn_t ret = IRQ_HANDLED;
  335. static int initialised = 0;
  336. FUNC_IN();
  337. if (initialised == 0)
  338. {
  339. INIT_WORK(&ots_check_work, ots_checkWorkFunction);
  340. initialised = 1;
  341. }
  342. else
  343. {
  344. PREPARE_WORK(&ots_check_work, ots_checkWorkFunction);
  345. }
  346. schedule_work(&ots_check_work);
  347. //FUNC_OUTR((int)ret);
  348. return ret;
  349. }
  350. /******************************************************************************/
  351. /******************************* Chip functions *******************************/
  352. /******************************************************************************/
  353. static void ots_setPowerMode (Ots_PowerModes power)
  354. {
  355. unsigned char tmpReg;
  356. FUNC_IN();
  357. if (power == ots_currentPowerMode)
  358. return; /* No need to do anything, we are in the same power mode... */
  359. switch(power)
  360. {
  361. default:
  362. case POWER_UNDEFINED:
  363. /* Error */
  364. DBG("Error: invalid power mode #%d", power);
  365. break;
  366. case POWER_ON:
  367. /* Set the power to on */
  368. s3c2410_gpio_setpin(S3C2410_GPD10, 1);
  369. msleep(100);
  370. /* TODO: Does we need to set chip settings? */
  371. tmpReg = 0x0; /* Set in "Active Mode" */
  372. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  373. msleep(400);
  374. break;
  375. case POWER_OFF:
  376. /* Set the power to off */
  377. s3c2410_gpio_setpin(S3C2410_GPD10, 0);
  378. msleep(10);
  379. break;
  380. case POWER_ONAUTOSTANDBY:
  381. if ( (ots_currentPowerMode != POWER_ON) &&
  382. (ots_currentPowerMode != POWER_DEEPSLEEP) )
  383. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  384. //tmpReg = i2c_smbus_read_byte_data(ots_client, 0x24);
  385. tmpReg = (((50) /* timeout in ms for auto sleep */ ) & 0x0F) << 4;
  386. tmpReg |= (1<< 2); /* Activate auto sleep mode */
  387. tmpReg |= 0x1; /* Set in "Sleep Mode" */
  388. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  389. msleep(4);
  390. break;
  391. case POWER_DEEPSLEEP:
  392. if ( (ots_currentPowerMode != POWER_ON) &&
  393. (ots_currentPowerMode != POWER_ONAUTOSTANDBY) )
  394. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  395. tmpReg = 0x02;
  396. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  397. msleep(4);
  398. break;
  399. }
  400. ots_currentPowerMode = power;
  401. FUNC_OUT();
  402. }
  403. static void ots_setDeviceParameters (unsigned char int_mode,
  404. unsigned char x_sensitivity,
  405. unsigned char y_sensitivity)
  406. {
  407. unsigned char tmpReg;
  408. FUNC_IN();
  409. /* Then set INT_WIDTH */
  410. /*
  411. * Interrupt width register @114 [0x72]
  412. * b7-b0: int width
  413. * Default: 0x64
  414. */
  415. i2c_smbus_write_byte_data(ots_client, 0x72, INT_DELAY);
  416. mdelay(4);
  417. /* Now set sensitivity */
  418. i2c_smbus_write_byte_data(ots_client, 0x6F, x_sensitivity);
  419. mdelay(4);
  420. i2c_smbus_write_byte_data(ots_client, 0x70, y_sensitivity);
  421. mdelay(4);
  422. i2c_smbus_write_byte_data(ots_client, 0xBE, 0x01); // TEST
  423. tmpReg = i2c_smbus_read_byte_data(ots_client, 0xBE); // TEST
  424. DBG("0xBE = %02X", tmpReg);
  425. DBG("Firmware Version =0x%x\n", i2c_smbus_read_byte_data(ots_client, 0x77));
  426. /* Activate the device ! */
  427. /*
  428. * Interrupt mode Setting register @113 [0x71]
  429. * b7-b6-b5: TP_NUM : How many finger, 000: none, 001: One, 010: Two
  430. * b4: INT_RELEASE: used to ack (1) IRQ in periodical mode
  431. * b3: EN_INT: Enable int (1: enabled, 0: disable)
  432. * b2: INT_POL: 0: active low, 1: active high
  433. * b1-b0: INT_MODE: 00: INT periodicaly, 01: INT assert when coord changes
  434. * 10: TOuch indicate, 11: INT assert when INT_RELEASE modified
  435. *
  436. * Default 0x0C [000 0 1 1 00]
  437. * Qisda: 0x0A [000 0 1 0 10]
  438. * Int periodicaly, Active High, and INT enabled
  439. */
  440. /* 2 Finger Active High Mode */
  441. tmpReg = (FINGER_NUM << 5) | (1 << 3) | (0 << 2) | ((int_mode & 0x03) << 0);
  442. DBG("Settings: 0x%02X", tmpReg);
  443. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  444. mdelay(4);
  445. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71); // TEST
  446. DBG("[0x71] Settings = %02X", tmpReg);
  447. FUNC_OUT();
  448. }
  449. static void ots_ackInterrupt (void)
  450. {
  451. unsigned char tmpReg;
  452. FUNC_IN();
  453. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71);
  454. tmpReg |= (1<<4);
  455. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  456. FUNC_OUT();
  457. }
  458. /******************************************************************************/
  459. /****************************** Module functions ******************************/
  460. /******************************************************************************/
  461. static int __init ots_init (void)
  462. {
  463. FUNC_IN();
  464. /* if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  465. {
  466. }*/
  467. /* Init GPIOs */
  468. s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
  469. s3c2410_gpio_pullup(S3C2410_GPD10, 2);
  470. i2c_add_driver(&ots_driver);
  471. FUNC_OUT();
  472. return 0;
  473. }
  474. // ---------------------------------------------------------------------------
  475. static void __exit ots_exit (void)
  476. {
  477. FUNC_IN();
  478. /*if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  479. {
  480. }*/
  481. /* Deinit GPIOs */
  482. /* Nothing to do, leave it as output is good enought, just set the
  483. * device as power off */
  484. ots_setPowerMode(POWER_OFF);
  485. i2c_del_driver(&ots_driver);
  486. FUNC_OUT();
  487. }
  488. // ---------------------------------------------------------------------------
  489. module_init (ots_init);
  490. module_exit (ots_exit);
  491. // ---------------------------------------------------------------------------
  492. MODULE_LICENSE ("GPL");
  493. MODULE_AUTHOR ("Bookeen <developers@bookeen.com>");
  494. MODULE_VERSION ("1.0");
  495. MODULE_DESCRIPTION ("Cybook Orizon Touchpanel driver");
  496. // ===========================================================================