Lines Matching +full:ssi +full:- +full:all
1 // SPDX-License-Identifier: GPL-2.0
3 // Renesas R-Car SSIU/SSI support
13 * SSI interrupt status debug message when debugging
61 #define EN (1 << 0) /* SSI Module Enable */
77 #define SSI_NAME "ssi"
101 #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
107 ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \
110 #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
111 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
113 #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) argument
123 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_use_busif() local
129 if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF))) in rsnd_ssi_use_busif()
270 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_master_clk_start() local
292 if (ssi->usrcnt > 0) { in rsnd_ssi_master_clk_start()
293 if (ssi->rate != rate) { in rsnd_ssi_master_clk_start()
294 dev_err(dev, "SSI parent/child should use same rate\n"); in rsnd_ssi_master_clk_start()
295 return -EINVAL; in rsnd_ssi_master_clk_start()
298 if (ssi->chan != chan) { in rsnd_ssi_master_clk_start()
299 dev_err(dev, "SSI parent/child should use same chan\n"); in rsnd_ssi_master_clk_start()
300 return -EINVAL; in rsnd_ssi_master_clk_start()
309 return -EIO; in rsnd_ssi_master_clk_start()
317 * SSI clock will be output contiguously in rsnd_ssi_master_clk_start()
321 * for SSI parent in rsnd_ssi_master_clk_start()
326 ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | in rsnd_ssi_master_clk_start()
328 ssi->wsr = CONT; in rsnd_ssi_master_clk_start()
329 ssi->rate = rate; in rsnd_ssi_master_clk_start()
330 ssi->chan = chan; in rsnd_ssi_master_clk_start()
342 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_master_clk_stop() local
350 if (ssi->usrcnt > 1) in rsnd_ssi_master_clk_stop()
353 ssi->cr_clk = 0; in rsnd_ssi_master_clk_stop()
354 ssi->rate = 0; in rsnd_ssi_master_clk_stop()
355 ssi->chan = 0; in rsnd_ssi_master_clk_stop()
367 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_config_init() local
368 u32 cr_own = ssi->cr_own; in rsnd_ssi_config_init()
369 u32 cr_mode = ssi->cr_mode; in rsnd_ssi_config_init()
370 u32 wsr = ssi->wsr; in rsnd_ssi_config_init()
384 if (rdai->bit_clk_inv) in rsnd_ssi_config_init()
386 if (rdai->frm_clk_inv && !is_tdm) in rsnd_ssi_config_init()
388 if (rdai->data_alignment) in rsnd_ssi_config_init()
390 if (rdai->sys_delay) in rsnd_ssi_config_init()
414 width = snd_pcm_format_width(runtime->format); in rsnd_ssi_config_init()
417 * The SWL and DWL bits in SSICR should be fixed at 32-bit in rsnd_ssi_config_init()
448 ssi->cr_own = cr_own; in rsnd_ssi_config_init()
449 ssi->cr_mode = cr_mode; in rsnd_ssi_config_init()
450 ssi->wsr = wsr; in rsnd_ssi_config_init()
455 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_register_setup() local
457 rsnd_mod_write(mod, SSIWSR, ssi->wsr); in rsnd_ssi_register_setup()
458 rsnd_mod_write(mod, SSICR, ssi->cr_own | in rsnd_ssi_register_setup()
459 ssi->cr_clk | in rsnd_ssi_register_setup()
460 ssi->cr_mode | in rsnd_ssi_register_setup()
461 ssi->cr_en); in rsnd_ssi_register_setup()
465 * SSI mod common functions
471 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_init() local
481 ssi->usrcnt++; in rsnd_ssi_init()
501 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_quit() local
507 if (!ssi->usrcnt) { in rsnd_ssi_quit()
509 return -EIO; in rsnd_ssi_quit()
516 ssi->usrcnt--; in rsnd_ssi_quit()
518 if (!ssi->usrcnt) { in rsnd_ssi_quit()
519 ssi->cr_own = 0; in rsnd_ssi_quit()
520 ssi->cr_mode = 0; in rsnd_ssi_quit()
521 ssi->wsr = 0; in rsnd_ssi_quit()
535 if (fmt_width > rdai->chan_width) { in rsnd_ssi_hw_params()
539 dev_err(dev, "invalid combination of slot-width and format-data-width\n"); in rsnd_ssi_hw_params()
540 return -EINVAL; in rsnd_ssi_hw_params()
550 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_start() local
564 * SSI parent EN is not needed. in rsnd_ssi_start()
569 ssi->cr_en = EN; in rsnd_ssi_start()
571 rsnd_mod_write(mod, SSICR, ssi->cr_own | in rsnd_ssi_start()
572 ssi->cr_clk | in rsnd_ssi_start()
573 ssi->cr_mode | in rsnd_ssi_start()
574 ssi->cr_en); in rsnd_ssi_start()
583 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_stop() local
592 cr = ssi->cr_own | in rsnd_ssi_stop()
593 ssi->cr_clk; in rsnd_ssi_stop()
596 * disable all IRQ, in rsnd_ssi_stop()
597 * Playback: Wait all data was sent in rsnd_ssi_stop()
601 rsnd_mod_write(mod, SSICR, cr | ssi->cr_en); in rsnd_ssi_stop()
605 /* In multi-SSI mode, stop is performed by setting ssi0129 in in rsnd_ssi_stop()
612 * disable SSI, in rsnd_ssi_stop()
615 rsnd_mod_write(mod, SSICR, cr); /* disabled all */ in rsnd_ssi_stop()
618 ssi->cr_en = 0; in rsnd_ssi_stop()
677 spin_lock(&priv->lock); in __rsnd_ssi_interrupt()
679 /* ignore all cases if not working */ in __rsnd_ssi_interrupt()
701 spin_unlock(&priv->lock); in __rsnd_ssi_interrupt()
707 snd_pcm_stop_xrun(io->substream); in __rsnd_ssi_interrupt()
725 * SSIP (= SSI parent) needs to be special, otherwise, in rsnd_ssi_get_status()
726 * 2nd SSI might doesn't start. see also rsnd_mod_call() in rsnd_ssi_get_status()
728 * We can't include parent SSI status on SSI, because we don't know in rsnd_ssi_get_status()
729 * how many SSI requests parent SSI. Thus, it is localed on "io" now. in rsnd_ssi_get_status()
734 * 1) start Capture -> SSI0/SSI1 are started. in rsnd_ssi_get_status()
735 * 2) start Playback -> SSI0 doesn't work, because it is already in rsnd_ssi_get_status()
741 * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 in rsnd_ssi_get_status()
743 * IO-1: SRC1 -> CTU2 -+ in rsnd_ssi_get_status()
745 * 1) start IO-0 -> start SSI0 in rsnd_ssi_get_status()
746 * 2) start IO-1 -> SSI0 doesn't need to start, because it is in rsnd_ssi_get_status()
750 return &io->parent_ssi_status; in rsnd_ssi_get_status()
756 * SSI PIO
807 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_common_probe() local
812 * SSI Multi secondaries in rsnd_ssi_common_probe()
818 * It can't judge ssi parent at this point in rsnd_ssi_common_probe()
823 * SSI might be called again as PIO fallback in rsnd_ssi_common_probe()
829 * mod->status. in rsnd_ssi_common_probe()
833 if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) { in rsnd_ssi_common_probe()
834 ret = request_irq(ssi->irq, in rsnd_ssi_common_probe()
839 rsnd_flags_set(ssi, RSND_SSI_PROBED); in rsnd_ssi_common_probe()
849 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_common_remove() local
852 /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ in rsnd_ssi_common_remove()
857 if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) { in rsnd_ssi_common_remove()
858 free_irq(ssi->irq, mod); in rsnd_ssi_common_remove()
860 rsnd_flags_del(ssi, RSND_SSI_PROBED); in rsnd_ssi_common_remove()
867 * SSI PIO functions
873 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_pio_interrupt() local
874 u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); in rsnd_ssi_pio_interrupt()
879 if (snd_pcm_format_width(runtime->format) == 24) in rsnd_ssi_pio_interrupt()
892 byte_pos = ssi->byte_pos + sizeof(*buf); in rsnd_ssi_pio_interrupt()
894 if (byte_pos >= ssi->next_period_byte) { in rsnd_ssi_pio_interrupt()
895 int period_pos = byte_pos / ssi->byte_per_period; in rsnd_ssi_pio_interrupt()
897 if (period_pos >= runtime->periods) { in rsnd_ssi_pio_interrupt()
902 ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; in rsnd_ssi_pio_interrupt()
907 WRITE_ONCE(ssi->byte_pos, byte_pos); in rsnd_ssi_pio_interrupt()
917 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_pio_init() local
920 ssi->byte_pos = 0; in rsnd_ssi_pio_init()
921 ssi->byte_per_period = runtime->period_size * in rsnd_ssi_pio_init()
922 runtime->channels * in rsnd_ssi_pio_init()
924 ssi->next_period_byte = ssi->byte_per_period; in rsnd_ssi_pio_init()
934 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_pio_pointer() local
937 *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos)); in rsnd_ssi_pio_pointer()
965 * SSI Multi secondaries in rsnd_ssi_dma_probe()
974 /* SSI probe might be called many times in MUX multi path */ in rsnd_ssi_dma_probe()
975 ret = rsnd_dma_attach(io, mod, &io->dma); in rsnd_ssi_dma_probe()
989 * SSI .probe might be called again. in rsnd_ssi_fallback()
993 mod->ops = &rsnd_ssi_pio_ops; in rsnd_ssi_fallback()
1012 * If not, "rcar_sound.ssi" will be used. in rsnd_ssi_dma_req()
1033 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); in rsnd_ssi_debug_info() local
1037 seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); in rsnd_ssi_debug_info()
1038 seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); in rsnd_ssi_debug_info()
1044 seq_printf(m, "chan: %d\n", ssi->chan); in rsnd_ssi_debug_info()
1045 seq_printf(m, "user: %d\n", ssi->usrcnt); in rsnd_ssi_debug_info()
1074 return mod->ops == &rsnd_ssi_dma_ops; in rsnd_ssi_is_dma_mode()
1078 * ssi mod function
1093 /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ in rsnd_ssi_connect()
1132 rsnd_ssi_connect(mod, &rdai->playback); in rsnd_parse_connect_ssi()
1134 rsnd_ssi_connect(mod, &rdai->capture); in rsnd_parse_connect_ssi()
1164 struct rsnd_ssi *ssi; in rsnd_ssi_probe() local
1170 return -EINVAL; in rsnd_ssi_probe()
1174 ret = -EINVAL; in rsnd_ssi_probe()
1178 ssi = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL); in rsnd_ssi_probe()
1179 if (!ssi) { in rsnd_ssi_probe()
1180 ret = -ENOMEM; in rsnd_ssi_probe()
1184 priv->ssi = ssi; in rsnd_ssi_probe()
1185 priv->ssi_nr = nr; in rsnd_ssi_probe()
1194 ret = -EINVAL; in rsnd_ssi_probe()
1199 ssi = rsnd_ssi_get(priv, i); in rsnd_ssi_probe()
1211 if (of_get_property(np, "shared-pin", NULL)) in rsnd_ssi_probe()
1212 rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); in rsnd_ssi_probe()
1214 if (of_get_property(np, "no-busif", NULL)) in rsnd_ssi_probe()
1215 rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF); in rsnd_ssi_probe()
1217 ssi->irq = irq_of_parse_and_map(np, 0); in rsnd_ssi_probe()
1218 if (!ssi->irq) { in rsnd_ssi_probe()
1219 ret = -EINVAL; in rsnd_ssi_probe()
1224 if (of_property_read_bool(np, "pio-transfer")) in rsnd_ssi_probe()
1229 ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, in rsnd_ssi_probe()
1249 struct rsnd_ssi *ssi; in rsnd_ssi_remove() local
1252 for_each_rsnd_ssi(ssi, priv, i) { in rsnd_ssi_remove()
1253 rsnd_mod_quit(rsnd_mod_get(ssi)); in rsnd_ssi_remove()