diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-23 15:54:12 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-26 10:40:42 +0200 |
commit | 0cab067f1cd3349907d4cc62e8812f0a5e146d75 (patch) | |
tree | 3f44dd4f8fa5aaca8814ec6c2aec8d1c1c77f414 /bsps/powerpc/gen83xx | |
parent | bsp/bfin: Move libcpu content to bsps (diff) | |
download | rtems-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.c | 262 | ||||
-rw-r--r-- | bsps/powerpc/gen83xx/dev/mpc83xx_i2cdrv.c | 668 | ||||
-rw-r--r-- | bsps/powerpc/gen83xx/dev/mpc83xx_spidrv.c | 675 |
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; +} + + + |