Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:53

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * RTEMS support for MPC83xx
0005  *
0006  * This file contains the MPC83xx I2C driver.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2007 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include <stdlib.h>
0035 #include <bsp.h>
0036 #include <bsp/irq.h>
0037 #include <mpc83xx/mpc83xx_i2cdrv.h>
0038 #include <rtems/error.h>
0039 #include <rtems/bspIo.h>
0040 #include <errno.h>
0041 #include <rtems/libi2c.h>
0042 
0043 #undef DEBUG
0044 
0045 #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
0046   #define I2CCR_MEN  (1 << 7)   /* module enable */
0047 #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0048   #define I2CCR_MDIS (1 << 7)   /* module disable */
0049 #endif
0050 #define I2CCR_MIEN (1 << 6)     /* module interrupt enable */
0051 #define I2CCR_MSTA (1 << 5)     /* 0->1 generates a start condiiton, 1->0 a stop */
0052 #define I2CCR_MTX  (1 << 4)     /* 0 = receive mode, 1 = transmit mode           */
0053 #define I2CCR_TXAK (1 << 3)     /* 0 = send ack 1 = send nak during receive      */
0054 #define I2CCR_RSTA (1 << 2)     /* 1 = send repeated start condition             */
0055 #define I2CCR_BCST (1 << 0)     /* 0 = disable 1 = enable broadcast accept       */
0056 
0057 #define I2CSR_MCF  (1 << 7)     /* data transfer (0=transfer in progres) */
0058 #define I2CSR_MAAS (1 << 6)     /* addessed as slave   */
0059 #define I2CSR_MBB  (1 << 5)     /* bus busy            */
0060 #define I2CSR_MAL  (1 << 4)     /* arbitration lost    */
0061 #define I2CSR_BCSTM (1 << 3)    /* broadcast match     */
0062 #define I2CSR_SRW  (1 << 2)     /* slave read/write    */
0063 #define I2CSR_MIF  (1 << 1)     /* module interrupt    */
0064 #define I2CSR_RXAK (1 << 0)     /* receive acknowledge */
0065 
0066 /*=========================================================================*\
0067 | Function:                                                                 |
0068 \*-------------------------------------------------------------------------*/
0069 static rtems_status_code mpc83xx_i2c_find_clock_divider
0070 (
0071 /*-------------------------------------------------------------------------*\
0072 | Purpose:                                                                  |
0073 |   determine proper divider value                                          |
0074 +---------------------------------------------------------------------------+
0075 | Input Parameters:                                                         |
0076 \*-------------------------------------------------------------------------*/
0077  uint8_t *result,                        /* result value                   */
0078  int divider                             /* requested divider              */
0079 )
0080 /*-------------------------------------------------------------------------*\
0081 | Return Value:                                                             |
0082 |    o = ok or error code                                                   |
0083 \*=========================================================================*/
0084 {
0085   int i;
0086   int fdr_val;
0087   rtems_status_code sc = RTEMS_SUCCESSFUL;
0088   struct {
0089     int divider;
0090     int fdr_val;
0091   } dividers[] ={
0092 #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
0093     {  256,0x20 }, {  288,0x21 }, {  320,0x22 }, {  352,0x23 },
0094     {  384,0x00 }, {  416,0x01 }, {  448,0x25 }, {  480,0x02 },
0095     {  512,0x26 }, {  576,0x03 }, {  640,0x04 }, {  704,0x05 },
0096     {  768,0x29 }, {  832,0x06 }, {  896,0x2a }, { 1024,0x07 },
0097     { 1152,0x08 }, { 1280,0x09 }, { 1536,0x0A }, { 1792,0x2E },
0098     { 1920,0x0B }, { 2048,0x2F }, { 2304,0x0C }, { 2560,0x0D },
0099     { 3072,0x0E }, { 3584,0x32 }, { 3840,0x0F }, { 4096,0x33 },
0100     { 4608,0x10 }, { 5120,0x11 }, { 6144,0x12 }, { 7168,0x36 },
0101     { 7680,0x13 }, { 8192,0x37 }, { 9216,0x14 }, {10240,0x15 },
0102     {12288,0x16 }, {14336,0x3A }, {15360,0x17 }, {16384,0x3B },
0103     {18432,0x18 }, {20480,0x19 }, {24576,0x1A }, {28672,0x3E },
0104     {30720,0x1B }, {32768,0x3F }, {36864,0x1C }, {40960,0x1D },
0105     {49152,0x1E }, {61440,0x1F }
0106 #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0107     { 768, 0x31 }
0108 #endif
0109   };
0110 
0111   if (divider <= 0) {
0112     sc = RTEMS_INVALID_NUMBER;
0113   }
0114 
0115   if (sc == RTEMS_SUCCESSFUL) {
0116     sc = RTEMS_INVALID_NUMBER;
0117     for (i = 0, fdr_val = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++) {
0118       fdr_val = dividers[i].fdr_val;
0119       if (dividers[i].divider >= divider)
0120     {
0121       sc = RTEMS_SUCCESSFUL;
0122       *result = fdr_val;
0123       break;
0124     }
0125     }
0126   }
0127   return sc;
0128 }
0129 
0130 /*=========================================================================*\
0131 | Function:                                                                 |
0132 \*-------------------------------------------------------------------------*/
0133 static int mpc83xx_i2c_wait
0134 (
0135 /*-------------------------------------------------------------------------*\
0136 | Purpose:                                                                  |
0137 |   wait for i2c to become idle                                             |
0138 +---------------------------------------------------------------------------+
0139 | Input Parameters:                                                         |
0140 \*-------------------------------------------------------------------------*/
0141  mpc83xx_i2c_softc_t *softc_ptr,          /* handle              */
0142  uint8_t              desired_status,     /* desired status word */
0143  uint8_t              status_mask         /* status word mask    */
0144 )
0145 /*-------------------------------------------------------------------------*\
0146 | Return Value:                                                             |
0147 |    o = ok or error code                                                   |
0148 \*=========================================================================*/
0149 {
0150   uint8_t act_status;
0151   rtems_status_code rc;
0152   uint32_t tout;
0153 
0154 #if defined(DEBUG)
0155   printk("mpc83xx_i2c_wait called... ");
0156 #endif
0157 
0158   if (softc_ptr->initialized) {
0159     /*
0160      * enable interrupt mask
0161      */
0162     softc_ptr->reg_ptr->i2ccr |= I2CCR_MIEN;
0163     rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100);
0164     if (rc != RTEMS_SUCCESSFUL) {
0165       return rc;
0166     }
0167   }
0168   else {
0169     tout = 0;
0170     do {
0171       if (tout++ > 1000000) {
0172 #if defined(DEBUG)
0173     printk("... exit with RTEMS_TIMEOUT\r\n");
0174 #endif
0175     return RTEMS_TIMEOUT;
0176       }
0177     } while (!(softc_ptr->reg_ptr->i2csr & I2CSR_MIF));
0178   }
0179   softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN;
0180 
0181   act_status = softc_ptr->reg_ptr->i2csr;
0182   if ((act_status  & status_mask) != desired_status) {
0183 #if defined(DEBUG)
0184     printk("... exit with RTEMS_IO_ERROR\r\n");
0185 #endif
0186     return RTEMS_IO_ERROR;
0187   }
0188 #if defined(DEBUG)
0189     printk("... exit OK\r\n");
0190 #endif
0191   return RTEMS_SUCCESSFUL;
0192 }
0193 
0194 /*=========================================================================*\
0195 | Function:                                                                 |
0196 \*-------------------------------------------------------------------------*/
0197 static void mpc83xx_i2c_irq_handler
0198 (
0199 /*-------------------------------------------------------------------------*\
0200 | Purpose:                                                                  |
0201 |   handle interrupts                                                       |
0202 +---------------------------------------------------------------------------+
0203 | Input Parameters:                                                         |
0204 \*-------------------------------------------------------------------------*/
0205  rtems_irq_hdl_param handle     /* handle, is softc_ptr structure          */
0206 )
0207 /*-------------------------------------------------------------------------*\
0208 | Return Value:                                                             |
0209 |    <none>                                                                 |
0210 \*=========================================================================*/
0211 {
0212   mpc83xx_i2c_softc_t *softc_ptr = (mpc83xx_i2c_softc_t *)handle;
0213 
0214   /*
0215    * clear IRQ flag
0216    */
0217   #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
0218     softc_ptr->reg_ptr->i2csr &= ~I2CSR_MIF;
0219   #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0220     softc_ptr->reg_ptr->i2csr = I2CSR_MIF;
0221   #endif
0222 
0223   /*
0224    * disable interrupt mask
0225    */
0226   softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN;
0227   if (softc_ptr->initialized) {
0228     rtems_semaphore_release(softc_ptr->irq_sema_id);
0229   }
0230 }
0231 
0232 /*=========================================================================*\
0233 | Function:                                                                 |
0234 \*-------------------------------------------------------------------------*/
0235 static void mpc83xx_i2c_irq_on_off
0236 (
0237 /*-------------------------------------------------------------------------*\
0238 | Purpose:                                                                  |
0239 |   enable/disable interrupts (void, handled at different position)         |
0240 +---------------------------------------------------------------------------+
0241 | Input Parameters:                                                         |
0242 \*-------------------------------------------------------------------------*/
0243  const
0244  rtems_irq_connect_data *irq_conn_data   /* irq connect data                */
0245 )
0246 /*-------------------------------------------------------------------------*\
0247 | Return Value:                                                             |
0248 |    <none>                                                                 |
0249 \*=========================================================================*/
0250 {
0251 }
0252 
0253 
0254 /*=========================================================================*\
0255 | Function:                                                                 |
0256 \*-------------------------------------------------------------------------*/
0257 static int mpc83xx_i2c_irq_isOn
0258 (
0259 /*-------------------------------------------------------------------------*\
0260 | Purpose:                                                                  |
0261 |   check state of interrupts, void, done differently                       |
0262 +---------------------------------------------------------------------------+
0263 | Input Parameters:                                                         |
0264 \*-------------------------------------------------------------------------*/
0265  const
0266  rtems_irq_connect_data *irq_conn_data  /* irq connect data                */
0267 )
0268 /*-------------------------------------------------------------------------*\
0269 | Return Value:                                                             |
0270 |    TRUE, if enabled                                                       |
0271 \*=========================================================================*/
0272 {
0273   return (TRUE);
0274 }
0275 
0276 /*=========================================================================*\
0277 | Function:                                                                 |
0278 \*-------------------------------------------------------------------------*/
0279 static void mpc83xx_i2c_install_irq_handler
0280 (
0281 /*-------------------------------------------------------------------------*\
0282 | Purpose:                                                                  |
0283 |   (un-)install the interrupt handler                                      |
0284 +---------------------------------------------------------------------------+
0285 | Input Parameters:                                                         |
0286 \*-------------------------------------------------------------------------*/
0287  mpc83xx_i2c_softc_t *softc_ptr,        /* ptr to control structure        */
0288  int install                            /* TRUE: install, FALSE: remove    */
0289 )
0290 /*-------------------------------------------------------------------------*\
0291 | Return Value:                                                             |
0292 |    <none>                                                                 |
0293 \*=========================================================================*/
0294 {
0295   rtems_status_code rc = RTEMS_SUCCESSFUL;
0296 
0297   rtems_irq_connect_data irq_conn_data = {
0298     softc_ptr->irq_number,
0299     mpc83xx_i2c_irq_handler,           /* rtems_irq_hdl           */
0300     (rtems_irq_hdl_param)softc_ptr,    /* (rtems_irq_hdl_param)   */
0301     mpc83xx_i2c_irq_on_off,            /* (rtems_irq_enable)      */
0302     mpc83xx_i2c_irq_on_off,            /* (rtems_irq_disable)     */
0303     mpc83xx_i2c_irq_isOn               /* (rtems_irq_is_enabled)  */
0304   };
0305 
0306   /*
0307    * (un-)install handler for I2C device
0308    */
0309   if (install) {
0310     /*
0311      * create semaphore for IRQ synchronization
0312      */
0313     rc = rtems_semaphore_create(rtems_build_name('i','2','c','s'),
0314                 0,
0315                 RTEMS_FIFO
0316                 | RTEMS_SIMPLE_BINARY_SEMAPHORE,
0317                 0,
0318                 &softc_ptr->irq_sema_id);
0319     if (rc != RTEMS_SUCCESSFUL) {
0320       rtems_panic("I2C: cannot create semaphore");
0321     }
0322     if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
0323       rtems_panic("I2C: cannot install IRQ handler");
0324     }
0325   }
0326   else {
0327     if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) {
0328       rtems_panic("I2C: cannot uninstall IRQ handler");
0329     }
0330     /*
0331      * delete sync semaphore
0332      */
0333     if (softc_ptr->irq_sema_id != 0) {
0334       rc = rtems_semaphore_delete(softc_ptr->irq_sema_id);
0335       if (rc != RTEMS_SUCCESSFUL) {
0336     rtems_panic("I2C: cannot delete semaphore");
0337       }
0338     }
0339   }
0340 }
0341 
0342 /*=========================================================================*\
0343 | Function:                                                                 |
0344 \*-------------------------------------------------------------------------*/
0345 static rtems_status_code mpc83xx_i2c_init
0346 (
0347 /*-------------------------------------------------------------------------*\
0348 | Purpose:                                                                  |
0349 |   initialize the driver                                                   |
0350 +---------------------------------------------------------------------------+
0351 | Input Parameters:                                                         |
0352 \*-------------------------------------------------------------------------*/
0353  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0354 )
0355 /*-------------------------------------------------------------------------*\
0356 | Return Value:                                                             |
0357 |    o = ok or error code                                                   |
0358 \*=========================================================================*/
0359 {
0360   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0361   uint8_t fdr_val;
0362   int errval;
0363 #if defined(DEBUG)
0364   printk("mpc83xx_i2c_init called... ");
0365 #endif
0366   /*
0367    * init HW registers
0368    */
0369   /*
0370    * init frequency divider to 100kHz
0371    */
0372   errval = mpc83xx_i2c_find_clock_divider(&fdr_val,
0373                       softc_ptr->base_frq/100000);
0374   if (errval != 0) {
0375     return errval;
0376   }
0377   softc_ptr->reg_ptr->i2cfdr = fdr_val;
0378   /*
0379    * init digital filter sampling rate
0380    */
0381   softc_ptr->reg_ptr->i2cdfsrr = 0x10 ; /* no special filtering needed */
0382   /*
0383    * set own slave address to broadcast (0x00)
0384    */
0385   softc_ptr->reg_ptr->i2cadr = 0x00 ;
0386 
0387   /*
0388    * set control register to module enable
0389    */
0390   #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H)
0391     softc_ptr->reg_ptr->i2ccr = I2CCR_MEN;
0392   #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H)
0393     softc_ptr->reg_ptr->i2ccr = 0;
0394   #endif
0395 
0396   /*
0397    * init interrupt stuff
0398    */
0399   mpc83xx_i2c_install_irq_handler(softc_ptr,TRUE);
0400 
0401   /*
0402    * mark, that we have initialized
0403    */
0404   softc_ptr->initialized = TRUE;
0405 #if defined(DEBUG)
0406   printk("... exit OK\r\n");
0407 #endif
0408   return RTEMS_SUCCESSFUL;
0409 }
0410 
0411 /*=========================================================================*\
0412 | Function:                                                                 |
0413 \*-------------------------------------------------------------------------*/
0414 static rtems_status_code mpc83xx_i2c_send_start
0415 (
0416 /*-------------------------------------------------------------------------*\
0417 | Purpose:                                                                  |
0418 |   send a start condition to bus                                           |
0419 +---------------------------------------------------------------------------+
0420 | Input Parameters:                                                         |
0421 \*-------------------------------------------------------------------------*/
0422  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0423 )
0424 /*-------------------------------------------------------------------------*\
0425 | Return Value:                                                             |
0426 |    o = ok or error code                                                   |
0427 \*=========================================================================*/
0428 {
0429   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0430 
0431 #if defined(DEBUG)
0432   printk("mpc83xx_i2c_send_start called... ");
0433 #endif
0434   if (0 != (softc_ptr->reg_ptr->i2ccr & I2CCR_MSTA)) {
0435     /*
0436      * already started, so send a "repeated start"
0437      */
0438     softc_ptr->reg_ptr->i2ccr |= I2CCR_RSTA;
0439   }
0440   else {
0441     softc_ptr->reg_ptr->i2ccr |= I2CCR_MSTA;
0442   }
0443 
0444 #if defined(DEBUG)
0445   printk("... exit OK\r\n");
0446 #endif
0447   return 0;
0448 }
0449 
0450 /*=========================================================================*\
0451 | Function:                                                                 |
0452 \*-------------------------------------------------------------------------*/
0453 static rtems_status_code mpc83xx_i2c_send_stop
0454 (
0455 /*-------------------------------------------------------------------------*\
0456 | Purpose:                                                                  |
0457 |   send a stop condition to bus                                            |
0458 +---------------------------------------------------------------------------+
0459 | Input Parameters:                                                         |
0460 \*-------------------------------------------------------------------------*/
0461  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0462 )
0463 /*-------------------------------------------------------------------------*\
0464 | Return Value:                                                             |
0465 |    o = ok or error code                                                   |
0466 \*=========================================================================*/
0467 {
0468   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0469 
0470 #if defined(DEBUG)
0471   printk("mpc83xx_i2c_send_stop called... ");
0472 #endif
0473   softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MSTA;
0474   /*
0475    * wait, 'til stop has been executed
0476    */
0477   while (0 != (softc_ptr->reg_ptr->i2csr & I2CSR_MBB)) {
0478     rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
0479   }
0480 #if defined(DEBUG)
0481   printk("... exit OK\r\n");
0482 #endif
0483   return 0;
0484 }
0485 
0486 /*=========================================================================*\
0487 | Function:                                                                 |
0488 \*-------------------------------------------------------------------------*/
0489 static rtems_status_code mpc83xx_i2c_send_addr
0490 (
0491 /*-------------------------------------------------------------------------*\
0492 | Purpose:                                                                  |
0493 |   address a slave device on the bus                                       |
0494 +---------------------------------------------------------------------------+
0495 | Input Parameters:                                                         |
0496 \*-------------------------------------------------------------------------*/
0497  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0498  uint32_t addr,                          /* address to send on bus         */
0499  int rw                                  /* 0=write,1=read                 */
0500 )
0501 /*-------------------------------------------------------------------------*\
0502 | Return Value:                                                             |
0503 |    o = ok or error code                                                   |
0504 \*=========================================================================*/
0505 {
0506   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0507   uint8_t addr_byte;
0508   rtems_status_code rc;
0509 
0510 #if defined(DEBUG)
0511   printk("mpc83xx_i2c_send_addr called... ");
0512 #endif
0513   softc_ptr->reg_ptr->i2ccr |= I2CCR_MTX;
0514   /*
0515    * determine, whether short or long address is needed, determine rd/wr
0516    */
0517   if (addr > 0x7f) {
0518     addr_byte = (0xf0
0519          | ((addr >> 7) & 0x06)
0520          | ((rw) ? 1 : 0));
0521     /*
0522      * send first byte
0523      */
0524     softc_ptr->reg_ptr->i2cdr = addr_byte;
0525     /*
0526      * wait for successful transfer
0527      */
0528     rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK);
0529     if (rc != RTEMS_SUCCESSFUL) {
0530 #if defined(DEBUG)
0531       printk("... exit rc=%d\r\n",rc);
0532 #endif
0533       return rc;
0534     }
0535   }
0536   /*
0537    * send (final) byte
0538    */
0539   addr_byte = ((addr << 1)
0540            | ((rw) ? 1 : 0));
0541 
0542   softc_ptr->reg_ptr->i2cdr = addr_byte;
0543   /*
0544    * wait for successful transfer
0545    */
0546   rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK);
0547 
0548 #if defined(DEBUG)
0549   printk("... exit rc=%d\r\n",rc);
0550 #endif
0551   return rc;
0552 }
0553 
0554 /*=========================================================================*\
0555 | Function:                                                                 |
0556 \*-------------------------------------------------------------------------*/
0557 static int mpc83xx_i2c_read_bytes
0558 (
0559 /*-------------------------------------------------------------------------*\
0560 | Purpose:                                                                  |
0561 |   receive some bytes from I2C device                                      |
0562 +---------------------------------------------------------------------------+
0563 | Input Parameters:                                                         |
0564 \*-------------------------------------------------------------------------*/
0565  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0566  unsigned char *buf,                     /* buffer to store bytes          */
0567  int len                                 /* number of bytes to receive     */
0568 )
0569 /*-------------------------------------------------------------------------*\
0570 | Return Value:                                                             |
0571 |    number of bytes received or (negative) error code                      |
0572 \*=========================================================================*/
0573 {
0574   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0575   rtems_status_code rc;
0576   unsigned char *p = buf;
0577 
0578 #if defined(DEBUG)
0579   printk("mpc83xx_i2c_read_bytes called... ");
0580 #endif
0581   softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MTX;
0582   softc_ptr->reg_ptr->i2ccr &= ~I2CCR_TXAK;
0583   /*
0584    * FIXME: do we need to deactivate TXAK from the start,
0585    * when only one byte is to be received?
0586    */
0587   /*
0588    * we need a dummy transfer here to start the first read
0589    */
0590   softc_ptr->reg_ptr->i2cdr;
0591 
0592   while (len-- > 0) {
0593     if (len == 0) {
0594       /*
0595        * last byte is not acknowledged
0596        */
0597       softc_ptr->reg_ptr->i2ccr |= I2CCR_TXAK;
0598     }
0599     /*
0600      * wait 'til end of transfer
0601      */
0602     rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF);
0603     if (rc != RTEMS_SUCCESSFUL) {
0604 #if defined(DEBUG)
0605       printk("... exit rc=%d\r\n",-rc);
0606 #endif
0607       return -rc;
0608     }
0609     *p++ = softc_ptr->reg_ptr->i2cdr;
0610 
0611   }
0612 
0613  /*
0614   * wait 'til end of last transfer
0615   */
0616   rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF);
0617 
0618 #if defined(DEBUG)
0619   printk("... exit OK, rc=%d\r\n",p-buf);
0620 #endif
0621   return p - buf;
0622 }
0623 
0624 /*=========================================================================*\
0625 | Function:                                                                 |
0626 \*-------------------------------------------------------------------------*/
0627 static int mpc83xx_i2c_write_bytes
0628 (
0629 /*-------------------------------------------------------------------------*\
0630 | Purpose:                                                                  |
0631 |   send some bytes to I2C device                                           |
0632 +---------------------------------------------------------------------------+
0633 | Input Parameters:                                                         |
0634 \*-------------------------------------------------------------------------*/
0635  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0636  unsigned char *buf,                     /* buffer to send                 */
0637  int len                                 /* number of bytes to send        */
0638 
0639 )
0640 /*-------------------------------------------------------------------------*\
0641 | Return Value:                                                             |
0642 |    number of bytes sent or (negative) error code                          |
0643 \*=========================================================================*/
0644 {
0645   mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc);
0646   rtems_status_code rc;
0647   unsigned char *p = buf;
0648 
0649 #if defined(DEBUG)
0650   printk("mpc83xx_i2c_write_bytes called... ");
0651 #endif
0652   softc_ptr->reg_ptr->i2ccr =
0653     (softc_ptr->reg_ptr->i2ccr & ~I2CCR_TXAK) | I2CCR_MTX;
0654   while (len-- > 0) {
0655     int rxack = len != 0 ? I2CSR_RXAK : 0;
0656 
0657     softc_ptr->reg_ptr->i2cdr = *p++;
0658     /*
0659      * wait 'til end of transfer
0660      */
0661     rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | rxack);
0662     if (rc != RTEMS_SUCCESSFUL) {
0663 #if defined(DEBUG)
0664       printk("... exit rc=%d\r\n",-rc);
0665 #endif
0666       return -rc;
0667     }
0668   }
0669 #if defined(DEBUG)
0670   printk("... exit OK, rc=%d\r\n",p-buf);
0671 #endif
0672   return p - buf;
0673 }
0674 
0675 rtems_libi2c_bus_ops_t mpc83xx_i2c_ops = {
0676   .init = mpc83xx_i2c_init,
0677   .send_start = mpc83xx_i2c_send_start,
0678   .send_stop = mpc83xx_i2c_send_stop,
0679   .send_addr = mpc83xx_i2c_send_addr,
0680   .read_bytes = mpc83xx_i2c_read_bytes,
0681   .write_bytes = mpc83xx_i2c_write_bytes,
0682 };
0683