1 // SPDX-License-Identifier: GPL-2.0
3 * CS40L50 Advanced Haptic Driver with waveform memory,
4 * integrated DSP, and closed-loop algorithms
6 * Copyright 2024 Cirrus Logic, Inc.
8 * Author: James Ogletree <james.ogletree@cirrus.com>
11 #include <linux/firmware/cirrus/cs_dsp.h>
12 #include <linux/firmware/cirrus/wmfw.h>
13 #include <linux/mfd/core.h>
14 #include <linux/mfd/cs40l50.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/regulator/consumer.h>
18 static const struct mfd_cell cs40l50_devs
[] = {
19 { .name
= "cs40l50-codec", },
20 { .name
= "cs40l50-vibra", },
23 const struct regmap_config cs40l50_regmap
= {
27 .reg_format_endian
= REGMAP_ENDIAN_BIG
,
28 .val_format_endian
= REGMAP_ENDIAN_BIG
,
30 EXPORT_SYMBOL_GPL(cs40l50_regmap
);
32 static const char * const cs40l50_supplies
[] = {
36 static const struct regmap_irq cs40l50_reg_irqs
[] = {
37 REGMAP_IRQ_REG(CS40L50_DSP_QUEUE_IRQ
, CS40L50_IRQ1_INT_2_OFFSET
,
38 CS40L50_DSP_QUEUE_MASK
),
39 REGMAP_IRQ_REG(CS40L50_AMP_SHORT_IRQ
, CS40L50_IRQ1_INT_1_OFFSET
,
40 CS40L50_AMP_SHORT_MASK
),
41 REGMAP_IRQ_REG(CS40L50_TEMP_ERR_IRQ
, CS40L50_IRQ1_INT_8_OFFSET
,
42 CS40L50_TEMP_ERR_MASK
),
43 REGMAP_IRQ_REG(CS40L50_BST_UVP_IRQ
, CS40L50_IRQ1_INT_9_OFFSET
,
44 CS40L50_BST_UVP_MASK
),
45 REGMAP_IRQ_REG(CS40L50_BST_SHORT_IRQ
, CS40L50_IRQ1_INT_9_OFFSET
,
46 CS40L50_BST_SHORT_MASK
),
47 REGMAP_IRQ_REG(CS40L50_BST_ILIMIT_IRQ
, CS40L50_IRQ1_INT_9_OFFSET
,
48 CS40L50_BST_ILIMIT_MASK
),
49 REGMAP_IRQ_REG(CS40L50_UVLO_VDDBATT_IRQ
, CS40L50_IRQ1_INT_10_OFFSET
,
50 CS40L50_UVLO_VDDBATT_MASK
),
51 REGMAP_IRQ_REG(CS40L50_GLOBAL_ERROR_IRQ
, CS40L50_IRQ1_INT_18_OFFSET
,
52 CS40L50_GLOBAL_ERROR_MASK
),
55 static struct regmap_irq_chip cs40l50_irq_chip
= {
57 .status_base
= CS40L50_IRQ1_INT_1
,
58 .mask_base
= CS40L50_IRQ1_MASK_1
,
59 .ack_base
= CS40L50_IRQ1_INT_1
,
61 .irqs
= cs40l50_reg_irqs
,
62 .num_irqs
= ARRAY_SIZE(cs40l50_reg_irqs
),
66 int cs40l50_dsp_write(struct device
*dev
, struct regmap
*regmap
, u32 val
)
71 /* Device NAKs if hibernating, so optionally retry */
72 for (i
= 0; i
< CS40L50_DSP_TIMEOUT_COUNT
; i
++) {
73 ret
= regmap_write(regmap
, CS40L50_DSP_QUEUE
, val
);
77 usleep_range(CS40L50_DSP_POLL_US
, CS40L50_DSP_POLL_US
+ 100);
80 /* If the write never took place, no need to check for the ACK */
81 if (i
== CS40L50_DSP_TIMEOUT_COUNT
) {
82 dev_err(dev
, "Timed out writing %#X to DSP: %d\n", val
, ret
);
86 ret
= regmap_read_poll_timeout(regmap
, CS40L50_DSP_QUEUE
, ack
, !ack
,
88 CS40L50_DSP_POLL_US
* CS40L50_DSP_TIMEOUT_COUNT
);
90 dev_err(dev
, "DSP failed to ACK %#X: %d\n", val
, ret
);
94 EXPORT_SYMBOL_GPL(cs40l50_dsp_write
);
96 static const struct cs_dsp_region cs40l50_dsp_regions
[] = {
97 { .type
= WMFW_HALO_PM_PACKED
, .base
= CS40L50_PMEM_0
},
98 { .type
= WMFW_HALO_XM_PACKED
, .base
= CS40L50_XMEM_PACKED_0
},
99 { .type
= WMFW_HALO_YM_PACKED
, .base
= CS40L50_YMEM_PACKED_0
},
100 { .type
= WMFW_ADSP2_XM
, .base
= CS40L50_XMEM_UNPACKED24_0
},
101 { .type
= WMFW_ADSP2_YM
, .base
= CS40L50_YMEM_UNPACKED24_0
},
104 static const struct reg_sequence cs40l50_internal_vamp_config
[] = {
105 { CS40L50_BST_LPMODE_SEL
, CS40L50_DCM_LOW_POWER
},
106 { CS40L50_BLOCK_ENABLES2
, CS40L50_OVERTEMP_WARN
},
109 static const struct reg_sequence cs40l50_irq_mask_override
[] = {
110 { CS40L50_IRQ1_MASK_2
, CS40L50_IRQ_MASK_2_OVERRIDE
},
111 { CS40L50_IRQ1_MASK_20
, CS40L50_IRQ_MASK_20_OVERRIDE
},
114 static int cs40l50_wseq_init(struct cs40l50
*cs40l50
)
116 struct cs_dsp
*dsp
= &cs40l50
->dsp
;
118 cs40l50
->wseqs
[CS40L50_STANDBY
].ctl
= cs_dsp_get_ctl(dsp
, "STANDBY_SEQUENCE",
121 if (!cs40l50
->wseqs
[CS40L50_STANDBY
].ctl
) {
122 dev_err(cs40l50
->dev
, "Control not found for standby sequence\n");
126 cs40l50
->wseqs
[CS40L50_ACTIVE
].ctl
= cs_dsp_get_ctl(dsp
, "ACTIVE_SEQUENCE",
129 if (!cs40l50
->wseqs
[CS40L50_ACTIVE
].ctl
) {
130 dev_err(cs40l50
->dev
, "Control not found for active sequence\n");
134 cs40l50
->wseqs
[CS40L50_PWR_ON
].ctl
= cs_dsp_get_ctl(dsp
, "PM_PWR_ON_SEQ",
137 if (!cs40l50
->wseqs
[CS40L50_PWR_ON
].ctl
) {
138 dev_err(cs40l50
->dev
, "Control not found for power-on sequence\n");
142 return cs_dsp_wseq_init(&cs40l50
->dsp
, cs40l50
->wseqs
, ARRAY_SIZE(cs40l50
->wseqs
));
145 static int cs40l50_dsp_config(struct cs40l50
*cs40l50
)
149 /* Configure internal V_AMP supply */
150 ret
= regmap_multi_reg_write(cs40l50
->regmap
, cs40l50_internal_vamp_config
,
151 ARRAY_SIZE(cs40l50_internal_vamp_config
));
155 ret
= cs_dsp_wseq_multi_write(&cs40l50
->dsp
, &cs40l50
->wseqs
[CS40L50_PWR_ON
],
156 cs40l50_internal_vamp_config
, CS_DSP_WSEQ_FULL
,
157 ARRAY_SIZE(cs40l50_internal_vamp_config
), false);
161 /* Override firmware defaults for IRQ masks */
162 ret
= regmap_multi_reg_write(cs40l50
->regmap
, cs40l50_irq_mask_override
,
163 ARRAY_SIZE(cs40l50_irq_mask_override
));
167 return cs_dsp_wseq_multi_write(&cs40l50
->dsp
, &cs40l50
->wseqs
[CS40L50_PWR_ON
],
168 cs40l50_irq_mask_override
, CS_DSP_WSEQ_FULL
,
169 ARRAY_SIZE(cs40l50_irq_mask_override
), false);
172 static int cs40l50_dsp_post_run(struct cs_dsp
*dsp
)
174 struct cs40l50
*cs40l50
= container_of(dsp
, struct cs40l50
, dsp
);
177 ret
= cs40l50_wseq_init(cs40l50
);
181 ret
= cs40l50_dsp_config(cs40l50
);
183 dev_err(cs40l50
->dev
, "Failed to configure DSP: %d\n", ret
);
187 ret
= devm_mfd_add_devices(cs40l50
->dev
, PLATFORM_DEVID_NONE
, cs40l50_devs
,
188 ARRAY_SIZE(cs40l50_devs
), NULL
, 0, NULL
);
190 dev_err(cs40l50
->dev
, "Failed to add child devices: %d\n", ret
);
195 static const struct cs_dsp_client_ops client_ops
= {
196 .post_run
= cs40l50_dsp_post_run
,
199 static void cs40l50_dsp_remove(void *data
)
204 static int cs40l50_dsp_init(struct cs40l50
*cs40l50
)
208 cs40l50
->dsp
.num
= 1;
209 cs40l50
->dsp
.type
= WMFW_HALO
;
210 cs40l50
->dsp
.dev
= cs40l50
->dev
;
211 cs40l50
->dsp
.regmap
= cs40l50
->regmap
;
212 cs40l50
->dsp
.base
= CS40L50_CORE_BASE
;
213 cs40l50
->dsp
.base_sysinfo
= CS40L50_SYS_INFO_ID
;
214 cs40l50
->dsp
.mem
= cs40l50_dsp_regions
;
215 cs40l50
->dsp
.num_mems
= ARRAY_SIZE(cs40l50_dsp_regions
);
216 cs40l50
->dsp
.no_core_startstop
= true;
217 cs40l50
->dsp
.client_ops
= &client_ops
;
219 ret
= cs_dsp_halo_init(&cs40l50
->dsp
);
223 return devm_add_action_or_reset(cs40l50
->dev
, cs40l50_dsp_remove
,
227 static int cs40l50_reset_dsp(struct cs40l50
*cs40l50
)
231 mutex_lock(&cs40l50
->lock
);
233 if (cs40l50
->dsp
.running
)
234 cs_dsp_stop(&cs40l50
->dsp
);
236 if (cs40l50
->dsp
.booted
)
237 cs_dsp_power_down(&cs40l50
->dsp
);
239 ret
= cs40l50_dsp_write(cs40l50
->dev
, cs40l50
->regmap
, CS40L50_SHUTDOWN
);
243 ret
= cs_dsp_power_up(&cs40l50
->dsp
, cs40l50
->fw
, "cs40l50.wmfw",
244 cs40l50
->bin
, "cs40l50.bin", "cs40l50");
248 ret
= cs40l50_dsp_write(cs40l50
->dev
, cs40l50
->regmap
, CS40L50_SYSTEM_RESET
);
252 ret
= cs40l50_dsp_write(cs40l50
->dev
, cs40l50
->regmap
, CS40L50_PREVENT_HIBER
);
256 ret
= cs_dsp_run(&cs40l50
->dsp
);
258 mutex_unlock(&cs40l50
->lock
);
263 static void cs40l50_dsp_power_down(void *data
)
265 cs_dsp_power_down(data
);
268 static void cs40l50_dsp_stop(void *data
)
273 static void cs40l50_dsp_bringup(const struct firmware
*bin
, void *context
)
275 struct cs40l50
*cs40l50
= context
;
279 /* Wavetable is optional; bringup DSP regardless */
282 ret
= cs40l50_reset_dsp(cs40l50
);
284 dev_err(cs40l50
->dev
, "Failed to reset DSP: %d\n", ret
);
288 ret
= regmap_read(cs40l50
->regmap
, CS40L50_NUM_WAVES
, &nwaves
);
292 dev_info(cs40l50
->dev
, "%u RAM effects loaded\n", nwaves
);
294 /* Add teardown actions for first-time bringup */
295 ret
= devm_add_action_or_reset(cs40l50
->dev
, cs40l50_dsp_power_down
,
298 dev_err(cs40l50
->dev
, "Failed to add power down action: %d\n", ret
);
302 ret
= devm_add_action_or_reset(cs40l50
->dev
, cs40l50_dsp_stop
, &cs40l50
->dsp
);
304 dev_err(cs40l50
->dev
, "Failed to add stop action: %d\n", ret
);
306 release_firmware(cs40l50
->bin
);
307 release_firmware(cs40l50
->fw
);
310 static void cs40l50_request_firmware(const struct firmware
*fw
, void *context
)
312 struct cs40l50
*cs40l50
= context
;
316 dev_err(cs40l50
->dev
, "No firmware file found\n");
322 ret
= request_firmware_nowait(THIS_MODULE
, FW_ACTION_UEVENT
, CS40L50_WT
,
323 cs40l50
->dev
, GFP_KERNEL
, cs40l50
,
324 cs40l50_dsp_bringup
);
326 dev_err(cs40l50
->dev
, "Failed to request %s: %d\n", CS40L50_WT
, ret
);
327 release_firmware(cs40l50
->fw
);
336 static struct cs40l50_irq cs40l50_irqs
[] = {
340 { "Boost current limit", },
342 { "Boost undervolt", },
347 static const struct reg_sequence cs40l50_err_rls
[] = {
348 { CS40L50_ERR_RLS
, CS40L50_GLOBAL_ERR_RLS_SET
},
349 { CS40L50_ERR_RLS
, CS40L50_GLOBAL_ERR_RLS_CLEAR
},
352 static irqreturn_t
cs40l50_hw_err(int irq
, void *data
)
354 struct cs40l50
*cs40l50
= data
;
357 mutex_lock(&cs40l50
->lock
);
359 /* Log hardware interrupt and execute error release sequence */
360 for (i
= 1; i
< ARRAY_SIZE(cs40l50_irqs
); i
++) {
361 if (cs40l50_irqs
[i
].virq
== irq
) {
362 dev_err(cs40l50
->dev
, "%s error\n", cs40l50_irqs
[i
].name
);
363 ret
= regmap_multi_reg_write(cs40l50
->regmap
, cs40l50_err_rls
,
364 ARRAY_SIZE(cs40l50_err_rls
));
369 mutex_unlock(&cs40l50
->lock
);
370 return IRQ_RETVAL(!ret
);
373 static irqreturn_t
cs40l50_dsp_queue(int irq
, void *data
)
375 struct cs40l50
*cs40l50
= data
;
376 u32 rd_ptr
, val
, wt_ptr
;
379 mutex_lock(&cs40l50
->lock
);
381 /* Read from DSP queue, log, and update read pointer */
383 ret
= regmap_read(cs40l50
->regmap
, CS40L50_DSP_QUEUE_WT
, &wt_ptr
);
387 ret
= regmap_read(cs40l50
->regmap
, CS40L50_DSP_QUEUE_RD
, &rd_ptr
);
391 /* Check if queue is empty */
392 if (wt_ptr
== rd_ptr
)
395 ret
= regmap_read(cs40l50
->regmap
, rd_ptr
, &val
);
399 dev_dbg(cs40l50
->dev
, "DSP payload: %#X", val
);
401 rd_ptr
+= sizeof(u32
);
403 if (rd_ptr
> CS40L50_DSP_QUEUE_END
)
404 rd_ptr
= CS40L50_DSP_QUEUE_BASE
;
406 ret
= regmap_write(cs40l50
->regmap
, CS40L50_DSP_QUEUE_RD
, rd_ptr
);
409 mutex_unlock(&cs40l50
->lock
);
411 return IRQ_RETVAL(!ret
);
414 static int cs40l50_irq_init(struct cs40l50
*cs40l50
)
418 ret
= devm_regmap_add_irq_chip(cs40l50
->dev
, cs40l50
->regmap
, cs40l50
->irq
,
419 IRQF_ONESHOT
| IRQF_SHARED
, 0,
420 &cs40l50_irq_chip
, &cs40l50
->irq_data
);
422 dev_err(cs40l50
->dev
, "Failed adding IRQ chip\n");
426 for (i
= 0; i
< ARRAY_SIZE(cs40l50_irqs
); i
++) {
427 virq
= regmap_irq_get_virq(cs40l50
->irq_data
, i
);
429 dev_err(cs40l50
->dev
, "Failed getting virq for %s\n",
430 cs40l50_irqs
[i
].name
);
434 cs40l50_irqs
[i
].virq
= virq
;
436 /* Handle DSP and hardware interrupts separately */
437 ret
= devm_request_threaded_irq(cs40l50
->dev
, virq
, NULL
,
438 i
? cs40l50_hw_err
: cs40l50_dsp_queue
,
439 IRQF_ONESHOT
| IRQF_SHARED
,
440 cs40l50_irqs
[i
].name
, cs40l50
);
442 return dev_err_probe(cs40l50
->dev
, ret
,
443 "Failed requesting %s IRQ\n",
444 cs40l50_irqs
[i
].name
);
451 static int cs40l50_get_model(struct cs40l50
*cs40l50
)
455 ret
= regmap_read(cs40l50
->regmap
, CS40L50_DEVID
, &cs40l50
->devid
);
459 if (cs40l50
->devid
!= CS40L50_DEVID_A
)
462 ret
= regmap_read(cs40l50
->regmap
, CS40L50_REVID
, &cs40l50
->revid
);
466 if (cs40l50
->revid
< CS40L50_REVID_B0
)
469 dev_dbg(cs40l50
->dev
, "Cirrus Logic CS40L50 rev. %02X\n", cs40l50
->revid
);
474 static int cs40l50_pm_runtime_setup(struct device
*dev
)
478 pm_runtime_set_autosuspend_delay(dev
, CS40L50_AUTOSUSPEND_MS
);
479 pm_runtime_use_autosuspend(dev
);
480 pm_runtime_get_noresume(dev
);
481 ret
= pm_runtime_set_active(dev
);
485 return devm_pm_runtime_enable(dev
);
488 int cs40l50_probe(struct cs40l50
*cs40l50
)
490 struct device
*dev
= cs40l50
->dev
;
493 mutex_init(&cs40l50
->lock
);
495 cs40l50
->reset_gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_HIGH
);
496 if (IS_ERR(cs40l50
->reset_gpio
))
497 return dev_err_probe(dev
, PTR_ERR(cs40l50
->reset_gpio
),
498 "Failed getting reset GPIO\n");
500 ret
= devm_regulator_bulk_get_enable(dev
, ARRAY_SIZE(cs40l50_supplies
),
503 return dev_err_probe(dev
, ret
, "Failed getting supplies\n");
505 /* Ensure minimum reset pulse width */
506 usleep_range(CS40L50_RESET_PULSE_US
, CS40L50_RESET_PULSE_US
+ 100);
508 gpiod_set_value_cansleep(cs40l50
->reset_gpio
, 0);
510 /* Wait for control port to be ready */
511 usleep_range(CS40L50_CP_READY_US
, CS40L50_CP_READY_US
+ 100);
513 ret
= cs40l50_get_model(cs40l50
);
515 return dev_err_probe(dev
, ret
, "Failed to get part number\n");
517 ret
= cs40l50_dsp_init(cs40l50
);
519 return dev_err_probe(dev
, ret
, "Failed to initialize DSP\n");
521 ret
= cs40l50_pm_runtime_setup(dev
);
523 return dev_err_probe(dev
, ret
, "Failed to initialize runtime PM\n");
525 ret
= cs40l50_irq_init(cs40l50
);
529 ret
= request_firmware_nowait(THIS_MODULE
, FW_ACTION_UEVENT
, CS40L50_FW
,
530 dev
, GFP_KERNEL
, cs40l50
, cs40l50_request_firmware
);
532 return dev_err_probe(dev
, ret
, "Failed to request %s\n", CS40L50_FW
);
534 pm_runtime_mark_last_busy(dev
);
535 pm_runtime_put_autosuspend(dev
);
539 EXPORT_SYMBOL_GPL(cs40l50_probe
);
541 int cs40l50_remove(struct cs40l50
*cs40l50
)
543 gpiod_set_value_cansleep(cs40l50
->reset_gpio
, 1);
547 EXPORT_SYMBOL_GPL(cs40l50_remove
);
549 static int cs40l50_runtime_suspend(struct device
*dev
)
551 struct cs40l50
*cs40l50
= dev_get_drvdata(dev
);
553 return regmap_write(cs40l50
->regmap
, CS40L50_DSP_QUEUE
, CS40L50_ALLOW_HIBER
);
556 static int cs40l50_runtime_resume(struct device
*dev
)
558 struct cs40l50
*cs40l50
= dev_get_drvdata(dev
);
560 return cs40l50_dsp_write(dev
, cs40l50
->regmap
, CS40L50_PREVENT_HIBER
);
563 EXPORT_GPL_DEV_PM_OPS(cs40l50_pm_ops
) = {
564 RUNTIME_PM_OPS(cs40l50_runtime_suspend
, cs40l50_runtime_resume
, NULL
)
567 MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver");
568 MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
569 MODULE_LICENSE("GPL");
570 MODULE_IMPORT_NS(FW_CS_DSP
);