qt2160.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * qt2160.c - Atmel AT42QT2160 Touch Sense Controller
  4. *
  5. * Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/leds.h>
  9. #include <linux/module.h>
  10. #include <linux/slab.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/i2c.h>
  13. #include <linux/irq.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/input.h>
  16. #define QT2160_VALID_CHIPID 0x11
  17. #define QT2160_CMD_CHIPID 0
  18. #define QT2160_CMD_CODEVER 1
  19. #define QT2160_CMD_GSTAT 2
  20. #define QT2160_CMD_KEYS3 3
  21. #define QT2160_CMD_KEYS4 4
  22. #define QT2160_CMD_SLIDE 5
  23. #define QT2160_CMD_GPIOS 6
  24. #define QT2160_CMD_SUBVER 7
  25. #define QT2160_CMD_CALIBRATE 10
  26. #define QT2160_CMD_DRIVE_X 70
  27. #define QT2160_CMD_PWMEN_X 74
  28. #define QT2160_CMD_PWM_DUTY 76
  29. #define QT2160_NUM_LEDS_X 8
  30. #define QT2160_CYCLE_INTERVAL 2000 /* msec - 2 sec */
  31. static unsigned char qt2160_key2code[] = {
  32. KEY_0, KEY_1, KEY_2, KEY_3,
  33. KEY_4, KEY_5, KEY_6, KEY_7,
  34. KEY_8, KEY_9, KEY_A, KEY_B,
  35. KEY_C, KEY_D, KEY_E, KEY_F,
  36. };
  37. #ifdef CONFIG_LEDS_CLASS
  38. struct qt2160_led {
  39. struct qt2160_data *qt2160;
  40. struct led_classdev cdev;
  41. char name[32];
  42. int id;
  43. enum led_brightness brightness;
  44. };
  45. #endif
  46. struct qt2160_data {
  47. struct i2c_client *client;
  48. struct input_dev *input;
  49. unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
  50. u16 key_matrix;
  51. #ifdef CONFIG_LEDS_CLASS
  52. struct qt2160_led leds[QT2160_NUM_LEDS_X];
  53. #endif
  54. };
  55. static int qt2160_read(struct i2c_client *client, u8 reg);
  56. static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
  57. #ifdef CONFIG_LEDS_CLASS
  58. static int qt2160_led_set(struct led_classdev *cdev,
  59. enum led_brightness value)
  60. {
  61. struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
  62. struct qt2160_data *qt2160 = led->qt2160;
  63. struct i2c_client *client = qt2160->client;
  64. u32 drive, pwmen;
  65. if (value != led->brightness) {
  66. drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
  67. pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
  68. if (value != LED_OFF) {
  69. drive |= BIT(led->id);
  70. pwmen |= BIT(led->id);
  71. } else {
  72. drive &= ~BIT(led->id);
  73. pwmen &= ~BIT(led->id);
  74. }
  75. qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
  76. qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
  77. /*
  78. * Changing this register will change the brightness
  79. * of every LED in the qt2160. It's a HW limitation.
  80. */
  81. if (value != LED_OFF)
  82. qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
  83. led->brightness = value;
  84. }
  85. return 0;
  86. }
  87. #endif /* CONFIG_LEDS_CLASS */
  88. static int qt2160_read_block(struct i2c_client *client,
  89. u8 inireg, u8 *buffer, unsigned int count)
  90. {
  91. int error, idx = 0;
  92. /*
  93. * Can't use SMBus block data read. Check for I2C functionality to speed
  94. * things up whenever possible. Otherwise we will be forced to read
  95. * sequentially.
  96. */
  97. if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  98. error = i2c_smbus_write_byte(client, inireg + idx);
  99. if (error) {
  100. dev_err(&client->dev,
  101. "couldn't send request. Returned %d\n", error);
  102. return error;
  103. }
  104. error = i2c_master_recv(client, buffer, count);
  105. if (error != count) {
  106. dev_err(&client->dev,
  107. "couldn't read registers. Returned %d bytes\n", error);
  108. return error;
  109. }
  110. } else {
  111. while (count--) {
  112. int data;
  113. error = i2c_smbus_write_byte(client, inireg + idx);
  114. if (error) {
  115. dev_err(&client->dev,
  116. "couldn't send request. Returned %d\n", error);
  117. return error;
  118. }
  119. data = i2c_smbus_read_byte(client);
  120. if (data < 0) {
  121. dev_err(&client->dev,
  122. "couldn't read register. Returned %d\n", data);
  123. return data;
  124. }
  125. buffer[idx++] = data;
  126. }
  127. }
  128. return 0;
  129. }
  130. static void qt2160_get_key_matrix(struct input_dev *input)
  131. {
  132. struct qt2160_data *qt2160 = input_get_drvdata(input);
  133. struct i2c_client *client = qt2160->client;
  134. u8 regs[6];
  135. u16 old_matrix, new_matrix;
  136. int ret, i, mask;
  137. dev_dbg(&client->dev, "requesting keys...\n");
  138. /*
  139. * Read all registers from General Status Register
  140. * to GPIOs register
  141. */
  142. ret = qt2160_read_block(client, QT2160_CMD_GSTAT, regs, 6);
  143. if (ret) {
  144. dev_err(&client->dev,
  145. "could not perform chip read.\n");
  146. return;
  147. }
  148. old_matrix = qt2160->key_matrix;
  149. qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
  150. mask = 0x01;
  151. for (i = 0; i < 16; ++i, mask <<= 1) {
  152. int keyval = new_matrix & mask;
  153. if ((old_matrix & mask) != keyval) {
  154. input_report_key(input, qt2160->keycodes[i], keyval);
  155. dev_dbg(&client->dev, "key %d %s\n",
  156. i, keyval ? "pressed" : "released");
  157. }
  158. }
  159. input_sync(input);
  160. }
  161. static irqreturn_t qt2160_irq(int irq, void *data)
  162. {
  163. struct input_dev *input = data;
  164. qt2160_get_key_matrix(input);
  165. return IRQ_HANDLED;
  166. }
  167. static int qt2160_read(struct i2c_client *client, u8 reg)
  168. {
  169. int ret;
  170. ret = i2c_smbus_write_byte(client, reg);
  171. if (ret) {
  172. dev_err(&client->dev,
  173. "couldn't send request. Returned %d\n", ret);
  174. return ret;
  175. }
  176. ret = i2c_smbus_read_byte(client);
  177. if (ret < 0) {
  178. dev_err(&client->dev,
  179. "couldn't read register. Returned %d\n", ret);
  180. return ret;
  181. }
  182. return ret;
  183. }
  184. static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
  185. {
  186. int ret;
  187. ret = i2c_smbus_write_byte_data(client, reg, data);
  188. if (ret < 0)
  189. dev_err(&client->dev,
  190. "couldn't write data. Returned %d\n", ret);
  191. return ret;
  192. }
  193. #ifdef CONFIG_LEDS_CLASS
  194. static int qt2160_register_leds(struct qt2160_data *qt2160)
  195. {
  196. struct i2c_client *client = qt2160->client;
  197. int error;
  198. int i;
  199. for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
  200. struct qt2160_led *led = &qt2160->leds[i];
  201. snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
  202. led->cdev.name = led->name;
  203. led->cdev.brightness_set_blocking = qt2160_led_set;
  204. led->cdev.brightness = LED_OFF;
  205. led->id = i;
  206. led->qt2160 = qt2160;
  207. error = devm_led_classdev_register(&client->dev, &led->cdev);
  208. if (error)
  209. return error;
  210. }
  211. /* Tur off LEDs */
  212. qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
  213. qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
  214. qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
  215. return 0;
  216. }
  217. #else
  218. static inline int qt2160_register_leds(struct qt2160_data *qt2160)
  219. {
  220. return 0;
  221. }
  222. #endif
  223. static bool qt2160_identify(struct i2c_client *client)
  224. {
  225. int id, ver, rev;
  226. /* Read Chid ID to check if chip is valid */
  227. id = qt2160_read(client, QT2160_CMD_CHIPID);
  228. if (id != QT2160_VALID_CHIPID) {
  229. dev_err(&client->dev, "ID %d not supported\n", id);
  230. return false;
  231. }
  232. /* Read chip firmware version */
  233. ver = qt2160_read(client, QT2160_CMD_CODEVER);
  234. if (ver < 0) {
  235. dev_err(&client->dev, "could not get firmware version\n");
  236. return false;
  237. }
  238. /* Read chip firmware revision */
  239. rev = qt2160_read(client, QT2160_CMD_SUBVER);
  240. if (rev < 0) {
  241. dev_err(&client->dev, "could not get firmware revision\n");
  242. return false;
  243. }
  244. dev_info(&client->dev, "AT42QT2160 firmware version %d.%d.%d\n",
  245. ver >> 4, ver & 0xf, rev);
  246. return true;
  247. }
  248. static int qt2160_probe(struct i2c_client *client)
  249. {
  250. struct qt2160_data *qt2160;
  251. struct input_dev *input;
  252. int i;
  253. int error;
  254. if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
  255. dev_err(&client->dev, "%s adapter not supported\n",
  256. dev_driver_string(&client->adapter->dev));
  257. return -ENODEV;
  258. }
  259. if (!qt2160_identify(client))
  260. return -ENODEV;
  261. /* Chip is valid and active. Allocate structure */
  262. qt2160 = devm_kzalloc(&client->dev, sizeof(*qt2160), GFP_KERNEL);
  263. if (!qt2160)
  264. return -ENOMEM;
  265. input = devm_input_allocate_device(&client->dev);
  266. if (!input)
  267. return -ENOMEM;
  268. qt2160->client = client;
  269. qt2160->input = input;
  270. input->name = "AT42QT2160 Touch Sense Keyboard";
  271. input->id.bustype = BUS_I2C;
  272. input->keycode = qt2160->keycodes;
  273. input->keycodesize = sizeof(qt2160->keycodes[0]);
  274. input->keycodemax = ARRAY_SIZE(qt2160_key2code);
  275. __set_bit(EV_KEY, input->evbit);
  276. __clear_bit(EV_REP, input->evbit);
  277. for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) {
  278. qt2160->keycodes[i] = qt2160_key2code[i];
  279. __set_bit(qt2160_key2code[i], input->keybit);
  280. }
  281. __clear_bit(KEY_RESERVED, input->keybit);
  282. input_set_drvdata(input, qt2160);
  283. /* Calibrate device */
  284. error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
  285. if (error) {
  286. dev_err(&client->dev, "failed to calibrate device\n");
  287. return error;
  288. }
  289. if (client->irq) {
  290. error = devm_request_threaded_irq(&client->dev, client->irq,
  291. NULL, qt2160_irq,
  292. IRQF_ONESHOT,
  293. "qt2160", input);
  294. if (error) {
  295. dev_err(&client->dev,
  296. "failed to allocate irq %d\n", client->irq);
  297. return error;
  298. }
  299. } else {
  300. error = input_setup_polling(input, qt2160_get_key_matrix);
  301. if (error) {
  302. dev_err(&client->dev, "Failed to setup polling\n");
  303. return error;
  304. }
  305. input_set_poll_interval(input, QT2160_CYCLE_INTERVAL);
  306. }
  307. error = qt2160_register_leds(qt2160);
  308. if (error) {
  309. dev_err(&client->dev, "Failed to register leds\n");
  310. return error;
  311. }
  312. error = input_register_device(qt2160->input);
  313. if (error) {
  314. dev_err(&client->dev,
  315. "Failed to register input device\n");
  316. return error;
  317. }
  318. return 0;
  319. }
  320. static const struct i2c_device_id qt2160_idtable[] = {
  321. { "qt2160" },
  322. { }
  323. };
  324. MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
  325. static struct i2c_driver qt2160_driver = {
  326. .driver = {
  327. .name = "qt2160",
  328. },
  329. .id_table = qt2160_idtable,
  330. .probe = qt2160_probe,
  331. };
  332. module_i2c_driver(qt2160_driver);
  333. MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
  334. MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
  335. MODULE_LICENSE("GPL");