arizona-haptics.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Arizona haptics driver
  3. *
  4. * Copyright 2012 Wolfson Microelectronics plc
  5. *
  6. * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/input.h>
  15. #include <linux/slab.h>
  16. #include <sound/soc.h>
  17. #include <sound/soc-dapm.h>
  18. #include <linux/mfd/arizona/core.h>
  19. #include <linux/mfd/arizona/pdata.h>
  20. #include <linux/mfd/arizona/registers.h>
  21. struct arizona_haptics {
  22. struct arizona *arizona;
  23. struct input_dev *input_dev;
  24. struct work_struct work;
  25. struct mutex mutex;
  26. u8 intensity;
  27. };
  28. static void arizona_haptics_work(struct work_struct *work)
  29. {
  30. struct arizona_haptics *haptics = container_of(work,
  31. struct arizona_haptics,
  32. work);
  33. struct arizona *arizona = haptics->arizona;
  34. int ret;
  35. if (!haptics->arizona->dapm) {
  36. dev_err(arizona->dev, "No DAPM context\n");
  37. return;
  38. }
  39. if (haptics->intensity) {
  40. ret = regmap_update_bits(arizona->regmap,
  41. ARIZONA_HAPTICS_PHASE_2_INTENSITY,
  42. ARIZONA_PHASE2_INTENSITY_MASK,
  43. haptics->intensity);
  44. if (ret != 0) {
  45. dev_err(arizona->dev, "Failed to set intensity: %d\n",
  46. ret);
  47. return;
  48. }
  49. /* This enable sequence will be a noop if already enabled */
  50. ret = regmap_update_bits(arizona->regmap,
  51. ARIZONA_HAPTICS_CONTROL_1,
  52. ARIZONA_HAP_CTRL_MASK,
  53. 1 << ARIZONA_HAP_CTRL_SHIFT);
  54. if (ret != 0) {
  55. dev_err(arizona->dev, "Failed to start haptics: %d\n",
  56. ret);
  57. return;
  58. }
  59. ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
  60. if (ret != 0) {
  61. dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
  62. ret);
  63. return;
  64. }
  65. ret = snd_soc_dapm_sync(arizona->dapm);
  66. if (ret != 0) {
  67. dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
  68. ret);
  69. return;
  70. }
  71. } else {
  72. /* This disable sequence will be a noop if already enabled */
  73. ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
  74. if (ret != 0) {
  75. dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
  76. ret);
  77. return;
  78. }
  79. ret = snd_soc_dapm_sync(arizona->dapm);
  80. if (ret != 0) {
  81. dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
  82. ret);
  83. return;
  84. }
  85. ret = regmap_update_bits(arizona->regmap,
  86. ARIZONA_HAPTICS_CONTROL_1,
  87. ARIZONA_HAP_CTRL_MASK, 0);
  88. if (ret != 0) {
  89. dev_err(arizona->dev, "Failed to stop haptics: %d\n",
  90. ret);
  91. return;
  92. }
  93. }
  94. }
  95. static int arizona_haptics_play(struct input_dev *input, void *data,
  96. struct ff_effect *effect)
  97. {
  98. struct arizona_haptics *haptics = input_get_drvdata(input);
  99. struct arizona *arizona = haptics->arizona;
  100. if (!arizona->dapm) {
  101. dev_err(arizona->dev, "No DAPM context\n");
  102. return -EBUSY;
  103. }
  104. if (effect->u.rumble.strong_magnitude) {
  105. /* Scale the magnitude into the range the device supports */
  106. if (arizona->pdata.hap_act) {
  107. haptics->intensity =
  108. effect->u.rumble.strong_magnitude >> 9;
  109. if (effect->direction < 0x8000)
  110. haptics->intensity += 0x7f;
  111. } else {
  112. haptics->intensity =
  113. effect->u.rumble.strong_magnitude >> 8;
  114. }
  115. } else {
  116. haptics->intensity = 0;
  117. }
  118. schedule_work(&haptics->work);
  119. return 0;
  120. }
  121. static void arizona_haptics_close(struct input_dev *input)
  122. {
  123. struct arizona_haptics *haptics = input_get_drvdata(input);
  124. cancel_work_sync(&haptics->work);
  125. if (haptics->arizona->dapm)
  126. snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
  127. }
  128. static int arizona_haptics_probe(struct platform_device *pdev)
  129. {
  130. struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
  131. struct arizona_haptics *haptics;
  132. int ret;
  133. haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
  134. if (!haptics)
  135. return -ENOMEM;
  136. haptics->arizona = arizona;
  137. ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
  138. ARIZONA_HAP_ACT, arizona->pdata.hap_act);
  139. if (ret != 0) {
  140. dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
  141. ret);
  142. return ret;
  143. }
  144. INIT_WORK(&haptics->work, arizona_haptics_work);
  145. haptics->input_dev = devm_input_allocate_device(&pdev->dev);
  146. if (!haptics->input_dev) {
  147. dev_err(arizona->dev, "Failed to allocate input device\n");
  148. return -ENOMEM;
  149. }
  150. input_set_drvdata(haptics->input_dev, haptics);
  151. haptics->input_dev->name = "arizona:haptics";
  152. haptics->input_dev->dev.parent = pdev->dev.parent;
  153. haptics->input_dev->close = arizona_haptics_close;
  154. __set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
  155. ret = input_ff_create_memless(haptics->input_dev, NULL,
  156. arizona_haptics_play);
  157. if (ret < 0) {
  158. dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
  159. ret);
  160. return ret;
  161. }
  162. ret = input_register_device(haptics->input_dev);
  163. if (ret < 0) {
  164. dev_err(arizona->dev, "couldn't register input device: %d\n",
  165. ret);
  166. return ret;
  167. }
  168. platform_set_drvdata(pdev, haptics);
  169. return 0;
  170. }
  171. static struct platform_driver arizona_haptics_driver = {
  172. .probe = arizona_haptics_probe,
  173. .driver = {
  174. .name = "arizona-haptics",
  175. },
  176. };
  177. module_platform_driver(arizona_haptics_driver);
  178. MODULE_ALIAS("platform:arizona-haptics");
  179. MODULE_DESCRIPTION("Arizona haptics driver");
  180. MODULE_LICENSE("GPL");
  181. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");