summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/cs42l42.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-22 21:29:05 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-22 21:29:05 +0300
commit064d7dcf51a82b480e953a15cca47e5df0426502 (patch)
treeb34ab58ee35e827c14071024dfc79fe50a5f31e6 /sound/soc/codecs/cs42l42.c
parentf3dd0c53370e70c0f9b7e931bbec12916f3bb8cc (diff)
parent7933b90b42896f5b6596e6a829bb31c5121fc2a9 (diff)
downloadlinux-064d7dcf51a82b480e953a15cca47e5df0426502.tar.xz
Merge tag 'sound-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "The majority of works in this cycle are about ASoC spread over trees. Most of them are for new devices and cleanups / refactoring works, and not much significant changes are seen in the core side. Below are some highlights: ASoC: - Continued refactoring to move into common helper functions - Lots of DT schema conversons and stylistic nits - Continued work on building out the new SOF IPC4 scheme - Continued work for Intel AVS - New drivers for Awinc AT88395, Infineon PEB2466, Iron Device SMA1303, Mediatek MT8188, Realtek RT712, Renesas IDT821034, Samsung/Tesla FSD SoC I2S, and TI TAS5720A-Q1 ALSA: - A few cleanups to make the remove callbacks to void returns - FireWire refactoring and enhancements - PCM kselftest enhancements" * tag 'sound-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (398 commits) ALSA: hda/hdmi: Register with vga_switcheroo on Dual GPU Macbooks ASoC: soc-ac97: Return correct error codes ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared ASoC: cs35l45: Remove separate namespace for tables ASoC: cs35l45: Remove separate tables module ASoC: soc-ac97: Convert to agnostic GPIO API ASoC: dt-bindings: renesas,rsnd.yaml: drop "dmas/dma-names" from "rcar_sound,ssi" ALSA: hda: cs35l41: Enable Amp High Pass Filter ALSA: hda: cs35l41: Ensure firmware/tuning pairs are always loaded ALSA: hda: cs35l41: Correct error condition handling ASoC: codecs: wcd934x: Use min macro for comparison and assignment ASoC: Intel: Skylake: Fix struct definition ASoC: tlv320adcx140: extend list of supported samplerates ASoC: imx-pcm-rpmsg: Remove unused variable SoC: rt5682s: Disable jack detection interrupt during suspend ASoC: SOF: Intel: hda-dsp: Set streaming flag for d0i3 ASoC: SOF: Intel: Enable d0i3 work for ipc4 ASoC: SOF: ipc4: Wake up dsp core before sending ipc msg ASoC: SOF: Intel: hda-dsp: use set_pm_gate according to ipc version ASoC: SOF: Introduce a new set_pm_gate() IPC PM op ...
Diffstat (limited to 'sound/soc/codecs/cs42l42.c')
-rw-r--r--sound/soc/codecs/cs42l42.c133
1 files changed, 89 insertions, 44 deletions
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 2fefbcf7bd13..e3edaa1a2761 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
@@ -293,6 +294,7 @@ bool cs42l42_readable_register(struct device *dev, unsigned int reg)
case CS42L42_SPDIF_SW_CTL1:
case CS42L42_SRC_SDIN_FS:
case CS42L42_SRC_SDOUT_FS:
+ case CS42L42_SOFT_RESET_REBOOT:
case CS42L42_SPDIF_CTL1:
case CS42L42_SPDIF_CTL2:
case CS42L42_SPDIF_CTL3:
@@ -358,6 +360,7 @@ bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
case CS42L42_LOAD_DET_DONE:
case CS42L42_DET_STATUS1:
case CS42L42_DET_STATUS2:
+ case CS42L42_SOFT_RESET_REBOOT:
return true;
default:
return false;
@@ -523,6 +526,10 @@ static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
/* Playback/Capture Requirements */
SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0),
+
+ /* Soundwire SRC power control */
+ SND_SOC_DAPM_PGA("DACSRC", CS42L42_PWR_CTL2, CS42L42_DAC_SRC_PDNB_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADCSRC", CS42L42_PWR_CTL2, CS42L42_ADC_SRC_PDNB_SHIFT, 0, NULL, 0),
};
static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
@@ -590,7 +597,6 @@ const struct snd_soc_component_driver cs42l42_soc_component = {
.num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map),
.controls = cs42l42_snd_controls,
.num_controls = ARRAY_SIZE(cs42l42_snd_controls),
- .idle_bias_on = 1,
.endianness = 1,
};
EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE);
@@ -651,11 +657,11 @@ static const struct cs42l42_pll_params pll_ratio_table[] = {
{ 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1}
};
-static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk)
+int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk,
+ unsigned int sample_rate)
{
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
int i;
- u32 fsync;
/* Don't reconfigure if there is an audio stream running */
if (cs42l42->stream_use) {
@@ -666,6 +672,10 @@ static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int
}
for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ /* MCLKint must be a multiple of the sample rate */
+ if (pll_ratio_table[i].mclk_int % sample_rate)
+ continue;
+
if (pll_ratio_table[i].sclk == clk) {
cs42l42->pll_config = i;
@@ -677,40 +687,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int
(pll_ratio_table[i].mclk_int !=
24000000)) <<
CS42L42_INTERNAL_FS_SHIFT);
-
- /* Set up the LRCLK */
- fsync = clk / cs42l42->srate;
- if (((fsync * cs42l42->srate) != clk)
- || ((fsync % 2) != 0)) {
- dev_err(component->dev,
- "Unsupported sclk %d/sample rate %d\n",
- clk,
- cs42l42->srate);
- return -EINVAL;
- }
- /* Set the LRCLK period */
- snd_soc_component_update_bits(component,
- CS42L42_FSYNC_P_LOWER,
- CS42L42_FSYNC_PERIOD_MASK,
- CS42L42_FRAC0_VAL(fsync - 1) <<
- CS42L42_FSYNC_PERIOD_SHIFT);
- snd_soc_component_update_bits(component,
- CS42L42_FSYNC_P_UPPER,
- CS42L42_FSYNC_PERIOD_MASK,
- CS42L42_FRAC1_VAL(fsync - 1) <<
- CS42L42_FSYNC_PERIOD_SHIFT);
- /* Set the LRCLK to 50% duty cycle */
- fsync = fsync / 2;
- snd_soc_component_update_bits(component,
- CS42L42_FSYNC_PW_LOWER,
- CS42L42_FSYNC_PULSE_WIDTH_MASK,
- CS42L42_FRAC0_VAL(fsync - 1) <<
- CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
- snd_soc_component_update_bits(component,
- CS42L42_FSYNC_PW_UPPER,
- CS42L42_FSYNC_PULSE_WIDTH_MASK,
- CS42L42_FRAC1_VAL(fsync - 1) <<
- CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
if (pll_ratio_table[i].mclk_src_sel == 0) {
/* Pass the clock straight through */
snd_soc_component_update_bits(component,
@@ -768,8 +744,9 @@ static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int
return -EINVAL;
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, SND_SOC_CS42L42_CORE);
-static void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate)
+void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate)
{
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int fs;
@@ -801,6 +778,47 @@ static void cs42l42_src_config(struct snd_soc_component *component, unsigned int
CS42L42_CLK_OASRC_SEL_MASK,
fs << CS42L42_CLK_OASRC_SEL_SHIFT);
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, SND_SOC_CS42L42_CORE);
+
+static int cs42l42_asp_config(struct snd_soc_component *component,
+ unsigned int sclk, unsigned int sample_rate)
+{
+ u32 fsync = sclk / sample_rate;
+
+ /* Set up the LRCLK */
+ if (((fsync * sample_rate) != sclk) || ((fsync % 2) != 0)) {
+ dev_err(component->dev,
+ "Unsupported sclk %d/sample rate %d\n",
+ sclk,
+ sample_rate);
+ return -EINVAL;
+ }
+ /* Set the LRCLK period */
+ snd_soc_component_update_bits(component,
+ CS42L42_FSYNC_P_LOWER,
+ CS42L42_FSYNC_PERIOD_MASK,
+ CS42L42_FRAC0_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PERIOD_SHIFT);
+ snd_soc_component_update_bits(component,
+ CS42L42_FSYNC_P_UPPER,
+ CS42L42_FSYNC_PERIOD_MASK,
+ CS42L42_FRAC1_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PERIOD_SHIFT);
+ /* Set the LRCLK to 50% duty cycle */
+ fsync = fsync / 2;
+ snd_soc_component_update_bits(component,
+ CS42L42_FSYNC_PW_LOWER,
+ CS42L42_FSYNC_PULSE_WIDTH_MASK,
+ CS42L42_FRAC0_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+ snd_soc_component_update_bits(component,
+ CS42L42_FSYNC_PW_UPPER,
+ CS42L42_FSYNC_PULSE_WIDTH_MASK,
+ CS42L42_FRAC1_VAL(fsync - 1) <<
+ CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+
+ return 0;
+}
static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
@@ -891,13 +909,12 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int channels = params_channels(params);
unsigned int width = (params_width(params) / 8) - 1;
+ unsigned int sample_rate = params_rate(params);
unsigned int slot_width = 0;
unsigned int val = 0;
unsigned int bclk;
int ret;
- cs42l42->srate = params_rate(params);
-
if (cs42l42->bclk_ratio) {
/* machine driver has set the BCLK/samp-rate ratio */
bclk = cs42l42->bclk_ratio * params_rate(params);
@@ -954,11 +971,15 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
break;
}
- ret = cs42l42_pll_config(component, bclk);
+ ret = cs42l42_pll_config(component, bclk, sample_rate);
if (ret)
return ret;
- cs42l42_src_config(component, params_rate(params));
+ ret = cs42l42_asp_config(component, bclk, sample_rate);
+ if (ret)
+ return ret;
+
+ cs42l42_src_config(component, sample_rate);
return 0;
}
@@ -998,7 +1019,7 @@ static int cs42l42_set_bclk_ratio(struct snd_soc_dai *dai,
return 0;
}
-static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
@@ -1091,6 +1112,7 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, SND_SOC_CS42L42_CORE);
#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
@@ -1633,7 +1655,7 @@ static const struct cs42l42_irq_params irq_params_table[] = {
CS42L42_TSRS_PLUG_VAL_MASK}
};
-static irqreturn_t cs42l42_irq_thread(int irq, void *data)
+irqreturn_t cs42l42_irq_thread(int irq, void *data)
{
struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data;
unsigned int stickies[12];
@@ -1642,9 +1664,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int current_button_status;
unsigned int i;
+ pm_runtime_get_sync(cs42l42->dev);
mutex_lock(&cs42l42->irq_lock);
if (cs42l42->suspended || !cs42l42->init_done) {
mutex_unlock(&cs42l42->irq_lock);
+ pm_runtime_put_autosuspend(cs42l42->dev);
return IRQ_NONE;
}
@@ -1747,9 +1771,12 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
}
mutex_unlock(&cs42l42->irq_lock);
+ pm_runtime_mark_last_busy(cs42l42->dev);
+ pm_runtime_put_autosuspend(cs42l42->dev);
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, SND_SOC_CS42L42_CORE);
static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
{
@@ -2125,6 +2152,9 @@ int cs42l42_suspend(struct device *dev)
u8 save_regs[ARRAY_SIZE(cs42l42_shutdown_seq)];
int i, ret;
+ if (!cs42l42->init_done)
+ return 0;
+
/*
* Wait for threaded irq handler to be idle and stop it processing
* future interrupts. This ensures a safe disable if the interrupt
@@ -2185,6 +2215,9 @@ int cs42l42_resume(struct device *dev)
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
int ret;
+ if (!cs42l42->init_done)
+ return 0;
+
/*
* If jack was unplugged and re-plugged during suspend it could
* have changed type but the tip-sense state hasn't changed.
@@ -2369,6 +2402,18 @@ int cs42l42_init(struct cs42l42_private *cs42l42)
if (ret != 0)
goto err_shutdown;
+ /*
+ * SRC power is linked to ASP power so doesn't work in Soundwire mode.
+ * Override it and use DAPM to control SRC power for Soundwire.
+ */
+ if (cs42l42->sdw_peripheral) {
+ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2,
+ CS42L42_SRC_PDN_OVERRIDE_MASK |
+ CS42L42_DAC_SRC_PDNB_MASK |
+ CS42L42_ADC_SRC_PDNB_MASK,
+ CS42L42_SRC_PDN_OVERRIDE_MASK);
+ }
+
/* Setup headset detection */
cs42l42_setup_hs_type_detect(cs42l42);