summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c')
-rw-r--r--c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c746
1 files changed, 746 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c b/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c
new file mode 100644
index 0000000000..2d78905d77
--- /dev/null
+++ b/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c
@@ -0,0 +1,746 @@
+/**
+ * @file
+ *
+ * @ingroup mpc55xx_dspi
+ *
+ * @brief Source file for the LibI2C bus driver for the Deserial Serial Peripheral Interface (DSPI).
+ */
+
+/*
+ * Copyright (c) 2008
+ * Embedded Brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * rtems@embedded-brains.de
+ *
+ * The license and distribution terms for this file may be found in the file
+ * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
+ */
+
+#include <mpc55xx/regs.h>
+#include <mpc55xx/dspi.h>
+#include <mpc55xx/edma.h>
+#include <mpc55xx/mpc55xx.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#define RTEMS_STATUS_CHECKS_USE_PRINTK
+
+#include <rtems/status-checks.h>
+
+#define MPC55XX_DSPI_FIFO_SIZE 4
+
+#define MPC55XX_DSPI_CTAR_NUMBER 8
+
+#define MPC55XX_DSPI_CTAR_DEFAULT 0
+
+#define MPC55XX_DSPI_EDMA_MAGIC_SIZE 128
+
+#define MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE 63
+
+typedef struct {
+ uint32_t scaler : 26;
+ uint32_t pbr : 2;
+ uint32_t br : 4;
+} mpc55xx_dspi_baudrate_scaler_entry;
+
+static const mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_baudrate_scaler_table [MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE] = {
+ { 4, 0, 0 },
+ { 6, 1, 0 },
+ { 8, 0, 1 },
+ { 10, 2, 0 },
+ { 12, 1, 1 },
+ { 14, 3, 0 },
+ { 16, 0, 3 },
+ { 18, 1, 2 },
+ { 20, 2, 1 },
+ { 24, 1, 3 },
+ { 28, 3, 1 },
+ { 30, 2, 2 },
+ { 32, 0, 4 },
+ { 40, 2, 3 },
+ { 42, 3, 2 },
+ { 48, 1, 4 },
+ { 56, 3, 3 },
+ { 64, 0, 5 },
+ { 80, 2, 4 },
+ { 96, 1, 5 },
+ { 112, 3, 4 },
+ { 128, 0, 6 },
+ { 160, 2, 5 },
+ { 192, 1, 6 },
+ { 224, 3, 5 },
+ { 256, 0, 7 },
+ { 320, 2, 6 },
+ { 384, 1, 7 },
+ { 448, 3, 6 },
+ { 512, 0, 8 },
+ { 640, 2, 7 },
+ { 768, 1, 8 },
+ { 896, 3, 7 },
+ { 1024, 0, 9 },
+ { 1280, 2, 8 },
+ { 1536, 1, 9 },
+ { 1792, 3, 8 },
+ { 2048, 0, 10 },
+ { 2560, 2, 9 },
+ { 3072, 1, 10 },
+ { 3584, 3, 9 },
+ { 4096, 0, 11 },
+ { 5120, 2, 10 },
+ { 6144, 1, 11 },
+ { 7168, 3, 10 },
+ { 8192, 0, 12 },
+ { 10240, 2, 11 },
+ { 12288, 1, 12 },
+ { 14336, 3, 11 },
+ { 16384, 0, 13 },
+ { 20480, 2, 12 },
+ { 24576, 1, 13 },
+ { 28672, 3, 12 },
+ { 32768, 0, 14 },
+ { 40960, 2, 13 },
+ { 49152, 1, 14 },
+ { 57344, 3, 13 },
+ { 65536, 0, 15 },
+ { 81920, 2, 14 },
+ { 98304, 1, 15 },
+ { 114688, 3, 14 },
+ { 163840, 2, 15 },
+ { 229376, 3, 15 },
+};
+
+static mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_search_baudrate_scaler( uint32_t scaler, int min, int mid, int max)
+{
+ if (scaler <= mpc55xx_dspi_baudrate_scaler_table [mid].scaler) {
+ max = mid;
+ } else {
+ min = mid;
+ }
+ mid = (min + max) / 2;
+ if (mid == min) {
+ return mpc55xx_dspi_baudrate_scaler_table [max];
+ } else {
+ return mpc55xx_dspi_search_baudrate_scaler( scaler, min, mid, max);
+ }
+}
+
+static uint32_t mpc55xx_dspi_push_data [8 * MPC55XX_DSPI_NUMBER] __attribute__ ((aligned (32)));
+
+static inline void mpc55xx_dspi_store_push_data( mpc55xx_dspi_bus_entry *e)
+{
+ mpc55xx_dspi_push_data [e->table_index * 8] = e->push_data.R;
+ rtems_cache_flush_multiple_data_lines( &mpc55xx_dspi_push_data [e->table_index * 8], 4);
+}
+
+static inline uint32_t mpc55xx_dspi_push_data_address( mpc55xx_dspi_bus_entry *e)
+{
+ return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8];
+}
+
+static inline uint32_t mpc55xx_dspi_nirvana_address( mpc55xx_dspi_bus_entry *e)
+{
+ return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8 + 1];
+}
+
+static rtems_status_code mpc55xx_dspi_init( rtems_libi2c_bus_t *bus)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
+ union DSPI_MCR_tag mcr = MPC55XX_ZERO_FLAGS;
+ union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
+ union DSPI_RSER_tag rser = MPC55XX_ZERO_FLAGS;
+ struct tcd_t tcd_push = MPC55XX_EDMA_TCD_DEFAULT;
+ int i = 0;
+
+ /* eDMA receive */
+ sc = rtems_semaphore_create (
+ rtems_build_name ( 'S', 'P', 'I', 'R'),
+ 0,
+ RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+ RTEMS_NO_PRIORITY,
+ &e->edma_channel_receive_update
+ );
+ CHECK_SC( sc, "Create receive update semaphore");
+
+ sc = mpc55xx_edma_obtain_channel( e->edma_channel_receive, &e->edma_channel_receive_error, e->edma_channel_receive_update);
+ CHECK_SC( sc, "Obtain receive eDMA channel");
+
+ /* eDMA transmit */
+ sc = rtems_semaphore_create (
+ rtems_build_name ( 'S', 'P', 'I', 'T'),
+ 0,
+ RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+ RTEMS_NO_PRIORITY,
+ &e->edma_channel_transmit_update
+ );
+ CHECK_SC( sc, "Create transmit update semaphore");
+
+ sc = mpc55xx_edma_obtain_channel( e->edma_channel_transmit, &e->edma_channel_transmit_error, e->edma_channel_transmit_update);
+ CHECK_SC( sc, "Obtain transmit eDMA channel");
+
+ sc = mpc55xx_edma_obtain_channel( e->edma_channel_push, NULL, RTEMS_ID_NONE);
+ CHECK_SC( sc, "Obtain push eDMA channel");
+
+ tcd_push.SADDR = mpc55xx_dspi_push_data_address( e);
+ tcd_push.SSIZE = 2;
+ tcd_push.SOFF = 0;
+ tcd_push.DADDR = (uint32_t) &e->regs->PUSHR.R;
+ tcd_push.DSIZE = 2;
+ tcd_push.DOFF = 0;
+ tcd_push.NBYTES = 4;
+ tcd_push.CITER = 1;
+ tcd_push.BITER = 1;
+
+ EDMA.TCD [e->edma_channel_push] = tcd_push;
+
+ /* Module Control Register */
+ mcr.B.MSTR = e->master ? 1 : 0;
+ mcr.B.CONT_SCKE = 0;
+ mcr.B.DCONF = 0;
+ mcr.B.FRZ = 0;
+ mcr.B.MTFE = 0;
+ mcr.B.PCSSE = 0;
+ mcr.B.ROOE = 0;
+ mcr.B.PCSIS0 = 1;
+ mcr.B.PCSIS1 = 1;
+ mcr.B.PCSIS2 = 1;
+ mcr.B.PCSIS3 = 1;
+ mcr.B.PCSIS5 = 1;
+ mcr.B.MDIS = 0;
+ mcr.B.DIS_TXF = 0;
+ mcr.B.DIS_RXF = 0;
+ mcr.B.CLR_TXF = 0;
+ mcr.B.CLR_RXF = 0;
+ mcr.B.SMPL_PT = 0;
+ mcr.B.HALT = 0;
+
+ e->regs->MCR.R = mcr.R;
+
+ /* Clock and Transfer Attributes Register */
+ ctar.B.DBR = 0;
+ ctar.B.FMSZ = 0x7;
+ ctar.B.CPOL = 0;
+ ctar.B.CPHA = 0;
+ ctar.B.LSBFE = 0;
+ ctar.B.PCSSCK = 0;
+ ctar.B.PASC = 0;
+ ctar.B.PDT = 0;
+ ctar.B.PBR = 0;
+ ctar.B.CSSCK = 0;
+ ctar.B.ASC = 0;
+ ctar.B.DT = 0;
+ ctar.B.BR = 0;
+
+ for (i = 0; i < MPC55XX_DSPI_CTAR_NUMBER; ++i) {
+ e->regs->CTAR [i].R = ctar.R;
+ }
+
+ /* DMA/Interrupt Request Select and Enable Register */
+ rser.B.TFFFRE = 1;
+ rser.B.TFFFDIRS = 1;
+ rser.B.RFDFRE = 1;
+ rser.B.RFDFDIRS = 1;
+
+ e->regs->RSER.R = rser.R;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code mpc55xx_dspi_send_start( rtems_libi2c_bus_t *bus)
+{
+ mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
+
+ /* Reset chip selects */
+ e->push_data.B.PCS0 = 0;
+ e->push_data.B.PCS1 = 0;
+ e->push_data.B.PCS2 = 0;
+ e->push_data.B.PCS3 = 0;
+ e->push_data.B.PCS4 = 0;
+ e->push_data.B.PCS5 = 0;
+ mpc55xx_dspi_store_push_data( e);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code mpc55xx_dspi_send_stop( rtems_libi2c_bus_t *bus)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code mpc55xx_dspi_send_addr( rtems_libi2c_bus_t *bus, uint32_t addr, int rw)
+{
+ mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
+ union DSPI_SR_tag sr = MPC55XX_ZERO_FLAGS;
+
+ /* Flush transmit and receive FIFO */
+ e->regs->MCR.B.CLR_TXF = 1;
+ e->regs->MCR.B.CLR_RXF = 1;
+
+ /* Clear status flags */
+ sr.B.EOQF = 1;
+ sr.B.TFFF = 1;
+ sr.B.RFDF = 1;
+ e->regs->SR.R = sr.R;
+
+ /* Frame command */
+ e->push_data.R = 0;
+ e->push_data.B.CONT = 0;
+ e->push_data.B.CTAS = MPC55XX_DSPI_CTAR_DEFAULT;
+ e->push_data.B.EOQ = 0;
+ e->push_data.B.CTCNT = 0;
+ switch (addr) {
+ case 0:
+ e->push_data.B.PCS0 = 1;
+ break;
+ case 1:
+ e->push_data.B.PCS1 = 1;
+ break;
+ case 2:
+ e->push_data.B.PCS2 = 1;
+ break;
+ case 3:
+ e->push_data.B.PCS3 = 1;
+ break;
+ case 4:
+ e->push_data.B.PCS4 = 1;
+ break;
+ case 5:
+ e->push_data.B.PCS5 = 1;
+ break;
+ default:
+ return -RTEMS_INVALID_ADDRESS;
+ }
+ mpc55xx_dspi_store_push_data( e);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_libi2c_tfr_mode_t *mode)
+{
+ mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
+ union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
+ // FIXME, TODO
+ extern uint32_t bsp_clock_speed;
+ uint32_t scaler = bsp_clock_speed / mode->baudrate;
+ mpc55xx_dspi_baudrate_scaler_entry bse = mpc55xx_dspi_search_baudrate_scaler( scaler, 0, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE / 2, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE);
+
+ if (mode->bits_per_char != 8) {
+ return -RTEMS_INVALID_NUMBER;
+ }
+
+ e->idle_char = mode->idle_char;
+
+ ctar.R = e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R;
+
+ ctar.B.PBR = bse.pbr;
+ ctar.B.BR = bse.br;
+
+ // ctar.B.PCSSCK = bse.pbr;
+ // ctar.B.CSSCK = bse.br;
+ // ctar.B.PASC = bse.pbr;
+ // ctar.B.ASC = bse.br;
+
+ ctar.B.PCSSCK = 0;
+ ctar.B.CSSCK = 0;
+ ctar.B.PASC = 0;
+ ctar.B.ASC = 0;
+
+ ctar.B.LSBFE = mode->lsb_first ? 1 : 0;
+ ctar.B.CPOL = mode->clock_inv ? 1 : 0;
+ ctar.B.CPHA = mode->clock_phs ? 1 : 0;
+
+ e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R = ctar.R;
+
+ return 0;
+}
+
+/**
+ * @brief Writes @a n characters from @a out to bus @a bus and synchronously stores the received data in @a in.
+ *
+ * eDMA channel usage for transmission:
+ * @dot
+ * digraph push {
+ * push [label="Push Register"];
+ * push_data [label="Push Data"];
+ * idle_push_data [label="Idle Push Data"];
+ * out [shape=box,label="Output Buffer"];
+ * edge [color=red,fontcolor=red];
+ * push -> idle_push_data [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_transmit"];
+ * push -> out [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_transmit"];
+ * out -> push_data [label="Channel Link",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_push"];
+ * edge [color=blue,fontcolor=blue];
+ * out -> push_data [label="Data"];
+ * push_data -> push [label="Data"];
+ * idle_push_data -> push [label="Data"];
+ * }
+ * @enddot
+ *
+ * eDMA channel usage for receiving:
+ * @dot
+ * digraph pop {
+ * pop [label="Pop Register"];
+ * nirvana [label="Nirvana"];
+ * in [shape=box,label="Input Buffer"];
+ * edge [color=red,fontcolor=red];
+ * pop -> nirvana [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_receive"];
+ * pop -> in [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_receive"];
+ * edge [color=blue,fontcolor=blue];
+ * pop -> nirvana [label="Data"];
+ * pop -> in [label="Data"];
+ * }
+ * @enddot
+ */
+static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, const unsigned char *out, int n)
+{
+ mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
+
+ /* Non cache aligned characters */
+ int n_nc = n;
+
+ /* Cache aligned characters */
+ int n_c = 0;
+
+ /* Register addresses */
+ volatile void *push = &e->regs->PUSHR.R;
+ volatile void *pop = &e->regs->POPR.R;
+ volatile union DSPI_SR_tag *status = &e->regs->SR;
+
+ /* Push and pop data */
+ union DSPI_PUSHR_tag push_data = e->push_data;
+ union DSPI_POPR_tag pop_data;
+
+ /* Status register */
+ union DSPI_SR_tag sr;
+
+ /* Read and write indices */
+ int r = 0;
+ int w = 0;
+
+ if (n == 0) {
+ return 0;
+ } else if (in == NULL && out == NULL) {
+ return -RTEMS_INVALID_ADDRESS;
+ }
+
+ if (n > MPC55XX_DSPI_EDMA_MAGIC_SIZE) {
+ n_nc = mpc55xx_non_cache_aligned_size( in);
+ n_c = mpc55xx_cache_aligned_size( in, n);
+ if (n_c > EDMA_TCD_BITER_LINKED_SIZE) {
+ SYSLOG_WARNING( "Buffer size out of range, cannot use eDMA\n");
+ n_nc = n;
+ n_c = 0;
+ } else if (n_nc + n_c != n) {
+ SYSLOG_WARNING( "Input buffer not proper cache aligned, cannot use eDMA\n");
+ n_nc = n;
+ n_c = 0;
+ }
+ }
+
+#ifdef DEBUG
+ if (e->regs->SR.B.TXCTR != e->regs->SR.B.RXCTR) {
+ SYSLOG_WARNING( "FIFO counter not equal\n");
+ }
+#endif /* DEBUG */
+
+ /* Direct IO */
+ if (out == NULL) {
+ push_data.B.TXDATA = e->idle_char;
+ while (r < n_nc || w < n_nc) {
+ /* Wait for available FIFO */
+ do {
+ sr.R = status->R;
+ } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
+
+ /* Write */
+ if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
+ ++w;
+ ppc_write_word( push_data.R, push);
+ }
+
+ /* Read */
+ if (r < n_nc && sr.B.RXCTR != 0) {
+ pop_data.R = ppc_read_word( pop);
+ in [r] = pop_data.B.RXDATA;
+ // printk( "[%03u]: 0x%02x -> 0x%02x\n", r, out [r], in [r]);
+ ++r;
+ }
+ }
+ } else if (in == NULL) {
+ while (r < n_nc || w < n_nc) {
+ /* Wait for available FIFO */
+ do {
+ sr.R = status->R;
+ } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
+
+ /* Write */
+ if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
+ push_data.B.TXDATA = out [w];
+ ++w;
+ ppc_write_word( push_data.R, push);
+ }
+
+ /* Read */
+ if (r < n_nc && sr.B.RXCTR != 0) {
+ pop_data.R = ppc_read_word( pop);
+ // printk( "[%03u]: 0x%02x -> 0x%02x\n", r, out [r], in [r]);
+ ++r;
+ }
+ }
+ } else {
+ while (r < n_nc || w < n_nc) {
+ /* Wait for available FIFO */
+ do {
+ sr.R = status->R;
+ } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
+
+ /* Write */
+ if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
+ push_data.B.TXDATA = out [w];
+ ++w;
+ ppc_write_word( push_data.R, push);
+ }
+
+ /* Read */
+ if (r < n_nc && sr.B.RXCTR != 0) {
+ pop_data.R = ppc_read_word( pop);
+ in [r] = pop_data.B.RXDATA;
+ // printk( "[%03u]: 0x%02x -> 0x%02x\n", r, out [r], in [r]);
+ ++r;
+ }
+ }
+ }
+
+ /* eDMA transfers */
+ if (n_c > 0) {
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned char *in_c = in + n_nc;
+ const unsigned char *out_c = out + n_nc;
+ struct tcd_t tcd_transmit = MPC55XX_EDMA_TCD_DEFAULT;
+ struct tcd_t tcd_receive = MPC55XX_EDMA_TCD_DEFAULT;
+
+ /* Cache operations */
+ rtems_cache_flush_multiple_data_lines( out_c, n_c);
+ rtems_cache_invalidate_multiple_data_lines( in_c, n_c);
+
+ /* Set transmit TCD */
+ if (out == NULL) {
+ e->push_data.B.TXDATA = e->idle_char;
+ mpc55xx_dspi_store_push_data( e);
+ tcd_transmit.SADDR = mpc55xx_dspi_push_data_address( e);
+ tcd_transmit.SSIZE = 2;
+ tcd_transmit.SOFF = 0;
+ tcd_transmit.DADDR = (uint32_t) push;
+ tcd_transmit.DSIZE = 2;
+ tcd_transmit.DOFF = 0;
+ tcd_transmit.NBYTES = 4;
+ tcd_transmit.CITER = n_c;
+ tcd_transmit.BITER = n_c;
+ } else {
+ EDMA.CDSBR.R = e->edma_channel_transmit;
+ tcd_transmit.SADDR = (uint32_t) out_c;
+ tcd_transmit.SSIZE = 0;
+ tcd_transmit.SOFF = 1;
+ tcd_transmit.DADDR = mpc55xx_dspi_push_data_address( e) + 3;
+ tcd_transmit.DSIZE = 0;
+ tcd_transmit.DOFF = 0;
+ tcd_transmit.NBYTES = 1;
+ tcd_transmit.CITERE_LINK = 1;
+ tcd_transmit.BITERE_LINK = 1;
+ tcd_transmit.MAJORLINKCH = e->edma_channel_push;
+ tcd_transmit.CITER = EDMA_TCD_LINK_AND_BITER( e->edma_channel_push, n_c);
+ tcd_transmit.BITER = EDMA_TCD_LINK_AND_BITER( e->edma_channel_push, n_c);
+ tcd_transmit.MAJORE_LINK = 1;
+ }
+ tcd_transmit.D_REQ = 1;
+ tcd_transmit.INT_MAJ = 1;
+ EDMA.TCD [e->edma_channel_transmit] = tcd_transmit;
+
+ /* Set receive TCD */
+ if (in == NULL) {
+ tcd_receive.DOFF = 0;
+ tcd_receive.DADDR = mpc55xx_dspi_nirvana_address( e);
+ } else {
+ tcd_receive.DOFF = 1;
+ tcd_receive.DADDR = (uint32_t) in_c;
+ }
+ tcd_receive.SADDR = (uint32_t) pop + 3;
+ tcd_receive.SSIZE = 0;
+ tcd_receive.SOFF = 0;
+ tcd_receive.DSIZE = 0;
+ tcd_receive.NBYTES = 1;
+ tcd_receive.D_REQ = 1;
+ tcd_receive.INT_MAJ = 1;
+ tcd_receive.CITER = n_c;
+ tcd_receive.BITER = n_c;
+ EDMA.TCD [e->edma_channel_receive] = tcd_receive;
+
+ /* Clear request flags */
+ sr.R = 0;
+ sr.B.TFFF = 1;
+ sr.B.RFDF = 1;
+ status->R = sr.R;
+
+ /* Enable hardware requests */
+ sc = mpc55xx_edma_enable_hardware_requests( e->edma_channel_receive, true);
+ CHECK_SCRV( sc, "Enable receive hardware requests");
+ sc = mpc55xx_edma_enable_hardware_requests( e->edma_channel_transmit, true);
+ CHECK_SCRV( sc, "Enable transmit hardware requests");
+
+ /* Wait for transmit update */
+ sc = rtems_semaphore_obtain( e->edma_channel_transmit_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ CHECK_SCRV( sc, "Transmit update");
+ if (e->edma_channel_transmit_error != 0) {
+ SYSLOG_ERROR( "Transmit error status: 0x%08x\n", e->edma_channel_transmit_error);
+ e->edma_channel_transmit_error = 0;
+ return -RTEMS_IO_ERROR;
+ }
+
+ /* Wait for receive update */
+ sc = rtems_semaphore_obtain( e->edma_channel_receive_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ CHECK_SCRV( sc, "Receive update");
+ if (e->edma_channel_receive_error != 0) {
+ SYSLOG_ERROR( "Receive error status: 0x%08x\n", e->edma_channel_receive_error);
+ e->edma_channel_receive_error = 0;
+ return -RTEMS_IO_ERROR;
+ }
+ }
+
+ return n;
+}
+
+/**
+ * @brief Reads @a n characters from bus @a bus and stores it in @a in.
+ *
+ * Writes idle characters to receive data.
+ *
+ * @see mpc55xx_dspi_read_write().
+ */
+static int mpc55xx_dspi_read( rtems_libi2c_bus_t *bus, unsigned char *in, int n)
+{
+ return mpc55xx_dspi_read_write( bus, in, NULL, n);
+}
+
+/**
+ * @brief Writes @a n characters from @a out to bus @a bus.
+ *
+ * Discards the synchronously received data.
+ *
+ * @see mpc55xx_dspi_read_write().
+ */
+static int mpc55xx_dspi_write( rtems_libi2c_bus_t *bus, unsigned char *out, int n)
+{
+ return mpc55xx_dspi_read_write( bus, NULL, out, n);
+}
+
+static int mpc55xx_dspi_ioctl( rtems_libi2c_bus_t *bus, int cmd, void *arg)
+{
+ int rv = -1;
+ switch (cmd) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+ rv = mpc55xx_dspi_set_transfer_mode( bus, (const rtems_libi2c_tfr_mode_t *) arg);
+ break;
+ case RTEMS_LIBI2C_IOCTL_READ_WRITE:
+ rv = mpc55xx_dspi_read_write(
+ bus,
+ ((rtems_libi2c_read_write_t *) arg)->rd_buf,
+ ((rtems_libi2c_read_write_t *) arg)->wr_buf,
+ ((rtems_libi2c_read_write_t *) arg)->byte_cnt
+ );
+ break;
+ default:
+ rv = -RTEMS_NOT_DEFINED;
+ break;
+ }
+ return rv;
+}
+
+static const rtems_libi2c_bus_ops_t mpc55xx_dspi_ops = {
+ .init = mpc55xx_dspi_init,
+ .send_start = mpc55xx_dspi_send_start,
+ .send_stop = mpc55xx_dspi_send_stop,
+ .send_addr = mpc55xx_dspi_send_addr,
+ .read_bytes = mpc55xx_dspi_read,
+ .write_bytes = mpc55xx_dspi_write,
+ .ioctl = mpc55xx_dspi_ioctl
+};
+
+mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { {
+ /* DSPI A */
+ .bus = {
+ .ops = &mpc55xx_dspi_ops,
+ .size = sizeof( mpc55xx_dspi_bus_entry)
+ },
+ .table_index = 0,
+ .bus_number = 0,
+ .regs = &DSPI_A,
+ .master = 1,
+ .push_data = MPC55XX_ZERO_FLAGS,
+ .edma_channel_transmit = 32,
+ .edma_channel_push = 43,
+ .edma_channel_receive = 33,
+ .edma_channel_transmit_update = 0,
+ .edma_channel_receive_update = 0,
+ .edma_channel_transmit_error = 0,
+ .edma_channel_receive_error = 0,
+ .idle_char = 0xffffffff,
+ }, {
+ /* DSPI B */
+ .bus = {
+ .ops = &mpc55xx_dspi_ops,
+ .size = sizeof( mpc55xx_dspi_bus_entry)
+ },
+ .table_index = 1,
+ .bus_number = 0,
+ .regs = &DSPI_B,
+ .master = 1,
+ .push_data = MPC55XX_ZERO_FLAGS,
+ .edma_channel_transmit = 12,
+ .edma_channel_push = 10,
+ .edma_channel_receive = 13,
+ .edma_channel_transmit_update = 0,
+ .edma_channel_receive_update = 0,
+ .edma_channel_transmit_error = 0,
+ .edma_channel_receive_error = 0,
+ .idle_char = 0xffffffff,
+ }, {
+ /* DSPI C */
+ .bus = {
+ .ops = &mpc55xx_dspi_ops,
+ .size = sizeof( mpc55xx_dspi_bus_entry)
+ },
+ .table_index = 2,
+ .bus_number = 0,
+ .regs = &DSPI_C,
+ .master = 1,
+ .push_data = MPC55XX_ZERO_FLAGS,
+ .edma_channel_transmit = 14,
+ .edma_channel_push = 11,
+ .edma_channel_receive = 15,
+ .edma_channel_transmit_update = 0,
+ .edma_channel_receive_update = 0,
+ .edma_channel_transmit_error = 0,
+ .edma_channel_receive_error = 0,
+ .idle_char = 0xffffffff,
+ }, {
+ /* DSPI D */
+ .bus = {
+ .ops = &mpc55xx_dspi_ops,
+ .size = sizeof( mpc55xx_dspi_bus_entry)
+ },
+ .table_index = 3,
+ .bus_number = 0,
+ .regs = &DSPI_D,
+ .master = 1,
+ .push_data = MPC55XX_ZERO_FLAGS,
+ .edma_channel_transmit = 16,
+ .edma_channel_push = 18,
+ .edma_channel_receive = 17,
+ .edma_channel_transmit_update = 0,
+ .edma_channel_receive_update = 0,
+ .edma_channel_transmit_error = 0,
+ .edma_channel_receive_error = 0,
+ .idle_char = 0xffffffff,
+ },
+};