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