1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Components shared between ASoC and HDA CS35L56 drivers |
4 | // |
5 | // Copyright (C) 2023 Cirrus Logic, Inc. and |
6 | // Cirrus Logic International Semiconductor Ltd. |
7 | |
8 | #include <linux/firmware/cirrus/wmfw.h> |
9 | #include <linux/gpio/consumer.h> |
10 | #include <linux/regmap.h> |
11 | #include <linux/regulator/consumer.h> |
12 | #include <linux/types.h> |
13 | #include <sound/cs-amp-lib.h> |
14 | |
15 | #include "cs35l56.h" |
16 | |
17 | static const struct reg_sequence cs35l56_patch[] = { |
18 | /* |
19 | * Firmware can change these to non-defaults to satisfy SDCA. |
20 | * Ensure that they are at known defaults. |
21 | */ |
22 | { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, |
23 | { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, |
24 | { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, |
25 | { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 }, |
26 | |
27 | /* These are not reset by a soft-reset, so patch to defaults. */ |
28 | { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, |
29 | { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, |
30 | { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, |
31 | }; |
32 | |
33 | int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) |
34 | { |
35 | return regmap_register_patch(map: cs35l56_base->regmap, regs: cs35l56_patch, |
36 | ARRAY_SIZE(cs35l56_patch)); |
37 | } |
38 | EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); |
39 | |
40 | static const struct reg_default cs35l56_reg_defaults[] = { |
41 | /* no defaults for OTP_MEM - first read populates cache */ |
42 | |
43 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, |
44 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, |
45 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, |
46 | { CS35L56_ASP1_CONTROL3, 0x00000002 }, |
47 | { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, |
48 | { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, |
49 | { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, |
50 | { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, |
51 | |
52 | /* no defaults for ASP1TX mixer */ |
53 | |
54 | { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, |
55 | { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, |
56 | { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, |
57 | { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 }, |
58 | { CS35L56_IRQ1_MASK_1, 0x83ffffff }, |
59 | { CS35L56_IRQ1_MASK_2, 0xffff7fff }, |
60 | { CS35L56_IRQ1_MASK_4, 0xe0ffffff }, |
61 | { CS35L56_IRQ1_MASK_8, 0xfc000fff }, |
62 | { CS35L56_IRQ1_MASK_18, 0x1f7df0ff }, |
63 | { CS35L56_IRQ1_MASK_20, 0x15c00000 }, |
64 | { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, |
65 | { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, |
66 | { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, |
67 | }; |
68 | |
69 | static bool cs35l56_is_dsp_memory(unsigned int reg) |
70 | { |
71 | switch (reg) { |
72 | case CS35L56_DSP1_XMEM_PACKED_0 ... CS35L56_DSP1_XMEM_PACKED_6143: |
73 | case CS35L56_DSP1_XMEM_UNPACKED32_0 ... CS35L56_DSP1_XMEM_UNPACKED32_4095: |
74 | case CS35L56_DSP1_XMEM_UNPACKED24_0 ... CS35L56_DSP1_XMEM_UNPACKED24_8191: |
75 | case CS35L56_DSP1_YMEM_PACKED_0 ... CS35L56_DSP1_YMEM_PACKED_4604: |
76 | case CS35L56_DSP1_YMEM_UNPACKED32_0 ... CS35L56_DSP1_YMEM_UNPACKED32_3070: |
77 | case CS35L56_DSP1_YMEM_UNPACKED24_0 ... CS35L56_DSP1_YMEM_UNPACKED24_6141: |
78 | case CS35L56_DSP1_PMEM_0 ... CS35L56_DSP1_PMEM_5114: |
79 | return true; |
80 | default: |
81 | return false; |
82 | } |
83 | } |
84 | |
85 | static bool cs35l56_readable_reg(struct device *dev, unsigned int reg) |
86 | { |
87 | switch (reg) { |
88 | case CS35L56_DEVID: |
89 | case CS35L56_REVID: |
90 | case CS35L56_RELID: |
91 | case CS35L56_OTPID: |
92 | case CS35L56_SFT_RESET: |
93 | case CS35L56_GLOBAL_ENABLES: |
94 | case CS35L56_BLOCK_ENABLES: |
95 | case CS35L56_BLOCK_ENABLES2: |
96 | case CS35L56_REFCLK_INPUT: |
97 | case CS35L56_GLOBAL_SAMPLE_RATE: |
98 | case CS35L56_OTP_MEM_53: |
99 | case CS35L56_OTP_MEM_54: |
100 | case CS35L56_OTP_MEM_55: |
101 | case CS35L56_ASP1_ENABLES1: |
102 | case CS35L56_ASP1_CONTROL1: |
103 | case CS35L56_ASP1_CONTROL2: |
104 | case CS35L56_ASP1_CONTROL3: |
105 | case CS35L56_ASP1_FRAME_CONTROL1: |
106 | case CS35L56_ASP1_FRAME_CONTROL5: |
107 | case CS35L56_ASP1_DATA_CONTROL1: |
108 | case CS35L56_ASP1_DATA_CONTROL5: |
109 | case CS35L56_DACPCM1_INPUT: |
110 | case CS35L56_DACPCM2_INPUT: |
111 | case CS35L56_ASP1TX1_INPUT: |
112 | case CS35L56_ASP1TX2_INPUT: |
113 | case CS35L56_ASP1TX3_INPUT: |
114 | case CS35L56_ASP1TX4_INPUT: |
115 | case CS35L56_DSP1RX1_INPUT: |
116 | case CS35L56_DSP1RX2_INPUT: |
117 | case CS35L56_SWIRE_DP3_CH1_INPUT: |
118 | case CS35L56_SWIRE_DP3_CH2_INPUT: |
119 | case CS35L56_SWIRE_DP3_CH3_INPUT: |
120 | case CS35L56_SWIRE_DP3_CH4_INPUT: |
121 | case CS35L56_IRQ1_CFG: |
122 | case CS35L56_IRQ1_STATUS: |
123 | case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: |
124 | case CS35L56_IRQ1_EINT_18: |
125 | case CS35L56_IRQ1_EINT_20: |
126 | case CS35L56_IRQ1_MASK_1: |
127 | case CS35L56_IRQ1_MASK_2: |
128 | case CS35L56_IRQ1_MASK_4: |
129 | case CS35L56_IRQ1_MASK_8: |
130 | case CS35L56_IRQ1_MASK_18: |
131 | case CS35L56_IRQ1_MASK_20: |
132 | case CS35L56_DSP_VIRTUAL1_MBOX_1: |
133 | case CS35L56_DSP_VIRTUAL1_MBOX_2: |
134 | case CS35L56_DSP_VIRTUAL1_MBOX_3: |
135 | case CS35L56_DSP_VIRTUAL1_MBOX_4: |
136 | case CS35L56_DSP_VIRTUAL1_MBOX_5: |
137 | case CS35L56_DSP_VIRTUAL1_MBOX_6: |
138 | case CS35L56_DSP_VIRTUAL1_MBOX_7: |
139 | case CS35L56_DSP_VIRTUAL1_MBOX_8: |
140 | case CS35L56_DSP_RESTRICT_STS1: |
141 | case CS35L56_DSP1_SYS_INFO_ID ... CS35L56_DSP1_SYS_INFO_END: |
142 | case CS35L56_DSP1_AHBM_WINDOW_DEBUG_0: |
143 | case CS35L56_DSP1_AHBM_WINDOW_DEBUG_1: |
144 | case CS35L56_DSP1_SCRATCH1: |
145 | case CS35L56_DSP1_SCRATCH2: |
146 | case CS35L56_DSP1_SCRATCH3: |
147 | case CS35L56_DSP1_SCRATCH4: |
148 | return true; |
149 | default: |
150 | return cs35l56_is_dsp_memory(reg); |
151 | } |
152 | } |
153 | |
154 | static bool cs35l56_precious_reg(struct device *dev, unsigned int reg) |
155 | { |
156 | switch (reg) { |
157 | case CS35L56_DSP1_XMEM_PACKED_0 ... CS35L56_DSP1_XMEM_PACKED_6143: |
158 | case CS35L56_DSP1_YMEM_PACKED_0 ... CS35L56_DSP1_YMEM_PACKED_4604: |
159 | case CS35L56_DSP1_PMEM_0 ... CS35L56_DSP1_PMEM_5114: |
160 | return true; |
161 | default: |
162 | return false; |
163 | } |
164 | } |
165 | |
166 | static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) |
167 | { |
168 | switch (reg) { |
169 | case CS35L56_DEVID: |
170 | case CS35L56_REVID: |
171 | case CS35L56_RELID: |
172 | case CS35L56_OTPID: |
173 | case CS35L56_SFT_RESET: |
174 | case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ |
175 | case CS35L56_BLOCK_ENABLES: /* owned by firmware */ |
176 | case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ |
177 | case CS35L56_REFCLK_INPUT: /* owned by firmware */ |
178 | case CS35L56_GLOBAL_SAMPLE_RATE: /* owned by firmware */ |
179 | case CS35L56_DACPCM1_INPUT: /* owned by firmware */ |
180 | case CS35L56_DACPCM2_INPUT: /* owned by firmware */ |
181 | case CS35L56_DSP1RX1_INPUT: /* owned by firmware */ |
182 | case CS35L56_DSP1RX2_INPUT: /* owned by firmware */ |
183 | case CS35L56_IRQ1_STATUS: |
184 | case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: |
185 | case CS35L56_IRQ1_EINT_18: |
186 | case CS35L56_IRQ1_EINT_20: |
187 | case CS35L56_DSP_VIRTUAL1_MBOX_1: |
188 | case CS35L56_DSP_VIRTUAL1_MBOX_2: |
189 | case CS35L56_DSP_VIRTUAL1_MBOX_3: |
190 | case CS35L56_DSP_VIRTUAL1_MBOX_4: |
191 | case CS35L56_DSP_VIRTUAL1_MBOX_5: |
192 | case CS35L56_DSP_VIRTUAL1_MBOX_6: |
193 | case CS35L56_DSP_VIRTUAL1_MBOX_7: |
194 | case CS35L56_DSP_VIRTUAL1_MBOX_8: |
195 | case CS35L56_DSP_RESTRICT_STS1: |
196 | case CS35L56_DSP1_SYS_INFO_ID ... CS35L56_DSP1_SYS_INFO_END: |
197 | case CS35L56_DSP1_AHBM_WINDOW_DEBUG_0: |
198 | case CS35L56_DSP1_AHBM_WINDOW_DEBUG_1: |
199 | case CS35L56_DSP1_SCRATCH1: |
200 | case CS35L56_DSP1_SCRATCH2: |
201 | case CS35L56_DSP1_SCRATCH3: |
202 | case CS35L56_DSP1_SCRATCH4: |
203 | return true; |
204 | case CS35L56_MAIN_RENDER_USER_MUTE: |
205 | case CS35L56_MAIN_RENDER_USER_VOLUME: |
206 | case CS35L56_MAIN_POSTURE_NUMBER: |
207 | return false; |
208 | default: |
209 | return cs35l56_is_dsp_memory(reg); |
210 | } |
211 | } |
212 | |
213 | /* |
214 | * The firmware boot sequence can overwrite the ASP1 config registers so that |
215 | * they don't match regmap's view of their values. Rewrite the values from the |
216 | * regmap cache into the hardware registers. |
217 | */ |
218 | int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) |
219 | { |
220 | struct reg_sequence asp1_regs[] = { |
221 | { .reg = CS35L56_ASP1_ENABLES1 }, |
222 | { .reg = CS35L56_ASP1_CONTROL1 }, |
223 | { .reg = CS35L56_ASP1_CONTROL2 }, |
224 | { .reg = CS35L56_ASP1_CONTROL3 }, |
225 | { .reg = CS35L56_ASP1_FRAME_CONTROL1 }, |
226 | { .reg = CS35L56_ASP1_FRAME_CONTROL5 }, |
227 | { .reg = CS35L56_ASP1_DATA_CONTROL1 }, |
228 | { .reg = CS35L56_ASP1_DATA_CONTROL5 }, |
229 | }; |
230 | int i, ret; |
231 | |
232 | /* Read values from regmap cache into a write sequence */ |
233 | for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) { |
234 | ret = regmap_read(map: cs35l56_base->regmap, reg: asp1_regs[i].reg, val: &asp1_regs[i].def); |
235 | if (ret) |
236 | goto err; |
237 | } |
238 | |
239 | /* Write the values cache-bypassed so that they will be written to silicon */ |
240 | ret = regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, regs: asp1_regs, |
241 | ARRAY_SIZE(asp1_regs)); |
242 | if (ret) |
243 | goto err; |
244 | |
245 | return 0; |
246 | |
247 | err: |
248 | dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n" , ret); |
249 | |
250 | return ret; |
251 | } |
252 | EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED); |
253 | |
254 | int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) |
255 | { |
256 | unsigned int val; |
257 | int ret; |
258 | |
259 | regmap_write(map: cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, val: command); |
260 | ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, |
261 | val, (val == 0), |
262 | CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); |
263 | if (ret) { |
264 | dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n" , command, ret); |
265 | return ret; |
266 | } |
267 | |
268 | return 0; |
269 | } |
270 | EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); |
271 | |
272 | int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) |
273 | { |
274 | int ret; |
275 | unsigned int reg; |
276 | unsigned int val; |
277 | |
278 | ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN); |
279 | if (ret) |
280 | return ret; |
281 | |
282 | if (cs35l56_base->rev < CS35L56_REVID_B0) |
283 | reg = CS35L56_DSP1_PM_CUR_STATE_A1; |
284 | else |
285 | reg = CS35L56_DSP1_PM_CUR_STATE; |
286 | |
287 | ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, |
288 | val, (val == CS35L56_HALO_STATE_SHUTDOWN), |
289 | CS35L56_HALO_STATE_POLL_US, |
290 | CS35L56_HALO_STATE_TIMEOUT_US); |
291 | if (ret < 0) |
292 | dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n" , |
293 | val, ret); |
294 | return ret; |
295 | } |
296 | EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED); |
297 | |
298 | int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) |
299 | { |
300 | unsigned int reg; |
301 | unsigned int val = 0; |
302 | int read_ret, poll_ret; |
303 | |
304 | if (cs35l56_base->rev < CS35L56_REVID_B0) |
305 | reg = CS35L56_DSP1_HALO_STATE_A1; |
306 | else |
307 | reg = CS35L56_DSP1_HALO_STATE; |
308 | |
309 | /* |
310 | * This can't be a regmap_read_poll_timeout() because cs35l56 will NAK |
311 | * I2C until it has booted which would terminate the poll |
312 | */ |
313 | poll_ret = read_poll_timeout(regmap_read, read_ret, |
314 | (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), |
315 | CS35L56_HALO_STATE_POLL_US, |
316 | CS35L56_HALO_STATE_TIMEOUT_US, |
317 | false, |
318 | cs35l56_base->regmap, reg, &val); |
319 | |
320 | if (poll_ret) { |
321 | dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n" , |
322 | read_ret, val); |
323 | return -EIO; |
324 | } |
325 | |
326 | return 0; |
327 | } |
328 | EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED); |
329 | |
330 | void cs35l56_wait_control_port_ready(void) |
331 | { |
332 | /* Wait for control port to be ready (datasheet tIRS). */ |
333 | usleep_range(CS35L56_CONTROL_PORT_READY_US, max: 2 * CS35L56_CONTROL_PORT_READY_US); |
334 | } |
335 | EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED); |
336 | |
337 | void cs35l56_wait_min_reset_pulse(void) |
338 | { |
339 | /* Satisfy minimum reset pulse width spec */ |
340 | usleep_range(CS35L56_RESET_PULSE_MIN_US, max: 2 * CS35L56_RESET_PULSE_MIN_US); |
341 | } |
342 | EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED); |
343 | |
344 | static const struct reg_sequence cs35l56_system_reset_seq[] = { |
345 | REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0), |
346 | REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), |
347 | }; |
348 | |
349 | void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) |
350 | { |
351 | /* |
352 | * Must enter cache-only first so there can't be any more register |
353 | * accesses other than the controlled system reset sequence below. |
354 | */ |
355 | regcache_cache_only(map: cs35l56_base->regmap, enable: true); |
356 | regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, |
357 | regs: cs35l56_system_reset_seq, |
358 | ARRAY_SIZE(cs35l56_system_reset_seq)); |
359 | |
360 | /* On SoundWire the registers won't be accessible until it re-enumerates. */ |
361 | if (is_soundwire) |
362 | return; |
363 | |
364 | cs35l56_wait_control_port_ready(); |
365 | regcache_cache_only(map: cs35l56_base->regmap, enable: false); |
366 | } |
367 | EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); |
368 | |
369 | int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) |
370 | { |
371 | int ret; |
372 | |
373 | if (!irq) |
374 | return 0; |
375 | |
376 | ret = devm_request_threaded_irq(dev: cs35l56_base->dev, irq, NULL, thread_fn: cs35l56_irq, |
377 | IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, |
378 | devname: "cs35l56" , dev_id: cs35l56_base); |
379 | if (!ret) |
380 | cs35l56_base->irq = irq; |
381 | else |
382 | dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n" , ret); |
383 | |
384 | return ret; |
385 | } |
386 | EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED); |
387 | |
388 | irqreturn_t cs35l56_irq(int irq, void *data) |
389 | { |
390 | struct cs35l56_base *cs35l56_base = data; |
391 | unsigned int status1 = 0, status8 = 0, status20 = 0; |
392 | unsigned int mask1, mask8, mask20; |
393 | unsigned int val; |
394 | int rv; |
395 | |
396 | irqreturn_t ret = IRQ_NONE; |
397 | |
398 | if (!cs35l56_base->init_done) |
399 | return IRQ_NONE; |
400 | |
401 | mutex_lock(&cs35l56_base->irq_lock); |
402 | |
403 | rv = pm_runtime_resume_and_get(dev: cs35l56_base->dev); |
404 | if (rv < 0) { |
405 | dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n" , rv); |
406 | goto err_unlock; |
407 | } |
408 | |
409 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_STATUS, val: &val); |
410 | if ((val & CS35L56_IRQ1_STS_MASK) == 0) { |
411 | dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n" ); |
412 | goto err; |
413 | } |
414 | |
415 | /* Ack interrupts */ |
416 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, val: &status1); |
417 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, val: &mask1); |
418 | status1 &= ~mask1; |
419 | regmap_write(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, val: status1); |
420 | |
421 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, val: &status8); |
422 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, val: &mask8); |
423 | status8 &= ~mask8; |
424 | regmap_write(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, val: status8); |
425 | |
426 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, val: &status20); |
427 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, val: &mask20); |
428 | status20 &= ~mask20; |
429 | /* We don't want EINT20 but they default to unmasked: force mask */ |
430 | regmap_write(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, val: 0xffffffff); |
431 | |
432 | dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n" , __func__, status1, status8); |
433 | |
434 | /* Check to see if unmasked bits are active */ |
435 | if (!status1 && !status8 && !status20) |
436 | goto err; |
437 | |
438 | if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) |
439 | dev_crit(cs35l56_base->dev, "Amp short error\n" ); |
440 | |
441 | if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) |
442 | dev_crit(cs35l56_base->dev, "Overtemp error\n" ); |
443 | |
444 | ret = IRQ_HANDLED; |
445 | |
446 | err: |
447 | pm_runtime_put(dev: cs35l56_base->dev); |
448 | err_unlock: |
449 | mutex_unlock(lock: &cs35l56_base->irq_lock); |
450 | |
451 | return ret; |
452 | } |
453 | EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED); |
454 | |
455 | int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) |
456 | { |
457 | unsigned int val; |
458 | int ret; |
459 | |
460 | /* |
461 | * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so |
462 | * can't be used here to test for memory retention. |
463 | * Assume that tuning must be re-loaded. |
464 | */ |
465 | if (cs35l56_base->secured) |
466 | return true; |
467 | |
468 | ret = pm_runtime_resume_and_get(dev: cs35l56_base->dev); |
469 | if (ret) { |
470 | dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n" , ret); |
471 | return ret; |
472 | } |
473 | |
474 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, val: &val); |
475 | if (ret) |
476 | dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n" , ret); |
477 | else |
478 | ret = !!(val & CS35L56_FIRMWARE_MISSING); |
479 | |
480 | pm_runtime_put_autosuspend(dev: cs35l56_base->dev); |
481 | |
482 | return ret; |
483 | } |
484 | EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED); |
485 | |
486 | static const struct reg_sequence cs35l56_hibernate_seq[] = { |
487 | /* This must be the last register access */ |
488 | REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE), |
489 | }; |
490 | |
491 | static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { |
492 | REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), |
493 | }; |
494 | |
495 | static void cs35l56_issue_wake_event(struct cs35l56_base *cs35l56_base) |
496 | { |
497 | /* |
498 | * Dummy transactions to trigger I2C/SPI auto-wake. Issue two |
499 | * transactions to meet the minimum required time from the rising edge |
500 | * to the last falling edge of wake. |
501 | * |
502 | * It uses bypassed write because we must wake the chip before |
503 | * disabling regmap cache-only. |
504 | * |
505 | * This can NAK on I2C which will terminate the write sequence so the |
506 | * single-write sequence is issued twice. |
507 | */ |
508 | regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, |
509 | regs: cs35l56_hibernate_wake_seq, |
510 | ARRAY_SIZE(cs35l56_hibernate_wake_seq)); |
511 | |
512 | usleep_range(CS35L56_WAKE_HOLD_TIME_US, max: 2 * CS35L56_WAKE_HOLD_TIME_US); |
513 | |
514 | regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, |
515 | regs: cs35l56_hibernate_wake_seq, |
516 | ARRAY_SIZE(cs35l56_hibernate_wake_seq)); |
517 | |
518 | cs35l56_wait_control_port_ready(); |
519 | } |
520 | |
521 | int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base) |
522 | { |
523 | unsigned int val; |
524 | int ret; |
525 | |
526 | if (!cs35l56_base->init_done) |
527 | return 0; |
528 | |
529 | /* Firmware must have entered a power-save state */ |
530 | ret = regmap_read_poll_timeout(cs35l56_base->regmap, |
531 | CS35L56_TRANSDUCER_ACTUAL_PS, |
532 | val, (val >= CS35L56_PS3), |
533 | CS35L56_PS3_POLL_US, |
534 | CS35L56_PS3_TIMEOUT_US); |
535 | if (ret) |
536 | dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n" , ret); |
537 | |
538 | /* Clear BOOT_DONE so it can be used to detect a reboot */ |
539 | regmap_write(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); |
540 | |
541 | if (!cs35l56_base->can_hibernate) { |
542 | regcache_cache_only(map: cs35l56_base->regmap, enable: true); |
543 | dev_dbg(cs35l56_base->dev, "Suspended: no hibernate" ); |
544 | |
545 | return 0; |
546 | } |
547 | |
548 | /* |
549 | * Must enter cache-only first so there can't be any more register |
550 | * accesses other than the controlled hibernate sequence below. |
551 | */ |
552 | regcache_cache_only(map: cs35l56_base->regmap, enable: true); |
553 | |
554 | regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, |
555 | regs: cs35l56_hibernate_seq, |
556 | ARRAY_SIZE(cs35l56_hibernate_seq)); |
557 | |
558 | dev_dbg(cs35l56_base->dev, "Suspended: hibernate" ); |
559 | |
560 | return 0; |
561 | } |
562 | EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED); |
563 | |
564 | int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire) |
565 | { |
566 | unsigned int val; |
567 | int ret; |
568 | |
569 | if (!cs35l56_base->init_done) |
570 | return 0; |
571 | |
572 | if (!cs35l56_base->can_hibernate) |
573 | goto out_sync; |
574 | |
575 | /* Must be done before releasing cache-only */ |
576 | if (!is_soundwire) |
577 | cs35l56_issue_wake_event(cs35l56_base); |
578 | |
579 | out_sync: |
580 | regcache_cache_only(map: cs35l56_base->regmap, enable: false); |
581 | |
582 | ret = cs35l56_wait_for_firmware_boot(cs35l56_base); |
583 | if (ret) { |
584 | dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n" , ret); |
585 | goto err; |
586 | } |
587 | |
588 | ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); |
589 | if (ret) |
590 | goto err; |
591 | |
592 | /* BOOT_DONE will be 1 if the amp reset */ |
593 | regmap_read(map: cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, val: &val); |
594 | if (val & CS35L56_OTP_BOOT_DONE_MASK) { |
595 | dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n" ); |
596 | regcache_mark_dirty(map: cs35l56_base->regmap); |
597 | } |
598 | |
599 | regcache_sync(map: cs35l56_base->regmap); |
600 | |
601 | dev_dbg(cs35l56_base->dev, "Resumed" ); |
602 | |
603 | return 0; |
604 | |
605 | err: |
606 | regcache_cache_only(map: cs35l56_base->regmap, enable: true); |
607 | |
608 | regmap_multi_reg_write_bypassed(map: cs35l56_base->regmap, |
609 | regs: cs35l56_hibernate_seq, |
610 | ARRAY_SIZE(cs35l56_hibernate_seq)); |
611 | |
612 | return ret; |
613 | } |
614 | EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED); |
615 | |
616 | static const struct cs_dsp_region cs35l56_dsp1_regions[] = { |
617 | { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, |
618 | { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, |
619 | { .type = WMFW_HALO_YM_PACKED, .base = CS35L56_DSP1_YMEM_PACKED_0 }, |
620 | { .type = WMFW_ADSP2_XM, .base = CS35L56_DSP1_XMEM_UNPACKED24_0 }, |
621 | { .type = WMFW_ADSP2_YM, .base = CS35L56_DSP1_YMEM_UNPACKED24_0 }, |
622 | }; |
623 | |
624 | void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp) |
625 | { |
626 | cs_dsp->num = 1; |
627 | cs_dsp->type = WMFW_HALO; |
628 | cs_dsp->rev = 0; |
629 | cs_dsp->dev = cs35l56_base->dev; |
630 | cs_dsp->regmap = cs35l56_base->regmap; |
631 | cs_dsp->base = CS35L56_DSP1_CORE_BASE; |
632 | cs_dsp->base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; |
633 | cs_dsp->mem = cs35l56_dsp1_regions; |
634 | cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); |
635 | cs_dsp->no_core_startstop = true; |
636 | } |
637 | EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED); |
638 | |
639 | struct cs35l56_pte { |
640 | u8 x; |
641 | u8 wafer_id; |
642 | u8 pte[2]; |
643 | u8 lot[3]; |
644 | u8 y; |
645 | u8 unused[3]; |
646 | u8 dvs; |
647 | } __packed; |
648 | static_assert((sizeof(struct cs35l56_pte) % sizeof(u32)) == 0); |
649 | |
650 | static int cs35l56_read_silicon_uid(struct cs35l56_base *cs35l56_base, u64 *uid) |
651 | { |
652 | struct cs35l56_pte pte; |
653 | u64 unique_id; |
654 | int ret; |
655 | |
656 | ret = regmap_raw_read(map: cs35l56_base->regmap, CS35L56_OTP_MEM_53, val: &pte, val_len: sizeof(pte)); |
657 | if (ret) { |
658 | dev_err(cs35l56_base->dev, "Failed to read OTP: %d\n" , ret); |
659 | return ret; |
660 | } |
661 | |
662 | unique_id = (u32)pte.lot[2] | ((u32)pte.lot[1] << 8) | ((u32)pte.lot[0] << 16); |
663 | unique_id <<= 32; |
664 | unique_id |= (u32)pte.x | ((u32)pte.y << 8) | ((u32)pte.wafer_id << 16) | |
665 | ((u32)pte.dvs << 24); |
666 | |
667 | dev_dbg(cs35l56_base->dev, "UniqueID = %#llx\n" , unique_id); |
668 | |
669 | *uid = unique_id; |
670 | |
671 | return 0; |
672 | } |
673 | |
674 | /* Firmware calibration controls */ |
675 | const struct cirrus_amp_cal_controls cs35l56_calibration_controls = { |
676 | .alg_id = 0x9f210, |
677 | .mem_region = WMFW_ADSP2_YM, |
678 | .ambient = "CAL_AMBIENT" , |
679 | .calr = "CAL_R" , |
680 | .status = "CAL_STATUS" , |
681 | .checksum = "CAL_CHECKSUM" , |
682 | }; |
683 | EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED); |
684 | |
685 | int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base) |
686 | { |
687 | u64 silicon_uid; |
688 | int ret; |
689 | |
690 | /* Driver can't apply calibration to a secured part, so skip */ |
691 | if (cs35l56_base->secured) |
692 | return 0; |
693 | |
694 | ret = cs35l56_read_silicon_uid(cs35l56_base, uid: &silicon_uid); |
695 | if (ret < 0) |
696 | return ret; |
697 | |
698 | ret = cs_amp_get_efi_calibration_data(dev: cs35l56_base->dev, target_uid: silicon_uid, |
699 | amp_index: cs35l56_base->cal_index, |
700 | out_data: &cs35l56_base->cal_data); |
701 | |
702 | /* Only return an error status if probe should be aborted */ |
703 | if ((ret == -ENOENT) || (ret == -EOVERFLOW)) |
704 | return 0; |
705 | |
706 | if (ret < 0) |
707 | return ret; |
708 | |
709 | cs35l56_base->cal_data_valid = true; |
710 | |
711 | return 0; |
712 | } |
713 | EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, SND_SOC_CS35L56_SHARED); |
714 | |
715 | int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, |
716 | bool *fw_missing, unsigned int *fw_version) |
717 | { |
718 | unsigned int prot_status; |
719 | int ret; |
720 | |
721 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, val: &prot_status); |
722 | if (ret) { |
723 | dev_err(cs35l56_base->dev, "Get PROTECTION_STATUS failed: %d\n" , ret); |
724 | return ret; |
725 | } |
726 | |
727 | *fw_missing = !!(prot_status & CS35L56_FIRMWARE_MISSING); |
728 | |
729 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_DSP1_FW_VER, val: fw_version); |
730 | if (ret) { |
731 | dev_err(cs35l56_base->dev, "Get FW VER failed: %d\n" , ret); |
732 | return ret; |
733 | } |
734 | |
735 | return 0; |
736 | } |
737 | EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, SND_SOC_CS35L56_SHARED); |
738 | |
739 | int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) |
740 | { |
741 | int ret; |
742 | unsigned int devid, revid, otpid, secured, fw_ver; |
743 | bool fw_missing; |
744 | |
745 | /* |
746 | * When the system is not using a reset_gpio ensure the device is |
747 | * awake, otherwise the device has just been released from reset and |
748 | * the driver must wait for the control port to become usable. |
749 | */ |
750 | if (!cs35l56_base->reset_gpio) |
751 | cs35l56_issue_wake_event(cs35l56_base); |
752 | else |
753 | cs35l56_wait_control_port_ready(); |
754 | |
755 | /* |
756 | * The HALO_STATE register is in different locations on Ax and B0 |
757 | * devices so the REVID needs to be determined before waiting for the |
758 | * firmware to boot. |
759 | */ |
760 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_REVID, val: &revid); |
761 | if (ret < 0) { |
762 | dev_err(cs35l56_base->dev, "Get Revision ID failed\n" ); |
763 | return ret; |
764 | } |
765 | cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); |
766 | |
767 | ret = cs35l56_wait_for_firmware_boot(cs35l56_base); |
768 | if (ret) |
769 | return ret; |
770 | |
771 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_DEVID, val: &devid); |
772 | if (ret < 0) { |
773 | dev_err(cs35l56_base->dev, "Get Device ID failed\n" ); |
774 | return ret; |
775 | } |
776 | devid &= CS35L56_DEVID_MASK; |
777 | |
778 | switch (devid) { |
779 | case 0x35A54: |
780 | case 0x35A56: |
781 | case 0x35A57: |
782 | break; |
783 | default: |
784 | dev_err(cs35l56_base->dev, "Unknown device %x\n" , devid); |
785 | return ret; |
786 | } |
787 | |
788 | cs35l56_base->type = devid & 0xFF; |
789 | |
790 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, val: &secured); |
791 | if (ret) { |
792 | dev_err(cs35l56_base->dev, "Get Secure status failed\n" ); |
793 | return ret; |
794 | } |
795 | |
796 | /* When any bus is restricted treat the device as secured */ |
797 | if (secured & CS35L56_RESTRICTED_MASK) |
798 | cs35l56_base->secured = true; |
799 | |
800 | ret = regmap_read(map: cs35l56_base->regmap, CS35L56_OTPID, val: &otpid); |
801 | if (ret < 0) { |
802 | dev_err(cs35l56_base->dev, "Get OTP ID failed\n" ); |
803 | return ret; |
804 | } |
805 | |
806 | ret = cs35l56_read_prot_status(cs35l56_base, &fw_missing, &fw_ver); |
807 | if (ret) |
808 | return ret; |
809 | |
810 | dev_info(cs35l56_base->dev, "Cirrus Logic CS35L%02X%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n" , |
811 | cs35l56_base->type, cs35l56_base->secured ? "s" : "" , cs35l56_base->rev, otpid, |
812 | fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing); |
813 | |
814 | /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ |
815 | regmap_write(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, val: 0xffffffff); |
816 | regmap_update_bits(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, |
817 | CS35L56_AMP_SHORT_ERR_EINT1_MASK, |
818 | val: 0); |
819 | regmap_update_bits(map: cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, |
820 | CS35L56_TEMP_ERR_EINT1_MASK, |
821 | val: 0); |
822 | |
823 | return 0; |
824 | } |
825 | EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED); |
826 | |
827 | int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base) |
828 | { |
829 | struct gpio_descs *descs; |
830 | int speaker_id; |
831 | int i, ret; |
832 | |
833 | /* Read the speaker type qualifier from the motherboard GPIOs */ |
834 | descs = gpiod_get_array_optional(dev: cs35l56_base->dev, con_id: "spk-id" , flags: GPIOD_IN); |
835 | if (!descs) { |
836 | return -ENOENT; |
837 | } else if (IS_ERR(ptr: descs)) { |
838 | ret = PTR_ERR(ptr: descs); |
839 | return dev_err_probe(dev: cs35l56_base->dev, err: ret, fmt: "Failed to get spk-id-gpios\n" ); |
840 | } |
841 | |
842 | speaker_id = 0; |
843 | for (i = 0; i < descs->ndescs; i++) { |
844 | ret = gpiod_get_value_cansleep(desc: descs->desc[i]); |
845 | if (ret < 0) { |
846 | dev_err_probe(dev: cs35l56_base->dev, err: ret, fmt: "Failed to read spk-id[%d]\n" , i); |
847 | goto err; |
848 | } |
849 | |
850 | speaker_id |= (ret << i); |
851 | } |
852 | |
853 | dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n" , speaker_id); |
854 | ret = speaker_id; |
855 | err: |
856 | gpiod_put_array(descs); |
857 | |
858 | return ret; |
859 | } |
860 | EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, SND_SOC_CS35L56_SHARED); |
861 | |
862 | static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { |
863 | [0x0C] = 128000, |
864 | [0x0F] = 256000, |
865 | [0x11] = 384000, |
866 | [0x12] = 512000, |
867 | [0x15] = 768000, |
868 | [0x17] = 1024000, |
869 | [0x1A] = 1500000, |
870 | [0x1B] = 1536000, |
871 | [0x1C] = 2000000, |
872 | [0x1D] = 2048000, |
873 | [0x1E] = 2400000, |
874 | [0x20] = 3000000, |
875 | [0x21] = 3072000, |
876 | [0x23] = 4000000, |
877 | [0x24] = 4096000, |
878 | [0x25] = 4800000, |
879 | [0x27] = 6000000, |
880 | [0x28] = 6144000, |
881 | [0x29] = 6250000, |
882 | [0x2A] = 6400000, |
883 | [0x2E] = 8000000, |
884 | [0x2F] = 8192000, |
885 | [0x30] = 9600000, |
886 | [0x32] = 12000000, |
887 | [0x33] = 12288000, |
888 | [0x37] = 13500000, |
889 | [0x38] = 19200000, |
890 | [0x39] = 22579200, |
891 | [0x3B] = 24576000, |
892 | }; |
893 | |
894 | int cs35l56_get_bclk_freq_id(unsigned int freq) |
895 | { |
896 | int i; |
897 | |
898 | if (freq == 0) |
899 | return -EINVAL; |
900 | |
901 | /* The BCLK frequency must be a valid PLL REFCLK */ |
902 | for (i = 0; i < ARRAY_SIZE(cs35l56_bclk_valid_for_pll_freq_table); ++i) { |
903 | if (cs35l56_bclk_valid_for_pll_freq_table[i] == freq) |
904 | return i; |
905 | } |
906 | |
907 | return -EINVAL; |
908 | } |
909 | EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, SND_SOC_CS35L56_SHARED); |
910 | |
911 | static const char * const cs35l56_supplies[/* auto-sized */] = { |
912 | "VDD_P" , |
913 | "VDD_IO" , |
914 | "VDD_A" , |
915 | }; |
916 | |
917 | void cs35l56_fill_supply_names(struct regulator_bulk_data *data) |
918 | { |
919 | int i; |
920 | |
921 | BUILD_BUG_ON(ARRAY_SIZE(cs35l56_supplies) != CS35L56_NUM_BULK_SUPPLIES); |
922 | for (i = 0; i < ARRAY_SIZE(cs35l56_supplies); i++) |
923 | data[i].supply = cs35l56_supplies[i]; |
924 | } |
925 | EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, SND_SOC_CS35L56_SHARED); |
926 | |
927 | const char * const cs35l56_tx_input_texts[] = { |
928 | "None" , "ASP1RX1" , "ASP1RX2" , "VMON" , "IMON" , "ERRVOL" , "CLASSH" , |
929 | "VDDBMON" , "VBSTMON" , "DSP1TX1" , "DSP1TX2" , "DSP1TX3" , "DSP1TX4" , |
930 | "DSP1TX5" , "DSP1TX6" , "DSP1TX7" , "DSP1TX8" , "TEMPMON" , |
931 | "INTERPOLATOR" , "SDW1RX1" , "SDW1RX2" , |
932 | }; |
933 | EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, SND_SOC_CS35L56_SHARED); |
934 | |
935 | const unsigned int cs35l56_tx_input_values[] = { |
936 | CS35L56_INPUT_SRC_NONE, |
937 | CS35L56_INPUT_SRC_ASP1RX1, |
938 | CS35L56_INPUT_SRC_ASP1RX2, |
939 | CS35L56_INPUT_SRC_VMON, |
940 | CS35L56_INPUT_SRC_IMON, |
941 | CS35L56_INPUT_SRC_ERR_VOL, |
942 | CS35L56_INPUT_SRC_CLASSH, |
943 | CS35L56_INPUT_SRC_VDDBMON, |
944 | CS35L56_INPUT_SRC_VBSTMON, |
945 | CS35L56_INPUT_SRC_DSP1TX1, |
946 | CS35L56_INPUT_SRC_DSP1TX2, |
947 | CS35L56_INPUT_SRC_DSP1TX3, |
948 | CS35L56_INPUT_SRC_DSP1TX4, |
949 | CS35L56_INPUT_SRC_DSP1TX5, |
950 | CS35L56_INPUT_SRC_DSP1TX6, |
951 | CS35L56_INPUT_SRC_DSP1TX7, |
952 | CS35L56_INPUT_SRC_DSP1TX8, |
953 | CS35L56_INPUT_SRC_TEMPMON, |
954 | CS35L56_INPUT_SRC_INTERPOLATOR, |
955 | CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL1, |
956 | CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL2, |
957 | }; |
958 | EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED); |
959 | |
960 | struct regmap_config cs35l56_regmap_i2c = { |
961 | .reg_bits = 32, |
962 | .val_bits = 32, |
963 | .reg_stride = 4, |
964 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
965 | .val_format_endian = REGMAP_ENDIAN_BIG, |
966 | .max_register = CS35L56_DSP1_PMEM_5114, |
967 | .reg_defaults = cs35l56_reg_defaults, |
968 | .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), |
969 | .volatile_reg = cs35l56_volatile_reg, |
970 | .readable_reg = cs35l56_readable_reg, |
971 | .precious_reg = cs35l56_precious_reg, |
972 | .cache_type = REGCACHE_MAPLE, |
973 | }; |
974 | EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); |
975 | |
976 | struct regmap_config cs35l56_regmap_spi = { |
977 | .reg_bits = 32, |
978 | .val_bits = 32, |
979 | .pad_bits = 16, |
980 | .reg_stride = 4, |
981 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
982 | .val_format_endian = REGMAP_ENDIAN_BIG, |
983 | .max_register = CS35L56_DSP1_PMEM_5114, |
984 | .reg_defaults = cs35l56_reg_defaults, |
985 | .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), |
986 | .volatile_reg = cs35l56_volatile_reg, |
987 | .readable_reg = cs35l56_readable_reg, |
988 | .precious_reg = cs35l56_precious_reg, |
989 | .cache_type = REGCACHE_MAPLE, |
990 | }; |
991 | EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); |
992 | |
993 | struct regmap_config cs35l56_regmap_sdw = { |
994 | .reg_bits = 32, |
995 | .val_bits = 32, |
996 | .reg_stride = 4, |
997 | .reg_format_endian = REGMAP_ENDIAN_LITTLE, |
998 | .val_format_endian = REGMAP_ENDIAN_BIG, |
999 | .max_register = CS35L56_DSP1_PMEM_5114, |
1000 | .reg_defaults = cs35l56_reg_defaults, |
1001 | .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), |
1002 | .volatile_reg = cs35l56_volatile_reg, |
1003 | .readable_reg = cs35l56_readable_reg, |
1004 | .precious_reg = cs35l56_precious_reg, |
1005 | .cache_type = REGCACHE_MAPLE, |
1006 | }; |
1007 | EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED); |
1008 | |
1009 | MODULE_DESCRIPTION("ASoC CS35L56 Shared" ); |
1010 | MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>" ); |
1011 | MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>" ); |
1012 | MODULE_LICENSE("GPL" ); |
1013 | MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); |
1014 | |