cy8c_tmg_ts.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /* drivers/input/touchscreen/cy8c_tmg_ts.c
  2. *
  3. * Copyright (C) 2007-2008 HTC Corporation.
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include <linux/cy8c_tmg_ts.h>
  16. #include <linux/delay.h>
  17. #include <linux/earlysuspend.h>
  18. #include <linux/hrtimer.h>
  19. #include <linux/i2c.h>
  20. #include <linux/input.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/module.h>
  23. #include <linux/platform_device.h>
  24. #define CY8C_REG_START_NEW_SCAN 0x0F
  25. #define CY8C_REG_INTR_STATUS 0x3C
  26. #define CY8C_REG_VERSION 0x3E
  27. struct cy8c_ts_data {
  28. struct i2c_client *client;
  29. struct input_dev *input_dev;
  30. int use_irq;
  31. struct hrtimer timer;
  32. struct work_struct work;
  33. uint16_t version;
  34. int (*power) (int on);
  35. struct early_suspend early_suspend;
  36. };
  37. struct workqueue_struct *cypress_touch_wq;
  38. #ifdef CONFIG_HAS_EARLYSUSPEND
  39. static void cy8c_ts_early_suspend(struct early_suspend *h);
  40. static void cy8c_ts_late_resume(struct early_suspend *h);
  41. #endif
  42. uint16_t sample_count, X_mean, Y_mean, first_touch;
  43. static s32 cy8c_read_word_data(struct i2c_client *client,
  44. u8 command, uint16_t * data)
  45. {
  46. s32 ret = i2c_smbus_read_word_data(client, command);
  47. if (ret != -1) {
  48. *data = (u16) ((ret << 8) | (ret >> 8));
  49. }
  50. return ret;
  51. }
  52. static int cy8c_init_panel(struct cy8c_ts_data *ts)
  53. {
  54. int ret;
  55. sample_count = X_mean = Y_mean = first_touch = 0;
  56. /* clean intr busy */
  57. ret = i2c_smbus_write_byte_data(ts->client, CY8C_REG_INTR_STATUS,
  58. 0x00);
  59. if (ret < 0) {
  60. dev_err(&ts->client->dev,
  61. "cy8c_init_panel failed for clean intr busy\n");
  62. goto exit;
  63. }
  64. /* start new scan */
  65. ret = i2c_smbus_write_byte_data(ts->client, CY8C_REG_START_NEW_SCAN,
  66. 0x01);
  67. if (ret < 0) {
  68. dev_err(&ts->client->dev,
  69. "cy8c_init_panel failed for start new scan\n");
  70. goto exit;
  71. }
  72. exit:
  73. return ret;
  74. }
  75. static void cy8c_ts_reset(struct i2c_client *client)
  76. {
  77. struct cy8c_ts_data *ts = i2c_get_clientdata(client);
  78. if (ts->power) {
  79. ts->power(0);
  80. msleep(10);
  81. ts->power(1);
  82. msleep(10);
  83. }
  84. cy8c_init_panel(ts);
  85. }
  86. static void cy8c_ts_work_func(struct work_struct *work)
  87. {
  88. struct cy8c_ts_data *ts = container_of(work, struct cy8c_ts_data, work);
  89. uint16_t x1, y1, x2, y2;
  90. uint8_t is_touch, start_reg, force, area, finger2_pressed;
  91. uint8_t buf[11];
  92. struct i2c_msg msg[2];
  93. int ret = 0;
  94. x2 = y2 = 0;
  95. /*printk("%s: enter\n",__func__);*/
  96. is_touch = i2c_smbus_read_byte_data(ts->client, 0x20);
  97. dev_dbg(&ts->client->dev, "fIsTouch %d,\n", is_touch);
  98. if (is_touch < 0 || is_touch > 3) {
  99. pr_err("%s: invalid is_touch = %d\n", __func__, is_touch);
  100. cy8c_ts_reset(ts->client);
  101. msleep(10);
  102. goto done;
  103. }
  104. msg[0].addr = ts->client->addr;
  105. msg[0].flags = 0;
  106. msg[0].len = 1;
  107. start_reg = 0x16;
  108. msg[0].buf = &start_reg;
  109. msg[1].addr = ts->client->addr;
  110. msg[1].flags = I2C_M_RD;
  111. msg[1].len = sizeof(buf);
  112. msg[1].buf = buf;
  113. ret = i2c_transfer(ts->client->adapter, msg, 2);
  114. if (ret < 0)
  115. goto done;
  116. /* parse data */
  117. force = buf[0];
  118. area = buf[1];
  119. x1 = (buf[2] << 8) | buf[3];
  120. y1 = (buf[6] << 8) | buf[7];
  121. is_touch = buf[10];
  122. if (is_touch == 2) {
  123. x2 = (buf[4] << 8) | buf[5];
  124. y2 = (buf[8] << 8) | buf[9];
  125. finger2_pressed = 1;
  126. }
  127. dev_dbg(&ts->client->dev,
  128. "bFingerForce %d, bFingerArea %d \n", force, area);
  129. dev_dbg(&ts->client->dev, "x1: %d, y1: %d \n", x1, y1);
  130. if (finger2_pressed)
  131. dev_dbg(&ts->client->dev, "x2: %d, y2: %d \n", x2, y2);
  132. /* drop the first one? */
  133. if ((is_touch == 1) && (first_touch == 0)) {
  134. first_touch = 1;
  135. goto done;
  136. }
  137. if (!first_touch)
  138. goto done;
  139. if (is_touch == 2)
  140. finger2_pressed = 1;
  141. input_report_abs(ts->input_dev, ABS_X, x1);
  142. input_report_abs(ts->input_dev, ABS_Y, y1);
  143. input_report_abs(ts->input_dev, ABS_PRESSURE, force);
  144. input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, area);
  145. input_report_key(ts->input_dev, BTN_TOUCH, is_touch);
  146. input_report_key(ts->input_dev, BTN_2, finger2_pressed);
  147. if (finger2_pressed) {
  148. input_report_abs(ts->input_dev, ABS_HAT0X, x2);
  149. input_report_abs(ts->input_dev, ABS_HAT0Y, y2);
  150. }
  151. input_sync(ts->input_dev);
  152. done:
  153. if (is_touch == 0)
  154. first_touch = sample_count = 0;
  155. /* prepare for next intr */
  156. i2c_smbus_write_byte_data(ts->client, CY8C_REG_INTR_STATUS, 0x00);
  157. if (!ts->use_irq)
  158. hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
  159. else
  160. enable_irq(ts->client->irq);
  161. }
  162. static enum hrtimer_restart cy8c_ts_timer_func(struct hrtimer *timer)
  163. {
  164. struct cy8c_ts_data *ts;
  165. ts = container_of(timer, struct cy8c_ts_data, timer);
  166. queue_work(cypress_touch_wq, &ts->work);
  167. return HRTIMER_NORESTART;
  168. }
  169. static irqreturn_t cy8c_ts_irq_handler(int irq, void *dev_id)
  170. {
  171. struct cy8c_ts_data *ts = dev_id;
  172. disable_irq_nosync(ts->client->irq);
  173. queue_work(cypress_touch_wq, &ts->work);
  174. return IRQ_HANDLED;
  175. }
  176. static int cy8c_ts_probe(struct i2c_client *client,
  177. const struct i2c_device_id *id)
  178. {
  179. struct cy8c_ts_data *ts;
  180. struct cy8c_i2c_platform_data *pdata;
  181. uint16_t panel_version;
  182. int ret = 0;
  183. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  184. dev_err(&client->dev, "need I2C_FUNC_I2C\n");
  185. ret = -ENODEV;
  186. goto err_check_functionality_failed;
  187. }
  188. ts = kzalloc(sizeof(struct cy8c_ts_data), GFP_KERNEL);
  189. if (ts == NULL) {
  190. dev_err(&client->dev, "allocate cy8c_ts_data failed\n");
  191. ret = -ENOMEM;
  192. goto err_alloc_data_failed;
  193. }
  194. INIT_WORK(&ts->work, cy8c_ts_work_func);
  195. ts->client = client;
  196. i2c_set_clientdata(client, ts);
  197. pdata = client->dev.platform_data;
  198. if (pdata) {
  199. ts->version = pdata->version;
  200. ts->power = pdata->power;
  201. }
  202. if (ts->power) {
  203. ret = ts->power(1);
  204. msleep(10);
  205. if (ret < 0) {
  206. dev_err(&client->dev, "power on failed\n");
  207. goto err_power_failed;
  208. }
  209. }
  210. ret = cy8c_read_word_data(ts->client, CY8C_REG_VERSION, &panel_version);
  211. if (ret < 0) {
  212. dev_err(&client->dev, "init panel failed\n");
  213. goto err_detect_failed;
  214. }
  215. dev_info(&client->dev, "Panel Version %04X\n", panel_version);
  216. if (pdata) {
  217. while (pdata->version > panel_version) {
  218. dev_info(&client->dev, "old tp detected, "
  219. "panel version = %x\n", panel_version);
  220. pdata++;
  221. }
  222. }
  223. ret = cy8c_init_panel(ts);
  224. if (ret < 0) {
  225. dev_err(&client->dev, "init panel failed\n");
  226. goto err_detect_failed;
  227. }
  228. ts->input_dev = input_allocate_device();
  229. if (ts->input_dev == NULL) {
  230. ret = -ENOMEM;
  231. dev_err(&client->dev, "Failed to allocate input device\n");
  232. goto err_input_dev_alloc_failed;
  233. }
  234. ts->input_dev->name = "cy8c-touchscreen";
  235. set_bit(EV_SYN, ts->input_dev->evbit);
  236. set_bit(EV_ABS, ts->input_dev->evbit);
  237. set_bit(EV_KEY, ts->input_dev->evbit);
  238. input_set_capability(ts->input_dev, EV_KEY, BTN_TOUCH);
  239. input_set_capability(ts->input_dev, EV_KEY, BTN_2);
  240. input_set_abs_params(ts->input_dev, ABS_X,
  241. pdata->abs_x_min, pdata->abs_x_max, 5, 0);
  242. input_set_abs_params(ts->input_dev, ABS_Y,
  243. pdata->abs_y_min, pdata->abs_y_max, 5, 0);
  244. input_set_abs_params(ts->input_dev, ABS_HAT0X,
  245. pdata->abs_x_min, pdata->abs_x_max, 0, 0);
  246. input_set_abs_params(ts->input_dev, ABS_HAT0Y,
  247. pdata->abs_y_min, pdata->abs_y_max, 0, 0);
  248. input_set_abs_params(ts->input_dev, ABS_PRESSURE,
  249. pdata->abs_pressure_min, pdata->abs_pressure_max,
  250. 0, 0);
  251. input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH,
  252. pdata->abs_width_min, pdata->abs_width_max, 0, 0);
  253. ret = input_register_device(ts->input_dev);
  254. if (ret) {
  255. dev_err(&client->dev,
  256. "cy8c_ts_probe: Unable to register %s input device\n",
  257. ts->input_dev->name);
  258. goto err_input_register_device_failed;
  259. }
  260. if (client->irq) {
  261. ret = request_irq(client->irq, cy8c_ts_irq_handler,
  262. IRQF_TRIGGER_LOW, CYPRESS_TMG_NAME, ts);
  263. if (ret == 0)
  264. ts->use_irq = 1;
  265. else
  266. dev_err(&client->dev, "request_irq failed\n");
  267. }
  268. if (!ts->use_irq) {
  269. hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  270. ts->timer.function = cy8c_ts_timer_func;
  271. hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
  272. }
  273. #ifdef CONFIG_HAS_EARLYSUSPEND
  274. ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  275. ts->early_suspend.suspend = cy8c_ts_early_suspend;
  276. ts->early_suspend.resume = cy8c_ts_late_resume;
  277. register_early_suspend(&ts->early_suspend);
  278. #endif
  279. dev_info(&client->dev, "Start touchscreen %s in %s mode\n",
  280. ts->input_dev->name, (ts->use_irq ? "interrupt" : "polling"));
  281. return 0;
  282. err_input_register_device_failed:
  283. input_free_device(ts->input_dev);
  284. err_input_dev_alloc_failed:
  285. if (ts->power)
  286. ts->power(0);
  287. err_detect_failed:
  288. err_power_failed:
  289. kfree(ts);
  290. err_alloc_data_failed:
  291. err_check_functionality_failed:
  292. return ret;
  293. }
  294. static int cy8c_ts_remove(struct i2c_client *client)
  295. {
  296. struct cy8c_ts_data *ts = i2c_get_clientdata(client);
  297. unregister_early_suspend(&ts->early_suspend);
  298. if (ts->use_irq)
  299. free_irq(client->irq, ts);
  300. else
  301. hrtimer_cancel(&ts->timer);
  302. input_unregister_device(ts->input_dev);
  303. kfree(ts);
  304. return 0;
  305. }
  306. static int cy8c_ts_suspend(struct i2c_client *client, pm_message_t mesg)
  307. {
  308. struct cy8c_ts_data *ts = i2c_get_clientdata(client);
  309. int ret;
  310. if (ts->use_irq)
  311. disable_irq_nosync(client->irq);
  312. else
  313. hrtimer_cancel(&ts->timer);
  314. ret = cancel_work_sync(&ts->work);
  315. if (ret && ts->use_irq)
  316. enable_irq(client->irq);
  317. if (ts->power)
  318. ts->power(0);
  319. return 0;
  320. }
  321. static int cy8c_ts_resume(struct i2c_client *client)
  322. {
  323. int ret;
  324. struct cy8c_ts_data *ts = i2c_get_clientdata(client);
  325. if (ts->power) {
  326. ret = ts->power(1);
  327. if (ret < 0)
  328. dev_err(&client->dev,
  329. "cy8c_ts_resume power on failed\n");
  330. msleep(10);
  331. cy8c_init_panel(ts);
  332. }
  333. if (ts->use_irq)
  334. enable_irq(client->irq);
  335. else
  336. hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
  337. return 0;
  338. }
  339. #ifdef CONFIG_HAS_EARLYSUSPEND
  340. static void cy8c_ts_early_suspend(struct early_suspend *h)
  341. {
  342. struct cy8c_ts_data *ts;
  343. ts = container_of(h, struct cy8c_ts_data, early_suspend);
  344. cy8c_ts_suspend(ts->client, PMSG_SUSPEND);
  345. }
  346. static void cy8c_ts_late_resume(struct early_suspend *h)
  347. {
  348. struct cy8c_ts_data *ts;
  349. ts = container_of(h, struct cy8c_ts_data, early_suspend);
  350. cy8c_ts_resume(ts->client);
  351. }
  352. #endif
  353. static const struct i2c_device_id cy8c_ts_i2c_id[] = {
  354. {CYPRESS_TMG_NAME, 0},
  355. {}
  356. };
  357. static struct i2c_driver cy8c_ts_driver = {
  358. .id_table = cy8c_ts_i2c_id,
  359. .probe = cy8c_ts_probe,
  360. .remove = cy8c_ts_remove,
  361. #ifndef CONFIG_HAS_EARLYSUSPEND
  362. .suspend = cy8c_ts_suspend,
  363. .resume = cy8c_ts_resume,
  364. #endif
  365. .driver = {
  366. .name = CYPRESS_TMG_NAME,
  367. .owner = THIS_MODULE,
  368. },
  369. };
  370. static int __devinit cy8c_ts_init(void)
  371. {
  372. cypress_touch_wq = create_singlethread_workqueue("cypress_touch_wq");
  373. if (!cypress_touch_wq)
  374. return -ENOMEM;
  375. return i2c_add_driver(&cy8c_ts_driver);
  376. }
  377. static void __exit cy8c_ts_exit(void)
  378. {
  379. if (cypress_touch_wq)
  380. destroy_workqueue(cypress_touch_wq);
  381. i2c_del_driver(&cy8c_ts_driver);
  382. }
  383. module_init(cy8c_ts_init);
  384. module_exit(cy8c_ts_exit);
  385. MODULE_DESCRIPTION("Cypress TMG Touchscreen Driver");
  386. MODULE_LICENSE("GPL");