sx8654.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Driver for Semtech SX8654 I2C touchscreen controller.
  3. *
  4. * Copyright (c) 2015 Armadeus Systems
  5. * Sébastien Szymanski <sebastien.szymanski@armadeus.com>
  6. *
  7. * Using code from:
  8. * - sx865x.c
  9. * Copyright (c) 2013 U-MoBo Srl
  10. * Pierluigi Passaro <p.passaro@u-mobo.com>
  11. * - sx8650.c
  12. * Copyright (c) 2009 Wayne Roberts
  13. * - tsc2007.c
  14. * Copyright (c) 2008 Kwangwoo Lee
  15. * - ads7846.c
  16. * Copyright (c) 2005 David Brownell
  17. * Copyright (c) 2006 Nokia Corporation
  18. * - corgi_ts.c
  19. * Copyright (C) 2004-2005 Richard Purdie
  20. * - omap_ts.[hc], ads7846.h, ts_osk.c
  21. * Copyright (C) 2002 MontaVista Software
  22. * Copyright (C) 2004 Texas Instruments
  23. * Copyright (C) 2005 Dirk Behme
  24. *
  25. * This program is free software; you can redistribute it and/or modify
  26. * it under the terms of the GNU General Public License version 2 as
  27. * published by the Free Software Foundation.
  28. */
  29. #include <linux/input.h>
  30. #include <linux/module.h>
  31. #include <linux/of.h>
  32. #include <linux/i2c.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/irq.h>
  35. /* register addresses */
  36. #define I2C_REG_TOUCH0 0x00
  37. #define I2C_REG_TOUCH1 0x01
  38. #define I2C_REG_CHANMASK 0x04
  39. #define I2C_REG_IRQMASK 0x22
  40. #define I2C_REG_IRQSRC 0x23
  41. #define I2C_REG_SOFTRESET 0x3f
  42. /* commands */
  43. #define CMD_READ_REGISTER 0x40
  44. #define CMD_MANUAL 0xc0
  45. #define CMD_PENTRG 0xe0
  46. /* value for I2C_REG_SOFTRESET */
  47. #define SOFTRESET_VALUE 0xde
  48. /* bits for I2C_REG_IRQSRC */
  49. #define IRQ_PENTOUCH_TOUCHCONVDONE 0x08
  50. #define IRQ_PENRELEASE 0x04
  51. /* bits for RegTouch1 */
  52. #define CONDIRQ 0x20
  53. #define FILT_7SA 0x03
  54. /* bits for I2C_REG_CHANMASK */
  55. #define CONV_X 0x80
  56. #define CONV_Y 0x40
  57. /* coordinates rate: higher nibble of CTRL0 register */
  58. #define RATE_MANUAL 0x00
  59. #define RATE_5000CPS 0xf0
  60. /* power delay: lower nibble of CTRL0 register */
  61. #define POWDLY_1_1MS 0x0b
  62. #define MAX_12BIT ((1 << 12) - 1)
  63. struct sx8654 {
  64. struct input_dev *input;
  65. struct i2c_client *client;
  66. };
  67. static irqreturn_t sx8654_irq(int irq, void *handle)
  68. {
  69. struct sx8654 *sx8654 = handle;
  70. int irqsrc;
  71. u8 data[4];
  72. unsigned int x, y;
  73. int retval;
  74. irqsrc = i2c_smbus_read_byte_data(sx8654->client,
  75. CMD_READ_REGISTER | I2C_REG_IRQSRC);
  76. dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
  77. if (irqsrc < 0)
  78. goto out;
  79. if (irqsrc & IRQ_PENRELEASE) {
  80. dev_dbg(&sx8654->client->dev, "pen release interrupt");
  81. input_report_key(sx8654->input, BTN_TOUCH, 0);
  82. input_sync(sx8654->input);
  83. }
  84. if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
  85. dev_dbg(&sx8654->client->dev, "pen touch interrupt");
  86. retval = i2c_master_recv(sx8654->client, data, sizeof(data));
  87. if (retval != sizeof(data))
  88. goto out;
  89. /* invalid data */
  90. if (unlikely(data[0] & 0x80 || data[2] & 0x80))
  91. goto out;
  92. x = ((data[0] & 0xf) << 8) | (data[1]);
  93. y = ((data[2] & 0xf) << 8) | (data[3]);
  94. input_report_abs(sx8654->input, ABS_X, x);
  95. input_report_abs(sx8654->input, ABS_Y, y);
  96. input_report_key(sx8654->input, BTN_TOUCH, 1);
  97. input_sync(sx8654->input);
  98. dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
  99. }
  100. out:
  101. return IRQ_HANDLED;
  102. }
  103. static int sx8654_open(struct input_dev *dev)
  104. {
  105. struct sx8654 *sx8654 = input_get_drvdata(dev);
  106. struct i2c_client *client = sx8654->client;
  107. int error;
  108. /* enable pen trigger mode */
  109. error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
  110. RATE_5000CPS | POWDLY_1_1MS);
  111. if (error) {
  112. dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
  113. return error;
  114. }
  115. error = i2c_smbus_write_byte(client, CMD_PENTRG);
  116. if (error) {
  117. dev_err(&client->dev, "writing command CMD_PENTRG failed");
  118. return error;
  119. }
  120. enable_irq(client->irq);
  121. return 0;
  122. }
  123. static void sx8654_close(struct input_dev *dev)
  124. {
  125. struct sx8654 *sx8654 = input_get_drvdata(dev);
  126. struct i2c_client *client = sx8654->client;
  127. int error;
  128. disable_irq(client->irq);
  129. /* enable manual mode mode */
  130. error = i2c_smbus_write_byte(client, CMD_MANUAL);
  131. if (error) {
  132. dev_err(&client->dev, "writing command CMD_MANUAL failed");
  133. return;
  134. }
  135. error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
  136. if (error) {
  137. dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
  138. return;
  139. }
  140. }
  141. static int sx8654_probe(struct i2c_client *client,
  142. const struct i2c_device_id *id)
  143. {
  144. struct sx8654 *sx8654;
  145. struct input_dev *input;
  146. int error;
  147. if (!i2c_check_functionality(client->adapter,
  148. I2C_FUNC_SMBUS_READ_WORD_DATA))
  149. return -ENXIO;
  150. sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
  151. if (!sx8654)
  152. return -ENOMEM;
  153. input = devm_input_allocate_device(&client->dev);
  154. if (!input)
  155. return -ENOMEM;
  156. input->name = "SX8654 I2C Touchscreen";
  157. input->id.bustype = BUS_I2C;
  158. input->dev.parent = &client->dev;
  159. input->open = sx8654_open;
  160. input->close = sx8654_close;
  161. __set_bit(INPUT_PROP_DIRECT, input->propbit);
  162. input_set_capability(input, EV_KEY, BTN_TOUCH);
  163. input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
  164. input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
  165. sx8654->client = client;
  166. sx8654->input = input;
  167. input_set_drvdata(sx8654->input, sx8654);
  168. error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
  169. SOFTRESET_VALUE);
  170. if (error) {
  171. dev_err(&client->dev, "writing softreset value failed");
  172. return error;
  173. }
  174. error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
  175. CONV_X | CONV_Y);
  176. if (error) {
  177. dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
  178. return error;
  179. }
  180. error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
  181. IRQ_PENTOUCH_TOUCHCONVDONE |
  182. IRQ_PENRELEASE);
  183. if (error) {
  184. dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
  185. return error;
  186. }
  187. error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
  188. CONDIRQ | FILT_7SA);
  189. if (error) {
  190. dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
  191. return error;
  192. }
  193. error = devm_request_threaded_irq(&client->dev, client->irq,
  194. NULL, sx8654_irq,
  195. IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
  196. client->name, sx8654);
  197. if (error) {
  198. dev_err(&client->dev,
  199. "Failed to enable IRQ %d, error: %d\n",
  200. client->irq, error);
  201. return error;
  202. }
  203. /* Disable the IRQ, we'll enable it in sx8654_open() */
  204. disable_irq(client->irq);
  205. error = input_register_device(sx8654->input);
  206. if (error)
  207. return error;
  208. i2c_set_clientdata(client, sx8654);
  209. return 0;
  210. }
  211. #ifdef CONFIG_OF
  212. static const struct of_device_id sx8654_of_match[] = {
  213. { .compatible = "semtech,sx8654", },
  214. { },
  215. };
  216. MODULE_DEVICE_TABLE(of, sx8654_of_match);
  217. #endif
  218. static const struct i2c_device_id sx8654_id_table[] = {
  219. { "semtech_sx8654", 0 },
  220. { },
  221. };
  222. MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
  223. static struct i2c_driver sx8654_driver = {
  224. .driver = {
  225. .name = "sx8654",
  226. .of_match_table = of_match_ptr(sx8654_of_match),
  227. },
  228. .id_table = sx8654_id_table,
  229. .probe = sx8654_probe,
  230. };
  231. module_i2c_driver(sx8654_driver);
  232. MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
  233. MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
  234. MODULE_LICENSE("GPL");