summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/gen83xx
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-23 15:54:12 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-26 10:40:42 +0200
commit0cab067f1cd3349907d4cc62e8812f0a5e146d75 (patch)
tree3f44dd4f8fa5aaca8814ec6c2aec8d1c1c77f414 /bsps/powerpc/gen83xx
parentbsp/bfin: Move libcpu content to bsps (diff)
downloadrtems-0cab067f1cd3349907d4cc62e8812f0a5e146d75.tar.bz2
bsps/powerpc: Move libcpu content to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/powerpc/gen83xx')
-rw-r--r--bsps/powerpc/gen83xx/dev/gtm.c262
-rw-r--r--bsps/powerpc/gen83xx/dev/mpc83xx_i2cdrv.c668
-rw-r--r--bsps/powerpc/gen83xx/dev/mpc83xx_spidrv.c675
3 files changed, 1605 insertions, 0 deletions
diff --git a/bsps/powerpc/gen83xx/dev/gtm.c b/bsps/powerpc/gen83xx/dev/gtm.c
new file mode 100644
index 0000000000..2f13a1d8cd
--- /dev/null
+++ b/bsps/powerpc/gen83xx/dev/gtm.c
@@ -0,0 +1,262 @@
+/**
+ * @file
+ *
+ * @brief Source file for timer functions.
+ */
+
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#include <rtems/bspIo.h>
+
+#include <mpc83xx/mpc83xx.h>
+#include <mpc83xx/gtm.h>
+
+#define RTEMS_STATUS_CHECKS_USE_PRINTK
+
+#include <rtems/status-checks.h>
+
+#define MPC83XX_GTM_CHECK_INDEX( timer) \
+ if (( timer) < 0 || ( timer) >= MPC83XX_GTM_NUMBER) { \
+ return RTEMS_INVALID_NUMBER; \
+ }
+
+#define GTM_MODULE(timer) ((timer)/4)
+#define GTM_MODULE_TIMER(timer) ((timer)%4)
+#define GTM_HIGH(timer) (GTM_MODULE_TIMER(timer)/2)
+#define GTM_LOW(timer) (GTM_MODULE_TIMER(timer)%2)
+
+#define MPC83XX_GTM_CLOCK_MASK MPC83XX_GTM_CLOCK_EXTERN
+
+static const uint8_t mpc83xx_gmt_interrupt_vector_table [MPC83XX_GTM_NUMBER] = { 90, 78, 84, 72, 91, 79, 85, 73 };
+
+rtems_status_code mpc83xx_gtm_initialize( int timer, int clock)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_interrupt_level level;
+
+ unsigned mask = 0xfU << (GTM_LOW(timer) * 4);
+ unsigned flags = 0x3U << (GTM_LOW(timer) * 4);
+ uint8_t reg = 0;
+
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+
+ reg = mpc83xx.gtm [GTM_MODULE(timer)].gtcfr [GTM_HIGH(timer)].reg;
+ mpc83xx.gtm [GTM_MODULE(timer)].gtcfr [GTM_HIGH(timer)].reg =
+ (uint8_t) ((reg & ~mask) | flags);
+
+ mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)] = 0;
+
+ rtems_interrupt_enable( level);
+
+ sc = mpc83xx_gtm_set_clock( timer, clock);
+ RTEMS_CHECK_SC( sc, "Set clock");
+
+ sc = mpc83xx_gtm_set_value( timer, 0);
+ RTEMS_CHECK_SC( sc, "Set value");
+
+ sc = mpc83xx_gtm_set_reference( timer, 0);
+ RTEMS_CHECK_SC( sc, "Set reference");
+
+ sc = mpc83xx_gtm_set_prescale( timer, 0);
+ RTEMS_CHECK_SC( sc, "Set prescale");
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_enable_restart( int timer, bool enable)
+{
+ rtems_interrupt_level level;
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+
+ if (enable) {
+ mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)] |= 0x0008;
+ } else {
+ mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)] &= ~0x0008;
+ }
+
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_set_clock( int timer, int clock)
+{
+ rtems_interrupt_level level;
+ uint16_t reg = 0;
+
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ if (clock & ~MPC83XX_GTM_CLOCK_MASK) {
+ return RTEMS_INVALID_CLOCK;
+ }
+
+ rtems_interrupt_disable( level);
+
+ reg = mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)];
+ mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)] = (reg & ~MPC83XX_GTM_CLOCK_MASK) | clock;
+
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_get_clock( int timer, int *clock)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ *clock = mpc83xx.gtm [GTM_MODULE(timer)]
+ .gt_tim_regs [GTM_HIGH(timer)]
+ .gtmdr [GTM_LOW(timer)] & MPC83XX_GTM_CLOCK_MASK;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_start( int timer)
+{
+ rtems_interrupt_level level;
+ uint8_t flags = 0x2 << (GTM_LOW(timer) * 4);
+
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+ mpc83xx.gtm [GTM_MODULE(timer)]
+.gtcfr [GTM_HIGH(timer)].reg &= ~flags;
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_stop( int timer)
+{
+ rtems_interrupt_level level;
+ uint8_t flags = 0x2 << (GTM_LOW(timer) * 4);
+
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+ mpc83xx.gtm [GTM_MODULE(timer)].gtcfr [GTM_HIGH(timer)].reg |= flags;
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_set_value( int timer, uint16_t value)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtcnr [GTM_LOW(timer)] = value;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_get_value( int timer, uint16_t *value)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ *value = mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtcnr [GTM_LOW(timer)];
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_set_reference( int timer, uint16_t reference)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtrfr [GTM_LOW(timer)] = reference;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_get_reference( int timer, uint16_t *reference)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ *reference = mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtrfr [GTM_LOW(timer)];
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_set_prescale( int timer, uint8_t prescale)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ mpc83xx.gtm [GTM_MODULE(timer)].gtpsr [GTM_MODULE_TIMER(timer)] = prescale;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_get_prescale( int timer, uint8_t *prescale)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ *prescale = mpc83xx.gtm [GTM_MODULE(timer)].gtpsr [GTM_MODULE_TIMER(timer)];
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_interrupt_get_vector( int timer, rtems_vector_number *vector)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ *vector = mpc83xx_gmt_interrupt_vector_table [timer];
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_interrupt_enable( int timer)
+{
+ rtems_interrupt_level level;
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+ mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtmdr [GTM_LOW(timer)] |= 0x0010;
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_interrupt_disable( int timer)
+{
+ rtems_interrupt_level level;
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ rtems_interrupt_disable( level);
+ mpc83xx.gtm [GTM_MODULE(timer)].gt_tim_regs [GTM_HIGH(timer)].gtmdr [GTM_LOW(timer)] &= ~0x0010;
+ rtems_interrupt_enable( level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code mpc83xx_gtm_interrupt_clear( int timer)
+{
+ MPC83XX_GTM_CHECK_INDEX( timer);
+
+ mpc83xx.gtm [GTM_MODULE(timer)].gtevr [GTM_MODULE_TIMER(timer)] = 0x0002;
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/powerpc/gen83xx/dev/mpc83xx_i2cdrv.c b/bsps/powerpc/gen83xx/dev/mpc83xx_i2cdrv.c
new file mode 100644
index 0000000000..b4c3d477f7
--- /dev/null
+++ b/bsps/powerpc/gen83xx/dev/mpc83xx_i2cdrv.c
@@ -0,0 +1,668 @@
+/*===============================================================*\
+| Project: RTEMS support for MPC83xx |
++-----------------------------------------------------------------+
+| Copyright (c) 2007 |
+| 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.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| this file contains the MPC83xx I2C driver |
+\*===============================================================*/
+#include <stdlib.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <mpc83xx/mpc83xx_i2cdrv.h>
+#include <rtems/error.h>
+#include <rtems/bspIo.h>
+#include <errno.h>
+#include <rtems/libi2c.h>
+
+#undef DEBUG
+
+#if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
+ #define I2CCR_MEN (1 << 7) /* module enable */
+#elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
+ #define I2CCR_MDIS (1 << 7) /* module disable */
+#endif
+#define I2CCR_MIEN (1 << 6) /* module interrupt enable */
+#define I2CCR_MSTA (1 << 5) /* 0->1 generates a start condiiton, 1->0 a stop */
+#define I2CCR_MTX (1 << 4) /* 0 = receive mode, 1 = transmit mode */
+#define I2CCR_TXAK (1 << 3) /* 0 = send ack 1 = send nak during receive */
+#define I2CCR_RSTA (1 << 2) /* 1 = send repeated start condition */
+#define I2CCR_BCST (1 << 0) /* 0 = disable 1 = enable broadcast accept */
+
+#define I2CSR_MCF (1 << 7) /* data transfer (0=transfer in progres) */
+#define I2CSR_MAAS (1 << 6) /* addessed as slave */
+#define I2CSR_MBB (1 << 5) /* bus busy */
+#define I2CSR_MAL (1 << 4) /* arbitration lost */
+#define I2CSR_BCSTM (1 << 3) /* broadcast match */
+#define I2CSR_SRW (1 << 2) /* slave read/write */
+#define I2CSR_MIF (1 << 1) /* module interrupt */
+#define I2CSR_RXAK (1 << 0) /* receive acknowledge */
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_i2c_find_clock_divider
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| determine proper divider value |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ uint8_t *result, /* result value */
+ int divider /* requested divider */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ int i;
+ int fdr_val;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ struct {
+ int divider;
+ int fdr_val;
+ } dividers[] ={
+#if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
+ { 256,0x20 }, { 288,0x21 }, { 320,0x22 }, { 352,0x23 },
+ { 384,0x00 }, { 416,0x01 }, { 448,0x25 }, { 480,0x02 },
+ { 512,0x26 }, { 576,0x03 }, { 640,0x04 }, { 704,0x05 },
+ { 768,0x29 }, { 832,0x06 }, { 896,0x2a }, { 1024,0x07 },
+ { 1152,0x08 }, { 1280,0x09 }, { 1536,0x0A }, { 1792,0x2E },
+ { 1920,0x0B }, { 2048,0x2F }, { 2304,0x0C }, { 2560,0x0D },
+ { 3072,0x0E }, { 3584,0x32 }, { 3840,0x0F }, { 4096,0x33 },
+ { 4608,0x10 }, { 5120,0x11 }, { 6144,0x12 }, { 7168,0x36 },
+ { 7680,0x13 }, { 8192,0x37 }, { 9216,0x14 }, {10240,0x15 },
+ {12288,0x16 }, {14336,0x3A }, {15360,0x17 }, {16384,0x3B },
+ {18432,0x18 }, {20480,0x19 }, {24576,0x1A }, {28672,0x3E },
+ {30720,0x1B }, {32768,0x3F }, {36864,0x1C }, {40960,0x1D },
+ {49152,0x1E }, {61440,0x1F }
+#elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
+ { 768, 0x31 }
+#endif
+ };
+
+ if (divider <= 0) {
+ sc = RTEMS_INVALID_NUMBER;
+ }
+
+ if (sc == RTEMS_SUCCESSFUL) {
+ sc = RTEMS_INVALID_NUMBER;
+ for (i = 0, fdr_val = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++) {
+ fdr_val = dividers[i].fdr_val;
+ if (dividers[i].divider >= divider)
+ {
+ sc = RTEMS_SUCCESSFUL;
+ *result = fdr_val;
+ break;
+ }
+ }
+ }
+ return sc;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_i2c_wait
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| wait for i2c to become idle |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ mpc83xx_i2c_softc_t *softc_ptr, /* handle */
+ uint8_t desired_status, /* desired status word */
+ uint8_t status_mask /* status word mask */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ uint8_t act_status;
+ rtems_status_code rc;
+ uint32_t tout;
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_wait called... ");
+#endif
+
+ if (softc_ptr->initialized) {
+ /*
+ * enable interrupt mask
+ */
+ softc_ptr->reg_ptr->i2ccr |= I2CCR_MIEN;
+ rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100);
+ if (rc != RTEMS_SUCCESSFUL) {
+ return rc;
+ }
+ }
+ else {
+ tout = 0;
+ do {
+ if (tout++ > 1000000) {
+#if defined(DEBUG)
+ printk("... exit with RTEMS_TIMEOUT\r\n");
+#endif
+ return RTEMS_TIMEOUT;
+ }
+ } while (!(softc_ptr->reg_ptr->i2csr & I2CSR_MIF));
+ }
+ softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN;
+
+ act_status = softc_ptr->reg_ptr->i2csr;
+ if ((act_status & status_mask) != desired_status) {
+#if defined(DEBUG)
+ printk("... exit with RTEMS_IO_ERROR\r\n");
+#endif
+ return RTEMS_IO_ERROR;
+ }
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_i2c_irq_handler
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| handle interrupts |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_irq_hdl_param handle /* handle, is softc_ptr structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = (mpc83xx_i2c_softc_t *)handle;
+
+ /*
+ * clear IRQ flag
+ */
+ #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
+ softc_ptr->reg_ptr->i2csr &= ~I2CSR_MIF;
+ #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
+ softc_ptr->reg_ptr->i2csr = I2CSR_MIF;
+ #endif
+
+ /*
+ * disable interrupt mask
+ */
+ softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN;
+ if (softc_ptr->initialized) {
+ rtems_semaphore_release(softc_ptr->irq_sema_id);
+ }
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_i2c_irq_on_off
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| enable/disable interrupts (void, handled at different position) |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ const
+ rtems_irq_connect_data *irq_conn_data /* irq connect data */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+}
+
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_i2c_irq_isOn
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| check state of interrupts, void, done differently |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ const
+ rtems_irq_connect_data *irq_conn_data /* irq connect data */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| TRUE, if enabled |
+\*=========================================================================*/
+{
+ return (TRUE);
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_i2c_install_irq_handler
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| (un-)install the interrupt handler |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ mpc83xx_i2c_softc_t *softc_ptr, /* ptr to control structure */
+ int install /* TRUE: install, FALSE: remove */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+ rtems_status_code rc = RTEMS_SUCCESSFUL;
+
+ rtems_irq_connect_data irq_conn_data = {
+ softc_ptr->irq_number,
+ mpc83xx_i2c_irq_handler, /* rtems_irq_hdl */
+ (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param) */
+ mpc83xx_i2c_irq_on_off, /* (rtems_irq_enable) */
+ mpc83xx_i2c_irq_on_off, /* (rtems_irq_disable) */
+ mpc83xx_i2c_irq_isOn /* (rtems_irq_is_enabled) */
+ };
+
+ /*
+ * (un-)install handler for I2C device
+ */
+ if (install) {
+ /*
+ * create semaphore for IRQ synchronization
+ */
+ rc = rtems_semaphore_create(rtems_build_name('i','2','c','s'),
+ 0,
+ RTEMS_FIFO
+ | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &softc_ptr->irq_sema_id);
+ if (rc != RTEMS_SUCCESSFUL) {
+ rtems_panic("I2C: cannot create semaphore");
+ }
+ if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
+ rtems_panic("I2C: cannot install IRQ handler");
+ }
+ }
+ else {
+ if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) {
+ rtems_panic("I2C: cannot uninstall IRQ handler");
+ }
+ /*
+ * delete sync semaphore
+ */
+ if (softc_ptr->irq_sema_id != 0) {
+ rc = rtems_semaphore_delete(softc_ptr->irq_sema_id);
+ if (rc != RTEMS_SUCCESSFUL) {
+ rtems_panic("I2C: cannot delete semaphore");
+ }
+ }
+ }
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_i2c_init
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| initialize the driver |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+ uint8_t fdr_val;
+ int errval;
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_init called... ");
+#endif
+ /*
+ * init HW registers
+ */
+ /*
+ * init frequency divider to 100kHz
+ */
+ errval = mpc83xx_i2c_find_clock_divider(&fdr_val,
+ softc_ptr->base_frq/100000);
+ if (errval != 0) {
+ return errval;
+ }
+ softc_ptr->reg_ptr->i2cfdr = fdr_val;
+ /*
+ * init digital filter sampling rate
+ */
+ softc_ptr->reg_ptr->i2cdfsrr = 0x10 ; /* no special filtering needed */
+ /*
+ * set own slave address to broadcast (0x00)
+ */
+ softc_ptr->reg_ptr->i2cadr = 0x00 ;
+
+ /*
+ * set control register to module enable
+ */
+ #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
+ softc_ptr->reg_ptr->i2ccr = I2CCR_MEN;
+ #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
+ softc_ptr->reg_ptr->i2ccr = 0;
+ #endif
+
+ /*
+ * init interrupt stuff
+ */
+ mpc83xx_i2c_install_irq_handler(softc_ptr,TRUE);
+
+ /*
+ * mark, that we have initialized
+ */
+ softc_ptr->initialized = TRUE;
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_i2c_send_start
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| send a start condition to bus |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_send_start called... ");
+#endif
+ if (0 != (softc_ptr->reg_ptr->i2ccr & I2CCR_MSTA)) {
+ /*
+ * already started, so send a "repeated start"
+ */
+ softc_ptr->reg_ptr->i2ccr |= I2CCR_RSTA;
+ }
+ else {
+ softc_ptr->reg_ptr->i2ccr |= I2CCR_MSTA;
+ }
+
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return 0;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_i2c_send_stop
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| send a stop condition to bus |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_send_stop called... ");
+#endif
+ softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MSTA;
+ /*
+ * wait, 'til stop has been executed
+ */
+ while (0 != (softc_ptr->reg_ptr->i2csr & I2CSR_MBB)) {
+ rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+ }
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return 0;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_i2c_send_addr
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| address a slave device on the bus |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ uint32_t addr, /* address to send on bus */
+ int rw /* 0=write,1=read */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+ uint8_t addr_byte;
+ rtems_status_code rc;
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_send_addr called... ");
+#endif
+ softc_ptr->reg_ptr->i2ccr |= I2CCR_MTX;
+ /*
+ * determine, whether short or long address is needed, determine rd/wr
+ */
+ if (addr > 0x7f) {
+ addr_byte = (0xf0
+ | ((addr >> 7) & 0x06)
+ | ((rw) ? 1 : 0));
+ /*
+ * send first byte
+ */
+ softc_ptr->reg_ptr->i2cdr = addr_byte;
+ /*
+ * wait for successful transfer
+ */
+ rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK);
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("... exit rc=%d\r\n",rc);
+#endif
+ return rc;
+ }
+ }
+ /*
+ * send (final) byte
+ */
+ addr_byte = ((addr << 1)
+ | ((rw) ? 1 : 0));
+
+ softc_ptr->reg_ptr->i2cdr = addr_byte;
+ /*
+ * wait for successful transfer
+ */
+ rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK);
+
+#if defined(DEBUG)
+ printk("... exit rc=%d\r\n",rc);
+#endif
+ return rc;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_i2c_read_bytes
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| receive some bytes from I2C device |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to store bytes */
+ int len /* number of bytes to receive */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| number of bytes received or (negative) error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+ rtems_status_code rc;
+ unsigned char *p = buf;
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_read_bytes called... ");
+#endif
+ softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MTX;
+ softc_ptr->reg_ptr->i2ccr &= ~I2CCR_TXAK;
+ /*
+ * FIXME: do we need to deactivate TXAK from the start,
+ * when only one byte is to be received?
+ */
+ /*
+ * we need a dummy transfer here to start the first read
+ */
+ softc_ptr->reg_ptr->i2cdr;
+
+ while (len-- > 0) {
+ if (len == 0) {
+ /*
+ * last byte is not acknowledged
+ */
+ softc_ptr->reg_ptr->i2ccr |= I2CCR_TXAK;
+ }
+ /*
+ * wait 'til end of transfer
+ */
+ rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF);
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("... exit rc=%d\r\n",-rc);
+#endif
+ return -rc;
+ }
+ *p++ = softc_ptr->reg_ptr->i2cdr;
+
+ }
+
+ /*
+ * wait 'til end of last transfer
+ */
+ rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF);
+
+#if defined(DEBUG)
+ printk("... exit OK, rc=%d\r\n",p-buf);
+#endif
+ return p - buf;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_i2c_write_bytes
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| send some bytes to I2C device |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to send */
+ int len /* number of bytes to send */
+
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| number of bytes sent or (negative) error code |
+\*=========================================================================*/
+{
+ mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
+ rtems_status_code rc;
+ unsigned char *p = buf;
+
+#if defined(DEBUG)
+ printk("mpc83xx_i2c_write_bytes called... ");
+#endif
+ softc_ptr->reg_ptr->i2ccr =
+ (softc_ptr->reg_ptr->i2ccr & ~I2CCR_TXAK) | I2CCR_MTX;
+ while (len-- > 0) {
+ int rxack = len != 0 ? I2CSR_RXAK : 0;
+
+ softc_ptr->reg_ptr->i2cdr = *p++;
+ /*
+ * wait 'til end of transfer
+ */
+ rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | rxack);
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("... exit rc=%d\r\n",-rc);
+#endif
+ return -rc;
+ }
+ }
+#if defined(DEBUG)
+ printk("... exit OK, rc=%d\r\n",p-buf);
+#endif
+ return p - buf;
+}
+
+rtems_libi2c_bus_ops_t mpc83xx_i2c_ops = {
+ .init = mpc83xx_i2c_init,
+ .send_start = mpc83xx_i2c_send_start,
+ .send_stop = mpc83xx_i2c_send_stop,
+ .send_addr = mpc83xx_i2c_send_addr,
+ .read_bytes = mpc83xx_i2c_read_bytes,
+ .write_bytes = mpc83xx_i2c_write_bytes,
+};
+
diff --git a/bsps/powerpc/gen83xx/dev/mpc83xx_spidrv.c b/bsps/powerpc/gen83xx/dev/mpc83xx_spidrv.c
new file mode 100644
index 0000000000..5534b4b72a
--- /dev/null
+++ b/bsps/powerpc/gen83xx/dev/mpc83xx_spidrv.c
@@ -0,0 +1,675 @@
+/*===============================================================*\
+| Project: RTEMS support for MPC83xx |
++-----------------------------------------------------------------+
+| Copyright (c) 2007 |
+| 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.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| this file contains the MPC83xx SPI driver |
+| NOTE: it uses the same API as the I2C driver |
+\*===============================================================*/
+#include <stdlib.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <mpc83xx/mpc83xx.h>
+#include <mpc83xx/mpc83xx_spidrv.h>
+#include <rtems/error.h>
+#include <rtems/bspIo.h>
+#include <errno.h>
+#include <rtems/libi2c.h>
+
+#undef DEBUG
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_spi_baud_to_mode
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| determine proper divider value |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ uint32_t baudrate, /* desired baudrate */
+ uint32_t base_frq, /* input frequency */
+ uint32_t *spimode /* result value */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ uint32_t divider;
+ uint32_t tmpmode = 0;
+ /*
+ * determine clock divider and DIV16 bit
+ */
+ divider = (base_frq+baudrate-1)/baudrate;
+ if (divider > 64) {
+ tmpmode = MPC83XX_SPIMODE_DIV16;
+ divider /= 16;
+ }
+ if ((divider < 1) ||
+ (divider > 64)) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ else {
+ tmpmode |= MPC83XX_SPIMODE_PM(divider/4-1);
+ }
+ *spimode = tmpmode;
+ return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code mpc83xx_spi_char_mode
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| determine proper value for character size |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ mpc83xx_spi_softc_t *softc_ptr, /* handle */
+ uint32_t bits_per_char, /* bits per character */
+ bool lsb_first, /* TRUE: send LSB first */
+ uint32_t *spimode /* result value */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ uint32_t tmpmode;
+
+ if (bits_per_char == 32) {
+ tmpmode = 0;
+ softc_ptr->bytes_per_char = 4;
+ softc_ptr->bit_shift = 0;
+ }
+ else {
+ if (lsb_first) {
+ /*
+ * non-reversed data (LSB first): 4..16 bits valid
+ * always aligned to bit 16 of data register
+ */
+ if ((bits_per_char >= 4) &&
+ (bits_per_char <= 16)) {
+ tmpmode = MPC83XX_SPIMODE_LEN( bits_per_char-1);
+ softc_ptr->bytes_per_char = (bits_per_char > 8) ? 2 : 1;
+ softc_ptr->bit_shift = 16-bits_per_char;
+ }
+ else {
+ return RTEMS_INVALID_NUMBER;
+ }
+ }
+ else {
+ /*
+ * reversed data (MSB first): only 8/16/32 bits valid,
+ * always in lowest bits of data register
+ */
+ if (bits_per_char == 8) {
+ tmpmode = MPC83XX_SPIMODE_LEN(8-1);
+ softc_ptr->bytes_per_char = 1;
+ softc_ptr->bit_shift = 0;
+ }
+ else if (bits_per_char == 16) {
+ tmpmode = MPC83XX_SPIMODE_LEN(16-1);
+ softc_ptr->bytes_per_char = 2;
+ softc_ptr->bit_shift = 0;
+ }
+ else {
+ return RTEMS_INVALID_NUMBER;
+ }
+ }
+ }
+
+ *spimode = tmpmode;
+ return 0;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_spi_wait
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| wait for spi to become idle |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ mpc83xx_spi_softc_t *softc_ptr, /* handle */
+ uint32_t irq_mask, /* irq mask to use */
+ uint32_t desired_status, /* desired status word */
+ uint32_t status_mask /* status word mask */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ uint32_t act_status;
+ rtems_status_code rc;
+ uint32_t tout;
+
+#if defined(DEBUG)
+ printk("mpc83xx_spi_wait called... ");
+#endif
+ if (softc_ptr->initialized) {
+ /*
+ * allow interrupts, when receiver is not empty
+ */
+ softc_ptr->reg_ptr->spim = irq_mask;
+ rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100);
+ if (rc != RTEMS_SUCCESSFUL) {
+ return rc;
+ }
+ }
+ else {
+ tout = 0;
+ do {
+ if (tout++ > 1000000) {
+#if defined(DEBUG)
+ printk("... exit with RTEMS_TIMEOUT\r\n");
+#endif
+ return RTEMS_TIMEOUT;
+ }
+ /*
+ * wait for SPI to terminate
+ */
+ } while (!(softc_ptr->reg_ptr->spie & MPC83XX_SPIE_NE));
+ }
+
+ act_status = softc_ptr->reg_ptr->spie;
+ if ((act_status & status_mask)!= desired_status) {
+#if defined(DEBUG)
+ printk("... exit with RTEMS_IO_ERROR,"
+ "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n",
+ act_status,status_mask,desired_status);
+#endif
+ return RTEMS_IO_ERROR;
+ }
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_spi_irq_handler
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| handle interrupts |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_irq_hdl_param handle /* handle, is softc_ptr structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+ mpc83xx_spi_softc_t *softc_ptr = (mpc83xx_spi_softc_t *)handle;
+
+ /*
+ * disable interrupt mask
+ */
+ softc_ptr->reg_ptr->spim = 0;
+ if (softc_ptr->initialized) {
+ rtems_semaphore_release(softc_ptr->irq_sema_id);
+ }
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_spi_irq_on_off
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| enable/disable interrupts (void, handled at different position) |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ const
+ rtems_irq_connect_data *irq_conn_data /* irq connect data */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+}
+
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static int mpc83xx_spi_irq_isOn
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| check state of interrupts, void, done differently |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ const
+ rtems_irq_connect_data *irq_conn_data /* irq connect data */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| TRUE, if enabled |
+\*=========================================================================*/
+{
+ return (TRUE);
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+static void mpc83xx_spi_install_irq_handler
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| (un-)install the interrupt handler |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ mpc83xx_spi_softc_t *softc_ptr, /* ptr to control structure */
+ int install /* TRUE: install, FALSE: remove */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| <none> |
+\*=========================================================================*/
+{
+ rtems_status_code rc = RTEMS_SUCCESSFUL;
+
+ rtems_irq_connect_data irq_conn_data = {
+ softc_ptr->irq_number,
+ mpc83xx_spi_irq_handler, /* rtems_irq_hdl */
+ (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param) */
+ mpc83xx_spi_irq_on_off, /* (rtems_irq_enable) */
+ mpc83xx_spi_irq_on_off, /* (rtems_irq_disable) */
+ mpc83xx_spi_irq_isOn /* (rtems_irq_is_enabled) */
+ };
+
+ /*
+ * (un-)install handler for SPI device
+ */
+ if (install) {
+ /*
+ * create semaphore for IRQ synchronization
+ */
+ rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
+ 0,
+ RTEMS_FIFO
+ | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &softc_ptr->irq_sema_id);
+ if (rc != RTEMS_SUCCESSFUL) {
+ rtems_panic("SPI: cannot create semaphore");
+ }
+ if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
+ rtems_panic("SPI: cannot install IRQ handler");
+ }
+ }
+ else {
+ if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) {
+ rtems_panic("SPI: cannot uninstall IRQ handler");
+ }
+ /*
+ * delete sync semaphore
+ */
+ if (softc_ptr->irq_sema_id != 0) {
+ rc = rtems_semaphore_delete(softc_ptr->irq_sema_id);
+ if (rc != RTEMS_SUCCESSFUL) {
+ rtems_panic("SPI: cannot delete semaphore");
+ }
+ }
+ }
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+rtems_status_code mpc83xx_spi_init
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| initialize the driver |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| o = ok or error code |
+\*=========================================================================*/
+{
+ mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
+#if defined(DEBUG)
+ printk("mpc83xx_spi_init called... ");
+#endif
+ /*
+ * init HW registers:
+ */
+ /*
+ * FIXME: set default mode in SPIM
+ */
+
+ /*
+ * init interrupt stuff
+ */
+ mpc83xx_spi_install_irq_handler(softc_ptr,TRUE);
+
+ /*
+ * mark, that we have initialized
+ */
+ softc_ptr->initialized = TRUE;
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+int mpc83xx_spi_read_write_bytes
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| transmit/receive some bytes from SPI device |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *rbuf, /* buffer to store bytes */
+ const unsigned char *tbuf, /* buffer to send bytes */
+ int len /* number of bytes to transceive */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| number of bytes received or (negative) error code |
+\*=========================================================================*/
+{
+ mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
+ rtems_status_code rc;
+ int bc = 0;
+ int bytes_per_char = softc_ptr->bytes_per_char;
+ int bit_shift = softc_ptr->bit_shift;
+ uint32_t spird_val;
+
+#if defined(DEBUG)
+ printk("mpc83xx_spi_read_write_bytes called... ");
+#endif
+
+ while (len > bytes_per_char-1) {
+ len -= bytes_per_char;
+ /*
+ * mark last byte in SPCOM
+ */
+#if defined(USE_LAST_BIT)
+ softc_ptr->reg_ptr->spcom = (len < bytes_per_char) ? MPC83XX_SPCOM_LST : 0;
+#else
+ softc_ptr->reg_ptr->spcom = 0;
+#endif
+ if (tbuf == NULL) {
+ /*
+ * perform idle char write to read byte
+ */
+ softc_ptr->reg_ptr->spitd = softc_ptr->idle_char << bit_shift;
+ }
+ else {
+ switch(bytes_per_char) {
+ case 1:
+ softc_ptr->reg_ptr->spitd = (*(uint8_t *)tbuf) << bit_shift;
+ break;
+ case 2:
+ softc_ptr->reg_ptr->spitd = (*(uint16_t *)tbuf) << bit_shift;
+ break;
+ case 4:
+ softc_ptr->reg_ptr->spitd = (*(uint32_t *)tbuf) << bit_shift;
+ break;
+ }
+ tbuf += softc_ptr->bytes_per_char;
+ }
+ /*
+ * wait 'til end of transfer
+ */
+#if defined(USE_LAST_BIT)
+ rc = mpc83xx_spi_wait(softc_ptr,
+ ((len == 0)
+ ? MPC83XX_SPIE_LT
+ : MPC83XX_SPIE_NE),
+ ((len == 0)
+ ? MPC83XX_SPIE_LT
+ : MPC83XX_SPIE_NF)
+ | MPC83XX_SPIE_NE,
+ MPC83XX_SPIE_LT
+ | MPC83XX_SPIE_OV
+ | MPC83XX_SPIE_UN
+ | MPC83XX_SPIE_NE
+ | MPC83XX_SPIE_NF);
+ if (len == 0) {
+ /*
+ * clear the "last transfer complete" event
+ */
+ softc_ptr->reg_ptr->spie = MPC83XX_SPIE_LT;
+ }
+#else
+ rc = mpc83xx_spi_wait(softc_ptr,
+ MPC83XX_SPIE_NE,
+ MPC83XX_SPIE_NF
+ | MPC83XX_SPIE_NE,
+ MPC83XX_SPIE_OV
+ | MPC83XX_SPIE_UN
+ | MPC83XX_SPIE_NE
+ | MPC83XX_SPIE_NF);
+#endif
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("... exit rc=%d\r\n",-rc);
+#endif
+ return -rc;
+ }
+ spird_val = softc_ptr->reg_ptr->spird;
+ if (rbuf != NULL) {
+ switch(bytes_per_char) {
+ case 1:
+ (*(uint8_t *)rbuf) = spird_val >> bit_shift;
+ break;
+ case 2:
+ (*(uint16_t *)rbuf) = spird_val >> bit_shift;
+ break;
+ case 4:
+ (*(uint32_t *)rbuf) = spird_val >> bit_shift;
+ break;
+ }
+ rbuf += bytes_per_char;
+ }
+ bc += bytes_per_char;
+ }
+#if defined(DEBUG)
+ printk("... exit OK, rc=%d\r\n",bc);
+#endif
+ return bc;
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+int mpc83xx_spi_read_bytes
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| receive some bytes from SPI device |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to store bytes */
+ int len /* number of bytes to receive */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| number of bytes received or (negative) error code |
+\*=========================================================================*/
+{
+ return mpc83xx_spi_read_write_bytes(bh,buf,NULL,len);
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+int mpc83xx_spi_write_bytes
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| send some bytes to SPI device |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to send */
+ int len /* number of bytes to send */
+
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| number of bytes sent or (negative) error code |
+\*=========================================================================*/
+{
+ return mpc83xx_spi_read_write_bytes(bh,NULL,buf,len);
+}
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+rtems_status_code mpc83xx_spi_set_tfr_mode
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| set SPI to desired baudrate/clock mode/character mode |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| rtems_status_code |
+\*=========================================================================*/
+{
+ mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc);
+ uint32_t spimode_baud,spimode;
+ rtems_status_code rc = RTEMS_SUCCESSFUL;
+
+ /* Set idle character */
+ softc_ptr->idle_char = tfr_mode->idle_char;
+
+ /*
+ * FIXME: set proper mode
+ */
+ if (rc == RTEMS_SUCCESSFUL) {
+ rc = mpc83xx_spi_baud_to_mode(tfr_mode->baudrate,
+ softc_ptr->base_frq,
+ &spimode_baud);
+ }
+ if (rc == RTEMS_SUCCESSFUL) {
+ rc = mpc83xx_spi_char_mode(softc_ptr,
+ tfr_mode->bits_per_char,
+ tfr_mode->lsb_first,
+ &spimode);
+ }
+ if (rc == RTEMS_SUCCESSFUL) {
+ spimode |= spimode_baud;
+ spimode |= MPC83XX_SPIMODE_M_S; /* set master mode */
+ if (!tfr_mode->lsb_first) {
+ spimode |= MPC83XX_SPIMODE_REV;
+ }
+ if (tfr_mode->clock_inv) {
+ spimode |= MPC83XX_SPIMODE_CI;
+ }
+ if (tfr_mode->clock_phs) {
+ spimode |= MPC83XX_SPIMODE_CP;
+ }
+ }
+
+ if (rc == RTEMS_SUCCESSFUL) {
+ /*
+ * disable SPI
+ */
+ softc_ptr->reg_ptr->spmode &= ~MPC83XX_SPIMODE_EN;
+ /*
+ * set new mode and reenable SPI
+ */
+ softc_ptr->reg_ptr->spmode = spimode | MPC83XX_SPIMODE_EN;
+ }
+ return rc;
+}
+
+
+/*=========================================================================*\
+| Function: |
+\*-------------------------------------------------------------------------*/
+int mpc83xx_spi_ioctl
+(
+/*-------------------------------------------------------------------------*\
+| Purpose: |
+| perform selected ioctl function for SPI |
++---------------------------------------------------------------------------+
+| Input Parameters: |
+\*-------------------------------------------------------------------------*/
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ int cmd, /* ioctl command code */
+ void *arg /* additional argument array */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value: |
+| rtems_status_code |
+\*=========================================================================*/
+{
+ int ret_val = -1;
+
+ switch(cmd) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+ ret_val =
+ -mpc83xx_spi_set_tfr_mode(bh,
+ (const rtems_libi2c_tfr_mode_t *)arg);
+ break;
+ case RTEMS_LIBI2C_IOCTL_READ_WRITE:
+ ret_val =
+ mpc83xx_spi_read_write_bytes(bh,
+ ((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:
+ ret_val = -RTEMS_NOT_DEFINED;
+ break;
+ }
+ return ret_val;
+}
+
+
+