cs40l50-vibra.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * CS40L50 Advanced Haptic Driver with waveform memory,
  4. * integrated DSP, and closed-loop algorithms
  5. *
  6. * Copyright 2024 Cirrus Logic, Inc.
  7. *
  8. * Author: James Ogletree <james.ogletree@cirrus.com>
  9. */
  10. #include <linux/bitfield.h>
  11. #include <linux/input.h>
  12. #include <linux/mfd/cs40l50.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/pm_runtime.h>
  15. /* Wavetables */
  16. #define CS40L50_RAM_INDEX_START 0x1000000
  17. #define CS40L50_RAM_INDEX_END 0x100007F
  18. #define CS40L50_RTH_INDEX_START 0x1400000
  19. #define CS40L50_RTH_INDEX_END 0x1400001
  20. #define CS40L50_ROM_INDEX_START 0x1800000
  21. #define CS40L50_ROM_INDEX_END 0x180001A
  22. #define CS40L50_TYPE_PCM 8
  23. #define CS40L50_TYPE_PWLE 12
  24. #define CS40L50_PCM_ID 0x0
  25. #define CS40L50_OWT_CUSTOM_DATA_SIZE 2
  26. #define CS40L50_CUSTOM_DATA_MASK 0xFFFFU
  27. /* DSP */
  28. #define CS40L50_GPIO_BASE 0x2804140
  29. #define CS40L50_OWT_BASE 0x2805C34
  30. #define CS40L50_OWT_SIZE 0x2805C38
  31. #define CS40L50_OWT_NEXT 0x2805C3C
  32. #define CS40L50_EFFECTS_MAX 1
  33. /* GPIO */
  34. #define CS40L50_GPIO_NUM_MASK GENMASK(14, 12)
  35. #define CS40L50_GPIO_EDGE_MASK BIT(15)
  36. #define CS40L50_GPIO_MAPPING_NONE 0
  37. #define CS40L50_GPIO_DISABLE 0x1FF
  38. enum cs40l50_bank_type {
  39. CS40L50_WVFRM_BANK_RAM,
  40. CS40L50_WVFRM_BANK_ROM,
  41. CS40L50_WVFRM_BANK_OWT,
  42. CS40L50_WVFRM_BANK_NUM,
  43. };
  44. /* Describes an area in DSP memory populated by effects */
  45. struct cs40l50_bank {
  46. enum cs40l50_bank_type type;
  47. u32 base_index;
  48. u32 max_index;
  49. };
  50. struct cs40l50_effect {
  51. enum cs40l50_bank_type type;
  52. struct list_head list;
  53. u32 gpio_reg;
  54. u32 index;
  55. int id;
  56. };
  57. /* Describes haptic interface of loaded DSP firmware */
  58. struct cs40l50_vibra_dsp {
  59. struct cs40l50_bank *banks;
  60. u32 gpio_base_reg;
  61. u32 owt_offset_reg;
  62. u32 owt_size_reg;
  63. u32 owt_base_reg;
  64. u32 push_owt_cmd;
  65. u32 delete_owt_cmd;
  66. u32 stop_cmd;
  67. int (*write)(struct device *dev, struct regmap *regmap, u32 val);
  68. };
  69. /* Describes configuration and state of haptic operations */
  70. struct cs40l50_vibra {
  71. struct device *dev;
  72. struct regmap *regmap;
  73. struct input_dev *input;
  74. struct workqueue_struct *vib_wq;
  75. struct list_head effect_head;
  76. struct cs40l50_vibra_dsp dsp;
  77. };
  78. struct cs40l50_work {
  79. struct cs40l50_vibra *vib;
  80. struct ff_effect *effect;
  81. struct work_struct work;
  82. s16 *custom_data;
  83. int custom_len;
  84. int count;
  85. int error;
  86. };
  87. static struct cs40l50_bank cs40l50_banks[] = {
  88. {
  89. .type = CS40L50_WVFRM_BANK_RAM,
  90. .base_index = CS40L50_RAM_INDEX_START,
  91. .max_index = CS40L50_RAM_INDEX_END,
  92. },
  93. {
  94. .type = CS40L50_WVFRM_BANK_ROM,
  95. .base_index = CS40L50_ROM_INDEX_START,
  96. .max_index = CS40L50_ROM_INDEX_END,
  97. },
  98. {
  99. .type = CS40L50_WVFRM_BANK_OWT,
  100. .base_index = CS40L50_RTH_INDEX_START,
  101. .max_index = CS40L50_RTH_INDEX_END,
  102. },
  103. };
  104. static struct cs40l50_vibra_dsp cs40l50_dsp = {
  105. .banks = cs40l50_banks,
  106. .gpio_base_reg = CS40L50_GPIO_BASE,
  107. .owt_base_reg = CS40L50_OWT_BASE,
  108. .owt_offset_reg = CS40L50_OWT_NEXT,
  109. .owt_size_reg = CS40L50_OWT_SIZE,
  110. .push_owt_cmd = CS40L50_OWT_PUSH,
  111. .delete_owt_cmd = CS40L50_OWT_DELETE,
  112. .stop_cmd = CS40L50_STOP_PLAYBACK,
  113. .write = cs40l50_dsp_write,
  114. };
  115. static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effect_head)
  116. {
  117. struct cs40l50_effect *effect;
  118. list_for_each_entry(effect, effect_head, list)
  119. if (effect->id == id)
  120. return effect;
  121. return NULL;
  122. }
  123. static int cs40l50_effect_bank_set(struct cs40l50_work *work_data,
  124. struct cs40l50_effect *effect)
  125. {
  126. s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
  127. if (bank_type >= CS40L50_WVFRM_BANK_NUM) {
  128. dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type);
  129. return -EINVAL;
  130. }
  131. if (work_data->custom_len > CS40L50_OWT_CUSTOM_DATA_SIZE)
  132. effect->type = CS40L50_WVFRM_BANK_OWT;
  133. else
  134. effect->type = bank_type;
  135. return 0;
  136. }
  137. static int cs40l50_effect_index_set(struct cs40l50_work *work_data,
  138. struct cs40l50_effect *effect)
  139. {
  140. struct cs40l50_vibra *vib = work_data->vib;
  141. struct cs40l50_effect *owt_effect;
  142. u32 base_index, max_index;
  143. base_index = vib->dsp.banks[effect->type].base_index;
  144. max_index = vib->dsp.banks[effect->type].max_index;
  145. effect->index = base_index;
  146. switch (effect->type) {
  147. case CS40L50_WVFRM_BANK_OWT:
  148. list_for_each_entry(owt_effect, &vib->effect_head, list)
  149. if (owt_effect->type == CS40L50_WVFRM_BANK_OWT)
  150. effect->index++;
  151. break;
  152. case CS40L50_WVFRM_BANK_ROM:
  153. case CS40L50_WVFRM_BANK_RAM:
  154. effect->index += work_data->custom_data[1] & CS40L50_CUSTOM_DATA_MASK;
  155. break;
  156. default:
  157. dev_err(vib->dev, "Bank type %d not supported\n", effect->type);
  158. return -EINVAL;
  159. }
  160. if (effect->index > max_index || effect->index < base_index) {
  161. dev_err(vib->dev, "Index out of bounds: %u\n", effect->index);
  162. return -ENOSPC;
  163. }
  164. return 0;
  165. }
  166. static int cs40l50_effect_gpio_mapping_set(struct cs40l50_work *work_data,
  167. struct cs40l50_effect *effect)
  168. {
  169. u16 gpio_edge, gpio_num, button = work_data->effect->trigger.button;
  170. struct cs40l50_vibra *vib = work_data->vib;
  171. if (button) {
  172. gpio_num = FIELD_GET(CS40L50_GPIO_NUM_MASK, button);
  173. gpio_edge = FIELD_GET(CS40L50_GPIO_EDGE_MASK, button);
  174. effect->gpio_reg = vib->dsp.gpio_base_reg + (gpio_num * 8) - gpio_edge;
  175. return regmap_write(vib->regmap, effect->gpio_reg, button);
  176. }
  177. effect->gpio_reg = CS40L50_GPIO_MAPPING_NONE;
  178. return 0;
  179. }
  180. struct cs40l50_owt_header {
  181. u32 type;
  182. u32 data_words;
  183. u32 offset;
  184. } __packed;
  185. static int cs40l50_upload_owt(struct cs40l50_work *work_data)
  186. {
  187. u8 *new_owt_effect_data __free(kfree) = NULL;
  188. struct cs40l50_vibra *vib = work_data->vib;
  189. size_t len = work_data->custom_len * 2;
  190. struct cs40l50_owt_header header;
  191. u32 offset, size;
  192. int error;
  193. error = regmap_read(vib->regmap, vib->dsp.owt_size_reg, &size);
  194. if (error)
  195. return error;
  196. if ((size * sizeof(u32)) < sizeof(header) + len) {
  197. dev_err(vib->dev, "No space in open wavetable for effect\n");
  198. return -ENOSPC;
  199. }
  200. header.type = work_data->custom_data[0] == CS40L50_PCM_ID ? CS40L50_TYPE_PCM :
  201. CS40L50_TYPE_PWLE;
  202. header.offset = sizeof(header) / sizeof(u32);
  203. header.data_words = len / sizeof(u32);
  204. new_owt_effect_data = kmalloc(sizeof(header) + len, GFP_KERNEL);
  205. if (!new_owt_effect_data)
  206. return -ENOMEM;
  207. memcpy(new_owt_effect_data, &header, sizeof(header));
  208. memcpy(new_owt_effect_data + sizeof(header), work_data->custom_data, len);
  209. error = regmap_read(vib->regmap, vib->dsp.owt_offset_reg, &offset);
  210. if (error)
  211. return error;
  212. error = regmap_bulk_write(vib->regmap, vib->dsp.owt_base_reg +
  213. (offset * sizeof(u32)), new_owt_effect_data,
  214. sizeof(header) + len);
  215. if (error)
  216. return error;
  217. error = vib->dsp.write(vib->dev, vib->regmap, vib->dsp.push_owt_cmd);
  218. if (error)
  219. return error;
  220. return 0;
  221. }
  222. static void cs40l50_add_worker(struct work_struct *work)
  223. {
  224. struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
  225. struct cs40l50_vibra *vib = work_data->vib;
  226. struct cs40l50_effect *effect;
  227. bool is_new = false;
  228. int error;
  229. error = pm_runtime_resume_and_get(vib->dev);
  230. if (error)
  231. goto err_exit;
  232. /* Update effect if already uploaded, otherwise create new effect */
  233. effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
  234. if (!effect) {
  235. effect = kzalloc(sizeof(*effect), GFP_KERNEL);
  236. if (!effect) {
  237. error = -ENOMEM;
  238. goto err_pm;
  239. }
  240. effect->id = work_data->effect->id;
  241. is_new = true;
  242. }
  243. error = cs40l50_effect_bank_set(work_data, effect);
  244. if (error)
  245. goto err_free;
  246. error = cs40l50_effect_index_set(work_data, effect);
  247. if (error)
  248. goto err_free;
  249. error = cs40l50_effect_gpio_mapping_set(work_data, effect);
  250. if (error)
  251. goto err_free;
  252. if (effect->type == CS40L50_WVFRM_BANK_OWT)
  253. error = cs40l50_upload_owt(work_data);
  254. err_free:
  255. if (is_new) {
  256. if (error)
  257. kfree(effect);
  258. else
  259. list_add(&effect->list, &vib->effect_head);
  260. }
  261. err_pm:
  262. pm_runtime_mark_last_busy(vib->dev);
  263. pm_runtime_put_autosuspend(vib->dev);
  264. err_exit:
  265. work_data->error = error;
  266. }
  267. static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect,
  268. struct ff_effect *old)
  269. {
  270. struct ff_periodic_effect *periodic = &effect->u.periodic;
  271. struct cs40l50_vibra *vib = input_get_drvdata(dev);
  272. struct cs40l50_work work_data;
  273. if (effect->type != FF_PERIODIC || periodic->waveform != FF_CUSTOM) {
  274. dev_err(vib->dev, "Type (%#X) or waveform (%#X) unsupported\n",
  275. effect->type, periodic->waveform);
  276. return -EINVAL;
  277. }
  278. work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data,
  279. effect->u.periodic.custom_len,
  280. sizeof(s16));
  281. if (IS_ERR(work_data.custom_data))
  282. return PTR_ERR(work_data.custom_data);
  283. work_data.custom_len = effect->u.periodic.custom_len;
  284. work_data.vib = vib;
  285. work_data.effect = effect;
  286. INIT_WORK_ONSTACK(&work_data.work, cs40l50_add_worker);
  287. /* Push to the workqueue to serialize with playbacks */
  288. queue_work(vib->vib_wq, &work_data.work);
  289. flush_work(&work_data.work);
  290. destroy_work_on_stack(&work_data.work);
  291. kfree(work_data.custom_data);
  292. return work_data.error;
  293. }
  294. static void cs40l50_start_worker(struct work_struct *work)
  295. {
  296. struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
  297. struct cs40l50_vibra *vib = work_data->vib;
  298. struct cs40l50_effect *start_effect;
  299. if (pm_runtime_resume_and_get(vib->dev) < 0)
  300. goto err_free;
  301. start_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
  302. if (start_effect) {
  303. while (--work_data->count >= 0) {
  304. vib->dsp.write(vib->dev, vib->regmap, start_effect->index);
  305. usleep_range(work_data->effect->replay.length,
  306. work_data->effect->replay.length + 100);
  307. }
  308. } else {
  309. dev_err(vib->dev, "Effect to play not found\n");
  310. }
  311. pm_runtime_mark_last_busy(vib->dev);
  312. pm_runtime_put_autosuspend(vib->dev);
  313. err_free:
  314. kfree(work_data);
  315. }
  316. static void cs40l50_stop_worker(struct work_struct *work)
  317. {
  318. struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
  319. struct cs40l50_vibra *vib = work_data->vib;
  320. if (pm_runtime_resume_and_get(vib->dev) < 0)
  321. return;
  322. vib->dsp.write(vib->dev, vib->regmap, vib->dsp.stop_cmd);
  323. pm_runtime_mark_last_busy(vib->dev);
  324. pm_runtime_put_autosuspend(vib->dev);
  325. kfree(work_data);
  326. }
  327. static int cs40l50_playback(struct input_dev *dev, int effect_id, int val)
  328. {
  329. struct cs40l50_vibra *vib = input_get_drvdata(dev);
  330. struct cs40l50_work *work_data;
  331. work_data = kzalloc(sizeof(*work_data), GFP_ATOMIC);
  332. if (!work_data)
  333. return -ENOMEM;
  334. work_data->vib = vib;
  335. if (val > 0) {
  336. work_data->effect = &dev->ff->effects[effect_id];
  337. work_data->count = val;
  338. INIT_WORK(&work_data->work, cs40l50_start_worker);
  339. } else {
  340. /* Stop the amplifier as device drives only one effect */
  341. INIT_WORK(&work_data->work, cs40l50_stop_worker);
  342. }
  343. queue_work(vib->vib_wq, &work_data->work);
  344. return 0;
  345. }
  346. static void cs40l50_erase_worker(struct work_struct *work)
  347. {
  348. struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
  349. struct cs40l50_effect *erase_effect, *owt_effect;
  350. struct cs40l50_vibra *vib = work_data->vib;
  351. int error;
  352. error = pm_runtime_resume_and_get(vib->dev);
  353. if (error)
  354. goto err_exit;
  355. erase_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
  356. if (!erase_effect) {
  357. dev_err(vib->dev, "Effect to erase not found\n");
  358. error = -EINVAL;
  359. goto err_pm;
  360. }
  361. if (erase_effect->gpio_reg != CS40L50_GPIO_MAPPING_NONE) {
  362. error = regmap_write(vib->regmap, erase_effect->gpio_reg,
  363. CS40L50_GPIO_DISABLE);
  364. if (error)
  365. goto err_pm;
  366. }
  367. if (erase_effect->type == CS40L50_WVFRM_BANK_OWT) {
  368. error = vib->dsp.write(vib->dev, vib->regmap,
  369. vib->dsp.delete_owt_cmd |
  370. (erase_effect->index & 0xFF));
  371. if (error)
  372. goto err_pm;
  373. list_for_each_entry(owt_effect, &vib->effect_head, list)
  374. if (owt_effect->type == CS40L50_WVFRM_BANK_OWT &&
  375. owt_effect->index > erase_effect->index)
  376. owt_effect->index--;
  377. }
  378. list_del(&erase_effect->list);
  379. kfree(erase_effect);
  380. err_pm:
  381. pm_runtime_mark_last_busy(vib->dev);
  382. pm_runtime_put_autosuspend(vib->dev);
  383. err_exit:
  384. work_data->error = error;
  385. }
  386. static int cs40l50_erase(struct input_dev *dev, int effect_id)
  387. {
  388. struct cs40l50_vibra *vib = input_get_drvdata(dev);
  389. struct cs40l50_work work_data;
  390. work_data.vib = vib;
  391. work_data.effect = &dev->ff->effects[effect_id];
  392. INIT_WORK_ONSTACK(&work_data.work, cs40l50_erase_worker);
  393. /* Push to workqueue to serialize with playbacks */
  394. queue_work(vib->vib_wq, &work_data.work);
  395. flush_work(&work_data.work);
  396. destroy_work_on_stack(&work_data.work);
  397. return work_data.error;
  398. }
  399. static void cs40l50_remove_wq(void *data)
  400. {
  401. flush_workqueue(data);
  402. destroy_workqueue(data);
  403. }
  404. static int cs40l50_vibra_probe(struct platform_device *pdev)
  405. {
  406. struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent);
  407. struct cs40l50_vibra *vib;
  408. int error;
  409. vib = devm_kzalloc(pdev->dev.parent, sizeof(*vib), GFP_KERNEL);
  410. if (!vib)
  411. return -ENOMEM;
  412. vib->dev = cs40l50->dev;
  413. vib->regmap = cs40l50->regmap;
  414. vib->dsp = cs40l50_dsp;
  415. vib->input = devm_input_allocate_device(vib->dev);
  416. if (!vib->input)
  417. return -ENOMEM;
  418. vib->input->id.product = cs40l50->devid;
  419. vib->input->id.version = cs40l50->revid;
  420. vib->input->name = "cs40l50_vibra";
  421. input_set_drvdata(vib->input, vib);
  422. input_set_capability(vib->input, EV_FF, FF_PERIODIC);
  423. input_set_capability(vib->input, EV_FF, FF_CUSTOM);
  424. error = input_ff_create(vib->input, CS40L50_EFFECTS_MAX);
  425. if (error) {
  426. dev_err(vib->dev, "Failed to create input device\n");
  427. return error;
  428. }
  429. vib->input->ff->upload = cs40l50_add;
  430. vib->input->ff->playback = cs40l50_playback;
  431. vib->input->ff->erase = cs40l50_erase;
  432. INIT_LIST_HEAD(&vib->effect_head);
  433. vib->vib_wq = alloc_ordered_workqueue("vib_wq", WQ_HIGHPRI);
  434. if (!vib->vib_wq)
  435. return -ENOMEM;
  436. error = devm_add_action_or_reset(vib->dev, cs40l50_remove_wq, vib->vib_wq);
  437. if (error)
  438. return error;
  439. error = input_register_device(vib->input);
  440. if (error)
  441. return error;
  442. return 0;
  443. }
  444. static const struct platform_device_id cs40l50_vibra_id_match[] = {
  445. { "cs40l50-vibra", },
  446. {}
  447. };
  448. MODULE_DEVICE_TABLE(platform, cs40l50_vibra_id_match);
  449. static struct platform_driver cs40l50_vibra_driver = {
  450. .probe = cs40l50_vibra_probe,
  451. .id_table = cs40l50_vibra_id_match,
  452. .driver = {
  453. .name = "cs40l50-vibra",
  454. },
  455. };
  456. module_platform_driver(cs40l50_vibra_driver);
  457. MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver");
  458. MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
  459. MODULE_LICENSE("GPL");