summaryrefslogtreecommitdiff
path: root/cs40l26/cs40l26-codec.c
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 /cs40l26/cs40l26-codec.c
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
Diffstat (limited to 'cs40l26/cs40l26-codec.c')
-rw-r--r--cs40l26/cs40l26-codec.c165
1 files changed, 133 insertions, 32 deletions
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" };