Introduce new DAI driver used for NXP's PDM MICFIL IP.
This block implements required digital interface to provide
a 24-bits audio signal from a PDM microphone bitstream in a configurable
output sampling rate.
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
We use the name cell at a given index to retrieve
a clock's id.
But not all clocks provide a name cell, so use 0x0 as clock-id
for these situations.
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
IRQs are currently only enabled during the driver
initialization function (i.e: sai_init()). As such,
even though they're not needed (i.e: after a TRIGGER_STOP
operation) they remain enabled. Fix this by enabling IRQs
after during the TRIGGER_START operation and disabling them
during the TRIGGER_STOP operation.
This change is required by irq chips (i.e: irqsteer) which
perform PM operations during irq_enable()/irq_disable(). If
interrupts are left enabled all the time that means the irq
chip's PM resources might also remain enabled.
To make this change possible, the irq will have to be stored
inside the SAI's configuration structure.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
TX/RX FIFO underrun shouldn't crash the RTOS when it occurs.
Also, since this can also happen under "normal" conditions
(i.e: DMA doesn't copy data fast enough from/to SAI's FIFOs)
the software should be able to recover from it.
As such:
1) Remove `z_irq_spurious()` call.
2) Clear error flag
3) De-escalate error message to warning message
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
The ESAI is already reset during the config_set() function
so no need to also reset it during init().
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
While running the following command:
aplay ... | arecord ...
multiple times, it was discovered that the SAI transmit
FIFO goes into underrun. This only happened in the
beginning, a few BCLK cycles after unmasking the transmit
data line. With the following flow:
1) Trigger start on RX
a) Do TX and RX software reset
b) Enable RX FIFO error interrupt
c) Enable RX DMA requests
d) Enable receive data line
e) Enable transmitter
f) Enable receiver
..... some time has passed .....
2) Trigger start on TX
a) Enable DMA requests
b) Enable transmit data line
and configuration in mind:
1) RX is SYNC with TX
2) TX is ASYNC
3) Each FSYNC edge is 32-bit wide
4) Each frame contains 2 32-bit words
this points to the following possibilites:
1) The transmitter is enabled so close to the
start of a new frame that even though the DMA requests
are asserted, the DMAC doesn't have enough time
to service them until the module goes into underrun
=> the timing is bad.
2) The transmitter is enabled somewhat close to
the start of a new frame such that the DMAC is not
fast enough to service the module until it goes into
underrun => DMAC is too slow AND the timing is bad.
Although the exact cause was not pinpointed, this patch
aims to fix the problem by writing a frame's worth of 0s
in the transmit FIFO. This way, even if we're dealing with
scenario 1) or 2), the DMAC has plenty of time to perform
the transfer (i.e: a frame), thus avoiding the underrun.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
Add support for performing pinctrl operations. For now,
the only supported operation is applying the pinctrl default
state. Pinctrl is left optional to allow for scenarios in which
this is not required (e.g: AMP system in which another
OS configures the pinctrl).
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
Some SAI instances are mutliline, meaning they can have multiple
TX/RX data lines (channels). Depending on the board, the index
of the TX/RX data lines that are connected to the consumer
(e.g: the codec) may not always be 0. This commit fixes this
issue by adding support for passing the index of the used
TX/RX data lines through the DTS.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
Since a DMA cell now allows specifying a channel and a MUX value
there's no need to fetch these values from the HAL. This, in turn,
allows for more flexibility and reduces the coding effort for new
platforms that want to use the SAI driver.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
Using the address of RDR/TDR for fifo base address computation
has the same effect as using the FSL_FEATURE_SAI_{TX/RX}_FIFO_BASEn
macro from NXP HAL. The only difference between the two is that
the macro is not defined for all SoCs so whenever we introduce
a new SoC that uses the SAI module we have to also introduce
the macro for said SoC. Using TDR/RDR has the advantage that
it doesn't require any additional changes to the NXP HAL.
Since we only support one data line per direction, it's fine
to just use RDR[0] and TDR[0] for the address computation.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
Currently, whenever performing TRIGGER_PAUSE operation, the
data line is not disabled. This works well if TX and RX don't
operate at the same time or they operate in ASYNC-ASYNC mode. This
is because sai_tx_rx_disable() will disable transmitter/receiver
all the time since there's no dependencies to take into consideration.
However, in the ASYNC-SYNC mode, sai_tx_rx_disable() may not disable
the current asynchronous side if the synchronous side is still enabled.
As a consequence, the asynchronous side will remain enabled, thus
leading to an underrun/overrun.
To fix this issue, sai_trigger_pause() should disable the data line
each time it's called. This way, even if sai_tx_rx_disable() doesn't
disable the current direction, the data line will be disabled, thus
stopping the consumption/production of frames.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
It might happens that DT(_INST)_PROP_OR is used with boolean properties.
For instance:
.single_wire = DT_INST_PROP_OR(index, single_wire, false), \
.tx_rx_swap = DT_INST_PROP_OR(index, tx_rx_swap, false), \
This is not required as boolean properties are generated with false
value when not present, so the _OR macro extension is superflous
and the above code can be replaced by:
.single_wire = DT_INST_PROP(index, single_wire), \
.tx_rx_swap = DT_INST_PROP(index, tx_rx_swap), \
Signed-off-by: Roman Studenikin <srv@meta.com>
ERRATA 051421 states that if the SAI is FSYNC/BCLK master,
one of the directions is SYNC with the other, and the
ASYNC direction has the BYP bit toggled, the SYNC direction's
BCLK won't be generated properly.
This commit fixes this issue by enabling BCI for the SYNC
direction. What this does is it makes the SYNC direction use
the BCLK from the ASYNC direction's pad, which, if the BYP
bit is toggled, will be the undivided MCLK. Without this fix,
the SYNC direction will use the ASYNC direction's BCLK obtained
by dividing the MCLK via the following formula: MCLK / ((DIV + 1) * 2).
This is wrong because the ASYNC direction will use an undivided
MCLK while the SYNC direction will use a divided MCLK.
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
With the introduction of the "rx_sync_mode" and "tx_sync_mode"
properties, the user may choose which synchronization mode the
SAI should use. To support this, the code had to be changed a
bit such that the software reset and the disable operations
work on all synchronization modes.
What this commit does, is it changes the software reset and
disable sequences such that they work with any of the
supported synchronization modes. Also, the syncMode field
of sai_transceiver_t structure is set to the value passed
from the DTS during sai_config_set().
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
In preparation for supporting all synchronization modes, this
commit introduces the rx_sync_mode/tx_sync_mode DTS properties.
Using these, the user will be able to specify which synchronization
mode the SAI should use.
At the moment, the driver does nothing with the values from
said properties but still checks if their values are sane
(i.e: it checks if the directions are both in SYNC mode which
is forbidden). By default, if "rx_sync_mode" or "tx_sync_mode"
is not specified, the direction will be set to ASYNC mode.
As such, below one may find a couple of valid examples
depicting this idea:
tx_sync_mode = <0>;
rx_sync_mode = <0>;
is the same as not specifying any of the properties,
tx_sync_mode = <1>;
rx_sync_mode = <0>;
is the same as:
tx_sync_mode = <1>;
Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>