Skip to content

Commit 8a731fd

Browse files
simontrimmerbroonie
authored andcommitted
ASoC: cs35l56: Move utility functions to shared file
Move the cs35l56 utility functions into the shared file so they are available for use in HDA. Signed-off-by: Simon Trimmer <simont@opensource.cirrus.com> Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Acked-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20230721132120.5523-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 0a2e492 commit 8a731fd

File tree

3 files changed

+215
-203
lines changed

3 files changed

+215
-203
lines changed

include/sound/cs35l56.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
274274
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
275275

276276
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
277+
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
278+
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
279+
void cs35l56_wait_min_reset_pulse(void);
280+
void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire);
281+
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
282+
irqreturn_t cs35l56_irq(int irq, void *data);
283+
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
277284
int cs35l56_get_bclk_freq_id(unsigned int freq);
278285
void cs35l56_fill_supply_names(struct regulator_bulk_data *data);
279286

sound/soc/codecs/cs35l56-shared.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,214 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
195195
}
196196
}
197197

198+
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
199+
{
200+
unsigned int val;
201+
int ret;
202+
203+
regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
204+
ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
205+
val, (val == 0),
206+
CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
207+
if (ret) {
208+
dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
209+
return ret;
210+
}
211+
212+
return 0;
213+
}
214+
EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
215+
216+
int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
217+
{
218+
unsigned int reg;
219+
unsigned int val;
220+
int ret;
221+
222+
if (cs35l56_base->rev < CS35L56_REVID_B0)
223+
reg = CS35L56_DSP1_HALO_STATE_A1;
224+
else
225+
reg = CS35L56_DSP1_HALO_STATE;
226+
227+
ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
228+
val,
229+
(val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
230+
CS35L56_HALO_STATE_POLL_US,
231+
CS35L56_HALO_STATE_TIMEOUT_US);
232+
233+
if ((ret < 0) && (ret != -ETIMEDOUT)) {
234+
dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret);
235+
return ret;
236+
}
237+
238+
if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
239+
dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
240+
return -EIO;
241+
}
242+
243+
return 0;
244+
}
245+
EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED);
246+
247+
void cs35l56_wait_min_reset_pulse(void)
248+
{
249+
/* Satisfy minimum reset pulse width spec */
250+
usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
251+
}
252+
EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
253+
254+
static const struct reg_sequence cs35l56_system_reset_seq[] = {
255+
REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
256+
};
257+
258+
void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
259+
{
260+
/*
261+
* Must enter cache-only first so there can't be any more register
262+
* accesses other than the controlled system reset sequence below.
263+
*/
264+
regcache_cache_only(cs35l56_base->regmap, true);
265+
regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
266+
cs35l56_system_reset_seq,
267+
ARRAY_SIZE(cs35l56_system_reset_seq));
268+
269+
/* On SoundWire the registers won't be accessible until it re-enumerates. */
270+
if (is_soundwire)
271+
return;
272+
273+
usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
274+
regcache_cache_only(cs35l56_base->regmap, false);
275+
}
276+
EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED);
277+
278+
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
279+
{
280+
int ret;
281+
282+
if (!irq)
283+
return 0;
284+
285+
ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
286+
IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
287+
"cs35l56", cs35l56_base);
288+
if (!ret)
289+
cs35l56_base->irq = irq;
290+
else
291+
dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
292+
293+
return ret;
294+
}
295+
EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED);
296+
297+
irqreturn_t cs35l56_irq(int irq, void *data)
298+
{
299+
struct cs35l56_base *cs35l56_base = data;
300+
unsigned int status1 = 0, status8 = 0, status20 = 0;
301+
unsigned int mask1, mask8, mask20;
302+
unsigned int val;
303+
int rv;
304+
305+
irqreturn_t ret = IRQ_NONE;
306+
307+
if (!cs35l56_base->init_done)
308+
return IRQ_NONE;
309+
310+
mutex_lock(&cs35l56_base->irq_lock);
311+
312+
rv = pm_runtime_resume_and_get(cs35l56_base->dev);
313+
if (rv < 0) {
314+
dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
315+
goto err_unlock;
316+
}
317+
318+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
319+
if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
320+
dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
321+
goto err;
322+
}
323+
324+
/* Ack interrupts */
325+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
326+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
327+
status1 &= ~mask1;
328+
regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);
329+
330+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
331+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
332+
status8 &= ~mask8;
333+
regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);
334+
335+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
336+
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
337+
status20 &= ~mask20;
338+
/* We don't want EINT20 but they default to unmasked: force mask */
339+
regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
340+
341+
dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);
342+
343+
/* Check to see if unmasked bits are active */
344+
if (!status1 && !status8 && !status20)
345+
goto err;
346+
347+
if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
348+
dev_crit(cs35l56_base->dev, "Amp short error\n");
349+
350+
if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
351+
dev_crit(cs35l56_base->dev, "Overtemp error\n");
352+
353+
ret = IRQ_HANDLED;
354+
355+
err:
356+
pm_runtime_put(cs35l56_base->dev);
357+
err_unlock:
358+
mutex_unlock(&cs35l56_base->irq_lock);
359+
360+
return ret;
361+
}
362+
EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED);
363+
364+
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
365+
{
366+
unsigned int val;
367+
int ret;
368+
369+
/* Nothing to re-patch if we haven't done any patching yet. */
370+
if (!cs35l56_base->fw_patched)
371+
return false;
372+
373+
/*
374+
* If we have control of RESET we will have asserted it so the firmware
375+
* will need re-patching.
376+
*/
377+
if (cs35l56_base->reset_gpio)
378+
return true;
379+
380+
/*
381+
* In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
382+
* can't be used here to test for memory retention.
383+
* Assume that tuning must be re-loaded.
384+
*/
385+
if (cs35l56_base->secured)
386+
return true;
387+
388+
ret = pm_runtime_resume_and_get(cs35l56_base->dev);
389+
if (ret) {
390+
dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret);
391+
return ret;
392+
}
393+
394+
ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val);
395+
if (ret)
396+
dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
397+
else
398+
ret = !!(val & CS35L56_FIRMWARE_MISSING);
399+
400+
pm_runtime_put_autosuspend(cs35l56_base->dev);
401+
402+
return ret;
403+
}
404+
EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED);
405+
198406
const struct cs_dsp_region cs35l56_dsp1_regions[] = {
199407
{ .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 },
200408
{ .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 },

0 commit comments

Comments
 (0)