cypress-sf.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Cypress StreetFighter Touchkey Driver
  4. *
  5. * Copyright (c) 2021 Yassine Oudjana <[email protected]>
  6. */
  7. #include <linux/bitmap.h>
  8. #include <linux/bitops.h>
  9. #include <linux/device.h>
  10. #include <linux/i2c.h>
  11. #include <linux/input.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/module.h>
  14. #include <linux/pm.h>
  15. #include <linux/regulator/consumer.h>
  16. #define CYPRESS_SF_DEV_NAME "cypress-sf"
  17. #define CYPRESS_SF_REG_BUTTON_STATUS 0x4a
  18. struct cypress_sf_data {
  19. struct i2c_client *client;
  20. struct input_dev *input_dev;
  21. struct regulator_bulk_data regulators[2];
  22. u32 *keycodes;
  23. unsigned long keystates;
  24. int num_keys;
  25. };
  26. static irqreturn_t cypress_sf_irq_handler(int irq, void *devid)
  27. {
  28. struct cypress_sf_data *touchkey = devid;
  29. unsigned long keystates, changed;
  30. bool new_state;
  31. int val, key;
  32. val = i2c_smbus_read_byte_data(touchkey->client,
  33. CYPRESS_SF_REG_BUTTON_STATUS);
  34. if (val < 0) {
  35. dev_err(&touchkey->client->dev,
  36. "Failed to read button status: %d", val);
  37. return IRQ_NONE;
  38. }
  39. keystates = val;
  40. bitmap_xor(&changed, &keystates, &touchkey->keystates,
  41. touchkey->num_keys);
  42. for_each_set_bit(key, &changed, touchkey->num_keys) {
  43. new_state = keystates & BIT(key);
  44. dev_dbg(&touchkey->client->dev,
  45. "Key %d changed to %d", key, new_state);
  46. input_report_key(touchkey->input_dev,
  47. touchkey->keycodes[key], new_state);
  48. }
  49. input_sync(touchkey->input_dev);
  50. touchkey->keystates = keystates;
  51. return IRQ_HANDLED;
  52. }
  53. static void cypress_sf_disable_regulators(void *arg)
  54. {
  55. struct cypress_sf_data *touchkey = arg;
  56. regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
  57. touchkey->regulators);
  58. }
  59. static int cypress_sf_probe(struct i2c_client *client)
  60. {
  61. struct cypress_sf_data *touchkey;
  62. int key, error;
  63. touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
  64. if (!touchkey)
  65. return -ENOMEM;
  66. touchkey->client = client;
  67. i2c_set_clientdata(client, touchkey);
  68. touchkey->regulators[0].supply = "vdd";
  69. touchkey->regulators[1].supply = "avdd";
  70. error = devm_regulator_bulk_get(&client->dev,
  71. ARRAY_SIZE(touchkey->regulators),
  72. touchkey->regulators);
  73. if (error) {
  74. dev_err(&client->dev, "Failed to get regulators: %d\n", error);
  75. return error;
  76. }
  77. touchkey->num_keys = device_property_read_u32_array(&client->dev,
  78. "linux,keycodes",
  79. NULL, 0);
  80. if (touchkey->num_keys < 0) {
  81. /* Default key count */
  82. touchkey->num_keys = 2;
  83. }
  84. touchkey->keycodes = devm_kcalloc(&client->dev,
  85. touchkey->num_keys,
  86. sizeof(*touchkey->keycodes),
  87. GFP_KERNEL);
  88. if (!touchkey->keycodes)
  89. return -ENOMEM;
  90. error = device_property_read_u32_array(&client->dev, "linux,keycodes",
  91. touchkey->keycodes,
  92. touchkey->num_keys);
  93. if (error) {
  94. dev_warn(&client->dev,
  95. "Failed to read keycodes: %d, using defaults\n",
  96. error);
  97. /* Default keycodes */
  98. touchkey->keycodes[0] = KEY_BACK;
  99. touchkey->keycodes[1] = KEY_MENU;
  100. }
  101. error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
  102. touchkey->regulators);
  103. if (error) {
  104. dev_err(&client->dev,
  105. "Failed to enable regulators: %d\n", error);
  106. return error;
  107. }
  108. error = devm_add_action_or_reset(&client->dev,
  109. cypress_sf_disable_regulators,
  110. touchkey);
  111. if (error)
  112. return error;
  113. touchkey->input_dev = devm_input_allocate_device(&client->dev);
  114. if (!touchkey->input_dev) {
  115. dev_err(&client->dev, "Failed to allocate input device\n");
  116. return -ENOMEM;
  117. }
  118. touchkey->input_dev->name = CYPRESS_SF_DEV_NAME;
  119. touchkey->input_dev->id.bustype = BUS_I2C;
  120. for (key = 0; key < touchkey->num_keys; ++key)
  121. input_set_capability(touchkey->input_dev,
  122. EV_KEY, touchkey->keycodes[key]);
  123. error = input_register_device(touchkey->input_dev);
  124. if (error) {
  125. dev_err(&client->dev,
  126. "Failed to register input device: %d\n", error);
  127. return error;
  128. }
  129. error = devm_request_threaded_irq(&client->dev, client->irq,
  130. NULL, cypress_sf_irq_handler,
  131. IRQF_ONESHOT,
  132. CYPRESS_SF_DEV_NAME, touchkey);
  133. if (error) {
  134. dev_err(&client->dev,
  135. "Failed to register threaded irq: %d", error);
  136. return error;
  137. }
  138. return 0;
  139. };
  140. static int __maybe_unused cypress_sf_suspend(struct device *dev)
  141. {
  142. struct i2c_client *client = to_i2c_client(dev);
  143. struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
  144. int error;
  145. disable_irq(client->irq);
  146. error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
  147. touchkey->regulators);
  148. if (error) {
  149. dev_err(dev, "Failed to disable regulators: %d", error);
  150. enable_irq(client->irq);
  151. return error;
  152. }
  153. return 0;
  154. }
  155. static int __maybe_unused cypress_sf_resume(struct device *dev)
  156. {
  157. struct i2c_client *client = to_i2c_client(dev);
  158. struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
  159. int error;
  160. error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
  161. touchkey->regulators);
  162. if (error) {
  163. dev_err(dev, "Failed to enable regulators: %d", error);
  164. return error;
  165. }
  166. enable_irq(client->irq);
  167. return 0;
  168. }
  169. static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
  170. cypress_sf_suspend, cypress_sf_resume);
  171. static struct i2c_device_id cypress_sf_id_table[] = {
  172. { CYPRESS_SF_DEV_NAME, 0 },
  173. { }
  174. };
  175. MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
  176. #ifdef CONFIG_OF
  177. static const struct of_device_id cypress_sf_of_match[] = {
  178. { .compatible = "cypress,sf3155", },
  179. { },
  180. };
  181. MODULE_DEVICE_TABLE(of, cypress_sf_of_match);
  182. #endif
  183. static struct i2c_driver cypress_sf_driver = {
  184. .driver = {
  185. .name = CYPRESS_SF_DEV_NAME,
  186. .pm = &cypress_sf_pm_ops,
  187. .of_match_table = of_match_ptr(cypress_sf_of_match),
  188. },
  189. .id_table = cypress_sf_id_table,
  190. .probe_new = cypress_sf_probe,
  191. };
  192. module_i2c_driver(cypress_sf_driver);
  193. MODULE_AUTHOR("Yassine Oudjana <[email protected]>");
  194. MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver");
  195. MODULE_LICENSE("GPL v2");