ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_ssie.c
Go to the documentation of this file.
1
25
26#include "ra8_ssie.h"
27
28#include <stdint.h>
29
30#include "ra8_attributes.h"
31#include "ra8_check.h"
32#include "ra8_dmac.h"
33#include "ra8_err.h"
34#include "ra8_hal_internal.h"
35#include "ra8_hw_err.h"
36#include "ra8_log.h"
37#include "ra8_mstp.h"
38#include "ra8_mstp_regs.h"
39#include "ra8_ssie_regs.h"
40
47static const char* s_tag = "SSIE";
48
62
74 {.tx_dma_channel = k_ra8_ssie_dma_ch_unused,
75 .rx_dma_channel = k_ra8_ssie_dma_ch_unused,
76 .initialized = false,
77 .dma_attached = false},
78 {.tx_dma_channel = k_ra8_ssie_dma_ch_unused,
79 .rx_dma_channel = k_ra8_ssie_dma_ch_unused,
80 .initialized = false,
81 .dma_attached = false},
82};
83
91
98static void* s_ssie_ctx;
99
102{
103 if ((uint16_t)channel >= k_ra8_ssie_channel_count) {
104 return nullptr;
105 }
106 return ra8_ssie(channel);
107}
108
133 uint8_t* out_omod,
134 uint8_t* out_frm,
135 uint8_t* out_pdta,
136 uint8_t* out_sdta)
137{
138 /* Defaults map to I2S (OMOD=00, FRM=00, PDTA=0, SDTA=0). */
139 *out_omod = k_ra8_ssie_omod_i2s;
140 *out_frm = k_ra8_ssie_frm_default;
141 *out_pdta = 0U;
142 *out_sdta = 0U;
143
144 switch (format) {
147 /* I2S and left-justified both map to OMOD=I2S with SDTA=0
148 * (already default). Shown in HUM Ch 46.3.1 "Stereo Format"
149 * Figures, p 3094-3096. */
150 return true;
152 /* Right-justified maps to OMOD=I2S with PDTA=1 (right-justify
153 * placement) per HUM Ch 46.2.1 "PDTA" p 3056. */
154 *out_pdta = 1U;
155 return true;
157 *out_omod = k_ra8_ssie_omod_monaural;
158 *out_frm = k_ra8_ssie_frm_default;
159 return true;
161 *out_omod = k_ra8_ssie_omod_tdm;
162 *out_frm = k_ra8_ssie_frm_alt1;
163 return true;
165 *out_omod = k_ra8_ssie_omod_tdm;
166 *out_frm = k_ra8_ssie_frm_alt2;
167 return true;
169 *out_omod = k_ra8_ssie_omod_tdm;
170 *out_frm = k_ra8_ssie_frm_alt3;
171 return true;
172 default:
173 return false;
174 }
175}
176
194static uint8_t internal_decode_event(uint32_t ssisr, uint32_t ssifsr)
195{
196 uint8_t events = k_ra8_ssie_evt_none;
197 if ((ssisr & k_ra8_ssie_mask_iirq) != 0U) {
198 events |= k_ra8_ssie_evt_idle;
199 }
200 if ((ssisr & k_ra8_ssie_mask_tuirq) != 0U) {
201 events |= k_ra8_ssie_evt_tx_under;
202 }
203 if ((ssisr & k_ra8_ssie_mask_toirq) != 0U) {
204 events |= k_ra8_ssie_evt_tx_over;
205 }
206 if ((ssisr & k_ra8_ssie_mask_ruirq) != 0U) {
207 events |= k_ra8_ssie_evt_rx_under;
208 }
209 if ((ssisr & k_ra8_ssie_mask_roirq) != 0U) {
210 events |= k_ra8_ssie_evt_rx_over;
211 }
212 if ((ssifsr & k_ra8_ssie_mask_tde) != 0U) {
213 events |= k_ra8_ssie_evt_tx_empty;
214 }
215 if ((ssifsr & k_ra8_ssie_mask_rdf) != 0U) {
216 events |= k_ra8_ssie_evt_rx_full;
217 }
218 return events;
219}
220
244static uint32_t
245internal_build_ssicr(const ra8_ssie_cfg_t* cfg, uint8_t frm, uint8_t pdta, uint8_t sdta)
246{
247 uint32_t ssicr = 0U;
248 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
249 if (cfg->role == k_ra8_ssie_role_controller) {
250 ssicr |= k_ra8_ssie_mask_mst;
251 }
252 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
253 ssicr |= ((uint32_t)cfg->bclk_div << k_ra8_ssie_bit_ckdv0) & k_ra8_ssie_mask_ckdv;
254 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
255 ssicr |= ((uint32_t)cfg->system_word << k_ra8_ssie_bit_swl0) & k_ra8_ssie_mask_swl;
256 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
257 ssicr |= ((uint32_t)cfg->data_word << k_ra8_ssie_bit_dwl0) & k_ra8_ssie_mask_dwl;
258 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
259 ssicr |= ((uint32_t)frm << k_ra8_ssie_bit_frm0) & k_ra8_ssie_mask_frm;
260 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
261 if (cfg->long_frame) {
262 ssicr |= k_ra8_ssie_mask_del;
263 }
264 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
265 if (pdta != 0U) {
266 ssicr |= k_ra8_ssie_mask_pdta;
267 }
268 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
269 if (sdta != 0U) {
270 ssicr |= k_ra8_ssie_mask_sdta;
271 }
272 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
273 if (cfg->spdp_high) {
274 ssicr |= k_ra8_ssie_mask_spdp;
275 }
276 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
277 if (cfg->lrckp_low) {
278 ssicr |= k_ra8_ssie_mask_lrckp;
279 }
280 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
281 if (cfg->bckp_rising) {
282 ssicr |= k_ra8_ssie_mask_bckp;
283 }
284 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3058 */
285 if (cfg->use_gpt_clk) {
286 ssicr |= k_ra8_ssie_mask_cks;
287 }
288 return ssicr;
289}
290
312{
313 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
314 return ra8_hw_wait_flag_clear32(&reg->SSIFCR,
316 (uint32_t)k_ra8_ssie_reset_poll_max);
317}
318
335{
336 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
337 return ra8_hw_wait_flag_clear32(&reg->SSIFCR,
339 (uint32_t)k_ra8_ssie_reset_poll_max);
340}
341
362static uint32_t internal_build_ssiofr(const ra8_ssie_cfg_t* cfg, uint8_t omod)
363{
364 uint32_t ssiofr = (uint32_t)omod & k_ra8_ssie_mask_omod;
365 if (cfg->lr_continue && cfg->role == k_ra8_ssie_role_controller) {
366 ssiofr |= k_ra8_ssie_mask_lrcont;
367 }
368 if (cfg->bck_idle_stop && cfg->role == k_ra8_ssie_role_controller && !cfg->lr_continue) {
369 ssiofr |= k_ra8_ssie_mask_bckastp;
370 }
371 return ssiofr;
372}
373
390static uint32_t internal_build_ssifcr(const ra8_ssie_cfg_t* cfg)
391{
392 uint32_t ssifcr = 0U;
393 if (cfg->byte_swap) {
394 ssifcr |= k_ra8_ssie_mask_bsw;
395 }
396 if (cfg->enable_aucke && cfg->role == k_ra8_ssie_role_controller) {
397 ssifcr |= k_ra8_ssie_mask_aucke;
398 }
399 return ssifcr;
400}
401
419static uint32_t internal_build_ssiscr(uint8_t tx_threshold, uint8_t rx_threshold)
420{
421 const uint32_t scr_tdes =
422 ((uint32_t)tx_threshold << k_ra8_ssie_shift_tdes) & k_ra8_ssie_mask_tdes;
423 const uint32_t scr_rdfs =
424 ((uint32_t)rx_threshold << k_ra8_ssie_shift_rdfs) & k_ra8_ssie_mask_rdfs;
425 return scr_tdes | scr_rdfs;
426}
427
447static ra8_err_t internal_pulse_fifo_reset(volatile r_ssie_regs_t* reg, uint32_t ssifcr_base)
448{
449 reg->SSIFCR = ssifcr_base | k_ra8_ssie_mask_rfrst_tfrst;
450 reg->SSIFCR = ssifcr_base;
452}
453
472static void internal_apply_dir_irq_bits(uint32_t desired_ren_ten, uint32_t* ssicr, uint32_t* ssifcr)
473{
474 if ((desired_ren_ten & k_ra8_ssie_mask_ten) != 0U) {
475 *ssicr |= k_ra8_ssie_mask_tuien;
476 *ssifcr |= k_ra8_ssie_mask_tie;
477 }
478 if ((desired_ren_ten & k_ra8_ssie_mask_ren) != 0U) {
479 *ssicr |= k_ra8_ssie_mask_roien;
480 *ssifcr |= k_ra8_ssie_mask_rie;
481 }
482}
483
507 uint8_t* out_omod,
508 uint8_t* out_frm,
509 uint8_t* out_pdta,
510 uint8_t* out_sdta)
511{
514 }
515 *out_omod = 0U;
516 *out_frm = 0U;
517 *out_pdta = 0U;
518 *out_sdta = 0U;
519 if (!internal_format_decode(cfg->format, out_omod, out_frm, out_pdta, out_sdta)) {
521 }
522 return k_ra8_ok;
523}
524
544{
546 reg->SSIFCR = 0U;
547 return internal_wait_ssirst_clear(reg);
548}
549
570static ra8_err_t internal_ssie_power_up(uint8_t channel, volatile r_ssie_regs_t* reg)
571{
572 const ra8_err_t mst_err = ra8_mstp_enable(s_ssie_mstp_table[channel]);
573 RA8_RETURN_ON_ERROR(mst_err, s_tag, "ssie_init: mstp enable");
574 const ra8_err_t rst_err = internal_pulse_ssi_reset(reg);
575 RA8_RETURN_ON_ERROR(rst_err, s_tag, "ssie_init: SSIRST stuck");
576 return k_ra8_ok;
577}
578
597static void internal_apply_init_regs(volatile r_ssie_regs_t* reg,
598 const ra8_ssie_cfg_t* cfg,
599 uint8_t frm,
600 uint8_t pdta,
601 uint8_t sdta,
602 uint8_t omod)
603{
604 reg->SSICR = internal_build_ssicr(cfg, frm, pdta, sdta);
605 reg->SSIOFR = internal_build_ssiofr(cfg, omod);
607 reg->SSIFCR = internal_build_ssifcr(cfg);
608}
609
610ra8_err_t ra8_ssie_init(uint8_t channel, const ra8_ssie_cfg_t* cfg)
611{
612 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
613 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
614 if (reg == nullptr) {
616 }
617
618 uint8_t omod = 0U;
619 uint8_t frm = 0U;
620 uint8_t pdta = 0U;
621 uint8_t sdta = 0U;
622 const ra8_err_t v_err = internal_validate_init_cfg(cfg, &omod, &frm, &pdta, &sdta);
623 RA8_RETURN_ON_ERROR(v_err, s_tag, "ssie_init: bad cfg");
624
625 /* HUM Ch 11.2.8 "MSTPCRC" p 446 */
626 /* HUM Ch 46.2.3 "SSIRST" p 3077 */
627 const ra8_err_t pwr_err = internal_ssie_power_up(channel, reg);
628 RA8_RETURN_ON_ERROR(pwr_err, s_tag, "ssie_init: power up");
629
630 internal_apply_init_regs(reg, cfg, frm, pdta, sdta, omod);
631
632 g_ssie_runtime[channel].initialized = true;
633 g_ssie_runtime[channel].dma_attached = false;
634 ra8_log_info_val(s_tag, "ssie_init channel", (uint32_t)channel);
635 return k_ra8_ok;
636}
637
639{
640 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
641 if (reg == nullptr) {
643 }
644 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
646 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
648
649 if (g_ssie_runtime[channel].dma_attached) {
650 (void)ra8_ssie_detach_dma(channel);
651 }
652 g_ssie_runtime[channel].initialized = false;
653 return ra8_mstp_disable(s_ssie_mstp_table[channel]);
654}
655
657{
658 if (dir != k_ra8_ssie_dir_rx && dir != k_ra8_ssie_dir_tx && dir != k_ra8_ssie_dir_tx_rx) {
660 }
661 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
662 if (reg == nullptr) {
664 }
665
666 /* HUM Ch 46.6.2 "Transmission" p 3098 / 46.6.3 "Reception" p 3099:
667 * the SSIE must be idle before REN/TEN may be set. */
668 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
669 uint32_t ssicr = reg->SSICR;
670 const uint32_t current_ren_ten = ssicr & k_ra8_ssie_mask_ren_ten;
671 const uint32_t desired_ren_ten = (uint32_t)dir;
672 if (desired_ren_ten == (current_ren_ten & desired_ren_ten)) {
673 return k_ra8_ok; /* Already enabled, nothing to do. */
674 }
675 if (current_ren_ten != 0U) {
676 return k_ra8_err_busy;
677 }
678 /* HUM Ch 46.2.2 "SSISR : Status Register" p 3066 */
679 if ((reg->SSISR & k_ra8_ssie_mask_iirq) == 0U) {
680 return k_ra8_err_busy;
681 }
682
683 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
684 uint32_t ssifcr = reg->SSIFCR;
685 const ra8_err_t rst_err = internal_pulse_fifo_reset(reg, ssifcr);
686 RA8_RETURN_ON_ERROR(rst_err, s_tag, "ssie_start: FIFO reset stuck");
687
688 /* HUM Ch 46.2.1 "SSICR" p 3057 */ /* / HUM Ch 46.2.3 "SSIFCR" p 3077 */
689 internal_apply_dir_irq_bits(desired_ren_ten, &ssicr, &ssifcr);
690
691 reg->SSIFCR = ssifcr;
692 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
693 reg->SSICR = ssicr | desired_ren_ten;
694 return k_ra8_ok;
695}
696
697ra8_err_t ra8_ssie_stop(uint8_t channel)
698{
699 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
700 if (reg == nullptr) {
702 }
703
704 /* HUM Ch 46.6.4 "Halt of Communication" p 3100 */
705 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
706 uint32_t ssicr = reg->SSICR;
709 ssicr |= k_ra8_ssie_mask_iien;
710 reg->SSICR = ssicr;
711
712 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
713 uint32_t ssifcr = reg->SSIFCR;
714 ssifcr &= ~k_ra8_ssie_mask_rie_tie;
715 reg->SSIFCR = ssifcr;
716 return k_ra8_ok;
717}
718
720{
721 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
722 if (reg == nullptr) {
724 }
725
726 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
727 const uint32_t ssifcr_save = reg->SSIFCR & ~k_ra8_ssie_mask_ssirst;
728 reg->SSIFCR = ssifcr_save | k_ra8_ssie_mask_ssirst;
729 reg->SSIFCR = ssifcr_save;
730 /* HUM Ch 46.2.3 "SSIFCR : FIFO Control Register" p 3077 */
731 const ra8_err_t rst_err = internal_wait_ssirst_clear(reg);
732 RA8_RETURN_ON_ERROR(rst_err, s_tag, "ssie_recover: SSIRST stuck");
733
734 /* HUM Ch 46.2.2 "SSISR : Status Register" p 3066-3072 */
735 const uint32_t ssisr = reg->SSISR;
736 reg->SSISR = ssisr & ~k_ra8_ssie_mask_err_all;
737 return k_ra8_ok;
738}
739
740ra8_err_t ra8_ssie_mute(uint8_t channel, bool enable)
741{
742 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
743 if (reg == nullptr) {
745 }
746 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3056 */
747 uint32_t ssicr = reg->SSICR;
748 if (enable) {
749 ssicr |= k_ra8_ssie_mask_muen;
750 } else {
751 ssicr &= ~k_ra8_ssie_mask_muen;
752 }
753 reg->SSICR = ssicr;
754 return k_ra8_ok;
755}
756
757ra8_err_t ra8_ssie_set_thresholds(uint8_t channel, uint8_t tx_threshold, uint8_t rx_threshold)
758{
759 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
760 if (reg == nullptr) {
762 }
763 if (tx_threshold > k_ra8_ssie_thresh_max || rx_threshold > k_ra8_ssie_thresh_max) {
765 }
766 /* HUM Ch 46.2.8 "SSISCR : Status Control Register" p 3094 */
767 reg->SSISCR = internal_build_ssiscr(tx_threshold, rx_threshold);
768 return k_ra8_ok;
769}
770
771ra8_err_t ra8_ssie_write_sample(uint8_t channel, uint32_t sample)
772{
773 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
774 if (reg == nullptr) {
776 }
777 /* HUM Ch 46.2.5 "SSIFTDR : Transmit FIFO Data Register" p 3088 */
778 reg->SSIFTDR = sample;
779 return k_ra8_ok;
780}
781
782ra8_err_t ra8_ssie_read_sample(uint8_t channel, uint32_t* out)
783{
784 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
785 volatile const r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
786 if (reg == nullptr) {
788 }
789 /* HUM Ch 46.2.6 "SSIFRDR : Receive FIFO Data Register" p 3089 */
790 *out = reg->SSIFRDR;
791 return k_ra8_ok;
792}
793
795 const uint32_t* buffer,
796 uint16_t samples,
797 uint16_t* out_written)
798{
799 RA8_CHECK_NULL_PTR(buffer, s_tag, "buffer must not be nullptr");
800 RA8_CHECK_NULL_PTR(out_written, s_tag, "out_written must not be nullptr");
801 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
802 if (reg == nullptr) {
804 }
805
806 uint16_t written = 0U;
807 for (uint16_t i = 0U; i < samples; i++) {
808 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
809 const uint8_t tdc = (uint8_t)((reg->SSIFSR & k_ra8_ssie_mask_tdc) >> k_ra8_ssie_shift_tdc);
810 if (tdc >= (uint8_t)k_ra8_ssie_fifo_depth) {
811 break;
812 }
813 /* HUM Ch 46.2.5 "SSIFTDR : Transmit FIFO Data Register" p 3088 */
814 reg->SSIFTDR = buffer[i];
815 written++;
816 }
817 if (written > 0U) {
818 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
819 const uint32_t fsr = reg->SSIFSR;
820 (void)fsr;
821 /* W1C of TDE keeps the RDF bit (mask_rdf_clear keeps RDF=1). */
823 }
824 *out_written = written;
825 return k_ra8_ok;
826}
827
829ra8_ssie_read_buffer(uint8_t channel, uint32_t* buffer, uint16_t samples, uint16_t* out_read)
830{
831 RA8_CHECK_NULL_PTR(buffer, s_tag, "buffer must not be nullptr");
832 RA8_CHECK_NULL_PTR(out_read, s_tag, "out_read must not be nullptr");
833 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
834 if (reg == nullptr) {
836 }
837
838 uint16_t read = 0U;
839 for (uint16_t i = 0U; i < samples; i++) {
840 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
841 const uint8_t rdc = (uint8_t)((reg->SSIFSR & k_ra8_ssie_mask_rdc) >> k_ra8_ssie_shift_rdc);
842 if (rdc == 0U) {
843 break;
844 }
845 /* HUM Ch 46.2.6 "SSIFRDR : Receive FIFO Data Register" p 3089 */
846 buffer[i] = reg->SSIFRDR;
847 read++;
848 }
849 if (read > 0U) {
850 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
851 const uint32_t fsr = reg->SSIFSR;
852 (void)fsr;
853 /* W1C of RDF keeps the TDE bit (mask_tde_clear keeps TDE=1). */
855 }
856 *out_read = read;
857 return k_ra8_ok;
858}
859
861{
862 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
863 volatile const r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
864 if (reg == nullptr) {
866 }
867 /* HUM Ch 46.2.2 "SSISR : Status Register" p 3066 */
868 const uint32_t ssisr = reg->SSISR;
869 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
870 const uint32_t ssifsr = reg->SSIFSR;
871
872 out->ssisr = ssisr;
873 out->ssifsr = ssifsr;
874 out->rx_count = (uint8_t)((ssifsr & k_ra8_ssie_mask_rdc) >> k_ra8_ssie_shift_rdc);
875 out->tx_count = (uint8_t)((ssifsr & k_ra8_ssie_mask_tdc) >> k_ra8_ssie_shift_tdc);
876 out->rx_full = ((ssifsr & k_ra8_ssie_mask_rdf) != 0U);
877 out->tx_empty = ((ssifsr & k_ra8_ssie_mask_tde) != 0U);
878 out->idle = ((ssisr & k_ra8_ssie_mask_iirq) != 0U);
879 out->error = ((ssisr & k_ra8_ssie_mask_err_all) != 0U);
880 out->events = internal_decode_event(ssisr, ssifsr);
881 return k_ra8_ok;
882}
883
884ra8_err_t ra8_ssie_clear_status(uint8_t channel, uint32_t mask)
885{
886 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
887 if (reg == nullptr) {
889 }
890 /* HUM Ch 46.2.2 "SSISR : Status Register" p 3069-3072 */
891 const uint32_t writeable = mask & k_ra8_ssie_mask_err_all;
892 const uint32_t current = reg->SSISR;
893 reg->SSISR = current & ~writeable;
894 return k_ra8_ok;
895}
896
897ra8_err_t ra8_ssie_set_irq_enable(uint8_t channel, uint32_t mask, bool enable)
898{
899 volatile r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
900 if (reg == nullptr) {
902 }
903 /* HUM Ch 46.2.1 "SSICR : Control Register" p 3057 */
904 const uint32_t apply = mask & k_ra8_ssie_mask_irq_all;
905 uint32_t ssicr = reg->SSICR;
906 if (enable) {
907 ssicr |= apply;
908 } else {
909 ssicr &= ~apply;
910 }
911 reg->SSICR = ssicr;
912 return k_ra8_ok;
913}
914
916{
917 s_ssie_fn = fn;
918 s_ssie_ctx = ctx;
919 return k_ra8_ok;
920}
921
923void ra8_ssie_dispatch(uint8_t channel)
924{
925 volatile const r_ssie_regs_t* reg = priv_ra8_ssie_internal_regs(channel);
926 if (reg == nullptr) {
927 return;
928 }
929 /* HUM Ch 46.2.2 "SSISR : Status Register" p 3066 */
930 const uint32_t ssisr = reg->SSISR;
931 /* HUM Ch 46.2.4 "SSIFSR : FIFO Status Register" p 3083 */
932 const uint32_t ssifsr = reg->SSIFSR;
933 const uint8_t events = internal_decode_event(ssisr, ssifsr);
935 void* const ctx = s_ssie_ctx;
936 if (fn != nullptr) {
937 fn(ctx, channel, events, ssisr);
938 }
939}
940
941ra8_err_t ra8_ssie_set_fifo_threshold(uint8_t channel, uint8_t tx_threshold, uint8_t rx_threshold)
942{
943 /* HUM Ch 46.2.8 "SSISCR : Status Control Register" p 3094.
944 * Convenience wrapper named after the SSITDMR / SSIRDMR aliases used
945 * by the audio pipeline; same effect as ra8_ssie_set_thresholds. */
946 return ra8_ssie_set_thresholds(channel, tx_threshold, rx_threshold);
947}
948
950{
951 if ((uint16_t)channel >= k_ra8_ssie_channel_count) {
953 }
954 return ra8_mstp_disable(s_ssie_mstp_table[channel]);
955}
956
958{
959 if ((uint16_t)channel >= k_ra8_ssie_channel_count) {
961 }
962 return ra8_mstp_enable(s_ssie_mstp_table[channel]);
963}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
8-channel DMA controller (DMAC0) driver
Error Code Definitions for ra8-firmware.
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Cross-translation-unit private helpers shared inside ra8_hal.
@ k_ra8_ssie_dma_ch_unused
Sentinel: no DMA channel.
@ k_ra8_ssie_thresh_max
Max SSISCR threshold value.
ra8_ssie_runtime_t g_ssie_runtime[k_ra8_ssie_channel_count]
Per-channel SSIE runtime state, shared across the ra8_ssie split.
Definition ra8_ssie.c:73
Bounded wait-flag primitives for RA8D2 HAL drivers.
static ra8_err_t ra8_hw_wait_flag_clear32(volatile const uint32_t *reg, uint32_t mask, uint32_t budget)
Spin until (*reg & mask) == 0 or budget runs out.
Definition ra8_hw_err.h:351
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
@ k_ra8_mstp_ssie1
MSTPC7 SSIE1.
@ k_ra8_mstp_ssie0
MSTPC8 SSIE0.
volatile r_ssie_regs_t * priv_ra8_ssie_internal_regs(uint8_t channel)
Implementation of priv_ra8_ssie_internal_regs() – bounds-check + accessor.
Definition ra8_ssie.c:101
ra8_err_t ra8_ssie_clear_status(uint8_t channel, uint32_t mask)
Clear sticky error flags in SSISR.
Definition ra8_ssie.c:884
ra8_err_t ra8_ssie_write_buffer(uint8_t channel, const uint32_t *buffer, uint16_t samples, uint16_t *out_written)
Drain a host buffer into the TX FIFO until either runs out.
Definition ra8_ssie.c:794
ra8_err_t ra8_ssie_init(uint8_t channel, const ra8_ssie_cfg_t *cfg)
Initialise an SSIE channel for I2S / TDM / monaural transfer.
Definition ra8_ssie.c:610
void ra8_ssie_dispatch(uint8_t channel)
ISR helper: fire the registered event handler.
Definition ra8_ssie.c:923
ra8_err_t ra8_ssie_start_recovery(uint8_t channel)
Force the channel back into a known idle state.
Definition ra8_ssie.c:719
static ra8_err_t internal_validate_init_cfg(const ra8_ssie_cfg_t *cfg, uint8_t *out_omod, uint8_t *out_frm, uint8_t *out_pdta, uint8_t *out_sdta)
Format-decode wrapper that validates ranges before delegation.
Definition ra8_ssie.c:506
static ra8_ssie_event_fn_t s_ssie_fn
Globally registered SSIE event callback (one slot, shared).
Definition ra8_ssie.c:90
static void internal_apply_init_regs(volatile r_ssie_regs_t *reg, const ra8_ssie_cfg_t *cfg, uint8_t frm, uint8_t pdta, uint8_t sdta, uint8_t omod)
Stamp SSICR/SSIOFR/SSISCR/SSIFCR for a freshly reset SSIE block.
Definition ra8_ssie.c:597
static ra8_err_t internal_wait_ssirst_clear(volatile r_ssie_regs_t *reg)
Bounded poll on SSIFCR until SSIRST clears.
Definition ra8_ssie.c:311
static void * s_ssie_ctx
Opaque context delivered to s_ssie_fn on dispatch.
Definition ra8_ssie.c:98
static void internal_apply_dir_irq_bits(uint32_t desired_ren_ten, uint32_t *ssicr, uint32_t *ssifcr)
Apply per-direction IRQ-enable bits to in-progress SSICR/SSIFCR.
Definition ra8_ssie.c:472
ra8_err_t ra8_ssie_set_thresholds(uint8_t channel, uint8_t tx_threshold, uint8_t rx_threshold)
Update the FIFO trigger watermarks at runtime.
Definition ra8_ssie.c:757
ra8_err_t ra8_ssie_read_sample(uint8_t channel, uint32_t *out)
Pop one 32-bit sample from the receive FIFO.
Definition ra8_ssie.c:782
ra8_err_t ra8_ssie_attach_handler(ra8_ssie_event_fn_t fn, void *ctx)
Attach a shared event callback for both SSIE channels.
Definition ra8_ssie.c:915
ra8_err_t ra8_ssie_set_fifo_threshold(uint8_t channel, uint8_t tx_threshold, uint8_t rx_threshold)
Programme SSITDMR / SSIRDMR FIFO thresholds in one call.
Definition ra8_ssie.c:941
ra8_err_t ra8_ssie_set_irq_enable(uint8_t channel, uint32_t mask, bool enable)
Update the IRQ enable mask without rewriting SSICR fully.
Definition ra8_ssie.c:897
ra8_err_t ra8_ssie_write_sample(uint8_t channel, uint32_t sample)
Push one 32-bit sample into the transmit FIFO.
Definition ra8_ssie.c:771
static uint8_t internal_decode_event(uint32_t ssisr, uint32_t ssifsr)
Decode SSISR/SSIFSR into a ra8_ssie_event_t bitmap.
Definition ra8_ssie.c:194
static ra8_err_t internal_ssie_power_up(uint8_t channel, volatile r_ssie_regs_t *reg)
Power up the SSIE block: enable MSTP then drive SSIRST low.
Definition ra8_ssie.c:570
static ra8_err_t internal_pulse_ssi_reset(volatile r_ssie_regs_t *reg)
Drive the soft-reset sequence required before SSICR writes.
Definition ra8_ssie.c:543
static uint32_t internal_build_ssiofr(const ra8_ssie_cfg_t *cfg, uint8_t omod)
Pack SSIOFR (audio format register) value from cfg + decoded OMOD.
Definition ra8_ssie.c:362
static ra8_err_t internal_pulse_fifo_reset(volatile r_ssie_regs_t *reg, uint32_t ssifcr_base)
Pulse RFRST/TFRST high then low and wait for both bits to clear.
Definition ra8_ssie.c:447
ra8_err_t ra8_ssie_deinit(uint8_t channel)
Tear down an SSIE channel and gate its clock.
Definition ra8_ssie.c:638
static uint32_t internal_build_ssiscr(uint8_t tx_threshold, uint8_t rx_threshold)
Pack SSISCR (status control register) value from TX/RX thresholds.
Definition ra8_ssie.c:419
ra8_err_t ra8_ssie_stop(uint8_t channel)
Disable transmission and reception.
Definition ra8_ssie.c:697
ra8_err_t ra8_ssie_mute(uint8_t channel, bool enable)
Enable or disable mute on the next frame boundary.
Definition ra8_ssie.c:740
ra8_err_t ra8_ssie_exit_stop(uint8_t channel)
Re-ungate the channel's MSTP bit.
Definition ra8_ssie.c:957
ra8_err_t ra8_ssie_start(uint8_t channel, ra8_ssie_dir_t dir)
Enable transmission, reception, or full duplex.
Definition ra8_ssie.c:656
ra8_err_t ra8_ssie_enter_stop(uint8_t channel)
Gate the channel's MSTP bit (preserve register state).
Definition ra8_ssie.c:949
ra8_err_t ra8_ssie_read_buffer(uint8_t channel, uint32_t *buffer, uint16_t samples, uint16_t *out_read)
Empty the RX FIFO into a host buffer until either runs out.
Definition ra8_ssie.c:829
static uint32_t internal_build_ssicr(const ra8_ssie_cfg_t *cfg, uint8_t frm, uint8_t pdta, uint8_t sdta)
Build the SSICR value from a config descriptor.
Definition ra8_ssie.c:245
ra8_err_t ra8_ssie_get_status(uint8_t channel, ra8_ssie_status_t *out)
Snapshot SSISR + SSIFSR into a status struct.
Definition ra8_ssie.c:860
static const ra8_mstp_t s_ssie_mstp_table[k_ra8_ssie_channel_count]
Channel-index -> MSTP id lookup.
Definition ra8_ssie.c:58
static uint32_t internal_build_ssifcr(const ra8_ssie_cfg_t *cfg)
Pack SSIFCR (FIFO control register) value from cfg.
Definition ra8_ssie.c:390
static bool internal_format_decode(ra8_ssie_format_t format, uint8_t *out_omod, uint8_t *out_frm, uint8_t *out_pdta, uint8_t *out_sdta)
Translate a public format enum to OMOD + FRM register fields.
Definition ra8_ssie.c:132
static ra8_err_t internal_wait_fifo_reset_clear(volatile r_ssie_regs_t *reg)
Bounded poll on SSIFCR until both FIFO reset bits clear.
Definition ra8_ssie.c:334
Serial Sound Interface Enhanced (SSIE / I2S audio) driver.
void(* ra8_ssie_event_fn_t)(void *ctx, uint8_t channel, uint8_t events, uint32_t ssisr)
SSIE event callback fired by ra8_ssie_dispatch.
Definition ra8_ssie.h:305
ra8_err_t ra8_ssie_detach_dma(uint8_t channel)
Tear down DMAC channels attached to the SSIE FIFOs.
ra8_ssie_format_t
Audio frame format (drives SSIOFR.OMOD[1:0] and SSICR.FRM).
Definition ra8_ssie.h:127
@ k_ra8_ssie_format_i2s
I2S, 2 channels per frame.
Definition ra8_ssie.h:128
@ k_ra8_ssie_format_tdm_4
TDM 4-slot.
Definition ra8_ssie.h:132
@ k_ra8_ssie_format_monaural
Monaural single-channel.
Definition ra8_ssie.h:131
@ k_ra8_ssie_format_tdm_8
TDM 8-slot.
Definition ra8_ssie.h:134
@ k_ra8_ssie_format_tdm_6
TDM 6-slot.
Definition ra8_ssie.h:133
@ k_ra8_ssie_format_left_just
Left-justified, 2 channels.
Definition ra8_ssie.h:129
@ k_ra8_ssie_format_right_just
Right-justified, 2 channels.
Definition ra8_ssie.h:130
ra8_ssie_dir_t
Communication direction selector for ra8_ssie_start.
Definition ra8_ssie.h:209
@ k_ra8_ssie_dir_tx
Transmission only (TEN).
Definition ra8_ssie.h:211
@ k_ra8_ssie_dir_rx
Reception only (REN).
Definition ra8_ssie.h:210
@ k_ra8_ssie_dir_tx_rx
Full duplex (TEN | REN).
Definition ra8_ssie.h:212
@ k_ra8_ssie_role_controller
Bit clock + LR clock are outputs.
Definition ra8_ssie.h:105
@ k_ra8_ssie_evt_tx_empty
TDE asserted (TIE on).
Definition ra8_ssie.h:228
@ k_ra8_ssie_evt_none
No bits set.
Definition ra8_ssie.h:226
@ k_ra8_ssie_evt_idle
IIRQ asserted.
Definition ra8_ssie.h:227
@ k_ra8_ssie_evt_tx_over
TOIRQ.
Definition ra8_ssie.h:231
@ k_ra8_ssie_evt_rx_under
RUIRQ.
Definition ra8_ssie.h:232
@ k_ra8_ssie_evt_rx_over
ROIRQ.
Definition ra8_ssie.h:233
@ k_ra8_ssie_evt_rx_full
RDF asserted (RIE on).
Definition ra8_ssie.h:229
@ k_ra8_ssie_evt_tx_under
TUIRQ.
Definition ra8_ssie.h:230
Serial Sound Interface Enhanced (SSIE) register layout for the RA8D2.
@ k_ra8_ssie_shift_tdc
TDC[5:0] starts at bit 24.
@ k_ra8_ssie_shift_rdc
RDC[5:0] starts at bit 8.
@ k_ra8_ssie_shift_tdes
TDES[4:0] starts at bit 8.
@ k_ra8_ssie_shift_rdfs
RDFS[4:0] starts at bit 0.
@ k_ra8_ssie_mask_rie
RIE receive full IRQ.
@ k_ra8_ssie_mask_tie
TIE transmit empty IRQ.
@ k_ra8_ssie_mask_aucke
AUCKE AUDIO_MCK enable.
@ k_ra8_ssie_mask_rie_tie
RIE | TIE.
@ k_ra8_ssie_mask_bsw
BSW byte-swap enable.
@ k_ra8_ssie_mask_ssirst
SSIRST software reset.
@ k_ra8_ssie_mask_rfrst_tfrst
Both FIFO reset bits.
@ k_ra8_ssie_channel_count
SSIE0 + SSIE1.
@ k_ra8_ssie_reset_poll_max
Bounded reset poll loops.
@ k_ra8_ssie_fifo_depth
32-stage FIFO per dir.
@ k_ra8_ssie_omod_i2s
RA8 ssie omod i2s.
@ k_ra8_ssie_omod_tdm
RA8 ssie omod tdm.
@ k_ra8_ssie_omod_monaural
RA8 ssie omod monaural.
@ k_ra8_ssie_bit_ckdv0
CKDV[3:0] @ [7:4] bit clock div.
@ k_ra8_ssie_bit_dwl0
DWL[2:0] @ [21:19] data word.
@ k_ra8_ssie_bit_frm0
FRM[1:0] @ [23:22] frame words.
@ k_ra8_ssie_bit_swl0
SWL[2:0] @ [18:16] system word.
@ k_ra8_ssie_frm_default
2 (I2S) / 1 (Mon) / – (TDM)
@ k_ra8_ssie_frm_alt3
– / – / 8 (TDM-8)
@ k_ra8_ssie_frm_alt1
– / – / 4 (TDM-4)
@ k_ra8_ssie_frm_alt2
– / – / 6 (TDM-6)
@ k_ra8_ssie_mask_err_all
ROIRQ|RUIRQ|TOIRQ|TUIRQ.
@ k_ra8_ssie_mask_ruirq
RUIRQ receive underflow.
@ k_ra8_ssie_mask_roirq
ROIRQ receive overflow.
@ k_ra8_ssie_mask_toirq
TOIRQ transmit overflow.
@ k_ra8_ssie_mask_tuirq
TUIRQ transmit underflow.
@ k_ra8_ssie_mask_iirq
IIRQ idle-mode flag (RO).
@ k_ra8_ssie_mask_err_ien
ROIEN..TUIEN tx/rx err IRQs.
@ k_ra8_ssie_mask_lrckp
LRCKP.
@ k_ra8_ssie_mask_ckdv
CKDV[3:0] @ [7:4].
@ k_ra8_ssie_mask_swl
SWL[2:0] @ [18:16].
@ k_ra8_ssie_mask_dwl
DWL[2:0] @ [21:19].
@ k_ra8_ssie_mask_sdta
SDTA.
@ k_ra8_ssie_mask_mst
MST.
@ k_ra8_ssie_mask_tuien
TUIEN.
@ k_ra8_ssie_mask_bckp
BCKP.
@ k_ra8_ssie_mask_ren
REN.
@ k_ra8_ssie_mask_del
DEL.
@ k_ra8_ssie_mask_spdp
SPDP.
@ k_ra8_ssie_mask_roien
ROIEN.
@ k_ra8_ssie_mask_muen
MUEN.
@ k_ra8_ssie_mask_ren_ten
REN | TEN.
@ k_ra8_ssie_mask_ten
TEN.
@ k_ra8_ssie_mask_iien
IIEN.
@ k_ra8_ssie_mask_frm
FRM[1:0] @ [23:22].
@ k_ra8_ssie_mask_cks
CKS audio clock select.
@ k_ra8_ssie_mask_pdta
PDTA.
@ k_ra8_ssie_mask_irq_all
IIEN..TUIEN aggregate IRQ.
@ k_ra8_ssie_mask_tde_clear
Keep RDF while clearing TDE.
@ k_ra8_ssie_mask_rdf_clear
Keep TDE while clearing RDF.
@ k_ra8_ssie_mask_rdf
RDF receive data full.
@ k_ra8_ssie_mask_tdc
TDC[5:0] @ [29:24].
@ k_ra8_ssie_mask_rdc
RDC[5:0] @ [13:8].
@ k_ra8_ssie_mask_tde
TDE transmit data empty.
@ k_ra8_ssie_mask_rdfs
RDFS[4:0] @ [4:0].
@ k_ra8_ssie_mask_tdes
TDES[4:0] @ [12:8].
static volatile r_ssie_regs_t * ra8_ssie(uint8_t channel)
Get pointer to an SSIE channel block.
@ k_ra8_ssie_mask_omod
OMOD[1:0] @ [1:0].
@ k_ra8_ssie_mask_lrcont
LRCONT continuation.
@ k_ra8_ssie_mask_bckastp
BCKASTP idle-stop BCK.
Per-channel SSIE register window.
volatile uint32_t SSISR
+0x04 Status register.
volatile uint32_t SSIFTDR
+0x18 Transmit FIFO data.
volatile uint32_t SSIOFR
+0x20 Audio format register.
volatile uint32_t SSIFSR
+0x14 FIFO status register.
volatile uint32_t SSISCR
+0x24 Status control register.
volatile uint32_t SSIFRDR
+0x1C Receive FIFO data.
volatile uint32_t SSICR
+0x00 Control register.
volatile uint32_t SSIFCR
+0x10 FIFO control register.
Configuration descriptor for ra8_ssie_init.
Definition ra8_ssie.h:246
uint8_t rx_threshold
SSISCR.RDFS[4:0] watermark.
Definition ra8_ssie.h:262
ra8_ssie_role_t role
Controller or peripheral.
Definition ra8_ssie.h:247
uint8_t tx_threshold
SSISCR.TDES[4:0] watermark.
Definition ra8_ssie.h:261
bool long_frame
true: SSICR.DEL = 0 (long).
Definition ra8_ssie.h:253
ra8_ssie_data_word_t data_word
Significant bits per channel.
Definition ra8_ssie.h:249
bool bckp_rising
true: SSICR.BCKP = 1.
Definition ra8_ssie.h:254
bool byte_swap
SSIFCR.BSW.
Definition ra8_ssie.h:257
ra8_ssie_system_word_t system_word
Total bits per channel.
Definition ra8_ssie.h:250
bool spdp_high
true: SSICR.SPDP = 1.
Definition ra8_ssie.h:256
bool bck_idle_stop
SSIOFR.BCKASTP (controller only).
Definition ra8_ssie.h:259
bool lr_continue
SSIOFR.LRCONT (controller only).
Definition ra8_ssie.h:258
bool lrckp_low
true: SSICR.LRCKP = 1.
Definition ra8_ssie.h:255
bool enable_aucke
SSIFCR.AUCKE (controller only).
Definition ra8_ssie.h:260
ra8_ssie_format_t format
I2S / TDM / monaural.
Definition ra8_ssie.h:248
ra8_ssie_bclk_div_t bclk_div
CKDV divider (controller only).
Definition ra8_ssie.h:251
bool use_gpt_clk
true: GTIOC2A; false: AUDIO_CLK.
Definition ra8_ssie.h:252
Per-channel runtime bookkeeping.
Snapshot of FIFO levels + error flags returned by ra8_ssie_get_status.
Definition ra8_ssie.h:270
uint32_t ssisr
Raw SSISR value.
Definition ra8_ssie.h:271
bool rx_full
RDF flag: RX above SSISCR.RDFS.
Definition ra8_ssie.h:275
uint8_t rx_count
RDC[5:0] – entries currently in RX.
Definition ra8_ssie.h:273
uint32_t ssifsr
Raw SSIFSR value.
Definition ra8_ssie.h:272
bool idle
IIRQ: SSIE in idle state.
Definition ra8_ssie.h:277
bool error
Any of ROIRQ/RUIRQ/TOIRQ/TUIRQ set.
Definition ra8_ssie.h:278
uint8_t tx_count
TDC[5:0] – entries currently in TX.
Definition ra8_ssie.h:274
bool tx_empty
TDE flag: TX below SSISCR.TDES.
Definition ra8_ssie.h:276
uint8_t events
Decoded ra8_ssie_event_t bitmap.
Definition ra8_ssie.h:279