brintos

brintos / linux-shallow public Read only

0
0
Text · 44.8 KiB · fa1d9d9 Raw
1517 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// cs35l45.c - CS35L45 ALSA SoC audio driver4//5// Copyright 2019-2022 Cirrus Logic, Inc.6//7// Author: James Schulman <james.schulman@cirrus.com>8 9#include <linux/gpio/consumer.h>10#include <linux/module.h>11#include <linux/pm_runtime.h>12#include <linux/property.h>13#include <linux/firmware.h>14#include <linux/regulator/consumer.h>15#include <sound/core.h>16#include <sound/pcm.h>17#include <sound/pcm_params.h>18#include <sound/soc.h>19#include <sound/tlv.h>20 21#include "cs35l45.h"22 23static bool cs35l45_check_cspl_mbox_sts(const enum cs35l45_cspl_mboxcmd cmd,24					enum cs35l45_cspl_mboxstate sts)25{26	switch (cmd) {27	case CSPL_MBOX_CMD_NONE:28	case CSPL_MBOX_CMD_UNKNOWN_CMD:29		return true;30	case CSPL_MBOX_CMD_PAUSE:31	case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:32		return (sts == CSPL_MBOX_STS_PAUSED);33	case CSPL_MBOX_CMD_RESUME:34		return (sts == CSPL_MBOX_STS_RUNNING);35	case CSPL_MBOX_CMD_REINIT:36		return (sts == CSPL_MBOX_STS_RUNNING);37	case CSPL_MBOX_CMD_STOP_PRE_REINIT:38		return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);39	case CSPL_MBOX_CMD_HIBERNATE:40		return (sts == CSPL_MBOX_STS_HIBERNATE);41	default:42		return false;43	}44}45 46static int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private *cs35l45,47				      struct regmap *regmap,48				      const enum cs35l45_cspl_mboxcmd cmd)49{50	unsigned int sts = 0, i;51	int ret;52 53	if (!cs35l45->dsp.cs_dsp.running) {54		dev_err(cs35l45->dev, "DSP not running\n");55		return -EPERM;56	}57 58	// Set mailbox cmd59	ret = regmap_write(regmap, CS35L45_DSP_VIRT1_MBOX_1, cmd);60	if (ret < 0) {61		if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)62			dev_err(cs35l45->dev, "Failed to write MBOX: %d\n", ret);63		return ret;64	}65 66	// Read mailbox status and verify it is appropriate for the given cmd67	for (i = 0; i < 5; i++) {68		usleep_range(1000, 1100);69 70		ret = regmap_read(regmap, CS35L45_DSP_MBOX_2, &sts);71		if (ret < 0) {72			dev_err(cs35l45->dev, "Failed to read MBOX STS: %d\n", ret);73			continue;74		}75 76		if (!cs35l45_check_cspl_mbox_sts(cmd, sts))77			dev_dbg(cs35l45->dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts);78		else79			return 0;80	}81 82	if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)83		dev_err(cs35l45->dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);84 85	return -ENOMSG;86}87 88static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w,89				struct snd_kcontrol *kcontrol, int event)90{91	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);92	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);93 94	dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event);95 96	switch (event) {97	case SND_SOC_DAPM_POST_PMU:98		regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES,99			     CS35L45_GLOBAL_EN_MASK);100 101		usleep_range(CS35L45_POST_GLOBAL_EN_US, CS35L45_POST_GLOBAL_EN_US + 100);102		break;103	case SND_SOC_DAPM_PRE_PMD:104		usleep_range(CS35L45_PRE_GLOBAL_DIS_US, CS35L45_PRE_GLOBAL_DIS_US + 100);105 106		regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 0);107		break;108	default:109		break;110	}111 112	return 0;113}114 115static int cs35l45_dsp_preload_ev(struct snd_soc_dapm_widget *w,116				  struct snd_kcontrol *kcontrol, int event)117{118	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);119	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);120	int ret;121 122	switch (event) {123	case SND_SOC_DAPM_PRE_PMU:124		if (cs35l45->dsp.cs_dsp.booted)125			return 0;126 127		return wm_adsp_early_event(w, kcontrol, event);128	case SND_SOC_DAPM_POST_PMU:129		if (cs35l45->dsp.cs_dsp.running)130			return 0;131 132		regmap_set_bits(cs35l45->regmap, CS35L45_PWRMGT_CTL,133				   CS35L45_MEM_RDY_MASK);134 135		return wm_adsp_event(w, kcontrol, event);136	case SND_SOC_DAPM_PRE_PMD:137		if (cs35l45->dsp.preloaded)138			return 0;139 140		if (cs35l45->dsp.cs_dsp.running) {141			ret = wm_adsp_event(w, kcontrol, event);142			if (ret)143				return ret;144		}145 146		return wm_adsp_early_event(w, kcontrol, event);147	default:148		return 0;149	}150}151 152static int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget *w,153				struct snd_kcontrol *kcontrol, int event)154{155	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);156	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);157 158	switch (event) {159	case SND_SOC_DAPM_POST_PMU:160		return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,161						 CSPL_MBOX_CMD_RESUME);162	case SND_SOC_DAPM_PRE_PMD:163		return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,164						 CSPL_MBOX_CMD_PAUSE);165	default:166		return 0;167	}168 169	return 0;170}171 172static int cs35l45_activate_ctl(struct snd_soc_component *component,173				const char *ctl_name, bool active)174{175	struct snd_card *card = component->card->snd_card;176	struct snd_kcontrol *kcontrol;177	struct snd_kcontrol_volatile *vd;178	unsigned int index_offset;179 180	kcontrol = snd_soc_component_get_kcontrol(component, ctl_name);181	if (!kcontrol) {182		dev_err(component->dev, "Can't find kcontrol %s\n", ctl_name);183		return -EINVAL;184	}185 186	index_offset = snd_ctl_get_ioff(kcontrol, &kcontrol->id);187	vd = &kcontrol->vd[index_offset];188	if (active)189		vd->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;190	else191		vd->access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;192 193	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kcontrol->id);194 195	return 0;196}197 198static int cs35l45_amplifier_mode_get(struct snd_kcontrol *kcontrol,199				      struct snd_ctl_elem_value *ucontrol)200{201	struct snd_soc_component *component =202			snd_soc_kcontrol_component(kcontrol);203	struct cs35l45_private *cs35l45 =204			snd_soc_component_get_drvdata(component);205 206	ucontrol->value.integer.value[0] = cs35l45->amplifier_mode;207 208	return 0;209}210 211static int cs35l45_amplifier_mode_put(struct snd_kcontrol *kcontrol,212				      struct snd_ctl_elem_value *ucontrol)213{214	struct snd_soc_component *component =215			snd_soc_kcontrol_component(kcontrol);216	struct cs35l45_private *cs35l45 =217			snd_soc_component_get_drvdata(component);218	struct snd_soc_dapm_context *dapm =219			snd_soc_component_get_dapm(component);220	unsigned int amp_state;221	int ret;222 223	if ((ucontrol->value.integer.value[0] == cs35l45->amplifier_mode) ||224	    (ucontrol->value.integer.value[0] > AMP_MODE_RCV))225		return 0;226 227	snd_soc_dapm_mutex_lock(dapm);228 229	ret = regmap_read(cs35l45->regmap, CS35L45_BLOCK_ENABLES, &amp_state);230	if (ret < 0) {231		dev_err(cs35l45->dev, "Failed to read AMP state: %d\n", ret);232		snd_soc_dapm_mutex_unlock(dapm);233		return ret;234	}235 236	regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,237				  CS35L45_AMP_EN_MASK);238	snd_soc_component_disable_pin_unlocked(component, "SPK");239	snd_soc_dapm_sync_unlocked(dapm);240 241	if (ucontrol->value.integer.value[0] == AMP_MODE_SPK) {242		regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,243				  CS35L45_RCV_EN_MASK);244 245		regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,246				   CS35L45_BST_EN_MASK,247				   CS35L45_BST_ENABLE << CS35L45_BST_EN_SHIFT);248 249		regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG,250				   CS35L45_HVLV_MODE_MASK,251				   CS35L45_HVLV_OPERATION <<252				   CS35L45_HVLV_MODE_SHIFT);253 254		ret = cs35l45_activate_ctl(component, "Analog PCM Volume", true);255		if (ret < 0)256			dev_err(cs35l45->dev,257				"Unable to deactivate ctl (%d)\n", ret);258 259	} else  /* AMP_MODE_RCV */ {260		regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,261				CS35L45_RCV_EN_MASK);262 263		regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,264				   CS35L45_BST_EN_MASK,265				   CS35L45_BST_DISABLE_FET_OFF <<266				   CS35L45_BST_EN_SHIFT);267 268		regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG,269				   CS35L45_HVLV_MODE_MASK,270				   CS35L45_FORCE_LV_OPERATION <<271				   CS35L45_HVLV_MODE_SHIFT);272 273		regmap_clear_bits(cs35l45->regmap,274				  CS35L45_BLOCK_ENABLES2,275				  CS35L45_AMP_DRE_EN_MASK);276 277		regmap_update_bits(cs35l45->regmap, CS35L45_AMP_GAIN,278				   CS35L45_AMP_GAIN_PCM_MASK,279				   CS35L45_AMP_GAIN_PCM_13DBV <<280				   CS35L45_AMP_GAIN_PCM_SHIFT);281 282		ret = cs35l45_activate_ctl(component, "Analog PCM Volume", false);283		if (ret < 0)284			dev_err(cs35l45->dev,285				"Unable to deactivate ctl (%d)\n", ret);286	}287 288	if (amp_state & CS35L45_AMP_EN_MASK)289		regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,290				CS35L45_AMP_EN_MASK);291 292	snd_soc_component_enable_pin_unlocked(component, "SPK");293	snd_soc_dapm_sync_unlocked(dapm);294	snd_soc_dapm_mutex_unlock(dapm);295 296	cs35l45->amplifier_mode = ucontrol->value.integer.value[0];297 298	return 1;299}300 301static const char * const cs35l45_asp_tx_txt[] = {302	"Zero", "ASP_RX1", "ASP_RX2",303	"VMON", "IMON", "ERR_VOL",304	"VDD_BATTMON", "VDD_BSTMON",305	"DSP_TX1", "DSP_TX2",306	"Interpolator", "IL_TARGET",307};308 309static const unsigned int cs35l45_asp_tx_val[] = {310	CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,311	CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,312	CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON,313	CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2,314	CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET,315};316 317static const struct soc_enum cs35l45_asp_tx_enums[] = {318	SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK,319			      ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,320			      cs35l45_asp_tx_val),321	SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK,322			      ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,323			      cs35l45_asp_tx_val),324	SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT, 0, CS35L45_PCM_SRC_MASK,325			      ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,326			      cs35l45_asp_tx_val),327	SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK,328			      ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,329			      cs35l45_asp_tx_val),330	SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK,331			      ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,332			      cs35l45_asp_tx_val),333};334 335static const char * const cs35l45_dsp_rx_txt[] = {336	"Zero", "ASP_RX1", "ASP_RX2",337	"VMON", "IMON", "ERR_VOL",338	"CLASSH_TGT", "VDD_BATTMON",339	"VDD_BSTMON", "TEMPMON",340};341 342static const unsigned int cs35l45_dsp_rx_val[] = {343	CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,344	CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,345	CS35L45_PCM_SRC_CLASSH_TGT, CS35L45_PCM_SRC_VDD_BATTMON,346	CS35L45_PCM_SRC_VDD_BSTMON, CS35L45_PCM_SRC_TEMPMON,347};348 349static const struct soc_enum cs35l45_dsp_rx_enums[] = {350	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX1_INPUT, 0, CS35L45_PCM_SRC_MASK,351			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,352			      cs35l45_dsp_rx_val),353	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX2_INPUT, 0, CS35L45_PCM_SRC_MASK,354			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,355			      cs35l45_dsp_rx_val),356	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX3_INPUT, 0, CS35L45_PCM_SRC_MASK,357			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,358			      cs35l45_dsp_rx_val),359	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX4_INPUT, 0, CS35L45_PCM_SRC_MASK,360			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,361			      cs35l45_dsp_rx_val),362	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX5_INPUT, 0, CS35L45_PCM_SRC_MASK,363			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,364			      cs35l45_dsp_rx_val),365	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX6_INPUT, 0, CS35L45_PCM_SRC_MASK,366			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,367			      cs35l45_dsp_rx_val),368	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX7_INPUT, 0, CS35L45_PCM_SRC_MASK,369			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,370			      cs35l45_dsp_rx_val),371	SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX8_INPUT, 0, CS35L45_PCM_SRC_MASK,372			      ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,373			      cs35l45_dsp_rx_val),374};375 376static const char * const cs35l45_dac_txt[] = {377	"Zero", "ASP_RX1", "ASP_RX2", "DSP_TX1", "DSP_TX2"378};379 380static const unsigned int cs35l45_dac_val[] = {381	CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,382	CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2383};384 385static const struct soc_enum cs35l45_dacpcm_enums[] = {386	SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK,387			      ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt,388			      cs35l45_dac_val),389};390 391static const struct snd_kcontrol_new cs35l45_asp_muxes[] = {392	SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]),393	SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]),394	SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]),395	SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]),396	SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]),397};398 399static const struct snd_kcontrol_new cs35l45_dsp_muxes[] = {400	SOC_DAPM_ENUM("DSP_RX1 Source", cs35l45_dsp_rx_enums[0]),401	SOC_DAPM_ENUM("DSP_RX2 Source", cs35l45_dsp_rx_enums[1]),402	SOC_DAPM_ENUM("DSP_RX3 Source", cs35l45_dsp_rx_enums[2]),403	SOC_DAPM_ENUM("DSP_RX4 Source", cs35l45_dsp_rx_enums[3]),404	SOC_DAPM_ENUM("DSP_RX5 Source", cs35l45_dsp_rx_enums[4]),405	SOC_DAPM_ENUM("DSP_RX6 Source", cs35l45_dsp_rx_enums[5]),406	SOC_DAPM_ENUM("DSP_RX7 Source", cs35l45_dsp_rx_enums[6]),407	SOC_DAPM_ENUM("DSP_RX8 Source", cs35l45_dsp_rx_enums[7]),408};409 410static const struct snd_kcontrol_new cs35l45_dac_muxes[] = {411	SOC_DAPM_ENUM("DACPCM Source", cs35l45_dacpcm_enums[0]),412};413static const struct snd_kcontrol_new amp_en_ctl =414	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);415 416static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {417	SND_SOC_DAPM_SPK("DSP1 Preload", NULL),418	SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0,419				cs35l45_dsp_preload_ev,420				SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),421	SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0,422				cs35l45_dsp_audio_ev,423				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),424	SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0,425			    cs35l45_global_en_ev,426			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),427	SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0),428 429	SND_SOC_DAPM_SIGGEN("VMON_SRC"),430	SND_SOC_DAPM_SIGGEN("IMON_SRC"),431	SND_SOC_DAPM_SIGGEN("TEMPMON_SRC"),432	SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),433	SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"),434	SND_SOC_DAPM_SIGGEN("ERR_VOL"),435	SND_SOC_DAPM_SIGGEN("AMP_INTP"),436	SND_SOC_DAPM_SIGGEN("IL_TARGET"),437 438	SND_SOC_DAPM_SUPPLY("VMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0, NULL, 0),439	SND_SOC_DAPM_SUPPLY("IMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0, NULL, 0),440	SND_SOC_DAPM_SUPPLY("TEMPMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_TEMPMON_EN_SHIFT, 0, NULL, 0),441	SND_SOC_DAPM_SUPPLY("VDD_BATTMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VDD_BATTMON_EN_SHIFT, 0, NULL, 0),442	SND_SOC_DAPM_SUPPLY("VDD_BSTMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VDD_BSTMON_EN_SHIFT, 0, NULL, 0),443 444	SND_SOC_DAPM_ADC("VMON", NULL, SND_SOC_NOPM, 0, 0),445	SND_SOC_DAPM_ADC("IMON", NULL, SND_SOC_NOPM, 0, 0),446	SND_SOC_DAPM_ADC("TEMPMON", NULL, SND_SOC_NOPM, 0, 0),447	SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, SND_SOC_NOPM, 0, 0),448	SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, SND_SOC_NOPM, 0, 0),449 450 451	SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0),452	SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0),453 454	SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX1_EN_SHIFT, 0),455	SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX2_EN_SHIFT, 0),456	SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL, 2, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX3_EN_SHIFT, 0),457	SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX4_EN_SHIFT, 0),458	SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0),459 460	SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]),461	SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]),462	SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]),463	SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]),464	SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]),465 466	SND_SOC_DAPM_MUX("DSP_RX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[0]),467	SND_SOC_DAPM_MUX("DSP_RX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[1]),468	SND_SOC_DAPM_MUX("DSP_RX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[2]),469	SND_SOC_DAPM_MUX("DSP_RX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[3]),470	SND_SOC_DAPM_MUX("DSP_RX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[4]),471	SND_SOC_DAPM_MUX("DSP_RX6 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[5]),472	SND_SOC_DAPM_MUX("DSP_RX7 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[6]),473	SND_SOC_DAPM_MUX("DSP_RX8 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[7]),474 475	SND_SOC_DAPM_MUX("DACPCM Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),476 477	SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0, &amp_en_ctl),478 479	SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0),480 481	SND_SOC_DAPM_OUTPUT("SPK"),482};483 484#define CS35L45_ASP_MUX_ROUTE(name) \485	{ name" Source", "ASP_RX1",	 "ASP_RX1" }, \486	{ name" Source", "ASP_RX2",	 "ASP_RX2" }, \487	{ name" Source", "DSP_TX1",	 "DSP1" }, \488	{ name" Source", "DSP_TX2",	 "DSP1" }, \489	{ name" Source", "VMON",	 "VMON" }, \490	{ name" Source", "IMON",	 "IMON" }, \491	{ name" Source", "ERR_VOL",	 "ERR_VOL" }, \492	{ name" Source", "VDD_BATTMON",	 "VDD_BATTMON" }, \493	{ name" Source", "VDD_BSTMON",	 "VDD_BSTMON" }, \494	{ name" Source", "Interpolator", "AMP_INTP" }, \495	{ name" Source", "IL_TARGET",	 "IL_TARGET" }496 497#define CS35L45_DSP_MUX_ROUTE(name) \498	{ name" Source", "ASP_RX1",	"ASP_RX1" }, \499	{ name" Source", "ASP_RX2",	"ASP_RX2" }500 501#define CS35L45_DAC_MUX_ROUTE(name) \502	{ name" Source", "ASP_RX1",	"ASP_RX1" }, \503	{ name" Source", "ASP_RX2",	"ASP_RX2" }, \504	{ name" Source", "DSP_TX1",	"DSP1" }, \505	{ name" Source", "DSP_TX2",	"DSP1" }506 507static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {508	/* Feedback */509	{ "VMON", NULL, "VMON_SRC" },510	{ "IMON", NULL, "IMON_SRC" },511	{ "TEMPMON", NULL, "TEMPMON_SRC" },512	{ "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" },513	{ "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" },514 515	{ "VMON", NULL, "VMON_EN" },516	{ "IMON", NULL, "IMON_EN" },517	{ "TEMPMON", NULL, "TEMPMON_EN" },518	{ "VDD_BATTMON", NULL, "VDD_BATTMON_EN" },519	{ "VDD_BSTMON", NULL, "VDD_BSTMON_EN" },520 521	{ "Capture", NULL, "ASP_TX1"},522	{ "Capture", NULL, "ASP_TX2"},523	{ "Capture", NULL, "ASP_TX3"},524	{ "Capture", NULL, "ASP_TX4"},525	{ "Capture", NULL, "ASP_TX5"},526	{ "ASP_TX1", NULL, "ASP_TX1 Source"},527	{ "ASP_TX2", NULL, "ASP_TX2 Source"},528	{ "ASP_TX3", NULL, "ASP_TX3 Source"},529	{ "ASP_TX4", NULL, "ASP_TX4 Source"},530	{ "ASP_TX5", NULL, "ASP_TX5 Source"},531 532	{ "ASP_TX1", NULL, "ASP_EN" },533	{ "ASP_TX2", NULL, "ASP_EN" },534	{ "ASP_TX3", NULL, "ASP_EN" },535	{ "ASP_TX4", NULL, "ASP_EN" },536	{ "ASP_TX1", NULL, "GLOBAL_EN" },537	{ "ASP_TX2", NULL, "GLOBAL_EN" },538	{ "ASP_TX3", NULL, "GLOBAL_EN" },539	{ "ASP_TX4", NULL, "GLOBAL_EN" },540	{ "ASP_TX5", NULL, "GLOBAL_EN" },541 542	CS35L45_ASP_MUX_ROUTE("ASP_TX1"),543	CS35L45_ASP_MUX_ROUTE("ASP_TX2"),544	CS35L45_ASP_MUX_ROUTE("ASP_TX3"),545	CS35L45_ASP_MUX_ROUTE("ASP_TX4"),546	CS35L45_ASP_MUX_ROUTE("ASP_TX5"),547 548	/* Playback */549	{ "ASP_RX1", NULL, "Playback" },550	{ "ASP_RX2", NULL, "Playback" },551	{ "ASP_RX1", NULL, "ASP_EN" },552	{ "ASP_RX2", NULL, "ASP_EN" },553 554	{ "AMP", NULL, "DACPCM Source"},555	{ "AMP", NULL, "GLOBAL_EN"},556 557	CS35L45_DSP_MUX_ROUTE("DSP_RX1"),558	CS35L45_DSP_MUX_ROUTE("DSP_RX2"),559	CS35L45_DSP_MUX_ROUTE("DSP_RX3"),560	CS35L45_DSP_MUX_ROUTE("DSP_RX4"),561	CS35L45_DSP_MUX_ROUTE("DSP_RX5"),562	CS35L45_DSP_MUX_ROUTE("DSP_RX6"),563	CS35L45_DSP_MUX_ROUTE("DSP_RX7"),564	CS35L45_DSP_MUX_ROUTE("DSP_RX8"),565 566	{"DSP1", NULL, "DSP_RX1 Source"},567	{"DSP1", NULL, "DSP_RX2 Source"},568	{"DSP1", NULL, "DSP_RX3 Source"},569	{"DSP1", NULL, "DSP_RX4 Source"},570	{"DSP1", NULL, "DSP_RX5 Source"},571	{"DSP1", NULL, "DSP_RX6 Source"},572	{"DSP1", NULL, "DSP_RX7 Source"},573	{"DSP1", NULL, "DSP_RX8 Source"},574 575	{"DSP1", NULL, "VMON_EN"},576	{"DSP1", NULL, "IMON_EN"},577	{"DSP1", NULL, "VDD_BATTMON_EN"},578	{"DSP1", NULL, "VDD_BSTMON_EN"},579	{"DSP1", NULL, "TEMPMON_EN"},580 581	{"DSP1 Preload", NULL, "DSP1 Preloader"},582	{"DSP1", NULL, "DSP1 Preloader"},583 584	CS35L45_DAC_MUX_ROUTE("DACPCM"),585 586	{ "AMP Enable", "Switch", "AMP" },587	{ "SPK", NULL, "AMP Enable"},588};589 590static const char * const amplifier_mode_texts[] = {"SPK", "RCV"};591static SOC_ENUM_SINGLE_DECL(amplifier_mode_enum, SND_SOC_NOPM, 0,592			    amplifier_mode_texts);593static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 1000, 300, 0);594static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);595 596static const struct snd_kcontrol_new cs35l45_controls[] = {597	SOC_ENUM_EXT("Amplifier Mode", amplifier_mode_enum,598		     cs35l45_amplifier_mode_get, cs35l45_amplifier_mode_put),599	SOC_SINGLE_TLV("Analog PCM Volume", CS35L45_AMP_GAIN,600			CS35L45_AMP_GAIN_PCM_SHIFT,601			CS35L45_AMP_GAIN_PCM_MASK >> CS35L45_AMP_GAIN_PCM_SHIFT,602			0, amp_gain_tlv),603	/* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */604	SOC_SINGLE_S_TLV("Digital PCM Volume",605			 CS35L45_AMP_PCM_CONTROL,606			 CS35L45_AMP_VOL_PCM_SHIFT + 1,607			 -409, 48,608			 (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1,609			 0, cs35l45_dig_pcm_vol_tlv),610	WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),611	WM_ADSP_FW_CONTROL("DSP1", 0),612};613 614static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq)615{616	unsigned int val;617	int freq_id;618 619	freq_id = cs35l45_get_clk_freq_id(freq);620	if (freq_id < 0) {621		dev_err(cs35l45->dev, "Invalid freq: %u\n", freq);622		return -EINVAL;623	}624 625	regmap_read(cs35l45->regmap, CS35L45_REFCLK_INPUT, &val);626	val = (val & CS35L45_PLL_REFCLK_FREQ_MASK) >> CS35L45_PLL_REFCLK_FREQ_SHIFT;627	if (val == freq_id)628		return 0;629 630	regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK);631	regmap_update_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT,632			   CS35L45_PLL_REFCLK_FREQ_MASK,633			   freq_id << CS35L45_PLL_REFCLK_FREQ_SHIFT);634	regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK);635	regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK);636	regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK);637 638	return 0;639}640 641static int cs35l45_asp_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)642{643	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(codec_dai->component);644	unsigned int asp_fmt, fsync_inv, bclk_inv;645 646	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {647	case SND_SOC_DAIFMT_CBC_CFC:648		break;649	default:650		dev_err(cs35l45->dev, "Invalid DAI clocking\n");651		return -EINVAL;652	}653 654	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {655	case SND_SOC_DAIFMT_DSP_A:656		asp_fmt = CS35l45_ASP_FMT_DSP_A;657		break;658	case SND_SOC_DAIFMT_I2S:659		asp_fmt = CS35L45_ASP_FMT_I2S;660		break;661	default:662		dev_err(cs35l45->dev, "Invalid DAI format\n");663		return -EINVAL;664	}665 666	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {667	case SND_SOC_DAIFMT_NB_IF:668		fsync_inv = 1;669		bclk_inv = 0;670		break;671	case SND_SOC_DAIFMT_IB_NF:672		fsync_inv = 0;673		bclk_inv = 1;674		break;675	case SND_SOC_DAIFMT_IB_IF:676		fsync_inv = 1;677		bclk_inv = 1;678		break;679	case SND_SOC_DAIFMT_NB_NF:680		fsync_inv = 0;681		bclk_inv = 0;682		break;683	default:684		dev_warn(cs35l45->dev, "Invalid DAI clock polarity\n");685		return -EINVAL;686	}687 688	regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,689			   CS35L45_ASP_FMT_MASK |690			   CS35L45_ASP_FSYNC_INV_MASK |691			   CS35L45_ASP_BCLK_INV_MASK,692			   (asp_fmt << CS35L45_ASP_FMT_SHIFT) |693			   (fsync_inv << CS35L45_ASP_FSYNC_INV_SHIFT) |694			   (bclk_inv << CS35L45_ASP_BCLK_INV_SHIFT));695 696	return 0;697}698 699static int cs35l45_asp_hw_params(struct snd_pcm_substream *substream,700				 struct snd_pcm_hw_params *params,701				 struct snd_soc_dai *dai)702{703	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);704	unsigned int asp_width, asp_wl, global_fs, slot_multiple, asp_fmt;705	int bclk;706 707	switch (params_rate(params)) {708	case 44100:709		global_fs = CS35L45_44P100_KHZ;710		break;711	case 48000:712		global_fs = CS35L45_48P0_KHZ;713		break;714	case 88200:715		global_fs = CS35L45_88P200_KHZ;716		break;717	case 96000:718		global_fs = CS35L45_96P0_KHZ;719		break;720	default:721		dev_warn(cs35l45->dev, "Unsupported sample rate (%d)\n",722			 params_rate(params));723		return -EINVAL;724	}725 726	regmap_update_bits(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE,727			   CS35L45_GLOBAL_FS_MASK,728			   global_fs << CS35L45_GLOBAL_FS_SHIFT);729 730	asp_wl = params_width(params);731 732	if (cs35l45->slot_width)733		asp_width = cs35l45->slot_width;734	else735		asp_width = params_width(params);736 737	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {738		regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,739				   CS35L45_ASP_WIDTH_RX_MASK,740				   asp_width << CS35L45_ASP_WIDTH_RX_SHIFT);741 742		regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL5,743				   CS35L45_ASP_WL_MASK,744				   asp_wl << CS35L45_ASP_WL_SHIFT);745	} else {746		regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,747				   CS35L45_ASP_WIDTH_TX_MASK,748				   asp_width << CS35L45_ASP_WIDTH_TX_SHIFT);749 750		regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL1,751				   CS35L45_ASP_WL_MASK,752				   asp_wl << CS35L45_ASP_WL_SHIFT);753	}754 755	if (cs35l45->sysclk_set)756		return 0;757 758	/* I2S always has an even number of channels */759	regmap_read(cs35l45->regmap, CS35L45_ASP_CONTROL2, &asp_fmt);760	asp_fmt = (asp_fmt & CS35L45_ASP_FMT_MASK) >> CS35L45_ASP_FMT_SHIFT;761	if (asp_fmt == CS35L45_ASP_FMT_I2S)762		slot_multiple = 2;763	else764		slot_multiple = 1;765 766	bclk = snd_soc_tdm_params_to_bclk(params, asp_width,767					  cs35l45->slot_count, slot_multiple);768 769	return cs35l45_set_pll(cs35l45, bclk);770}771 772static int cs35l45_asp_set_tdm_slot(struct snd_soc_dai *dai,773				    unsigned int tx_mask, unsigned int rx_mask,774				    int slots, int slot_width)775{776	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);777 778	if (slot_width && ((slot_width < 16) || (slot_width > 128)))779		return -EINVAL;780 781	cs35l45->slot_width = slot_width;782	cs35l45->slot_count = slots;783 784	return 0;785}786 787static int cs35l45_asp_set_sysclk(struct snd_soc_dai *dai,788				  int clk_id, unsigned int freq, int dir)789{790	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);791	int ret;792 793	if (clk_id != 0) {794		dev_err(cs35l45->dev, "Invalid clk_id %d\n", clk_id);795		return -EINVAL;796	}797 798	cs35l45->sysclk_set = false;799	if (freq == 0)800		return 0;801 802	ret = cs35l45_set_pll(cs35l45, freq);803	if (ret < 0)804		return -EINVAL;805 806	cs35l45->sysclk_set = true;807 808	return 0;809}810 811static int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream)812{813	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);814	unsigned int global_fs, val, hpf_tune;815 816	if (mute)817		return 0;818 819	regmap_read(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, &global_fs);820	global_fs = (global_fs & CS35L45_GLOBAL_FS_MASK) >> CS35L45_GLOBAL_FS_SHIFT;821	switch (global_fs) {822	case CS35L45_44P100_KHZ:823		hpf_tune = CS35L45_HPF_44P1;824		break;825	case CS35L45_88P200_KHZ:826		hpf_tune = CS35L45_HPF_88P2;827		break;828	default:829		hpf_tune = CS35l45_HPF_DEFAULT;830		break;831	}832 833	regmap_read(cs35l45->regmap, CS35L45_AMP_PCM_HPF_TST, &val);834	if (val != hpf_tune) {835		struct reg_sequence hpf_override_seq[] = {836			{ 0x00000040,			0x00000055 },837			{ 0x00000040,			0x000000AA },838			{ 0x00000044,			0x00000055 },839			{ 0x00000044,			0x000000AA },840			{ CS35L45_AMP_PCM_HPF_TST,	hpf_tune },841			{ 0x00000040,			0x00000000 },842			{ 0x00000044,			0x00000000 },843		};844		regmap_multi_reg_write(cs35l45->regmap, hpf_override_seq,845				       ARRAY_SIZE(hpf_override_seq));846	}847 848	return 0;849}850 851static const struct snd_soc_dai_ops cs35l45_asp_dai_ops = {852	.set_fmt = cs35l45_asp_set_fmt,853	.hw_params = cs35l45_asp_hw_params,854	.set_tdm_slot = cs35l45_asp_set_tdm_slot,855	.set_sysclk = cs35l45_asp_set_sysclk,856	.mute_stream = cs35l45_mute_stream,857};858 859static struct snd_soc_dai_driver cs35l45_dai[] = {860	{861		.name = "cs35l45",862		.playback = {863			.stream_name = "Playback",864			.channels_min = 1,865			.channels_max = 2,866			.rates = CS35L45_RATES,867			.formats = CS35L45_FORMATS,868		},869		.capture = {870			.stream_name = "Capture",871			.channels_min = 1,872			.channels_max = 5,873			.rates = CS35L45_RATES,874			.formats = CS35L45_FORMATS,875		},876		.symmetric_rate = true,877		.symmetric_sample_bits = true,878		.ops = &cs35l45_asp_dai_ops,879	},880};881 882static int cs35l45_component_probe(struct snd_soc_component *component)883{884	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);885 886	return wm_adsp2_component_probe(&cs35l45->dsp, component);887}888 889static void cs35l45_component_remove(struct snd_soc_component *component)890{891	struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);892 893	wm_adsp2_component_remove(&cs35l45->dsp, component);894}895 896static const struct snd_soc_component_driver cs35l45_component = {897	.probe = cs35l45_component_probe,898	.remove = cs35l45_component_remove,899 900	.dapm_widgets = cs35l45_dapm_widgets,901	.num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets),902 903	.dapm_routes = cs35l45_dapm_routes,904	.num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes),905 906	.controls = cs35l45_controls,907	.num_controls = ARRAY_SIZE(cs35l45_controls),908 909	.name = "cs35l45",910 911	.endianness = 1,912};913 914static void cs35l45_setup_hibernate(struct cs35l45_private *cs35l45)915{916	unsigned int wksrc;917 918	if (cs35l45->bus_type == CONTROL_BUS_I2C)919		wksrc = CS35L45_WKSRC_I2C;920	else921		wksrc = CS35L45_WKSRC_SPI;922 923	regmap_update_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,924			   CS35L45_WKSRC_EN_MASK,925			   wksrc << CS35L45_WKSRC_EN_SHIFT);926 927	regmap_set_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,928			   CS35L45_UPDT_WKCTL_MASK);929 930	regmap_update_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,931			   CS35L45_WKI2C_ADDR_MASK, cs35l45->i2c_addr);932 933	regmap_set_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,934			   CS35L45_UPDT_WKI2C_MASK);935}936 937static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45)938{939	dev_dbg(cs35l45->dev, "Enter hibernate\n");940 941	cs35l45_setup_hibernate(cs35l45);942 943	regmap_set_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, CS35L45_DSP_VIRT2_MBOX_MASK);944 945	// Don't wait for ACK since bus activity would wake the device946	regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);947 948	return 0;949}950 951static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)952{953	const int wake_retries = 20;954	const int sleep_retries = 5;955	int ret, i, j;956 957	for (i = 0; i < sleep_retries; i++) {958		dev_dbg(cs35l45->dev, "Exit hibernate\n");959 960		for (j = 0; j < wake_retries; j++) {961			ret = cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,962					  CSPL_MBOX_CMD_OUT_OF_HIBERNATE);963			if (!ret) {964				dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j);965				regmap_clear_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2,966						 CS35L45_DSP_VIRT2_MBOX_MASK);967				return 0;968			}969			usleep_range(100, 200);970		}971 972		dev_err(cs35l45->dev, "Wake failed, re-enter hibernate: %d\n", ret);973 974		cs35l45_setup_hibernate(cs35l45);975	}976 977	dev_err(cs35l45->dev, "Timed out waking device\n");978 979	return -ETIMEDOUT;980}981 982static int cs35l45_runtime_suspend(struct device *dev)983{984	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);985 986	if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)987		return 0;988 989	cs35l45_enter_hibernate(cs35l45);990 991	regcache_cache_only(cs35l45->regmap, true);992	regcache_mark_dirty(cs35l45->regmap);993 994	dev_dbg(cs35l45->dev, "Runtime suspended\n");995 996	return 0;997}998 999static int cs35l45_runtime_resume(struct device *dev)1000{1001	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);1002	int ret;1003 1004	if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)1005		return 0;1006 1007	dev_dbg(cs35l45->dev, "Runtime resume\n");1008 1009	regcache_cache_only(cs35l45->regmap, false);1010 1011	ret = cs35l45_exit_hibernate(cs35l45);1012	if (ret)1013		return ret;1014 1015	ret = regcache_sync(cs35l45->regmap);1016	if (ret != 0)1017		dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);1018 1019	/* Clear global error status */1020	regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);1021	regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);1022	regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);1023	return ret;1024}1025 1026static int cs35l45_sys_suspend(struct device *dev)1027{1028	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);1029 1030	dev_dbg(cs35l45->dev, "System suspend, disabling IRQ\n");1031	disable_irq(cs35l45->irq);1032 1033	return 0;1034}1035 1036static int cs35l45_sys_suspend_noirq(struct device *dev)1037{1038	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);1039 1040	dev_dbg(cs35l45->dev, "Late system suspend, reenabling IRQ\n");1041	enable_irq(cs35l45->irq);1042 1043	return 0;1044}1045 1046static int cs35l45_sys_resume_noirq(struct device *dev)1047{1048	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);1049 1050	dev_dbg(cs35l45->dev, "Early system resume, disabling IRQ\n");1051	disable_irq(cs35l45->irq);1052 1053	return 0;1054}1055 1056static int cs35l45_sys_resume(struct device *dev)1057{1058	struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);1059 1060	dev_dbg(cs35l45->dev, "System resume, reenabling IRQ\n");1061	enable_irq(cs35l45->irq);1062 1063	return 0;1064}1065 1066static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)1067{1068	struct device_node *node = cs35l45->dev->of_node;1069	unsigned int gpio_regs[] = {CS35L45_GPIO1_CTRL1, CS35L45_GPIO2_CTRL1,1070				    CS35L45_GPIO3_CTRL1};1071	unsigned int pad_regs[] = {CS35L45_SYNC_GPIO1,1072				   CS35L45_INTB_GPIO2_MCLK_REF, CS35L45_GPIO3};1073	struct device_node *child;1074	unsigned int val;1075	char of_name[32];1076	int ret, i;1077 1078	if (!node)1079		return 0;1080 1081	for (i = 0; i < CS35L45_NUM_GPIOS; i++) {1082		sprintf(of_name, "cirrus,gpio-ctrl%d", i + 1);1083		child = of_get_child_by_name(node, of_name);1084		if (!child)1085			continue;1086 1087		ret = of_property_read_u32(child, "gpio-dir", &val);1088		if (!ret)1089			regmap_update_bits(cs35l45->regmap, gpio_regs[i],1090					   CS35L45_GPIO_DIR_MASK,1091					   val << CS35L45_GPIO_DIR_SHIFT);1092 1093		ret = of_property_read_u32(child, "gpio-lvl", &val);1094		if (!ret)1095			regmap_update_bits(cs35l45->regmap, gpio_regs[i],1096					   CS35L45_GPIO_LVL_MASK,1097					   val << CS35L45_GPIO_LVL_SHIFT);1098 1099		ret = of_property_read_u32(child, "gpio-op-cfg", &val);1100		if (!ret)1101			regmap_update_bits(cs35l45->regmap, gpio_regs[i],1102					   CS35L45_GPIO_OP_CFG_MASK,1103					   val << CS35L45_GPIO_OP_CFG_SHIFT);1104 1105		ret = of_property_read_u32(child, "gpio-pol", &val);1106		if (!ret)1107			regmap_update_bits(cs35l45->regmap, gpio_regs[i],1108					   CS35L45_GPIO_POL_MASK,1109					   val << CS35L45_GPIO_POL_SHIFT);1110 1111		ret = of_property_read_u32(child, "gpio-ctrl", &val);1112		if (!ret)1113			regmap_update_bits(cs35l45->regmap, pad_regs[i],1114					   CS35L45_GPIO_CTRL_MASK,1115					   val << CS35L45_GPIO_CTRL_SHIFT);1116 1117		ret = of_property_read_u32(child, "gpio-invert", &val);1118		if (!ret) {1119			regmap_update_bits(cs35l45->regmap, pad_regs[i],1120					   CS35L45_GPIO_INVERT_MASK,1121					   val << CS35L45_GPIO_INVERT_SHIFT);1122			if (i == 1)1123				cs35l45->irq_invert = val;1124		}1125 1126		of_node_put(child);1127	}1128 1129	if (device_property_read_u32(cs35l45->dev,1130				     "cirrus,asp-sdout-hiz-ctrl", &val) == 0) {1131		regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3,1132				   CS35L45_ASP_DOUT_HIZ_CTRL_MASK,1133				   val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT);1134	}1135 1136	return 0;1137}1138 1139static int cs35l45_dsp_virt2_mbox3_irq_handle(struct cs35l45_private *cs35l45,1140					      const unsigned int cmd,1141					      unsigned int data)1142{1143	static char *speak_status = "Unknown";1144 1145	switch (cmd) {1146	case EVENT_SPEAKER_STATUS:1147		switch (data) {1148		case 1:1149			speak_status = "All Clear";1150			break;1151		case 2:1152			speak_status = "Open Circuit";1153			break;1154		case 4:1155			speak_status = "Short Circuit";1156			break;1157		}1158 1159		dev_info(cs35l45->dev, "MBOX event (SPEAKER_STATUS): %s\n",1160			 speak_status);1161		break;1162	case EVENT_BOOT_DONE:1163		dev_dbg(cs35l45->dev, "MBOX event (BOOT_DONE)\n");1164		break;1165	default:1166		dev_err(cs35l45->dev, "MBOX event not supported %u\n", cmd);1167		return -EINVAL;1168	}1169 1170	return 0;1171}1172 1173static irqreturn_t cs35l45_dsp_virt2_mbox_cb(int irq, void *data)1174{1175	struct cs35l45_private *cs35l45 = data;1176	unsigned int mbox_val;1177	int ret = 0;1178 1179	ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_3, &mbox_val);1180	if (!ret && mbox_val)1181		cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45, mbox_val & CS35L45_MBOX3_CMD_MASK,1182				(mbox_val & CS35L45_MBOX3_DATA_MASK) >> CS35L45_MBOX3_DATA_SHIFT);1183 1184	/* Handle DSP trace log IRQ */1185	ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_4, &mbox_val);1186	if (!ret && mbox_val != 0) {1187		dev_err(cs35l45->dev, "Spurious DSP MBOX4 IRQ\n");1188	}1189 1190	return IRQ_RETVAL(ret);1191}1192 1193static irqreturn_t cs35l45_pll_unlock(int irq, void *data)1194{1195	struct cs35l45_private *cs35l45 = data;1196 1197	dev_dbg(cs35l45->dev, "PLL unlock detected!");1198 1199	return IRQ_HANDLED;1200}1201 1202static irqreturn_t cs35l45_pll_lock(int irq, void *data)1203{1204	struct cs35l45_private *cs35l45 = data;1205 1206	dev_dbg(cs35l45->dev, "PLL lock detected!");1207 1208	return IRQ_HANDLED;1209}1210 1211static irqreturn_t cs35l45_spk_safe_err(int irq, void *data);1212 1213static const struct cs35l45_irq cs35l45_irqs[] = {1214	CS35L45_IRQ(AMP_SHORT_ERR, "Amplifier short error", cs35l45_spk_safe_err),1215	CS35L45_IRQ(UVLO_VDDBATT_ERR, "VDDBATT undervoltage error", cs35l45_spk_safe_err),1216	CS35L45_IRQ(BST_SHORT_ERR, "Boost inductor error", cs35l45_spk_safe_err),1217	CS35L45_IRQ(BST_UVP_ERR, "Boost undervoltage error", cs35l45_spk_safe_err),1218	CS35L45_IRQ(TEMP_ERR, "Overtemperature error", cs35l45_spk_safe_err),1219	CS35L45_IRQ(AMP_CAL_ERR, "Amplifier calibration error", cs35l45_spk_safe_err),1220	CS35L45_IRQ(UVLO_VDDLV_ERR, "LV threshold detector error", cs35l45_spk_safe_err),1221	CS35L45_IRQ(GLOBAL_ERROR, "Global error", cs35l45_spk_safe_err),1222	CS35L45_IRQ(DSP_WDT_EXPIRE, "DSP Watchdog Timer", cs35l45_spk_safe_err),1223	CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE, "PLL unlock", cs35l45_pll_unlock),1224	CS35L45_IRQ(PLL_LOCK_FLAG, "PLL lock", cs35l45_pll_lock),1225	CS35L45_IRQ(DSP_VIRT2_MBOX, "DSP virtual MBOX 2 write flag", cs35l45_dsp_virt2_mbox_cb),1226};1227 1228static irqreturn_t cs35l45_spk_safe_err(int irq, void *data)1229{1230	struct cs35l45_private *cs35l45 = data;1231	int i;1232 1233	i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0);1234 1235	if (i < 0 || i >= ARRAY_SIZE(cs35l45_irqs))1236		dev_err(cs35l45->dev, "Unspecified global error condition (%d) detected!\n", irq);1237	else1238		dev_err(cs35l45->dev, "%s condition detected!\n", cs35l45_irqs[i].name);1239 1240	return IRQ_HANDLED;1241}1242 1243static const struct regmap_irq cs35l45_reg_irqs[] = {1244	CS35L45_REG_IRQ(IRQ1_EINT_1, AMP_SHORT_ERR),1245	CS35L45_REG_IRQ(IRQ1_EINT_1, UVLO_VDDBATT_ERR),1246	CS35L45_REG_IRQ(IRQ1_EINT_1, BST_SHORT_ERR),1247	CS35L45_REG_IRQ(IRQ1_EINT_1, BST_UVP_ERR),1248	CS35L45_REG_IRQ(IRQ1_EINT_1, TEMP_ERR),1249	CS35L45_REG_IRQ(IRQ1_EINT_3, AMP_CAL_ERR),1250	CS35L45_REG_IRQ(IRQ1_EINT_18, UVLO_VDDLV_ERR),1251	CS35L45_REG_IRQ(IRQ1_EINT_18, GLOBAL_ERROR),1252	CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_WDT_EXPIRE),1253	CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_UNLOCK_FLAG_RISE),1254	CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_LOCK_FLAG),1255	CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_VIRT2_MBOX),1256};1257 1258static const struct regmap_irq_chip cs35l45_regmap_irq_chip = {1259	.name = "cs35l45 IRQ1 Controller",1260	.main_status = CS35L45_IRQ1_STATUS,1261	.status_base = CS35L45_IRQ1_EINT_1,1262	.mask_base = CS35L45_IRQ1_MASK_1,1263	.ack_base = CS35L45_IRQ1_EINT_1,1264	.num_regs = 18,1265	.irqs = cs35l45_reg_irqs,1266	.num_irqs = ARRAY_SIZE(cs35l45_reg_irqs),1267	.runtime_pm = true,1268};1269 1270static int cs35l45_initialize(struct cs35l45_private *cs35l45)1271{1272	struct device *dev = cs35l45->dev;1273	unsigned int dev_id[5];1274	unsigned int sts;1275	int ret;1276 1277	ret = regmap_read_poll_timeout(cs35l45->regmap, CS35L45_IRQ1_EINT_4, sts,1278				       (sts & CS35L45_OTP_BOOT_DONE_STS_MASK),1279				       1000, 5000);1280	if (ret < 0) {1281		dev_err(cs35l45->dev, "Timeout waiting for OTP boot\n");1282		return ret;1283	}1284 1285	ret = regmap_bulk_read(cs35l45->regmap, CS35L45_DEVID, dev_id, ARRAY_SIZE(dev_id));1286	if (ret) {1287		dev_err(cs35l45->dev, "Get Device ID failed: %d\n", ret);1288		return ret;1289	}1290 1291	switch (dev_id[0]) {1292	case 0x35A450:1293	case 0x35A460:1294		break;1295	default:1296		dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]);1297		return -ENODEV;1298	}1299 1300	dev_info(cs35l45->dev, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n",1301		 dev_id[1], dev_id[4]);1302 1303	regmap_write(cs35l45->regmap, CS35L45_IRQ1_EINT_4,1304		     CS35L45_OTP_BOOT_DONE_STS_MASK | CS35L45_OTP_BUSY_MASK);1305 1306	ret = cs35l45_apply_patch(cs35l45);1307	if (ret < 0) {1308		dev_err(dev, "Failed to apply init patch %d\n", ret);1309		return ret;1310	}1311 1312	ret = cs35l45_apply_property_config(cs35l45);1313	if (ret < 0)1314		return ret;1315 1316	cs35l45->amplifier_mode = AMP_MODE_SPK;1317 1318	return 0;1319}1320 1321static const struct reg_sequence cs35l45_fs_errata_patch[] = {1322	{0x02B80080,			0x00000001},1323	{0x02B80088,			0x00000001},1324	{0x02B80090,			0x00000001},1325	{0x02B80098,			0x00000001},1326	{0x02B800A0,			0x00000001},1327	{0x02B800A8,			0x00000001},1328	{0x02B800B0,			0x00000001},1329	{0x02B800B8,			0x00000001},1330	{0x02B80280,			0x00000001},1331	{0x02B80288,			0x00000001},1332	{0x02B80290,			0x00000001},1333	{0x02B80298,			0x00000001},1334	{0x02B802A0,			0x00000001},1335	{0x02B802A8,			0x00000001},1336	{0x02B802B0,			0x00000001},1337	{0x02B802B8,			0x00000001},1338};1339 1340static const struct cs_dsp_region cs35l45_dsp1_regions[] = {1341	{ .type = WMFW_HALO_PM_PACKED,	.base = CS35L45_DSP1_PMEM_0 },1342	{ .type = WMFW_HALO_XM_PACKED,	.base = CS35L45_DSP1_XMEM_PACK_0 },1343	{ .type = WMFW_HALO_YM_PACKED,	.base = CS35L45_DSP1_YMEM_PACK_0 },1344	{. type = WMFW_ADSP2_XM,	.base = CS35L45_DSP1_XMEM_UNPACK24_0},1345	{. type = WMFW_ADSP2_YM,	.base = CS35L45_DSP1_YMEM_UNPACK24_0},1346};1347 1348static int cs35l45_dsp_init(struct cs35l45_private *cs35l45)1349{1350	struct wm_adsp *dsp = &cs35l45->dsp;1351	int ret;1352 1353	dsp->part = "cs35l45";1354	dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */1355	dsp->toggle_preload = true;1356	dsp->cs_dsp.num = 1;1357	dsp->cs_dsp.type = WMFW_HALO;1358	dsp->cs_dsp.rev = 0;1359	dsp->cs_dsp.dev = cs35l45->dev;1360	dsp->cs_dsp.regmap = cs35l45->regmap;1361	dsp->cs_dsp.base = CS35L45_DSP1_CLOCK_FREQ;1362	dsp->cs_dsp.base_sysinfo = CS35L45_DSP1_SYS_ID;1363	dsp->cs_dsp.mem = cs35l45_dsp1_regions;1364	dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l45_dsp1_regions);1365	dsp->cs_dsp.lock_regions = 0xFFFFFFFF;1366 1367	ret = wm_halo_init(dsp);1368 1369	regmap_multi_reg_write(cs35l45->regmap, cs35l45_fs_errata_patch,1370						   ARRAY_SIZE(cs35l45_fs_errata_patch));1371 1372	return ret;1373}1374 1375int cs35l45_probe(struct cs35l45_private *cs35l45)1376{1377	struct device *dev = cs35l45->dev;1378	unsigned long irq_pol = IRQF_ONESHOT | IRQF_SHARED;1379	int ret, i, irq;1380 1381	cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt");1382	if (IS_ERR(cs35l45->vdd_batt))1383		return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_batt),1384				     "Failed to request vdd-batt\n");1385 1386	cs35l45->vdd_a = devm_regulator_get(dev, "vdd-a");1387	if (IS_ERR(cs35l45->vdd_a))1388		return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_a),1389				     "Failed to request vdd-a\n");1390 1391	/* VDD_BATT must always be enabled before other supplies */1392	ret = regulator_enable(cs35l45->vdd_batt);1393	if (ret < 0)1394		return dev_err_probe(dev, ret, "Failed to enable vdd-batt\n");1395 1396	ret = regulator_enable(cs35l45->vdd_a);1397	if (ret < 0)1398		return dev_err_probe(dev, ret, "Failed to enable vdd-a\n");1399 1400	/* If reset is shared only one instance can claim it */1401	cs35l45->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);1402	if (IS_ERR(cs35l45->reset_gpio)) {1403		ret = PTR_ERR(cs35l45->reset_gpio);1404		cs35l45->reset_gpio = NULL;1405		if (ret == -EBUSY) {1406			dev_dbg(dev, "Reset line busy, assuming shared reset\n");1407		} else {1408			dev_err_probe(dev, ret, "Failed to get reset GPIO\n");1409			goto err;1410		}1411	}1412 1413	if (cs35l45->reset_gpio) {1414		usleep_range(CS35L45_RESET_HOLD_US, CS35L45_RESET_HOLD_US + 100);1415		gpiod_set_value_cansleep(cs35l45->reset_gpio, 1);1416	}1417 1418	usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100);1419 1420	ret = cs35l45_initialize(cs35l45);1421	if (ret < 0)1422		goto err_reset;1423 1424	ret = cs35l45_dsp_init(cs35l45);1425	if (ret < 0)1426		goto err_reset;1427 1428	pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000);1429	pm_runtime_use_autosuspend(cs35l45->dev);1430	pm_runtime_mark_last_busy(cs35l45->dev);1431	pm_runtime_set_active(cs35l45->dev);1432	pm_runtime_get_noresume(cs35l45->dev);1433	pm_runtime_enable(cs35l45->dev);1434 1435	if (cs35l45->irq) {1436		if (cs35l45->irq_invert)1437			irq_pol |= IRQF_TRIGGER_HIGH;1438		else1439			irq_pol |= IRQF_TRIGGER_LOW;1440 1441		ret = devm_regmap_add_irq_chip(dev, cs35l45->regmap, cs35l45->irq, irq_pol, 0,1442					       &cs35l45_regmap_irq_chip, &cs35l45->irq_data);1443		if (ret) {1444			dev_err(dev, "Failed to register IRQ chip: %d\n", ret);1445			goto err_dsp;1446		}1447 1448		for (i = 0; i < ARRAY_SIZE(cs35l45_irqs); i++) {1449			irq = regmap_irq_get_virq(cs35l45->irq_data, cs35l45_irqs[i].irq);1450			if (irq < 0) {1451				dev_err(dev, "Failed to get %s\n", cs35l45_irqs[i].name);1452				ret = irq;1453				goto err_dsp;1454			}1455 1456			ret = devm_request_threaded_irq(dev, irq, NULL, cs35l45_irqs[i].handler,1457							irq_pol, cs35l45_irqs[i].name, cs35l45);1458			if (ret) {1459				dev_err(dev, "Failed to request IRQ %s: %d\n",1460					cs35l45_irqs[i].name, ret);1461				goto err_dsp;1462			}1463		}1464	}1465 1466	ret = devm_snd_soc_register_component(dev, &cs35l45_component,1467					      cs35l45_dai,1468					      ARRAY_SIZE(cs35l45_dai));1469	if (ret < 0)1470		goto err_dsp;1471 1472	pm_runtime_put_autosuspend(cs35l45->dev);1473 1474	return 0;1475 1476err_dsp:1477	pm_runtime_disable(cs35l45->dev);1478	pm_runtime_put_noidle(cs35l45->dev);1479	wm_adsp2_remove(&cs35l45->dsp);1480 1481err_reset:1482	gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);1483err:1484	regulator_disable(cs35l45->vdd_a);1485	regulator_disable(cs35l45->vdd_batt);1486 1487	return ret;1488}1489EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);1490 1491void cs35l45_remove(struct cs35l45_private *cs35l45)1492{1493	pm_runtime_get_sync(cs35l45->dev);1494	pm_runtime_disable(cs35l45->dev);1495	wm_adsp2_remove(&cs35l45->dsp);1496 1497	gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);1498 1499	pm_runtime_put_noidle(cs35l45->dev);1500	regulator_disable(cs35l45->vdd_a);1501	/* VDD_BATT must be the last to power-off */1502	regulator_disable(cs35l45->vdd_batt);1503}1504EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);1505 1506EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = {1507	RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)1508 1509	SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend, cs35l45_sys_resume)1510	NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq, cs35l45_sys_resume_noirq)1511};1512 1513MODULE_DESCRIPTION("ASoC CS35L45 driver");1514MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");1515MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");1516MODULE_LICENSE("GPL");1517