summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTai Kuo <taikuo@google.com>2021-08-02 15:59:17 +0800
committerchasewu <chasewu@google.com>2021-09-08 10:29:57 +0800
commit2370e83abc93b307a0e1550d9565bc750a62d445 (patch)
treea3ce80a77a11cbf0e2f4c64672160723865e9781
parentf70cd15574b2c93b7fa54517af9c7a1c0ec5a611 (diff)
downloadamplifiers-2370e83abc93b307a0e1550d9565bc750a62d445.tar.gz
cs40l26: merge CirrusLogic dsp v3.1.2 and cs40l26 v1.1.0
Branch: v5.10-cs40l26 Tag: cs40l26-v1.1.0_5.10 Files: drivers/input/misc/cs40l26-i2c.c (No changes) drivers/input/misc/cs40l26-spi.c (No changes) drivers/input/misc/cs40l26-sysfs.c drivers/input/misc/cs40l26-tables.c drivers/input/misc/cs40l26.c include/linux/mfd/cs40l26.h sound/soc/codecs/cs40l26.c -> cs40l26-codec.c Features: - Increase A2H Volume Granularity - Add more debug-level statements - sysfs control to get amount of space left in wavetable - DT control to set maximum boost peak current - sysfs control to read die temperature - sysfs control to swap firmware variants at runtime - Load firmware synchronously - Inverted streaming and waveform playback - SVC enable for effects streamed via ASP - Map Haptic Effects to GPI events - Actuator Safe Mode workaround - Remove support for A0 silicon Bug fixes: - Remove unused variables - Cancel worker threads before deleting workqueue commits: c07047bd1087 ASoC: cs40l26: Add control to enable invert streaming data 7d0b08956875 input: cs40l26: Remove A0 silicon support d6c20f8342fd input: cs40l26: Update firmware swap function (Skip) 421500c4eb47 Documentation: cs40l26: Add option to load specified SVC tuning a3fb83ecc3b3 input: cs40l26: Add option to load specified SVC tuning 736aa239110c ASoC: cs40l26: Add control to enable SVC for streaming data 7c060144b291 input: cs40l26: Implement actuator safe mode workaround 9b866d0e0362 input: cs40l26: Map Haptic Effects to GPI Events e28e0a5131cc input: cs40l26: Add ability to invert waveform playback 961e4ba3a4bb input: cs40l26: Load firmware synchronously 23463ef1ab4a input: cs40l26: Add ability to swap firmware variants 05b2d67e3c66 input: cs40l26: Remove ENABLE/DISABLE macros b6bd69389b17 input: cs40l26: Remove unneeded use of variable in cs40l26_pcm_ev 27af6399be8c input: cs40l26: Cancel worker threads before destroying workqueue 1794f854a2d0 input: cs40l26: Add control to read die temperature when DSP is active 50bf4051b3a8 input: cs40l26: Remove silicon rev. checks for algorithm IDs (Skip) 3982e2db9db5 Documentation: cs40l26: Allow user to set peak boost current 756186d689c5 input: cs40l26: Allow user to set peak boost current ed0f6bc72faa input: cs40l26: Control to read remaining space in wavetable 72510182f0f2 input: cs40l26: Use percentage value to set A0 gain 91d781c96e12 input: cs40l26: Make status registers readable via regmap a8beb7e4c41f ASoC: cs40l26: Add dev_dbg statments to ALSA callbacks c5b8320ebbce input: cs40l26: Add debug statements 17b3a65e18d1 input: cs40l26: Control to read Power On Sequence 8c4f68e0194a ASoC: cs40l26: Increase A2H Volume granularity Branch: v5.10-cirrus-dsp-fw Tag: cl-dsp-fw-v3.1.2_5.10 Files: drivers/firmware/cirrus/cl_dsp.c include/linux/firmware/cirrus/cl_dsp.h Allocate array memory for .bin file data dynamically instead of using a hard-coded value to avoid possibility of a kernel crash. Allow firmware to load even if there are incompatibilities between the expected firmware version, the loaded firmware, and the tuning file revisions. commits: 79a4a41e4fc6 firmware: cirrus: Allocate data array dynamically 19140c2d644b firmware: cirrus: Loosen restrictions on firmware loading 8e02f2e42990 firmware: cirrus: Don't explicitly free coefficient parent name Bug: 191658078 Bug: 180110149 Bug: 194540033 Bug: 193793095 Test: Check idlcli vibrator commands. Test: Back EMF for internal calibration. Test: Firmware swap. Signed-off-by: Tai Kuo <taikuo@google.com> Change-Id: I7db82ce23663772a83e69490b88cfb47e4bf93f3
-rw-r--r--cs40l26/cl_dsp.c28
-rw-r--r--cs40l26/cl_dsp.h4
-rw-r--r--cs40l26/cs40l26-codec.c165
-rw-r--r--cs40l26/cs40l26-sysfs.c157
-rw-r--r--cs40l26/cs40l26-tables.c46
-rw-r--r--cs40l26/cs40l26.c1146
-rw-r--r--cs40l26/cs40l26.h168
7 files changed, 1007 insertions, 707 deletions
diff --git a/cs40l26/cl_dsp.c b/cs40l26/cl_dsp.c
index 8e02340..f92babc 100644
--- a/cs40l26/cl_dsp.c
+++ b/cs40l26/cl_dsp.c
@@ -211,7 +211,12 @@ static int cl_dsp_owt_init(struct cl_dsp *dsp, const struct firmware *bin)
return -EPERM;
}
- memcpy(&dsp->wt_desc->owt.raw_data, &bin->data[0], bin->size);
+ dsp->wt_desc->owt.raw_data = devm_kzalloc(dsp->dev, bin->size,
+ GFP_KERNEL);
+ if (!dsp->wt_desc->owt.raw_data)
+ return -ENOMEM;
+
+ memcpy(dsp->wt_desc->owt.raw_data, &bin->data[0], bin->size);
return 0;
}
@@ -219,7 +224,7 @@ static int cl_dsp_owt_init(struct cl_dsp *dsp, const struct firmware *bin)
static int cl_dsp_read_wt(struct cl_dsp *dsp, int pos, int size)
{
struct cl_dsp_owt_header *entry = dsp->wt_desc->owt.waves;
- void *buf = (void *)&dsp->wt_desc->owt.raw_data[pos];
+ 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;
@@ -266,13 +271,7 @@ static int cl_dsp_coeff_header_parse(struct cl_dsp *dsp,
return -EINVAL;
}
- if (CL_DSP_GET_MAJOR(header.fw_revision)
- != CL_DSP_GET_MAJOR(dsp->algo_info[0].rev)) {
- dev_err(dev,
- "Coeff. revision 0x%06X incompatible with 0x%06X\n",
- header.fw_revision, dsp->algo_info[0].rev);
- return -EINVAL;
- } else if (header.fw_revision != dsp->algo_info[0].rev) {
+ if (header.fw_revision != dsp->algo_info[0].rev) {
dev_warn(dev,
"Coeff. rev. 0x%06X mistmatches 0x%06X, continuing..\n",
header.fw_revision, dsp->algo_info[0].rev);
@@ -327,6 +326,7 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
union cl_dsp_wmdr_header wmdr_header;
char wt_date[CL_DSP_WMDR_DATE_LEN];
unsigned int reg, wt_reg, algo_rev;
+ u16 algo_id, parent_id;
int i;
if (!dsp)
@@ -358,11 +358,13 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
memcpy(data_block.payload, &fw->data[pos],
data_block.header.data_len);
+ algo_id = data_block.header.algo_id & 0xFFFF;
+
if (data_block.header.block_type != CL_DSP_WMDR_NAME_TYPE &&
data_block.header.block_type != CL_DSP_WMDR_INFO_TYPE) {
for (i = 0; i < dsp->num_algos; i++) {
- if (data_block.header.algo_id
- == dsp->algo_info[i].id)
+ parent_id = dsp->algo_info[i].id & 0xFFFF;
+ if (algo_id == parent_id)
break;
}
@@ -388,8 +390,7 @@ int cl_dsp_coeff_file_parse(struct cl_dsp *dsp, const struct firmware *fw)
goto err_free;
}
- wt_found = ((data_block.header.algo_id & 0xFFFF) ==
- (dsp->wt_desc->id & 0xFFFF));
+ wt_found = (algo_id == (dsp->wt_desc->id & 0xFFFF));
}
switch (data_block.header.block_type) {
@@ -884,7 +885,6 @@ static void cl_dsp_coeff_free(struct cl_dsp *dsp)
coeff_desc = list_first_entry(&dsp->coeff_desc_head,
struct cl_dsp_coeff_desc, list);
list_del(&coeff_desc->list);
- kfree(coeff_desc->parent_name);
devm_kfree(dsp->dev, coeff_desc);
}
}
diff --git a/cs40l26/cl_dsp.h b/cs40l26/cl_dsp.h
index fbaf62e..41d0d25 100644
--- a/cs40l26/cl_dsp.h
+++ b/cs40l26/cl_dsp.h
@@ -140,8 +140,6 @@
#define CL_DSP_OWT_HEADER_MAX_LEN 128
#define CL_DSP_OWT_HEADER_ENTRY_SIZE 12
-#define CL_DSP_MAX_BIN_SIZE 9584
-
/* macros */
#define CL_DSP_WORD_ALIGN(n) (CL_DSP_BYTES_PER_WORD +\
(((n) / CL_DSP_BYTES_PER_WORD) *\
@@ -268,7 +266,7 @@ struct cl_dsp_owt_desc {
struct cl_dsp_owt_header waves[CL_DSP_OWT_HEADER_MAX_LEN];
int nwaves;
u32 bytes;
- u8 raw_data[CL_DSP_MAX_BIN_SIZE];
+ u8 *raw_data;
};
struct cl_dsp_wt_desc {
diff --git a/cs40l26/cs40l26-codec.c b/cs40l26/cs40l26-codec.c
index 9c14b9f..c19d2e9 100644
--- a/cs40l26/cs40l26-codec.c
+++ b/cs40l26/cs40l26-codec.c
@@ -60,7 +60,7 @@ static int cs40l26_swap_ext_clk(struct cs40l26_codec *codec, u8 clk_src)
}
ret = regmap_update_bits(regmap, CS40L26_REFCLK_INPUT,
- CS40L26_PLL_REFCLK_OPEN_LOOP_MASK, CS40L26_ENABLE <<
+ CS40L26_PLL_REFCLK_OPEN_LOOP_MASK, 1 <<
CS40L26_PLL_REFCLK_OPEN_LOOP_SHIFT);
if (ret) {
dev_err(dev, "Failed to set Open-Loop PLL\n");
@@ -77,7 +77,7 @@ static int cs40l26_swap_ext_clk(struct cs40l26_codec *codec, u8 clk_src)
}
ret = regmap_update_bits(regmap, CS40L26_REFCLK_INPUT,
- CS40L26_PLL_REFCLK_OPEN_LOOP_MASK, CS40L26_DISABLE <<
+ CS40L26_PLL_REFCLK_OPEN_LOOP_MASK, 0 <<
CS40L26_PLL_REFCLK_OPEN_LOOP_SHIFT);
if (ret)
dev_err(dev, "Failed to close PLL loop\n");
@@ -94,6 +94,9 @@ static int cs40l26_clk_en(struct snd_soc_dapm_widget *w,
struct device *dev = cs40l26->dev;
int ret;
+ dev_info(dev, "%s: %s\n", __func__,
+ event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
mutex_lock(&cs40l26->lock);
@@ -135,6 +138,9 @@ static int cs40l26_a2h_ev(struct snd_soc_dapm_widget *w,
int ret;
u32 reg;
+ dev_dbg(dev, "%s: %s\n", __func__,
+ event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
+
ret = cl_dsp_get_reg(cs40l26->dsp, "A2HEN", CL_DSP_XM_UNPACKED_TYPE,
CS40L26_A2H_ALGO_ID, &reg);
if (ret)
@@ -163,9 +169,9 @@ static int cs40l26_a2h_ev(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
}
- return regmap_write(cs40l26->regmap, reg, CS40L26_ENABLE);
+ return regmap_write(cs40l26->regmap, reg, 1);
case SND_SOC_DAPM_PRE_PMD:
- return regmap_write(cs40l26->regmap, reg, CS40L26_DISABLE);
+ return regmap_write(cs40l26->regmap, reg, 0);
default:
dev_err(dev, "Invalid A2H event: %d\n", event);
return -EINVAL;
@@ -181,9 +187,12 @@ static int cs40l26_pcm_ev(struct snd_soc_dapm_widget *w,
struct device *dev = cs40l26->dev;
u32 asp_en_mask = CS40L26_ASP_TX1_EN_MASK | CS40L26_ASP_TX2_EN_MASK |
CS40L26_ASP_RX1_EN_MASK | CS40L26_ASP_RX2_EN_MASK;
- u32 asp_enables;
+ u32 asp_enables, reg;
int ret;
+ dev_info(dev, "%s: %s\n", __func__,
+ event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
ret = regmap_update_bits(regmap, CS40L26_DACPCM1_INPUT,
@@ -200,10 +209,9 @@ static int cs40l26_pcm_ev(struct snd_soc_dapm_widget *w,
return ret;
}
- asp_enables = CS40L26_ENABLE | (CS40L26_ENABLE <<
- CS40L26_ASP_TX2_EN_SHIFT) | (CS40L26_ENABLE <<
- CS40L26_ASP_RX1_EN_SHIFT) | (CS40L26_ENABLE <<
- CS40L26_ASP_RX2_EN_SHIFT);
+ asp_enables = 1 | (1 << CS40L26_ASP_TX2_EN_SHIFT)
+ | (1 << CS40L26_ASP_RX1_EN_SHIFT)
+ | (1 << CS40L26_ASP_RX2_EN_SHIFT);
ret = regmap_update_bits(regmap, CS40L26_ASP_ENABLES1,
asp_en_mask, asp_enables);
@@ -224,6 +232,28 @@ static int cs40l26_pcm_ev(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
+ ret = cl_dsp_get_reg(cs40l26->dsp, "FLAGS",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(regmap, reg, codec->svc_for_streaming_data);
+ if (ret) {
+ dev_err(dev, "Failed to specify SVC for streaming\n");
+ return ret;
+ }
+
+ ret = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_INVERT",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(regmap, reg, codec->invert_streaming_data);
+ if (ret) {
+ dev_err(dev, "Failed to specify SVC for streaming\n");
+ return ret;
+ }
+
ret = cs40l26_ack_write(cs40l26, CS40L26_DSP_VIRTUAL1_MBOX_1,
CS40L26_DSP_MBOX_CMD_START_I2S,
CS40L26_DSP_MBOX_RESET);
@@ -239,13 +269,8 @@ static int cs40l26_pcm_ev(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
- asp_enables = CS40L26_DISABLE | (CS40L26_DISABLE <<
- CS40L26_ASP_TX2_EN_SHIFT) | (CS40L26_DISABLE <<
- CS40L26_ASP_RX1_EN_SHIFT) | (CS40L26_DISABLE <<
- CS40L26_ASP_RX2_EN_SHIFT);
-
ret = regmap_update_bits(regmap, CS40L26_ASP_ENABLES1,
- asp_en_mask, asp_enables);
+ asp_en_mask, 0);
if (ret) {
dev_err(dev, "Failed to clear ASPTX1 input\n");
return ret;
@@ -264,6 +289,83 @@ static int cs40l26_pcm_ev(struct snd_soc_dapm_widget *w,
return ret;
}
+static int cs40l26_svc_for_streaming_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs40l26_codec *codec =
+ snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
+ struct cs40l26_private *cs40l26 = codec->core;
+
+ mutex_lock(&cs40l26->lock);
+
+ if (codec->svc_for_streaming_data)
+ ucontrol->value.enumerated.item[0] = 1;
+ else
+ ucontrol->value.enumerated.item[0] = 0;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return 0;
+}
+
+static int cs40l26_svc_for_streaming_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs40l26_codec *codec =
+ snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
+ struct cs40l26_private *cs40l26 = codec->core;
+
+ mutex_lock(&cs40l26->lock);
+
+ if (ucontrol->value.enumerated.item[0])
+ codec->svc_for_streaming_data = true;
+ else
+ codec->svc_for_streaming_data = false;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return 0;
+}
+
+static int cs40l26_invert_streaming_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs40l26_codec *codec =
+ snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
+ struct cs40l26_private *cs40l26 = codec->core;
+
+ mutex_lock(&cs40l26->lock);
+
+ if (codec->invert_streaming_data)
+ ucontrol->value.enumerated.item[0] = 1;
+ else
+ ucontrol->value.enumerated.item[0] = 0;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return 0;
+}
+
+static int cs40l26_invert_streaming_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs40l26_codec *codec =
+ snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
+ struct cs40l26_private *cs40l26 = codec->core;
+
+ mutex_lock(&cs40l26->lock);
+
+ if (ucontrol->value.enumerated.item[0])
+ codec->invert_streaming_data = true;
+ else
+ codec->invert_streaming_data = false;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return 0;
+}
+
+
static int cs40l26_tuning_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -302,7 +404,7 @@ static int cs40l26_tuning_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static int cs40l26_volume_get(struct snd_kcontrol *kcontrol,
+static int cs40l26_a2h_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct cs40l26_codec *codec =
@@ -321,17 +423,9 @@ static int cs40l26_volume_get(struct snd_kcontrol *kcontrol,
pm_runtime_get_sync(dev);
ret = regmap_read(regmap, reg, &val);
- if (ret) {
+ if (ret)
dev_err(dev, "Failed to get VOLUMELEVEL\n");
- goto err_pm;
- }
-
- if (val == CS40L26_VOLUME_MAX)
- val = CS40L26_VOLUME_MAX_STEPS;
- else
- val /= CS40L26_VOLUME_STEP_SIZE;
-err_pm:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -340,7 +434,7 @@ err_pm:
return ret;
}
-static int cs40l26_volume_put(struct snd_kcontrol *kcontrol,
+static int cs40l26_a2h_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct cs40l26_codec *codec =
@@ -356,11 +450,12 @@ static int cs40l26_volume_put(struct snd_kcontrol *kcontrol,
if (ret)
return ret;
- val = ucontrol->value.integer.value[0];
- if (val == CS40L26_VOLUME_MAX_STEPS)
- val = CS40L26_VOLUME_MAX;
+ if (ucontrol->value.integer.value[0] > CS40L26_A2H_VOLUME_MAX)
+ val = CS40L26_A2H_VOLUME_MAX;
+ else if (ucontrol->value.integer.value[0] < 0)
+ val = 0;
else
- val *= CS40L26_VOLUME_STEP_SIZE;
+ val = ucontrol->value.integer.value[0];
pm_runtime_get_sync(dev);
@@ -377,8 +472,14 @@ static int cs40l26_volume_put(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new cs40l26_controls[] = {
SOC_SINGLE_EXT("A2H Tuning", 0, 0, CS40L26_A2H_MAX_TUNINGS, 0,
cs40l26_tuning_get, cs40l26_tuning_put),
- SOC_SINGLE_EXT("A2H Volume", 0, 0, CS40L26_VOLUME_MAX_STEPS, 0,
- cs40l26_volume_get, cs40l26_volume_put),
+ SOC_SINGLE_EXT("A2H Volume", 0, 0, CS40L26_A2H_VOLUME_MAX, 0,
+ cs40l26_a2h_volume_get, cs40l26_a2h_volume_put),
+ SOC_SINGLE_EXT("SVC for streaming data", 0, 0, 1, 0,
+ cs40l26_svc_for_streaming_data_get,
+ cs40l26_svc_for_streaming_data_put),
+ SOC_SINGLE_EXT("Invert streaming data", 0, 0, 1, 0,
+ cs40l26_invert_streaming_data_get,
+ cs40l26_invert_streaming_data_put),
};
static const char * const cs40l26_out_mux_texts[] = { "Off", "PCM", "A2H" };
diff --git a/cs40l26/cs40l26-sysfs.c b/cs40l26/cs40l26-sysfs.c
index 47996d0..8e5c9dc 100644
--- a/cs40l26/cs40l26-sysfs.c
+++ b/cs40l26/cs40l26-sysfs.c
@@ -62,7 +62,7 @@ static ssize_t cs40l26_halo_heartbeat_show(struct device *dev,
pm_runtime_get_sync(cs40l26->dev);
ret = cl_dsp_get_reg(cs40l26->dsp, "HALO_HEARTBEAT",
- CL_DSP_XM_UNPACKED_TYPE, CS40L26_FW_ID, &reg);
+ CL_DSP_XM_UNPACKED_TYPE, cs40l26->fw.id, &reg);
if (ret)
return ret;
@@ -179,7 +179,116 @@ static ssize_t cs40l26_vibe_state_show(struct device *dev,
}
static DEVICE_ATTR(vibe_state, 0660, cs40l26_vibe_state_show, NULL);
+static ssize_t cs40l26_pseq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ struct list_head *op_head = &cs40l26->pseq_op_head;
+ u32 base = cs40l26->pseq_base;
+ int i, count = 0;
+ struct cs40l26_pseq_op *pseq_op;
+
+ mutex_lock(&cs40l26->lock);
+
+ list_for_each_entry_reverse(pseq_op, op_head, list) {
+ dev_info(cs40l26->dev, "%d: Address: 0x%08X, Size: %d words\n",
+ count + 1, base + pseq_op->offset, pseq_op->size);
+
+ for (i = 0; i < pseq_op->size; i++)
+ dev_info(cs40l26->dev, "0x%08X\n",
+ *(pseq_op->words + i));
+
+ count++;
+ }
+
+ mutex_unlock(&cs40l26->lock);
+
+ if (count != cs40l26->pseq_num_ops) {
+ dev_err(cs40l26->dev, "Malformed Power on seq.\n");
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", cs40l26->pseq_num_ops);
+}
+static DEVICE_ATTR(power_on_seq, 0440, cs40l26_pseq_show, NULL);
+
+static ssize_t cs40l26_owt_free_space_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ u32 reg, nbytes;
+ int ret;
+
+ pm_runtime_get_sync(cs40l26->dev);
+
+ ret = cl_dsp_get_reg(cs40l26->dsp, "OWT_SIZE_XM",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_VIBEGEN_ALGO_ID, &reg);
+ if (ret)
+ goto err_pm;
+
+ ret = regmap_read(cs40l26->regmap, reg, &nbytes);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get remaining OWT space\n");
+ goto err_pm;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", nbytes);
+
+err_pm:
+ pm_runtime_mark_last_busy(cs40l26->dev);
+ pm_runtime_put_autosuspend(cs40l26->dev);
+
+ return ret;
+}
+static DEVICE_ATTR(owt_free_space, 0440, cs40l26_owt_free_space_show, NULL);
+
+static ssize_t cs40l26_die_temp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ struct regmap *regmap = cs40l26->regmap;
+ u16 die_temp;
+ int ret;
+ u32 val;
+
+ pm_runtime_get_sync(cs40l26->dev);
+
+ ret = regmap_read(regmap, CS40L26_GLOBAL_ENABLES, &val);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to read GLOBAL_EN status\n");
+ goto err_pm;
+ }
+
+ if (!(val & CS40L26_GLOBAL_EN_MASK)) {
+ dev_err(cs40l26->dev,
+ "Global enable must be set to get die temp.\n");
+ ret = -EPERM;
+ goto err_pm;
+ }
+
+ ret = regmap_read(regmap, CS40L26_ENABLES_AND_CODES_DIG, &val);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get die temperature\n");
+ goto err_pm;
+ }
+
+ die_temp = (val & CS40L26_TEMP_RESULT_FILT_MASK) >>
+ CS40L26_TEMP_RESULT_FILT_SHIFT;
+
+ 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);
+
+ return ret;
+}
+static DEVICE_ATTR(die_temp, 0440, cs40l26_die_temp_show, NULL);
+
static struct attribute *cs40l26_dev_attrs[] = {
+ &dev_attr_die_temp.attr,
+ &dev_attr_owt_free_space.attr,
+ &dev_attr_power_on_seq.attr,
&dev_attr_dsp_state.attr,
&dev_attr_halo_heartbeat.attr,
&dev_attr_fw_mode.attr,
@@ -660,7 +769,7 @@ static ssize_t cs40l26_redc_cal_time_ms_show(struct device *dev,
ret = cl_dsp_get_reg(cs40l26->dsp, "REDC_PLAYTIME_MS",
CL_DSP_XM_UNPACKED_TYPE,
- CS40L26_FW_ID, &reg);
+ cs40l26->fw.id, &reg);
if (ret)
goto err_mutex;
@@ -867,6 +976,49 @@ err_mutex:
return snprintf(buf, PAGE_SIZE, "0x%06X\n", max_vbst);
}
+static ssize_t cs40l26_calib_fw_load_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&cs40l26->lock);
+
+ if (cs40l26->fw.id == CS40L26_FW_ID)
+ ret = snprintf(buf, PAGE_SIZE, "%u\n", 0);
+ else if (cs40l26->fw.id == CS40L26_FW_CALIB_ID)
+ ret = snprintf(buf, PAGE_SIZE, "%u\n", 1);
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&cs40l26->lock);
+
+ return ret;
+}
+
+static ssize_t cs40l26_calib_fw_load_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct cs40l26_private *cs40l26 = dev_get_drvdata(dev);
+ int ret;
+ unsigned int variant;
+
+ ret = kstrtou32(buf, 10, &variant);
+ if (ret)
+ return ret;
+
+ if (variant == 0)
+ ret = cs40l26_fw_swap(cs40l26, CS40L26_FW_ID);
+ else if (variant == 1)
+ ret = cs40l26_fw_swap(cs40l26, CS40L26_FW_CALIB_ID);
+ else
+ ret = -EINVAL;
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(calib_fw_load, 0660, cs40l26_calib_fw_load_show,
+ cs40l26_calib_fw_load_store);
static DEVICE_ATTR(max_vbst, 0440, cs40l26_max_vbst_show, NULL);
static DEVICE_ATTR(max_bemf, 0440, cs40l26_max_bemf_show, NULL);
static DEVICE_ATTR(logging_max_reset,
@@ -895,6 +1047,7 @@ static DEVICE_ATTR(redc_cal_time_ms,
0440, cs40l26_redc_cal_time_ms_show, NULL);
static struct attribute *cs40l26_dev_attrs_cal[] = {
+ &dev_attr_calib_fw_load.attr,
&dev_attr_max_vbst.attr,
&dev_attr_max_bemf.attr,
&dev_attr_logging_max_reset.attr,
diff --git a/cs40l26/cs40l26-tables.c b/cs40l26/cs40l26-tables.c
index 9bd8056..189d49a 100644
--- a/cs40l26/cs40l26-tables.c
+++ b/cs40l26/cs40l26-tables.c
@@ -41,29 +41,23 @@ const struct dev_pm_ops cs40l26_pm_ops = {
cs40l26_sys_resume_noirq)
};
-const char * const cs40l26_ram_coeff_files[3] = {
- CS40L26_WT_FILE_NAME,
- CS40L26_SVC_TUNING_FILE_NAME,
- CS40L26_A2H_TUNING_FILE_NAME,
-};
-
-const u8 cs40l26_pseq_v2_op_sizes[CS40L26_PSEQ_V2_NUM_OPS][2] = {
- { CS40L26_PSEQ_V2_OP_WRITE_REG_FULL,
- CS40L26_PSEQ_V2_OP_WRITE_REG_FULL_WORDS},
- { CS40L26_PSEQ_V2_OP_WRITE_FIELD,
- CS40L26_PSEQ_V2_OP_WRITE_FIELD_WORDS},
- { CS40L26_PSEQ_V2_OP_WRITE_REG_ADDR8,
- CS40L26_PSEQ_V2_OP_WRITE_REG_ADDR8_WORDS},
- { CS40L26_PSEQ_V2_OP_WRITE_REG_INCR,
- CS40L26_PSEQ_V2_OP_WRITE_REG_INCR_WORDS},
- { CS40L26_PSEQ_V2_OP_WRITE_REG_L16,
- CS40L26_PSEQ_V2_OP_WRITE_REG_L16_WORDS},
- { CS40L26_PSEQ_V2_OP_WRITE_REG_H16,
- CS40L26_PSEQ_V2_OP_WRITE_REG_H16_WORDS},
- { CS40L26_PSEQ_V2_OP_DELAY,
- CS40L26_PSEQ_V2_OP_DELAY_WORDS},
- { CS40L26_PSEQ_V2_OP_END,
- CS40L26_PSEQ_V2_OP_END_WORDS},
+const u8 cs40l26_pseq_op_sizes[CS40L26_PSEQ_NUM_OPS][2] = {
+ { CS40L26_PSEQ_OP_WRITE_REG_FULL,
+ CS40L26_PSEQ_OP_WRITE_REG_FULL_WORDS},
+ { CS40L26_PSEQ_OP_WRITE_FIELD,
+ CS40L26_PSEQ_OP_WRITE_FIELD_WORDS},
+ { CS40L26_PSEQ_OP_WRITE_REG_ADDR8,
+ CS40L26_PSEQ_OP_WRITE_REG_ADDR8_WORDS},
+ { CS40L26_PSEQ_OP_WRITE_REG_INCR,
+ CS40L26_PSEQ_OP_WRITE_REG_INCR_WORDS},
+ { CS40L26_PSEQ_OP_WRITE_REG_L16,
+ CS40L26_PSEQ_OP_WRITE_REG_L16_WORDS},
+ { CS40L26_PSEQ_OP_WRITE_REG_H16,
+ CS40L26_PSEQ_OP_WRITE_REG_H16_WORDS},
+ { CS40L26_PSEQ_OP_DELAY,
+ CS40L26_PSEQ_OP_DELAY_WORDS},
+ { CS40L26_PSEQ_OP_END,
+ CS40L26_PSEQ_OP_END_WORDS},
};
struct regulator_bulk_data cs40l26_supplies[CS40L26_NUM_SUPPLIES] = {
@@ -75,7 +69,7 @@ const struct mfd_cell cs40l26_devs[CS40L26_NUM_MFD_DEVS] = {
{ .name = "cs40l26-codec" },
};
-const u32 cs40l26_attn_q21_2_vals[101] = {
+const u32 cs40l26_attn_q21_2_vals[CS40L26_NUM_PCT_MAP_VALUES] = {
400, /* MUTE */
160, /* 1% */
136,
@@ -234,6 +228,8 @@ bool cs40l26_readable_reg(struct device *dev, unsigned int reg)
case CS40L26_OSC_TRIM:
case CS40L26_ERROR_RELEASE:
case CS40L26_PLL_OVERRIDE:
+ case CS40L26_CHIP_STATUS_1:
+ case CS40L26_CHIP_STATUS_2:
case CS40L26_BIAS_PTE_MODE_CONTROL:
case CS40L26_SCL_PAD_CONTROL:
case CS40L26_SDA_PAD_CONTROL:
@@ -534,6 +530,8 @@ CS40L26_DSP1_XROM_UNPACKED32_3070:
case CS40L26_DSP1_AHBM_WINDOW6_CONTROL_1:
case CS40L26_DSP1_AHBM_WINDOW7_CONTROL_0:
case CS40L26_DSP1_AHBM_WINDOW7_CONTROL_1:
+ case CS40L26_DSP1_AHBM_WINDOW_DEBUG_0:
+ case CS40L26_DSP1_AHBM_WINDOW_DEBUG_1:
case CS40L26_DSP1_XMEM_UNPACKED24_0 ...
CS40L26_DSP1_XMEM_UNPACKED24_8191:
case CS40L26_DSP1_XROM_UNPACKED24_0 ...
diff --git a/cs40l26/cs40l26.c b/cs40l26/cs40l26.c
index 4f10c6f..9b75a6f 100644
--- a/cs40l26/cs40l26.c
+++ b/cs40l26/cs40l26.c
@@ -128,34 +128,17 @@ EXPORT_SYMBOL(cs40l26_class_h_set);
int cs40l26_dsp_state_get(struct cs40l26_private *cs40l26, u8 *state)
{
- u32 algo_id, reg, dsp_state;
- int ret;
-
- if (cs40l26->fw_loaded) {
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- algo_id = CS40L26_PM_ALGO_ID;
- else
- algo_id = CS40L26_PM_ROM_ALGO_ID;
+ u32 reg, dsp_state;
+ int ret = 0;
+ if (cs40l26->fw_loaded)
ret = cl_dsp_get_reg(cs40l26->dsp, "PM_CUR_STATE",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &reg);
- if (ret)
- return ret;
- } else {
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- reg = CS40L26_A0_PM_CUR_STATE_STATIC_REG;
- break;
- case CS40L26_REVID_A1:
- reg = CS40L26_A1_PM_CUR_STATE_STATIC_REG;
- break;
- default:
- dev_err(cs40l26->dev,
- "Revid ID not supported: 0x%02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
- }
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_PM_ALGO_ID, &reg);
+ else
+ reg = CS40L26_A1_PM_CUR_STATE_STATIC_REG;
+
+ if (ret)
+ return ret;
ret = cs40l26_dsp_read(cs40l26, reg, &dsp_state);
if (ret)
@@ -185,7 +168,7 @@ int cs40l26_pm_timeout_ms_set(struct cs40l26_private *cs40l26,
{
u32 timeout_ticks = timeout_ms * CS40L26_PM_TICKS_MS_DIV;
struct regmap *regmap = cs40l26->regmap;
- u32 lower_val, reg, algo_id;
+ u32 lower_val, reg;
u8 upper_val;
int ret;
@@ -194,13 +177,8 @@ int cs40l26_pm_timeout_ms_set(struct cs40l26_private *cs40l26,
lower_val = timeout_ticks & CS40L26_PM_TIMEOUT_TICKS_LOWER_MASK;
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- algo_id = CS40L26_PM_ALGO_ID;
- else
- algo_id = CS40L26_PM_ROM_ALGO_ID;
-
ret = cl_dsp_get_reg(cs40l26->dsp, "PM_TIMER_TIMEOUT_TICKS",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &reg);
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_PM_ALGO_ID, &reg);
if (ret)
return ret;
@@ -217,33 +195,17 @@ EXPORT_SYMBOL(cs40l26_pm_timeout_ms_set);
int cs40l26_pm_timeout_ms_get(struct cs40l26_private *cs40l26,
u32 *timeout_ms)
{
- u32 lower_val, upper_val, algo_id, reg;
- int ret;
-
- if (cs40l26->fw_loaded) {
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- algo_id = CS40L26_PM_ALGO_ID;
- else
- algo_id = CS40L26_PM_ROM_ALGO_ID;
+ u32 lower_val, upper_val, reg;
+ int ret = 0;
+ if (cs40l26->fw_loaded)
ret = cl_dsp_get_reg(cs40l26->dsp, "PM_TIMER_TIMEOUT_TICKS",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &reg);
- if (ret)
- return ret;
- } else {
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- reg = CS40L26_A0_PM_TIMEOUT_TICKS_STATIC_REG;
- break;
- case CS40L26_REVID_A1:
- reg = CS40L26_A1_PM_TIMEOUT_TICKS_STATIC_REG;
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
- }
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_PM_ALGO_ID, &reg);
+ else
+ reg = CS40L26_A1_PM_TIMEOUT_TICKS_STATIC_REG;
+
+ if (ret)
+ return ret;
ret = regmap_read(cs40l26->regmap, reg +
CS40L26_PM_STDBY_TIMEOUT_LOWER_OFFSET, &lower_val);
@@ -405,27 +367,21 @@ static int cs40l26_dsp_shutdown(struct cs40l26_private *cs40l26)
static int cs40l26_dsp_pre_config(struct cs40l26_private *cs40l26)
{
+ u32 halo_state, timeout_ms;
u8 dsp_state;
- u32 halo_state, halo_state_reg;
- int ret;
+ int ret, i;
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- halo_state_reg = CS40L26_A0_DSP_HALO_STATE_REG;
- break;
- case CS40L26_REVID_A1:
- halo_state_reg = CS40L26_A1_DSP_HALO_STATE_REG;
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
+ ret = cs40l26_pm_state_transition(cs40l26,
+ CS40L26_PM_STATE_PREVENT_HIBERNATE);
+ if (ret)
+ return ret;
- ret = regmap_read(cs40l26->regmap, halo_state_reg,
+ ret = regmap_read(cs40l26->regmap, CS40L26_A1_DSP_HALO_STATE_REG,
&halo_state);
- if (ret)
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get HALO state\n");
return ret;
+ }
if (halo_state != CS40L26_DSP_HALO_STATE_RUN) {
dev_err(cs40l26->dev, "DSP not Ready: HALO_STATE: %08X\n",
@@ -433,24 +389,34 @@ static int cs40l26_dsp_pre_config(struct cs40l26_private *cs40l26)
return -EINVAL;
}
- ret = cs40l26_pm_state_transition(cs40l26,
- CS40L26_PM_STATE_PREVENT_HIBERNATE);
- if (ret)
- return ret;
- ret = cs40l26_dsp_state_get(cs40l26, &dsp_state);
+ ret = cs40l26_pm_timeout_ms_get(cs40l26, &timeout_ms);
if (ret)
return ret;
- if (dsp_state != CS40L26_DSP_STATE_SHUTDOWN &&
- dsp_state != CS40L26_DSP_STATE_STANDBY) {
- dev_err(cs40l26->dev, "DSP core not safe to kill\n");
+ for (i = 0; i < 10; i++) {
+ ret = cs40l26_dsp_state_get(cs40l26, &dsp_state);
+ if (ret)
+ return ret;
+
+ if (dsp_state != CS40L26_DSP_STATE_SHUTDOWN &&
+ dsp_state != CS40L26_DSP_STATE_STANDBY)
+ dev_warn(cs40l26->dev, "DSP core not safe to kill\n");
+ else
+ break;
+
+ usleep_range(CS40L26_MS_TO_US(timeout_ms),
+ CS40L26_MS_TO_US(timeout_ms) + 100);
+ }
+
+ if (i == 10) {
+ dev_err(cs40l26->dev, "DSP Core could not be shut down\n");
return -EINVAL;
}
/* errata write fixing indeterminent PLL lock time */
ret = regmap_update_bits(cs40l26->regmap, CS40L26_PLL_REFCLK_DETECT_0,
- CS40L26_PLL_REFCLK_DET_EN_MASK, CS40L26_DISABLE);
+ CS40L26_PLL_REFCLK_DET_EN_MASK, 0);
if (ret) {
dev_err(cs40l26->dev, "Failed to disable PLL refclk detect\n");
return ret;
@@ -588,6 +554,12 @@ static int cs40l26_handle_mbox_buffer(struct cs40l26_private *cs40l26)
return -EINVAL;
}
break;
+ case CS40L26_DSP_MBOX_LE_EST_START:
+ dev_dbg(dev, "LE_EST_START\n");
+ break;
+ case CS40L26_DSP_MBOX_LE_EST_DONE:
+ dev_dbg(dev, "LE_EST_DONE\n");
+ break;
case CS40L26_DSP_MBOX_SYS_ACK:
dev_err(dev, "Mbox buffer value (0x%X) not supported\n",
val);
@@ -855,8 +827,7 @@ static int cs40l26_handle_irq1(struct cs40l26_private *cs40l26,
CS40L26_WKSRC_STS_SHIFT);
ret = cl_dsp_get_reg(cs40l26->dsp, "LAST_WAKESRC_CTL",
- CL_DSP_XM_UNPACKED_TYPE,
- CS40L26_FW_ID, &reg);
+ CL_DSP_XM_UNPACKED_TYPE, cs40l26->fw.id, &reg);
if (ret)
goto err;
@@ -1200,173 +1171,50 @@ err:
return (irq1_count + irq2_count) ? IRQ_HANDLED : IRQ_NONE;
}
-static bool cs40l26_pseq_v1_addr_exists(struct cs40l26_private *cs40l26,
- u16 addr, int *index)
-{
- int i;
-
- if (cs40l26->pseq_v1_len == 0)
- return false;
-
- for (i = 0; i < cs40l26->pseq_v1_len; i++) {
- if (cs40l26->pseq_v1_table[i].addr == addr) {
- *index = i;
- return true;
- }
- }
-
- *index = -1;
-
- return false;
-}
-
-static int cs40l26_pseq_v1_write(struct cs40l26_private *cs40l26,
- unsigned int pseq_v1_offset)
-{
- struct regmap *regmap = cs40l26->regmap;
- unsigned int len = cs40l26->pseq_v1_len;
- struct device *dev = cs40l26->dev;
- u32 val;
- u16 addr;
- int ret;
-
- addr = cs40l26->pseq_v1_table[pseq_v1_offset].addr;
- val = cs40l26->pseq_v1_table[pseq_v1_offset].val;
-
- /* the "upper half" first 24-bit word of the sequence pair is written
- * to the write sequencer as: [23-16] addr{15-0},
- * [15-0] val{31-24} with bits [24-31] acting as a buffer
- */
- ret = regmap_write(regmap, cs40l26->pseq_base +
- (pseq_v1_offset * CS40L26_PSEQ_V1_STRIDE),
- (addr << CS40L26_PSEQ_V1_ADDR_SHIFT) |
- ((val & ~CS40L26_PSEQ_V1_VAL_MASK)
- >> CS40L26_PSEQ_V1_VAL_SHIFT));
- if (ret) {
- dev_err(dev, "Failed to write power on seq. (upper half)\n");
- return ret;
- }
-
- /* the "lower half" of the address-value pair is written to the write
- * sequencer as: [23-0] data{23-0} with bits [24-31] acting as a buffer
- */
- ret = regmap_write(regmap, cs40l26->pseq_base + CL_DSP_BYTES_PER_WORD
- + (pseq_v1_offset * CS40L26_PSEQ_V1_STRIDE),
- val & CS40L26_PSEQ_V1_VAL_MASK);
- if (ret) {
- dev_err(dev, "Failed to write power on seq. (lower half)\n");
- return ret;
- }
-
- /* end of sequence must be marked by list terminator */
- ret = regmap_write(regmap, cs40l26->pseq_base +
- (len * CS40L26_PSEQ_V1_STRIDE),
- CS40L26_PSEQ_V1_LIST_TERM);
- if (ret)
- dev_err(dev, "Failed to write power on seq. terminator\n");
-
- return ret;
-}
-
-static int cs40l26_pseq_v1_add_pair(struct cs40l26_private *cs40l26, u16 addr,
- u32 val, bool replace)
-{
- unsigned int len = cs40l26->pseq_v1_len;
- struct device *dev = cs40l26->dev;
- unsigned int pseq_v1_offset, prev_val;
- int ret, index;
-
- if (len >= CS40L26_PSEQ_V1_MAX_ENTRIES) {
- dev_err(dev, "Power on seq. exceeded max number of entries\n");
- return -E2BIG;
- }
-
- if (cs40l26_pseq_v1_addr_exists(cs40l26, addr, &index) && replace) {
- prev_val = cs40l26->pseq_v1_table[index].val;
- cs40l26->pseq_v1_table[index].val = val;
- pseq_v1_offset = index;
- } else {
- cs40l26->pseq_v1_table[len].addr = addr;
- cs40l26->pseq_v1_table[len].val = val;
- cs40l26->pseq_v1_len++;
- pseq_v1_offset = len;
- }
-
- ret = cs40l26_pseq_v1_write(cs40l26, pseq_v1_offset);
- if (ret) { /* If an error occurs during write, reset the sequence */
- if (index < 0) { /* No previous value for this address */
- cs40l26->pseq_v1_table[len].addr = 0;
- cs40l26->pseq_v1_table[len].val = 0;
- cs40l26->pseq_v1_len--;
- } else {
- cs40l26->pseq_v1_table[index].val = prev_val;
- }
- }
-
- return ret;
-}
-
-int cs40l26_pseq_v1_multi_add_pair(struct cs40l26_private *cs40l26,
- const struct reg_sequence *reg_seq, int num_regs, bool replace)
-{
- int ret, i;
-
- for (i = 0; i < num_regs; i++) {
- ret = cs40l26_pseq_v1_add_pair(cs40l26, (u16) (reg_seq[i].reg &
- CS40L26_PSEQ_V1_ADDR_MASK), reg_seq[i].def,
- replace);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(cs40l26_pseq_v1_multi_add_pair);
-
-static int cs40l26_pseq_v2_add_op(struct cs40l26_private *cs40l26,
+static int cs40l26_pseq_add_op(struct cs40l26_private *cs40l26,
int num_words, u32 *words)
{
struct regmap *regmap = cs40l26->regmap;
struct device *dev = cs40l26->dev;
u32 offset_for_new_op, *op_words;
int ret;
- struct cs40l26_pseq_v2_op *pseq_v2_op_end, *pseq_v2_op_new, *op;
+ struct cs40l26_pseq_op *pseq_op_end, *pseq_op_new, *op;
/* get location of the list terminator */
- list_for_each_entry(pseq_v2_op_end, &cs40l26->pseq_v2_op_head, list) {
- if (pseq_v2_op_end->operation == CS40L26_PSEQ_V2_OP_END)
+ list_for_each_entry(pseq_op_end, &cs40l26->pseq_op_head, list) {
+ if (pseq_op_end->operation == CS40L26_PSEQ_OP_END)
break;
}
- if (pseq_v2_op_end->operation != CS40L26_PSEQ_V2_OP_END) {
+ if (pseq_op_end->operation != CS40L26_PSEQ_OP_END) {
dev_err(dev, "Failed to find END_OF_SCRIPT\n");
return -EINVAL;
}
- offset_for_new_op = pseq_v2_op_end->offset;
+ offset_for_new_op = pseq_op_end->offset;
/* add new op to list */
op_words = kzalloc(num_words * CL_DSP_BYTES_PER_WORD, GFP_KERNEL);
if (!op_words)
return -ENOMEM;
memcpy(op_words, words, num_words * CL_DSP_BYTES_PER_WORD);
- pseq_v2_op_new = devm_kzalloc(dev, sizeof(*pseq_v2_op_new), GFP_KERNEL);
- if (!pseq_v2_op_new) {
+ pseq_op_new = devm_kzalloc(dev, sizeof(*pseq_op_new), GFP_KERNEL);
+ if (!pseq_op_new) {
ret = -ENOMEM;
goto err_free;
}
- pseq_v2_op_new->size = num_words;
- pseq_v2_op_new->offset = offset_for_new_op;
- pseq_v2_op_new->words = op_words;
- list_add(&pseq_v2_op_new->list, &cs40l26->pseq_v2_op_head);
+ pseq_op_new->size = num_words;
+ pseq_op_new->offset = offset_for_new_op;
+ pseq_op_new->words = op_words;
+ list_add(&pseq_op_new->list, &cs40l26->pseq_op_head);
- cs40l26->pseq_v2_num_ops++;
+ cs40l26->pseq_num_ops++;
/* bump end of script offset to accomodate new operation */
- pseq_v2_op_end->offset += num_words * CL_DSP_BYTES_PER_WORD;
+ pseq_op_end->offset += num_words * CL_DSP_BYTES_PER_WORD;
- list_for_each_entry(op, &cs40l26->pseq_v2_op_head, list) {
+ list_for_each_entry(op, &cs40l26->pseq_op_head, list) {
if (op->offset >= offset_for_new_op) {
ret = regmap_bulk_write(regmap, cs40l26->pseq_base +
op->offset,
@@ -1387,22 +1235,22 @@ err_free:
return ret;
}
-static int cs40l26_pseq_v2_add_write_reg_full(struct cs40l26_private *cs40l26,
+static int cs40l26_pseq_add_write_reg_full(struct cs40l26_private *cs40l26,
u32 addr, u32 data, bool update_if_op_already_in_seq)
{
int ret;
- struct cs40l26_pseq_v2_op *op;
- u32 op_words[CS40L26_PSEQ_V2_OP_WRITE_REG_FULL_WORDS];
+ struct cs40l26_pseq_op *op;
+ u32 op_words[CS40L26_PSEQ_OP_WRITE_REG_FULL_WORDS];
- op_words[0] = (CS40L26_PSEQ_V2_OP_WRITE_REG_FULL <<
- CS40L26_PSEQ_V2_OP_SHIFT);
+ op_words[0] = (CS40L26_PSEQ_OP_WRITE_REG_FULL <<
+ CS40L26_PSEQ_OP_SHIFT);
op_words[0] |= addr >> 16;
op_words[1] = (addr & 0x0000FFFF) << 8;
op_words[1] |= (data & 0xFF000000) >> 24;
op_words[2] = (data & 0x00FFFFFF);
if (update_if_op_already_in_seq) {
- list_for_each_entry(op, &cs40l26->pseq_v2_op_head, list) {
+ list_for_each_entry(op, &cs40l26->pseq_op_head, list) {
/* check if op with same op and addr already exists */
if ((op->words[0] == op_words[0]) &&
((op->words[1] & 0xFFFFFF00) ==
@@ -1420,21 +1268,21 @@ static int cs40l26_pseq_v2_add_write_reg_full(struct cs40l26_private *cs40l26,
}
/* if no matching op is found or !update, add the op */
- ret = cs40l26_pseq_v2_add_op(cs40l26,
- CS40L26_PSEQ_V2_OP_WRITE_REG_FULL_WORDS,
+ ret = cs40l26_pseq_add_op(cs40l26,
+ CS40L26_PSEQ_OP_WRITE_REG_FULL_WORDS,
op_words);
return ret;
}
-int cs40l26_pseq_v2_multi_add_write_reg_full(struct cs40l26_private *cs40l26,
+int cs40l26_pseq_multi_add_write_reg_full(struct cs40l26_private *cs40l26,
const struct reg_sequence *reg_seq, int num_regs,
bool update_if_op_already_in_seq)
{
int ret, i;
for (i = 0; i < num_regs; i++) {
- ret = cs40l26_pseq_v2_add_write_reg_full(cs40l26,
+ ret = cs40l26_pseq_add_write_reg_full(cs40l26,
reg_seq[i].reg, reg_seq[i].def,
update_if_op_already_in_seq);
if (ret)
@@ -1443,94 +1291,77 @@ int cs40l26_pseq_v2_multi_add_write_reg_full(struct cs40l26_private *cs40l26,
return 0;
}
-EXPORT_SYMBOL(cs40l26_pseq_v2_multi_add_write_reg_full);
+EXPORT_SYMBOL(cs40l26_pseq_multi_add_write_reg_full);
-static int cs40l26_pseq_v1_init(struct cs40l26_private *cs40l26)
+/* 24-bit address, 16-bit data */
+static int cs40l26_pseq_add_write_reg_h16(struct cs40l26_private *cs40l26,
+ u32 addr, u16 data, bool update_if_op_already_in_seq)
{
+ int ret;
struct device *dev = cs40l26->dev;
- int ret, i, index = 0;
- u8 upper_val = 0;
- u16 addr = 0;
- u32 val, word, algo_id;
-
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- algo_id = CS40L26_PM_ALGO_ID;
- else
- algo_id = CS40L26_PM_ROM_ALGO_ID;
-
- ret = cl_dsp_get_reg(cs40l26->dsp, "POWER_ON_SEQUENCE",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &cs40l26->pseq_base);
- if (ret)
- return ret;
-
- for (i = 0; i < CS40L26_PSEQ_V1_MAX_WRITES; i++) {
- ret = regmap_read(cs40l26->regmap,
- cs40l26->pseq_base +
- (i * CL_DSP_BYTES_PER_WORD), &word);
- if (ret) {
- dev_err(dev, "Failed to read from power on seq.\n");
- return ret;
- }
-
- if ((word & CS40L26_PSEQ_V1_LIST_TERM_MASK) ==
- CS40L26_PSEQ_V1_LIST_TERM)
- break;
+ struct cs40l26_pseq_op *op;
+ u32 op_words[CS40L26_PSEQ_OP_WRITE_REG_H16_WORDS];
- if (i % CS40L26_PSEQ_V1_PAIR_NUM_WORDS) { /* lower half */
- index = i / CS40L26_PSEQ_V1_PAIR_NUM_WORDS;
- val = (upper_val << CS40L26_PSEQ_V1_VAL_SHIFT) |
- (word & CS40L26_PSEQ_V1_VAL_MASK);
+ if (addr & 0xFF000000) {
+ dev_err(dev, "invalid address for pseq write_reg_h16\n");
+ return -EINVAL;
+ }
- cs40l26->pseq_v1_table[index].addr = addr;
- cs40l26->pseq_v1_table[index].val = val;
- } else { /* upper half */
- addr = (word & CS40L26_PSEQ_V1_ADDR_WORD_MASK) >>
- CS40L26_PSEQ_V1_ADDR_SHIFT;
+ op_words[0] = (CS40L26_PSEQ_OP_WRITE_REG_H16 <<
+ CS40L26_PSEQ_OP_SHIFT);
+ op_words[0] |= (addr & 0x00FFFF00) >> 8;
+ op_words[1] = (addr & 0x000000FF) << 16;
+ op_words[1] |= data;
- upper_val = word & CS40L26_PSEQ_V1_VAL_WORD_UPPER_MASK;
+ if (update_if_op_already_in_seq) {
+ list_for_each_entry(op, &cs40l26->pseq_op_head, list) {
+ /* check if op with same op and addr already exists */
+ if ((op->words[0] == op_words[0]) &&
+ ((op->words[1] & 0x00FF0000) ==
+ (op_words[1] & 0x00FF0000))) {
+ /* update data in the existing op and return */
+ ret = regmap_bulk_write(cs40l26->regmap,
+ cs40l26->pseq_base + op->offset,
+ op_words, op->size);
+ if (ret)
+ dev_err(cs40l26->dev,
+ "Failed to update op\n");
+ return ret;
+ }
}
}
- if (i >= CS40L26_PSEQ_V1_MAX_WRITES) {
- dev_err(dev, "Original sequence exceeds max # of entries\n");
- return -E2BIG;
- }
-
- ret = regmap_write(cs40l26->regmap, cs40l26->pseq_base +
- (i * CL_DSP_BYTES_PER_WORD), CS40L26_PSEQ_V1_LIST_TERM);
- if (ret)
- return ret;
+ /* if no matching op is found or !update, add the op */
+ ret = cs40l26_pseq_add_op(cs40l26,
+ CS40L26_PSEQ_OP_WRITE_REG_H16_WORDS,
+ op_words);
- cs40l26->pseq_v1_len = index + 1;
- return 0;
+ return ret;
}
-static int cs40l26_pseq_v2_init(struct cs40l26_private *cs40l26)
+static int cs40l26_pseq_init(struct cs40l26_private *cs40l26)
{
struct device *dev = cs40l26->dev;
+ u32 words[CS40L26_PSEQ_MAX_WORDS], *op_words;
+ struct cs40l26_pseq_op *pseq_op;
int ret, i, j, num_words, read_size;
u8 operation;
- u32 words[CS40L26_PSEQ_V2_MAX_WORDS], algo_id, *op_words;
- struct cs40l26_pseq_v2_op *pseq_v2_op;
-
- INIT_LIST_HEAD(&cs40l26->pseq_v2_op_head);
- cs40l26->pseq_v2_num_ops = 0;
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- algo_id = CS40L26_PM_ALGO_ID;
- else
- algo_id = CS40L26_PM_ROM_ALGO_ID;
+ INIT_LIST_HEAD(&cs40l26->pseq_op_head);
+ cs40l26->pseq_num_ops = 0;
ret = cl_dsp_get_reg(cs40l26->dsp, "POWER_ON_SEQUENCE",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &cs40l26->pseq_base);
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_PM_ALGO_ID,
+ &cs40l26->pseq_base);
if (ret)
return ret;
/* read pseq memory space */
i = 0;
- while (i < CS40L26_PSEQ_V2_MAX_WORDS) {
+ while (i < CS40L26_PSEQ_MAX_WORDS) {
read_size = min(CS40L26_MAX_I2C_READ_SIZE_BYTES,
- CS40L26_PSEQ_V2_MAX_WORDS - i);
+ CS40L26_PSEQ_MAX_WORDS - i);
+
ret = regmap_bulk_read(cs40l26->regmap,
cs40l26->pseq_base + i * CL_DSP_BYTES_PER_WORD,
words + i,
@@ -1543,20 +1374,20 @@ static int cs40l26_pseq_v2_init(struct cs40l26_private *cs40l26)
}
i = 0;
- while (i < CS40L26_PSEQ_V2_MAX_WORDS) {
- operation = (words[i] & CS40L26_PSEQ_V2_OP_MASK) >>
- CS40L26_PSEQ_V2_OP_SHIFT;
+ while (i < CS40L26_PSEQ_MAX_WORDS) {
+ operation = (words[i] & CS40L26_PSEQ_OP_MASK) >>
+ CS40L26_PSEQ_OP_SHIFT;
/* get num words for given operation */
- for (j = 0; j < CS40L26_PSEQ_V2_NUM_OPS; j++) {
- if (cs40l26_pseq_v2_op_sizes[j][0] == operation) {
- num_words = cs40l26_pseq_v2_op_sizes[j][1];
+ for (j = 0; j < CS40L26_PSEQ_NUM_OPS; j++) {
+ if (cs40l26_pseq_op_sizes[j][0] == operation) {
+ num_words = cs40l26_pseq_op_sizes[j][1];
break;
}
}
- if (j == CS40L26_PSEQ_V2_NUM_OPS) {
- dev_err(dev, "Failed to determine pseq_v2 op size\n");
+ if (j == CS40L26_PSEQ_NUM_OPS) {
+ dev_err(dev, "Failed to determine pseq op size\n");
return -EINVAL;
}
@@ -1566,37 +1397,28 @@ static int cs40l26_pseq_v2_init(struct cs40l26_private *cs40l26)
return -ENOMEM;
memcpy(op_words, &words[i], num_words * CL_DSP_BYTES_PER_WORD);
- pseq_v2_op = devm_kzalloc(dev, sizeof(*pseq_v2_op), GFP_KERNEL);
- if (!pseq_v2_op) {
+ pseq_op = devm_kzalloc(dev, sizeof(*pseq_op), GFP_KERNEL);
+ if (!pseq_op) {
ret = -ENOMEM;
goto err_free;
}
- pseq_v2_op->size = num_words;
- pseq_v2_op->offset = i * CL_DSP_BYTES_PER_WORD;
- pseq_v2_op->operation = operation;
- pseq_v2_op->words = op_words;
- list_add(&pseq_v2_op->list, &cs40l26->pseq_v2_op_head);
+ pseq_op->size = num_words;
+ pseq_op->offset = i * CL_DSP_BYTES_PER_WORD;
+ pseq_op->operation = operation;
+ pseq_op->words = op_words;
+ list_add(&pseq_op->list, &cs40l26->pseq_op_head);
- cs40l26->pseq_v2_num_ops++;
+ cs40l26->pseq_num_ops++;
i += num_words;
- if (operation == CS40L26_PSEQ_V2_OP_END)
+ if (operation == CS40L26_PSEQ_OP_END)
break;
}
- dev_dbg(dev, "PSEQ_V2 num ops: %d\n", cs40l26->pseq_v2_num_ops);
- dev_dbg(dev, "offset\tsize\twords\n");
- list_for_each_entry(pseq_v2_op, &cs40l26->pseq_v2_op_head, list) {
- dev_dbg(dev, "0x%04X\t%d", pseq_v2_op->offset,
- pseq_v2_op->size);
- for (j = 0; j < pseq_v2_op->size; j++)
- dev_dbg(dev, "0x%08X", *(pseq_v2_op->words + j));
- }
-
- if (operation != CS40L26_PSEQ_V2_OP_END) {
- dev_err(dev, "PSEQ_V2 END_OF_SCRIPT not found\n");
+ if (operation != CS40L26_PSEQ_OP_END) {
+ dev_err(dev, "PSEQ END_OF_SCRIPT not found\n");
return -E2BIG;
}
@@ -1608,25 +1430,107 @@ err_free:
return ret;
}
-static int cs40l26_pseq_init(struct cs40l26_private *cs40l26)
+static int cs40l26_update_reg_defaults_via_pseq(struct cs40l26_private *cs40l26)
{
+ struct device *dev = cs40l26->dev;
int ret;
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_init(cs40l26);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_init(cs40l26);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
+ /* set SPK_DEFAULT_HIZ to 1 */
+ ret = cs40l26_pseq_add_write_reg_h16(cs40l26,
+ CS40L26_TST_DAC_MSM_CONFIG,
+ CS40L26_TST_DAC_MSM_CONFIG_DEFAULT_CHANGE_VALUE_H16,
+ true);
+ if (ret)
+ dev_err(dev, "Failed to sequence register default updates\n");
+
+ return ret;
+}
+
+static int cs40l26_buzzgen_set(struct cs40l26_private *cs40l26, u16 freq,
+ u16 level, u16 duration, u8 offset)
+{
+ int ret;
+ unsigned int base_reg, offset_reg;
+
+ ret = cl_dsp_get_reg(cs40l26->dsp, "BUZZ_EFFECTS1_BUZZ_FREQ",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_BUZZGEN_ALGO_ID, &base_reg);
+ if (ret)
+ return ret;
+
+ offset_reg = base_reg + (offset * 12);
+
+ ret = regmap_write(cs40l26->regmap, offset_reg, freq);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to write BUZZGEN frequency\n");
+ return ret;
+ }
+
+ ret = regmap_write(cs40l26->regmap, offset_reg + 4,
+ CS40L26_BUZZGEN_LEVEL_DEFAULT);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to write BUZZGEN level\n");
+ return ret;
+ }
+
+ ret = regmap_write(cs40l26->regmap, offset_reg + 8, duration / 4);
+ if (ret)
+ dev_err(cs40l26->dev, "Failed to write BUZZGEN duration\n");
+
+ return ret;
+}
+
+static int cs40l26_gpio_index_set(struct cs40l26_private *cs40l26,
+ struct ff_effect *effect)
+{
+ u16 button = effect->trigger.button;
+ u8 bank = (button & CS40L26_BTN_BANK_MASK) >> CS40L26_BTN_BANK_SHIFT;
+ u8 edge = (button & CS40L26_BTN_EDGE_MASK) >> CS40L26_BTN_EDGE_SHIFT;
+ u8 gpio = (button & CS40L26_BTN_NUM_MASK) >> CS40L26_BTN_NUM_SHIFT;
+ u8 index = button & CS40L26_BTN_INDEX_MASK;
+ u8 buzz = button & CS40L26_BTN_BUZZ_MASK;
+ u16 write_val, freq;
+ u8 offset;
+ u32 reg;
+ int ret;
+
+ if (gpio != 1) {
+ dev_err(cs40l26->dev, "GPIO%u not supported on 0x%02X\n", gpio,
+ cs40l26->revid);
+ return -EINVAL;
+ }
+
+ if (edge > 1) {
+ dev_err(cs40l26->dev, "Invalid GPI edge %u\n", edge);
return -EINVAL;
}
+ offset = ((edge ^ 1)) * 4;
+ reg = cs40l26->event_map_base + offset;
+
+ pm_runtime_get_sync(cs40l26->dev);
+
+ if (buzz) {
+ freq = CS40L26_MS_TO_HZ(effect->u.periodic.period);
+
+ ret = cs40l26_buzzgen_set(cs40l26, freq,
+ CS40L26_BUZZGEN_LEVEL_DEFAULT,
+ effect->replay.length, 0);
+ if (ret)
+ goto pm_err;
+
+ write_val = 1 << CS40L26_BTN_BUZZ_SHIFT;
+ } else {
+ write_val = index | (bank << CS40L26_BTN_BANK_SHIFT);
+ }
+
+ ret = regmap_update_bits(cs40l26->regmap, reg,
+ CS40L26_EVENT_MAP_INDEX_MASK, write_val);
if (ret)
- dev_err(cs40l26->dev, "Failed to init pseq\n");
+ dev_err(cs40l26->dev, "Failed to update event map\n");
+
+pm_err:
+ pm_runtime_mark_last_busy(cs40l26->dev);
+ pm_runtime_put_autosuspend(cs40l26->dev);
return ret;
}
@@ -1635,53 +1539,22 @@ static void cs40l26_set_gain_worker(struct work_struct *work)
{
struct cs40l26_private *cs40l26 =
container_of(work, struct cs40l26_private, set_gain_work);
- u16 amp_vol_pcm;
- u32 reg, val;
+ u32 reg;
int ret;
pm_runtime_get_sync(cs40l26->dev);
mutex_lock(&cs40l26->lock);
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- amp_vol_pcm = CS40L26_AMP_VOL_PCM_MAX & cs40l26->gain_pct;
-
- ret = regmap_update_bits(cs40l26->regmap, CS40L26_AMP_CTRL,
- CS40L26_AMP_CTRL_VOL_PCM_MASK, amp_vol_pcm <<
- CS40L26_AMP_CTRL_VOL_PCM_SHIFT);
- if (ret) {
- dev_err(cs40l26->dev, "Failed to update digtal gain\n");
- goto err_mutex;
- }
-
- ret = regmap_read(cs40l26->regmap, CS40L26_AMP_CTRL, &val);
- if (ret) {
- dev_err(cs40l26->dev, "Failed to read AMP control\n");
- goto err_mutex;
- }
-
- ret = cs40l26_pseq_v1_add_pair(cs40l26,
- CS40L26_AMP_CTRL, val, true);
- if (ret)
- dev_err(cs40l26->dev, "Failed to set gain in pseq\n");
- break;
- case CS40L26_REVID_A1:
- val = cs40l26_attn_q21_2_vals[cs40l26->gain_pct];
-
- /* Write Q21.2 value to SOURCE_ATTENUATION */
- ret = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_ATTENUATION",
+ /* Write Q21.2 value to SOURCE_ATTENUATION */
+ ret = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_ATTENUATION",
CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
- if (ret)
- goto err_mutex;
+ if (ret)
+ goto err_mutex;
- ret = regmap_write(cs40l26->regmap, reg, val);
- if (ret)
- dev_err(cs40l26->dev, "Failed to set attenuation\n");
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- }
+ ret = regmap_write(cs40l26->regmap, reg,
+ cs40l26_attn_q21_2_vals[cs40l26->gain_pct]);
+ if (ret)
+ dev_err(cs40l26->dev, "Failed to set attenuation\n");
err_mutex:
mutex_unlock(&cs40l26->lock);
@@ -1694,15 +1567,13 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
struct cs40l26_private *cs40l26 = container_of(work,
struct cs40l26_private, vibe_start_work);
struct device *dev = cs40l26->dev;
+ u32 index = 0;
int ret = 0;
unsigned int reg, freq;
- u32 index = 0, buzz_id;
+ bool invert;
u16 duration;
- if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM)
- buzz_id = CS40L26_BUZZGEN_ALGO_ID;
- else
- buzz_id = CS40L26_BUZZGEN_ROM_ALGO_ID;
+ dev_dbg(dev, "%s\n", __func__);
if (cs40l26->effect->u.periodic.waveform == FF_CUSTOM)
index = cs40l26->trigger_indices[cs40l26->effect->id];
@@ -1721,6 +1592,29 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
ktime_set(CS40L26_MS_TO_SECS(duration),
CS40L26_MS_TO_NS(duration % 1000)), HRTIMER_MODE_REL);
+ ret = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_INVERT",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
+ if (ret)
+ goto err_mutex;
+
+ switch (cs40l26->effect->direction) {
+ case 0x0000:
+ invert = false;
+ break;
+ case 0x8000:
+ invert = true;
+ break;
+ default:
+ dev_err(dev, "Invalid ff_effect direction: 0x%X\n",
+ cs40l26->effect->direction);
+ ret = -EINVAL;
+ goto err_mutex;
+ }
+
+ ret = regmap_write(cs40l26->regmap, reg, invert);
+ if (ret)
+ goto err_mutex;
+
cs40l26_vibe_state_set(cs40l26, CS40L26_VIBE_STATE_HAPTIC);
switch (cs40l26->effect->u.periodic.waveform) {
@@ -1731,26 +1625,10 @@ static void cs40l26_vibe_start_worker(struct work_struct *work)
goto err_mutex;
break;
case FF_SINE:
- ret = cl_dsp_get_reg(cs40l26->dsp, "BUZZ_EFFECTS2_BUZZ_FREQ",
- CL_DSP_XM_UNPACKED_TYPE, buzz_id, &reg);
- if (ret)
- goto err_mutex;
-
freq = CS40L26_MS_TO_HZ(cs40l26->effect->u.periodic.period);
- ret = regmap_write(cs40l26->regmap, reg, freq);
- if (ret)
- goto err_mutex;
-
- ret = regmap_write(cs40l26->regmap, reg +
- CS40L26_BUZZGEN_LEVEL_OFFSET,
- CS40L26_BUZZGEN_LEVEL_DEFAULT);
- if (ret)
- goto err_mutex;
-
- ret = regmap_write(cs40l26->regmap, reg +
- CS40L26_BUZZGEN_DURATION_OFFSET, duration /
- CS40L26_BUZZGEN_DURATION_DIV_STEP);
+ ret = cs40l26_buzzgen_set(cs40l26, freq,
+ CS40L26_BUZZGEN_LEVEL_DEFAULT, duration, 1);
if (ret)
goto err_mutex;
@@ -1781,9 +1659,10 @@ static void cs40l26_vibe_stop_worker(struct work_struct *work)
struct cs40l26_private *cs40l26 = container_of(work,
struct cs40l26_private, vibe_stop_work);
unsigned int reg;
- u32 algo_id;
int ret;
+ dev_dbg(cs40l26->dev, "%s\n", __func__);
+
pm_runtime_get_sync(cs40l26->dev);
mutex_lock(&cs40l26->lock);
@@ -1795,13 +1674,8 @@ static void cs40l26_vibe_stop_worker(struct work_struct *work)
goto mutex_exit;
}
} else {
- if (cs40l26->fw_mode == CS40L26_FW_MODE_ROM)
- algo_id = CS40L26_VIBEGEN_ROM_ALGO_ID;
- else
- algo_id = CS40L26_VIBEGEN_ALGO_ID;
-
ret = cl_dsp_get_reg(cs40l26->dsp, "END_PLAYBACK",
- CL_DSP_XM_UNPACKED_TYPE, algo_id, &reg);
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_VIBEGEN_ALGO_ID, &reg);
if (ret)
goto mutex_exit;
@@ -1840,6 +1714,11 @@ static void cs40l26_set_gain(struct input_dev *dev, u16 gain)
{
struct cs40l26_private *cs40l26 = input_get_drvdata(dev);
+ if (gain < 0 || gain >= CS40L26_NUM_PCT_MAP_VALUES) {
+ dev_err(cs40l26->dev, "Gain value %u out of bounds\n", gain);
+ return;
+ }
+
cs40l26->gain_pct = gain;
queue_work(cs40l26->vibe_workqueue, &cs40l26->set_gain_work);
@@ -1851,6 +1730,9 @@ static int cs40l26_playback_effect(struct input_dev *dev,
struct cs40l26_private *cs40l26 = input_get_drvdata(dev);
struct ff_effect *effect;
+ dev_dbg(cs40l26->dev, "%s: effect ID = %d, val = %d\n", __func__,
+ effect_id, val);
+
effect = &dev->ff->effects[effect_id];
if (!effect) {
dev_err(cs40l26->dev, "No such effect to playback\n");
@@ -2217,6 +2099,8 @@ static int cs40l26_upload_effect(struct input_dev *dev,
goto out_free;
}
+ dev_dbg(cdev, "%s: ID = %u, index = 0x%08X\n",
+ __func__, effect->id, trigger_index);
break;
case FF_SINE:
if (effect->u.periodic.period) {
@@ -2240,6 +2124,10 @@ static int cs40l26_upload_effect(struct input_dev *dev,
return -EINVAL;
}
+ if (effect->trigger.button)
+ ret = cs40l26_gpio_index_set(cs40l26, effect);
+
+
out_free:
kfree(raw_custom_data);
@@ -2353,12 +2241,9 @@ static int cs40l26_part_num_resolve(struct cs40l26_private *cs40l26)
}
val &= CS40L26_REVID_MASK;
- switch (val) {
- case CS40L26_REVID_A0:
- case CS40L26_REVID_A1:
+ if (val == CS40L26_REVID_A1) {
cs40l26->revid = val;
- break;
- default:
+ } else {
dev_err(dev, "Invalid device revision: 0x%02X\n", val);
return -EINVAL;
}
@@ -2369,31 +2254,46 @@ static int cs40l26_part_num_resolve(struct cs40l26_private *cs40l26)
return 0;
}
-static int cs40l26_cl_dsp_init(struct cs40l26_private *cs40l26)
+static int cs40l26_cl_dsp_init(struct cs40l26_private *cs40l26, u32 id)
{
int ret = 0;
+ if (cs40l26->dsp) {
+ ret = cl_dsp_destroy(cs40l26->dsp);
+ if (ret) {
+ dev_err(cs40l26->dev,
+ "Failed to destroy existing DSP structure\n");
+ return ret;
+ }
+ cs40l26->dsp = NULL;
+ }
+
cs40l26->dsp = cl_dsp_create(cs40l26->dev, cs40l26->regmap);
- if (!cs40l26->dsp)
+ if (!cs40l26->dsp) {
+ dev_err(cs40l26->dev, "Failed to allocate space for DSP\n");
return -ENOMEM;
+ }
if (cs40l26->fw_mode == CS40L26_FW_MODE_ROM) {
+ cs40l26->fw.id = CS40L26_FW_ID;
cs40l26->fw.min_rev = CS40L26_FW_ROM_MIN_REV;
cs40l26->fw.num_coeff_files = 0;
- cs40l26->fw.coeff_files = NULL;
} else {
- if (cs40l26->revid == CS40L26_REVID_A1)
+ cs40l26->fw.id = id;
+
+ if (id == CS40L26_FW_ID)
cs40l26->fw.min_rev = CS40L26_FW_A1_RAM_MIN_REV;
- else
- cs40l26->fw.min_rev = CS40L26_FW_A0_RAM_MIN_REV;
+ if (id == CS40L26_FW_CALIB_ID)
+ cs40l26->fw.min_rev = CS40L26_FW_CALIB_MIN_REV;
- cs40l26->fw.num_coeff_files =
- ARRAY_SIZE(cs40l26_ram_coeff_files);
- cs40l26->fw.coeff_files = cs40l26_ram_coeff_files;
+ cs40l26->fw.num_coeff_files = 3;
+ cs40l26->fw.coeff_files[0] = CS40L26_WT_FILE_NAME;
+ cs40l26->fw.coeff_files[1] = CS40L26_A2H_TUNING_FILE_NAME;
+ cs40l26->fw.coeff_files[2] = CS40L26_SVC_TUNING_FILE_NAME;
ret = cl_dsp_wavetable_create(cs40l26->dsp,
CS40L26_VIBEGEN_ALGO_ID, CS40L26_WT_NAME_XM,
- CS40L26_WT_NAME_YM, "cs40l26.bin");
+ CS40L26_WT_NAME_YM, CS40L26_WT_FILE_NAME);
}
cs40l26->num_owt_effects = 0;
@@ -2434,6 +2334,13 @@ static int cs40l26_wksrc_config(struct cs40l26_private *cs40l26)
static int cs40l26_gpio_config(struct cs40l26_private *cs40l26)
{
u32 unmask_bits;
+ int ret;
+
+ ret = cl_dsp_get_reg(cs40l26->dsp, "ENT_MAP_TABLE_EVENT_DATA_PACKED",
+ CL_DSP_XM_UNPACKED_TYPE, CS40L26_EVENT_HANDLER_ALGO_ID,
+ &cs40l26->event_map_base);
+ if (ret)
+ return ret;
unmask_bits = BIT(CS40L26_IRQ1_GPIO1_RISE)
| BIT(CS40L26_IRQ1_GPIO1_FALL);
@@ -2474,21 +2381,8 @@ static int cs40l26_brownout_prevention_init(struct cs40l26_private *cs40l26)
return ret;
}
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_add_pair(cs40l26,
- CS40L26_BLOCK_ENABLES2, val, CS40L26_PSEQ_V1_REPLACE);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_add_write_reg_full(cs40l26,
- CS40L26_BLOCK_ENABLES2, val, true);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
-
+ ret = cs40l26_pseq_add_write_reg_full(cs40l26, CS40L26_BLOCK_ENABLES2,
+ val, true);
if (ret) {
dev_err(dev, "Failed to sequence brownout prevention\n");
return ret;
@@ -2592,22 +2486,8 @@ static int cs40l26_brownout_prevention_init(struct cs40l26_private *cs40l26)
return ret;
}
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_add_pair(cs40l26,
- CS40L26_VBBR_CONFIG, val,
- CS40L26_PSEQ_V1_REPLACE);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_add_write_reg_full(cs40l26,
- CS40L26_VBBR_CONFIG, val,
- true);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
+ ret = cs40l26_pseq_add_write_reg_full(cs40l26,
+ CS40L26_VBBR_CONFIG, val, true);
if (ret)
return ret;
}
@@ -2713,22 +2593,8 @@ static int cs40l26_brownout_prevention_init(struct cs40l26_private *cs40l26)
return ret;
}
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_add_pair(cs40l26,
- CS40L26_VPBR_CONFIG, val,
- CS40L26_PSEQ_V1_REPLACE);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_add_write_reg_full(cs40l26,
- CS40L26_VPBR_CONFIG, val,
- true);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- return -EINVAL;
- }
+ ret = cs40l26_pseq_add_write_reg_full(cs40l26,
+ CS40L26_VPBR_CONFIG, val, true);
if (ret)
return ret;
}
@@ -2761,7 +2627,7 @@ static int cs40l26_verify_fw(struct cs40l26_private *cs40l26)
if (ret)
return ret;
- if (val != CS40L26_FW_ID) {
+ if (val != cs40l26->fw.id) {
dev_err(cs40l26->dev, "Invalid firmware ID: 0x%X\n", val);
return -EINVAL;
}
@@ -2808,22 +2674,8 @@ static int cs40l26_asp_config(struct cs40l26_private *cs40l26)
goto err_free;
}
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_multi_add_pair(cs40l26, dsp1rx_config, 2,
- CS40L26_PSEQ_V1_REPLACE);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_multi_add_write_reg_full(cs40l26,
- dsp1rx_config, 2, true);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- ret = -EINVAL;
- goto err_free;
- }
-
+ ret = cs40l26_pseq_multi_add_write_reg_full(cs40l26, dsp1rx_config, 2,
+ true);
if (ret)
dev_err(cs40l26->dev, "Failed to add ASP config to pseq\n");
@@ -2854,25 +2706,36 @@ static int cs40l26_bst_dcm_config(struct cs40l26_private *cs40l26)
return ret;
}
- switch (cs40l26->revid) {
- case CS40L26_REVID_A0:
- ret = cs40l26_pseq_v1_add_pair(cs40l26,
- CS40L26_BST_DCM_CTL, val, true);
- break;
- case CS40L26_REVID_A1:
- ret = cs40l26_pseq_v2_add_write_reg_full(cs40l26,
- CS40L26_BST_DCM_CTL, val, true);
- break;
- default:
- dev_err(cs40l26->dev, "Revid ID not supported: %02X\n",
- cs40l26->revid);
- ret = -EINVAL;
- }
+ ret = cs40l26_pseq_add_write_reg_full(cs40l26,
+ CS40L26_BST_DCM_CTL, val, true);
}
return ret;
}
+static int cs40l26_bst_ipk_config(struct cs40l26_private *cs40l26)
+{
+ u32 val, bst_ipk_ma = cs40l26->pdata.bst_ipk / 1000;
+ int ret;
+
+ if (bst_ipk_ma < CS40L26_BST_IPK_MILLIAMP_MIN ||
+ bst_ipk_ma > CS40L26_BST_IPK_MILLIAMP_MAX) {
+ val = CS40L26_BST_IPK_DEFAULT;
+ dev_dbg(cs40l26->dev, "Using default BST_IPK\n");
+ } else {
+ val = (bst_ipk_ma / 50) - 16;
+ }
+
+ ret = regmap_write(cs40l26->regmap, CS40L26_BST_IPK_CTL, val);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to update BST peak current\n");
+ return ret;
+ }
+
+ return cs40l26_pseq_add_write_reg_full(cs40l26, CS40L26_BST_IPK_CTL,
+ val, true);
+}
+
static int cs40l26_dsp_config(struct cs40l26_private *cs40l26)
{
struct regmap *regmap = cs40l26->regmap;
@@ -2883,84 +2746,89 @@ static int cs40l26_dsp_config(struct cs40l26_private *cs40l26)
ret = cs40l26_verify_fw(cs40l26);
if (ret)
- goto err_out;
+ return ret;
ret = regmap_update_bits(regmap, CS40L26_PWRMGT_CTL,
- CS40L26_MEM_RDY_MASK,
- CS40L26_ENABLE << CS40L26_MEM_RDY_SHIFT);
+ CS40L26_MEM_RDY_MASK, 1 << CS40L26_MEM_RDY_SHIFT);
if (ret) {
dev_err(dev, "Failed to set MEM_RDY to initialize RAM\n");
- goto err_out;
+ return ret;
}
if (cs40l26->fw_mode == CS40L26_FW_MODE_RAM) {
ret = cl_dsp_get_reg(cs40l26->dsp, "CALL_RAM_INIT",
- CL_DSP_XM_UNPACKED_TYPE,
- CS40L26_FW_ID, &reg);
+ CL_DSP_XM_UNPACKED_TYPE, cs40l26->fw.id, &reg);
if (ret)
- goto err_out;
+ return ret;
- ret = cs40l26_dsp_write(cs40l26, reg, CS40L26_ENABLE);
+ ret = cs40l26_dsp_write(cs40l26, reg, 1);
if (ret)
- goto err_out;
+ return ret;
}
cs40l26->fw_loaded = true;
ret = cs40l26_dsp_start(cs40l26);
if (ret)
- goto err_out;
+ return ret;
ret = cs40l26_pseq_init(cs40l26);
if (ret)
- goto err_out;
+ return ret;
+
+ ret = cs40l26_update_reg_defaults_via_pseq(cs40l26);
+ if (ret)
+ return ret;
ret = cs40l26_iseq_init(cs40l26);
if (ret)
- goto err_out;
+ return ret;
ret = cs40l26_irq_update_mask(cs40l26, CS40L26_IRQ1_MASK_1,
BIT(CS40L26_IRQ1_VIRTUAL2_MBOX_WR), CS40L26_IRQ_UNMASK);
if (ret)
- goto err_out;
+ return ret;
ret = cs40l26_wksrc_config(cs40l26);
if (ret)
- goto err_out;
+ return ret;
ret = cs40l26_gpio_config(cs40l26);
if (ret)
- goto err_out;
+ return ret;
ret = cs40l26_bst_dcm_config(cs40l26);
if (ret)
- goto err_out;
+ return ret;
+
+ ret = cs40l26_bst_ipk_config(cs40l26);
+ if (ret)
+ return ret;
ret = cs40l26_brownout_prevention_init(cs40l26);
if (ret)
- goto err_out;
+ return ret;
/* ensure firmware running */
ret = cl_dsp_get_reg(cs40l26->dsp, "HALO_STATE",
- CL_DSP_XM_UNPACKED_TYPE, CS40L26_FW_ID,
- &reg);
+ CL_DSP_XM_UNPACKED_TYPE, cs40l26->fw.id, &reg);
if (ret)
- goto err_out;
+ return ret;
ret = regmap_read(regmap, reg, &val);
if (ret) {
dev_err(dev, "Failed to read HALO_STATE\n");
- goto err_out;
+ return ret;
}
if (val != CS40L26_DSP_HALO_STATE_RUN) {
dev_err(dev, "Firmware in unexpected state: 0x%X\n", val);
- goto err_out;
+ return ret;
}
ret = cs40l26_pm_runtime_setup(cs40l26);
if (ret)
- goto err_out;
+ return ret;
pm_runtime_get_sync(dev);
@@ -2987,47 +2855,149 @@ static int cs40l26_dsp_config(struct cs40l26_private *cs40l26)
pm_err:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
-err_out:
- enable_irq(cs40l26->irq);
+
return ret;
}
-static void cs40l26_firmware_load(const struct firmware *fw, void *context)
+static int cs40l26_svc_le_select(struct cs40l26_private *cs40l26)
{
- struct cs40l26_private *cs40l26 = (struct cs40l26_private *)context;
- struct device *dev = cs40l26->dev;
- const struct firmware *coeff_fw;
+ unsigned int reg, le_est = 0;
int ret, i;
- if (!fw) {
- dev_err(dev, "Failed to request firmware file\n");
- return;
- }
+ pm_runtime_get_sync(cs40l26->dev);
- cs40l26->pm_ready = false;
+ ret = cs40l26_ack_write(cs40l26, CS40L26_DSP_VIRTUAL1_MBOX_1,
+ CS40L26_DSP_MBOX_CMD_LE_EST, CS40L26_DSP_MBOX_RESET);
+ if (ret)
+ goto pm_err;
- ret = cl_dsp_firmware_parse(cs40l26->dsp, fw,
- cs40l26->fw_mode == CS40L26_FW_MODE_RAM);
- release_firmware(fw);
+ ret = cl_dsp_get_reg(cs40l26->dsp, "LE_EST_STATUS",
+ CL_DSP_YM_UNPACKED_TYPE, CS40l26_SVC_ALGO_ID, &reg);
if (ret)
- return;
+ goto pm_err;
+
+ for (i = 0; i < 2; i++) {
+ usleep_range(5000, 5100);
+ ret = regmap_read(cs40l26->regmap, reg, &le_est);
+ if (ret) {
+ dev_err(cs40l26->dev, "Failed to get LE_EST_STATUS\n");
+ goto pm_err;
+ }
+
+ if (le_est >= cs40l26->svc_le->le1_min &&
+ le_est <= cs40l26->svc_le->le1_max) {
+ cs40l26->fw.coeff_files[2] =
+ CS40L26_SVC_TUNING_FILE_NAME1;
+ break;
+ } else if (le_est >= cs40l26->svc_le->le2_min &&
+ le_est <= cs40l26->svc_le->le2_max) {
+ cs40l26->fw.coeff_files[2] =
+ CS40L26_SVC_TUNING_FILE_NAME2;
+ break;
+ }
+ }
+
+ if (i == 2) {
+ dev_warn(cs40l26->dev, "Falling back to default SVC tuning\n");
+ cs40l26->fw.coeff_files[2] = CS40L26_SVC_TUNING_FILE_NAME;
+ }
+
+pm_err:
+ pm_runtime_mark_last_busy(cs40l26->dev);
+ pm_runtime_put_autosuspend(cs40l26->dev);
+
+ return ret;
+}
+
+static void cs40l26_coeff_load(struct cs40l26_private *cs40l26)
+{
+ struct device *dev = cs40l26->dev;
+ const struct firmware *coeff;
+ int i;
for (i = 0; i < cs40l26->fw.num_coeff_files; i++) {
- request_firmware(&coeff_fw, cs40l26->fw.coeff_files[i],
- dev);
- if (!coeff_fw) {
+ request_firmware(&coeff, cs40l26->fw.coeff_files[i], dev);
+ if (!coeff) {
dev_warn(dev, "Continuing...\n");
continue;
}
- if (cl_dsp_coeff_file_parse(cs40l26->dsp, coeff_fw))
+ if (cl_dsp_coeff_file_parse(cs40l26->dsp, coeff))
dev_warn(dev, "Continuing...\n");
else
- dev_dbg(dev, "%s Loaded Successfully\n",
- cs40l26->fw.coeff_files[i]);
+ dev_info(dev, "%s Loaded Successfully\n",
+ cs40l26->fw.coeff_files[i]);
+ }
+}
+
+static int cs40l26_firmware_load(struct cs40l26_private *cs40l26, u32 id)
+{
+ struct device *dev = cs40l26->dev;
+ const struct firmware *fw;
+ int ret;
+
+ if (cs40l26->fw.id == CS40L26_FW_ID)
+ ret = request_firmware(&fw, CS40L26_FW_FILE_NAME, dev);
+ else
+ ret = request_firmware(&fw, CS40L26_FW_CALIB_NAME, dev);
+
+ if (ret)
+ return ret;
+
+ ret = cl_dsp_firmware_parse(cs40l26->dsp, fw, true);
+ release_firmware(fw);
+
+ return ret;
+}
+
+int cs40l26_fw_swap(struct cs40l26_private *cs40l26, u32 id)
+{
+ struct device *dev = cs40l26->dev;
+ int ret;
+
+ if (id == cs40l26->fw.id) {
+ dev_warn(dev, "Cannot swap to same ID as running firmware\n");
+ return 0;
}
- cs40l26_dsp_config(cs40l26);
+ cs40l26_pm_runtime_teardown(cs40l26);
+
+ cs40l26->fw_loaded = false;
+
+ disable_irq(cs40l26->irq);
+
+ ret = cs40l26_cl_dsp_init(cs40l26, id);
+ if (ret)
+ goto irq_exit;
+
+ ret = cs40l26_dsp_pre_config(cs40l26);
+ if (ret)
+ goto irq_exit;
+
+ ret = cs40l26_firmware_load(cs40l26, id);
+ if (ret)
+ goto irq_exit;
+
+ cs40l26_coeff_load(cs40l26);
+
+ ret = cs40l26_dsp_config(cs40l26);
+
+irq_exit:
+ 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_platform_data(struct cs40l26_private *cs40l26)
@@ -3035,7 +3005,7 @@ static int cs40l26_handle_platform_data(struct cs40l26_private *cs40l26)
struct device *dev = cs40l26->dev;
struct device_node *np = dev->of_node;
const char *str = NULL;
- u32 val;
+ u32 val, tmp;
if (!np) {
dev_err(dev, "No platform data found\n");
@@ -3113,6 +3083,35 @@ static int cs40l26_handle_platform_data(struct cs40l26_private *cs40l26)
else
cs40l26->pdata.bst_dcm_en = CS40L26_BST_DCM_EN_DEFAULT;
+ if (!of_property_read_u32(np, "cirrus,bst-ipk-microamp", &val))
+ cs40l26->pdata.bst_ipk = val;
+ else
+ cs40l26->pdata.bst_ipk = 0;
+
+ if (of_property_count_u32_elems(np, "cirrus,svc-le1") == 2 &&
+ of_property_count_u32_elems(np, "cirrus,svc-le2") == 2) {
+ of_property_read_u32_index(np, "cirrus,svc-le1", 0, &tmp);
+ of_property_read_u32_index(np, "cirrus,svc-le1", 1, &val);
+
+ cs40l26->svc_le = devm_kzalloc(dev,
+ sizeof(struct cs40l26_svc_le), GFP_KERNEL);
+ if (!cs40l26->svc_le)
+ return -ENOMEM;
+
+ cs40l26->svc_le->le1_min = min(tmp, val);
+ cs40l26->svc_le->le1_max = max(tmp, val);
+
+ of_property_read_u32_index(np, "cirrus,svc-le2", 0, &tmp);
+ of_property_read_u32_index(np, "cirrus,svc-le2", 1, &val);
+
+ cs40l26->svc_le->le2_min = min(tmp, val);
+ cs40l26->svc_le->le2_max = max(tmp, val);
+
+ cs40l26->pdata.svc_le_is_valid = true;
+ } else {
+ cs40l26->pdata.svc_le_is_valid = false;
+ }
+
return 0;
}
@@ -3177,7 +3176,7 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
usleep_range(CS40L26_MIN_RESET_PULSE_WIDTH,
CS40L26_MIN_RESET_PULSE_WIDTH + 100);
- gpiod_set_value_cansleep(cs40l26->reset_gpio, CS40L26_ENABLE);
+ gpiod_set_value_cansleep(cs40l26->reset_gpio, 1);
usleep_range(CS40L26_CONTROL_PORT_READY_DELAY,
CS40L26_CONTROL_PORT_READY_DELAY + 100);
@@ -3186,6 +3185,12 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
if (ret)
goto err;
+ ret = cs40l26_update_reg_defaults(cs40l26);
+ if (ret) {
+ dev_err(dev, "Failed to update reg defaults\n");
+ goto err;
+ }
+
ret = devm_request_threaded_irq(dev, cs40l26->irq, NULL, cs40l26_irq,
IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
"cs40l26", cs40l26);
@@ -3193,23 +3198,54 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
dev_err(dev, "Failed to request threaded IRQ\n");
goto err;
}
+
/* the /ALERT pin may be asserted prior to firmware initialization.
* Disable the interrupt handler until firmware has downloaded
* so erroneous interrupt requests are ignored
*/
disable_irq(cs40l26->irq);
- ret = cs40l26_cl_dsp_init(cs40l26);
+ cs40l26->pm_ready = false;
+ cs40l26->fw_loaded = false;
+
+ ret = cs40l26_cl_dsp_init(cs40l26, CS40L26_FW_ID);
if (ret)
- goto err;
+ goto irq_err;
ret = cs40l26_dsp_pre_config(cs40l26);
if (ret)
- goto err;
+ goto irq_err;
+
+ ret = cs40l26_firmware_load(cs40l26, cs40l26->fw.id);
+ if (ret)
+ goto irq_err;
+
+ if (cs40l26->pdata.svc_le_is_valid) {
+ ret = cs40l26_dsp_config(cs40l26);
+ if (ret)
+ goto irq_err;
+
+ enable_irq(cs40l26->irq);
+
+ ret = cs40l26_svc_le_select(cs40l26);
+ if (ret)
+ goto err;
+
+ disable_irq(cs40l26->irq);
+ cs40l26_pm_runtime_teardown(cs40l26);
+
+ ret = cs40l26_dsp_pre_config(cs40l26);
+ if (ret)
+ goto err;
+ }
- request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
- CS40L26_FW_FILE_NAME, dev, GFP_KERNEL, cs40l26,
- cs40l26_firmware_load);
+ cs40l26_coeff_load(cs40l26);
+
+ ret = cs40l26_dsp_config(cs40l26);
+ if (ret)
+ goto irq_err;
+
+ enable_irq(cs40l26->irq);
ret = cs40l26_input_init(cs40l26);
if (ret)
@@ -3224,6 +3260,8 @@ int cs40l26_probe(struct cs40l26_private *cs40l26,
return 0;
+irq_err:
+ enable_irq(cs40l26->irq);
err:
cs40l26_remove(cs40l26);
@@ -3246,10 +3284,10 @@ int cs40l26_remove(struct cs40l26_private *cs40l26)
cs40l26_pm_runtime_teardown(cs40l26);
if (cs40l26->vibe_workqueue) {
- destroy_workqueue(cs40l26->vibe_workqueue);
cancel_work_sync(&cs40l26->vibe_start_work);
cancel_work_sync(&cs40l26->vibe_stop_work);
cancel_work_sync(&cs40l26->set_gain_work);
+ destroy_workqueue(cs40l26->vibe_workqueue);
}
if (vp_consumer)
@@ -3258,7 +3296,7 @@ int cs40l26_remove(struct cs40l26_private *cs40l26)
if (va_consumer)
regulator_disable(va_consumer);
- gpiod_set_value_cansleep(cs40l26->reset_gpio, CS40L26_DISABLE);
+ gpiod_set_value_cansleep(cs40l26->reset_gpio, 0);
if (cs40l26->vibe_timer.function)
hrtimer_cancel(&cs40l26->vibe_timer);
diff --git a/cs40l26/cs40l26.h b/cs40l26/cs40l26.h
index 7c0bce8..0e5c427 100644
--- a/cs40l26/cs40l26.h
+++ b/cs40l26/cs40l26.h
@@ -86,6 +86,8 @@
#define CS40L26_OSC_TRIM 0x2030
#define CS40L26_ERROR_RELEASE 0x2034
#define CS40L26_PLL_OVERRIDE 0x2038
+#define CS40L26_CHIP_STATUS_1 0x2040
+#define CS40L26_CHIP_STATUS_2 0x2044
#define CS40L26_BIAS_PTE_MODE_CONTROL 0x2404
#define CS40L26_SCL_PAD_CONTROL 0x2408
#define CS40L26_SDA_PAD_CONTROL 0x240C
@@ -400,6 +402,8 @@
#define CS40L26_DSP1_AHBM_WINDOW6_CONTROL_1 0x25E2034
#define CS40L26_DSP1_AHBM_WINDOW7_CONTROL_0 0x25E2038
#define CS40L26_DSP1_AHBM_WINDOW7_CONTROL_1 0x25E203C
+#define CS40L26_DSP1_AHBM_WINDOW_DEBUG_0 0x25E2040
+#define CS40L26_DSP1_AHBM_WINDOW_DEBUG_1 0x25E2044
#define CS40L26_DSP1_XMEM_UNPACKED24_0 0x2800000
#define CS40L26_DSP1_XMEM_UNPACKED24_1 0x2800004
#define CS40L26_DSP1_XMEM_UNPACKED24_2 0x2800008
@@ -616,9 +620,16 @@
#define CS40L26_DSP1_PROM_30713 0x3C7DFE4
#define CS40L26_DSP1_PROM_30714 0x3C7DFE8
-/* this is not a CS40L26 restriction and may be able to be removed */
#define CS40L26_MAX_I2C_READ_SIZE_BYTES 32
+/* Register default changes */
+#define CS40L26_TST_DAC_MSM_CONFIG_DEFAULT_CHANGE_VALUE_FULL 0x11330000
+#define CS40L26_TST_DAC_MSM_CONFIG_DEFAULT_CHANGE_VALUE_H16 (\
+ CS40L26_TST_DAC_MSM_CONFIG_DEFAULT_CHANGE_VALUE_FULL >> 16)
+#define CS40L26_SPK_DEFAULT_HIZ_MASK BIT(28)
+#define CS40L26_SPK_DEFAULT_HIZ_SHIFT 28
+
+/* Device */
#define CS40L26_DEV_NAME "CS40L26"
#define CS40L26_INPUT_DEV_NAME "cs40l26_input"
#define CS40L26_DEVID_A 0x40A260
@@ -626,15 +637,11 @@
#define CS40L26_DEVID_MASK GENMASK(23, 0)
#define CS40L26_NUM_DEVS 2
-#define CS40L26_REVID_A0 0xA0
#define CS40L26_REVID_A1 0xA1
#define CS40L26_REVID_MASK GENMASK(7, 0)
#define CS40L26_GLOBAL_EN_MASK BIT(0)
-#define CS40L26_DISABLE 0
-#define CS40L26_ENABLE 1
-
#define CS40L26_DSP_CCM_CORE_KILL 0x00000080
#define CS40L26_DSP_CCM_CORE_RESET 0x00000281
@@ -645,6 +652,8 @@
#define CS40L26_DSP_HALO_STATE_RUN 2
+#define CS40L26_NUM_PCT_MAP_VALUES 101
+
/* DSP State */
#define CS40L26_DSP_STATE_HIBERNATE 0
#define CS40L26_DSP_STATE_SHUTDOWN 1
@@ -655,12 +664,6 @@
#define CS40L26_DSP_STATE_STR_LEN 10
-/* ROM Controls A0 */
-#define CS40L26_A0_PM_CUR_STATE_STATIC_REG 0x02800358
-#define CS40L26_A0_PM_TIMEOUT_TICKS_STATIC_REG 0x02800338
-#define CS40L26_A0_DSP_HALO_STATE_REG 0x02806f40
-
-
/* ROM Controls A1 */
#define CS40L26_A1_PM_CUR_STATE_STATIC_REG 0x02800370
#define CS40L26_A1_PM_TIMEOUT_TICKS_STATIC_REG 0x02800350
@@ -682,47 +685,28 @@
#define CS40L26_LOGGER_ALGO_ID 0x0004013D
#define CS40L26_EXT_ALGO_ID 0x0004013C
-#define CS40L26_VIBEGEN_ROM_ALGO_ID 0x000000BD
-#define CS40L26_BUZZGEN_ROM_ALGO_ID 0x0000F202
-#define CS40L26_PM_ROM_ALGO_ID 0x0000F206
-
/* power management */
-#define CS40L26_PSEQ_V1_MAX_ENTRIES 32
-#define CS40L26_PSEQ_V1_MAX_WRITES 64
-#define CS40L26_PSEQ_V1_VAL_SHIFT 24
-#define CS40L26_PSEQ_V1_VAL_MASK GENMASK(23, 0)
-#define CS40L26_PSEQ_V1_ADDR_SHIFT 8
-#define CS40L26_PSEQ_V1_ADDR_MASK GENMASK(15, 0)
-#define CS40L26_PSEQ_V1_LIST_TERM 0xFFFFFF
-#define CS40L26_PSEQ_V1_LIST_TERM_MASK GENMASK(31, 0)
-#define CS40L26_PSEQ_V1_STRIDE 8
-#define CS40L26_PSEQ_V1_PAIR_NUM_WORDS 2
-#define CS40L26_PSEQ_V1_ADDR_WORD_MASK GENMASK(23, 8)
-#define CS40L26_PSEQ_V1_VAL_WORD_UPPER_MASK GENMASK(8, 0)
-#define CS40L26_PSEQ_V1_DO_NOT_REPLACE 0
-#define CS40L26_PSEQ_V1_REPLACE 1
-
-#define CS40L26_PSEQ_V2_MAX_WORDS_PER_OP CS40L26_PSEQ_V2_OP_WRITE_FIELD_WORDS
-#define CS40L26_PSEQ_V2_MAX_WORDS 129
-#define CS40L26_PSEQ_V2_NUM_OPS 8
-#define CS40L26_PSEQ_V2_OP_MASK GENMASK(23, 16)
-#define CS40L26_PSEQ_V2_OP_SHIFT 16
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_FULL 0x00
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_FULL_WORDS 3
-#define CS40L26_PSEQ_V2_OP_WRITE_FIELD 0x01
-#define CS40L26_PSEQ_V2_OP_WRITE_FIELD_WORDS 4
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_ADDR8 0x02
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_ADDR8_WORDS 2
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_INCR 0x03
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_INCR_WORDS 2
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_L16 0x04
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_L16_WORDS 2
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_H16 0x05
-#define CS40L26_PSEQ_V2_OP_WRITE_REG_H16_WORDS 2
-#define CS40L26_PSEQ_V2_OP_DELAY 0xFE
-#define CS40L26_PSEQ_V2_OP_DELAY_WORDS 1
-#define CS40L26_PSEQ_V2_OP_END 0xFF
-#define CS40L26_PSEQ_V2_OP_END_WORDS 1
+#define CS40L26_PSEQ_MAX_WORDS_PER_OP CS40L26_PSEQ_OP_WRITE_FIELD_WORDS
+#define CS40L26_PSEQ_MAX_WORDS 129
+#define CS40L26_PSEQ_NUM_OPS 8
+#define CS40L26_PSEQ_OP_MASK GENMASK(23, 16)
+#define CS40L26_PSEQ_OP_SHIFT 16
+#define CS40L26_PSEQ_OP_WRITE_REG_FULL 0x00
+#define CS40L26_PSEQ_OP_WRITE_REG_FULL_WORDS 3
+#define CS40L26_PSEQ_OP_WRITE_FIELD 0x01
+#define CS40L26_PSEQ_OP_WRITE_FIELD_WORDS 4
+#define CS40L26_PSEQ_OP_WRITE_REG_ADDR8 0x02
+#define CS40L26_PSEQ_OP_WRITE_REG_ADDR8_WORDS 2
+#define CS40L26_PSEQ_OP_WRITE_REG_INCR 0x03
+#define CS40L26_PSEQ_OP_WRITE_REG_INCR_WORDS 2
+#define CS40L26_PSEQ_OP_WRITE_REG_L16 0x04
+#define CS40L26_PSEQ_OP_WRITE_REG_L16_WORDS 2
+#define CS40L26_PSEQ_OP_WRITE_REG_H16 0x05
+#define CS40L26_PSEQ_OP_WRITE_REG_H16_WORDS 2
+#define CS40L26_PSEQ_OP_DELAY 0xFE
+#define CS40L26_PSEQ_OP_DELAY_WORDS 1
+#define CS40L26_PSEQ_OP_END 0xFF
+#define CS40L26_PSEQ_OP_END_WORDS 1
#define CS40L26_PM_STDBY_TIMEOUT_LOWER_OFFSET 16
#define CS40L26_PM_STDBY_TIMEOUT_UPPER_OFFSET 20
@@ -768,6 +752,8 @@
#define CS40L26_DSP_MBOX_CMD_OWT_PUSH 0x03000008
#define CS40L26_DSP_MBOX_CMD_OWT_RESET 0x03000009
+#define CS40L26_DSP_MBOX_CMD_LE_EST 0x07000004
+
#define CS40L26_DSP_MBOX_CMD_INDEX_MASK GENMASK(28, 24)
#define CS40L26_DSP_MBOX_CMD_INDEX_SHIFT 24
@@ -783,20 +769,27 @@
#define CS40L26_DSP_MBOX_F0_EST_DONE 0x07000021
#define CS40L26_DSP_MBOX_REDC_EST_START 0x07000012
#define CS40L26_DSP_MBOX_REDC_EST_DONE 0x07000022
+#define CS40L26_DSP_MBOX_LE_EST_START 0x07000014
+#define CS40L26_DSP_MBOX_LE_EST_DONE 0x07000024
#define CS40L26_DSP_MBOX_SYS_ACK 0x0A000000
#define CS40L26_DSP_MBOX_PANIC 0x0C000000
/* Firmware Mode */
#define CS40L26_FW_FILE_NAME "cs40l26.wmfw"
+#define CS40L26_FW_CALIB_NAME "cs40l26-calib.wmfw"
#define CS40L26_WT_FILE_NAME "cs40l26.bin"
#define CS40L26_SVC_TUNING_FILE_NAME "cs40l26-svc.bin"
+#define CS40L26_SVC_TUNING_FILE_NAME1 "cs40l26-svc1.bin"
+#define CS40L26_SVC_TUNING_FILE_NAME2 "cs40l26-svc2.bin"
#define CS40L26_A2H_TUNING_FILE_NAME "cs40l26-a2h.bin"
#define CS40L26_FW_ID 0x1800D4
#define CS40L26_FW_ROM_MIN_REV 0x040000
#define CS40L26_FW_A0_RAM_MIN_REV 0x050004
#define CS40L26_FW_A1_RAM_MIN_REV 0x070201
+#define CS40L26_FW_CALIB_ID 0x1800DA
+#define CS40L26_FW_CALIB_MIN_REV 0x010000
#define CS40L26_CCM_CORE_RESET 0x00000200
#define CS40L26_CCM_CORE_ENABLE 0x00000281
@@ -857,6 +850,19 @@
#define CS40L26_AMP_VOL_PCM_MAX 0x07FF
+/* GPI Triggering */
+#define CS40L26_EVENT_MAP_INDEX_MASK GENMASK(8, 0)
+
+#define CS40L26_BTN_INDEX_MASK GENMASK(6, 0)
+#define CS40L26_BTN_BUZZ_MASK BIT(7)
+#define CS40L26_BTN_BUZZ_SHIFT 7
+#define CS40L26_BTN_BANK_MASK BIT(8)
+#define CS40L26_BTN_BANK_SHIFT 8
+#define CS40L26_BTN_NUM_MASK GENMASK(14, 12)
+#define CS40L26_BTN_NUM_SHIFT 12
+#define CS40L26_BTN_EDGE_MASK BIT(15)
+#define CS40L26_BTN_EDGE_SHIFT 15
+
/* Interrupts */
#define CS40L26_IRQ_STATUS_DEASSERT 0x0
#define CS40L26_IRQ_STATUS_ASSERT 0x1
@@ -876,11 +882,22 @@
#define CS40L26_NUM_OUTPUT_SETUP_WRITES 3
+/* temp monitoring */
+#define CS40L26_TEMPMON_EN_MASK BIT(10)
+#define CS40L26_TEMPMON_EN_SHIFT 10
+#define CS40L26_TEMP_RESULT_FILT_MASK GENMASK(24, 16)
+#define CS40L26_TEMP_RESULT_FILT_SHIFT 16
+
/* BST */
#define CS40L26_BST_DCM_EN_DEFAULT 1
#define CS40L26_BST_DCM_EN_MASK BIT(0)
#define CS40L26_BST_DCM_EN_SHIFT 0
+#define CS40L26_BST_IPK_MILLIAMP_MAX 4800
+#define CS40L26_BST_IPK_MILLIAMP_MIN 1600
+
+#define CS40L26_BST_IPK_DEFAULT 0x4A
+
/* brownout prevention */
#define CS40L26_VXBR_DEFAULT 0xFFFFFFFF
@@ -1048,10 +1065,7 @@
#define CS40L26_A2H_MAX_TUNINGS 5
-#define CS40L26_VOLUME_MAX_STEPS 100
-#define CS40L26_VOLUME_MAX 0x7FFFFF
-#define CS40L26_VOLUME_STEP_SIZE (CS40L26_VOLUME_MAX / \
- CS40L26_VOLUME_MAX_STEPS)
+#define CS40L26_A2H_VOLUME_MAX 0x7FFFFF
/* OWT */
#define CS40L26_WT_STR_MAX_LEN 512
@@ -1114,9 +1128,6 @@
#define CS40L26_SAMPS_TO_MS(n) ((n) / 8)
-extern const struct cl_dsp_fw_desc cs40l26_fw;
-extern const struct cl_dsp_fw_desc cs40l26_ram_fw;
-
/* enums */
enum cs40l26_vibe_state {
CS40L26_VIBE_STATE_STOPPED,
@@ -1225,11 +1236,8 @@ enum cs40l26_pm_state {
struct cs40l26_fw {
unsigned int id;
unsigned int min_rev;
- unsigned int halo_state_run;
unsigned int num_coeff_files;
- const char * const *coeff_files;
- const char *fw_file;
- bool write_fw;
+ const char *coeff_files[3];
};
struct cs40l26_owt_section {
@@ -1245,12 +1253,7 @@ struct cs40l26_iseq_pair {
u32 val;
};
-struct cs40l26_pseq_v1_pair {
- u16 addr;
- u32 val;
-};
-
-struct cs40l26_pseq_v2_op {
+struct cs40l26_pseq_op {
u8 size;
u16 offset; /* offset in bytes from pseq_base */
u8 operation;
@@ -1258,6 +1261,13 @@ struct cs40l26_pseq_v2_op {
struct list_head list;
};
+struct cs40l26_svc_le {
+ u32 le1_min;
+ u32 le1_max;
+ u32 le2_min;
+ u32 le2_max;
+};
+
struct cs40l26_platform_data {
const char *device_name;
bool vbbr_en;
@@ -1275,6 +1285,8 @@ struct cs40l26_platform_data {
u32 vpbr_wait;
u32 vpbr_rel_rate;
bool bst_dcm_en;
+ u32 bst_ipk;
+ u32 svc_le_is_valid;
};
struct cs40l26_private {
@@ -1296,11 +1308,9 @@ struct cs40l26_private {
struct workqueue_struct *vibe_workqueue;
int irq;
bool vibe_init_success;
- unsigned int pseq_v1_len;
- unsigned int pseq_v2_num_ops;
+ unsigned int pseq_num_ops;
u32 pseq_base;
- struct cs40l26_pseq_v1_pair pseq_v1_table[CS40L26_PSEQ_V1_MAX_ENTRIES];
- struct list_head pseq_v2_op_head;
+ struct list_head pseq_op_head;
enum cs40l26_pm_state pm_state;
struct cs40l26_iseq_pair iseq_table[CS40L26_ISEQ_MAX_ENTRIES];
enum cs40l26_fw_mode fw_mode;
@@ -1318,6 +1328,8 @@ struct cs40l26_private {
int num_owt_effects;
int cal_requested;
u16 gain_pct;
+ u32 event_map_base;
+ struct cs40l26_svc_le *svc_le;
};
struct cs40l26_codec {
@@ -1332,6 +1344,8 @@ struct cs40l26_codec {
int tdm_width;
int tdm_slots;
int tdm_slot[2];
+ bool svc_for_streaming_data;
+ bool invert_streaming_data;
};
struct cs40l26_pll_sysclk_config {
@@ -1340,6 +1354,7 @@ struct cs40l26_pll_sysclk_config {
};
/* exported function prototypes */
+int cs40l26_fw_swap(struct cs40l26_private *cs40l26, u32 id);
void cs40l26_vibe_state_set(struct cs40l26_private *cs40l26,
enum cs40l26_vibe_state);
int cs40l26_class_h_set(struct cs40l26_private *cs40l26, bool class_h);
@@ -1351,9 +1366,7 @@ 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_pseq_v1_multi_add_pair(struct cs40l26_private *cs40l26,
- const struct reg_sequence *reg_seq, int num_regs, bool replace);
-int cs40l26_pseq_v2_multi_add_write_reg_full(struct cs40l26_private *cs40l26,
+int cs40l26_pseq_multi_add_write_reg_full(struct cs40l26_private *cs40l26,
const struct reg_sequence *reg_seq, int num_regs,
bool update_if_op_already_in_seq);
int cs40l26_resume(struct device *dev);
@@ -1377,9 +1390,8 @@ extern struct regulator_bulk_data
extern const struct dev_pm_ops cs40l26_pm_ops;
extern const struct regmap_config cs40l26_regmap;
extern const struct mfd_cell cs40l26_devs[CS40L26_NUM_MFD_DEVS];
-extern const u8 cs40l26_pseq_v2_op_sizes[CS40L26_PSEQ_V2_NUM_OPS][2];
-extern const char * const cs40l26_ram_coeff_files[3];
-extern const u32 cs40l26_attn_q21_2_vals[101];
+extern const u8 cs40l26_pseq_op_sizes[CS40L26_PSEQ_NUM_OPS][2];
+extern const u32 cs40l26_attn_q21_2_vals[CS40L26_NUM_PCT_MAP_VALUES];
/* sysfs */