summaryrefslogtreecommitdiff
path: root/cs40l26/cs40l26.c
diff options
context:
space:
mode:
Diffstat (limited to 'cs40l26/cs40l26.c')
-rw-r--r--cs40l26/cs40l26.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/cs40l26/cs40l26.c b/cs40l26/cs40l26.c
index 93fe669..39f5253 100644
--- a/cs40l26/cs40l26.c
+++ b/cs40l26/cs40l26.c
@@ -708,6 +708,7 @@ static int cs40l26_handle_mbox_buffer(struct cs40l26_private *cs40l26)
switch (val) {
case CS40L26_DSP_MBOX_COMPLETE_MBOX:
dev_dbg(dev, "Mailbox: COMPLETE_MBOX\n");
+ complete_all(&cs40l26->erase_cont);
cs40l26_vibe_state_update(cs40l26,
CS40L26_VIBE_STATE_EVENT_MBOX_COMPLETE);
break;
@@ -1943,6 +1944,8 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
if (!cs40l26->vibe_state_reporting)
cs40l26_vibe_state_update(cs40l26,
CS40L26_VIBE_STATE_EVENT_MBOX_PLAYBACK);
+
+ reinit_completion(&cs40l26->erase_cont);
err_mutex:
mutex_unlock(&cs40l26->lock);
pm_runtime_mark_last_busy(dev);
@@ -2428,7 +2431,12 @@ static int cs40l26_refactor_owt(struct cs40l26_private *cs40l26, s16 *in_data,
ch = cl_dsp_memchunk_create((void *) in_data, in_data_bytes);
cl_dsp_memchunk_read(&ch, 8); /* Skip padding */
- nsections = cl_dsp_memchunk_read(&ch, 8);
+ ret = cl_dsp_memchunk_read(&ch, 8);
+ if (ret < 0)
+ return ret;
+
+ nsections = ret;
+
global_rep = cl_dsp_memchunk_read(&ch, 8);
sections = kcalloc(nsections, sizeof(struct cs40l26_owt_section),
@@ -2957,6 +2965,7 @@ static void cs40l26_erase_worker(struct work_struct *work)
struct cs40l26_private, erase_work);
int ret = 0;
int effect_id;
+ u16 duration;
u32 index;
ret = pm_runtime_get_sync(cs40l26->dev);
@@ -2967,6 +2976,22 @@ static void cs40l26_erase_worker(struct work_struct *work)
effect_id = cs40l26->erase_effect->id;
index = cs40l26->trigger_indices[effect_id];
+ duration = (cs40l26->erase_effect->replay.length == 0) ?
+ CS40L26_MAX_WAIT_VIBE_COMPLETE_MS :
+ cs40l26->erase_effect->replay.length + CS40L26_ERASE_BUFFER_MS;
+
+ /* Check for ongoing effect playback. */
+ if (cs40l26->vibe_state == CS40L26_VIBE_STATE_HAPTIC) {
+ /* Wait for effect to complete. */
+ mutex_unlock(&cs40l26->lock);
+ if (!wait_for_completion_timeout(&cs40l26->erase_cont,
+ msecs_to_jiffies(duration))) {
+ ret = -ETIME;
+ dev_err(cs40l26->dev, "Failed to erase effect: %d", ret);
+ goto pm_err;
+ }
+ mutex_lock(&cs40l26->lock);
+ }
dev_dbg(cs40l26->dev, "%s: effect ID = %d\n", __func__, effect_id);
@@ -2992,6 +3017,7 @@ static void cs40l26_erase_worker(struct work_struct *work)
out_mutex:
mutex_unlock(&cs40l26->lock);
+pm_err:
pm_runtime_mark_last_busy(cs40l26->dev);
pm_runtime_put_autosuspend(cs40l26->dev);
@@ -4798,6 +4824,7 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
cs40l26->pm_ready = false;
init_completion(&cs40l26->i2s_cont);
+ init_completion(&cs40l26->erase_cont);
if (!cs40l26->fw_defer) {
ret = cs40l26_fw_upload(cs40l26);