xref: /openbmc/linux/sound/pci/hda/cs35l41_hda.c (revision 57904291176fa16a981cefca5cbe1a0b50196792)
17b2f3eb4SLucas Tanure // SPDX-License-Identifier: GPL-2.0
27b2f3eb4SLucas Tanure //
38c286a0fSLucas Tanure // CS35l41 ALSA HDA audio driver
47b2f3eb4SLucas Tanure //
57b2f3eb4SLucas Tanure // Copyright 2021 Cirrus Logic, Inc.
67b2f3eb4SLucas Tanure //
77b2f3eb4SLucas Tanure // Author: Lucas Tanure <tanureal@opensource.cirrus.com>
87b2f3eb4SLucas Tanure 
97b2f3eb4SLucas Tanure #include <linux/acpi.h>
107b2f3eb4SLucas Tanure #include <linux/module.h>
11622f2199SStefan Binding #include <linux/moduleparam.h>
127b2f3eb4SLucas Tanure #include <sound/hda_codec.h>
132e81e1ffSVitaly Rodionov #include <sound/soc.h>
141873ebd3SStefan Binding #include <linux/pm_runtime.h>
157b2f3eb4SLucas Tanure #include "hda_local.h"
167b2f3eb4SLucas Tanure #include "hda_auto_parser.h"
177b2f3eb4SLucas Tanure #include "hda_jack.h"
187b2f3eb4SLucas Tanure #include "hda_generic.h"
197b2f3eb4SLucas Tanure #include "hda_component.h"
207b2f3eb4SLucas Tanure #include "cs35l41_hda.h"
212e81e1ffSVitaly Rodionov #include "hda_cs_dsp_ctl.h"
22ef4ba63fSStefan Binding #include "cs35l41_hda_property.h"
232e81e1ffSVitaly Rodionov 
242e81e1ffSVitaly Rodionov #define CS35L41_FIRMWARE_ROOT "cirrus/"
252e81e1ffSVitaly Rodionov #define CS35L41_PART "cs35l41"
262e81e1ffSVitaly Rodionov 
272e81e1ffSVitaly Rodionov #define HALO_STATE_DSP_CTL_NAME		"HALO_STATE"
282e81e1ffSVitaly Rodionov #define HALO_STATE_DSP_CTL_TYPE		5
292e81e1ffSVitaly Rodionov #define HALO_STATE_DSP_CTL_ALG		262308
303e34e2aeSStefan Binding #define CAL_R_DSP_CTL_NAME		"CAL_R"
313e34e2aeSStefan Binding #define CAL_STATUS_DSP_CTL_NAME		"CAL_STATUS"
323e34e2aeSStefan Binding #define CAL_CHECKSUM_DSP_CTL_NAME	"CAL_CHECKSUM"
333e34e2aeSStefan Binding #define CAL_AMBIENT_DSP_CTL_NAME	"CAL_AMBIENT"
343e34e2aeSStefan Binding #define CAL_DSP_CTL_TYPE		5
353e34e2aeSStefan Binding #define CAL_DSP_CTL_ALG			205
367b2f3eb4SLucas Tanure 
37622f2199SStefan Binding static bool firmware_autostart = 1;
38622f2199SStefan Binding module_param(firmware_autostart, bool, 0444);
39622f2199SStefan Binding MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
40622f2199SStefan Binding 			     "(0=Disable, 1=Enable) (default=1); ");
41622f2199SStefan Binding 
427b2f3eb4SLucas Tanure static const struct reg_sequence cs35l41_hda_config[] = {
431e616a9cSLucas Tanure 	{ CS35L41_PLL_CLK_CTRL,		0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
444fa58b1dSStefan Binding 	{ CS35L41_DSP_CLK_CTRL,		0x00000003 }, // DSP CLK EN
457b2f3eb4SLucas Tanure 	{ CS35L41_GLOBAL_CLK_CTRL,	0x00000003 }, // GLOBAL_FS = 48 kHz
467b2f3eb4SLucas Tanure 	{ CS35L41_SP_ENABLES,		0x00010000 }, // ASP_RX1_EN = 1
477b2f3eb4SLucas Tanure 	{ CS35L41_SP_RATE_CTRL,		0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
481e616a9cSLucas Tanure 	{ CS35L41_SP_FORMAT,		0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
494fa58b1dSStefan Binding 	{ CS35L41_SP_HIZ_CTRL,		0x00000002 }, // Hi-Z unused
504fa58b1dSStefan Binding 	{ CS35L41_SP_TX_WL,		0x00000018 }, // 24 cycles/slot
514fa58b1dSStefan Binding 	{ CS35L41_SP_RX_WL,		0x00000018 }, // 24 cycles/slot
527b2f3eb4SLucas Tanure 	{ CS35L41_DAC_PCM1_SRC,		0x00000008 }, // DACPCM1_SRC = ASPRX1
534fa58b1dSStefan Binding 	{ CS35L41_ASP_TX1_SRC,		0x00000018 }, // ASPTX1 SRC = VMON
544fa58b1dSStefan Binding 	{ CS35L41_ASP_TX2_SRC,		0x00000019 }, // ASPTX2 SRC = IMON
554fa58b1dSStefan Binding 	{ CS35L41_ASP_TX3_SRC,		0x00000032 }, // ASPTX3 SRC = ERRVOL
564fa58b1dSStefan Binding 	{ CS35L41_ASP_TX4_SRC,		0x00000033 }, // ASPTX4 SRC = CLASSH_TGT
574fa58b1dSStefan Binding 	{ CS35L41_DSP1_RX1_SRC,		0x00000008 }, // DSP1RX1 SRC = ASPRX1
584fa58b1dSStefan Binding 	{ CS35L41_DSP1_RX2_SRC,		0x00000009 }, // DSP1RX2 SRC = ASPRX2
594fa58b1dSStefan Binding 	{ CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
604fa58b1dSStefan Binding 	{ CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
614fa58b1dSStefan Binding 	{ CS35L41_DSP1_RX5_SRC,         0x00000020 }, // DSP1RX5 SRC = ERRVOL
627b2f3eb4SLucas Tanure };
637b2f3eb4SLucas Tanure 
642e81e1ffSVitaly Rodionov static const struct reg_sequence cs35l41_hda_config_dsp[] = {
652e81e1ffSVitaly Rodionov 	{ CS35L41_PLL_CLK_CTRL,		0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
662e81e1ffSVitaly Rodionov 	{ CS35L41_DSP_CLK_CTRL,		0x00000003 }, // DSP CLK EN
672e81e1ffSVitaly Rodionov 	{ CS35L41_GLOBAL_CLK_CTRL,	0x00000003 }, // GLOBAL_FS = 48 kHz
682e81e1ffSVitaly Rodionov 	{ CS35L41_SP_ENABLES,		0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1
692e81e1ffSVitaly Rodionov 	{ CS35L41_SP_RATE_CTRL,		0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
702e81e1ffSVitaly Rodionov 	{ CS35L41_SP_FORMAT,		0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
712e81e1ffSVitaly Rodionov 	{ CS35L41_SP_HIZ_CTRL,		0x00000003 }, // Hi-Z unused/disabled
722e81e1ffSVitaly Rodionov 	{ CS35L41_SP_TX_WL,		0x00000018 }, // 24 cycles/slot
732e81e1ffSVitaly Rodionov 	{ CS35L41_SP_RX_WL,		0x00000018 }, // 24 cycles/slot
742e81e1ffSVitaly Rodionov 	{ CS35L41_DAC_PCM1_SRC,		0x00000032 }, // DACPCM1_SRC = ERR_VOL
752e81e1ffSVitaly Rodionov 	{ CS35L41_ASP_TX1_SRC,		0x00000018 }, // ASPTX1 SRC = VMON
762e81e1ffSVitaly Rodionov 	{ CS35L41_ASP_TX2_SRC,		0x00000019 }, // ASPTX2 SRC = IMON
772e81e1ffSVitaly Rodionov 	{ CS35L41_ASP_TX3_SRC,		0x00000028 }, // ASPTX3 SRC = VPMON
782e81e1ffSVitaly Rodionov 	{ CS35L41_ASP_TX4_SRC,		0x00000029 }, // ASPTX4 SRC = VBSTMON
792e81e1ffSVitaly Rodionov 	{ CS35L41_DSP1_RX1_SRC,		0x00000008 }, // DSP1RX1 SRC = ASPRX1
802e81e1ffSVitaly Rodionov 	{ CS35L41_DSP1_RX2_SRC,		0x00000008 }, // DSP1RX2 SRC = ASPRX1
812e81e1ffSVitaly Rodionov 	{ CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
822e81e1ffSVitaly Rodionov 	{ CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
832e81e1ffSVitaly Rodionov 	{ CS35L41_DSP1_RX5_SRC,         0x00000029 }, // DSP1RX5 SRC = VBSTMON
842d816d4fSStefan Binding };
852d816d4fSStefan Binding 
862d816d4fSStefan Binding static const struct reg_sequence cs35l41_hda_unmute[] = {
872d816d4fSStefan Binding 	{ CS35L41_AMP_DIG_VOL_CTRL,	0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB
882d816d4fSStefan Binding 	{ CS35L41_AMP_GAIN_CTRL,	0x00000084 }, // AMP_GAIN_PCM 4.5 dB
892d816d4fSStefan Binding };
902d816d4fSStefan Binding 
912d816d4fSStefan Binding static const struct reg_sequence cs35l41_hda_unmute_dsp[] = {
925791c769SStefan Binding 	{ CS35L41_AMP_DIG_VOL_CTRL,	0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB
932e81e1ffSVitaly Rodionov 	{ CS35L41_AMP_GAIN_CTRL,	0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB
942e81e1ffSVitaly Rodionov };
952e81e1ffSVitaly Rodionov 
96f29db089SLucas Tanure static const struct reg_sequence cs35l41_hda_mute[] = {
97f29db089SLucas Tanure 	{ CS35L41_AMP_GAIN_CTRL,	0x00000000 }, // AMP_GAIN_PCM 0.5 dB
985791c769SStefan Binding 	{ CS35L41_AMP_DIG_VOL_CTRL,	0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute
99f29db089SLucas Tanure };
100f29db089SLucas Tanure 
cs35l41_add_controls(struct cs35l41_hda * cs35l41)1012176c6b5SRichard Fitzgerald static void cs35l41_add_controls(struct cs35l41_hda *cs35l41)
1022e81e1ffSVitaly Rodionov {
1032e81e1ffSVitaly Rodionov 	struct hda_cs_dsp_ctl_info info;
1042e81e1ffSVitaly Rodionov 
1052e81e1ffSVitaly Rodionov 	info.device_name = cs35l41->amp_name;
10647ceabd9SStefan Binding 	info.fw_type = cs35l41->firmware_type;
1072e81e1ffSVitaly Rodionov 	info.card = cs35l41->codec->card;
1082e81e1ffSVitaly Rodionov 
1092176c6b5SRichard Fitzgerald 	hda_cs_dsp_add_controls(&cs35l41->cs_dsp, &info);
1102e81e1ffSVitaly Rodionov }
1112e81e1ffSVitaly Rodionov 
1122e81e1ffSVitaly Rodionov static const struct cs_dsp_client_ops client_ops = {
1132e81e1ffSVitaly Rodionov 	.control_remove = hda_cs_dsp_control_remove,
1142e81e1ffSVitaly Rodionov };
1152e81e1ffSVitaly Rodionov 
cs35l41_request_firmware_file(struct cs35l41_hda * cs35l41,const struct firmware ** firmware,char ** filename,const char * dir,const char * ssid,const char * amp_name,int spkid,const char * filetype)1162e81e1ffSVitaly Rodionov static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
1172e81e1ffSVitaly Rodionov 					 const struct firmware **firmware, char **filename,
118bb6eb621SStefan Binding 					 const char *dir, const char *ssid, const char *amp_name,
11963f4b99fSStefan Binding 					 int spkid, const char *filetype)
1202e81e1ffSVitaly Rodionov {
1212e81e1ffSVitaly Rodionov 	const char * const dsp_name = cs35l41->cs_dsp.name;
1222e81e1ffSVitaly Rodionov 	char *s, c;
1232e81e1ffSVitaly Rodionov 	int ret = 0;
1242e81e1ffSVitaly Rodionov 
12563f4b99fSStefan Binding 	if (spkid > -1 && ssid && amp_name)
12663f4b99fSStefan Binding 		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d-%s.%s", dir, CS35L41_PART,
12747ceabd9SStefan Binding 				      dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
12847ceabd9SStefan Binding 				      ssid, spkid, amp_name, filetype);
12963f4b99fSStefan Binding 	else if (spkid > -1 && ssid)
13063f4b99fSStefan Binding 		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d.%s", dir, CS35L41_PART,
13147ceabd9SStefan Binding 				      dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
13247ceabd9SStefan Binding 				      ssid, spkid, filetype);
13363f4b99fSStefan Binding 	else if (ssid && amp_name)
134bb6eb621SStefan Binding 		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, CS35L41_PART,
13547ceabd9SStefan Binding 				      dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
13647ceabd9SStefan Binding 				      ssid, amp_name, filetype);
137bb6eb621SStefan Binding 	else if (ssid)
138bb6eb621SStefan Binding 		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, CS35L41_PART,
13947ceabd9SStefan Binding 				      dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
14047ceabd9SStefan Binding 				      ssid, filetype);
141bb6eb621SStefan Binding 	else
142bb6eb621SStefan Binding 		*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART,
14347ceabd9SStefan Binding 				      dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
14447ceabd9SStefan Binding 				      filetype);
1452e81e1ffSVitaly Rodionov 
1462e81e1ffSVitaly Rodionov 	if (*filename == NULL)
1472e81e1ffSVitaly Rodionov 		return -ENOMEM;
1482e81e1ffSVitaly Rodionov 
1492e81e1ffSVitaly Rodionov 	/*
1502e81e1ffSVitaly Rodionov 	 * Make sure that filename is lower-case and any non alpha-numeric
1512e81e1ffSVitaly Rodionov 	 * characters except full stop and '/' are replaced with hyphens.
1522e81e1ffSVitaly Rodionov 	 */
1532e81e1ffSVitaly Rodionov 	s = *filename;
1542e81e1ffSVitaly Rodionov 	while (*s) {
1552e81e1ffSVitaly Rodionov 		c = *s;
1562e81e1ffSVitaly Rodionov 		if (isalnum(c))
1572e81e1ffSVitaly Rodionov 			*s = tolower(c);
1582e81e1ffSVitaly Rodionov 		else if (c != '.' && c != '/')
1592e81e1ffSVitaly Rodionov 			*s = '-';
1602e81e1ffSVitaly Rodionov 		s++;
1612e81e1ffSVitaly Rodionov 	}
1622e81e1ffSVitaly Rodionov 
1632e81e1ffSVitaly Rodionov 	ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
1642e81e1ffSVitaly Rodionov 	if (ret != 0) {
1652e81e1ffSVitaly Rodionov 		dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
1662e81e1ffSVitaly Rodionov 		kfree(*filename);
1672e81e1ffSVitaly Rodionov 		*filename = NULL;
1682e81e1ffSVitaly Rodionov 	}
1692e81e1ffSVitaly Rodionov 
1702e81e1ffSVitaly Rodionov 	return ret;
1712e81e1ffSVitaly Rodionov }
1722e81e1ffSVitaly Rodionov 
cs35l41_request_firmware_files_spkid(struct cs35l41_hda * cs35l41,const struct firmware ** wmfw_firmware,char ** wmfw_filename,const struct firmware ** coeff_firmware,char ** coeff_filename)17363f4b99fSStefan Binding static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
17463f4b99fSStefan Binding 						const struct firmware **wmfw_firmware,
17563f4b99fSStefan Binding 						char **wmfw_filename,
17663f4b99fSStefan Binding 						const struct firmware **coeff_firmware,
17763f4b99fSStefan Binding 						char **coeff_filename)
17863f4b99fSStefan Binding {
17963f4b99fSStefan Binding 	int ret;
18063f4b99fSStefan Binding 
18163f4b99fSStefan Binding 	/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */
18263f4b99fSStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
18363f4b99fSStefan Binding 					    CS35L41_FIRMWARE_ROOT,
18463f4b99fSStefan Binding 					    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
18563f4b99fSStefan Binding 					    cs35l41->speaker_id, "wmfw");
18663f4b99fSStefan Binding 	if (!ret) {
18763f4b99fSStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
1885d542b85SStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
18963f4b99fSStefan Binding 						    CS35L41_FIRMWARE_ROOT,
19063f4b99fSStefan Binding 						    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
19163f4b99fSStefan Binding 						    cs35l41->speaker_id, "bin");
1925d542b85SStefan Binding 		if (ret)
1935d542b85SStefan Binding 			goto coeff_err;
1945d542b85SStefan Binding 
1955d542b85SStefan Binding 		return 0;
19663f4b99fSStefan Binding 	}
19763f4b99fSStefan Binding 
19863f4b99fSStefan Binding 	/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
19963f4b99fSStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
20063f4b99fSStefan Binding 					    CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
20163f4b99fSStefan Binding 					    cs35l41->amp_name, -1, "wmfw");
20263f4b99fSStefan Binding 	if (!ret) {
20363f4b99fSStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
2045d542b85SStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
205cd40dad2SStefan Binding 						    CS35L41_FIRMWARE_ROOT,
206cd40dad2SStefan Binding 						    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
207cd40dad2SStefan Binding 						    cs35l41->speaker_id, "bin");
2085d542b85SStefan Binding 		if (ret)
2095d542b85SStefan Binding 			goto coeff_err;
2105d542b85SStefan Binding 
2115d542b85SStefan Binding 		return 0;
21263f4b99fSStefan Binding 	}
21363f4b99fSStefan Binding 
21463f4b99fSStefan Binding 	/* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
21563f4b99fSStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
21663f4b99fSStefan Binding 					    CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
21763f4b99fSStefan Binding 					    NULL, cs35l41->speaker_id, "wmfw");
21863f4b99fSStefan Binding 	if (!ret) {
21963f4b99fSStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
22063f4b99fSStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
22163f4b99fSStefan Binding 						    CS35L41_FIRMWARE_ROOT,
22263f4b99fSStefan Binding 						    cs35l41->acpi_subsystem_id,
22363f4b99fSStefan Binding 						    cs35l41->amp_name, cs35l41->speaker_id, "bin");
22463f4b99fSStefan Binding 		if (ret)
22563f4b99fSStefan Binding 			/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
2265d542b85SStefan Binding 			ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
227cd40dad2SStefan Binding 							    coeff_filename, CS35L41_FIRMWARE_ROOT,
228cd40dad2SStefan Binding 							    cs35l41->acpi_subsystem_id, NULL,
229cd40dad2SStefan Binding 							    cs35l41->speaker_id, "bin");
2305d542b85SStefan Binding 		if (ret)
2315d542b85SStefan Binding 			goto coeff_err;
2325d542b85SStefan Binding 
2335d542b85SStefan Binding 		return 0;
23463f4b99fSStefan Binding 	}
23563f4b99fSStefan Binding 
23663f4b99fSStefan Binding 	/* try cirrus/part-dspN-fwtype-sub.wmfw */
23763f4b99fSStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
23863f4b99fSStefan Binding 					    CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
23963f4b99fSStefan Binding 					    NULL, -1, "wmfw");
24063f4b99fSStefan Binding 	if (!ret) {
24163f4b99fSStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
24263f4b99fSStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
24363f4b99fSStefan Binding 						    CS35L41_FIRMWARE_ROOT,
244cd40dad2SStefan Binding 						    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
245cd40dad2SStefan Binding 						    cs35l41->speaker_id, "bin");
24663f4b99fSStefan Binding 		if (ret)
24763f4b99fSStefan Binding 			/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
2485d542b85SStefan Binding 			ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
249cd40dad2SStefan Binding 							    coeff_filename, CS35L41_FIRMWARE_ROOT,
250cd40dad2SStefan Binding 							    cs35l41->acpi_subsystem_id, NULL,
251cd40dad2SStefan Binding 							    cs35l41->speaker_id, "bin");
2525d542b85SStefan Binding 		if (ret)
2535d542b85SStefan Binding 			goto coeff_err;
25463f4b99fSStefan Binding 	}
25563f4b99fSStefan Binding 
25663f4b99fSStefan Binding 	return ret;
2575d542b85SStefan Binding coeff_err:
2585d542b85SStefan Binding 	release_firmware(*wmfw_firmware);
2595d542b85SStefan Binding 	kfree(*wmfw_filename);
2605d542b85SStefan Binding 	return ret;
2615d542b85SStefan Binding }
2625d542b85SStefan Binding 
cs35l41_fallback_firmware_file(struct cs35l41_hda * cs35l41,const struct firmware ** wmfw_firmware,char ** wmfw_filename,const struct firmware ** coeff_firmware,char ** coeff_filename)2635d542b85SStefan Binding static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
2645d542b85SStefan Binding 					  const struct firmware **wmfw_firmware,
2655d542b85SStefan Binding 					  char **wmfw_filename,
2665d542b85SStefan Binding 					  const struct firmware **coeff_firmware,
2675d542b85SStefan Binding 					  char **coeff_filename)
2685d542b85SStefan Binding {
2695d542b85SStefan Binding 	int ret;
2705d542b85SStefan Binding 
2715d542b85SStefan Binding 	/* Handle fallback */
2725d542b85SStefan Binding 	dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
2735d542b85SStefan Binding 
2745d542b85SStefan Binding 	/* fallback try cirrus/part-dspN-fwtype.wmfw */
2755d542b85SStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
2765d542b85SStefan Binding 					    CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
2775d542b85SStefan Binding 	if (ret)
2785d542b85SStefan Binding 		goto err;
2795d542b85SStefan Binding 
2805d542b85SStefan Binding 	/* fallback try cirrus/part-dspN-fwtype.bin */
2815d542b85SStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
2825d542b85SStefan Binding 					    CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
2835d542b85SStefan Binding 	if (ret) {
2845d542b85SStefan Binding 		release_firmware(*wmfw_firmware);
2855d542b85SStefan Binding 		kfree(*wmfw_filename);
2865d542b85SStefan Binding 		goto err;
2875d542b85SStefan Binding 	}
2885d542b85SStefan Binding 	return 0;
2895d542b85SStefan Binding 
2905d542b85SStefan Binding err:
2915d542b85SStefan Binding 	dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
2925d542b85SStefan Binding 	return ret;
29363f4b99fSStefan Binding }
29463f4b99fSStefan Binding 
cs35l41_request_firmware_files(struct cs35l41_hda * cs35l41,const struct firmware ** wmfw_firmware,char ** wmfw_filename,const struct firmware ** coeff_firmware,char ** coeff_filename)2952e81e1ffSVitaly Rodionov static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
2962e81e1ffSVitaly Rodionov 					  const struct firmware **wmfw_firmware,
2972e81e1ffSVitaly Rodionov 					  char **wmfw_filename,
2982e81e1ffSVitaly Rodionov 					  const struct firmware **coeff_firmware,
2992e81e1ffSVitaly Rodionov 					  char **coeff_filename)
3002e81e1ffSVitaly Rodionov {
3012e81e1ffSVitaly Rodionov 	int ret;
3022e81e1ffSVitaly Rodionov 
303cd40dad2SStefan Binding 	if (cs35l41->speaker_id > -1) {
304cd40dad2SStefan Binding 		ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
30563f4b99fSStefan Binding 							   coeff_firmware, coeff_filename);
306cd40dad2SStefan Binding 		goto out;
307cd40dad2SStefan Binding 	}
30863f4b99fSStefan Binding 
309bb6eb621SStefan Binding 	/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
3102e81e1ffSVitaly Rodionov 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
311bb6eb621SStefan Binding 					    CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
31263f4b99fSStefan Binding 					    cs35l41->amp_name, -1, "wmfw");
3132e81e1ffSVitaly Rodionov 	if (!ret) {
314bb6eb621SStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
315cd40dad2SStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
316cd40dad2SStefan Binding 						    CS35L41_FIRMWARE_ROOT,
317cd40dad2SStefan Binding 						    cs35l41->acpi_subsystem_id, cs35l41->amp_name,
318cd40dad2SStefan Binding 						    -1, "bin");
3195d542b85SStefan Binding 		if (ret)
3205d542b85SStefan Binding 			goto coeff_err;
3215d542b85SStefan Binding 
322cd40dad2SStefan Binding 		goto out;
323bb6eb621SStefan Binding 	}
324bb6eb621SStefan Binding 
325bb6eb621SStefan Binding 	/* try cirrus/part-dspN-fwtype-sub.wmfw */
326bb6eb621SStefan Binding 	ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
327bb6eb621SStefan Binding 					    CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
32863f4b99fSStefan Binding 					    NULL, -1, "wmfw");
329bb6eb621SStefan Binding 	if (!ret) {
330bb6eb621SStefan Binding 		/* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
331bb6eb621SStefan Binding 		ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
332bb6eb621SStefan Binding 						    CS35L41_FIRMWARE_ROOT,
333bb6eb621SStefan Binding 						    cs35l41->acpi_subsystem_id,
33463f4b99fSStefan Binding 						    cs35l41->amp_name, -1, "bin");
335bb6eb621SStefan Binding 		if (ret)
336bb6eb621SStefan Binding 			/* try cirrus/part-dspN-fwtype-sub.bin */
337cd40dad2SStefan Binding 			ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
338bb6eb621SStefan Binding 							    CS35L41_FIRMWARE_ROOT,
339cd40dad2SStefan Binding 							    cs35l41->acpi_subsystem_id, NULL, -1,
340cd40dad2SStefan Binding 							    "bin");
3415d542b85SStefan Binding 		if (ret)
3425d542b85SStefan Binding 			goto coeff_err;
343bb6eb621SStefan Binding 	}
344bb6eb621SStefan Binding 
345cd40dad2SStefan Binding out:
3465d542b85SStefan Binding 	if (ret)
3475d542b85SStefan Binding 		/* if all attempts at finding firmware fail, try fallback */
3485d542b85SStefan Binding 		goto fallback;
3495d542b85SStefan Binding 
350cd40dad2SStefan Binding 	return 0;
351cd40dad2SStefan Binding 
3525d542b85SStefan Binding coeff_err:
353cd40dad2SStefan Binding 	release_firmware(*wmfw_firmware);
354cd40dad2SStefan Binding 	kfree(*wmfw_filename);
3555d542b85SStefan Binding fallback:
3565d542b85SStefan Binding 	return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
3575d542b85SStefan Binding 					      coeff_firmware, coeff_filename);
3582e81e1ffSVitaly Rodionov }
3592e81e1ffSVitaly Rodionov 
3603e34e2aeSStefan Binding #if IS_ENABLED(CONFIG_EFI)
cs35l41_apply_calibration(struct cs35l41_hda * cs35l41,__be32 ambient,__be32 r0,__be32 status,__be32 checksum)36131dbb503SStefan Binding static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, __be32 ambient, __be32 r0,
36231dbb503SStefan Binding 				     __be32 status, __be32 checksum)
3633e34e2aeSStefan Binding {
3643e34e2aeSStefan Binding 	int ret;
3653e34e2aeSStefan Binding 
3663e34e2aeSStefan Binding 	ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_AMBIENT_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
3673e34e2aeSStefan Binding 				   CAL_DSP_CTL_ALG, &ambient, 4);
3683e34e2aeSStefan Binding 	if (ret) {
3693e34e2aeSStefan Binding 		dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_AMBIENT_DSP_CTL_NAME,
3703e34e2aeSStefan Binding 			ret);
3713e34e2aeSStefan Binding 		return ret;
3723e34e2aeSStefan Binding 	}
3733e34e2aeSStefan Binding 	ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_R_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
3743e34e2aeSStefan Binding 				   CAL_DSP_CTL_ALG, &r0, 4);
3753e34e2aeSStefan Binding 	if (ret) {
3763e34e2aeSStefan Binding 		dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_R_DSP_CTL_NAME, ret);
3773e34e2aeSStefan Binding 		return ret;
3783e34e2aeSStefan Binding 	}
3793e34e2aeSStefan Binding 	ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_STATUS_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
3803e34e2aeSStefan Binding 				   CAL_DSP_CTL_ALG, &status, 4);
3813e34e2aeSStefan Binding 	if (ret) {
3823e34e2aeSStefan Binding 		dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_STATUS_DSP_CTL_NAME,
3833e34e2aeSStefan Binding 			ret);
3843e34e2aeSStefan Binding 		return ret;
3853e34e2aeSStefan Binding 	}
3863e34e2aeSStefan Binding 	ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_CHECKSUM_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
3873e34e2aeSStefan Binding 				   CAL_DSP_CTL_ALG, &checksum, 4);
3883e34e2aeSStefan Binding 	if (ret) {
3893e34e2aeSStefan Binding 		dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_CHECKSUM_DSP_CTL_NAME,
3903e34e2aeSStefan Binding 			ret);
3913e34e2aeSStefan Binding 		return ret;
3923e34e2aeSStefan Binding 	}
3933e34e2aeSStefan Binding 
3943e34e2aeSStefan Binding 	return 0;
3953e34e2aeSStefan Binding }
3963e34e2aeSStefan Binding 
cs35l41_save_calibration(struct cs35l41_hda * cs35l41)3973e34e2aeSStefan Binding static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
3983e34e2aeSStefan Binding {
3993e34e2aeSStefan Binding 	static efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe,
4003e34e2aeSStefan Binding 					      0x5a, 0xa3, 0x5d, 0xb3);
4013e34e2aeSStefan Binding 	static efi_char16_t efi_name[] = L"CirrusSmartAmpCalibrationData";
4023e34e2aeSStefan Binding 	const struct cs35l41_amp_efi_data *efi_data;
4033e34e2aeSStefan Binding 	const struct cs35l41_amp_cal_data *cl;
4043e34e2aeSStefan Binding 	unsigned long data_size = 0;
4053e34e2aeSStefan Binding 	efi_status_t status;
4063e34e2aeSStefan Binding 	int ret = 0;
4073e34e2aeSStefan Binding 	u8 *data = NULL;
4083e34e2aeSStefan Binding 	u32 attr;
4093e34e2aeSStefan Binding 
4103e34e2aeSStefan Binding 	/* Get real size of UEFI variable */
4113e34e2aeSStefan Binding 	status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
4123e34e2aeSStefan Binding 	if (status == EFI_BUFFER_TOO_SMALL) {
4133e34e2aeSStefan Binding 		ret = -ENODEV;
4143e34e2aeSStefan Binding 		/* Allocate data buffer of data_size bytes */
4153e34e2aeSStefan Binding 		data = vmalloc(data_size);
4163e34e2aeSStefan Binding 		if (!data)
4173e34e2aeSStefan Binding 			return -ENOMEM;
4183e34e2aeSStefan Binding 		/* Get variable contents into buffer */
4193e34e2aeSStefan Binding 		status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
4203e34e2aeSStefan Binding 		if (status == EFI_SUCCESS) {
4213e34e2aeSStefan Binding 			efi_data = (struct cs35l41_amp_efi_data *)data;
4223e34e2aeSStefan Binding 			dev_dbg(cs35l41->dev, "Calibration: Size=%d, Amp Count=%d\n",
4233e34e2aeSStefan Binding 				efi_data->size, efi_data->count);
4243e34e2aeSStefan Binding 			if (efi_data->count > cs35l41->index) {
4253e34e2aeSStefan Binding 				cl = &efi_data->data[cs35l41->index];
4263e34e2aeSStefan Binding 				dev_dbg(cs35l41->dev,
4273e34e2aeSStefan Binding 					"Calibration: Ambient=%02x, Status=%02x, R0=%d\n",
4283e34e2aeSStefan Binding 					cl->calAmbient, cl->calStatus, cl->calR);
4293e34e2aeSStefan Binding 
4303e34e2aeSStefan Binding 				/* Calibration can only be applied whilst the DSP is not running */
4313e34e2aeSStefan Binding 				ret = cs35l41_apply_calibration(cs35l41,
4323e34e2aeSStefan Binding 								cpu_to_be32(cl->calAmbient),
4333e34e2aeSStefan Binding 								cpu_to_be32(cl->calR),
4343e34e2aeSStefan Binding 								cpu_to_be32(cl->calStatus),
4353e34e2aeSStefan Binding 								cpu_to_be32(cl->calR + 1));
4363e34e2aeSStefan Binding 			}
4373e34e2aeSStefan Binding 		}
4383e34e2aeSStefan Binding 		vfree(data);
4393e34e2aeSStefan Binding 	}
4403e34e2aeSStefan Binding 	return ret;
4413e34e2aeSStefan Binding }
4423e34e2aeSStefan Binding #else
cs35l41_save_calibration(struct cs35l41_hda * cs35l41)4433e34e2aeSStefan Binding static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
4443e34e2aeSStefan Binding {
4453e34e2aeSStefan Binding 	dev_warn(cs35l41->dev, "Calibration not supported without EFI support.\n");
4463e34e2aeSStefan Binding 	return 0;
4473e34e2aeSStefan Binding }
4483e34e2aeSStefan Binding #endif
4493e34e2aeSStefan Binding 
cs35l41_init_dsp(struct cs35l41_hda * cs35l41)4502e81e1ffSVitaly Rodionov static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
4512e81e1ffSVitaly Rodionov {
4522e81e1ffSVitaly Rodionov 	const struct firmware *coeff_firmware = NULL;
4532e81e1ffSVitaly Rodionov 	const struct firmware *wmfw_firmware = NULL;
4542e81e1ffSVitaly Rodionov 	struct cs_dsp *dsp = &cs35l41->cs_dsp;
4552e81e1ffSVitaly Rodionov 	char *coeff_filename = NULL;
4562e81e1ffSVitaly Rodionov 	char *wmfw_filename = NULL;
4572e81e1ffSVitaly Rodionov 	int ret;
4582e81e1ffSVitaly Rodionov 
4592e81e1ffSVitaly Rodionov 	if (!cs35l41->halo_initialized) {
4602e81e1ffSVitaly Rodionov 		cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, dsp);
4612e81e1ffSVitaly Rodionov 		dsp->client_ops = &client_ops;
4622e81e1ffSVitaly Rodionov 
4632e81e1ffSVitaly Rodionov 		ret = cs_dsp_halo_init(&cs35l41->cs_dsp);
4642e81e1ffSVitaly Rodionov 		if (ret)
4652e81e1ffSVitaly Rodionov 			return ret;
4662e81e1ffSVitaly Rodionov 		cs35l41->halo_initialized = true;
4672e81e1ffSVitaly Rodionov 	}
4682e81e1ffSVitaly Rodionov 
4692e81e1ffSVitaly Rodionov 	ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename,
4702e81e1ffSVitaly Rodionov 					     &coeff_firmware, &coeff_filename);
4712e81e1ffSVitaly Rodionov 	if (ret < 0)
4722e81e1ffSVitaly Rodionov 		return ret;
4732e81e1ffSVitaly Rodionov 
4742e81e1ffSVitaly Rodionov 	dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename);
4752e81e1ffSVitaly Rodionov 	if (coeff_filename)
4762e81e1ffSVitaly Rodionov 		dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename);
4772e81e1ffSVitaly Rodionov 	else
4782e81e1ffSVitaly Rodionov 		dev_warn(cs35l41->dev, "No Coefficient File available.\n");
4792e81e1ffSVitaly Rodionov 
4802e81e1ffSVitaly Rodionov 	ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
48147ceabd9SStefan Binding 			      hda_cs_dsp_fw_ids[cs35l41->firmware_type]);
4823e34e2aeSStefan Binding 	if (ret)
4833e34e2aeSStefan Binding 		goto err_release;
4842e81e1ffSVitaly Rodionov 
4852176c6b5SRichard Fitzgerald 	cs35l41_add_controls(cs35l41);
4862176c6b5SRichard Fitzgerald 
4873e34e2aeSStefan Binding 	ret = cs35l41_save_calibration(cs35l41);
4883e34e2aeSStefan Binding 
4893e34e2aeSStefan Binding err_release:
4902e81e1ffSVitaly Rodionov 	release_firmware(wmfw_firmware);
4912e81e1ffSVitaly Rodionov 	release_firmware(coeff_firmware);
4922e81e1ffSVitaly Rodionov 	kfree(wmfw_filename);
4932e81e1ffSVitaly Rodionov 	kfree(coeff_filename);
4942e81e1ffSVitaly Rodionov 
4952e81e1ffSVitaly Rodionov 	return ret;
4962e81e1ffSVitaly Rodionov }
4972e81e1ffSVitaly Rodionov 
cs35l41_shutdown_dsp(struct cs35l41_hda * cs35l41)4982e81e1ffSVitaly Rodionov static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
4992e81e1ffSVitaly Rodionov {
5002e81e1ffSVitaly Rodionov 	struct cs_dsp *dsp = &cs35l41->cs_dsp;
5012e81e1ffSVitaly Rodionov 
5022e81e1ffSVitaly Rodionov 	cs_dsp_stop(dsp);
5032e81e1ffSVitaly Rodionov 	cs_dsp_power_down(dsp);
5042e81e1ffSVitaly Rodionov 	cs35l41->firmware_running = false;
5052e81e1ffSVitaly Rodionov 	dev_dbg(cs35l41->dev, "Unloaded Firmware\n");
5062e81e1ffSVitaly Rodionov }
5072e81e1ffSVitaly Rodionov 
cs35l41_remove_dsp(struct cs35l41_hda * cs35l41)5082e81e1ffSVitaly Rodionov static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
5092e81e1ffSVitaly Rodionov {
5102e81e1ffSVitaly Rodionov 	struct cs_dsp *dsp = &cs35l41->cs_dsp;
5112e81e1ffSVitaly Rodionov 
51247ceabd9SStefan Binding 	cancel_work_sync(&cs35l41->fw_load_work);
51388672826SStefan Binding 
51488672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
5152e81e1ffSVitaly Rodionov 	cs35l41_shutdown_dsp(cs35l41);
5162e81e1ffSVitaly Rodionov 	cs_dsp_remove(dsp);
5172e81e1ffSVitaly Rodionov 	cs35l41->halo_initialized = false;
51888672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
5192e81e1ffSVitaly Rodionov }
5202e81e1ffSVitaly Rodionov 
521aa4a38afSStefan Binding /* Protection release cycle to get the speaker out of Safe-Mode */
cs35l41_error_release(struct device * dev,struct regmap * regmap,unsigned int mask)522aa4a38afSStefan Binding static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
523aa4a38afSStefan Binding {
524aa4a38afSStefan Binding 	regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0);
525aa4a38afSStefan Binding 	regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
526aa4a38afSStefan Binding 	regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
527aa4a38afSStefan Binding }
528aa4a38afSStefan Binding 
529aa4a38afSStefan Binding /* Clear all errors to release safe mode. Global Enable must be cleared first. */
cs35l41_irq_release(struct cs35l41_hda * cs35l41)530aa4a38afSStefan Binding static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
531aa4a38afSStefan Binding {
532aa4a38afSStefan Binding 	cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors);
533aa4a38afSStefan Binding 	cs35l41->irq_errors = 0;
534aa4a38afSStefan Binding }
535aa4a38afSStefan Binding 
cs35l41_hda_play_start(struct device * dev)536a5adbfb6SStefan Binding static void cs35l41_hda_play_start(struct device *dev)
5377b2f3eb4SLucas Tanure {
5387b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
5397b2f3eb4SLucas Tanure 	struct regmap *reg = cs35l41->regmap;
5407b2f3eb4SLucas Tanure 
541a5adbfb6SStefan Binding 	dev_dbg(dev, "Play (Start)\n");
542a5adbfb6SStefan Binding 
543a5adbfb6SStefan Binding 	if (cs35l41->playback_started) {
544a5adbfb6SStefan Binding 		dev_dbg(dev, "Playback already started.");
545a5adbfb6SStefan Binding 		return;
546a5adbfb6SStefan Binding 	}
547a5adbfb6SStefan Binding 
54847ceabd9SStefan Binding 	cs35l41->playback_started = true;
549a5adbfb6SStefan Binding 
5502e81e1ffSVitaly Rodionov 	if (cs35l41->firmware_running) {
5512e81e1ffSVitaly Rodionov 		regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
5522e81e1ffSVitaly Rodionov 				       ARRAY_SIZE(cs35l41_hda_config_dsp));
553a5adbfb6SStefan Binding 		regmap_update_bits(reg, CS35L41_PWR_CTRL2,
5542e81e1ffSVitaly Rodionov 				   CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
5552e81e1ffSVitaly Rodionov 				   1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
556a5adbfb6SStefan Binding 		cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME);
5572e81e1ffSVitaly Rodionov 	} else {
558a5adbfb6SStefan Binding 		regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
5592e81e1ffSVitaly Rodionov 	}
560a5adbfb6SStefan Binding 	regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
561734b965eSLucas Tanure 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
562734b965eSLucas Tanure 		regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
563a5adbfb6SStefan Binding 
564a5adbfb6SStefan Binding }
565a5adbfb6SStefan Binding 
cs35l41_hda_play_done(struct device * dev)566a5adbfb6SStefan Binding static void cs35l41_hda_play_done(struct device *dev)
567a5adbfb6SStefan Binding {
568a5adbfb6SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
569a5adbfb6SStefan Binding 	struct regmap *reg = cs35l41->regmap;
570a5adbfb6SStefan Binding 
571a5adbfb6SStefan Binding 	dev_dbg(dev, "Play (Complete)\n");
572a5adbfb6SStefan Binding 
573507032d6SCristian Ciocaltea 	cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1,
574fa3efcc3SStefan Binding 			      cs35l41->firmware_running);
5752d816d4fSStefan Binding 	if (cs35l41->firmware_running) {
5762d816d4fSStefan Binding 		regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp,
5772d816d4fSStefan Binding 				       ARRAY_SIZE(cs35l41_hda_unmute_dsp));
5782d816d4fSStefan Binding 	} else {
5792d816d4fSStefan Binding 		regmap_multi_reg_write(reg, cs35l41_hda_unmute,
5802d816d4fSStefan Binding 				       ARRAY_SIZE(cs35l41_hda_unmute));
5812d816d4fSStefan Binding 	}
582a5adbfb6SStefan Binding }
583a5adbfb6SStefan Binding 
cs35l41_hda_pause_start(struct device * dev)584a5adbfb6SStefan Binding static void cs35l41_hda_pause_start(struct device *dev)
585a5adbfb6SStefan Binding {
586a5adbfb6SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
587a5adbfb6SStefan Binding 	struct regmap *reg = cs35l41->regmap;
588a5adbfb6SStefan Binding 
589a5adbfb6SStefan Binding 	dev_dbg(dev, "Pause (Start)\n");
590a5adbfb6SStefan Binding 
591f29db089SLucas Tanure 	regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
592507032d6SCristian Ciocaltea 	cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0,
593fa3efcc3SStefan Binding 			      cs35l41->firmware_running);
594a5adbfb6SStefan Binding }
595a5adbfb6SStefan Binding 
cs35l41_hda_pause_done(struct device * dev)596a5adbfb6SStefan Binding static void cs35l41_hda_pause_done(struct device *dev)
597a5adbfb6SStefan Binding {
598a5adbfb6SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
599a5adbfb6SStefan Binding 	struct regmap *reg = cs35l41->regmap;
600a5adbfb6SStefan Binding 
601a5adbfb6SStefan Binding 	dev_dbg(dev, "Pause (Complete)\n");
602a5adbfb6SStefan Binding 
603a5adbfb6SStefan Binding 	regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
604734b965eSLucas Tanure 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
605734b965eSLucas Tanure 		regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
6062e81e1ffSVitaly Rodionov 	if (cs35l41->firmware_running) {
607a5adbfb6SStefan Binding 		cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE);
608a5adbfb6SStefan Binding 		regmap_update_bits(reg, CS35L41_PWR_CTRL2,
6092e81e1ffSVitaly Rodionov 				   CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
6102e81e1ffSVitaly Rodionov 				   0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
6112e81e1ffSVitaly Rodionov 	}
612aa4a38afSStefan Binding 	cs35l41_irq_release(cs35l41);
61347ceabd9SStefan Binding 	cs35l41->playback_started = false;
614a5adbfb6SStefan Binding }
615a5adbfb6SStefan Binding 
cs35l41_hda_pre_playback_hook(struct device * dev,int action)61601ecc562SStefan Binding static void cs35l41_hda_pre_playback_hook(struct device *dev, int action)
61701ecc562SStefan Binding {
61801ecc562SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
61901ecc562SStefan Binding 
62001ecc562SStefan Binding 	switch (action) {
62101ecc562SStefan Binding 	case HDA_GEN_PCM_ACT_CLEANUP:
62201ecc562SStefan Binding 		mutex_lock(&cs35l41->fw_mutex);
62301ecc562SStefan Binding 		cs35l41_hda_pause_start(dev);
62401ecc562SStefan Binding 		mutex_unlock(&cs35l41->fw_mutex);
62501ecc562SStefan Binding 		break;
62601ecc562SStefan Binding 	default:
62701ecc562SStefan Binding 		break;
62801ecc562SStefan Binding 	}
62901ecc562SStefan Binding }
cs35l41_hda_playback_hook(struct device * dev,int action)630a5adbfb6SStefan Binding static void cs35l41_hda_playback_hook(struct device *dev, int action)
631a5adbfb6SStefan Binding {
632a5adbfb6SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
633a5adbfb6SStefan Binding 
634a5adbfb6SStefan Binding 	switch (action) {
635a5adbfb6SStefan Binding 	case HDA_GEN_PCM_ACT_OPEN:
63601ecc562SStefan Binding 		/*
63701ecc562SStefan Binding 		 * All amps must be resumed before we can start playing back.
63801ecc562SStefan Binding 		 * This ensures, for external boost, that all amps are in AMP_SAFE mode.
63901ecc562SStefan Binding 		 * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the
64001ecc562SStefan Binding 		 * other actions.
64101ecc562SStefan Binding 		 */
642a5adbfb6SStefan Binding 		pm_runtime_get_sync(dev);
64301ecc562SStefan Binding 		break;
64401ecc562SStefan Binding 	case HDA_GEN_PCM_ACT_PREPARE:
645a5adbfb6SStefan Binding 		mutex_lock(&cs35l41->fw_mutex);
646a5adbfb6SStefan Binding 		cs35l41_hda_play_start(dev);
647a5adbfb6SStefan Binding 		mutex_unlock(&cs35l41->fw_mutex);
648a5adbfb6SStefan Binding 		break;
64901ecc562SStefan Binding 	case HDA_GEN_PCM_ACT_CLEANUP:
65001ecc562SStefan Binding 		mutex_lock(&cs35l41->fw_mutex);
65101ecc562SStefan Binding 		cs35l41_hda_pause_done(dev);
65201ecc562SStefan Binding 		mutex_unlock(&cs35l41->fw_mutex);
65301ecc562SStefan Binding 		break;
65401ecc562SStefan Binding 	case HDA_GEN_PCM_ACT_CLOSE:
655c4d0510bSStefan Binding 		mutex_lock(&cs35l41->fw_mutex);
656c4d0510bSStefan Binding 		if (!cs35l41->firmware_running && cs35l41->request_fw_load &&
657c4d0510bSStefan Binding 		    !cs35l41->fw_request_ongoing) {
658c4d0510bSStefan Binding 			dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n");
659c4d0510bSStefan Binding 			cs35l41->fw_request_ongoing = true;
660c4d0510bSStefan Binding 			schedule_work(&cs35l41->fw_load_work);
661c4d0510bSStefan Binding 		}
662c4d0510bSStefan Binding 		mutex_unlock(&cs35l41->fw_mutex);
663c4d0510bSStefan Binding 
66401ecc562SStefan Binding 		/*
66501ecc562SStefan Binding 		 * Playback must be finished for all amps before we start runtime suspend.
66601ecc562SStefan Binding 		 * This ensures no amps are playing back when we start putting them to sleep.
66701ecc562SStefan Binding 		 */
66801ecc562SStefan Binding 		pm_runtime_mark_last_busy(dev);
66901ecc562SStefan Binding 		pm_runtime_put_autosuspend(dev);
67001ecc562SStefan Binding 		break;
67101ecc562SStefan Binding 	default:
67201ecc562SStefan Binding 		break;
67301ecc562SStefan Binding 	}
67401ecc562SStefan Binding }
67501ecc562SStefan Binding 
cs35l41_hda_post_playback_hook(struct device * dev,int action)67601ecc562SStefan Binding static void cs35l41_hda_post_playback_hook(struct device *dev, int action)
67701ecc562SStefan Binding {
67801ecc562SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
67901ecc562SStefan Binding 
68001ecc562SStefan Binding 	switch (action) {
681a5adbfb6SStefan Binding 	case HDA_GEN_PCM_ACT_PREPARE:
682a5adbfb6SStefan Binding 		mutex_lock(&cs35l41->fw_mutex);
683a5adbfb6SStefan Binding 		cs35l41_hda_play_done(dev);
684a5adbfb6SStefan Binding 		mutex_unlock(&cs35l41->fw_mutex);
685a5adbfb6SStefan Binding 		break;
686cd8abf7dSLucas Tanure 	default:
687cd8abf7dSLucas Tanure 		break;
6887b2f3eb4SLucas Tanure 	}
6897b2f3eb4SLucas Tanure }
6907b2f3eb4SLucas Tanure 
cs35l41_hda_channel_map(struct device * dev,unsigned int tx_num,unsigned int * tx_slot,unsigned int rx_num,unsigned int * rx_slot)6917b2f3eb4SLucas Tanure static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot,
6927b2f3eb4SLucas Tanure 				    unsigned int rx_num, unsigned int *rx_slot)
6937b2f3eb4SLucas Tanure {
6947b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
69500f87ec7SStefan Binding 	static const char * const channel_name[] = { "L", "R" };
69600f87ec7SStefan Binding 
69700f87ec7SStefan Binding 	if (!cs35l41->amp_name) {
69800f87ec7SStefan Binding 		if (*rx_slot >= ARRAY_SIZE(channel_name))
69900f87ec7SStefan Binding 			return -EINVAL;
70000f87ec7SStefan Binding 
70100f87ec7SStefan Binding 		cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d",
70200f87ec7SStefan Binding 						   channel_name[*rx_slot], cs35l41->channel_index);
70300f87ec7SStefan Binding 		if (!cs35l41->amp_name)
70400f87ec7SStefan Binding 			return -ENOMEM;
70500f87ec7SStefan Binding 	}
7067b2f3eb4SLucas Tanure 
7077b2f3eb4SLucas Tanure 	return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
7087b2f3eb4SLucas Tanure 				    rx_slot);
7097b2f3eb4SLucas Tanure }
7107b2f3eb4SLucas Tanure 
cs35l41_ready_for_reset(struct cs35l41_hda * cs35l41)711a3ff5646SStefan Binding static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
71288672826SStefan Binding {
713a3ff5646SStefan Binding 	int ret = 0;
714a3ff5646SStefan Binding 
71588672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
71688672826SStefan Binding 	if (cs35l41->firmware_running) {
71788672826SStefan Binding 
71888672826SStefan Binding 		regcache_cache_only(cs35l41->regmap, false);
71988672826SStefan Binding 
720a3ff5646SStefan Binding 		ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
721a3ff5646SStefan Binding 		if (ret) {
722a3ff5646SStefan Binding 			dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
723a3ff5646SStefan Binding 			goto err;
724a3ff5646SStefan Binding 		}
725a3ff5646SStefan Binding 
726a3ff5646SStefan Binding 		/* Test key needs to be unlocked to allow the OTP settings to re-apply */
727a3ff5646SStefan Binding 		cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
728a3ff5646SStefan Binding 		ret = regcache_sync(cs35l41->regmap);
729a3ff5646SStefan Binding 		cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
730a3ff5646SStefan Binding 		if (ret) {
731a3ff5646SStefan Binding 			dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
732a3ff5646SStefan Binding 			goto err;
733a3ff5646SStefan Binding 		}
734a3ff5646SStefan Binding 
735a3ff5646SStefan Binding 		if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
736a3ff5646SStefan Binding 			cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
737a3ff5646SStefan Binding 
73888672826SStefan Binding 		cs35l41_shutdown_dsp(cs35l41);
73988672826SStefan Binding 		cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
740a3ff5646SStefan Binding 	}
741a3ff5646SStefan Binding err:
74288672826SStefan Binding 	regcache_cache_only(cs35l41->regmap, true);
74388672826SStefan Binding 	regcache_mark_dirty(cs35l41->regmap);
744a3ff5646SStefan Binding 
74588672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
746a3ff5646SStefan Binding 
747a3ff5646SStefan Binding 	return ret;
74888672826SStefan Binding }
74988672826SStefan Binding 
cs35l41_system_suspend_prep(struct device * dev)750c4d0510bSStefan Binding static int cs35l41_system_suspend_prep(struct device *dev)
751c4d0510bSStefan Binding {
752c4d0510bSStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
753c4d0510bSStefan Binding 
754c4d0510bSStefan Binding 	dev_dbg(cs35l41->dev, "System Suspend Prepare\n");
755c4d0510bSStefan Binding 
756c4d0510bSStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
757c4d0510bSStefan Binding 		dev_err_once(cs35l41->dev, "System Suspend not supported\n");
758c4d0510bSStefan Binding 		return 0; /* don't block the whole system suspend */
759c4d0510bSStefan Binding 	}
760c4d0510bSStefan Binding 
761c4d0510bSStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
762c4d0510bSStefan Binding 	if (cs35l41->playback_started)
763c4d0510bSStefan Binding 		cs35l41_hda_pause_start(dev);
764c4d0510bSStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
765c4d0510bSStefan Binding 
766c4d0510bSStefan Binding 	return 0;
767c4d0510bSStefan Binding }
768c4d0510bSStefan Binding 
cs35l41_system_suspend(struct device * dev)76988672826SStefan Binding static int cs35l41_system_suspend(struct device *dev)
77088672826SStefan Binding {
77188672826SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
77288672826SStefan Binding 	int ret;
77388672826SStefan Binding 
77488672826SStefan Binding 	dev_dbg(cs35l41->dev, "System Suspend\n");
77588672826SStefan Binding 
77688672826SStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
77715a59cb0STakashi Iwai 		dev_err_once(cs35l41->dev, "System Suspend not supported\n");
77815a59cb0STakashi Iwai 		return 0; /* don't block the whole system suspend */
77988672826SStefan Binding 	}
78088672826SStefan Binding 
781c4d0510bSStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
782c4d0510bSStefan Binding 	if (cs35l41->playback_started)
783c4d0510bSStefan Binding 		cs35l41_hda_pause_done(dev);
784c4d0510bSStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
785c4d0510bSStefan Binding 
78688672826SStefan Binding 	ret = pm_runtime_force_suspend(dev);
787f2a58481SStefan Binding 	if (ret) {
788f2a58481SStefan Binding 		dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret);
78988672826SStefan Binding 		return ret;
790f2a58481SStefan Binding 	}
79188672826SStefan Binding 
79288672826SStefan Binding 	/* Shutdown DSP before system suspend */
793f2a58481SStefan Binding 	ret = cs35l41_ready_for_reset(cs35l41);
794f2a58481SStefan Binding 
795f2a58481SStefan Binding 	if (ret)
796f2a58481SStefan Binding 		dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret);
79788672826SStefan Binding 
79888672826SStefan Binding 	/*
79988672826SStefan Binding 	 * Reset GPIO may be shared, so cannot reset here.
80088672826SStefan Binding 	 * However beyond this point, amps may be powered down.
80188672826SStefan Binding 	 */
802f2a58481SStefan Binding 	return ret;
80388672826SStefan Binding }
80488672826SStefan Binding 
cs35l41_system_resume(struct device * dev)80588672826SStefan Binding static int cs35l41_system_resume(struct device *dev)
80688672826SStefan Binding {
80788672826SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
80888672826SStefan Binding 	int ret;
80988672826SStefan Binding 
81088672826SStefan Binding 	dev_dbg(cs35l41->dev, "System Resume\n");
81188672826SStefan Binding 
81288672826SStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
81315a59cb0STakashi Iwai 		dev_err_once(cs35l41->dev, "System Resume not supported\n");
81415a59cb0STakashi Iwai 		return 0; /* don't block the whole system resume */
81588672826SStefan Binding 	}
81688672826SStefan Binding 
81788672826SStefan Binding 	if (cs35l41->reset_gpio) {
81888672826SStefan Binding 		usleep_range(2000, 2100);
81988672826SStefan Binding 		gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
82088672826SStefan Binding 	}
82188672826SStefan Binding 
82288672826SStefan Binding 	usleep_range(2000, 2100);
82388672826SStefan Binding 
82488672826SStefan Binding 	ret = pm_runtime_force_resume(dev);
825f2a58481SStefan Binding 	if (ret) {
826f2a58481SStefan Binding 		dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret);
827f2a58481SStefan Binding 		return ret;
828f2a58481SStefan Binding 	}
82988672826SStefan Binding 
83088672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
831c4d0510bSStefan Binding 
832f2a58481SStefan Binding 	if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
83388672826SStefan Binding 		cs35l41->fw_request_ongoing = true;
83488672826SStefan Binding 		schedule_work(&cs35l41->fw_load_work);
83588672826SStefan Binding 	}
83688672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
83788672826SStefan Binding 
83888672826SStefan Binding 	return ret;
83988672826SStefan Binding }
84088672826SStefan Binding 
cs35l41_runtime_idle(struct device * dev)841ae50e2abSTakashi Iwai static int cs35l41_runtime_idle(struct device *dev)
842ae50e2abSTakashi Iwai {
843ae50e2abSTakashi Iwai 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
844ae50e2abSTakashi Iwai 
845ae50e2abSTakashi Iwai 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
846ae50e2abSTakashi Iwai 		return -EBUSY; /* suspend not supported yet on this model */
847ae50e2abSTakashi Iwai 	return 0;
848ae50e2abSTakashi Iwai }
849ae50e2abSTakashi Iwai 
cs35l41_runtime_suspend(struct device * dev)8501873ebd3SStefan Binding static int cs35l41_runtime_suspend(struct device *dev)
8511873ebd3SStefan Binding {
8521873ebd3SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
85388672826SStefan Binding 	int ret = 0;
8541873ebd3SStefan Binding 
85588672826SStefan Binding 	dev_dbg(cs35l41->dev, "Runtime Suspend\n");
8561873ebd3SStefan Binding 
85788672826SStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
85888672826SStefan Binding 		dev_dbg(cs35l41->dev, "Runtime Suspend not supported\n");
8591873ebd3SStefan Binding 		return 0;
86088672826SStefan Binding 	}
8611873ebd3SStefan Binding 
86288672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
86388672826SStefan Binding 
86488672826SStefan Binding 	if (cs35l41->firmware_running) {
86588672826SStefan Binding 		ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
86688672826SStefan Binding 					      cs35l41->hw_cfg.bst_type);
86788672826SStefan Binding 		if (ret)
86888672826SStefan Binding 			goto err;
86988672826SStefan Binding 	} else {
87088672826SStefan Binding 		cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
87188672826SStefan Binding 	}
8721873ebd3SStefan Binding 
8731873ebd3SStefan Binding 	regcache_cache_only(cs35l41->regmap, true);
8741873ebd3SStefan Binding 	regcache_mark_dirty(cs35l41->regmap);
8751873ebd3SStefan Binding 
87688672826SStefan Binding err:
87788672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
87888672826SStefan Binding 
87988672826SStefan Binding 	return ret;
8801873ebd3SStefan Binding }
8811873ebd3SStefan Binding 
cs35l41_runtime_resume(struct device * dev)8821873ebd3SStefan Binding static int cs35l41_runtime_resume(struct device *dev)
8831873ebd3SStefan Binding {
8841873ebd3SStefan Binding 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
88588672826SStefan Binding 	int ret = 0;
8861873ebd3SStefan Binding 
88788672826SStefan Binding 	dev_dbg(cs35l41->dev, "Runtime Resume\n");
8881873ebd3SStefan Binding 
8891873ebd3SStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
89088672826SStefan Binding 		dev_dbg(cs35l41->dev, "Runtime Resume not supported\n");
8911873ebd3SStefan Binding 		return 0;
8921873ebd3SStefan Binding 	}
8931873ebd3SStefan Binding 
89488672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
8951873ebd3SStefan Binding 
8961873ebd3SStefan Binding 	regcache_cache_only(cs35l41->regmap, false);
8971873ebd3SStefan Binding 
89888672826SStefan Binding 	if (cs35l41->firmware_running)	{
8991873ebd3SStefan Binding 		ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
9001873ebd3SStefan Binding 		if (ret) {
90188672826SStefan Binding 			dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
90288672826SStefan Binding 			goto err;
90388672826SStefan Binding 		}
9041873ebd3SStefan Binding 	}
9051873ebd3SStefan Binding 
9061873ebd3SStefan Binding 	/* Test key needs to be unlocked to allow the OTP settings to re-apply */
9071873ebd3SStefan Binding 	cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
9081873ebd3SStefan Binding 	ret = regcache_sync(cs35l41->regmap);
9091873ebd3SStefan Binding 	cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
9101873ebd3SStefan Binding 	if (ret) {
9111873ebd3SStefan Binding 		dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
91288672826SStefan Binding 		goto err;
9131873ebd3SStefan Binding 	}
9141873ebd3SStefan Binding 
9151873ebd3SStefan Binding 	if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
9161873ebd3SStefan Binding 		cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
9171873ebd3SStefan Binding 
91888672826SStefan Binding err:
91988672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
92088672826SStefan Binding 
92188672826SStefan Binding 	return ret;
9221873ebd3SStefan Binding }
9231873ebd3SStefan Binding 
cs35l41_smart_amp(struct cs35l41_hda * cs35l41)9242e81e1ffSVitaly Rodionov static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
9252e81e1ffSVitaly Rodionov {
92631dbb503SStefan Binding 	__be32 halo_sts;
9272e81e1ffSVitaly Rodionov 	int ret;
9282e81e1ffSVitaly Rodionov 
9292e81e1ffSVitaly Rodionov 	ret = cs35l41_init_dsp(cs35l41);
9302e81e1ffSVitaly Rodionov 	if (ret) {
9312e81e1ffSVitaly Rodionov 		dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
9322e81e1ffSVitaly Rodionov 		goto clean_dsp;
9332e81e1ffSVitaly Rodionov 	}
9342e81e1ffSVitaly Rodionov 
9352e81e1ffSVitaly Rodionov 	ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap);
9362e81e1ffSVitaly Rodionov 	if (ret) {
9372e81e1ffSVitaly Rodionov 		dev_err(cs35l41->dev, "Cannot Write FS Errata: %d\n", ret);
9382e81e1ffSVitaly Rodionov 		goto clean_dsp;
9392e81e1ffSVitaly Rodionov 	}
9402e81e1ffSVitaly Rodionov 
9412e81e1ffSVitaly Rodionov 	ret = cs_dsp_run(&cs35l41->cs_dsp);
9422e81e1ffSVitaly Rodionov 	if (ret) {
9432e81e1ffSVitaly Rodionov 		dev_err(cs35l41->dev, "Fail to start dsp: %d\n", ret);
9442e81e1ffSVitaly Rodionov 		goto clean_dsp;
9452e81e1ffSVitaly Rodionov 	}
9462e81e1ffSVitaly Rodionov 
9472e81e1ffSVitaly Rodionov 	ret = read_poll_timeout(hda_cs_dsp_read_ctl, ret,
9482e81e1ffSVitaly Rodionov 				be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN,
9492e81e1ffSVitaly Rodionov 				1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME,
9502e81e1ffSVitaly Rodionov 				HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG,
9512e81e1ffSVitaly Rodionov 				&halo_sts, sizeof(halo_sts));
9522e81e1ffSVitaly Rodionov 
9532e81e1ffSVitaly Rodionov 	if (ret) {
95431dbb503SStefan Binding 		dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %u\n",
9552e81e1ffSVitaly Rodionov 			 halo_sts);
9562e81e1ffSVitaly Rodionov 		goto clean_dsp;
9572e81e1ffSVitaly Rodionov 	}
9582e81e1ffSVitaly Rodionov 
9595299b79cSStefan Binding 	ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
9605299b79cSStefan Binding 	if (ret) {
9615299b79cSStefan Binding 		dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret);
9625299b79cSStefan Binding 		goto clean_dsp;
9635299b79cSStefan Binding 	}
9645299b79cSStefan Binding 
9652e81e1ffSVitaly Rodionov 	cs35l41->firmware_running = true;
9662e81e1ffSVitaly Rodionov 
9672e81e1ffSVitaly Rodionov 	return 0;
9682e81e1ffSVitaly Rodionov 
9692e81e1ffSVitaly Rodionov clean_dsp:
9702e81e1ffSVitaly Rodionov 	cs35l41_shutdown_dsp(cs35l41);
9712e81e1ffSVitaly Rodionov 	return ret;
9722e81e1ffSVitaly Rodionov }
9732e81e1ffSVitaly Rodionov 
cs35l41_load_firmware(struct cs35l41_hda * cs35l41,bool load)97447ceabd9SStefan Binding static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
97547ceabd9SStefan Binding {
97647ceabd9SStefan Binding 	if (cs35l41->firmware_running && !load) {
97747ceabd9SStefan Binding 		dev_dbg(cs35l41->dev, "Unloading Firmware\n");
97847ceabd9SStefan Binding 		cs35l41_shutdown_dsp(cs35l41);
97947ceabd9SStefan Binding 	} else if (!cs35l41->firmware_running && load) {
98047ceabd9SStefan Binding 		dev_dbg(cs35l41->dev, "Loading Firmware\n");
98147ceabd9SStefan Binding 		cs35l41_smart_amp(cs35l41);
98247ceabd9SStefan Binding 	} else {
98347ceabd9SStefan Binding 		dev_dbg(cs35l41->dev, "Unable to Load firmware.\n");
98447ceabd9SStefan Binding 	}
98547ceabd9SStefan Binding }
98647ceabd9SStefan Binding 
cs35l41_fw_load_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)98747ceabd9SStefan Binding static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
98847ceabd9SStefan Binding 				   struct snd_ctl_elem_value *ucontrol)
98947ceabd9SStefan Binding {
99047ceabd9SStefan Binding 	struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
99147ceabd9SStefan Binding 
99247ceabd9SStefan Binding 	ucontrol->value.integer.value[0] = cs35l41->request_fw_load;
99347ceabd9SStefan Binding 	return 0;
99447ceabd9SStefan Binding }
99547ceabd9SStefan Binding 
cs35l41_fw_load_work(struct work_struct * work)99647ceabd9SStefan Binding static void cs35l41_fw_load_work(struct work_struct *work)
99747ceabd9SStefan Binding {
99847ceabd9SStefan Binding 	struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
99947ceabd9SStefan Binding 
100088672826SStefan Binding 	pm_runtime_get_sync(cs35l41->dev);
100188672826SStefan Binding 
100247ceabd9SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
100347ceabd9SStefan Binding 
100447ceabd9SStefan Binding 	/* Recheck if playback is ongoing, mutex will block playback during firmware loading */
100547ceabd9SStefan Binding 	if (cs35l41->playback_started)
100688672826SStefan Binding 		dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
100747ceabd9SStefan Binding 	else
100847ceabd9SStefan Binding 		cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
100947ceabd9SStefan Binding 
101047ceabd9SStefan Binding 	cs35l41->fw_request_ongoing = false;
101147ceabd9SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
101288672826SStefan Binding 
101388672826SStefan Binding 	pm_runtime_mark_last_busy(cs35l41->dev);
101488672826SStefan Binding 	pm_runtime_put_autosuspend(cs35l41->dev);
101547ceabd9SStefan Binding }
101647ceabd9SStefan Binding 
cs35l41_fw_load_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)101747ceabd9SStefan Binding static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
101847ceabd9SStefan Binding 				   struct snd_ctl_elem_value *ucontrol)
101947ceabd9SStefan Binding {
102047ceabd9SStefan Binding 	struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
102147ceabd9SStefan Binding 
102247ceabd9SStefan Binding 	if (cs35l41->request_fw_load == ucontrol->value.integer.value[0])
1023448425f0SStefan Binding 		return 0;
102447ceabd9SStefan Binding 
102547ceabd9SStefan Binding 	if (cs35l41->fw_request_ongoing) {
102647ceabd9SStefan Binding 		dev_dbg(cs35l41->dev, "Existing request not complete\n");
1027448425f0SStefan Binding 		return -EBUSY;
102847ceabd9SStefan Binding 	}
102947ceabd9SStefan Binding 
103047ceabd9SStefan Binding 	/* Check if playback is ongoing when initial request is made */
103147ceabd9SStefan Binding 	if (cs35l41->playback_started) {
103247ceabd9SStefan Binding 		dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
1033448425f0SStefan Binding 		return -EBUSY;
103447ceabd9SStefan Binding 	}
103547ceabd9SStefan Binding 
103647ceabd9SStefan Binding 	cs35l41->fw_request_ongoing = true;
103747ceabd9SStefan Binding 	cs35l41->request_fw_load = ucontrol->value.integer.value[0];
103847ceabd9SStefan Binding 	schedule_work(&cs35l41->fw_load_work);
103947ceabd9SStefan Binding 
1040448425f0SStefan Binding 	return 1;
104147ceabd9SStefan Binding }
104247ceabd9SStefan Binding 
cs35l41_fw_type_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)104347ceabd9SStefan Binding static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol,
104447ceabd9SStefan Binding 				   struct snd_ctl_elem_value *ucontrol)
104547ceabd9SStefan Binding {
104647ceabd9SStefan Binding 	struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
104747ceabd9SStefan Binding 
104847ceabd9SStefan Binding 	ucontrol->value.enumerated.item[0] = cs35l41->firmware_type;
104947ceabd9SStefan Binding 
105047ceabd9SStefan Binding 	return 0;
105147ceabd9SStefan Binding }
105247ceabd9SStefan Binding 
cs35l41_fw_type_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)105347ceabd9SStefan Binding static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
105447ceabd9SStefan Binding 				   struct snd_ctl_elem_value *ucontrol)
105547ceabd9SStefan Binding {
105647ceabd9SStefan Binding 	struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
105747ceabd9SStefan Binding 
105847ceabd9SStefan Binding 	if (ucontrol->value.enumerated.item[0] < HDA_CS_DSP_NUM_FW) {
1059448425f0SStefan Binding 		if (cs35l41->firmware_type != ucontrol->value.enumerated.item[0]) {
106047ceabd9SStefan Binding 			cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
1061448425f0SStefan Binding 			return 1;
1062448425f0SStefan Binding 		} else {
106347ceabd9SStefan Binding 			return 0;
106447ceabd9SStefan Binding 		}
1065448425f0SStefan Binding 	}
106647ceabd9SStefan Binding 
106747ceabd9SStefan Binding 	return -EINVAL;
106847ceabd9SStefan Binding }
106947ceabd9SStefan Binding 
cs35l41_fw_type_ctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)107047ceabd9SStefan Binding static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
107147ceabd9SStefan Binding {
107247ceabd9SStefan Binding 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids);
107347ceabd9SStefan Binding }
107447ceabd9SStefan Binding 
cs35l41_create_controls(struct cs35l41_hda * cs35l41)107547ceabd9SStefan Binding static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
107647ceabd9SStefan Binding {
107747ceabd9SStefan Binding 	char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
107847ceabd9SStefan Binding 	char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
107947ceabd9SStefan Binding 	struct snd_kcontrol_new fw_type_ctl = {
108047ceabd9SStefan Binding 		.name = fw_type_ctl_name,
108147ceabd9SStefan Binding 		.iface = SNDRV_CTL_ELEM_IFACE_CARD,
108247ceabd9SStefan Binding 		.info = cs35l41_fw_type_ctl_info,
108347ceabd9SStefan Binding 		.get = cs35l41_fw_type_ctl_get,
108447ceabd9SStefan Binding 		.put = cs35l41_fw_type_ctl_put,
108547ceabd9SStefan Binding 	};
108647ceabd9SStefan Binding 	struct snd_kcontrol_new fw_load_ctl = {
108747ceabd9SStefan Binding 		.name = fw_load_ctl_name,
108847ceabd9SStefan Binding 		.iface = SNDRV_CTL_ELEM_IFACE_CARD,
108947ceabd9SStefan Binding 		.info = snd_ctl_boolean_mono_info,
109047ceabd9SStefan Binding 		.get = cs35l41_fw_load_ctl_get,
109147ceabd9SStefan Binding 		.put = cs35l41_fw_load_ctl_put,
109247ceabd9SStefan Binding 	};
109347ceabd9SStefan Binding 	int ret;
109447ceabd9SStefan Binding 
109547ceabd9SStefan Binding 	scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type",
109647ceabd9SStefan Binding 		  cs35l41->amp_name);
109747ceabd9SStefan Binding 	scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load",
109847ceabd9SStefan Binding 		  cs35l41->amp_name);
109947ceabd9SStefan Binding 
110047ceabd9SStefan Binding 	ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
110147ceabd9SStefan Binding 	if (ret) {
110247ceabd9SStefan Binding 		dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret);
110347ceabd9SStefan Binding 		return ret;
110447ceabd9SStefan Binding 	}
110547ceabd9SStefan Binding 
110647ceabd9SStefan Binding 	dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name);
110747ceabd9SStefan Binding 
110847ceabd9SStefan Binding 	ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41));
110947ceabd9SStefan Binding 	if (ret) {
111047ceabd9SStefan Binding 		dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret);
111147ceabd9SStefan Binding 		return ret;
111247ceabd9SStefan Binding 	}
111347ceabd9SStefan Binding 
111447ceabd9SStefan Binding 	dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
111547ceabd9SStefan Binding 
111647ceabd9SStefan Binding 	return 0;
111747ceabd9SStefan Binding }
111847ceabd9SStefan Binding 
cs35l41_hda_bind(struct device * dev,struct device * master,void * master_data)11197b2f3eb4SLucas Tanure static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
11207b2f3eb4SLucas Tanure {
11217b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
11227b2f3eb4SLucas Tanure 	struct hda_component *comps = master_data;
11237cf5ce66SStefan Binding 	unsigned int sleep_flags;
112447ceabd9SStefan Binding 	int ret = 0;
11257b2f3eb4SLucas Tanure 
11268c286a0fSLucas Tanure 	if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS)
11277b2f3eb4SLucas Tanure 		return -EINVAL;
11287b2f3eb4SLucas Tanure 
11298c286a0fSLucas Tanure 	comps = &comps[cs35l41->index];
11308c286a0fSLucas Tanure 	if (comps->dev)
11318c286a0fSLucas Tanure 		return -EBUSY;
11328c286a0fSLucas Tanure 
11331873ebd3SStefan Binding 	pm_runtime_get_sync(dev);
11341873ebd3SStefan Binding 
113588672826SStefan Binding 	mutex_lock(&cs35l41->fw_mutex);
113688672826SStefan Binding 
11377b2f3eb4SLucas Tanure 	comps->dev = dev;
1138e99f3c7eSStefan Binding 	if (!cs35l41->acpi_subsystem_id)
11397269734aSAndy Shevchenko 		cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
1140e99f3c7eSStefan Binding 						       comps->codec->core.subsystem_id);
114122d5cbd2SStefan Binding 	cs35l41->codec = comps->codec;
11427b2f3eb4SLucas Tanure 	strscpy(comps->name, dev_name(dev), sizeof(comps->name));
11437b2f3eb4SLucas Tanure 
114447ceabd9SStefan Binding 	cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT;
114547ceabd9SStefan Binding 
1146622f2199SStefan Binding 	if (firmware_autostart) {
1147622f2199SStefan Binding 		dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
114847ceabd9SStefan Binding 		cs35l41->request_fw_load = true;
11492e81e1ffSVitaly Rodionov 		if (cs35l41_smart_amp(cs35l41) < 0)
11502e81e1ffSVitaly Rodionov 			dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n");
1151622f2199SStefan Binding 	} else {
1152622f2199SStefan Binding 		dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n");
1153622f2199SStefan Binding 	}
11542e81e1ffSVitaly Rodionov 
115547ceabd9SStefan Binding 	ret = cs35l41_create_controls(cs35l41);
115647ceabd9SStefan Binding 
11571873ebd3SStefan Binding 	comps->playback_hook = cs35l41_hda_playback_hook;
115801ecc562SStefan Binding 	comps->pre_playback_hook = cs35l41_hda_pre_playback_hook;
115901ecc562SStefan Binding 	comps->post_playback_hook = cs35l41_hda_post_playback_hook;
11601873ebd3SStefan Binding 
116188672826SStefan Binding 	mutex_unlock(&cs35l41->fw_mutex);
116288672826SStefan Binding 
11637cf5ce66SStefan Binding 	sleep_flags = lock_system_sleep();
11647cf5ce66SStefan Binding 	if (!device_link_add(&comps->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
11657cf5ce66SStefan Binding 		dev_warn(dev, "Unable to create device link\n");
11667cf5ce66SStefan Binding 	unlock_system_sleep(sleep_flags);
11677cf5ce66SStefan Binding 
11681873ebd3SStefan Binding 	pm_runtime_mark_last_busy(dev);
11691873ebd3SStefan Binding 	pm_runtime_put_autosuspend(dev);
11701873ebd3SStefan Binding 
1171cfad53a9SStefan Binding 	dev_info(cs35l41->dev,
1172cfad53a9SStefan Binding 		 "CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n",
1173cfad53a9SStefan Binding 		 cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type,
1174cfad53a9SStefan Binding 		 cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH,
1175cfad53a9SStefan Binding 		 cs35l41->hw_cfg.spk_pos ? 'R' : 'L',
1176cfad53a9SStefan Binding 		 cs35l41->firmware_running, cs35l41->speaker_id);
1177cfad53a9SStefan Binding 
117847ceabd9SStefan Binding 	return ret;
11797b2f3eb4SLucas Tanure }
11807b2f3eb4SLucas Tanure 
cs35l41_hda_unbind(struct device * dev,struct device * master,void * master_data)11817b2f3eb4SLucas Tanure static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
11827b2f3eb4SLucas Tanure {
11837b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
11847b2f3eb4SLucas Tanure 	struct hda_component *comps = master_data;
11857cf5ce66SStefan Binding 	unsigned int sleep_flags;
11867b2f3eb4SLucas Tanure 
11877cf5ce66SStefan Binding 	if (comps[cs35l41->index].dev == dev) {
11887b2f3eb4SLucas Tanure 		memset(&comps[cs35l41->index], 0, sizeof(*comps));
11897cf5ce66SStefan Binding 		sleep_flags = lock_system_sleep();
1190*ff27bd8eSSimon Trimmer 		device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
11917cf5ce66SStefan Binding 		unlock_system_sleep(sleep_flags);
11927cf5ce66SStefan Binding 	}
11937b2f3eb4SLucas Tanure }
11947b2f3eb4SLucas Tanure 
11957b2f3eb4SLucas Tanure static const struct component_ops cs35l41_hda_comp_ops = {
11967b2f3eb4SLucas Tanure 	.bind = cs35l41_hda_bind,
11977b2f3eb4SLucas Tanure 	.unbind = cs35l41_hda_unbind,
11987b2f3eb4SLucas Tanure };
11997b2f3eb4SLucas Tanure 
cs35l41_bst_short_err(int irq,void * data)1200aa4a38afSStefan Binding static irqreturn_t cs35l41_bst_short_err(int irq, void *data)
1201aa4a38afSStefan Binding {
1202aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1203aa4a38afSStefan Binding 
1204aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "LBST Error\n");
1205aa4a38afSStefan Binding 	set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1206aa4a38afSStefan Binding 
1207aa4a38afSStefan Binding 	return IRQ_HANDLED;
1208aa4a38afSStefan Binding }
1209aa4a38afSStefan Binding 
cs35l41_bst_dcm_uvp_err(int irq,void * data)1210aa4a38afSStefan Binding static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data)
1211aa4a38afSStefan Binding {
1212aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1213aa4a38afSStefan Binding 
1214aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n");
1215aa4a38afSStefan Binding 	set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1216aa4a38afSStefan Binding 
1217aa4a38afSStefan Binding 	return IRQ_HANDLED;
1218aa4a38afSStefan Binding }
1219aa4a38afSStefan Binding 
cs35l41_bst_ovp_err(int irq,void * data)1220aa4a38afSStefan Binding static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data)
1221aa4a38afSStefan Binding {
1222aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1223aa4a38afSStefan Binding 
1224aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n");
1225aa4a38afSStefan Binding 	set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1226aa4a38afSStefan Binding 
1227aa4a38afSStefan Binding 	return IRQ_HANDLED;
1228aa4a38afSStefan Binding }
1229aa4a38afSStefan Binding 
cs35l41_temp_err(int irq,void * data)1230aa4a38afSStefan Binding static irqreturn_t cs35l41_temp_err(int irq, void *data)
1231aa4a38afSStefan Binding {
1232aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1233aa4a38afSStefan Binding 
1234aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n");
1235aa4a38afSStefan Binding 	set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1236aa4a38afSStefan Binding 
1237aa4a38afSStefan Binding 	return IRQ_HANDLED;
1238aa4a38afSStefan Binding }
1239aa4a38afSStefan Binding 
cs35l41_temp_warn(int irq,void * data)1240aa4a38afSStefan Binding static irqreturn_t cs35l41_temp_warn(int irq, void *data)
1241aa4a38afSStefan Binding {
1242aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1243aa4a38afSStefan Binding 
1244aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n");
1245aa4a38afSStefan Binding 	set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1246aa4a38afSStefan Binding 
1247aa4a38afSStefan Binding 	return IRQ_HANDLED;
1248aa4a38afSStefan Binding }
1249aa4a38afSStefan Binding 
cs35l41_amp_short(int irq,void * data)1250aa4a38afSStefan Binding static irqreturn_t cs35l41_amp_short(int irq, void *data)
1251aa4a38afSStefan Binding {
1252aa4a38afSStefan Binding 	struct cs35l41_hda *cs35l41 = data;
1253aa4a38afSStefan Binding 
1254aa4a38afSStefan Binding 	dev_crit_ratelimited(cs35l41->dev, "Amp short error\n");
1255aa4a38afSStefan Binding 	set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
1256aa4a38afSStefan Binding 
1257aa4a38afSStefan Binding 	return IRQ_HANDLED;
1258aa4a38afSStefan Binding }
1259aa4a38afSStefan Binding 
1260aa4a38afSStefan Binding static const struct cs35l41_irq cs35l41_irqs[] = {
1261aa4a38afSStefan Binding 	CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err),
1262aa4a38afSStefan Binding 	CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err),
1263aa4a38afSStefan Binding 	CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err),
1264aa4a38afSStefan Binding 	CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn),
1265aa4a38afSStefan Binding 	CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err),
1266aa4a38afSStefan Binding 	CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short),
1267aa4a38afSStefan Binding };
1268aa4a38afSStefan Binding 
1269aa4a38afSStefan Binding static const struct regmap_irq cs35l41_reg_irqs[] = {
1270aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR),
1271aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR),
1272aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR),
1273aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN),
1274aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR),
1275aa4a38afSStefan Binding 	CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
1276aa4a38afSStefan Binding };
1277aa4a38afSStefan Binding 
12781873ebd3SStefan Binding static struct regmap_irq_chip cs35l41_regmap_irq_chip = {
1279aa4a38afSStefan Binding 	.name = "cs35l41 IRQ1 Controller",
1280aa4a38afSStefan Binding 	.status_base = CS35L41_IRQ1_STATUS1,
1281aa4a38afSStefan Binding 	.mask_base = CS35L41_IRQ1_MASK1,
1282aa4a38afSStefan Binding 	.ack_base = CS35L41_IRQ1_STATUS1,
1283aa4a38afSStefan Binding 	.num_regs = 4,
1284aa4a38afSStefan Binding 	.irqs = cs35l41_reg_irqs,
1285aa4a38afSStefan Binding 	.num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
12861873ebd3SStefan Binding 	.runtime_pm = true,
1287aa4a38afSStefan Binding };
1288aa4a38afSStefan Binding 
cs35l41_hda_apply_properties(struct cs35l41_hda * cs35l41)1289f7f20737SLucas Tanure static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
12907b2f3eb4SLucas Tanure {
1291f7f20737SLucas Tanure 	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
1292aa4a38afSStefan Binding 	bool using_irq = false;
1293aa4a38afSStefan Binding 	int irq, irq_pol;
12947b2f3eb4SLucas Tanure 	int ret;
1295aa4a38afSStefan Binding 	int i;
12967b2f3eb4SLucas Tanure 
12972603c974SLucas Tanure 	if (!cs35l41->hw_cfg.valid)
12982603c974SLucas Tanure 		return -EINVAL;
12992603c974SLucas Tanure 
13005577dd23SLucas Tanure 	ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
1301b8388a1aSLucas Tanure 	if (ret)
1302b8388a1aSLucas Tanure 		return ret;
13037b2f3eb4SLucas Tanure 
13042603c974SLucas Tanure 	if (hw_cfg->gpio1.valid) {
1305f7f20737SLucas Tanure 		switch (hw_cfg->gpio1.func) {
1306cd8abf7dSLucas Tanure 		case CS35L41_NOT_USED:
1307cd8abf7dSLucas Tanure 			break;
13087b2f3eb4SLucas Tanure 		case CS35l41_VSPK_SWITCH:
1309fcad8950SLucas Tanure 			hw_cfg->gpio1.func = CS35L41_GPIO1_GPIO;
1310fcad8950SLucas Tanure 			hw_cfg->gpio1.out_en = true;
13117b2f3eb4SLucas Tanure 			break;
13127b2f3eb4SLucas Tanure 		case CS35l41_SYNC:
1313fcad8950SLucas Tanure 			hw_cfg->gpio1.func = CS35L41_GPIO1_MDSYNC;
13147b2f3eb4SLucas Tanure 			break;
1315cd8abf7dSLucas Tanure 		default:
13162603c974SLucas Tanure 			dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n",
13172603c974SLucas Tanure 				hw_cfg->gpio1.func);
1318cd8abf7dSLucas Tanure 			return -EINVAL;
13197b2f3eb4SLucas Tanure 		}
13202603c974SLucas Tanure 	}
13217b2f3eb4SLucas Tanure 
13222603c974SLucas Tanure 	if (hw_cfg->gpio2.valid) {
1323f7f20737SLucas Tanure 		switch (hw_cfg->gpio2.func) {
1324cd8abf7dSLucas Tanure 		case CS35L41_NOT_USED:
1325cd8abf7dSLucas Tanure 			break;
13267b2f3eb4SLucas Tanure 		case CS35L41_INTERRUPT:
1327aa4a38afSStefan Binding 			using_irq = true;
1328f81ee579SLucas Tanure 			hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
13297b2f3eb4SLucas Tanure 			break;
1330cd8abf7dSLucas Tanure 		default:
13312603c974SLucas Tanure 			dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
1332cd8abf7dSLucas Tanure 			return -EINVAL;
13337b2f3eb4SLucas Tanure 		}
13342603c974SLucas Tanure 	}
13357b2f3eb4SLucas Tanure 
1336aa4a38afSStefan Binding 	irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
1337aa4a38afSStefan Binding 
1338aa4a38afSStefan Binding 	if (cs35l41->irq && using_irq) {
1339aa4a38afSStefan Binding 		ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
1340aa4a38afSStefan Binding 					       IRQF_ONESHOT | IRQF_SHARED | irq_pol,
1341aa4a38afSStefan Binding 					       0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
1342aa4a38afSStefan Binding 		if (ret)
1343aa4a38afSStefan Binding 			return ret;
1344aa4a38afSStefan Binding 
1345aa4a38afSStefan Binding 		for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
1346aa4a38afSStefan Binding 			irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
1347aa4a38afSStefan Binding 			if (irq < 0)
1348aa4a38afSStefan Binding 				return irq;
1349aa4a38afSStefan Binding 
1350aa4a38afSStefan Binding 			ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
1351aa4a38afSStefan Binding 							cs35l41_irqs[i].handler,
1352aa4a38afSStefan Binding 							IRQF_ONESHOT | IRQF_SHARED | irq_pol,
1353aa4a38afSStefan Binding 							cs35l41_irqs[i].name, cs35l41);
1354aa4a38afSStefan Binding 			if (ret)
1355aa4a38afSStefan Binding 				return ret;
1356aa4a38afSStefan Binding 		}
1357aa4a38afSStefan Binding 	}
1358fcad8950SLucas Tanure 
1359f7f20737SLucas Tanure 	return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
13607b2f3eb4SLucas Tanure }
13617b2f3eb4SLucas Tanure 
cs35l41_get_speaker_id(struct device * dev,int amp_index,int num_amps,int fixed_gpio_id)1362ef4ba63fSStefan Binding int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)
136363f4b99fSStefan Binding {
136463f4b99fSStefan Binding 	struct gpio_desc *speaker_id_desc;
136563f4b99fSStefan Binding 	int speaker_id = -ENODEV;
136663f4b99fSStefan Binding 
136763f4b99fSStefan Binding 	if (fixed_gpio_id >= 0) {
136863f4b99fSStefan Binding 		dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
136963f4b99fSStefan Binding 		speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
137063f4b99fSStefan Binding 		if (IS_ERR(speaker_id_desc)) {
137163f4b99fSStefan Binding 			speaker_id = PTR_ERR(speaker_id_desc);
137263f4b99fSStefan Binding 			return speaker_id;
137363f4b99fSStefan Binding 		}
137463f4b99fSStefan Binding 		speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
137563f4b99fSStefan Binding 		gpiod_put(speaker_id_desc);
137663f4b99fSStefan Binding 		dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
137763f4b99fSStefan Binding 	} else {
137863f4b99fSStefan Binding 		int base_index;
137963f4b99fSStefan Binding 		int gpios_per_amp;
138063f4b99fSStefan Binding 		int count;
138163f4b99fSStefan Binding 		int tmp;
138263f4b99fSStefan Binding 		int i;
138363f4b99fSStefan Binding 
138463f4b99fSStefan Binding 		count = gpiod_count(dev, "spk-id");
138563f4b99fSStefan Binding 		if (count > 0) {
138663f4b99fSStefan Binding 			speaker_id = 0;
138763f4b99fSStefan Binding 			gpios_per_amp = count / num_amps;
138863f4b99fSStefan Binding 			base_index = gpios_per_amp * amp_index;
138963f4b99fSStefan Binding 
139063f4b99fSStefan Binding 			if (count % num_amps)
139163f4b99fSStefan Binding 				return -EINVAL;
139263f4b99fSStefan Binding 
139363f4b99fSStefan Binding 			dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
139463f4b99fSStefan Binding 
139563f4b99fSStefan Binding 			for (i = 0; i < gpios_per_amp; i++) {
139663f4b99fSStefan Binding 				speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
139763f4b99fSStefan Binding 								  GPIOD_IN);
139863f4b99fSStefan Binding 				if (IS_ERR(speaker_id_desc)) {
139963f4b99fSStefan Binding 					speaker_id = PTR_ERR(speaker_id_desc);
140063f4b99fSStefan Binding 					break;
140163f4b99fSStefan Binding 				}
140263f4b99fSStefan Binding 				tmp = gpiod_get_value_cansleep(speaker_id_desc);
140363f4b99fSStefan Binding 				gpiod_put(speaker_id_desc);
140463f4b99fSStefan Binding 				if (tmp < 0) {
140563f4b99fSStefan Binding 					speaker_id = tmp;
140663f4b99fSStefan Binding 					break;
140763f4b99fSStefan Binding 				}
140863f4b99fSStefan Binding 				speaker_id |= tmp << i;
140963f4b99fSStefan Binding 			}
141063f4b99fSStefan Binding 			dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
141163f4b99fSStefan Binding 		}
141263f4b99fSStefan Binding 	}
141363f4b99fSStefan Binding 	return speaker_id;
141463f4b99fSStefan Binding }
141563f4b99fSStefan Binding 
cs35l41_hda_read_acpi(struct cs35l41_hda * cs35l41,const char * hid,int id)1416f7f20737SLucas Tanure static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
14177b2f3eb4SLucas Tanure {
1418f7f20737SLucas Tanure 	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
14197b2f3eb4SLucas Tanure 	u32 values[HDA_MAX_COMPONENTS];
14207b2f3eb4SLucas Tanure 	struct acpi_device *adev;
14218c286a0fSLucas Tanure 	struct device *physdev;
14227269734aSAndy Shevchenko 	const char *sub;
14237b2f3eb4SLucas Tanure 	char *property;
14247b2f3eb4SLucas Tanure 	size_t nval;
14257b2f3eb4SLucas Tanure 	int i, ret;
14267b2f3eb4SLucas Tanure 
14277b2f3eb4SLucas Tanure 	adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
14287b2f3eb4SLucas Tanure 	if (!adev) {
14297b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
1430f7f20737SLucas Tanure 		return -ENODEV;
14317b2f3eb4SLucas Tanure 	}
14327b2f3eb4SLucas Tanure 
14338c286a0fSLucas Tanure 	physdev = get_device(acpi_get_first_physical_node(adev));
14347b2f3eb4SLucas Tanure 	acpi_dev_put(adev);
14357b2f3eb4SLucas Tanure 
14367269734aSAndy Shevchenko 	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
14377269734aSAndy Shevchenko 	if (IS_ERR(sub))
14387269734aSAndy Shevchenko 		sub = NULL;
14397269734aSAndy Shevchenko 	cs35l41->acpi_subsystem_id = sub;
1440eef37596SStefan Binding 
1441ef4ba63fSStefan Binding 	ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
1442ef4ba63fSStefan Binding 	if (!ret) {
1443ef4ba63fSStefan Binding 		dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
1444ef4ba63fSStefan Binding 		goto put_physdev;
1445ef4ba63fSStefan Binding 	}
1446ef4ba63fSStefan Binding 
14477b2f3eb4SLucas Tanure 	property = "cirrus,dev-index";
14488c286a0fSLucas Tanure 	ret = device_property_count_u32(physdev, property);
1449ef4ba63fSStefan Binding 	if (ret <= 0)
1450ef4ba63fSStefan Binding 		goto err;
1451ef4ba63fSStefan Binding 
14527b2f3eb4SLucas Tanure 	if (ret > ARRAY_SIZE(values)) {
14537b2f3eb4SLucas Tanure 		ret = -EINVAL;
14547b2f3eb4SLucas Tanure 		goto err;
14557b2f3eb4SLucas Tanure 	}
14567b2f3eb4SLucas Tanure 	nval = ret;
14577b2f3eb4SLucas Tanure 
14588c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
14597b2f3eb4SLucas Tanure 	if (ret)
14607b2f3eb4SLucas Tanure 		goto err;
14617b2f3eb4SLucas Tanure 
14627b2f3eb4SLucas Tanure 	cs35l41->index = -1;
14637b2f3eb4SLucas Tanure 	for (i = 0; i < nval; i++) {
14647b2f3eb4SLucas Tanure 		if (values[i] == id) {
14657b2f3eb4SLucas Tanure 			cs35l41->index = i;
14667b2f3eb4SLucas Tanure 			break;
14677b2f3eb4SLucas Tanure 		}
14687b2f3eb4SLucas Tanure 	}
14697b2f3eb4SLucas Tanure 	if (cs35l41->index == -1) {
14707b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "No index found in %s\n", property);
14717b2f3eb4SLucas Tanure 		ret = -ENODEV;
14727b2f3eb4SLucas Tanure 		goto err;
14737b2f3eb4SLucas Tanure 	}
14747b2f3eb4SLucas Tanure 
14758c286a0fSLucas Tanure 	/* To use the same release code for all laptop variants we can't use devm_ version of
14768c286a0fSLucas Tanure 	 * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
14778c286a0fSLucas Tanure 	 */
147820bcf721SAndy Shevchenko 	cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index,
14797b2f3eb4SLucas Tanure 						     GPIOD_OUT_LOW, "cs35l41-reset");
14807b2f3eb4SLucas Tanure 
14817b2f3eb4SLucas Tanure 	property = "cirrus,speaker-position";
14828c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
14837b2f3eb4SLucas Tanure 	if (ret)
1484f7f20737SLucas Tanure 		goto err;
14857b2f3eb4SLucas Tanure 	hw_cfg->spk_pos = values[cs35l41->index];
14867b2f3eb4SLucas Tanure 
148700f87ec7SStefan Binding 	cs35l41->channel_index = 0;
148800f87ec7SStefan Binding 	for (i = 0; i < cs35l41->index; i++)
148900f87ec7SStefan Binding 		if (values[i] == hw_cfg->spk_pos)
149000f87ec7SStefan Binding 			cs35l41->channel_index++;
149100f87ec7SStefan Binding 
14927b2f3eb4SLucas Tanure 	property = "cirrus,gpio1-func";
14938c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
14947b2f3eb4SLucas Tanure 	if (ret)
1495f7f20737SLucas Tanure 		goto err;
1496f7f20737SLucas Tanure 	hw_cfg->gpio1.func = values[cs35l41->index];
14972603c974SLucas Tanure 	hw_cfg->gpio1.valid = true;
14987b2f3eb4SLucas Tanure 
14997b2f3eb4SLucas Tanure 	property = "cirrus,gpio2-func";
15008c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
15017b2f3eb4SLucas Tanure 	if (ret)
1502f7f20737SLucas Tanure 		goto err;
1503f7f20737SLucas Tanure 	hw_cfg->gpio2.func = values[cs35l41->index];
15042603c974SLucas Tanure 	hw_cfg->gpio2.valid = true;
15057b2f3eb4SLucas Tanure 
15067b2f3eb4SLucas Tanure 	property = "cirrus,boost-peak-milliamp";
15078c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
15087b2f3eb4SLucas Tanure 	if (ret == 0)
15097b2f3eb4SLucas Tanure 		hw_cfg->bst_ipk = values[cs35l41->index];
15102603c974SLucas Tanure 	else
15112603c974SLucas Tanure 		hw_cfg->bst_ipk = -1;
15127b2f3eb4SLucas Tanure 
15137b2f3eb4SLucas Tanure 	property = "cirrus,boost-ind-nanohenry";
15148c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
15157b2f3eb4SLucas Tanure 	if (ret == 0)
15167b2f3eb4SLucas Tanure 		hw_cfg->bst_ind = values[cs35l41->index];
15172603c974SLucas Tanure 	else
15182603c974SLucas Tanure 		hw_cfg->bst_ind = -1;
15197b2f3eb4SLucas Tanure 
15207b2f3eb4SLucas Tanure 	property = "cirrus,boost-cap-microfarad";
15218c286a0fSLucas Tanure 	ret = device_property_read_u32_array(physdev, property, values, nval);
15227b2f3eb4SLucas Tanure 	if (ret == 0)
15237b2f3eb4SLucas Tanure 		hw_cfg->bst_cap = values[cs35l41->index];
15242603c974SLucas Tanure 	else
15252603c974SLucas Tanure 		hw_cfg->bst_cap = -1;
15267b2f3eb4SLucas Tanure 
152763f4b99fSStefan Binding 	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
152863f4b99fSStefan Binding 
1529b8388a1aSLucas Tanure 	if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
1530b8388a1aSLucas Tanure 		hw_cfg->bst_type = CS35L41_INT_BOOST;
1531b8388a1aSLucas Tanure 	else
1532b8388a1aSLucas Tanure 		hw_cfg->bst_type = CS35L41_EXT_BOOST;
1533b8388a1aSLucas Tanure 
15342603c974SLucas Tanure 	hw_cfg->valid = true;
15358c286a0fSLucas Tanure 	put_device(physdev);
15367b2f3eb4SLucas Tanure 
1537f7f20737SLucas Tanure 	return 0;
15387b2f3eb4SLucas Tanure 
15397b2f3eb4SLucas Tanure err:
15407b2f3eb4SLucas Tanure 	dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
1541ef4ba63fSStefan Binding 	hw_cfg->valid = false;
1542ef4ba63fSStefan Binding 	hw_cfg->gpio1.valid = false;
1543ef4ba63fSStefan Binding 	hw_cfg->gpio2.valid = false;
1544ef4ba63fSStefan Binding put_physdev:
1545aca289f7SAndy Shevchenko 	put_device(physdev);
15467b2f3eb4SLucas Tanure 
1547f7f20737SLucas Tanure 	return ret;
15487b2f3eb4SLucas Tanure }
15497b2f3eb4SLucas Tanure 
cs35l41_hda_probe(struct device * dev,const char * device_name,int id,int irq,struct regmap * regmap)15507b2f3eb4SLucas Tanure int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
15517b2f3eb4SLucas Tanure 		      struct regmap *regmap)
15527b2f3eb4SLucas Tanure {
15537b2f3eb4SLucas Tanure 	unsigned int int_sts, regid, reg_revid, mtl_revid, chipid, int_status;
15547b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41;
15557b2f3eb4SLucas Tanure 	int ret;
15567b2f3eb4SLucas Tanure 
1557aa4a38afSStefan Binding 	BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs));
1558aa4a38afSStefan Binding 	BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ);
1559aa4a38afSStefan Binding 
15607b2f3eb4SLucas Tanure 	if (IS_ERR(regmap))
15617b2f3eb4SLucas Tanure 		return PTR_ERR(regmap);
15627b2f3eb4SLucas Tanure 
15637b2f3eb4SLucas Tanure 	cs35l41 = devm_kzalloc(dev, sizeof(*cs35l41), GFP_KERNEL);
15647b2f3eb4SLucas Tanure 	if (!cs35l41)
15657b2f3eb4SLucas Tanure 		return -ENOMEM;
15667b2f3eb4SLucas Tanure 
15677b2f3eb4SLucas Tanure 	cs35l41->dev = dev;
15687b2f3eb4SLucas Tanure 	cs35l41->irq = irq;
15697b2f3eb4SLucas Tanure 	cs35l41->regmap = regmap;
15707b2f3eb4SLucas Tanure 	dev_set_drvdata(dev, cs35l41);
15717b2f3eb4SLucas Tanure 
1572f7f20737SLucas Tanure 	ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
1573e35cd688SAndy Shevchenko 	if (ret)
1574e35cd688SAndy Shevchenko 		return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
15757b2f3eb4SLucas Tanure 
15767b2f3eb4SLucas Tanure 	if (IS_ERR(cs35l41->reset_gpio)) {
15777b2f3eb4SLucas Tanure 		ret = PTR_ERR(cs35l41->reset_gpio);
15787b2f3eb4SLucas Tanure 		cs35l41->reset_gpio = NULL;
15797b2f3eb4SLucas Tanure 		if (ret == -EBUSY) {
15807b2f3eb4SLucas Tanure 			dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n");
15817b2f3eb4SLucas Tanure 		} else {
1582e35cd688SAndy Shevchenko 			dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO\n");
15837b2f3eb4SLucas Tanure 			goto err;
15847b2f3eb4SLucas Tanure 		}
15857b2f3eb4SLucas Tanure 	}
15867b2f3eb4SLucas Tanure 	if (cs35l41->reset_gpio) {
15877b2f3eb4SLucas Tanure 		usleep_range(2000, 2100);
15887b2f3eb4SLucas Tanure 		gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
15897b2f3eb4SLucas Tanure 	}
15907b2f3eb4SLucas Tanure 
15917b2f3eb4SLucas Tanure 	usleep_range(2000, 2100);
15927b2f3eb4SLucas Tanure 
15937b2f3eb4SLucas Tanure 	ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
15947b2f3eb4SLucas Tanure 				       int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
15957b2f3eb4SLucas Tanure 	if (ret) {
15967b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE: %d\n", ret);
15977b2f3eb4SLucas Tanure 		goto err;
15987b2f3eb4SLucas Tanure 	}
15997b2f3eb4SLucas Tanure 
16007b2f3eb4SLucas Tanure 	ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_sts);
16017b2f3eb4SLucas Tanure 	if (ret || (int_sts & CS35L41_OTP_BOOT_ERR)) {
16028c286a0fSLucas Tanure 		dev_err(cs35l41->dev, "OTP Boot status %x error: %d\n",
16038c286a0fSLucas Tanure 			int_sts & CS35L41_OTP_BOOT_ERR, ret);
16047b2f3eb4SLucas Tanure 		ret = -EIO;
16057b2f3eb4SLucas Tanure 		goto err;
16067b2f3eb4SLucas Tanure 	}
16077b2f3eb4SLucas Tanure 
16087b2f3eb4SLucas Tanure 	ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
16097b2f3eb4SLucas Tanure 	if (ret) {
16107b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret);
16117b2f3eb4SLucas Tanure 		goto err;
16127b2f3eb4SLucas Tanure 	}
16137b2f3eb4SLucas Tanure 
16147b2f3eb4SLucas Tanure 	ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
16157b2f3eb4SLucas Tanure 	if (ret) {
16167b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret);
16177b2f3eb4SLucas Tanure 		goto err;
16187b2f3eb4SLucas Tanure 	}
16197b2f3eb4SLucas Tanure 
16207b2f3eb4SLucas Tanure 	mtl_revid = reg_revid & CS35L41_MTLREVID_MASK;
16217b2f3eb4SLucas Tanure 
16227b2f3eb4SLucas Tanure 	chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
16237b2f3eb4SLucas Tanure 	if (regid != chipid) {
16247b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", regid, chipid);
16257b2f3eb4SLucas Tanure 		ret = -ENODEV;
16267b2f3eb4SLucas Tanure 		goto err;
16277b2f3eb4SLucas Tanure 	}
16287b2f3eb4SLucas Tanure 
16296e4320d8SCharles Keepax 	ret = cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
16306e4320d8SCharles Keepax 	if (ret)
16316e4320d8SCharles Keepax 		goto err;
16326e4320d8SCharles Keepax 
16337b2f3eb4SLucas Tanure 	ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
16347b2f3eb4SLucas Tanure 	if (ret)
16357b2f3eb4SLucas Tanure 		goto err;
16367b2f3eb4SLucas Tanure 
16377b2f3eb4SLucas Tanure 	ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
16387b2f3eb4SLucas Tanure 	if (ret) {
16397b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
16407b2f3eb4SLucas Tanure 		goto err;
16417b2f3eb4SLucas Tanure 	}
16427b2f3eb4SLucas Tanure 
16436e4320d8SCharles Keepax 	ret = cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
16446e4320d8SCharles Keepax 	if (ret)
16456e4320d8SCharles Keepax 		goto err;
16466e4320d8SCharles Keepax 
16472d816d4fSStefan Binding 	ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute,
16482d816d4fSStefan Binding 				     ARRAY_SIZE(cs35l41_hda_mute));
16492d816d4fSStefan Binding 	if (ret)
16502d816d4fSStefan Binding 		goto err;
16512d816d4fSStefan Binding 
165247ceabd9SStefan Binding 	INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work);
16532e81e1ffSVitaly Rodionov 	mutex_init(&cs35l41->fw_mutex);
16542e81e1ffSVitaly Rodionov 
16551873ebd3SStefan Binding 	pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
16561873ebd3SStefan Binding 	pm_runtime_use_autosuspend(cs35l41->dev);
16571873ebd3SStefan Binding 	pm_runtime_mark_last_busy(cs35l41->dev);
16581873ebd3SStefan Binding 	pm_runtime_set_active(cs35l41->dev);
16591873ebd3SStefan Binding 	pm_runtime_get_noresume(cs35l41->dev);
16601873ebd3SStefan Binding 	pm_runtime_enable(cs35l41->dev);
16611873ebd3SStefan Binding 
1662f7f20737SLucas Tanure 	ret = cs35l41_hda_apply_properties(cs35l41);
16637b2f3eb4SLucas Tanure 	if (ret)
16641873ebd3SStefan Binding 		goto err_pm;
16651873ebd3SStefan Binding 
16661873ebd3SStefan Binding 	pm_runtime_put_autosuspend(cs35l41->dev);
16677b2f3eb4SLucas Tanure 
16687b2f3eb4SLucas Tanure 	ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
16697b2f3eb4SLucas Tanure 	if (ret) {
16707b2f3eb4SLucas Tanure 		dev_err(cs35l41->dev, "Register component failed: %d\n", ret);
1671d3af600cSCristian Ciocaltea 		goto err_pm;
16727b2f3eb4SLucas Tanure 	}
16737b2f3eb4SLucas Tanure 
16747b2f3eb4SLucas Tanure 	dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
16757b2f3eb4SLucas Tanure 
16767b2f3eb4SLucas Tanure 	return 0;
16777b2f3eb4SLucas Tanure 
16781873ebd3SStefan Binding err_pm:
1679e7ba68a6SCristian Ciocaltea 	pm_runtime_dont_use_autosuspend(cs35l41->dev);
16801873ebd3SStefan Binding 	pm_runtime_disable(cs35l41->dev);
16811873ebd3SStefan Binding 	pm_runtime_put_noidle(cs35l41->dev);
16821873ebd3SStefan Binding 
16837b2f3eb4SLucas Tanure err:
16845577dd23SLucas Tanure 	if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
16857b2f3eb4SLucas Tanure 		gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
16867b2f3eb4SLucas Tanure 	gpiod_put(cs35l41->reset_gpio);
16877269734aSAndy Shevchenko 	kfree(cs35l41->acpi_subsystem_id);
16887b2f3eb4SLucas Tanure 
16897b2f3eb4SLucas Tanure 	return ret;
16907b2f3eb4SLucas Tanure }
169177dc3a6eSLucas Tanure EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, SND_HDA_SCODEC_CS35L41);
16927b2f3eb4SLucas Tanure 
cs35l41_hda_remove(struct device * dev)169385c25662SUwe Kleine-König void cs35l41_hda_remove(struct device *dev)
16947b2f3eb4SLucas Tanure {
16957b2f3eb4SLucas Tanure 	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
16967b2f3eb4SLucas Tanure 
16971873ebd3SStefan Binding 	pm_runtime_get_sync(cs35l41->dev);
1698e7ba68a6SCristian Ciocaltea 	pm_runtime_dont_use_autosuspend(cs35l41->dev);
16991873ebd3SStefan Binding 	pm_runtime_disable(cs35l41->dev);
17001873ebd3SStefan Binding 
17012e81e1ffSVitaly Rodionov 	if (cs35l41->halo_initialized)
17022e81e1ffSVitaly Rodionov 		cs35l41_remove_dsp(cs35l41);
17032e81e1ffSVitaly Rodionov 
17047b2f3eb4SLucas Tanure 	component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
17057b2f3eb4SLucas Tanure 
17061873ebd3SStefan Binding 	pm_runtime_put_noidle(cs35l41->dev);
17071873ebd3SStefan Binding 
17085577dd23SLucas Tanure 	if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
17097b2f3eb4SLucas Tanure 		gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
17107b2f3eb4SLucas Tanure 	gpiod_put(cs35l41->reset_gpio);
17117269734aSAndy Shevchenko 	kfree(cs35l41->acpi_subsystem_id);
17127b2f3eb4SLucas Tanure }
171377dc3a6eSLucas Tanure EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
17147b2f3eb4SLucas Tanure 
17151873ebd3SStefan Binding const struct dev_pm_ops cs35l41_hda_pm_ops = {
1716ae50e2abSTakashi Iwai 	RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
1717ae50e2abSTakashi Iwai 		       cs35l41_runtime_idle)
1718c4d0510bSStefan Binding 	.prepare = cs35l41_system_suspend_prep,
171988672826SStefan Binding 	SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
17201873ebd3SStefan Binding };
17211873ebd3SStefan Binding EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
17221873ebd3SStefan Binding 
17237b2f3eb4SLucas Tanure MODULE_DESCRIPTION("CS35L41 HDA Driver");
17242e81e1ffSVitaly Rodionov MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
17257b2f3eb4SLucas Tanure MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
17267b2f3eb4SLucas Tanure MODULE_LICENSE("GPL");
1727e57d904aSRichard Fitzgerald MODULE_IMPORT_NS(FW_CS_DSP);
1728