blob: 1a3f84599cb584331f9766ca6bd5b00bacaa580d [file] [log] [blame]
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001// SPDX-License-Identifier: GPL-2.0-only
2//
3// HDA audio driver for Cirrus Logic CS35L56 smart amp
4//
5// Copyright (C) 2023 Cirrus Logic, Inc. and
6// Cirrus Logic International Semiconductor Ltd.
7//
8
9#include <linux/acpi.h>
10#include <linux/debugfs.h>
11#include <linux/gpio/consumer.h>
12#include <linux/module.h>
13#include <linux/pm_runtime.h>
14#include <linux/regmap.h>
15#include <linux/slab.h>
16#include <sound/core.h>
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +000017#include <sound/cs-amp-lib.h>
Simon Trimmer73cfbfa2023-07-21 14:21:20 +010018#include <sound/hda_codec.h>
19#include <sound/tlv.h>
Richard Fitzgerald6f03b442023-09-18 10:51:28 +010020#include "cirrus_scodec.h"
Simon Trimmer73cfbfa2023-07-21 14:21:20 +010021#include "cs35l56_hda.h"
22#include "hda_component.h"
23#include "hda_cs_dsp_ctl.h"
24#include "hda_generic.h"
25
26 /*
27 * The cs35l56_hda_dai_config[] reg sequence configures the device as
28 * ASP1_BCLK_FREQ = 3.072 MHz
29 * ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S
30 * ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots
31 * ASP1_RX_WL = 24 bits per sample
32 * ASP1_TX_WL = 24 bits per sample
33 * ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
Richard Fitzgerald856ce892024-01-29 16:27:28 +000034 *
35 * Override any Windows-specific mixer settings applied by the firmware.
Simon Trimmer73cfbfa2023-07-21 14:21:20 +010036 */
37static const struct reg_sequence cs35l56_hda_dai_config[] = {
38 { CS35L56_ASP1_CONTROL1, 0x00000021 },
39 { CS35L56_ASP1_CONTROL2, 0x20200200 },
40 { CS35L56_ASP1_CONTROL3, 0x00000003 },
Richard Fitzgerald856ce892024-01-29 16:27:28 +000041 { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
42 { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
Simon Trimmer73cfbfa2023-07-21 14:21:20 +010043 { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
44 { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
45 { CS35L56_ASP1_ENABLES1, 0x00000000 },
Richard Fitzgerald856ce892024-01-29 16:27:28 +000046 { CS35L56_ASP1TX1_INPUT, 0x00000018 },
47 { CS35L56_ASP1TX2_INPUT, 0x00000019 },
48 { CS35L56_ASP1TX3_INPUT, 0x00000020 },
49 { CS35L56_ASP1TX4_INPUT, 0x00000028 },
50
Simon Trimmer73cfbfa2023-07-21 14:21:20 +010051};
52
53static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
54{
55 unsigned int val;
56 int ret;
57
58 pm_runtime_get_sync(cs35l56->base.dev);
59 ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
60 if (ret == 0) {
61 /* Wait for firmware to enter PS0 power state */
62 ret = regmap_read_poll_timeout(cs35l56->base.regmap,
63 CS35L56_TRANSDUCER_ACTUAL_PS,
64 val, (val == CS35L56_PS0),
65 CS35L56_PS0_POLL_US,
66 CS35L56_PS0_TIMEOUT_US);
67 if (ret)
68 dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
69 }
70 regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
71 BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
72 cs35l56->asp_tx_mask);
73 cs35l56->playing = true;
74}
75
76static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)
77{
78 cs35l56->playing = false;
79 cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
80 regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
81 BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
82 BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |
83 BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));
84
85 pm_runtime_mark_last_busy(cs35l56->base.dev);
86 pm_runtime_put_autosuspend(cs35l56->base.dev);
87}
88
89static void cs35l56_hda_playback_hook(struct device *dev, int action)
90{
91 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
92
93 dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);
94
95 switch (action) {
96 case HDA_GEN_PCM_ACT_PREPARE:
97 if (cs35l56->playing)
98 break;
99
100 /* If we're suspended: flag that resume should start playback */
101 if (cs35l56->suspended) {
102 cs35l56->playing = true;
103 break;
104 }
105
106 cs35l56_hda_play(cs35l56);
107 break;
108 case HDA_GEN_PCM_ACT_CLEANUP:
109 if (!cs35l56->playing)
110 break;
111
112 cs35l56_hda_pause(cs35l56);
113 break;
114 default:
115 break;
116 }
117}
118
Richard Fitzgeralddeff8482023-09-19 09:11:53 +0100119static int cs35l56_hda_runtime_suspend(struct device *dev)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100120{
121 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
122
123 if (cs35l56->cs_dsp.booted)
124 cs_dsp_stop(&cs35l56->cs_dsp);
125
126 return cs35l56_runtime_suspend_common(&cs35l56->base);
127}
128
Richard Fitzgeralddeff8482023-09-19 09:11:53 +0100129static int cs35l56_hda_runtime_resume(struct device *dev)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100130{
131 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
132 int ret;
133
134 ret = cs35l56_runtime_resume_common(&cs35l56->base, false);
135 if (ret < 0)
136 return ret;
137
138 if (cs35l56->cs_dsp.booted) {
139 ret = cs_dsp_run(&cs35l56->cs_dsp);
140 if (ret) {
141 dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
142 goto err;
143 }
144 }
145
Richard Fitzgerald856ce892024-01-29 16:27:28 +0000146 ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
147 if (ret)
148 goto err;
149
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100150 return 0;
151
152err:
153 cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
154 regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
155 CS35L56_MBOX_CMD_HIBERNATE_NOW);
156
157 regcache_cache_only(cs35l56->base.regmap, true);
158
159 return ret;
160}
161
162static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,
163 struct snd_ctl_elem_info *uinfo)
164{
165 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
166 uinfo->count = 1;
167 uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;
168 if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)
169 uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;
170 strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],
171 sizeof(uinfo->value.enumerated.name));
172
173 return 0;
174}
175
176static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
177 struct snd_ctl_elem_value *ucontrol)
178{
179 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
180 unsigned int reg_val;
181 int i;
182
183 regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
184 reg_val &= CS35L56_ASP_TXn_SRC_MASK;
185
186 for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
187 if (cs35l56_tx_input_values[i] == reg_val) {
188 ucontrol->value.enumerated.item[0] = i;
189 break;
190 }
191 }
192
193 return 0;
194}
195
196static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
197 struct snd_ctl_elem_value *ucontrol)
198{
199 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
200 unsigned int item = ucontrol->value.enumerated.item[0];
201 bool changed;
202
203 if (item >= CS35L56_NUM_INPUT_SRC)
204 return -EINVAL;
205
206 regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
207 CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
208 &changed);
209
210 return changed;
211}
212
213static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,
214 struct snd_ctl_elem_info *uinfo)
215{
216 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
217 uinfo->count = 1;
218 uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;
219 uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;
220 return 0;
221}
222
223static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
224 struct snd_ctl_elem_value *ucontrol)
225{
226 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
227 unsigned int pos;
228 int ret;
229
230 ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos);
231 if (ret)
232 return ret;
233
234 ucontrol->value.integer.value[0] = pos;
235
Richard Fitzgerald72ca5662023-09-14 15:08:52 +0100236 return 0;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100237}
238
239static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
240 struct snd_ctl_elem_value *ucontrol)
241{
242 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
243 unsigned long pos = ucontrol->value.integer.value[0];
244 bool changed;
245 int ret;
246
247 if ((pos < CS35L56_MAIN_POSTURE_MIN) ||
248 (pos > CS35L56_MAIN_POSTURE_MAX))
249 return -EINVAL;
250
251 ret = regmap_update_bits_check(cs35l56->base.regmap,
252 CS35L56_MAIN_POSTURE_NUMBER,
253 CS35L56_MAIN_POSTURE_MASK,
254 pos, &changed);
255 if (ret)
256 return ret;
257
258 return changed;
259}
260
261static const struct {
262 const char *name;
263 unsigned int reg;
264} cs35l56_hda_mixer_controls[] = {
265 { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },
266 { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },
267 { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },
268 { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },
269};
270
271static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);
272
273static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,
274 struct snd_ctl_elem_info *uinfo)
275{
276 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
277 uinfo->count = 1;
278 uinfo->value.integer.step = 1;
279 uinfo->value.integer.min = 0;
280 uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
281 CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
282
283 return 0;
284}
285
286static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
287 struct snd_ctl_elem_value *ucontrol)
288{
289 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
290 unsigned int raw_vol;
291 int vol;
292 int ret;
293
294 ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol);
295
296 if (ret)
297 return ret;
298
299 vol = (s16)(raw_vol & 0xFFFF);
300 vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
301
302 if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))
303 vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));
304
305 ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
306
307 return 0;
308}
309
310static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
311 struct snd_ctl_elem_value *ucontrol)
312{
313 struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
314 long vol = ucontrol->value.integer.value[0];
315 unsigned int raw_vol;
316 bool changed;
317 int ret;
318
319 if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
320 CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))
321 return -EINVAL;
322
323 raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
324 CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
325
326 ret = regmap_update_bits_check(cs35l56->base.regmap,
327 CS35L56_MAIN_RENDER_USER_VOLUME,
328 CS35L56_MAIN_RENDER_USER_VOLUME_MASK,
329 raw_vol, &changed);
330 if (ret)
331 return ret;
332
333 return changed;
334}
335
336static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)
337{
338 struct snd_kcontrol_new ctl_template = {
339 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
340 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
341 .info = cs35l56_hda_posture_info,
342 .get = cs35l56_hda_posture_get,
343 .put = cs35l56_hda_posture_put,
344 };
345 char name[64];
346 int i;
347
348 snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);
349 ctl_template.name = name;
350 cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);
351 if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))
352 dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
353
354 /* Mixer controls */
355 ctl_template.info = cs35l56_hda_mixer_info;
356 ctl_template.get = cs35l56_hda_mixer_get;
357 ctl_template.put = cs35l56_hda_mixer_put;
358
359 BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));
360
361 for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {
362 snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,
363 cs35l56_hda_mixer_controls[i].name);
364 ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;
365 cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);
366 if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {
367 dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",
368 ctl_template.name);
369 }
370 }
371
372 ctl_template.info = cs35l56_hda_vol_info;
373 ctl_template.get = cs35l56_hda_vol_get;
374 ctl_template.put = cs35l56_hda_vol_put;
375 ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);
376 ctl_template.tlv.p = cs35l56_hda_vol_tlv;
377 snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);
378 ctl_template.name = name;
379 cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);
380 if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))
381 dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
382}
383
384static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
385{
386 int i;
387
388 for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)
389 snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);
390
391 snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);
392 snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
393}
394
395static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
396 .control_remove = hda_cs_dsp_control_remove,
397};
398
399static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
400 const struct firmware **firmware, char **filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000401 const char *base_name, const char *system_name,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100402 const char *amp_name,
403 const char *filetype)
404{
405 char *s, c;
406 int ret = 0;
407
408 if (system_name && amp_name)
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000409 *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100410 system_name, amp_name, filetype);
411 else if (system_name)
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000412 *filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100413 system_name, filetype);
414 else
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000415 *filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100416
417 if (!*filename)
418 return -ENOMEM;
419
420 /*
421 * Make sure that filename is lower-case and any non alpha-numeric
422 * characters except full stop and forward slash are replaced with
423 * hyphens.
424 */
425 s = *filename;
426 while (*s) {
427 c = *s;
428 if (isalnum(c))
429 *s = tolower(c);
430 else if (c != '.' && c != '/')
431 *s = '-';
432 s++;
433 }
434
435 ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev);
436 if (ret) {
437 dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);
438 kfree(*filename);
439 *filename = NULL;
440 return ret;
441 }
442
443 dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);
444
445 return 0;
446}
447
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100448static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000449 unsigned int preloaded_fw_ver,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100450 const struct firmware **wmfw_firmware,
451 char **wmfw_filename,
452 const struct firmware **coeff_firmware,
453 char **coeff_filename)
454{
455 const char *system_name = cs35l56->system_name;
456 const char *amp_name = cs35l56->amp_name;
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000457 char base_name[37];
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100458 int ret;
459
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000460 if (preloaded_fw_ver) {
461 snprintf(base_name, sizeof(base_name),
Simon Trimmer769dca22024-03-08 13:58:59 +0000462 "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
463 cs35l56->base.type,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000464 cs35l56->base.rev,
465 cs35l56->base.secured ? "-s" : "",
466 preloaded_fw_ver & 0xffffff);
467 } else {
468 snprintf(base_name, sizeof(base_name),
Simon Trimmer769dca22024-03-08 13:58:59 +0000469 "cirrus/cs35l%02x-%02x%s-dsp1-misc",
470 cs35l56->base.type,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000471 cs35l56->base.rev,
472 cs35l56->base.secured ? "-s" : "");
473 }
474
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100475 if (system_name && amp_name) {
476 if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000477 base_name, system_name, amp_name, "wmfw")) {
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100478 cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000479 base_name, system_name, amp_name, "bin");
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100480 return;
481 }
482 }
483
484 if (system_name) {
485 if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000486 base_name, system_name, NULL, "wmfw")) {
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100487 if (amp_name)
488 cs35l56_hda_request_firmware_file(cs35l56,
489 coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000490 base_name, system_name,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100491 amp_name, "bin");
492 if (!*coeff_firmware)
493 cs35l56_hda_request_firmware_file(cs35l56,
494 coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000495 base_name, system_name,
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100496 NULL, "bin");
497 return;
498 }
Richard Fitzgerald77c60722024-01-29 16:27:34 +0000499
500 /*
501 * Check for system-specific bin files without wmfw before
502 * falling back to generic firmware
503 */
504 if (amp_name)
505 cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000506 base_name, system_name, amp_name, "bin");
Richard Fitzgerald77c60722024-01-29 16:27:34 +0000507 if (!*coeff_firmware)
508 cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000509 base_name, system_name, NULL, "bin");
Richard Fitzgerald77c60722024-01-29 16:27:34 +0000510
511 if (*coeff_firmware)
512 return;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100513 }
514
515 ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000516 base_name, NULL, NULL, "wmfw");
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100517 if (!ret) {
518 cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000519 base_name, NULL, NULL, "bin");
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100520 return;
521 }
522
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100523 if (!*coeff_firmware)
524 cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000525 base_name, NULL, NULL, "bin");
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100526}
527
528static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
529 char *wmfw_filename,
530 const struct firmware *coeff_firmware,
531 char *coeff_filename)
532{
533 if (wmfw_firmware)
534 release_firmware(wmfw_firmware);
535 kfree(wmfw_filename);
536
537 if (coeff_firmware)
538 release_firmware(coeff_firmware);
539 kfree(coeff_filename);
540}
541
542static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56)
543{
544 struct hda_cs_dsp_ctl_info info;
545
546 info.device_name = cs35l56->amp_name;
547 info.fw_type = HDA_CS_DSP_FW_MISC;
548 info.card = cs35l56->codec->card;
549
550 hda_cs_dsp_add_controls(&cs35l56->cs_dsp, &info);
551}
552
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +0000553static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
554{
555 int ret;
556
557 if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
558 return;
559
560 ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
561 &cs35l56_calibration_controls,
562 &cs35l56->base.cal_data);
563 if (ret < 0)
564 dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
565 else
566 dev_info(cs35l56->base.dev, "Calibration applied\n");
567}
568
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100569static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
570{
571 const struct firmware *coeff_firmware = NULL;
572 const struct firmware *wmfw_firmware = NULL;
573 char *coeff_filename = NULL;
574 char *wmfw_filename = NULL;
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000575 unsigned int preloaded_fw_ver;
576 bool firmware_missing;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100577 int ret = 0;
578
Richard Fitzgerald15c378d2023-07-31 17:57:20 +0100579 /* Prepare for a new DSP power-up */
580 if (cs35l56->base.fw_patched)
581 cs_dsp_power_down(&cs35l56->cs_dsp);
582
583 cs35l56->base.fw_patched = false;
584
Richard Fitzgerald2f860dd2023-07-31 17:57:24 +0100585 pm_runtime_get_sync(cs35l56->base.dev);
586
Richard Fitzgerald2f860dd2023-07-31 17:57:24 +0100587 /*
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000588 * The firmware can only be upgraded if it is currently running
589 * from the built-in ROM. If not, the wmfw/bin must be for the
590 * version of firmware that is running on the chip.
Richard Fitzgerald2f860dd2023-07-31 17:57:24 +0100591 */
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000592 ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
593 if (ret)
594 goto err_pm_put;
595
596 if (firmware_missing)
597 preloaded_fw_ver = 0;
598
599 cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
600 &wmfw_firmware, &wmfw_filename,
601 &coeff_firmware, &coeff_filename);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100602
Richard Fitzgerald31067972023-07-31 17:57:25 +0100603 /*
604 * If the BIOS didn't patch the firmware a bin file is mandatory to
605 * enable the ASP·
606 */
607 if (!coeff_firmware && firmware_missing) {
608 dev_err(cs35l56->base.dev, ".bin file required but not found\n");
609 ret = -ENOENT;
610 goto err_fw_release;
611 }
612
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100613 mutex_lock(&cs35l56->base.irq_lock);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100614
615 /*
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000616 * If the firmware hasn't been patched it must be shutdown before
617 * doing a full patch and reset afterwards. If it is already
618 * running a patched version the firmware files only contain
619 * tunings and we can use the lower cost reinit sequence instead.
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100620 */
Richard Fitzgerald6f8ad042024-01-29 16:27:36 +0000621 if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100622 ret = cs35l56_firmware_shutdown(&cs35l56->base);
623 if (ret)
624 goto err;
625 }
626
627 ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
628 coeff_firmware, coeff_filename, "misc");
629 if (ret) {
630 dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
631 goto err;
632 }
633
634 if (wmfw_filename)
635 dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);
636
637 if (coeff_filename)
638 dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
639
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +0000640 /* If we downloaded firmware, reset the device and wait for it to boot */
641 if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100642 cs35l56_system_reset(&cs35l56->base, false);
Richard Fitzgeraldc3657092023-07-31 17:57:19 +0100643 regcache_mark_dirty(cs35l56->base.regmap);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100644 ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
645 if (ret)
Richard Fitzgerald0ba0dfd2023-07-31 17:57:23 +0100646 goto err_powered_up;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100647 }
648
649 /* Disable auto-hibernate so that runtime_pm has control */
650 ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
651 if (ret)
Richard Fitzgerald0ba0dfd2023-07-31 17:57:23 +0100652 goto err_powered_up;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100653
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100654 regcache_sync(cs35l56->base.regmap);
655
656 regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS,
657 CS35L56_FIRMWARE_MISSING);
658 cs35l56->base.fw_patched = true;
Richard Fitzgerald7b6466a2023-07-31 17:57:18 +0100659
660 ret = cs_dsp_run(&cs35l56->cs_dsp);
661 if (ret)
662 dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
663
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +0000664 cs35l56_hda_apply_calibration(cs35l56);
665 ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
666 if (ret)
667 cs_dsp_stop(&cs35l56->cs_dsp);
668
Richard Fitzgerald0ba0dfd2023-07-31 17:57:23 +0100669err_powered_up:
670 if (!cs35l56->base.fw_patched)
671 cs_dsp_power_down(&cs35l56->cs_dsp);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100672err:
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100673 mutex_unlock(&cs35l56->base.irq_lock);
Richard Fitzgerald31067972023-07-31 17:57:25 +0100674err_fw_release:
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100675 cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
676 coeff_firmware, coeff_filename);
Richard Fitzgerald2f860dd2023-07-31 17:57:24 +0100677err_pm_put:
678 pm_runtime_put(cs35l56->base.dev);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100679
680 return ret;
681}
682
683static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
684{
685 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
686 struct hda_component *comps = master_data;
687 int ret;
688
689 if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS)
690 return -EINVAL;
691
692 comps = &comps[cs35l56->index];
693 if (comps->dev)
694 return -EBUSY;
695
696 comps->dev = dev;
697 cs35l56->codec = comps->codec;
698 strscpy(comps->name, dev_name(dev), sizeof(comps->name));
699 comps->playback_hook = cs35l56_hda_playback_hook;
700
701 ret = cs35l56_hda_fw_load(cs35l56);
702 if (ret)
703 return ret;
704
705 cs35l56_hda_create_controls(cs35l56);
706 cs35l56_hda_add_dsp_controls(cs35l56);
707
708#if IS_ENABLED(CONFIG_SND_DEBUG)
709 cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
710 cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
711#endif
712
713 dev_dbg(cs35l56->base.dev, "Bound\n");
714
715 return 0;
716}
717
718static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
719{
720 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
721 struct hda_component *comps = master_data;
722
723 cs35l56_hda_remove_controls(cs35l56);
724
725#if IS_ENABLED(CONFIG_SND_DEBUG)
726 cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);
727 debugfs_remove_recursive(cs35l56->debugfs_root);
728#endif
729
Richard Fitzgeraldfb78d732023-07-31 17:57:22 +0100730 if (cs35l56->base.fw_patched)
731 cs_dsp_power_down(&cs35l56->cs_dsp);
732
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100733 cs_dsp_remove(&cs35l56->cs_dsp);
734
735 if (comps[cs35l56->index].dev == dev)
736 memset(&comps[cs35l56->index], 0, sizeof(*comps));
737
738 dev_dbg(cs35l56->base.dev, "Unbound\n");
739}
740
741static const struct component_ops cs35l56_hda_comp_ops = {
742 .bind = cs35l56_hda_bind,
743 .unbind = cs35l56_hda_unbind,
744};
745
746static int cs35l56_hda_system_suspend(struct device *dev)
747{
748 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
749
750 if (cs35l56->playing)
751 cs35l56_hda_pause(cs35l56);
752
753 cs35l56->suspended = true;
754
755 /*
756 * The interrupt line is normally shared, but after we start suspending
757 * we can't check if our device is the source of an interrupt, and can't
758 * clear it. Prevent this race by temporarily disabling the parent irq
759 * until we reach _no_irq.
760 */
761 if (cs35l56->base.irq)
762 disable_irq(cs35l56->base.irq);
763
764 return pm_runtime_force_suspend(dev);
765}
766
767static int cs35l56_hda_system_suspend_late(struct device *dev)
768{
769 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
770
771 /*
772 * RESET is usually shared by all amps so it must not be asserted until
773 * all driver instances have done their suspend() stage.
774 */
775 if (cs35l56->base.reset_gpio) {
776 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
777 cs35l56_wait_min_reset_pulse();
778 }
779
780 return 0;
781}
782
783static int cs35l56_hda_system_suspend_no_irq(struct device *dev)
784{
785 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
786
787 /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
788 if (cs35l56->base.irq)
789 enable_irq(cs35l56->base.irq);
790
791 return 0;
792}
793
794static int cs35l56_hda_system_resume_no_irq(struct device *dev)
795{
796 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
797
798 /*
799 * WAKE interrupts unmask if the CS35L56 hibernates, which can cause
800 * spurious interrupts, and the interrupt line is normally shared.
801 * We can't check if our device is the source of an interrupt, and can't
802 * clear it, until it has fully resumed. Prevent this race by temporarily
803 * disabling the parent irq until we complete resume().
804 */
805 if (cs35l56->base.irq)
806 disable_irq(cs35l56->base.irq);
807
808 return 0;
809}
810
811static int cs35l56_hda_system_resume_early(struct device *dev)
812{
813 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
814
815 /* Ensure a spec-compliant RESET pulse. */
816 if (cs35l56->base.reset_gpio) {
817 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
818 cs35l56_wait_min_reset_pulse();
819
820 /* Release shared RESET before drivers start resume(). */
821 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
822 cs35l56_wait_control_port_ready();
823 }
824
825 return 0;
826}
827
828static int cs35l56_hda_system_resume(struct device *dev)
829{
830 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
831 int ret;
832
833 /* Undo pm_runtime_force_suspend() before re-enabling the irq */
834 ret = pm_runtime_force_resume(dev);
835 if (cs35l56->base.irq)
836 enable_irq(cs35l56->base.irq);
837
838 if (ret)
839 return ret;
840
841 cs35l56->suspended = false;
842
843 ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
844 dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
845 if (ret > 0) {
846 ret = cs35l56_hda_fw_load(cs35l56);
847 if (ret)
848 return ret;
849 }
850
851 if (cs35l56->playing)
852 cs35l56_hda_play(cs35l56);
853
854 return 0;
855}
856
Simon Trimmer769dca22024-03-08 13:58:59 +0000857static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100858{
859 u32 values[HDA_MAX_COMPONENTS];
Simon Trimmer769dca22024-03-08 13:58:59 +0000860 char hid_string[8];
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100861 struct acpi_device *adev;
862 const char *property, *sub;
863 size_t nval;
864 int i, ret;
865
866 /*
867 * ACPI_COMPANION isn't available when this driver was instantiated by
868 * the serial-multi-instantiate driver, so lookup the node by HID
869 */
870 if (!ACPI_COMPANION(cs35l56->base.dev)) {
Simon Trimmer769dca22024-03-08 13:58:59 +0000871 snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
872 adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100873 if (!adev) {
874 dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
875 dev_name(cs35l56->base.dev));
876 return -ENODEV;
877 }
878 ACPI_COMPANION_SET(cs35l56->base.dev, adev);
879 }
880
881 property = "cirrus,dev-index";
882 ret = device_property_count_u32(cs35l56->base.dev, property);
883 if (ret <= 0)
884 goto err;
885
886 if (ret > ARRAY_SIZE(values)) {
887 ret = -EINVAL;
888 goto err;
889 }
890 nval = ret;
891
892 ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
893 if (ret)
894 goto err;
895
896 cs35l56->index = -1;
897 for (i = 0; i < nval; i++) {
898 if (values[i] == id) {
899 cs35l56->index = i;
900 break;
901 }
902 }
Richard Fitzgerald8ca3ee62023-07-31 17:57:26 +0100903 /*
904 * It's not an error for the ID to be missing: for I2C there can be
905 * an alias address that is not a real device. So reject silently.
906 */
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100907 if (cs35l56->index == -1) {
Richard Fitzgerald8ca3ee62023-07-31 17:57:26 +0100908 dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100909 ret = -ENODEV;
910 goto err;
911 }
912
913 sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
914
915 if (IS_ERR(sub)) {
Richard Fitzgerald21484e42023-09-14 16:25:25 +0100916 dev_info(cs35l56->base.dev,
917 "Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
918 PTR_ERR(sub));
919 } else {
Richard Fitzgerald6f03b442023-09-18 10:51:28 +0100920 ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
921 if (ret == -ENOENT) {
922 cs35l56->system_name = sub;
923 } else if (ret >= 0) {
924 cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);
925 kfree(sub);
926 if (!cs35l56->system_name)
927 return -ENOMEM;
928 } else {
929 return ret;
930 }
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100931 }
932
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100933 cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
934 "reset",
935 cs35l56->index,
936 GPIOD_OUT_LOW);
937 if (IS_ERR(cs35l56->base.reset_gpio)) {
938 ret = PTR_ERR(cs35l56->base.reset_gpio);
939
940 /*
941 * If RESET is shared the first amp to probe will grab the reset
942 * line and reset all the amps
943 */
944 if (ret != -EBUSY)
945 return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
946
947 dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
948 cs35l56->base.reset_gpio = NULL;
949 }
950
951 return 0;
952
953err:
Richard Fitzgerald8ca3ee62023-07-31 17:57:26 +0100954 if (ret != -ENODEV)
955 dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100956
957 return ret;
958}
959
Simon Trimmer769dca22024-03-08 13:58:59 +0000960int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100961{
962 int ret;
963
964 mutex_init(&cs35l56->base.irq_lock);
965 dev_set_drvdata(cs35l56->base.dev, cs35l56);
966
Simon Trimmer769dca22024-03-08 13:58:59 +0000967 ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
Richard Fitzgerald8ca3ee62023-07-31 17:57:26 +0100968 if (ret)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100969 goto err;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100970
971 cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",
972 cs35l56->index + 1);
973 if (!cs35l56->amp_name) {
974 ret = -ENOMEM;
975 goto err;
976 }
977
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +0000978 cs35l56->base.cal_index = cs35l56->index;
979
Simon Trimmer73cfbfa2023-07-21 14:21:20 +0100980 cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
981 cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
982
983 if (cs35l56->base.reset_gpio) {
984 dev_dbg(cs35l56->base.dev, "Hard reset\n");
985
986 /*
987 * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the
988 * ACPI defines a different default state. So explicitly set low.
989 */
990 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
991 cs35l56_wait_min_reset_pulse();
992 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
993 }
994
995 ret = cs35l56_hw_init(&cs35l56->base);
996 if (ret < 0)
997 goto err;
998
999 /* Reset the device and wait for it to boot */
1000 cs35l56_system_reset(&cs35l56->base, false);
1001 ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
1002 if (ret)
1003 goto err;
1004
1005 ret = cs35l56_set_patch(&cs35l56->base);
1006 if (ret)
Dan Carpenter367ef1e2023-07-27 10:16:33 +03001007 goto err;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001008
1009 regcache_mark_dirty(cs35l56->base.regmap);
1010 regcache_sync(cs35l56->base.regmap);
1011
1012 /* Disable auto-hibernate so that runtime_pm has control */
1013 ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
1014 if (ret)
1015 goto err;
1016
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +00001017 ret = cs35l56_get_calibration(&cs35l56->base);
1018 if (ret)
1019 goto err;
1020
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001021 ret = cs_dsp_halo_init(&cs35l56->cs_dsp);
1022 if (ret) {
1023 dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");
1024 goto err;
1025 }
1026
Simon Trimmer3c9531632024-03-25 14:29:37 +00001027 dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
1028 cs35l56->system_name, cs35l56->amp_name);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001029
1030 regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
1031 ARRAY_SIZE(cs35l56_hda_dai_config));
Richard Fitzgerald856ce892024-01-29 16:27:28 +00001032 ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
1033 if (ret)
1034 goto err;
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001035
1036 /*
1037 * By default only enable one ASP1TXn, where n=amplifier index,
1038 * This prevents multiple amps trying to drive the same slot.
1039 */
1040 cs35l56->asp_tx_mask = BIT(cs35l56->index);
1041
1042 pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);
1043 pm_runtime_use_autosuspend(cs35l56->base.dev);
1044 pm_runtime_set_active(cs35l56->base.dev);
1045 pm_runtime_mark_last_busy(cs35l56->base.dev);
1046 pm_runtime_enable(cs35l56->base.dev);
1047
Simon Trimmercafe9c62024-03-25 14:55:10 +00001048 cs35l56->base.init_done = true;
1049
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001050 ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
1051 if (ret) {
1052 dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
1053 goto pm_err;
1054 }
1055
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001056 return 0;
1057
1058pm_err:
1059 pm_runtime_disable(cs35l56->base.dev);
1060err:
1061 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
1062
1063 return ret;
1064}
1065EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56);
1066
1067void cs35l56_hda_remove(struct device *dev)
1068{
1069 struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
1070
Richard Fitzgeraldcaaaa342023-09-08 11:12:23 +01001071 pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001072 pm_runtime_get_sync(cs35l56->base.dev);
1073 pm_runtime_disable(cs35l56->base.dev);
1074
1075 component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);
1076
1077 kfree(cs35l56->system_name);
1078 pm_runtime_put_noidle(cs35l56->base.dev);
1079
1080 gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
1081}
1082EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56);
1083
1084const struct dev_pm_ops cs35l56_hda_pm_ops = {
Richard Fitzgeralddeff8482023-09-19 09:11:53 +01001085 RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001086 SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
1087 LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
1088 cs35l56_hda_system_resume_early)
1089 NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,
1090 cs35l56_hda_system_resume_no_irq)
1091};
1092EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56);
1093
1094MODULE_DESCRIPTION("CS35L56 HDA Driver");
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +00001095MODULE_IMPORT_NS(FW_CS_DSP);
Richard Fitzgerald6f03b442023-09-18 10:51:28 +01001096MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001097MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
1098MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
Richard Fitzgeraldcfa43aa2024-02-23 15:39:09 +00001099MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB);
Simon Trimmer73cfbfa2023-07-21 14:21:20 +01001100MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
1101MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
1102MODULE_LICENSE("GPL");