summaryrefslogtreecommitdiff
path: root/sound/soc/intel/common/sst-dsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/common/sst-dsp.c')
-rw-r--r--sound/soc/intel/common/sst-dsp.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
index 64e94212d..a627236dd 100644
--- a/sound/soc/intel/common/sst-dsp.c
+++ b/sound/soc/intel/common/sst-dsp.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
@@ -196,6 +197,22 @@ int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
+/* This is for registers bits with attribute RWC */
+void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ unsigned int old, new;
+ u32 ret;
+
+ ret = sst_dsp_shim_read_unlocked(sst, offset);
+
+ old = ret;
+ new = (old & (~mask)) | (value & mask);
+
+ sst_dsp_shim_write_unlocked(sst, offset, new);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
+
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
@@ -222,6 +239,60 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
+/* This is for registers bits with attribute RWC */
+void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
+
+int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
+ u32 target, u32 timeout, char *operation)
+{
+ int time, ret;
+ u32 reg;
+ bool done = false;
+
+ /*
+ * we will poll for couple of ms using mdelay, if not successful
+ * then go to longer sleep using usleep_range
+ */
+
+ /* check if set state successful */
+ for (time = 0; time < 5; time++) {
+ if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) {
+ done = true;
+ break;
+ }
+ mdelay(1);
+ }
+
+ if (done == false) {
+ /* sleeping in 10ms steps so adjust timeout value */
+ timeout /= 10;
+
+ for (time = 0; time < timeout; time++) {
+ if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target)
+ break;
+
+ usleep_range(5000, 10000);
+ }
+ }
+
+ reg = sst_dsp_shim_read_unlocked(ctx, offset);
+ dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
+ (time < timeout) ? "successful" : "timedout");
+ ret = time < timeout ? 0 : -ETIME;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
+
void sst_dsp_dump(struct sst_dsp *sst)
{
if (sst->ops->dump)