// SPDX-License-Identifier: GPL-2.0 // // Renesas R-Car SSIU/SSI support // // Copyright (C) 2013 Renesas Solutions Corp. // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> // // Based on fsi.c // Kuninori Morimoto <morimoto.kuninori@renesas.com>
/* * you can enable below define if you don't need * SSI interrupt status debug message when debugging * see rsnd_print_irq_status() * * #define RSND_DEBUG_NO_IRQ_STATUS 1
*/
/* * SSICR
*/ #define FORCE (1u << 31) /* Fixed */ #define DMEN (1u << 28) /* DMA Enable */ #define UIEN (1u << 27) /* Underflow Interrupt Enable */ #define OIEN (1u << 26) /* Overflow Interrupt Enable */ #define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ #define DIEN (1u << 24) /* Data Interrupt Enable */ #define CHNL_4 (1u << 22) /* Channels */ #define CHNL_6 (2u << 22) /* Channels */ #define CHNL_8 (3u << 22) /* Channels */ #define DWL_MASK (7u << 19) /* Data Word Length mask */ #define DWL_8 (0u << 19) /* Data Word Length */ #define DWL_16 (1u << 19) /* Data Word Length */ #define DWL_18 (2u << 19) /* Data Word Length */ #define DWL_20 (3u << 19) /* Data Word Length */ #define DWL_22 (4u << 19) /* Data Word Length */ #define DWL_24 (5u << 19) /* Data Word Length */ #define DWL_32 (6u << 19) /* Data Word Length */
/* * System word length
*/ #define SWL_16 (1 << 16) /* R/W System Word Length */ #define SWL_24 (2 << 16) /* R/W System Word Length */ #define SWL_32 (3 << 16) /* R/W System Word Length */
#define SCKD (1 << 15) /* Serial Bit Clock Direction */ #define SWSD (1 << 14) /* Serial WS Direction */ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ #define SWSP (1 << 12) /* Serial WS Polarity */ #define SDTA (1 << 10) /* Serial Data Alignment */ #define PDTA (1 << 9) /* Parallel Data Alignment */ #define DEL (1 << 8) /* Serial Data Delay */ #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ #define EN (1 << 0) /* SSI Module Enable */
/* * SSISR
*/ #define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ #define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ #define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ #define DIRQ (1 << 24) /* Data Interrupt Status Flag */
unsignedint rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx)
{ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); staticconstint ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12,
}; int j, ret; unsignedint main_rate; int width = rsnd_rdai_width_get(rdai);
for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
/* * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 * with it is not allowed. (SSIWSR.WS_MODE with * SSICR.CKDV = 000 is not allowed either). * Skip it. See SSICR.CKDV
*/ if (j == 0) continue;
/* * We shouldn't exchange SWSP after running. * This means, parent needs to care it.
*/ if (rsnd_ssi_is_parent(mod, io)) goto init_end;
if (rsnd_io_is_play(io))
cr_own |= TRMD;
cr_own &= ~DWL_MASK;
width = snd_pcm_format_width(runtime->format); if (is_tdm_split) { /* * The SWL and DWL bits in SSICR should be fixed at 32-bit * setting when TDM split mode. * see datasheet * Operation :: TDM Format Split Function (TDM Split Mode)
*/
width = 32;
}
switch (width) { case 8:
cr_own |= DWL_8; break; case 16:
cr_own |= DWL_16; break; case 24:
cr_own |= DWL_24; break; case 32:
cr_own |= DWL_32; break;
}
if (rsnd_ssi_is_dma_mode(mod)) {
cr_mode = UIEN | OIEN | /* over/under run */
DMEN; /* DMA : enable DMA */
} else {
cr_mode = DIEN; /* PIO : enable Data interrupt */
}
/* * disable all IRQ, * Playback: Wait all data was sent * Capture: It might not receave data. Do nothing
*/ if (rsnd_io_is_play(io)) {
rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
rsnd_ssi_status_check(mod, DIRQ);
}
/* In multi-SSI mode, stop is performed by setting ssi0129 in * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
*/ if (rsnd_ssi_multi_secondaries_runtime(io)) return 0;
/* * disable SSI, * and, wait idle state
*/
rsnd_mod_write(mod, SSICR, cr); /* disabled all */
rsnd_ssi_status_check(mod, IIRQ);
ssi->cr_en = 0;
return 0;
}
staticint rsnd_ssi_irq(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv, int enable)
{
u32 val = 0; int is_tdm, is_tdm_split; int id = rsnd_mod_id(mod);
static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type)
{ /* * SSIP (= SSI parent) needs to be special, otherwise, * 2nd SSI might doesn't start. see also rsnd_mod_call() * * We can't include parent SSI status on SSI, because we don't know * how many SSI requests parent SSI. Thus, it is localed on "io" now. * ex) trouble case * Playback: SSI0 * Capture : SSI1 (needs SSI0) * * 1) start Capture -> SSI0/SSI1 are started. * 2) start Playback -> SSI0 doesn't work, because it is already * marked as "started" on 1) * * OTOH, using each mod's status is good for MUX case. * It doesn't need to start in 2nd start * ex) * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 * | * IO-1: SRC1 -> CTU2 -+ * * 1) start IO-0 -> start SSI0 * 2) start IO-1 -> SSI0 doesn't need to start, because it is * already started on 1)
*/ if (type == RSND_MOD_SSIP) return &io->parent_ssi_status;
switch (rsnd_mod_id(mod)) { case 1: case 2: case 9:
rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); break; case 4:
rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); break; case 8:
rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); break;
}
}
staticint rsnd_ssi_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd)
{ /* * rsnd_rdai_is_clk_master() will be enabled after set_fmt, * and, pcm_new will be called after it. * This function reuse pcm_new at this point.
*/
rsnd_ssi_parent_attach(mod, io);
/* * SSIP/SSIU/IRQ are not needed on * SSI Multi secondaries
*/ if (rsnd_ssi_is_multi_secondary(mod, io)) return 0;
/* * It can't judge ssi parent at this point * see rsnd_ssi_pcm_new()
*/
/* * SSI might be called again as PIO fallback * It is easy to manual handling for IRQ request/free * * OTOH, this function might be called many times if platform is * using MIX. It needs xxx_attach() many times on xxx_probe(). * Because of it, we can't control .probe/.remove calling count by * mod->status. * But it don't need to call request_irq() many times. * Let's control it by RSND_SSI_PROBED flag.
*/ if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
ret = request_irq(ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
if (snd_pcm_format_width(runtime->format) == 24)
shift = 8;
/* * 8/16/32 data can be assesse to TDR/RDR register * directly as 32bit data * see rsnd_ssi_init()
*/ if (rsnd_io_is_play(io))
rsnd_mod_write(mod, SSITDR, (*buf) << shift); else
*buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
byte_pos = ssi->byte_pos + sizeof(*buf);
if (byte_pos >= ssi->next_period_byte) { int period_pos = byte_pos / ssi->byte_per_period;
/* * It should use "rcar_sound,ssiu" on DT. * But, we need to keep compatibility for old version. * * If it has "rcar_sound.ssiu", it will be used. * If not, "rcar_sound.ssi" will be used. * see * rsnd_ssiu_dma_req() * rsnd_dma_of_path()
*/
if (rsnd_ssi_use_busif(io))
name = is_play ? "rxu" : "txu"; else
name = is_play ? "rx" : "tx";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.