162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// cs35l45.c - CS35L45 ALSA SoC audio driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright 2019-2022 Cirrus Logic, Inc. 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// Author: James Schulman <james.schulman@cirrus.com> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1262306a36Sopenharmony_ci#include <linux/property.h> 1362306a36Sopenharmony_ci#include <linux/firmware.h> 1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1562306a36Sopenharmony_ci#include <sound/core.h> 1662306a36Sopenharmony_ci#include <sound/pcm.h> 1762306a36Sopenharmony_ci#include <sound/pcm_params.h> 1862306a36Sopenharmony_ci#include <sound/soc.h> 1962306a36Sopenharmony_ci#include <sound/tlv.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "cs35l45.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool cs35l45_check_cspl_mbox_sts(const enum cs35l45_cspl_mboxcmd cmd, 2462306a36Sopenharmony_ci enum cs35l45_cspl_mboxstate sts) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci switch (cmd) { 2762306a36Sopenharmony_ci case CSPL_MBOX_CMD_NONE: 2862306a36Sopenharmony_ci case CSPL_MBOX_CMD_UNKNOWN_CMD: 2962306a36Sopenharmony_ci return true; 3062306a36Sopenharmony_ci case CSPL_MBOX_CMD_PAUSE: 3162306a36Sopenharmony_ci case CSPL_MBOX_CMD_OUT_OF_HIBERNATE: 3262306a36Sopenharmony_ci return (sts == CSPL_MBOX_STS_PAUSED); 3362306a36Sopenharmony_ci case CSPL_MBOX_CMD_RESUME: 3462306a36Sopenharmony_ci return (sts == CSPL_MBOX_STS_RUNNING); 3562306a36Sopenharmony_ci case CSPL_MBOX_CMD_REINIT: 3662306a36Sopenharmony_ci return (sts == CSPL_MBOX_STS_RUNNING); 3762306a36Sopenharmony_ci case CSPL_MBOX_CMD_STOP_PRE_REINIT: 3862306a36Sopenharmony_ci return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); 3962306a36Sopenharmony_ci case CSPL_MBOX_CMD_HIBERNATE: 4062306a36Sopenharmony_ci return (sts == CSPL_MBOX_STS_HIBERNATE); 4162306a36Sopenharmony_ci default: 4262306a36Sopenharmony_ci return false; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private *cs35l45, 4762306a36Sopenharmony_ci struct regmap *regmap, 4862306a36Sopenharmony_ci const enum cs35l45_cspl_mboxcmd cmd) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci unsigned int sts = 0, i; 5162306a36Sopenharmony_ci int ret; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (!cs35l45->dsp.cs_dsp.running) { 5462306a36Sopenharmony_ci dev_err(cs35l45->dev, "DSP not running\n"); 5562306a36Sopenharmony_ci return -EPERM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci // Set mailbox cmd 5962306a36Sopenharmony_ci ret = regmap_write(regmap, CS35L45_DSP_VIRT1_MBOX_1, cmd); 6062306a36Sopenharmony_ci if (ret < 0) { 6162306a36Sopenharmony_ci if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) 6262306a36Sopenharmony_ci dev_err(cs35l45->dev, "Failed to write MBOX: %d\n", ret); 6362306a36Sopenharmony_ci return ret; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci // Read mailbox status and verify it is appropriate for the given cmd 6762306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 6862306a36Sopenharmony_ci usleep_range(1000, 1100); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ret = regmap_read(regmap, CS35L45_DSP_MBOX_2, &sts); 7162306a36Sopenharmony_ci if (ret < 0) { 7262306a36Sopenharmony_ci dev_err(cs35l45->dev, "Failed to read MBOX STS: %d\n", ret); 7362306a36Sopenharmony_ci continue; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!cs35l45_check_cspl_mbox_sts(cmd, sts)) 7762306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts); 7862306a36Sopenharmony_ci else 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) 8362306a36Sopenharmony_ci dev_err(cs35l45->dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return -ENOMSG; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w, 8962306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 9262306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci switch (event) { 9762306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 9862306a36Sopenharmony_ci regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 9962306a36Sopenharmony_ci CS35L45_GLOBAL_EN_MASK); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci usleep_range(CS35L45_POST_GLOBAL_EN_US, CS35L45_POST_GLOBAL_EN_US + 100); 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 10462306a36Sopenharmony_ci usleep_range(CS35L45_PRE_GLOBAL_DIS_US, CS35L45_PRE_GLOBAL_DIS_US + 100); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 0); 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci default: 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int cs35l45_dsp_preload_ev(struct snd_soc_dapm_widget *w, 11662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 11962306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 12062306a36Sopenharmony_ci int ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci switch (event) { 12362306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 12462306a36Sopenharmony_ci if (cs35l45->dsp.cs_dsp.booted) 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return wm_adsp_early_event(w, kcontrol, event); 12862306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 12962306a36Sopenharmony_ci if (cs35l45->dsp.cs_dsp.running) 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_PWRMGT_CTL, 13362306a36Sopenharmony_ci CS35L45_MEM_RDY_MASK); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return wm_adsp_event(w, kcontrol, event); 13662306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 13762306a36Sopenharmony_ci if (cs35l45->dsp.preloaded) 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (cs35l45->dsp.cs_dsp.running) { 14162306a36Sopenharmony_ci ret = wm_adsp_event(w, kcontrol, event); 14262306a36Sopenharmony_ci if (ret) 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return wm_adsp_early_event(w, kcontrol, event); 14762306a36Sopenharmony_ci default: 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget *w, 15362306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 15662306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci switch (event) { 15962306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 16062306a36Sopenharmony_ci return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap, 16162306a36Sopenharmony_ci CSPL_MBOX_CMD_RESUME); 16262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 16362306a36Sopenharmony_ci return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap, 16462306a36Sopenharmony_ci CSPL_MBOX_CMD_PAUSE); 16562306a36Sopenharmony_ci default: 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic const char * const cs35l45_asp_tx_txt[] = { 17362306a36Sopenharmony_ci "Zero", "ASP_RX1", "ASP_RX2", 17462306a36Sopenharmony_ci "VMON", "IMON", "ERR_VOL", 17562306a36Sopenharmony_ci "VDD_BATTMON", "VDD_BSTMON", 17662306a36Sopenharmony_ci "DSP_TX1", "DSP_TX2", 17762306a36Sopenharmony_ci "Interpolator", "IL_TARGET", 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const unsigned int cs35l45_asp_tx_val[] = { 18162306a36Sopenharmony_ci CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2, 18262306a36Sopenharmony_ci CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL, 18362306a36Sopenharmony_ci CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON, 18462306a36Sopenharmony_ci CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2, 18562306a36Sopenharmony_ci CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET, 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const struct soc_enum cs35l45_asp_tx_enums[] = { 18962306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK, 19062306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 19162306a36Sopenharmony_ci cs35l45_asp_tx_val), 19262306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK, 19362306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 19462306a36Sopenharmony_ci cs35l45_asp_tx_val), 19562306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT, 0, CS35L45_PCM_SRC_MASK, 19662306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 19762306a36Sopenharmony_ci cs35l45_asp_tx_val), 19862306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK, 19962306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 20062306a36Sopenharmony_ci cs35l45_asp_tx_val), 20162306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK, 20262306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, 20362306a36Sopenharmony_ci cs35l45_asp_tx_val), 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic const char * const cs35l45_dsp_rx_txt[] = { 20762306a36Sopenharmony_ci "Zero", "ASP_RX1", "ASP_RX2", 20862306a36Sopenharmony_ci "VMON", "IMON", "ERR_VOL", 20962306a36Sopenharmony_ci "CLASSH_TGT", "VDD_BATTMON", 21062306a36Sopenharmony_ci "VDD_BSTMON", "TEMPMON", 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const unsigned int cs35l45_dsp_rx_val[] = { 21462306a36Sopenharmony_ci CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2, 21562306a36Sopenharmony_ci CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL, 21662306a36Sopenharmony_ci CS35L45_PCM_SRC_CLASSH_TGT, CS35L45_PCM_SRC_VDD_BATTMON, 21762306a36Sopenharmony_ci CS35L45_PCM_SRC_VDD_BSTMON, CS35L45_PCM_SRC_TEMPMON, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic const struct soc_enum cs35l45_dsp_rx_enums[] = { 22162306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX1_INPUT, 0, CS35L45_PCM_SRC_MASK, 22262306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 22362306a36Sopenharmony_ci cs35l45_dsp_rx_val), 22462306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX2_INPUT, 0, CS35L45_PCM_SRC_MASK, 22562306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 22662306a36Sopenharmony_ci cs35l45_dsp_rx_val), 22762306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX3_INPUT, 0, CS35L45_PCM_SRC_MASK, 22862306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 22962306a36Sopenharmony_ci cs35l45_dsp_rx_val), 23062306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX4_INPUT, 0, CS35L45_PCM_SRC_MASK, 23162306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 23262306a36Sopenharmony_ci cs35l45_dsp_rx_val), 23362306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX5_INPUT, 0, CS35L45_PCM_SRC_MASK, 23462306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 23562306a36Sopenharmony_ci cs35l45_dsp_rx_val), 23662306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX6_INPUT, 0, CS35L45_PCM_SRC_MASK, 23762306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 23862306a36Sopenharmony_ci cs35l45_dsp_rx_val), 23962306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX7_INPUT, 0, CS35L45_PCM_SRC_MASK, 24062306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 24162306a36Sopenharmony_ci cs35l45_dsp_rx_val), 24262306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX8_INPUT, 0, CS35L45_PCM_SRC_MASK, 24362306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt, 24462306a36Sopenharmony_ci cs35l45_dsp_rx_val), 24562306a36Sopenharmony_ci}; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic const char * const cs35l45_dac_txt[] = { 24862306a36Sopenharmony_ci "Zero", "ASP_RX1", "ASP_RX2", "DSP_TX1", "DSP_TX2" 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic const unsigned int cs35l45_dac_val[] = { 25262306a36Sopenharmony_ci CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2, 25362306a36Sopenharmony_ci CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic const struct soc_enum cs35l45_dacpcm_enums[] = { 25762306a36Sopenharmony_ci SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK, 25862306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt, 25962306a36Sopenharmony_ci cs35l45_dac_val), 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l45_asp_muxes[] = { 26362306a36Sopenharmony_ci SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]), 26462306a36Sopenharmony_ci SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]), 26562306a36Sopenharmony_ci SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]), 26662306a36Sopenharmony_ci SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]), 26762306a36Sopenharmony_ci SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]), 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l45_dsp_muxes[] = { 27162306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX1 Source", cs35l45_dsp_rx_enums[0]), 27262306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX2 Source", cs35l45_dsp_rx_enums[1]), 27362306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX3 Source", cs35l45_dsp_rx_enums[2]), 27462306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX4 Source", cs35l45_dsp_rx_enums[3]), 27562306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX5 Source", cs35l45_dsp_rx_enums[4]), 27662306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX6 Source", cs35l45_dsp_rx_enums[5]), 27762306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX7 Source", cs35l45_dsp_rx_enums[6]), 27862306a36Sopenharmony_ci SOC_DAPM_ENUM("DSP_RX8 Source", cs35l45_dsp_rx_enums[7]), 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l45_dac_muxes[] = { 28262306a36Sopenharmony_ci SOC_DAPM_ENUM("DACPCM Source", cs35l45_dacpcm_enums[0]), 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = { 28662306a36Sopenharmony_ci SND_SOC_DAPM_SPK("DSP1 Preload", NULL), 28762306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0, 28862306a36Sopenharmony_ci cs35l45_dsp_preload_ev, 28962306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 29062306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, 29162306a36Sopenharmony_ci cs35l45_dsp_audio_ev, 29262306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 29362306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0, 29462306a36Sopenharmony_ci cs35l45_global_en_ev, 29562306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 29662306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0), 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VMON_SRC"), 29962306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IMON_SRC"), 30062306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"), 30162306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"), 30262306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("ERR_VOL"), 30362306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("AMP_INTP"), 30462306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IL_TARGET"), 30562306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0), 30662306a36Sopenharmony_ci SND_SOC_DAPM_ADC("IMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0), 30762306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, CS35L45_BLOCK_ENABLES, 30862306a36Sopenharmony_ci CS35L45_VDD_BATTMON_EN_SHIFT, 0), 30962306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, CS35L45_BLOCK_ENABLES, 31062306a36Sopenharmony_ci CS35L45_VDD_BSTMON_EN_SHIFT, 0), 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0), 31362306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0), 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX1_EN_SHIFT, 0), 31662306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX2_EN_SHIFT, 0), 31762306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL, 2, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX3_EN_SHIFT, 0), 31862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX4_EN_SHIFT, 0), 31962306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0), 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]), 32262306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]), 32362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]), 32462306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]), 32562306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]), 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[0]), 32862306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[1]), 32962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[2]), 33062306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[3]), 33162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[4]), 33262306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX6 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[5]), 33362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX7 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[6]), 33462306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DSP_RX8 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[7]), 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DACPCM Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]), 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0), 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPK"), 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci#define CS35L45_ASP_MUX_ROUTE(name) \ 34462306a36Sopenharmony_ci { name" Source", "ASP_RX1", "ASP_RX1" }, \ 34562306a36Sopenharmony_ci { name" Source", "ASP_RX2", "ASP_RX2" }, \ 34662306a36Sopenharmony_ci { name" Source", "DSP_TX1", "DSP1" }, \ 34762306a36Sopenharmony_ci { name" Source", "DSP_TX2", "DSP1" }, \ 34862306a36Sopenharmony_ci { name" Source", "VMON", "VMON" }, \ 34962306a36Sopenharmony_ci { name" Source", "IMON", "IMON" }, \ 35062306a36Sopenharmony_ci { name" Source", "ERR_VOL", "ERR_VOL" }, \ 35162306a36Sopenharmony_ci { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \ 35262306a36Sopenharmony_ci { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \ 35362306a36Sopenharmony_ci { name" Source", "Interpolator", "AMP_INTP" }, \ 35462306a36Sopenharmony_ci { name" Source", "IL_TARGET", "IL_TARGET" } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci#define CS35L45_DSP_MUX_ROUTE(name) \ 35762306a36Sopenharmony_ci { name" Source", "ASP_RX1", "ASP_RX1" }, \ 35862306a36Sopenharmony_ci { name" Source", "ASP_RX2", "ASP_RX2" } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci#define CS35L45_DAC_MUX_ROUTE(name) \ 36162306a36Sopenharmony_ci { name" Source", "ASP_RX1", "ASP_RX1" }, \ 36262306a36Sopenharmony_ci { name" Source", "ASP_RX2", "ASP_RX2" }, \ 36362306a36Sopenharmony_ci { name" Source", "DSP_TX1", "DSP1" }, \ 36462306a36Sopenharmony_ci { name" Source", "DSP_TX2", "DSP1" } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l45_dapm_routes[] = { 36762306a36Sopenharmony_ci /* Feedback */ 36862306a36Sopenharmony_ci { "VMON", NULL, "VMON_SRC" }, 36962306a36Sopenharmony_ci { "IMON", NULL, "IMON_SRC" }, 37062306a36Sopenharmony_ci { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" }, 37162306a36Sopenharmony_ci { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" }, 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci { "Capture", NULL, "ASP_TX1"}, 37462306a36Sopenharmony_ci { "Capture", NULL, "ASP_TX2"}, 37562306a36Sopenharmony_ci { "Capture", NULL, "ASP_TX3"}, 37662306a36Sopenharmony_ci { "Capture", NULL, "ASP_TX4"}, 37762306a36Sopenharmony_ci { "Capture", NULL, "ASP_TX5"}, 37862306a36Sopenharmony_ci { "ASP_TX1", NULL, "ASP_TX1 Source"}, 37962306a36Sopenharmony_ci { "ASP_TX2", NULL, "ASP_TX2 Source"}, 38062306a36Sopenharmony_ci { "ASP_TX3", NULL, "ASP_TX3 Source"}, 38162306a36Sopenharmony_ci { "ASP_TX4", NULL, "ASP_TX4 Source"}, 38262306a36Sopenharmony_ci { "ASP_TX5", NULL, "ASP_TX5 Source"}, 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci { "ASP_TX1", NULL, "ASP_EN" }, 38562306a36Sopenharmony_ci { "ASP_TX2", NULL, "ASP_EN" }, 38662306a36Sopenharmony_ci { "ASP_TX3", NULL, "ASP_EN" }, 38762306a36Sopenharmony_ci { "ASP_TX4", NULL, "ASP_EN" }, 38862306a36Sopenharmony_ci { "ASP_TX1", NULL, "GLOBAL_EN" }, 38962306a36Sopenharmony_ci { "ASP_TX2", NULL, "GLOBAL_EN" }, 39062306a36Sopenharmony_ci { "ASP_TX3", NULL, "GLOBAL_EN" }, 39162306a36Sopenharmony_ci { "ASP_TX4", NULL, "GLOBAL_EN" }, 39262306a36Sopenharmony_ci { "ASP_TX5", NULL, "GLOBAL_EN" }, 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci CS35L45_ASP_MUX_ROUTE("ASP_TX1"), 39562306a36Sopenharmony_ci CS35L45_ASP_MUX_ROUTE("ASP_TX2"), 39662306a36Sopenharmony_ci CS35L45_ASP_MUX_ROUTE("ASP_TX3"), 39762306a36Sopenharmony_ci CS35L45_ASP_MUX_ROUTE("ASP_TX4"), 39862306a36Sopenharmony_ci CS35L45_ASP_MUX_ROUTE("ASP_TX5"), 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Playback */ 40162306a36Sopenharmony_ci { "ASP_RX1", NULL, "Playback" }, 40262306a36Sopenharmony_ci { "ASP_RX2", NULL, "Playback" }, 40362306a36Sopenharmony_ci { "ASP_RX1", NULL, "ASP_EN" }, 40462306a36Sopenharmony_ci { "ASP_RX2", NULL, "ASP_EN" }, 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci { "AMP", NULL, "DACPCM Source"}, 40762306a36Sopenharmony_ci { "AMP", NULL, "GLOBAL_EN"}, 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX1"), 41062306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX2"), 41162306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX3"), 41262306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX4"), 41362306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX5"), 41462306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX6"), 41562306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX7"), 41662306a36Sopenharmony_ci CS35L45_DSP_MUX_ROUTE("DSP_RX8"), 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX1 Source"}, 41962306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX2 Source"}, 42062306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX3 Source"}, 42162306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX4 Source"}, 42262306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX5 Source"}, 42362306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX6 Source"}, 42462306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX7 Source"}, 42562306a36Sopenharmony_ci {"DSP1", NULL, "DSP_RX8 Source"}, 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci {"DSP1 Preload", NULL, "DSP1 Preloader"}, 42862306a36Sopenharmony_ci {"DSP1", NULL, "DSP1 Preloader"}, 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci CS35L45_DAC_MUX_ROUTE("DACPCM"), 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci { "SPK", NULL, "AMP"}, 43362306a36Sopenharmony_ci}; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l45_controls[] = { 43862306a36Sopenharmony_ci /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */ 43962306a36Sopenharmony_ci SOC_SINGLE_S_TLV("Digital PCM Volume", 44062306a36Sopenharmony_ci CS35L45_AMP_PCM_CONTROL, 44162306a36Sopenharmony_ci CS35L45_AMP_VOL_PCM_SHIFT + 1, 44262306a36Sopenharmony_ci -409, 48, 44362306a36Sopenharmony_ci (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1, 44462306a36Sopenharmony_ci 0, cs35l45_dig_pcm_vol_tlv), 44562306a36Sopenharmony_ci WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), 44662306a36Sopenharmony_ci WM_ADSP_FW_CONTROL("DSP1", 0), 44762306a36Sopenharmony_ci}; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci unsigned int val; 45262306a36Sopenharmony_ci int freq_id; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci freq_id = cs35l45_get_clk_freq_id(freq); 45562306a36Sopenharmony_ci if (freq_id < 0) { 45662306a36Sopenharmony_ci dev_err(cs35l45->dev, "Invalid freq: %u\n", freq); 45762306a36Sopenharmony_ci return -EINVAL; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci regmap_read(cs35l45->regmap, CS35L45_REFCLK_INPUT, &val); 46162306a36Sopenharmony_ci val = (val & CS35L45_PLL_REFCLK_FREQ_MASK) >> CS35L45_PLL_REFCLK_FREQ_SHIFT; 46262306a36Sopenharmony_ci if (val == freq_id) 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); 46662306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, 46762306a36Sopenharmony_ci CS35L45_PLL_REFCLK_FREQ_MASK, 46862306a36Sopenharmony_ci freq_id << CS35L45_PLL_REFCLK_FREQ_SHIFT); 46962306a36Sopenharmony_ci regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); 47062306a36Sopenharmony_ci regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); 47162306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int cs35l45_asp_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(codec_dai->component); 47962306a36Sopenharmony_ci unsigned int asp_fmt, fsync_inv, bclk_inv; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 48262306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci dev_err(cs35l45->dev, "Invalid DAI clocking\n"); 48662306a36Sopenharmony_ci return -EINVAL; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 49062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 49162306a36Sopenharmony_ci asp_fmt = CS35l45_ASP_FMT_DSP_A; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 49462306a36Sopenharmony_ci asp_fmt = CS35L45_ASP_FMT_I2S; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci dev_err(cs35l45->dev, "Invalid DAI format\n"); 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 50262306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 50362306a36Sopenharmony_ci fsync_inv = 1; 50462306a36Sopenharmony_ci bclk_inv = 0; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 50762306a36Sopenharmony_ci fsync_inv = 0; 50862306a36Sopenharmony_ci bclk_inv = 1; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 51162306a36Sopenharmony_ci fsync_inv = 1; 51262306a36Sopenharmony_ci bclk_inv = 1; 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 51562306a36Sopenharmony_ci fsync_inv = 0; 51662306a36Sopenharmony_ci bclk_inv = 0; 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci default: 51962306a36Sopenharmony_ci dev_warn(cs35l45->dev, "Invalid DAI clock polarity\n"); 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 52462306a36Sopenharmony_ci CS35L45_ASP_FMT_MASK | 52562306a36Sopenharmony_ci CS35L45_ASP_FSYNC_INV_MASK | 52662306a36Sopenharmony_ci CS35L45_ASP_BCLK_INV_MASK, 52762306a36Sopenharmony_ci (asp_fmt << CS35L45_ASP_FMT_SHIFT) | 52862306a36Sopenharmony_ci (fsync_inv << CS35L45_ASP_FSYNC_INV_SHIFT) | 52962306a36Sopenharmony_ci (bclk_inv << CS35L45_ASP_BCLK_INV_SHIFT)); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int cs35l45_asp_hw_params(struct snd_pcm_substream *substream, 53562306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 53662306a36Sopenharmony_ci struct snd_soc_dai *dai) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 53962306a36Sopenharmony_ci unsigned int asp_width, asp_wl, global_fs, slot_multiple, asp_fmt; 54062306a36Sopenharmony_ci int bclk; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci switch (params_rate(params)) { 54362306a36Sopenharmony_ci case 44100: 54462306a36Sopenharmony_ci global_fs = CS35L45_44P100_KHZ; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci case 48000: 54762306a36Sopenharmony_ci global_fs = CS35L45_48P0_KHZ; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case 88200: 55062306a36Sopenharmony_ci global_fs = CS35L45_88P200_KHZ; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case 96000: 55362306a36Sopenharmony_ci global_fs = CS35L45_96P0_KHZ; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci default: 55662306a36Sopenharmony_ci dev_warn(cs35l45->dev, "Unsupported sample rate (%d)\n", 55762306a36Sopenharmony_ci params_rate(params)); 55862306a36Sopenharmony_ci return -EINVAL; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, 56262306a36Sopenharmony_ci CS35L45_GLOBAL_FS_MASK, 56362306a36Sopenharmony_ci global_fs << CS35L45_GLOBAL_FS_SHIFT); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci asp_wl = params_width(params); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (cs35l45->slot_width) 56862306a36Sopenharmony_ci asp_width = cs35l45->slot_width; 56962306a36Sopenharmony_ci else 57062306a36Sopenharmony_ci asp_width = params_width(params); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 57362306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 57462306a36Sopenharmony_ci CS35L45_ASP_WIDTH_RX_MASK, 57562306a36Sopenharmony_ci asp_width << CS35L45_ASP_WIDTH_RX_SHIFT); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL5, 57862306a36Sopenharmony_ci CS35L45_ASP_WL_MASK, 57962306a36Sopenharmony_ci asp_wl << CS35L45_ASP_WL_SHIFT); 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, 58262306a36Sopenharmony_ci CS35L45_ASP_WIDTH_TX_MASK, 58362306a36Sopenharmony_ci asp_width << CS35L45_ASP_WIDTH_TX_SHIFT); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL1, 58662306a36Sopenharmony_ci CS35L45_ASP_WL_MASK, 58762306a36Sopenharmony_ci asp_wl << CS35L45_ASP_WL_SHIFT); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (cs35l45->sysclk_set) 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* I2S always has an even number of channels */ 59462306a36Sopenharmony_ci regmap_read(cs35l45->regmap, CS35L45_ASP_CONTROL2, &asp_fmt); 59562306a36Sopenharmony_ci asp_fmt = (asp_fmt & CS35L45_ASP_FMT_MASK) >> CS35L45_ASP_FMT_SHIFT; 59662306a36Sopenharmony_ci if (asp_fmt == CS35L45_ASP_FMT_I2S) 59762306a36Sopenharmony_ci slot_multiple = 2; 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci slot_multiple = 1; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci bclk = snd_soc_tdm_params_to_bclk(params, asp_width, 60262306a36Sopenharmony_ci cs35l45->slot_count, slot_multiple); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return cs35l45_set_pll(cs35l45, bclk); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int cs35l45_asp_set_tdm_slot(struct snd_soc_dai *dai, 60862306a36Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 60962306a36Sopenharmony_ci int slots, int slot_width) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (slot_width && ((slot_width < 16) || (slot_width > 128))) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci cs35l45->slot_width = slot_width; 61762306a36Sopenharmony_ci cs35l45->slot_count = slots; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int cs35l45_asp_set_sysclk(struct snd_soc_dai *dai, 62362306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 62662306a36Sopenharmony_ci int ret; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (clk_id != 0) { 62962306a36Sopenharmony_ci dev_err(cs35l45->dev, "Invalid clk_id %d\n", clk_id); 63062306a36Sopenharmony_ci return -EINVAL; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci cs35l45->sysclk_set = false; 63462306a36Sopenharmony_ci if (freq == 0) 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ret = cs35l45_set_pll(cs35l45, freq); 63862306a36Sopenharmony_ci if (ret < 0) 63962306a36Sopenharmony_ci return -EINVAL; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci cs35l45->sysclk_set = true; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); 64962306a36Sopenharmony_ci unsigned int global_fs, val, hpf_tune; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (mute) 65262306a36Sopenharmony_ci return 0; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci regmap_read(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, &global_fs); 65562306a36Sopenharmony_ci global_fs = (global_fs & CS35L45_GLOBAL_FS_MASK) >> CS35L45_GLOBAL_FS_SHIFT; 65662306a36Sopenharmony_ci switch (global_fs) { 65762306a36Sopenharmony_ci case CS35L45_44P100_KHZ: 65862306a36Sopenharmony_ci hpf_tune = CS35L45_HPF_44P1; 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case CS35L45_88P200_KHZ: 66162306a36Sopenharmony_ci hpf_tune = CS35L45_HPF_88P2; 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci default: 66462306a36Sopenharmony_ci hpf_tune = CS35l45_HPF_DEFAULT; 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci regmap_read(cs35l45->regmap, CS35L45_AMP_PCM_HPF_TST, &val); 66962306a36Sopenharmony_ci if (val != hpf_tune) { 67062306a36Sopenharmony_ci struct reg_sequence hpf_override_seq[] = { 67162306a36Sopenharmony_ci { 0x00000040, 0x00000055 }, 67262306a36Sopenharmony_ci { 0x00000040, 0x000000AA }, 67362306a36Sopenharmony_ci { 0x00000044, 0x00000055 }, 67462306a36Sopenharmony_ci { 0x00000044, 0x000000AA }, 67562306a36Sopenharmony_ci { CS35L45_AMP_PCM_HPF_TST, hpf_tune }, 67662306a36Sopenharmony_ci { 0x00000040, 0x00000000 }, 67762306a36Sopenharmony_ci { 0x00000044, 0x00000000 }, 67862306a36Sopenharmony_ci }; 67962306a36Sopenharmony_ci regmap_multi_reg_write(cs35l45->regmap, hpf_override_seq, 68062306a36Sopenharmony_ci ARRAY_SIZE(hpf_override_seq)); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops cs35l45_asp_dai_ops = { 68762306a36Sopenharmony_ci .set_fmt = cs35l45_asp_set_fmt, 68862306a36Sopenharmony_ci .hw_params = cs35l45_asp_hw_params, 68962306a36Sopenharmony_ci .set_tdm_slot = cs35l45_asp_set_tdm_slot, 69062306a36Sopenharmony_ci .set_sysclk = cs35l45_asp_set_sysclk, 69162306a36Sopenharmony_ci .mute_stream = cs35l45_mute_stream, 69262306a36Sopenharmony_ci}; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic struct snd_soc_dai_driver cs35l45_dai[] = { 69562306a36Sopenharmony_ci { 69662306a36Sopenharmony_ci .name = "cs35l45", 69762306a36Sopenharmony_ci .playback = { 69862306a36Sopenharmony_ci .stream_name = "Playback", 69962306a36Sopenharmony_ci .channels_min = 1, 70062306a36Sopenharmony_ci .channels_max = 2, 70162306a36Sopenharmony_ci .rates = CS35L45_RATES, 70262306a36Sopenharmony_ci .formats = CS35L45_FORMATS, 70362306a36Sopenharmony_ci }, 70462306a36Sopenharmony_ci .capture = { 70562306a36Sopenharmony_ci .stream_name = "Capture", 70662306a36Sopenharmony_ci .channels_min = 1, 70762306a36Sopenharmony_ci .channels_max = 5, 70862306a36Sopenharmony_ci .rates = CS35L45_RATES, 70962306a36Sopenharmony_ci .formats = CS35L45_FORMATS, 71062306a36Sopenharmony_ci }, 71162306a36Sopenharmony_ci .symmetric_rate = true, 71262306a36Sopenharmony_ci .symmetric_sample_bits = true, 71362306a36Sopenharmony_ci .ops = &cs35l45_asp_dai_ops, 71462306a36Sopenharmony_ci }, 71562306a36Sopenharmony_ci}; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int cs35l45_component_probe(struct snd_soc_component *component) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return wm_adsp2_component_probe(&cs35l45->dsp, component); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic void cs35l45_component_remove(struct snd_soc_component *component) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci wm_adsp2_component_remove(&cs35l45->dsp, component); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic const struct snd_soc_component_driver cs35l45_component = { 73262306a36Sopenharmony_ci .probe = cs35l45_component_probe, 73362306a36Sopenharmony_ci .remove = cs35l45_component_remove, 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci .dapm_widgets = cs35l45_dapm_widgets, 73662306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets), 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci .dapm_routes = cs35l45_dapm_routes, 73962306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes), 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci .controls = cs35l45_controls, 74262306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(cs35l45_controls), 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci .name = "cs35l45", 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci .endianness = 1, 74762306a36Sopenharmony_ci}; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void cs35l45_setup_hibernate(struct cs35l45_private *cs35l45) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci unsigned int wksrc; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (cs35l45->bus_type == CONTROL_BUS_I2C) 75462306a36Sopenharmony_ci wksrc = CS35L45_WKSRC_I2C; 75562306a36Sopenharmony_ci else 75662306a36Sopenharmony_ci wksrc = CS35L45_WKSRC_SPI; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL, 75962306a36Sopenharmony_ci CS35L45_WKSRC_EN_MASK, 76062306a36Sopenharmony_ci wksrc << CS35L45_WKSRC_EN_SHIFT); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL, 76362306a36Sopenharmony_ci CS35L45_UPDT_WKCTL_MASK); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_WKI2C_CTL, 76662306a36Sopenharmony_ci CS35L45_WKI2C_ADDR_MASK, cs35l45->i2c_addr); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_WKI2C_CTL, 76962306a36Sopenharmony_ci CS35L45_UPDT_WKI2C_MASK); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Enter hibernate\n"); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci cs35l45_setup_hibernate(cs35l45); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, CS35L45_DSP_VIRT2_MBOX_MASK); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci // Don't wait for ACK since bus activity would wake the device 78162306a36Sopenharmony_ci regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci const int wake_retries = 20; 78962306a36Sopenharmony_ci const int sleep_retries = 5; 79062306a36Sopenharmony_ci int ret, i, j; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci for (i = 0; i < sleep_retries; i++) { 79362306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Exit hibernate\n"); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci for (j = 0; j < wake_retries; j++) { 79662306a36Sopenharmony_ci ret = cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap, 79762306a36Sopenharmony_ci CSPL_MBOX_CMD_OUT_OF_HIBERNATE); 79862306a36Sopenharmony_ci if (!ret) { 79962306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j); 80062306a36Sopenharmony_ci regmap_clear_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, 80162306a36Sopenharmony_ci CS35L45_DSP_VIRT2_MBOX_MASK); 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci usleep_range(100, 200); 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci dev_err(cs35l45->dev, "Wake failed, re-enter hibernate: %d\n", ret); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci cs35l45_setup_hibernate(cs35l45); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci dev_err(cs35l45->dev, "Timed out waking device\n"); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return -ETIMEDOUT; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int cs35l45_runtime_suspend(struct device *dev) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running) 82262306a36Sopenharmony_ci return 0; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci cs35l45_enter_hibernate(cs35l45); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci regcache_cache_only(cs35l45->regmap, true); 82762306a36Sopenharmony_ci regcache_mark_dirty(cs35l45->regmap); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Runtime suspended\n"); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int cs35l45_runtime_resume(struct device *dev) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 83762306a36Sopenharmony_ci int ret; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running) 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Runtime resume\n"); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci regcache_cache_only(cs35l45->regmap, false); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci ret = cs35l45_exit_hibernate(cs35l45); 84762306a36Sopenharmony_ci if (ret) 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci ret = regcache_sync(cs35l45->regmap); 85162306a36Sopenharmony_ci if (ret != 0) 85262306a36Sopenharmony_ci dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Clear global error status */ 85562306a36Sopenharmony_ci regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 85662306a36Sopenharmony_ci regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 85762306a36Sopenharmony_ci regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); 85862306a36Sopenharmony_ci return ret; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic int cs35l45_sys_suspend(struct device *dev) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "System suspend, disabling IRQ\n"); 86662306a36Sopenharmony_ci disable_irq(cs35l45->irq); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic int cs35l45_sys_suspend_noirq(struct device *dev) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Late system suspend, reenabling IRQ\n"); 87662306a36Sopenharmony_ci enable_irq(cs35l45->irq); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int cs35l45_sys_resume_noirq(struct device *dev) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "Early system resume, disabling IRQ\n"); 88662306a36Sopenharmony_ci disable_irq(cs35l45->irq); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return 0; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int cs35l45_sys_resume(struct device *dev) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "System resume, reenabling IRQ\n"); 89662306a36Sopenharmony_ci enable_irq(cs35l45->irq); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int cs35l45_apply_property_config(struct cs35l45_private *cs35l45) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct device_node *node = cs35l45->dev->of_node; 90462306a36Sopenharmony_ci unsigned int gpio_regs[] = {CS35L45_GPIO1_CTRL1, CS35L45_GPIO2_CTRL1, 90562306a36Sopenharmony_ci CS35L45_GPIO3_CTRL1}; 90662306a36Sopenharmony_ci unsigned int pad_regs[] = {CS35L45_SYNC_GPIO1, 90762306a36Sopenharmony_ci CS35L45_INTB_GPIO2_MCLK_REF, CS35L45_GPIO3}; 90862306a36Sopenharmony_ci struct device_node *child; 90962306a36Sopenharmony_ci unsigned int val; 91062306a36Sopenharmony_ci char of_name[32]; 91162306a36Sopenharmony_ci int ret, i; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (!node) 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci for (i = 0; i < CS35L45_NUM_GPIOS; i++) { 91762306a36Sopenharmony_ci sprintf(of_name, "cirrus,gpio-ctrl%d", i + 1); 91862306a36Sopenharmony_ci child = of_get_child_by_name(node, of_name); 91962306a36Sopenharmony_ci if (!child) 92062306a36Sopenharmony_ci continue; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-dir", &val); 92362306a36Sopenharmony_ci if (!ret) 92462306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, gpio_regs[i], 92562306a36Sopenharmony_ci CS35L45_GPIO_DIR_MASK, 92662306a36Sopenharmony_ci val << CS35L45_GPIO_DIR_SHIFT); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-lvl", &val); 92962306a36Sopenharmony_ci if (!ret) 93062306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, gpio_regs[i], 93162306a36Sopenharmony_ci CS35L45_GPIO_LVL_MASK, 93262306a36Sopenharmony_ci val << CS35L45_GPIO_LVL_SHIFT); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-op-cfg", &val); 93562306a36Sopenharmony_ci if (!ret) 93662306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, gpio_regs[i], 93762306a36Sopenharmony_ci CS35L45_GPIO_OP_CFG_MASK, 93862306a36Sopenharmony_ci val << CS35L45_GPIO_OP_CFG_SHIFT); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-pol", &val); 94162306a36Sopenharmony_ci if (!ret) 94262306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, gpio_regs[i], 94362306a36Sopenharmony_ci CS35L45_GPIO_POL_MASK, 94462306a36Sopenharmony_ci val << CS35L45_GPIO_POL_SHIFT); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-ctrl", &val); 94762306a36Sopenharmony_ci if (!ret) 94862306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, pad_regs[i], 94962306a36Sopenharmony_ci CS35L45_GPIO_CTRL_MASK, 95062306a36Sopenharmony_ci val << CS35L45_GPIO_CTRL_SHIFT); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ret = of_property_read_u32(child, "gpio-invert", &val); 95362306a36Sopenharmony_ci if (!ret) { 95462306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, pad_regs[i], 95562306a36Sopenharmony_ci CS35L45_GPIO_INVERT_MASK, 95662306a36Sopenharmony_ci val << CS35L45_GPIO_INVERT_SHIFT); 95762306a36Sopenharmony_ci if (i == 1) 95862306a36Sopenharmony_ci cs35l45->irq_invert = val; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci of_node_put(child); 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (device_property_read_u32(cs35l45->dev, 96562306a36Sopenharmony_ci "cirrus,asp-sdout-hiz-ctrl", &val) == 0) { 96662306a36Sopenharmony_ci regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3, 96762306a36Sopenharmony_ci CS35L45_ASP_DOUT_HIZ_CTRL_MASK, 96862306a36Sopenharmony_ci val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci return 0; 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic int cs35l45_dsp_virt2_mbox3_irq_handle(struct cs35l45_private *cs35l45, 97562306a36Sopenharmony_ci const unsigned int cmd, 97662306a36Sopenharmony_ci unsigned int data) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci static char *speak_status = "Unknown"; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci switch (cmd) { 98162306a36Sopenharmony_ci case EVENT_SPEAKER_STATUS: 98262306a36Sopenharmony_ci switch (data) { 98362306a36Sopenharmony_ci case 1: 98462306a36Sopenharmony_ci speak_status = "All Clear"; 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci case 2: 98762306a36Sopenharmony_ci speak_status = "Open Circuit"; 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci case 4: 99062306a36Sopenharmony_ci speak_status = "Short Circuit"; 99162306a36Sopenharmony_ci break; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci dev_info(cs35l45->dev, "MBOX event (SPEAKER_STATUS): %s\n", 99562306a36Sopenharmony_ci speak_status); 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci case EVENT_BOOT_DONE: 99862306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "MBOX event (BOOT_DONE)\n"); 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci default: 100162306a36Sopenharmony_ci dev_err(cs35l45->dev, "MBOX event not supported %u\n", cmd); 100262306a36Sopenharmony_ci return -EINVAL; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci return 0; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic irqreturn_t cs35l45_dsp_virt2_mbox_cb(int irq, void *data) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = data; 101162306a36Sopenharmony_ci unsigned int mbox_val; 101262306a36Sopenharmony_ci int ret = 0; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_3, &mbox_val); 101562306a36Sopenharmony_ci if (!ret && mbox_val) 101662306a36Sopenharmony_ci cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45, mbox_val & CS35L45_MBOX3_CMD_MASK, 101762306a36Sopenharmony_ci (mbox_val & CS35L45_MBOX3_DATA_MASK) >> CS35L45_MBOX3_DATA_SHIFT); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Handle DSP trace log IRQ */ 102062306a36Sopenharmony_ci ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_4, &mbox_val); 102162306a36Sopenharmony_ci if (!ret && mbox_val != 0) { 102262306a36Sopenharmony_ci dev_err(cs35l45->dev, "Spurious DSP MBOX4 IRQ\n"); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci return IRQ_RETVAL(ret); 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic irqreturn_t cs35l45_pll_unlock(int irq, void *data) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = data; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "PLL unlock detected!"); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci return IRQ_HANDLED; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic irqreturn_t cs35l45_pll_lock(int irq, void *data) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = data; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci dev_dbg(cs35l45->dev, "PLL lock detected!"); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return IRQ_HANDLED; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic irqreturn_t cs35l45_spk_safe_err(int irq, void *data); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic const struct cs35l45_irq cs35l45_irqs[] = { 104962306a36Sopenharmony_ci CS35L45_IRQ(AMP_SHORT_ERR, "Amplifier short error", cs35l45_spk_safe_err), 105062306a36Sopenharmony_ci CS35L45_IRQ(UVLO_VDDBATT_ERR, "VDDBATT undervoltage error", cs35l45_spk_safe_err), 105162306a36Sopenharmony_ci CS35L45_IRQ(BST_SHORT_ERR, "Boost inductor error", cs35l45_spk_safe_err), 105262306a36Sopenharmony_ci CS35L45_IRQ(BST_UVP_ERR, "Boost undervoltage error", cs35l45_spk_safe_err), 105362306a36Sopenharmony_ci CS35L45_IRQ(TEMP_ERR, "Overtemperature error", cs35l45_spk_safe_err), 105462306a36Sopenharmony_ci CS35L45_IRQ(AMP_CAL_ERR, "Amplifier calibration error", cs35l45_spk_safe_err), 105562306a36Sopenharmony_ci CS35L45_IRQ(UVLO_VDDLV_ERR, "LV threshold detector error", cs35l45_spk_safe_err), 105662306a36Sopenharmony_ci CS35L45_IRQ(GLOBAL_ERROR, "Global error", cs35l45_spk_safe_err), 105762306a36Sopenharmony_ci CS35L45_IRQ(DSP_WDT_EXPIRE, "DSP Watchdog Timer", cs35l45_spk_safe_err), 105862306a36Sopenharmony_ci CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE, "PLL unlock", cs35l45_pll_unlock), 105962306a36Sopenharmony_ci CS35L45_IRQ(PLL_LOCK_FLAG, "PLL lock", cs35l45_pll_lock), 106062306a36Sopenharmony_ci CS35L45_IRQ(DSP_VIRT2_MBOX, "DSP virtual MBOX 2 write flag", cs35l45_dsp_virt2_mbox_cb), 106162306a36Sopenharmony_ci}; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic irqreturn_t cs35l45_spk_safe_err(int irq, void *data) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci struct cs35l45_private *cs35l45 = data; 106662306a36Sopenharmony_ci int i; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci dev_err(cs35l45->dev, "%s condition detected!\n", cs35l45_irqs[i].name); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci return IRQ_HANDLED; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic const struct regmap_irq cs35l45_reg_irqs[] = { 107662306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_1, AMP_SHORT_ERR), 107762306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_1, UVLO_VDDBATT_ERR), 107862306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_1, BST_SHORT_ERR), 107962306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_1, BST_UVP_ERR), 108062306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_1, TEMP_ERR), 108162306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_3, AMP_CAL_ERR), 108262306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_18, UVLO_VDDLV_ERR), 108362306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_18, GLOBAL_ERROR), 108462306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_WDT_EXPIRE), 108562306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_UNLOCK_FLAG_RISE), 108662306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_LOCK_FLAG), 108762306a36Sopenharmony_ci CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_VIRT2_MBOX), 108862306a36Sopenharmony_ci}; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic const struct regmap_irq_chip cs35l45_regmap_irq_chip = { 109162306a36Sopenharmony_ci .name = "cs35l45 IRQ1 Controller", 109262306a36Sopenharmony_ci .main_status = CS35L45_IRQ1_STATUS, 109362306a36Sopenharmony_ci .status_base = CS35L45_IRQ1_EINT_1, 109462306a36Sopenharmony_ci .mask_base = CS35L45_IRQ1_MASK_1, 109562306a36Sopenharmony_ci .ack_base = CS35L45_IRQ1_EINT_1, 109662306a36Sopenharmony_ci .num_regs = 18, 109762306a36Sopenharmony_ci .irqs = cs35l45_reg_irqs, 109862306a36Sopenharmony_ci .num_irqs = ARRAY_SIZE(cs35l45_reg_irqs), 109962306a36Sopenharmony_ci .runtime_pm = true, 110062306a36Sopenharmony_ci}; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int cs35l45_initialize(struct cs35l45_private *cs35l45) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct device *dev = cs35l45->dev; 110562306a36Sopenharmony_ci unsigned int dev_id[5]; 110662306a36Sopenharmony_ci unsigned int sts; 110762306a36Sopenharmony_ci int ret; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci ret = regmap_read_poll_timeout(cs35l45->regmap, CS35L45_IRQ1_EINT_4, sts, 111062306a36Sopenharmony_ci (sts & CS35L45_OTP_BOOT_DONE_STS_MASK), 111162306a36Sopenharmony_ci 1000, 5000); 111262306a36Sopenharmony_ci if (ret < 0) { 111362306a36Sopenharmony_ci dev_err(cs35l45->dev, "Timeout waiting for OTP boot\n"); 111462306a36Sopenharmony_ci return ret; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = regmap_bulk_read(cs35l45->regmap, CS35L45_DEVID, dev_id, ARRAY_SIZE(dev_id)); 111862306a36Sopenharmony_ci if (ret) { 111962306a36Sopenharmony_ci dev_err(cs35l45->dev, "Get Device ID failed: %d\n", ret); 112062306a36Sopenharmony_ci return ret; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci switch (dev_id[0]) { 112462306a36Sopenharmony_ci case 0x35A450: 112562306a36Sopenharmony_ci case 0x35A460: 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci default: 112862306a36Sopenharmony_ci dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]); 112962306a36Sopenharmony_ci return -ENODEV; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci dev_info(cs35l45->dev, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n", 113362306a36Sopenharmony_ci dev_id[1], dev_id[4]); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci regmap_write(cs35l45->regmap, CS35L45_IRQ1_EINT_4, 113662306a36Sopenharmony_ci CS35L45_OTP_BOOT_DONE_STS_MASK | CS35L45_OTP_BUSY_MASK); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = cs35l45_apply_patch(cs35l45); 113962306a36Sopenharmony_ci if (ret < 0) { 114062306a36Sopenharmony_ci dev_err(dev, "Failed to apply init patch %d\n", ret); 114162306a36Sopenharmony_ci return ret; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci ret = cs35l45_apply_property_config(cs35l45); 114562306a36Sopenharmony_ci if (ret < 0) 114662306a36Sopenharmony_ci return ret; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci return 0; 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic const struct reg_sequence cs35l45_fs_errata_patch[] = { 115262306a36Sopenharmony_ci {0x02B80080, 0x00000001}, 115362306a36Sopenharmony_ci {0x02B80088, 0x00000001}, 115462306a36Sopenharmony_ci {0x02B80090, 0x00000001}, 115562306a36Sopenharmony_ci {0x02B80098, 0x00000001}, 115662306a36Sopenharmony_ci {0x02B800A0, 0x00000001}, 115762306a36Sopenharmony_ci {0x02B800A8, 0x00000001}, 115862306a36Sopenharmony_ci {0x02B800B0, 0x00000001}, 115962306a36Sopenharmony_ci {0x02B800B8, 0x00000001}, 116062306a36Sopenharmony_ci {0x02B80280, 0x00000001}, 116162306a36Sopenharmony_ci {0x02B80288, 0x00000001}, 116262306a36Sopenharmony_ci {0x02B80290, 0x00000001}, 116362306a36Sopenharmony_ci {0x02B80298, 0x00000001}, 116462306a36Sopenharmony_ci {0x02B802A0, 0x00000001}, 116562306a36Sopenharmony_ci {0x02B802A8, 0x00000001}, 116662306a36Sopenharmony_ci {0x02B802B0, 0x00000001}, 116762306a36Sopenharmony_ci {0x02B802B8, 0x00000001}, 116862306a36Sopenharmony_ci}; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic const struct cs_dsp_region cs35l45_dsp1_regions[] = { 117162306a36Sopenharmony_ci { .type = WMFW_HALO_PM_PACKED, .base = CS35L45_DSP1_PMEM_0 }, 117262306a36Sopenharmony_ci { .type = WMFW_HALO_XM_PACKED, .base = CS35L45_DSP1_XMEM_PACK_0 }, 117362306a36Sopenharmony_ci { .type = WMFW_HALO_YM_PACKED, .base = CS35L45_DSP1_YMEM_PACK_0 }, 117462306a36Sopenharmony_ci {. type = WMFW_ADSP2_XM, .base = CS35L45_DSP1_XMEM_UNPACK24_0}, 117562306a36Sopenharmony_ci {. type = WMFW_ADSP2_YM, .base = CS35L45_DSP1_YMEM_UNPACK24_0}, 117662306a36Sopenharmony_ci}; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic int cs35l45_dsp_init(struct cs35l45_private *cs35l45) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct wm_adsp *dsp = &cs35l45->dsp; 118162306a36Sopenharmony_ci int ret; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci dsp->part = "cs35l45"; 118462306a36Sopenharmony_ci dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */ 118562306a36Sopenharmony_ci dsp->toggle_preload = true; 118662306a36Sopenharmony_ci dsp->cs_dsp.num = 1; 118762306a36Sopenharmony_ci dsp->cs_dsp.type = WMFW_HALO; 118862306a36Sopenharmony_ci dsp->cs_dsp.rev = 0; 118962306a36Sopenharmony_ci dsp->cs_dsp.dev = cs35l45->dev; 119062306a36Sopenharmony_ci dsp->cs_dsp.regmap = cs35l45->regmap; 119162306a36Sopenharmony_ci dsp->cs_dsp.base = CS35L45_DSP1_CLOCK_FREQ; 119262306a36Sopenharmony_ci dsp->cs_dsp.base_sysinfo = CS35L45_DSP1_SYS_ID; 119362306a36Sopenharmony_ci dsp->cs_dsp.mem = cs35l45_dsp1_regions; 119462306a36Sopenharmony_ci dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l45_dsp1_regions); 119562306a36Sopenharmony_ci dsp->cs_dsp.lock_regions = 0xFFFFFFFF; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci ret = wm_halo_init(dsp); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci regmap_multi_reg_write(cs35l45->regmap, cs35l45_fs_errata_patch, 120062306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_fs_errata_patch)); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci return ret; 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ciint cs35l45_probe(struct cs35l45_private *cs35l45) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct device *dev = cs35l45->dev; 120862306a36Sopenharmony_ci unsigned long irq_pol = IRQF_ONESHOT | IRQF_SHARED; 120962306a36Sopenharmony_ci int ret, i, irq; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt"); 121262306a36Sopenharmony_ci if (IS_ERR(cs35l45->vdd_batt)) 121362306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_batt), 121462306a36Sopenharmony_ci "Failed to request vdd-batt\n"); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci cs35l45->vdd_a = devm_regulator_get(dev, "vdd-a"); 121762306a36Sopenharmony_ci if (IS_ERR(cs35l45->vdd_a)) 121862306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_a), 121962306a36Sopenharmony_ci "Failed to request vdd-a\n"); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci /* VDD_BATT must always be enabled before other supplies */ 122262306a36Sopenharmony_ci ret = regulator_enable(cs35l45->vdd_batt); 122362306a36Sopenharmony_ci if (ret < 0) 122462306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to enable vdd-batt\n"); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci ret = regulator_enable(cs35l45->vdd_a); 122762306a36Sopenharmony_ci if (ret < 0) 122862306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to enable vdd-a\n"); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* If reset is shared only one instance can claim it */ 123162306a36Sopenharmony_ci cs35l45->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 123262306a36Sopenharmony_ci if (IS_ERR(cs35l45->reset_gpio)) { 123362306a36Sopenharmony_ci ret = PTR_ERR(cs35l45->reset_gpio); 123462306a36Sopenharmony_ci cs35l45->reset_gpio = NULL; 123562306a36Sopenharmony_ci if (ret == -EBUSY) { 123662306a36Sopenharmony_ci dev_dbg(dev, "Reset line busy, assuming shared reset\n"); 123762306a36Sopenharmony_ci } else { 123862306a36Sopenharmony_ci dev_err_probe(dev, ret, "Failed to get reset GPIO\n"); 123962306a36Sopenharmony_ci goto err; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (cs35l45->reset_gpio) { 124462306a36Sopenharmony_ci usleep_range(CS35L45_RESET_HOLD_US, CS35L45_RESET_HOLD_US + 100); 124562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l45->reset_gpio, 1); 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci ret = cs35l45_initialize(cs35l45); 125162306a36Sopenharmony_ci if (ret < 0) 125262306a36Sopenharmony_ci goto err_reset; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci ret = cs35l45_dsp_init(cs35l45); 125562306a36Sopenharmony_ci if (ret < 0) 125662306a36Sopenharmony_ci goto err_reset; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000); 125962306a36Sopenharmony_ci pm_runtime_use_autosuspend(cs35l45->dev); 126062306a36Sopenharmony_ci pm_runtime_mark_last_busy(cs35l45->dev); 126162306a36Sopenharmony_ci pm_runtime_set_active(cs35l45->dev); 126262306a36Sopenharmony_ci pm_runtime_get_noresume(cs35l45->dev); 126362306a36Sopenharmony_ci pm_runtime_enable(cs35l45->dev); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (cs35l45->irq) { 126662306a36Sopenharmony_ci if (cs35l45->irq_invert) 126762306a36Sopenharmony_ci irq_pol |= IRQF_TRIGGER_HIGH; 126862306a36Sopenharmony_ci else 126962306a36Sopenharmony_ci irq_pol |= IRQF_TRIGGER_LOW; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci ret = devm_regmap_add_irq_chip(dev, cs35l45->regmap, cs35l45->irq, irq_pol, 0, 127262306a36Sopenharmony_ci &cs35l45_regmap_irq_chip, &cs35l45->irq_data); 127362306a36Sopenharmony_ci if (ret) { 127462306a36Sopenharmony_ci dev_err(dev, "Failed to register IRQ chip: %d\n", ret); 127562306a36Sopenharmony_ci goto err_dsp; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l45_irqs); i++) { 127962306a36Sopenharmony_ci irq = regmap_irq_get_virq(cs35l45->irq_data, cs35l45_irqs[i].irq); 128062306a36Sopenharmony_ci if (irq < 0) { 128162306a36Sopenharmony_ci dev_err(dev, "Failed to get %s\n", cs35l45_irqs[i].name); 128262306a36Sopenharmony_ci ret = irq; 128362306a36Sopenharmony_ci goto err_dsp; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq, NULL, cs35l45_irqs[i].handler, 128762306a36Sopenharmony_ci irq_pol, cs35l45_irqs[i].name, cs35l45); 128862306a36Sopenharmony_ci if (ret) { 128962306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ %s: %d\n", 129062306a36Sopenharmony_ci cs35l45_irqs[i].name, ret); 129162306a36Sopenharmony_ci goto err_dsp; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &cs35l45_component, 129762306a36Sopenharmony_ci cs35l45_dai, 129862306a36Sopenharmony_ci ARRAY_SIZE(cs35l45_dai)); 129962306a36Sopenharmony_ci if (ret < 0) 130062306a36Sopenharmony_ci goto err_dsp; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci pm_runtime_put_autosuspend(cs35l45->dev); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci return 0; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cierr_dsp: 130762306a36Sopenharmony_ci pm_runtime_disable(cs35l45->dev); 130862306a36Sopenharmony_ci pm_runtime_put_noidle(cs35l45->dev); 130962306a36Sopenharmony_ci wm_adsp2_remove(&cs35l45->dsp); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cierr_reset: 131262306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); 131362306a36Sopenharmony_cierr: 131462306a36Sopenharmony_ci regulator_disable(cs35l45->vdd_a); 131562306a36Sopenharmony_ci regulator_disable(cs35l45->vdd_batt); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci return ret; 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_civoid cs35l45_remove(struct cs35l45_private *cs35l45) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci pm_runtime_get_sync(cs35l45->dev); 132462306a36Sopenharmony_ci pm_runtime_disable(cs35l45->dev); 132562306a36Sopenharmony_ci wm_adsp2_remove(&cs35l45->dsp); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci pm_runtime_put_noidle(cs35l45->dev); 133062306a36Sopenharmony_ci regulator_disable(cs35l45->vdd_a); 133162306a36Sopenharmony_ci /* VDD_BATT must be the last to power-off */ 133262306a36Sopenharmony_ci regulator_disable(cs35l45->vdd_batt); 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ciEXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = { 133762306a36Sopenharmony_ci RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend, cs35l45_sys_resume) 134062306a36Sopenharmony_ci NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq, cs35l45_sys_resume_noirq) 134162306a36Sopenharmony_ci}; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC CS35L45 driver"); 134462306a36Sopenharmony_ciMODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); 134562306a36Sopenharmony_ciMODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 134662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1347