orizon_ts.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. }
  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 void ots_checkWorkFunction (struct work_struct *work)
  297. {
  298. unsigned long x1, y1, x2, y2;
  299. FUNC_IN();
  300. /* Here do what the interrupt should... (ie read touch values) */
  301. x1 = i2c_smbus_read_byte_data(ots_client, 0);
  302. x1 |= i2c_smbus_read_byte_data(ots_client, 1) << 8;
  303. y1 = i2c_smbus_read_byte_data(ots_client, 2);
  304. y1 |= i2c_smbus_read_byte_data(ots_client, 3) << 8;
  305. x2 = i2c_smbus_read_byte_data(ots_client, 4);
  306. x2 |= i2c_smbus_read_byte_data(ots_client, 5) << 8;
  307. y2 = i2c_smbus_read_byte_data(ots_client, 6);
  308. y2 |= i2c_smbus_read_byte_data(ots_client, 7) << 8;
  309. DBG("x1: %lu\ty1: %lu\ty1: %lu\ty2: %lu", x1, y1, x2, y2);
  310. /* Say I get the data */
  311. ots_ackInterrupt();
  312. FUNC_OUT();
  313. }
  314. static irqreturn_t ots_interrupt (int irq, void *dev_id)
  315. {
  316. irqreturn_t ret = IRQ_HANDLED;
  317. static int initialised = 0;
  318. FUNC_IN();
  319. if (initialised == 0)
  320. {
  321. INIT_WORK(&ots_check_work, ots_checkWorkFunction);
  322. initialised = 1;
  323. }
  324. else
  325. {
  326. PREPARE_WORK(&ots_check_work, ots_checkWorkFunction);
  327. }
  328. schedule_work(&ots_check_work);
  329. //FUNC_OUTR((int)ret);
  330. return ret;
  331. }
  332. /******************************************************************************/
  333. /******************************* Chip functions *******************************/
  334. /******************************************************************************/
  335. static void ots_setPowerMode (Ots_PowerModes power)
  336. {
  337. unsigned char tmpReg;
  338. FUNC_IN();
  339. if (power == ots_currentPowerMode)
  340. return; /* No need to do anything, we are in the same power mode... */
  341. switch(power)
  342. {
  343. default:
  344. case POWER_UNDEFINED:
  345. /* Error */
  346. DBG("Error: invalid power mode #%d", power);
  347. break;
  348. case POWER_ON:
  349. /* Set the power to on */
  350. s3c2410_gpio_setpin(S3C2410_GPD10, 1);
  351. msleep(100);
  352. /* TODO: Does we need to set chip settings? */
  353. tmpReg = 0x0; /* Set in "Active Mode" */
  354. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  355. msleep(400);
  356. break;
  357. case POWER_OFF:
  358. /* Set the power to off */
  359. s3c2410_gpio_setpin(S3C2410_GPD10, 0);
  360. msleep(10);
  361. break;
  362. case POWER_ONAUTOSTANDBY:
  363. if ( (ots_currentPowerMode != POWER_ON) &&
  364. (ots_currentPowerMode != POWER_DEEPSLEEP) )
  365. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  366. //tmpReg = i2c_smbus_read_byte_data(ots_client, 0x24);
  367. tmpReg = (((50) /* timeout in ms for auto sleep */ ) & 0x0F) << 4;
  368. tmpReg |= (1<< 2); /* Activate auto sleep mode */
  369. tmpReg |= 0x1; /* Set in "Sleep Mode" */
  370. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  371. msleep(4);
  372. break;
  373. case POWER_DEEPSLEEP:
  374. if ( (ots_currentPowerMode != POWER_ON) &&
  375. (ots_currentPowerMode != POWER_ONAUTOSTANDBY) )
  376. ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
  377. tmpReg = 0x02;
  378. i2c_smbus_write_byte_data(ots_client, 0x73, tmpReg);
  379. msleep(4);
  380. break;
  381. }
  382. ots_currentPowerMode = power;
  383. FUNC_OUT();
  384. }
  385. static void ots_setDeviceParameters (unsigned char int_mode,
  386. unsigned char x_sensitivity,
  387. unsigned char y_sensitivity)
  388. {
  389. unsigned char tmpReg;
  390. FUNC_IN();
  391. /* Then set INT_WIDTH */
  392. /*
  393. * Interrupt width register @114 [0x72]
  394. * b7-b0: int width
  395. * Default: 0x64
  396. */
  397. i2c_smbus_write_byte_data(ots_client, 0x72, INT_DELAY);
  398. mdelay(4);
  399. /* Now set sensitivity */
  400. i2c_smbus_write_byte_data(ots_client, 0x6F, x_sensitivity);
  401. mdelay(4);
  402. i2c_smbus_write_byte_data(ots_client, 0x70, y_sensitivity);
  403. mdelay(4);
  404. i2c_smbus_write_byte_data(ots_client, 0xBE, 0x01); // TEST
  405. tmpReg = i2c_smbus_read_byte_data(ots_client, 0xBE); // TEST
  406. DBG("0xBE = %02X", tmpReg);
  407. DBG("Firmware Version =0x%x\n", i2c_smbus_read_byte_data(ots_client, 0x77));
  408. /* Activate the device ! */
  409. /*
  410. * Interrupt mode Setting register @113 [0x71]
  411. * b7-b6-b5: TP_NUM : How many finger, 000: none, 001: One, 010: Two
  412. * b4: INT_RELEASE: used to ack (1) IRQ in periodical mode
  413. * b3: EN_INT: Enable int (1: enabled, 0: disable)
  414. * b2: INT_POL: 0: active low, 1: active high
  415. * b1-b0: INT_MODE: 00: INT periodicaly, 01: INT assert when coord changes
  416. * 10: TOuch indicate, 11: INT assert when INT_RELEASE modified
  417. *
  418. * Default 0x0C [000 0 1 1 00]
  419. * Qisda: 0x0A [000 0 1 0 10]
  420. * Int periodicaly, Active High, and INT enabled
  421. */
  422. /* 2 Finger Active High Mode */
  423. tmpReg = (FINGER_NUM << 5) | (1 << 3) | (0 << 2) | ((int_mode & 0x03) << 0);
  424. DBG("Settings: 0x%02X", tmpReg);
  425. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  426. mdelay(4);
  427. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71); // TEST
  428. DBG("[0x71] Settings = %02X", tmpReg);
  429. FUNC_OUT();
  430. }
  431. static void ots_ackInterrupt (void)
  432. {
  433. unsigned char tmpReg;
  434. FUNC_IN();
  435. tmpReg = i2c_smbus_read_byte_data(ots_client, 0x71);
  436. tmpReg |= (1<<4);
  437. i2c_smbus_write_byte_data(ots_client, 0x71, tmpReg);
  438. FUNC_OUT();
  439. }
  440. /******************************************************************************/
  441. /****************************** Module functions ******************************/
  442. /******************************************************************************/
  443. static int __init ots_init (void)
  444. {
  445. FUNC_IN();
  446. /* if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  447. {
  448. }*/
  449. /* Init GPIOs */
  450. s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
  451. s3c2410_gpio_pullup(S3C2410_GPD10, 2);
  452. i2c_add_driver(&ots_driver);
  453. FUNC_OUT();
  454. return 0;
  455. }
  456. // ---------------------------------------------------------------------------
  457. static void __exit ots_exit (void)
  458. {
  459. FUNC_IN();
  460. /*if (GET_CAPABILITY(PLAT_CAP_GSENSOR) == PLAT_CAP_GMMA7660)
  461. {
  462. }*/
  463. /* Deinit GPIOs */
  464. /* Nothing to do, leave it as output is good enought, just set the
  465. * device as power off */
  466. ots_setPowerMode(POWER_OFF);
  467. i2c_del_driver(&ots_driver);
  468. FUNC_OUT();
  469. }
  470. // ---------------------------------------------------------------------------
  471. module_init (ots_init);
  472. module_exit (ots_exit);
  473. // ---------------------------------------------------------------------------
  474. MODULE_LICENSE ("GPL");
  475. MODULE_AUTHOR ("Bookeen <developers@bookeen.com>");
  476. MODULE_VERSION ("1.0");
  477. MODULE_DESCRIPTION ("Cybook Orizon Touchpanel driver");
  478. // ===========================================================================