File Index
Files and directories
Sign in
FILE

cs35l45.c

File preview with syntax highlighting.

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