summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com>2022-10-30 18:59:59 -0700
committerSecurityBot <android-nexus-securitybot@system.gserviceaccount.com>2022-10-30 18:59:59 -0700
commit0dd8c419639d9b1c02a65507fcb992435606ee14 (patch)
tree711b841c749dc2ba106ff0fd6c1443ef3ca8348a
parentad41b7b82d645108e3082a087fd412a289497852 (diff)
parent5f2484108386af73566a0efc2d7ef720ab392975 (diff)
downloadamplifiers-0dd8c419639d9b1c02a65507fcb992435606ee14.tar.gz
Merge android13-gs-pixel-5.10-tm-qpr2 into android13-gs-pixel-5.10-udc
SBMerger: 478053055 Change-Id: I2ae72a1dacfbc4061304f626ef5cc3d071f2f928 Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r--cs40l26/Makefile1
-rw-r--r--cs40l26/cl_dsp.c213
-rw-r--r--cs40l26/cl_dsp.h3
-rw-r--r--cs40l26/cs40l26-codec.c151
-rw-r--r--cs40l26/cs40l26-i2c.c2
-rw-r--r--cs40l26/cs40l26-spi.c2
-rw-r--r--cs40l26/cs40l26-sysfs.c484
-rw-r--r--cs40l26/cs40l26-tables.c2
-rw-r--r--cs40l26/cs40l26.c677
-rw-r--r--cs40l26/cs40l26.h52
10 files changed, 817 insertions, 770 deletions
diff --git a/cs40l26/Makefile b/cs40l26/Makefile
index 5642c07..3c4ceaf 100644
--- a/cs40l26/Makefile
+++ b/cs40l26/Makefile
@@ -21,6 +21,7 @@ KBUILD_OPTIONS += CONFIG_INPUT_CS40L26_I2C=m \
EXTRA_CFLAGS += -DDYNAMIC_DEBUG_MODULE
EXTRA_CFLAGS += -DCONFIG_INPUT_CS40L26_ATTR_UNDER_BUS
+EXTRA_CFLAGS += -DCONFIG_GOOG_CUST
modules modules_install clean:
$(MAKE) -C $(KERNEL_SRC) M=$(M) \
diff --git a/cs40l26/cl_dsp.c b/cs40l26/cl_dsp.c
index bcbee33..ee6a525 100644
--- a/cs40l26/cl_dsp.c
+++ b/cs40l26/cl_dsp.c
@@ -30,35 +30,45 @@ static inline bool cl_dsp_memchunk_valid_addr(struct cl_dsp_memchunk *ch,
return (u8 *)addr <= ch->max;
}
-int cl_dsp_memchunk_read(struct cl_dsp_memchunk *ch, int nbits)
+int cl_dsp_memchunk_read(struct cl_dsp *dsp, struct cl_dsp_memchunk *ch,
+ int nbits, void *val)
{
- int nread, i;
- u32 result;
+ int nbytes = nbits / 8, nread, i;
+ u32 result = 0;
- if (!ch->cachebits) {
- if (cl_dsp_memchunk_end(ch))
- return -ENOSPC;
+ if (nbits > 32) {
+ dev_err(dsp->dev, "Exceeded maximum read length: %d > 32\n", nbits);
+ return -EINVAL;
+ }
- ch->cache = 0;
- ch->cachebits = 24;
+ while (nbits) {
+ if (!ch->cachebits) {
+ if (cl_dsp_memchunk_end(ch)) {
+ dev_err(dsp->dev, "Read past end of memory chunk\n");
+ return -ENOSPC;
+ }
- for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= 8)
- ch->cache |= *ch->data++;
+ ch->cache = 0;
+ ch->cachebits = 24;
- ch->bytes += sizeof(ch->cache);
- }
+ for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= 8)
+ ch->cache |= *ch->data++;
- nread = min(ch->cachebits, nbits);
- nbits -= nread;
+ ch->bytes += sizeof(ch->cache);
+ }
- result = ch->cache >> (32 - nread);
- ch->cache <<= nread;
- ch->cachebits -= nread;
+ nread = min(ch->cachebits, nbits);
+ nbits -= nread;
- if (nbits)
- result = (result << nbits) | cl_dsp_memchunk_read(ch, nbits);
+ result |= ((ch->cache >> (32 - nread)) << nbits);
+ ch->cache <<= nread;
+ ch->cachebits -= nread;
+ }
+
+ if (val)
+ memcpy(val, &result, nbytes);
- return result;
+ return 0;
}
EXPORT_SYMBOL(cl_dsp_memchunk_read);
@@ -241,11 +251,16 @@ static int cl_dsp_read_wt(struct cl_dsp *dsp, int pos, int size)
void *buf = (void *)(dsp->wt_desc->owt.raw_data + pos);
struct cl_dsp_memchunk ch = cl_dsp_memchunk_create(buf, size);
u32 *wbuf = buf, *max = buf;
- int i;
+ int i, ret;
for (i = 0; i < ARRAY_SIZE(dsp->wt_desc->owt.waves); i++, entry++) {
- entry->flags = cl_dsp_memchunk_read(&ch, 16);
- entry->type = cl_dsp_memchunk_read(&ch, 8);
+ ret = cl_dsp_memchunk_read(dsp, &ch, 16, &entry->flags);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(dsp, &ch, 8, &entry->type);
+ if (ret)
+ return ret;
if (entry->type == WT_TYPE_TERMINATOR) {
dsp->wt_desc->owt.nwaves = i;
@@ -255,8 +270,14 @@ static int cl_dsp_read_wt(struct cl_dsp *dsp, int pos, int size)
return dsp->wt_desc->owt.bytes;
}
- entry->offset = cl_dsp_memchunk_read(&ch, 24);
- entry->size = cl_dsp_memchunk_read(&ch, 24);
+ ret = cl_dsp_memchunk_read(dsp, &ch, 24, &entry->offset);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(dsp, &ch, 24, &entry->size);
+ if (ret)
+ return ret;
+
entry->data = wbuf + entry->offset;
if (wbuf + entry->offset + entry->size > max) {
@@ -331,6 +352,56 @@ static void cl_dsp_coeff_handle_info_text(struct cl_dsp *dsp, const u8 *data,
kfree(info_str);
}
+static int cl_dsp_wavetable_check(struct cl_dsp *dsp, const struct firmware *fw,
+ unsigned int reg, unsigned int pos, u32 data_len, u32 type)
+{
+ u32 data_len_bytes = data_len / 4 * 3;
+ unsigned int limit, wt_reg;
+ bool is_xm;
+ int ret;
+
+ if (type == CL_DSP_XM_UNPACKED_TYPE) {
+ is_xm = true;
+ limit = dsp->wt_desc->wt_limit_xm;
+ ret = cl_dsp_get_reg(dsp, dsp->wt_desc->wt_name_xm,
+ type, dsp->wt_desc->id, &wt_reg);
+ } else if (type == CL_DSP_YM_UNPACKED_TYPE) {
+ is_xm = false;
+ limit = dsp->wt_desc->wt_limit_ym;
+ ret = cl_dsp_get_reg(dsp, dsp->wt_desc->wt_name_ym,
+ type, dsp->wt_desc->id, &wt_reg);
+ } else {
+ dev_err(dsp->dev, "Invalid wavetable memory type 0x%04X\n",
+ type);
+ ret = -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ if (reg == wt_reg) {
+ if (data_len > limit) {
+ dev_err(dsp->dev, "%s too large: %d bytes\n",
+ is_xm ? "XM" : "YM", data_len_bytes);
+ return -EFBIG;
+ }
+
+ ret = cl_dsp_owt_init(dsp, fw);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_read_wt(dsp, pos, data_len);
+ if (ret < 0)
+ return ret;
+
+ dsp->wt_desc->is_xm = is_xm;
+
+ dev_info(dsp->dev, "Wavetable found: %d bytes (XM)\n",
+ data_len_bytes);
+ }
+
+ return 0;
+}
+
int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
{
unsigned int pos = CL_DSP_COEFF_FILE_HEADER_SIZE;
@@ -339,9 +410,10 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
struct cl_dsp_coeff_data_block data_block;
union cl_dsp_wmdr_header wmdr_header;
char wt_date[CL_DSP_WMDR_DATE_LEN];
- unsigned int reg, wt_reg, algo_rev;
+ unsigned int reg, algo_rev;
u16 algo_id, parent_id;
struct device *dev;
+ u32 data_len;
int i;
if (!dsp)
@@ -367,13 +439,12 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
CL_DSP_COEFF_DBLK_HEADER_SIZE);
pos += CL_DSP_COEFF_DBLK_HEADER_SIZE;
- data_block.payload = kmalloc(data_block.header.data_len,
- GFP_KERNEL);
+ data_len = data_block.header.data_len;
+ data_block.payload = kmalloc(data_len, GFP_KERNEL);
if (!data_block.payload)
return -ENOMEM;
- memcpy(data_block.payload, &fw->data[pos],
- data_block.header.data_len);
+ memcpy(data_block.payload, &fw->data[pos], data_len);
algo_id = data_block.header.algo_id & 0xFFFF;
@@ -417,9 +488,9 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
reg = 0;
cl_dsp_coeff_handle_info_text(dsp, data_block.payload,
- data_block.header.data_len);
+ data_len);
- if (data_block.header.data_len < CL_DSP_WMDR_DATE_LEN)
+ if (data_len < CL_DSP_WMDR_DATE_LEN)
break;
if (memcmp(&fw->data[pos], CL_DSP_WMDR_DATE_PREFIX,
@@ -441,39 +512,11 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
CL_DSP_BYTES_PER_WORD;
if (wt_found) {
- ret = cl_dsp_get_reg(dsp,
- dsp->wt_desc->wt_name_xm,
- CL_DSP_XM_UNPACKED_TYPE,
- dsp->wt_desc->id, &wt_reg);
+ ret = cl_dsp_wavetable_check(dsp,
+ fw, reg, pos, data_len,
+ CL_DSP_XM_UNPACKED_TYPE);
if (ret)
goto err_free;
-
- if (reg == wt_reg) {
- if (data_block.header.data_len >
- dsp->wt_desc->wt_limit_xm) {
- dev_err(dev,
- "XM too large: %d bytes\n",
- data_block.header.data_len
- / 4 * 3);
-
- ret = -EINVAL;
- goto err_free;
- } else {
- ret = cl_dsp_owt_init(dsp, fw);
- if (ret)
- goto err_free;
-
- ret = cl_dsp_read_wt(dsp, pos,
- data_block.header.data_len);
- if (ret < 0)
- goto err_free;
- dsp->wt_desc->is_xm = true;
- }
-
- dev_info(dev,
- "Wavetable found: %d bytes (XM)\n",
- data_block.header.data_len / 4 * 3);
- }
}
break;
case CL_DSP_XM_PACKED_TYPE:
@@ -489,35 +532,11 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
dsp->algo_info[i].ym_base *
CL_DSP_UNPACKED_NUM_BYTES;
if (wt_found) {
- ret = cl_dsp_get_reg(dsp,
- dsp->wt_desc->wt_name_ym,
- CL_DSP_YM_UNPACKED_TYPE,
- dsp->wt_desc->id, &wt_reg);
+ ret = cl_dsp_wavetable_check(dsp,
+ fw, reg, pos, data_len,
+ CL_DSP_YM_UNPACKED_TYPE);
if (ret)
goto err_free;
-
- if (reg == wt_reg) {
- if (data_block.header.data_len >
- dsp->wt_desc->wt_limit_ym) {
- dev_err(dev,
- "YM too large: %d bytes\n",
- data_block.header.data_len
- / 4 * 3);
-
- ret = -EINVAL;
- goto err_free;
- } else {
- ret = cl_dsp_read_wt(dsp, pos,
- data_block.header.data_len);
- if (ret < 0)
- goto err_free;
- dsp->wt_desc->is_xm = false;
- }
-
- dev_dbg(dev,
- "Wavetable found: %d bytes (YM)\n",
- data_block.header.data_len / 4 * 3);
- }
}
break;
case CL_DSP_YM_PACKED_TYPE:
@@ -535,8 +554,7 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
}
if (reg) {
ret = cl_dsp_raw_write(dsp, reg, &fw->data[pos],
- data_block.header.data_len,
- CL_DSP_MAX_WLEN);
+ data_len, CL_DSP_MAX_WLEN);
if (ret) {
dev_err(dev, "Failed to write coefficients\n");
goto err_free;
@@ -544,7 +562,7 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
}
/* Blocks are word-aligned */
- pos += (data_block.header.data_len + 3) & ~CL_DSP_ALIGN;
+ pos += (data_len + 3) & ~CL_DSP_ALIGN;
kfree(data_block.payload);
}
@@ -1088,9 +1106,9 @@ int cl_dsp_wavetable_create(struct cl_dsp *dsp, unsigned int id,
return -ENOMEM;
wt_desc->id = id;
- memcpy(wt_desc->wt_name_xm, wt_name_xm, CL_DSP_WMDR_NAME_LEN);
- memcpy(wt_desc->wt_name_ym, wt_name_ym, CL_DSP_WMDR_NAME_LEN);
- memcpy(wt_desc->wt_file, wt_file, CL_DSP_WMDR_NAME_LEN);
+ strscpy(wt_desc->wt_name_xm, wt_name_xm, strlen(wt_name_xm) + 1);
+ strscpy(wt_desc->wt_name_ym, wt_name_ym, strlen(wt_name_ym) + 1);
+ strscpy(wt_desc->wt_file, wt_file, strlen(wt_file) + 1);
dsp->wt_desc = wt_desc;
@@ -1104,7 +1122,7 @@ struct cl_dsp *cl_dsp_create(struct device *dev, struct regmap *regmap)
dsp = devm_kzalloc(dev, sizeof(struct cl_dsp), GFP_KERNEL);
if (!dsp)
- return NULL;
+ return ERR_PTR(-ENOMEM);
dsp->dev = dev;
dsp->regmap = regmap;
@@ -1135,3 +1153,4 @@ EXPORT_SYMBOL(cl_dsp_destroy);
MODULE_DESCRIPTION("Cirrus Logic DSP Firmware Driver");
MODULE_AUTHOR("Fred Treven, Cirrus Logic Inc, <fred.treven@cirrus.com>");
MODULE_LICENSE("GPL");
+MODULE_VERSION("3.1.10");
diff --git a/cs40l26/cl_dsp.h b/cs40l26/cl_dsp.h
index eb01682..31169f4 100644
--- a/cs40l26/cl_dsp.h
+++ b/cs40l26/cl_dsp.h
@@ -311,7 +311,8 @@ int cl_dsp_get_reg(struct cl_dsp *dsp, const char *coeff_name,
unsigned int *reg);
struct cl_dsp_memchunk cl_dsp_memchunk_create(void *data, int size);
int cl_dsp_memchunk_write(struct cl_dsp_memchunk *ch, int nbits, u32 val);
-int cl_dsp_memchunk_read(struct cl_dsp_memchunk *ch, int nbits);
+int cl_dsp_memchunk_read(struct cl_dsp *dsp, struct cl_dsp_memchunk *ch,
+ int nbits, void *val);
int cl_dsp_memchunk_flush(struct cl_dsp_memchunk *ch);
int cl_dsp_raw_write(struct cl_dsp *dsp, unsigned int reg,
const void *val, size_t val_len, size_t limit);
diff --git a/cs40l26/cs40l26-codec.c b/cs40l26/cs40l26-codec.c
index d126149..b1c8b6e 100644
--- a/cs40l26/cs40l26-codec.c
+++ b/cs40l26/cs40l26-codec.c
@@ -2,7 +2,7 @@
//
// cs40l26.c -- ALSA SoC Audio driver for Cirrus Logic Haptic Device: CS40L26
//
-// Copyright 2021 Cirrus Logic. Inc.
+// Copyright 2022 Cirrus Logic. Inc.
#include "cs40l26.h"
@@ -167,8 +167,15 @@ static int cs40l26_a2h_ev(struct snd_soc_dapm_widget *w,
ret = cl_dsp_coeff_file_parse(cs40l26->dsp, fw);
release_firmware(fw);
- if (ret)
+ if (ret) {
+ dev_warn(dev,
+ "Failed to load %s, %d. Continuing...",
+ codec->bin_file, ret);
return ret;
+ }
+
+ dev_info(dev, "%s Loaded Successfully\n",
+ codec->bin_file);
codec->tuning_prev = codec->tuning;
@@ -276,11 +283,9 @@ static int cs40l26_i2s_vmon_get(struct snd_kcontrol *kcontrol,
int ret;
u32 val;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = regmap_read(cs40l26->regmap, CS40L26_SPKMON_VMON_DEC_OUT_DATA,
&val);
@@ -299,8 +304,7 @@ static int cs40l26_i2s_vmon_get(struct snd_kcontrol *kcontrol,
CS40L26_VMON_DEC_OUT_DATA_MASK;
pm_err:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -359,31 +363,32 @@ static int cs40l26_svc_for_streaming_data_get(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = regmap_read(regmap, reg, &val);
if (ret) {
dev_err(cs40l26->dev, "Failed to read FLAGS\n");
- return ret;
+ goto pm_err;
}
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
-
if (val & CS40L26_SVC_FOR_STREAMING_MASK)
ucontrol->value.enumerated.item[0] = 1;
else
ucontrol->value.enumerated.item[0] = 0;
+pm_err:
+ cs40l26_pm_exit(dev);
+
return ret;
}
+
static int cs40l26_svc_for_streaming_data_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_codec *codec =
snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_private *cs40l26 = codec->core;
@@ -397,11 +402,11 @@ static int cs40l26_svc_for_streaming_data_put(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
+
+ snd_soc_dapm_mutex_lock(dapm);
ret = regmap_update_bits(regmap, reg,
CS40L26_SVC_FOR_STREAMING_MASK,
@@ -409,8 +414,9 @@ static int cs40l26_svc_for_streaming_data_put(struct snd_kcontrol *kcontrol,
if (ret)
dev_err(cs40l26->dev, "Failed to specify SVC for streaming\n");
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -431,32 +437,32 @@ static int cs40l26_invert_streaming_data_get(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = regmap_read(regmap, reg, &val);
if (ret) {
dev_err(cs40l26->dev, "Failed to read SOURCE_INVERT\n");
- return ret;
+ goto pm_err;
}
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
-
if (val)
ucontrol->value.enumerated.item[0] = 1;
else
ucontrol->value.enumerated.item[0] = 0;
+pm_err:
+ cs40l26_pm_exit(dev);
+
return ret;
}
static int cs40l26_invert_streaming_data_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_codec *codec =
snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_private *cs40l26 = codec->core;
@@ -470,18 +476,19 @@ static int cs40l26_invert_streaming_data_put(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
+
+ snd_soc_dapm_mutex_lock(dapm);
ret = regmap_write(regmap, reg, ucontrol->value.enumerated.item[0]);
if (ret)
dev_err(cs40l26->dev, "Failed to specify invert streaming data\n");
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -540,27 +547,29 @@ static int cs40l26_a2h_volume_get(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = regmap_read(regmap, reg, &val);
- if (ret)
+ if (ret) {
dev_err(dev, "Failed to get VOLUMELEVEL\n");
-
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ goto pm_err;
+ }
ucontrol->value.integer.value[0] = val;
+pm_err:
+ cs40l26_pm_exit(dev);
+
return ret;
}
static int cs40l26_a2h_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_codec *codec =
snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_private *cs40l26 = codec->core;
@@ -574,6 +583,12 @@ static int cs40l26_a2h_volume_put(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
+ return ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
if (ucontrol->value.integer.value[0] > CS40L26_A2H_VOLUME_MAX)
val = CS40L26_A2H_VOLUME_MAX;
else if (ucontrol->value.integer.value[0] < 0)
@@ -581,18 +596,13 @@ static int cs40l26_a2h_volume_put(struct snd_kcontrol *kcontrol,
else
val = ucontrol->value.integer.value[0];
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
- return ret;
- }
-
ret = regmap_write(regmap, reg, val);
if (ret)
dev_err(dev, "Failed to set VOLUMELEVEL\n");
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -638,11 +648,9 @@ static int cs40l26_a2h_delay_get(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = regmap_read(regmap, reg, &val);
if (ret) {
@@ -653,8 +661,7 @@ static int cs40l26_a2h_delay_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = val;
err:
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -662,6 +669,8 @@ err:
static int cs40l26_a2h_delay_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_codec *codec =
snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
struct cs40l26_private *cs40l26 = codec->core;
@@ -675,6 +684,12 @@ static int cs40l26_a2h_delay_put(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
+ return ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
if (ucontrol->value.integer.value[0] > CS40L26_A2H_DELAY_MAX)
val = CS40L26_A2H_DELAY_MAX;
else if (ucontrol->value.integer.value[0] < 0)
@@ -682,18 +697,13 @@ static int cs40l26_a2h_delay_put(struct snd_kcontrol *kcontrol,
else
val = ucontrol->value.integer.value[0];
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
- return ret;
- }
-
ret = regmap_write(regmap, reg, val);
if (ret)
dev_err(dev, "Failed to set LRADELAYSAMPS\n");
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -836,11 +846,9 @@ static int cs40l26_pcm_hw_params(struct snd_pcm_substream *substream,
u8 asp_rx_wl, asp_rx_width, global_fs;
int ret, lrck;
- ret = pm_runtime_get_sync(codec->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(codec->dev, ret);
+ ret = cs40l26_pm_enter(codec->dev);
+ if (ret)
return ret;
- }
lrck = params_rate(params);
switch (lrck) {
@@ -902,8 +910,7 @@ static int cs40l26_pcm_hw_params(struct snd_pcm_substream *substream,
codec->tdm_slot[1]);
err_pm:
- pm_runtime_mark_last_busy(codec->dev);
- pm_runtime_put_autosuspend(codec->dev);
+ cs40l26_pm_exit(codec->dev);
return ret;
}
diff --git a/cs40l26/cs40l26-i2c.c b/cs40l26/cs40l26-i2c.c
index fac18be..971a49c 100644
--- a/cs40l26/cs40l26-i2c.c
+++ b/cs40l26/cs40l26-i2c.c
@@ -2,7 +2,7 @@
//
// cs40l26-i2c.c -- CS40L26 I2C Driver
//
-// Copyright 2021 Cirrus Logic, Inc.
+// Copyright 2022 Cirrus Logic, Inc.
//
// Author: Fred Treven <fred.treven@cirrus.com>
//
diff --git a/cs40l26/cs40l26-spi.c b/cs40l26/cs40l26-spi.c
index 695cab8..7d0f021 100644
--- a/cs40l26/cs40l26-spi.c
+++ b/cs40l26/cs40l26-spi.c
@@ -2,7 +2,7 @@
//
// cs40l26-spi.c -- CS40L26 SPI Driver
//
-// Copyright 2021 Cirrus Logic, Inc.
+// Copyright 2022 Cirrus Logic, Inc.
//
// Author: Fred Treven <fred.treven@cirrus.com>
//
diff --git a/cs40l26/cs40l26-sysfs.c b/cs40l26/cs40l26-sysfs.c
index ce4f711..1f125db 100644
--- a/cs40l26/cs40l26-sysfs.c
+++ b/cs40l26/cs40l26-sysfs.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
//
-// cs40l26-syfs.c -- CS40L26 Boosted Haptic Driver with Integrated DSP and
+// cs40l26-sysfs.c -- CS40L26 Boosted Haptic Driver with Integrated DSP and
// Waveform Memory with Advanced Closed Loop Algorithms and LRA protection
//
-// Copyright 2021 Cirrus Logic, Inc.
+// Copyright 2022 Cirrus Logic, Inc.
//
// Author: Fred Treven <fred.treven@cirrus.com>
//
@@ -20,16 +20,13 @@ static ssize_t dsp_state_show(struct device *dev,
u8 dsp_state;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_dsp_state_get(cs40l26, &dsp_state);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -51,16 +48,13 @@ static ssize_t halo_heartbeat_show(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = regmap_read(cs40l26->regmap, reg, &halo_heartbeat);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -76,16 +70,13 @@ static ssize_t pm_stdby_timeout_ms_show(struct device *dev,
u32 timeout_ms;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_pm_stdby_timeout_ms_get(cs40l26, &timeout_ms);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -104,16 +95,13 @@ static ssize_t pm_stdby_timeout_ms_store(struct device *dev,
if (ret)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_pm_stdby_timeout_ms_set(cs40l26, timeout_ms);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -129,16 +117,13 @@ static ssize_t pm_active_timeout_ms_show(struct device *dev,
u32 timeout_ms;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_pm_active_timeout_ms_get(cs40l26, &timeout_ms);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -157,16 +142,13 @@ static ssize_t pm_active_timeout_ms_store(struct device *dev,
if (ret)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_pm_active_timeout_ms_set(cs40l26, timeout_ms);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -206,6 +188,12 @@ static ssize_t power_on_seq_show(struct device *dev,
base = cs40l26->pseq_base;
+ if (list_empty(&cs40l26->pseq_op_head)) {
+ dev_err(cs40l26->dev, "Power on sequence is empty\n");
+ ret = -EINVAL;
+ goto err_mutex;
+ }
+
list_for_each_entry_reverse(op, &cs40l26->pseq_op_head, list) {
switch (op->operation) {
case CS40L26_PSEQ_OP_WRITE_FULL:
@@ -259,11 +247,9 @@ static ssize_t owt_free_space_show(struct device *dev,
u32 reg, words;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cl_dsp_get_reg(cs40l26->dsp, "OWT_SIZE_XM",
CL_DSP_XM_UNPACKED_TYPE, CS40L26_VIBEGEN_ALGO_ID, &reg);
@@ -279,8 +265,7 @@ static ssize_t owt_free_space_show(struct device *dev,
ret = snprintf(buf, PAGE_SIZE, "%d\n", words * CL_DSP_BYTES_PER_WORD);
err_pm:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -295,11 +280,9 @@ static ssize_t die_temp_show(struct device *dev,
int ret;
u32 val;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = regmap_read(regmap, CS40L26_GLOBAL_ENABLES, &val);
if (ret) {
@@ -326,8 +309,7 @@ static ssize_t die_temp_show(struct device *dev,
ret = snprintf(buf, PAGE_SIZE, "0x%03X\n", die_temp);
err_pm:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -340,11 +322,9 @@ static ssize_t num_waves_show(struct device *dev,
u32 nwaves;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cs40l26_get_num_waves(cs40l26, &nwaves);
if (ret)
@@ -353,8 +333,7 @@ static ssize_t num_waves_show(struct device *dev,
ret = snprintf(buf, PAGE_SIZE, "%u\n", nwaves);
err_pm:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -368,11 +347,9 @@ static ssize_t boost_disable_delay_show(struct device *dev,
u32 reg, boost_disable_delay;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cl_dsp_get_reg(cs40l26->dsp, "BOOST_DISABLE_DELAY",
CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
@@ -386,8 +363,7 @@ static ssize_t boost_disable_delay_show(struct device *dev,
ret = snprintf(buf, PAGE_SIZE, "%d\n", boost_disable_delay);
err_pm:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -408,11 +384,9 @@ static ssize_t boost_disable_delay_store(struct device *dev,
boost_disable_delay > CS40L26_BOOST_DISABLE_DELAY_MAX)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = cl_dsp_get_reg(cs40l26->dsp, "BOOST_DISABLE_DELAY",
CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
@@ -422,8 +396,7 @@ static ssize_t boost_disable_delay_store(struct device *dev,
ret = regmap_write(cs40l26->regmap, reg, boost_disable_delay);
err_pm:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -439,11 +412,9 @@ static ssize_t f0_offset_show(struct device *dev,
unsigned int reg, val;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -462,8 +433,8 @@ static ssize_t f0_offset_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -482,11 +453,9 @@ static ssize_t f0_offset_store(struct device *dev,
if (val > CS40L26_F0_OFFSET_MAX && val < CS40L26_F0_OFFSET_MIN)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -504,8 +473,8 @@ static ssize_t f0_offset_store(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -587,11 +556,9 @@ static ssize_t f0_comp_enable_store(struct device *dev,
if (ret)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -621,8 +588,8 @@ static ssize_t f0_comp_enable_store(struct device *dev,
err_mutex:
cs40l26->comp_enable_pend = false;
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -667,11 +634,10 @@ static ssize_t redc_comp_enable_store(struct device *dev,
if (ret)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
+
mutex_lock(&cs40l26->lock);
cs40l26->comp_enable_pend = true;
@@ -700,8 +666,8 @@ static ssize_t redc_comp_enable_store(struct device *dev,
err_mutex:
cs40l26->comp_enable_pend = false;
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -786,11 +752,10 @@ static ssize_t vpbr_thld_store(struct device *dev,
sysfs_val < CS40L26_VPBR_THLD_MIN)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
+
mutex_lock(&cs40l26->lock);
if (cs40l26->fw_id == CS40L26_FW_CALIB_ID) {
@@ -835,8 +800,8 @@ static ssize_t vpbr_thld_store(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -874,11 +839,9 @@ static ssize_t dbc_enable_show(struct device *dev,
u32 val, reg;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -902,8 +865,7 @@ static ssize_t dbc_enable_show(struct device *dev,
err_pm:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -922,11 +884,9 @@ static ssize_t dbc_enable_store(struct device *dev,
if (val > 1)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -934,8 +894,7 @@ static ssize_t dbc_enable_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return ret ? ret : count;
}
@@ -965,11 +924,9 @@ static ssize_t dbc_env_rel_coef_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -977,8 +934,7 @@ static ssize_t dbc_env_rel_coef_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1008,11 +964,9 @@ static ssize_t dbc_rise_headroom_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1020,8 +974,7 @@ static ssize_t dbc_rise_headroom_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1051,11 +1004,9 @@ static ssize_t dbc_fall_headroom_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1063,8 +1014,7 @@ static ssize_t dbc_fall_headroom_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1094,11 +1044,9 @@ static ssize_t dbc_tx_lvl_thresh_fs_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1106,8 +1054,7 @@ static ssize_t dbc_tx_lvl_thresh_fs_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1137,11 +1084,9 @@ static ssize_t dbc_tx_lvl_hold_off_ms_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1149,8 +1094,7 @@ static ssize_t dbc_tx_lvl_hold_off_ms_store(struct device *dev,
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1180,6 +1124,11 @@ static ssize_t trigger_calibration_store(struct device *dev,
dev_dbg(cs40l26->dev, "%s: %s", __func__, buf);
+ if (!cs40l26->calib_fw) {
+ dev_err(cs40l26->dev, "Must use calibration firmware\n");
+ return -EPERM;
+ }
+
ret = kstrtou32(buf, 16, &calibration_request_payload);
if (ret ||
calibration_request_payload < 1 ||
@@ -1192,12 +1141,10 @@ static ssize_t trigger_calibration_store(struct device *dev,
(calibration_request_payload &
CS40L26_DSP_MBOX_CMD_PAYLOAD_MASK);
- /* pm_runtime_put occurs is irq_handler after diagnostic is finished */
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ /* pm_exit occurs is irq_handler after diagnostic is finished */
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1225,11 +1172,9 @@ static ssize_t f0_measured_show(struct device *dev,
int ret;
u32 reg, f0_measured;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1245,8 +1190,8 @@ static ssize_t f0_measured_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1262,11 +1207,9 @@ static ssize_t q_measured_show(struct device *dev,
int ret;
u32 reg, q_measured;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1282,8 +1225,8 @@ static ssize_t q_measured_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1299,17 +1242,15 @@ static ssize_t redc_measured_show(struct device *dev,
int ret;
u32 reg, redc_measured;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
ret = cl_dsp_get_reg(cs40l26->dsp, "RE_EST_STATUS",
CL_DSP_YM_UNPACKED_TYPE,
- CS40l26_SVC_ALGO_ID, &reg);
+ CS40L26_SVC_ALGO_ID, &reg);
if (ret)
goto err_mutex;
@@ -1319,8 +1260,8 @@ static ssize_t redc_measured_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1336,11 +1277,9 @@ static ssize_t redc_est_show(struct device *dev, struct device_attribute *attr,
int ret;
u32 reg, redc_est;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1356,8 +1295,8 @@ static ssize_t redc_est_show(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1378,11 +1317,9 @@ static ssize_t redc_est_store(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1398,8 +1335,8 @@ static ssize_t redc_est_store(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1415,11 +1352,9 @@ static ssize_t f0_stored_show(struct device *dev,
int ret;
u32 reg, f0_stored;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1435,8 +1370,8 @@ static ssize_t f0_stored_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1460,11 +1395,9 @@ static ssize_t f0_stored_store(struct device *dev,
f0_stored > CS40L26_F0_EST_MAX)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1480,8 +1413,8 @@ static ssize_t f0_stored_store(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1497,11 +1430,9 @@ static ssize_t q_stored_show(struct device *dev, struct device_attribute *attr,
int ret;
u32 reg, q_stored;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1517,8 +1448,8 @@ static ssize_t q_stored_show(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1540,11 +1471,9 @@ static ssize_t q_stored_store(struct device *dev, struct device_attribute *attr,
if (ret || q_stored < CS40L26_Q_EST_MIN || q_stored > CS40L26_Q_EST_MAX)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1560,8 +1489,8 @@ static ssize_t q_stored_store(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1577,11 +1506,9 @@ static ssize_t redc_stored_show(struct device *dev,
int ret;
u32 reg, redc_stored;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1597,8 +1524,8 @@ static ssize_t redc_stored_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1619,11 +1546,9 @@ static ssize_t redc_stored_store(struct device *dev,
if (ret)
return ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1639,8 +1564,8 @@ static ssize_t redc_stored_store(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1656,11 +1581,9 @@ static ssize_t f0_and_q_cal_time_ms_show(struct device *dev,
u32 reg, tone_dur_ms, freq_span_raw, freq_centre;
int ret, freq_span, f0_and_q_cal_time_ms;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1719,8 +1642,8 @@ static ssize_t f0_and_q_cal_time_ms_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1737,11 +1660,9 @@ static ssize_t redc_cal_time_ms_show(struct device *dev,
int ret;
u32 reg, redc_playtime_ms, redc_total_cal_time_ms;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1759,8 +1680,8 @@ static ssize_t redc_cal_time_ms_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -1776,11 +1697,9 @@ static ssize_t logging_en_show(struct device *dev,
u32 reg, enable;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1797,8 +1716,8 @@ static ssize_t logging_en_show(struct device *dev,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -1820,11 +1739,9 @@ static ssize_t logging_en_store(struct device *dev,
if (enable != 0 && enable != 1)
return -EINVAL;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -1845,13 +1762,6 @@ static ssize_t logging_en_store(struct device *dev,
goto exit_mutex;
if (cs40l26->fw_id == CS40L26_FW_ID) {
- if (src_count != CS40L26_LOGGER_SRC_COUNT) {
- dev_err(cdev, "Unexpected source count %u\n",
- src_count);
- ret = -EINVAL;
- goto exit_mutex;
- }
-
ret = regmap_read(regmap, reg, &src);
if (ret) {
dev_err(cdev, "Failed to get Logger Source\n");
@@ -1867,13 +1777,6 @@ static ssize_t logging_en_store(struct device *dev,
goto exit_mutex;
}
} else if (cs40l26->fw_id == CS40L26_FW_CALIB_ID) {
- if (src_count != CS40L26_LOGGER_SRC_COUNT_CALIB) {
- dev_err(cdev, "Unexpected source count %u\n",
- src_count);
- ret = -EINVAL;
- goto exit_mutex;
- }
-
for (i = 0; i < src_count; i++) {
ret = regmap_read(regmap, reg +
(i * CL_DSP_BYTES_PER_WORD), &src);
@@ -1910,9 +1813,8 @@ static ssize_t logging_en_store(struct device *dev,
exit_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+ cs40l26_pm_exit(cdev);
return ret ? ret : count;
}
@@ -1933,17 +1835,14 @@ static ssize_t logging_max_reset_store(struct device *dev,
if (rst != 1)
return -EINVAL;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
cs40l26_ack_write(cs40l26, CS40L26_DSP_VIRTUAL1_MBOX_1,
CS40L26_DSP_MBOX_CMD_LOGGER_MAX_RESET, CS40L26_DSP_MBOX_RESET);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
return count;
}
@@ -1962,7 +1861,10 @@ static ssize_t max_bemf_show(struct device *dev, struct device_attribute *attr,
return -EPERM;
}
- pm_runtime_get_sync(cs40l26->dev);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return ret;
+
mutex_lock(&cs40l26->lock);
ret = cl_dsp_get_reg(cs40l26->dsp, "DATA", CL_DSP_XM_UNPACKED_TYPE,
@@ -1977,8 +1879,8 @@ static ssize_t max_bemf_show(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -2000,7 +1902,10 @@ static ssize_t max_vbst_show(struct device *dev, struct device_attribute *attr,
return -EPERM;
}
- pm_runtime_get_sync(cs40l26->dev);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return ret;
+
mutex_lock(&cs40l26->lock);
ret = cl_dsp_get_reg(cs40l26->dsp, "DATA", CL_DSP_XM_UNPACKED_TYPE,
@@ -2015,8 +1920,8 @@ static ssize_t max_vbst_show(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -2039,7 +1944,10 @@ static ssize_t max_vmon_show(struct device *dev, struct device_attribute *attr,
else
offset = CS40L26_LOGGER_DATA_1_MAX_OFFSET;
- pm_runtime_get_sync(cs40l26->dev);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return ret;
+
mutex_lock(&cs40l26->lock);
ret = cl_dsp_get_reg(cs40l26->dsp, "DATA", CL_DSP_XM_UNPACKED_TYPE,
@@ -2053,8 +1961,8 @@ static ssize_t max_vmon_show(struct device *dev, struct device_attribute *attr,
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -2070,14 +1978,17 @@ static ssize_t svc_le_est_show(struct device *dev,
unsigned int le;
int ret;
- pm_runtime_get_sync(cs40l26->dev);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return ret;
+
mutex_lock(&cs40l26->lock);
ret = cs40l26_svc_le_estimate(cs40l26, &le);
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+
+ cs40l26_pm_exit(cs40l26->dev);
if (ret)
return ret;
@@ -2086,8 +1997,45 @@ static ssize_t svc_le_est_show(struct device *dev,
}
static DEVICE_ATTR_RO(svc_le_est);
+static ssize_t svc_le_stored_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&cs40l26->lock);
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", cs40l26->svc_le_est_stored);
+
+ mutex_unlock(&cs40l26->lock);
+
+ return ret;
+}
+
+static ssize_t svc_le_stored_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ int ret;
+ u32 svc_le_stored;
+
+ ret = kstrtou32(buf, 10, &svc_le_stored);
+ if (ret)
+ return ret;
+
+ mutex_lock(&cs40l26->lock);
+
+ cs40l26->svc_le_est_stored = svc_le_stored;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return count;
+}
+static DEVICE_ATTR_RW(svc_le_stored);
+
static struct attribute *cs40l26_dev_attrs_cal[] = {
&dev_attr_svc_le_est.attr,
+ &dev_attr_svc_le_stored.attr,
&dev_attr_max_vbst.attr,
&dev_attr_max_bemf.attr,
&dev_attr_max_vmon.attr,
diff --git a/cs40l26/cs40l26-tables.c b/cs40l26/cs40l26-tables.c
index c1de6c4..a217f9a 100644
--- a/cs40l26/cs40l26-tables.c
+++ b/cs40l26/cs40l26-tables.c
@@ -3,7 +3,7 @@
// cs40l26-tables.c -- CS40L26 Boosted Haptic Driver with Integrated DSP and
// Waveform Memory with Advanced Closed Loop Algorithms and LRA protection
//
-// Copyright 2021 Cirrus Logic, Inc.
+// Copyright 2022 Cirrus Logic, Inc.
//
// Author: Fred Treven <fred.treven@cirrus.com>
//
diff --git a/cs40l26/cs40l26.c b/cs40l26/cs40l26.c
index 39f5253..d4d4b3f 100644
--- a/cs40l26/cs40l26.c
+++ b/cs40l26/cs40l26.c
@@ -3,7 +3,7 @@
// cs40l26.c -- CS40L26 Boosted Haptic Driver with Integrated DSP and
// Waveform Memory with Advanced Closed Loop Algorithms and LRA protection
//
-// Copyright 2021 Cirrus Logic, Inc.
+// Copyright 2022 Cirrus Logic, Inc.
//
// Author: Fred Treven <fred.treven@cirrus.com>
//
@@ -25,18 +25,6 @@ static inline bool is_buzz(unsigned int index)
index <= CS40L26_BUZZGEN_INDEX_END);
}
-static inline bool is_ram(unsigned int index)
-{
- return (index >= CS40L26_RAM_INDEX_START &&
- index <= CS40L26_RAM_INDEX_END);
-}
-
-static inline bool is_rom(unsigned int index)
-{
- return (index >= CS40L26_ROM_INDEX_START &&
- index <= CS40L26_ROM_INDEX_END);
-}
-
static inline bool section_complete(struct cs40l26_owt_section *s)
{
return s->delay ? true : false;
@@ -212,11 +200,9 @@ int cs40l26_dbc_get(struct cs40l26_private *cs40l26, enum cs40l26_dbc dbc,
unsigned int reg;
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
mutex_lock(&cs40l26->lock);
@@ -232,8 +218,7 @@ int cs40l26_dbc_get(struct cs40l26_private *cs40l26, enum cs40l26_dbc dbc,
err_pm:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -540,7 +525,6 @@ static int cs40l26_dsp_start(struct cs40l26_private *cs40l26)
unsigned int val;
int ret;
-
ret = regmap_read(cs40l26->regmap, CS40L26_A1_DSP_REQ_ACTIVE_REG,
&val);
if (ret) {
@@ -756,8 +740,7 @@ static int cs40l26_handle_mbox_buffer(struct cs40l26_private *cs40l26)
cs40l26->cal_requested &=
~CS40L26_CALIBRATION_CONTROL_REQUEST_F0_AND_Q;
/* for pm_runtime_get see trigger_calibration */
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
} else {
dev_err(dev, "Unexpected mbox msg: %d", val);
return -EINVAL;
@@ -774,8 +757,7 @@ static int cs40l26_handle_mbox_buffer(struct cs40l26_private *cs40l26)
cs40l26->cal_requested &=
~CS40L26_CALIBRATION_CONTROL_REQUEST_REDC;
/* for pm_runtime_get see trigger_calibration */
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
} else {
dev_err(dev, "Unexpected mbox msg: %d", val);
return -EINVAL;
@@ -802,8 +784,6 @@ static int cs40l26_handle_mbox_buffer(struct cs40l26_private *cs40l26)
int cs40l26_asp_start(struct cs40l26_private *cs40l26)
{
- bool ack = false;
- unsigned int val;
int ret;
if (cs40l26->pdata.asp_scale_pct < CS40L26_GAIN_FULL_SCALE)
@@ -819,29 +799,8 @@ int cs40l26_asp_start(struct cs40l26_private *cs40l26)
reinit_completion(&cs40l26->i2s_cont);
- ret = regmap_write(cs40l26->regmap, CS40L26_DSP_VIRTUAL1_MBOX_1,
- CS40L26_DSP_MBOX_CMD_START_I2S);
- if (ret) {
- dev_err(cs40l26->dev, "Failed to start I2S\n");
- return ret;
- }
-
- while (!ack) {
- usleep_range(CS40L26_DSP_TIMEOUT_US_MIN,
- CS40L26_DSP_TIMEOUT_US_MAX);
-
- ret = regmap_read(cs40l26->regmap, CS40L26_DSP_VIRTUAL1_MBOX_1,
- &val);
- if (ret) {
- dev_err(cs40l26->dev, "Failed to read from MBOX_1\n");
- return ret;
- }
-
- if (val == CS40L26_DSP_MBOX_RESET)
- ack = true;
- }
-
- return 0;
+ return cs40l26_ack_write(cs40l26, CS40L26_DSP_VIRTUAL1_MBOX_1,
+ CS40L26_DSP_MBOX_CMD_START_I2S, CS40L26_DSP_MBOX_RESET);
}
EXPORT_SYMBOL(cs40l26_asp_start);
@@ -854,18 +813,20 @@ void cs40l26_vibe_state_update(struct cs40l26_private *cs40l26,
return;
}
+ dev_dbg(cs40l26->dev, "effects_in_flight = %d\n",
+ cs40l26->effects_in_flight);
+
switch (event) {
case CS40L26_VIBE_STATE_EVENT_MBOX_PLAYBACK:
case CS40L26_VIBE_STATE_EVENT_GPIO_TRIGGER:
cs40l26_remove_asp_scaling(cs40l26);
- cs40l26->effects_in_flight++;
+ cs40l26->effects_in_flight = cs40l26->effects_in_flight <= 0 ? 1 :
+ cs40l26->effects_in_flight + 1;
break;
case CS40L26_VIBE_STATE_EVENT_MBOX_COMPLETE:
case CS40L26_VIBE_STATE_EVENT_GPIO_COMPLETE:
- cs40l26->effects_in_flight--;
- if (cs40l26->effects_in_flight < 0)
- dev_err(cs40l26->dev, "effects_in_flight < 0, %d\n",
- cs40l26->effects_in_flight);
+ cs40l26->effects_in_flight = cs40l26->effects_in_flight <= 0 ? 0 :
+ cs40l26->effects_in_flight - 1;
if (cs40l26->effects_in_flight == 0 && cs40l26->asp_enable)
if (cs40l26_asp_start(cs40l26))
return;
@@ -1317,8 +1278,8 @@ static irqreturn_t cs40l26_irq(int irq, void *data)
err:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
+
/* if an error has occurred, all IRQs have not been successfully
* processed; however, IRQ_HANDLED is still returned if at least one
* interrupt request generated by CS40L26 was handled successfully.
@@ -1736,11 +1697,12 @@ static int cs40l26_buzzgen_set(struct cs40l26_private *cs40l26, u16 freq,
static int cs40l26_map_gpi_to_haptic(struct cs40l26_private *cs40l26,
u32 index, u8 bank, struct ff_effect *effect)
{
- int ret;
- bool edge, ev_handler_bank_ram, owt;
- u32 reg, write_val;
u16 button = effect->trigger.button;
u8 gpio = (button & CS40L26_BTN_NUM_MASK) >> CS40L26_BTN_NUM_SHIFT;
+ bool edge, ev_handler_bank_ram, owt, use_timeout;
+ unsigned int fw_rev;
+ u32 reg, write_val;
+ int ret;
edge = (button & CS40L26_BTN_EDGE_MASK) >> CS40L26_BTN_EDGE_SHIFT;
@@ -1774,18 +1736,44 @@ static int cs40l26_map_gpi_to_haptic(struct cs40l26_private *cs40l26,
(ev_handler_bank_ram << CS40L26_BTN_BANK_SHIFT) |
(owt << CS40L26_BTN_OWT_SHIFT);
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
return ret;
- }
ret = regmap_write(cs40l26->regmap, reg, write_val);
- if (ret)
+ if (ret) {
dev_err(cs40l26->dev, "Failed to update event map\n");
+ goto pm_exit;
+ }
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ ret = cl_dsp_fw_rev_get(cs40l26->dsp, &fw_rev);
+ if (ret)
+ goto pm_exit;
+
+ use_timeout = (!cs40l26->calib_fw &&
+ fw_rev >= CS40L26_FW_GPI_TIMEOUT_MIN_REV) ||
+ (cs40l26->calib_fw && fw_rev >=
+ CS40L26_FW_GPI_TIMEOUT_CALIB_MIN_REV);
+
+ if (use_timeout) {
+ ret = cl_dsp_get_reg(cs40l26->dsp, "TIMEOUT_GPI_MS",
+ CL_DSP_XM_UNPACKED_TYPE,
+ CS40L26_VIBEGEN_ALGO_ID, &reg);
+ if (ret)
+ goto pm_exit;
+
+ ret = regmap_write(cs40l26->regmap, reg, effect->replay.length);
+ if (ret)
+ dev_err(cs40l26->dev, "Failed to set GPI timeout\n");
+ }
+
+ if (edge)
+ cs40l26->gpi_ids[CS40L26_GPIO_MAP_A_PRESS] = effect->id;
+ else
+ cs40l26->gpi_ids[CS40L26_GPIO_MAP_A_RELEASE] = effect->id;
+
+pm_exit:
+ cs40l26_pm_exit(cs40l26->dev);
return ret;
}
@@ -1797,7 +1785,7 @@ static struct cs40l26_owt *cs40l26_owt_find(struct cs40l26_private *cs40l26,
if (list_empty(&cs40l26->owt_head)) {
dev_err(cs40l26->dev, "OWT list is empty\n");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
list_for_each_entry(owt, &cs40l26->owt_head, list) {
@@ -1807,7 +1795,7 @@ static struct cs40l26_owt *cs40l26_owt_find(struct cs40l26_private *cs40l26,
if (owt->effect_id != id) {
dev_err(cs40l26->dev, "OWT effect with ID %d not found\n", id);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
return owt;
@@ -1821,9 +1809,9 @@ static void cs40l26_set_gain_worker(struct work_struct *work)
u32 reg;
int ret;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0)
- return cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return;
mutex_lock(&cs40l26->lock);
@@ -1851,8 +1839,7 @@ static void cs40l26_set_gain_worker(struct work_struct *work)
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
}
static void cs40l26_vibe_start_worker(struct work_struct *work)
@@ -1870,9 +1857,9 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
dev_dbg(dev, "%s\n", __func__);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- return cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
+ return;
mutex_lock(&cs40l26->lock);
@@ -1884,8 +1871,8 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
if (is_owt(index)) {
owt = cs40l26_owt_find(cs40l26, effect->id);
- if (owt == NULL) {
- ret = -ENOMEM;
+ if (IS_ERR(owt)) {
+ ret = PTR_ERR(owt);
goto err_mutex;
}
}
@@ -1948,8 +1935,8 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
reinit_completion(&cs40l26->erase_cont);
err_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+
+ cs40l26_pm_exit(dev);
}
static void cs40l26_vibe_stop_worker(struct work_struct *work)
@@ -1960,9 +1947,9 @@ static void cs40l26_vibe_stop_worker(struct work_struct *work)
dev_dbg(cs40l26->dev, "%s\n", __func__);
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0)
- return cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return;
/* wait for SVC init phase to complete */
if (cs40l26->delay_before_stop_playback_us)
@@ -1971,8 +1958,11 @@ static void cs40l26_vibe_stop_worker(struct work_struct *work)
mutex_lock(&cs40l26->lock);
- if (cs40l26->vibe_state != CS40L26_VIBE_STATE_HAPTIC)
+ if (cs40l26->vibe_state != CS40L26_VIBE_STATE_HAPTIC) {
+ dev_warn(cs40l26->dev, "Attempted stop when vibe_state = %d\n",
+ cs40l26->vibe_state);
goto mutex_exit;
+ }
ret = cs40l26_ack_write(cs40l26, CS40L26_DSP_VIRTUAL1_MBOX_1,
CS40L26_STOP_PLAYBACK, CS40L26_DSP_MBOX_RESET);
@@ -1983,8 +1973,7 @@ static void cs40l26_vibe_stop_worker(struct work_struct *work)
mutex_exit:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
}
static void cs40l26_set_gain(struct input_dev *dev, u16 gain)
@@ -2059,28 +2048,28 @@ EXPORT_SYMBOL(cs40l26_get_num_waves);
static struct cl_dsp_owt_header *cs40l26_header(struct cs40l26_private *cs40l26,
u8 index)
{
- if (!cs40l26->dsp || !cs40l26->dsp->wt_desc)
- return NULL;
-
- if (index >= cs40l26->dsp->wt_desc->owt.nwaves)
- return NULL;
+ if (!cs40l26->dsp || !cs40l26->dsp->wt_desc ||
+ index >= cs40l26->dsp->wt_desc->owt.nwaves)
+ return ERR_PTR(-EINVAL);
return &cs40l26->dsp->wt_desc->owt.waves[index];
-
}
-static int cs40l26_owt_get_wlength(struct cs40l26_private *cs40l26, u8 index)
+static int cs40l26_owt_get_wlength(struct cs40l26_private *cs40l26,
+ u8 index, u32 *wlen_whole)
{
struct device *dev = cs40l26->dev;
struct cl_dsp_owt_header *entry;
struct cl_dsp_memchunk ch;
- if (index == 0)
+ if (index == 0) {
+ *wlen_whole = 0;
return 0;
+ }
entry = cs40l26_header(cs40l26, index);
- if (entry == NULL)
- return -EINVAL;
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
switch (entry->type) {
case WT_TYPE_V6_PCM_F0_REDC:
@@ -2095,7 +2084,7 @@ static int cs40l26_owt_get_wlength(struct cs40l26_private *cs40l26, u8 index)
ch = cl_dsp_memchunk_create(entry->data, sizeof(u32));
/* First 24 bits of each waveform is the length in samples @ 8 kHz */
- return cl_dsp_memchunk_read(&ch, 24);
+ return cl_dsp_memchunk_read(cs40l26->dsp, &ch, 24, wlen_whole);
}
static void cs40l26_owt_set_section_info(struct cs40l26_private *cs40l26,
@@ -2118,35 +2107,63 @@ static void cs40l26_owt_set_section_info(struct cs40l26_private *cs40l26,
}
}
-static void cs40l26_owt_get_section_info(struct cs40l26_private *cs40l26,
+static int cs40l26_owt_get_section_info(struct cs40l26_private *cs40l26,
struct cl_dsp_memchunk *ch,
struct cs40l26_owt_section *sections, u8 nsections)
{
- int i;
+ int ret = 0, i;
for (i = 0; i < nsections; i++) {
- sections[i].amplitude = cl_dsp_memchunk_read(ch, 8);
- sections[i].index = cl_dsp_memchunk_read(ch, 8);
- sections[i].repeat = cl_dsp_memchunk_read(ch, 8);
- sections[i].flags = cl_dsp_memchunk_read(ch, 8);
- sections[i].delay = cl_dsp_memchunk_read(ch, 16);
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 8,
+ &sections[i].amplitude);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 8,
+ &sections[i].index);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 8,
+ &sections[i].repeat);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 8,
+ &sections[i].flags);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 16,
+ &sections[i].delay);
+ if (ret)
+ return ret;
if (sections[i].flags & CS40L26_WT_TYPE10_COMP_DURATION_FLAG) {
- cl_dsp_memchunk_read(ch, 8); /* Skip padding */
- sections[i].duration = cl_dsp_memchunk_read(ch, 16);
+ /* Skip padding */
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 8, NULL);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, ch, 16,
+ &sections[i].duration);
+ if (ret)
+ return ret;
}
}
+
+ return ret;
}
static int cs40l26_owt_calculate_wlength(struct cs40l26_private *cs40l26,
u8 nsections, u8 global_rep, u8 *data, u32 data_size_bytes,
u32 *owt_wlen)
{
- struct cl_dsp_memchunk ch;
- u32 total_len = 0, section_len = 0, loop_len = 0;
+ u32 total_len = 0, section_len = 0, loop_len = 0, wlen_whole = 0;
bool in_loop = false;
+ int ret = 0, i;
struct cs40l26_owt_section *sections;
- int ret = 0, i, wlen_whole;
+ struct cl_dsp_memchunk ch;
u32 dlen, wlen;
if (nsections < 1) {
@@ -2160,16 +2177,19 @@ static int cs40l26_owt_calculate_wlength(struct cs40l26_private *cs40l26,
return -ENOMEM;
ch = cl_dsp_memchunk_create((void *) data, data_size_bytes);
- cs40l26_owt_get_section_info(cs40l26, &ch, sections, nsections);
+ ret = cs40l26_owt_get_section_info(cs40l26, &ch, sections, nsections);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get section info\n");
+ goto err_free;
+ }
for (i = 0; i < nsections; i++) {
- wlen_whole = cs40l26_owt_get_wlength(cs40l26,
- sections[i].index);
- if (wlen_whole < 0) {
+ ret = cs40l26_owt_get_wlength(cs40l26, sections[i].index,
+ &wlen_whole);
+ if (ret < 0) {
dev_err(cs40l26->dev,
"Failed to get wlength for index %u\n",
sections[i].index);
- ret = wlen_whole;
goto err_free;
}
@@ -2248,11 +2268,9 @@ static int cs40l26_owt_upload(struct cs40l26_private *cs40l26, u8 *data,
unsigned int write_reg, reg, wt_offset, wt_size_words, wt_base;
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = cl_dsp_get_reg(dsp, "OWT_NEXT_XM", CL_DSP_XM_UNPACKED_TYPE,
CS40L26_VIBEGEN_ALGO_ID, &reg);
@@ -2305,8 +2323,7 @@ static int cs40l26_owt_upload(struct cs40l26_private *cs40l26, u8 *data,
data_size_bytes, write_reg);
err_pm:
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -2318,21 +2335,26 @@ static u8 *cs40l26_ncw_amp_scaling(struct cs40l26_private *cs40l26, u8 amp,
struct cl_dsp_memchunk in_ch, out_ch;
u16 amp_product;
u8 *out_data;
- int i;
+ int i, ret;
if (nsections <= 0) {
dev_err(cs40l26->dev, "Too few sections for NCW\n");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
sections = kcalloc(nsections, sizeof(struct cs40l26_owt_section),
GFP_KERNEL);
if (!sections)
- return NULL;
+ return ERR_PTR(-ENOMEM);
in_ch = cl_dsp_memchunk_create(in_data, data_bytes);
- cs40l26_owt_get_section_info(cs40l26, &in_ch, sections, nsections);
+ ret = cs40l26_owt_get_section_info(cs40l26, &in_ch, sections,
+ nsections);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get section info\n");
+ return ERR_PTR(ret);
+ }
for (i = 0; i < nsections; i++) {
if (sections[i].index != 0) {
@@ -2343,16 +2365,14 @@ static u8 *cs40l26_ncw_amp_scaling(struct cs40l26_private *cs40l26, u8 amp,
}
out_data = kcalloc(data_bytes, sizeof(u8), GFP_KERNEL);
- if (!out_data)
- goto sections_free;
+ if (!out_data) {
+ kfree(sections);
+ return ERR_PTR(-ENOMEM);
+ }
out_ch = cl_dsp_memchunk_create((void *) out_data, data_bytes);
cs40l26_owt_set_section_info(cs40l26, &out_ch, sections, nsections);
-
-sections_free:
- kfree(sections);
-
return out_data;
}
@@ -2369,8 +2389,8 @@ static int cs40l26_owt_comp_data_size(struct cs40l26_private *cs40l26,
}
header = cs40l26_header(cs40l26, sections[i].index);
- if (header == NULL)
- return -ENOMEM;
+ if (IS_ERR(header))
+ return PTR_ERR(header);
if (header->type == WT_TYPE_V6_COMPOSITE) {
size += (header->size - 2) * 4;
@@ -2388,7 +2408,8 @@ static int cs40l26_owt_comp_data_size(struct cs40l26_private *cs40l26,
}
static int cs40l26_refactor_owt(struct cs40l26_private *cs40l26, s16 *in_data,
- u32 in_data_nibbles, bool pwle, bool svc_waveform, u8 **out_data)
+ u32 in_data_nibbles, bool pwle, bool svc_waveform,
+ u8 **out_data)
{
u8 nsections, global_rep, out_nsections = 0;
int ret = 0, pos_byte = 0, in_pos_nib = 2;
@@ -2416,12 +2437,15 @@ static int cs40l26_refactor_owt(struct cs40l26_private *cs40l26, s16 *in_data,
out_data_bytes);
cl_dsp_memchunk_write(&out_ch, 16,
CS40L26_WT_HEADER_DEFAULT_FLAGS |
- (svc_waveform ? CS40L26_OWT_SVC_METADATA : 0));
+ (svc_waveform ?
+ CS40L26_OWT_SVC_METADATA : 0));
cl_dsp_memchunk_write(&out_ch, 8, WT_TYPE_V6_PWLE);
cl_dsp_memchunk_write(&out_ch, 24, CS40L26_WT_HEADER_OFFSET +
- (svc_waveform ? CS40L26_WT_METADATA_OFFSET : 0));
+ (svc_waveform ?
+ CS40L26_WT_METADATA_OFFSET : 0));
cl_dsp_memchunk_write(&out_ch, 24, (in_data_bytes / 4) -
- (svc_waveform ? CS40L26_WT_METADATA_OFFSET : 0));
+ (svc_waveform ?
+ CS40L26_WT_METADATA_OFFSET : 0));
memcpy(*out_data + out_ch.bytes, in_data, in_data_bytes);
@@ -2430,21 +2454,29 @@ 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 */
- ret = cl_dsp_memchunk_read(&ch, 8);
- if (ret < 0)
+ /* Skip padding */
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8, NULL);
+ if (ret)
return ret;
- nsections = ret;
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8, &nsections);
+ if (ret)
+ return ret;
- global_rep = cl_dsp_memchunk_read(&ch, 8);
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8, &global_rep);
+ if (ret)
+ return ret;
sections = kcalloc(nsections, sizeof(struct cs40l26_owt_section),
GFP_KERNEL);
if (!sections)
return -ENOMEM;
- cs40l26_owt_get_section_info(cs40l26, &ch, sections, nsections);
+ ret = cs40l26_owt_get_section_info(cs40l26, &ch, sections, nsections);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get section info\n");
+ return ret;
+ }
data_bytes = cs40l26_owt_comp_data_size(cs40l26, nsections,
sections);
@@ -2484,18 +2516,33 @@ static int cs40l26_refactor_owt(struct cs40l26_private *cs40l26, s16 *in_data,
}
header = cs40l26_header(cs40l26, sections[i].index);
- if (header == NULL) {
- ret = -ENOMEM;
+ if (IS_ERR(header)) {
+ ret = PTR_ERR(header);
goto data_err_free;
}
if (header->type == WT_TYPE_V6_COMPOSITE) {
ch = cl_dsp_memchunk_create(header->data, 8);
- cl_dsp_memchunk_read(&ch, 24); /* Skip Wlength */
- cl_dsp_memchunk_read(&ch, 8); /* Skip Padding */
- ncw_nsections = cl_dsp_memchunk_read(&ch, 8);
+ /* Skip Wlength */
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 24, NULL);
+ if (ret)
+ return ret;
+
+ /* Skip Padding */
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8, NULL);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8,
+ &ncw_nsections);
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_memchunk_read(cs40l26->dsp, &ch, 8,
+ &ncw_global_rep);
+ if (ret)
+ return ret;
- ncw_global_rep = cl_dsp_memchunk_read(&ch, 8);
if (ncw_global_rep != 0) {
dev_err(dev,
"No NCW support for outer repeat\n");
@@ -2509,8 +2556,8 @@ static int cs40l26_refactor_owt(struct cs40l26_private *cs40l26, s16 *in_data,
ncw_data = cs40l26_ncw_amp_scaling(cs40l26,
sections[i].amplitude, ncw_nsections,
header->data + 8, ncw_bytes);
- if (ncw_data == NULL) {
- ret = -ENOMEM;
+ if (IS_ERR(ncw_data)) {
+ ret = PTR_ERR(ncw_data);
goto data_err_free;
}
@@ -2678,9 +2725,9 @@ static void cs40l26_upload_worker(struct work_struct *work)
u16 index, bank;
bool pwle, svc_waveform;
- ret = pm_runtime_get_sync(cdev);
- if (ret < 0)
- return cs40l26_resume_error_handle(cdev, ret);
+ ret = cs40l26_pm_enter(cdev);
+ if (ret)
+ return;
mutex_lock(&cs40l26->lock);
@@ -2692,6 +2739,12 @@ static void cs40l26_upload_worker(struct work_struct *work)
goto out_mutex;
}
+ if (is_owt(cs40l26->trigger_indices[effect->id])) {
+ dev_err(cdev, "Open Wavetable effects cannot be edited\n");
+ ret = -EPERM;
+ goto out_mutex;
+ }
+
switch (effect->u.periodic.waveform) {
case FF_CUSTOM:
pwle = (cs40l26->raw_custom_data[0] ==
@@ -2703,8 +2756,9 @@ static void cs40l26_upload_worker(struct work_struct *work)
if (len > CS40L26_CUSTOM_DATA_SIZE) {
refactored_size = cs40l26_refactor_owt(cs40l26,
- cs40l26->raw_custom_data, len, pwle, svc_waveform,
- &refactored_data);
+ cs40l26->raw_custom_data, len,
+ pwle, svc_waveform,
+ &refactored_data);
if (refactored_size <= 0) {
dev_err(cdev,
@@ -2810,8 +2864,8 @@ out_free:
out_mutex:
mutex_unlock(&cs40l26->lock);
- pm_runtime_mark_last_busy(cdev);
- pm_runtime_put_autosuspend(cdev);
+
+ cs40l26_pm_exit(cdev);
cs40l26->upload_ret = ret;
}
@@ -2856,6 +2910,7 @@ static int cs40l26_upload_effect(struct input_dev *dev,
out_free:
memset(&cs40l26->upload_effect, 0, sizeof(struct ff_effect));
kfree(cs40l26->raw_custom_data);
+ cs40l26->raw_custom_data = NULL;
return ret;
}
@@ -2869,51 +2924,44 @@ const struct attribute_group *cs40l26_dev_attr_groups[] = {
};
#endif
-static int cs40l26_clear_gpi_event_reg(struct cs40l26_private *cs40l26, u32 reg)
+static enum cs40l26_gpio_map cs40l26_map_get(struct cs40l26_private *cs40l26,
+ int effect_id)
{
- struct regmap *regmap = cs40l26->regmap;
- int ret;
+ if (cs40l26->gpi_ids[CS40L26_GPIO_MAP_A_PRESS] == effect_id)
+ return CS40L26_GPIO_MAP_A_PRESS;
+ else if (cs40l26->gpi_ids[CS40L26_GPIO_MAP_A_RELEASE] == effect_id)
+ return CS40L26_GPIO_MAP_A_RELEASE;
- ret = regmap_write(regmap, reg, CS40L26_EVENT_MAP_GPI_EVENT_DISABLE);
- if (ret)
- dev_err(cs40l26->dev, "Failed to clear gpi reg: %08X", reg);
-
- return ret;
+ return CS40L26_GPIO_MAP_INVALID;
}
static int cs40l26_erase_gpi_mapping(struct cs40l26_private *cs40l26,
- int effect_id)
+ enum cs40l26_gpio_map mapping)
{
- struct device *dev = cs40l26->dev;
- u32 index = cs40l26->trigger_indices[effect_id];
- u8 trigger_index, gpi_index;
- u32 reg, val;
- int i, ret;
+ int ret = 0;
+ u32 reg;
- trigger_index = index & 0xFF;
+ if (mapping == CS40L26_GPIO_MAP_A_PRESS)
+ reg = CS40L26_A1_EVENT_MAP_1;
+ else if (mapping == CS40L26_GPIO_MAP_A_RELEASE)
+ reg = CS40L26_A1_EVENT_MAP_2;
+ else
+ ret = -EINVAL;
- for (i = 0; i < CS40L26_EVENT_MAP_NUM_GPI_REGS; i++) {
- reg = cs40l26->event_map_base + (i * 4);
- ret = regmap_read(cs40l26->regmap, reg, &val);
- if (ret) {
- dev_err(dev, "Failed to read gpi event reg: 0x%08X",
- reg);
- return ret;
- }
- gpi_index = val & 0xFF;
-
- if (is_buzz(index) ||
- (is_owt(index) && val & CS40L26_BTN_OWT_MASK) ||
- (is_ram(index) && val & CS40L26_BTN_BANK_MASK) ||
- (is_rom(index) && ~val & CS40L26_BTN_BANK_MASK)) {
- if (trigger_index == gpi_index) {
- ret = cs40l26_clear_gpi_event_reg(cs40l26, reg);
- if (ret)
- return ret;
- }
- }
+ if (ret) {
+ dev_err(cs40l26->dev, "Invalid GPI mapping %u\n", mapping);
+ return ret;
+ }
+
+ ret = regmap_write(cs40l26->regmap, reg, CS40L26_EVENT_MAP_GPI_DISABLE);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to clear GPI mapping %u\n",
+ mapping);
+ return ret;
}
+ cs40l26->gpi_ids[mapping] = -1;
+
return 0;
}
@@ -2932,8 +2980,8 @@ static int cs40l26_erase_owt(struct cs40l26_private *cs40l26, int effect_id)
int ret;
owt = cs40l26_owt_find(cs40l26, effect_id);
- if (owt == NULL)
- return -ENOMEM;
+ if (IS_ERR(owt))
+ return PTR_ERR(owt);
cmd |= (owt->trigger_index & 0xFF);
@@ -2951,6 +2999,8 @@ static int cs40l26_erase_owt(struct cs40l26_private *cs40l26, int effect_id)
}
}
+ cs40l26->trigger_indices[effect_id] = 0;
+
list_del(&owt->list);
kfree(owt);
cs40l26->num_owt_effects--;
@@ -2958,19 +3008,19 @@ static int cs40l26_erase_owt(struct cs40l26_private *cs40l26, int effect_id)
return 0;
}
-
static void cs40l26_erase_worker(struct work_struct *work)
{
struct cs40l26_private *cs40l26 = container_of(work,
struct cs40l26_private, erase_work);
int ret = 0;
+ enum cs40l26_gpio_map mapping;
int effect_id;
u16 duration;
u32 index;
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0)
- return cs40l26_resume_error_handle(cs40l26->dev, ret);
+ ret = cs40l26_pm_enter(cs40l26->dev);
+ if (ret)
+ return;
mutex_lock(&cs40l26->lock);
@@ -2987,7 +3037,8 @@ static void cs40l26_erase_worker(struct work_struct *work)
if (!wait_for_completion_timeout(&cs40l26->erase_cont,
msecs_to_jiffies(duration))) {
ret = -ETIME;
- dev_err(cs40l26->dev, "Failed to erase effect: %d", ret);
+ dev_err(cs40l26->dev, "Failed to erase effect: %d",
+ ret);
goto pm_err;
}
mutex_lock(&cs40l26->lock);
@@ -2995,31 +3046,25 @@ static void cs40l26_erase_worker(struct work_struct *work)
dev_dbg(cs40l26->dev, "%s: effect ID = %d\n", __func__, effect_id);
- if (is_owt(index)) {
- ret = cs40l26_erase_owt(cs40l26, effect_id);
+ mapping = cs40l26_map_get(cs40l26, effect_id);
+ if (mapping != CS40L26_GPIO_MAP_INVALID) {
+ ret = cs40l26_erase_gpi_mapping(cs40l26, mapping);
if (ret)
- dev_err(cs40l26->dev, "Failed to erase OWT effect: %d",
- ret);
- goto out_mutex;
+ goto out_mutex;
}
- if (is_buzz(index)) {
+ if (is_owt(index))
+ ret = cs40l26_erase_owt(cs40l26, effect_id);
+ else if (is_buzz(index))
ret = cs40l26_erase_buzz(cs40l26, effect_id);
- if (ret)
- dev_err(cs40l26->dev, "Failed to erase buzz effect: %d",
- ret);
- goto out_mutex;
- }
- ret = cs40l26_erase_gpi_mapping(cs40l26, effect_id);
if (ret)
- dev_err(cs40l26->dev, "Failed to erase gpi mapping: %d", ret);
+ dev_err(cs40l26->dev, "Failed to erase effect: %d", ret);
out_mutex:
mutex_unlock(&cs40l26->lock);
pm_err:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
+ cs40l26_pm_exit(cs40l26->dev);
cs40l26->erase_ret = ret;
}
@@ -3793,13 +3838,6 @@ static int cs40l26_handle_errata(struct cs40l26_private *cs40l26)
num_writes = CS40L26_ERRATA_A1_EXPL_EN_NUM_WRITES;
}
- ret = regmap_register_patch(cs40l26->regmap, cs40l26_a1_errata,
- num_writes);
- if (ret) {
- dev_err(cs40l26->dev, "Failed to patch A1 errata\n");
- return ret;
- }
-
return cs40l26_pseq_multi_write(cs40l26, cs40l26_a1_errata, num_writes,
false, CS40L26_PSEQ_OP_WRITE_FULL);
}
@@ -3963,11 +4001,9 @@ static int cs40l26_dsp_config(struct cs40l26_private *cs40l26)
if (ret)
return ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(dev, ret);
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
return ret;
- }
ret = cl_dsp_get_reg(cs40l26->dsp, "TIMEOUT_MS",
CL_DSP_XM_UNPACKED_TYPE, CS40L26_VIBEGEN_ALGO_ID, &reg);
@@ -4011,8 +4047,7 @@ static int cs40l26_dsp_config(struct cs40l26_private *cs40l26)
}
pm_err:
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
return ret;
}
@@ -4051,7 +4086,8 @@ int cs40l26_svc_le_estimate(struct cs40l26_private *cs40l26, unsigned int *le)
return ret;
ret = cl_dsp_get_reg(cs40l26->dsp, "LE_EST_STATUS",
- CL_DSP_YM_UNPACKED_TYPE, CS40l26_SVC_ALGO_ID, &reg);
+ CL_DSP_YM_UNPACKED_TYPE, CS40L26_SVC_ALGO_ID,
+ &reg);
if (ret)
return ret;
@@ -4077,20 +4113,10 @@ int cs40l26_svc_le_estimate(struct cs40l26_private *cs40l26, unsigned int *le)
EXPORT_SYMBOL(cs40l26_svc_le_estimate);
static int cs40l26_tuning_select_from_svc_le(struct cs40l26_private *cs40l26,
- u32 *tuning_num)
+ unsigned int le, u32 *tuning_num)
{
- unsigned int le;
- int ret, i;
-
- ret = pm_runtime_get_sync(cs40l26->dev);
- if (ret < 0) {
- cs40l26_resume_error_handle(cs40l26->dev, ret);
- return ret;
- }
-
- ret = cs40l26_svc_le_estimate(cs40l26, &le);
- if (ret)
- goto pm_err;
+ int ret = 0;
+ int i;
if (le) {
for (i = 0; i < cs40l26->num_svc_le_vals; i++) {
@@ -4108,10 +4134,6 @@ static int cs40l26_tuning_select_from_svc_le(struct cs40l26_private *cs40l26,
if (!le || i == cs40l26->num_svc_le_vals)
dev_warn(cs40l26->dev, "Using default tunings\n");
-pm_err:
- pm_runtime_mark_last_busy(cs40l26->dev);
- pm_runtime_put_autosuspend(cs40l26->dev);
-
return ret;
}
@@ -4125,7 +4147,7 @@ static char **cs40l26_get_tuning_names(struct cs40l26_private *cs40l26, int n,
coeff_files = kcalloc(n, sizeof(char *), GFP_KERNEL);
if (!coeff_files)
- return NULL;
+ return ERR_PTR(-ENOMEM);
for (i = 0; i < n; i++) {
coeff_files[i] =
@@ -4157,16 +4179,15 @@ static char **cs40l26_get_tuning_names(struct cs40l26_private *cs40l26, int n,
CS40L26_TUNING_FILE_NAME_MAX_LEN);
strscpy(coeff_files[0], wt_tuning, CS40L26_TUNING_FILE_NAME_MAX_LEN);
+ strscpy(coeff_files[1], svc_tuning, CS40L26_TUNING_FILE_NAME_MAX_LEN);
if (cs40l26->fw_id == CS40L26_FW_ID) {
- strscpy(coeff_files[1], CS40L26_A2H_TUNING_FILE_NAME,
- CS40L26_TUNING_FILE_NAME_MAX_LEN);
- strscpy(coeff_files[2], svc_tuning,
+ strscpy(coeff_files[2], CS40L26_A2H_TUNING_FILE_NAME,
CS40L26_TUNING_FILE_NAME_MAX_LEN);
strscpy(coeff_files[3], CS40L26_DVL_FILE_NAME,
CS40L26_TUNING_FILE_NAME_MAX_LEN);
} else {
- strscpy(coeff_files[1], CS40L26_CALIB_BIN_FILE_NAME,
+ strscpy(coeff_files[2], CS40L26_CALIB_BIN_FILE_NAME,
CS40L26_TUNING_FILE_NAME_MAX_LEN);
}
@@ -4174,7 +4195,7 @@ static char **cs40l26_get_tuning_names(struct cs40l26_private *cs40l26, int n,
err_free:
kfree(coeff_files);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
static int cs40l26_coeff_load(struct cs40l26_private *cs40l26, u32 tuning)
@@ -4188,8 +4209,8 @@ static int cs40l26_coeff_load(struct cs40l26_private *cs40l26, u32 tuning)
CS40L26_TUNING_FILES_RUNTIME : CS40L26_TUNING_FILES_CAL;
coeff_files = cs40l26_get_tuning_names(cs40l26, num_files, tuning);
- if (!coeff_files)
- return -ENOMEM;
+ if (IS_ERR(coeff_files))
+ return PTR_ERR(coeff_files);
for (i = 0; i < num_files; i++) {
ret = request_firmware(&coeff, coeff_files[i], dev);
@@ -4306,8 +4327,8 @@ static int cs40l26_cl_dsp_reinit(struct cs40l26_private *cs40l26)
}
cs40l26->dsp = cl_dsp_create(cs40l26->dev, cs40l26->regmap);
- if (!cs40l26->dsp)
- return -ENOMEM;
+ if (IS_ERR(cs40l26->dsp))
+ return PTR_ERR(cs40l26->dsp);
return cl_dsp_wavetable_create(cs40l26->dsp, CS40L26_VIBEGEN_ALGO_ID,
CS40L26_WT_NAME_XM, CS40L26_WT_NAME_YM, CS40L26_WT_FILE_NAME);
@@ -4317,9 +4338,10 @@ static int cs40l26_fw_upload(struct cs40l26_private *cs40l26)
{
bool svc_le_required = cs40l26->num_svc_le_vals && !cs40l26->calib_fw;
struct device *dev = cs40l26->dev;
- u32 tuning_num = 0;
+ u32 rev, branch, tuning_num = 0;
const struct firmware *fw;
int ret;
+ unsigned int le = 0;
cs40l26->fw_loaded = false;
@@ -4355,17 +4377,47 @@ static int cs40l26_fw_upload(struct cs40l26_private *cs40l26)
return ret;
if (svc_le_required) {
- ret = cs40l26_dsp_config(cs40l26);
+ ret = cl_dsp_fw_rev_get(cs40l26->dsp, &rev);
if (ret)
return ret;
- ret = cs40l26_tuning_select_from_svc_le(cs40l26, &tuning_num);
- if (ret)
- return ret;
+ branch = CL_DSP_GET_MAJOR(rev);
- cs40l26_pm_runtime_teardown(cs40l26);
+ switch (branch) {
+ case CS40L26_FW_MAINT_BRANCH:
+ ret = cs40l26_dsp_config(cs40l26);
+ if (ret)
+ return ret;
+
+ ret = cs40l26_pm_enter(dev);
+ if (ret)
+ return ret;
+
+ ret = cs40l26_svc_le_estimate(cs40l26, &le);
+ if (ret)
+ dev_warn(dev, "svc_le est failed, %d", ret);
+
+ cs40l26_pm_exit(dev);
+
+ cs40l26_pm_runtime_teardown(cs40l26);
- ret = cs40l26_dsp_pre_config(cs40l26);
+ ret = cs40l26_dsp_pre_config(cs40l26);
+ if (ret)
+ return ret;
+
+ break;
+
+ case CS40L26_FW_BRANCH:
+ le = cs40l26->svc_le_est_stored;
+ break;
+
+ default:
+ dev_err(dev, "Invalid firmware branch, %d", branch);
+ return -EINVAL;
+ }
+
+ ret = cs40l26_tuning_select_from_svc_le(cs40l26,
+ le, &tuning_num);
if (ret)
return ret;
}
@@ -4377,35 +4429,30 @@ static int cs40l26_fw_upload(struct cs40l26_private *cs40l26)
return cs40l26_dsp_config(cs40l26);
}
-int cs40l26_fw_swap(struct cs40l26_private *cs40l26, u32 id)
+int cs40l26_fw_swap(struct cs40l26_private *cs40l26, const u32 id)
{
struct device *dev = cs40l26->dev;
- bool deferred = cs40l26->fw_defer;
- u32 pseq_rom_end_of_script_loc;
- int ret;
-
- if (cs40l26->fw_defer) {
- cs40l26->fw_defer = false;
- } else {
- disable_irq(cs40l26->irq);
- cs40l26_pm_runtime_teardown(cs40l26);
- }
+ bool re_enable = false;
+ int ret = 0;
if (cs40l26->revid != CS40L26_REVID_A1 &&
cs40l26->revid != CS40L26_REVID_B0) {
dev_err(dev, "pseq unrecognized revid: %d\n", cs40l26->revid);
- ret = -EINVAL;
- goto defer_err;
+ return -EINVAL;
}
- /* reset pseq END_OF_SCRIPT to location from ROM */
- pseq_rom_end_of_script_loc = CS40L26_PSEQ_ROM_END_OF_SCRIPT;
+ if (cs40l26->fw_loaded) {
+ disable_irq(cs40l26->irq);
+ cs40l26_pm_runtime_teardown(cs40l26);
+ re_enable = true;
+ }
- ret = cs40l26_dsp_write(cs40l26, pseq_rom_end_of_script_loc,
+ /* reset pseq END_OF_SCRIPT to location from ROM */
+ ret = cs40l26_dsp_write(cs40l26, CS40L26_PSEQ_ROM_END_OF_SCRIPT,
CS40L26_PSEQ_OP_END << CS40L26_PSEQ_OP_SHIFT);
if (ret) {
dev_err(dev, "Failed to reset pseq END_OF_SCRIPT %d\n", ret);
- goto defer_err;
+ return ret;
}
if (id == CS40L26_FW_CALIB_ID)
@@ -4415,42 +4462,28 @@ int cs40l26_fw_swap(struct cs40l26_private *cs40l26, u32 id)
ret = cs40l26_fw_upload(cs40l26);
if (ret)
- goto defer_err;
+ return ret;
- if (deferred) {
+ if (cs40l26->fw_defer && cs40l26->fw_loaded) {
ret = devm_request_threaded_irq(dev, cs40l26->irq, NULL,
cs40l26_irq, IRQF_ONESHOT | IRQF_SHARED |
IRQF_TRIGGER_LOW, "cs40l26", cs40l26);
if (ret) {
dev_err(dev, "Failed to request threaded IRQ: %d\n",
ret);
- goto defer_err;
+ return ret;
}
- } else {
- enable_irq(cs40l26->irq);
- }
- return 0;
+ cs40l26->fw_defer = false;
+ }
-defer_err:
- if (deferred)
- cs40l26->fw_defer = true;
+ if (re_enable)
+ enable_irq(cs40l26->irq);
return ret;
}
EXPORT_SYMBOL(cs40l26_fw_swap);
-static int cs40l26_update_reg_defaults(struct cs40l26_private *cs40l26)
-{
- int ret;
-
- ret = regmap_update_bits(cs40l26->regmap, CS40L26_TST_DAC_MSM_CONFIG,
- CS40L26_SPK_DEFAULT_HIZ_MASK, 1 <<
- CS40L26_SPK_DEFAULT_HIZ_SHIFT);
-
- return ret;
-}
-
static int cs40l26_handle_svc_le_nodes(struct cs40l26_private *cs40l26)
{
struct device *dev = cs40l26->dev;
@@ -4669,7 +4702,7 @@ static int cs40l26_handle_platform_data(struct cs40l26_private *cs40l26)
}
if (!of_property_read_u32(np, "cirrus,boost-ctl-microvolt", &val))
- cs40l26->pdata.boost_ctl = val | CS40L26_PDATA_PRESENT;
+ cs40l26->pdata.boost_ctl = val;
else
cs40l26->pdata.boost_ctl = CS40L26_BST_CTL_DEFAULT;
@@ -4801,23 +4834,26 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
ret = cs40l26_set_pll_loop(cs40l26, CS40L26_PLL_REFCLK_SET_OPEN_LOOP);
if (ret)
- return ret;
+ goto err;
- ret = cs40l26_clear_gpi_event_reg(cs40l26, CS40L26_A1_EVENT_MAP_1);
+ ret = cs40l26_erase_gpi_mapping(cs40l26, CS40L26_GPIO_MAP_A_PRESS);
if (ret)
- return ret;
+ goto err;
- ret = cs40l26_clear_gpi_event_reg(cs40l26, CS40L26_A1_EVENT_MAP_2);
+ ret = cs40l26_erase_gpi_mapping(cs40l26, CS40L26_GPIO_MAP_A_RELEASE);
if (ret)
- return ret;
+ goto err;
ret = cs40l26_part_num_resolve(cs40l26);
if (ret)
goto err;
- ret = cs40l26_update_reg_defaults(cs40l26);
+ /* Set LRA to high-z to avoid fault conditions */
+ ret = regmap_update_bits(cs40l26->regmap, CS40L26_TST_DAC_MSM_CONFIG,
+ CS40L26_SPK_DEFAULT_HIZ_MASK, 1 <<
+ CS40L26_SPK_DEFAULT_HIZ_SHIFT);
if (ret) {
- dev_err(dev, "Failed to update reg defaults\n");
+ dev_err(dev, "Failed to set LRA to HI-Z\n");
goto err;
}
@@ -4911,6 +4947,27 @@ int cs40l26_remove(struct cs40l26_private *cs40l26)
}
EXPORT_SYMBOL(cs40l26_remove);
+int cs40l26_pm_enter(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ cs40l26_resume_error_handle(dev, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(cs40l26_pm_enter);
+
+void cs40l26_pm_exit(struct device *dev)
+{
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
+EXPORT_SYMBOL(cs40l26_pm_exit);
+
int cs40l26_suspend(struct device *dev)
{
struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
@@ -4958,8 +5015,7 @@ void cs40l26_resume_error_handle(struct device *dev, int ret)
pm_runtime_set_active(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ cs40l26_pm_exit(dev);
}
EXPORT_SYMBOL(cs40l26_resume_error_handle);
@@ -5008,3 +5064,4 @@ EXPORT_SYMBOL(cs40l26_sys_resume_noirq);
MODULE_DESCRIPTION("CS40L26 Boosted Mono Class D Amplifier for Haptics");
MODULE_AUTHOR("Fred Treven, Cirrus Logic Inc. <fred.treven@cirrus.com>");
MODULE_LICENSE("GPL");
+MODULE_VERSION("5.6.3");
diff --git a/cs40l26/cs40l26.h b/cs40l26/cs40l26.h
index d7be94f..359abe1 100644
--- a/cs40l26/cs40l26.h
+++ b/cs40l26/cs40l26.h
@@ -3,7 +3,7 @@
* cs40l26.h -- CS40L26 Boosted Haptic Driver with Integrated DSP and
* Waveform Memory with Advanced Closed Loop Algorithms and LRA protection
*
- * Copyright 2021 Cirrus Logic, Inc.
+ * Copyright 2022 Cirrus Logic, Inc.
*
* Author: Fred Treven <fred.treven@cirrus.com>
*/
@@ -703,7 +703,7 @@
#define CS40L26_MAILBOX_ALGO_ID 0x0001F203
#define CS40L26_MDSYNC_ALGO_ID 0x0001F20F
#define CS40L26_PM_ALGO_ID 0x0001F206
-#define CS40l26_SVC_ALGO_ID 0x0001F207
+#define CS40L26_SVC_ALGO_ID 0x0001F207
#define CS40L26_VIBEGEN_ALGO_ID 0x000100BD
#define CS40L26_LOGGER_ALGO_ID 0x0004013D
#define CS40L26_EXT_ALGO_ID 0x0004013C
@@ -780,7 +780,11 @@
/* DSP mailbox controls */
#define CS40L26_DSP_TIMEOUT_US_MIN 1000
#define CS40L26_DSP_TIMEOUT_US_MAX 1100
+#if IS_ENABLED(CONFIG_GOOG_CUST)
+#define CS40L26_DSP_TIMEOUT_COUNT 3
+#else
#define CS40L26_DSP_TIMEOUT_COUNT 100
+#endif
#define CS40L26_DSP_MBOX_RESET 0x0
@@ -833,7 +837,7 @@
#define CS40L26_FW_CALIB_NAME "cs40l26-calib.wmfw"
#define CS40L26_TUNING_FILES_RUNTIME 4
-#define CS40L26_TUNING_FILES_CAL 2
+#define CS40L26_TUNING_FILES_CAL 3
#define CS40L26_WT_FILE_NAME "cs40l26.bin"
#define CS40L26_WT_FILE_PREFIX "cs40l26-wt"
@@ -852,17 +856,19 @@
#define CS40L26_SVC_LE_MAX_ATTEMPTS 2
#define CS40L26_SVC_DT_PREFIX "svc-le"
-#define CS40L26_FW_ID 0x1800D4
-#define CS40L26_FW_MIN_REV 0x07021C
-#define CS40L26_FW_BRANCH 0x07
-#define CS40L26_FW_CALIB_ID 0x1800DA
-#define CS40L26_FW_CALIB_MIN_REV 0x010014
-#define CS40L26_FW_CALIB_BRANCH 0x01
-#define CS40L26_FW_MAINT_MIN_REV 0x270216
-#define CS40L26_FW_MAINT_BRANCH 0x27
-#define CS40L26_FW_MAINT_CALIB_MIN_REV 0x21010D
-#define CS40L26_FW_MAINT_CALIB_BRANCH 0x21
-#define CS40L26_FW_BRANCH_MASK GENMASK(23, 21)
+#define CS40L26_FW_ID 0x1800D4
+#define CS40L26_FW_MIN_REV 0x07021C
+#define CS40L26_FW_BRANCH 0x07
+#define CS40L26_FW_CALIB_ID 0x1800DA
+#define CS40L26_FW_CALIB_MIN_REV 0x010014
+#define CS40L26_FW_CALIB_BRANCH 0x01
+#define CS40L26_FW_MAINT_MIN_REV 0x270216
+#define CS40L26_FW_MAINT_BRANCH 0x27
+#define CS40L26_FW_MAINT_CALIB_MIN_REV 0x21010D
+#define CS40L26_FW_MAINT_CALIB_BRANCH 0x21
+#define CS40L26_FW_GPI_TIMEOUT_MIN_REV 0x07022A
+#define CS40L26_FW_GPI_TIMEOUT_CALIB_MIN_REV 0x010122
+#define CS40L26_FW_BRANCH_MASK GENMASK(23, 21)
#define CS40L26_CCM_CORE_RESET 0x00000200
#define CS40L26_CCM_CORE_ENABLE 0x00000281
@@ -934,7 +940,7 @@
#define CS40L26_GPIO1 1
#define CS40L26_EVENT_MAP_INDEX_MASK GENMASK(8, 0)
#define CS40L26_EVENT_MAP_NUM_GPI_REGS 4
-#define CS40L26_EVENT_MAP_GPI_EVENT_DISABLE 0x1FF
+#define CS40L26_EVENT_MAP_GPI_DISABLE 0x1FF
#define CS40L26_BTN_INDEX_MASK GENMASK(7, 0)
#define CS40L26_BTN_BUZZ_MASK BIT(7)
@@ -1167,9 +1173,6 @@
#define CS40L26_A2H_DELAY_MAX 0x190
-#define CS40L26_PDATA_PRESENT 0x80000000
-#define CS40L26_PDATA_MASK ~CS40L26_PDATA_PRESENT
-
#define CS40L26_VMON_DEC_OUT_DATA_MASK GENMASK(23, 0)
#define CS40L26_VMON_OVFL_FLAG_MASK BIT(31)
#define CS40L26_VMON_DEC_OUT_DATA_MAX CS40L26_VMON_DEC_OUT_DATA_MASK
@@ -1289,6 +1292,13 @@
#define CS40L26_SAMPS_TO_MS(n) ((n) / 8)
/* enums */
+enum cs40l26_gpio_map {
+ CS40L26_GPIO_MAP_A_PRESS,
+ CS40L26_GPIO_MAP_A_RELEASE,
+ CS40L26_GPIO_MAP_NUM_AVAILABLE,
+ CS40L26_GPIO_MAP_INVALID,
+};
+
enum cs40l26_dbc {
CS40L26_DBC_ENV_REL_COEF, /* 0 */
CS40L26_DBC_RISE_HEADROOM,
@@ -1472,6 +1482,7 @@ struct cs40l26_private {
struct input_dev *input;
struct cl_dsp *dsp;
unsigned int trigger_indices[FF_MAX_EFFECTS];
+ int gpi_ids[CS40L26_GPIO_MAP_NUM_AVAILABLE];
struct ff_effect *trigger_effect;
struct ff_effect upload_effect;
struct ff_effect *erase_effect;
@@ -1518,6 +1529,7 @@ struct cs40l26_private {
struct completion i2s_cont;
struct completion erase_cont;
u8 vpbr_thld;
+ unsigned int svc_le_est_stored;
};
struct cs40l26_codec {
@@ -1551,7 +1563,7 @@ int cs40l26_dbc_set(struct cs40l26_private *cs40l26, enum cs40l26_dbc dbc,
u32 val);
int cs40l26_asp_start(struct cs40l26_private *cs40l26);
int cs40l26_get_num_waves(struct cs40l26_private *cs40l26, u32 *num_waves);
-int cs40l26_fw_swap(struct cs40l26_private *cs40l26, u32 id);
+int cs40l26_fw_swap(struct cs40l26_private *cs40l26, const u32 id);
void cs40l26_vibe_state_update(struct cs40l26_private *cs40l26,
enum cs40l26_vibe_state_event event);
int cs40l26_pm_stdby_timeout_ms_get(struct cs40l26_private *cs40l26,
@@ -1566,6 +1578,8 @@ int cs40l26_pm_state_transition(struct cs40l26_private *cs40l26,
enum cs40l26_pm_state state);
int cs40l26_ack_write(struct cs40l26_private *cs40l26, u32 reg, u32 write_val,
u32 reset_val);
+int cs40l26_pm_enter(struct device *dev);
+void cs40l26_pm_exit(struct device *dev);
void cs40l26_resume_error_handle(struct device *dev, int ret);
int cs40l26_resume(struct device *dev);
int cs40l26_sys_resume(struct device *dev);