Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Driver for GRLIB port of OpenCores I2C-master
0005  *
0006  * COPYRIGHT (c) 2007 Cobham Gaisler AB
0007  * based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  *
0030  * This file contains the driver and initialization code
0031  */
0032 
0033 #include <bsp.h>
0034 #include <stdlib.h>
0035 #include <stdio.h>
0036 #include <string.h>
0037 #include <grlib/ambapp.h>
0038 #include <rtems/libi2c.h>
0039 #include <drvmgr/drvmgr.h>
0040 #include <grlib/ambapp_bus.h>
0041 
0042 #include <grlib/i2cmst.h>
0043 
0044 #include <grlib/grlib_impl.h>
0045 
0046 /* Enable debug printks? */
0047 /*#define DEBUG*/
0048 
0049 #ifdef DEBUG
0050  #define DBG(args...) printk(args)
0051 #else
0052  #define DBG(args...)
0053 #endif
0054 
0055 /* The OC I2C core will perform a write after a start unless the RD bit
0056    in the command register has been set. Since the rtems framework has
0057    a send_start function we buffer that command and use it when the first
0058    data is written. The START is buffered in the sendstart member below */
0059 typedef struct gr_i2cmst_prv {
0060   rtems_libi2c_bus_t              i2clib_desc;
0061   struct drvmgr_dev    *dev;
0062   gr_i2cmst_regs_t                *reg_ptr;
0063   unsigned int                    sysfreq;     /* System clock frequency in kHz */
0064   int                             minor;
0065   unsigned char                   sendstart;   /* START events are buffered here */ 
0066   /* rtems_irq_number             irq_number; */
0067   /* rtems_id                     irq_sema_id; */
0068 } gr_i2cmst_prv_t;
0069 
0070 /* Calculates the scaler value for 100 kHz operation */
0071 static int gr_i2cmst_calc_scaler(int sysfreq)
0072 {
0073   return sysfreq/500 - 1;
0074 }
0075 
0076 /* Wait for the current transfer to end */
0077 static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
0078 {
0079   uint32_t tout = 0;
0080   int current_sts;
0081 
0082   DBG("(gr_i2cmst_wait called...");
0083 
0084   do {
0085     if (tout++ > 1000000) {
0086       DBG("gr_i2cmst_wait: TIMEOUT\n");
0087       return RTEMS_TIMEOUT;
0088     }
0089   } while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP);
0090 
0091   current_sts = prv_ptr->reg_ptr->cmdsts & ~GRI2C_STS_IF & ~GRI2C_STS_BUSY;
0092 
0093   if (current_sts != expected_sts) {
0094 #if defined(DEBUG)
0095     if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) {
0096       DBG("Transfer NAKed..");
0097     }
0098     if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) {
0099       DBG("arbitration lost..");
0100     }
0101     if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) {
0102       DBG("transfer still in progress, huh?..");
0103     }
0104     DBG("exited with IO error..)");
0105 #endif
0106     DBG("gr_i2cmst_wait: IO-ERROR\n");
0107     return RTEMS_IO_ERROR;
0108   }
0109 
0110   DBG("exited...)");
0111 
0112   return RTEMS_SUCCESSFUL;
0113 }
0114 
0115 /* Initialize hardware core */
0116 static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
0117 {
0118   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0119 
0120   DBG("gr_i2cmst_init called...");
0121 
0122   /* Disable core before changing prescale register */
0123   prv_ptr->reg_ptr->ctrl = 0;
0124 
0125   /* Calculate and set prescale value */
0126   prv_ptr->reg_ptr->prescl = gr_i2cmst_calc_scaler(prv_ptr->sysfreq);
0127 
0128   /* Enable core, interrupts are not enabled */
0129   prv_ptr->reg_ptr->ctrl = GRI2C_CTRL_EN;
0130 
0131   /* Clear possible START condition */
0132   prv_ptr->sendstart = 0;
0133 
0134   DBG("exited\n");
0135 
0136   return RTEMS_SUCCESSFUL;
0137 }
0138 
0139 static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl)
0140 {
0141   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0142 
0143   DBG("gr_i2cmst_send_start called...");
0144 
0145   /* The OC I2C core does not work with stand alone START events,
0146      instead the event is buffered */
0147   prv_ptr->sendstart = GRI2C_CMD_STA;
0148 
0149   DBG("exited\n");
0150 
0151   return RTEMS_SUCCESSFUL;
0152 }
0153 
0154 static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl)
0155 {
0156   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0157 
0158   DBG("gr_i2cmst_send_stop called...");
0159 
0160   prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO;
0161 
0162   DBG("exited\n");
0163 
0164   return RTEMS_SUCCESSFUL;
0165 }
0166 
0167 static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
0168                          uint32_t addr, int rw)
0169 {
0170   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0171   uint8_t addr_byte;
0172   rtems_status_code rc;
0173 
0174   DBG("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...", 
0175      addr, rw);
0176 
0177   /*  Check if long address is needed */
0178   if (addr > 0x7f) {
0179     addr_byte = ((addr >> 7) & 0x06) | (rw ? 1 : 0);
0180 
0181     prv_ptr->reg_ptr->tdrd = addr_byte;
0182     prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
0183     prv_ptr->sendstart = 0;
0184 
0185     /* Wait for transfer to complete */
0186     rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
0187     if (rc != RTEMS_SUCCESSFUL) {
0188 
0189       DBG("exited with error\n");
0190 
0191       return -rc;
0192     }
0193   }
0194 
0195   /* For 10-bit adresses the last byte should only be written for a
0196      write operation  */
0197   rc = RTEMS_SUCCESSFUL;
0198   if (addr <= 0x7f || rw == 0) {
0199     addr_byte = (addr << 1) | (rw ? 1 : 0);
0200 
0201     prv_ptr->reg_ptr->tdrd = addr_byte;
0202     prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
0203     prv_ptr->sendstart = 0;
0204 
0205     /* Wait for transfer to complete */
0206     rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
0207     if (rc != RTEMS_SUCCESSFUL) {
0208       DBG("exited with error\n");
0209       return -rc;
0210     }
0211   }
0212 
0213   DBG("exited\n");
0214   return rc;
0215 }
0216 
0217 
0218 static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
0219                 unsigned char *bytes, int nbytes)
0220 {
0221   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0222   unsigned char *buf = bytes;
0223   rtems_status_code rc;
0224   unsigned char expected_sts = GRI2C_STATUS_IDLE;
0225 
0226   DBG("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
0227 
0228   while (nbytes-- > 0) {
0229     if (nbytes == 0) {
0230       /* Respond with NAK to end sequential read */
0231       prv_ptr->reg_ptr->cmdsts = (GRI2C_CMD_RD | GRI2C_CMD_ACK |
0232                   prv_ptr->sendstart);
0233       expected_sts = GRI2C_STS_RXACK;
0234     } else {
0235       prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_RD | prv_ptr->sendstart;
0236     }
0237     prv_ptr->sendstart = 0;
0238     /* Wait until end of transfer */
0239     rc = gr_i2cmst_wait(prv_ptr, expected_sts);
0240     if (rc != RTEMS_SUCCESSFUL) {
0241       DBG("exited with error\n");
0242       return -rc;
0243     }
0244     *buf++ = prv_ptr->reg_ptr->tdrd;
0245   }
0246 
0247   DBG("exited\n");
0248 
0249   return buf - bytes;
0250 }
0251 
0252 static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
0253                 unsigned char *bytes, int nbytes)
0254 {
0255   gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
0256   unsigned char *buf = bytes;
0257   rtems_status_code rc;
0258 
0259   DBG("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
0260 
0261   while (nbytes-- > 0) {
0262 
0263     DBG("writing byte 0x%02X...", *buf);
0264 
0265     prv_ptr->reg_ptr->tdrd = *buf++;
0266     prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
0267     prv_ptr->sendstart = 0;
0268 
0269     /* Wait for transfer to complete  */
0270     rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
0271 
0272     if (rc != RTEMS_SUCCESSFUL) {
0273       DBG("exited with error\n");
0274       return -rc;
0275     }
0276   }
0277 
0278   DBG("exited\n");
0279 
0280   return buf - bytes;
0281 }
0282 
0283 static rtems_libi2c_bus_ops_t gr_i2cmst_ops = {
0284   init:        gr_i2cmst_init,
0285   send_start:  gr_i2cmst_send_start,
0286   send_stop:   gr_i2cmst_send_stop,
0287   send_addr:   gr_i2cmst_send_addr,
0288   read_bytes:  gr_i2cmst_read_bytes,
0289   write_bytes: gr_i2cmst_write_bytes,
0290 };
0291 
0292 /* Get Hardware and disable it */
0293 static int i2cmst_device_init(gr_i2cmst_prv_t *priv)
0294 {
0295     struct amba_dev_info *ambadev;
0296     struct ambapp_core *pnpinfo;
0297 
0298     /* Get device information from AMBA PnP information */
0299     ambadev = (struct amba_dev_info *)priv->dev->businfo;
0300     if ( ambadev == NULL ) {
0301         return -1;
0302     }
0303     pnpinfo = &ambadev->info;
0304     priv->reg_ptr = (gr_i2cmst_regs_t *)pnpinfo->apb_slv->start;
0305 
0306     /* Disable core */
0307     priv->reg_ptr->ctrl = 0;
0308 
0309     priv->i2clib_desc.ops = &gr_i2cmst_ops;
0310     priv->i2clib_desc.size = sizeof(gr_i2cmst_ops);
0311     return 0;
0312 }
0313 
0314 
0315 /******************* Driver Manager Part ***********************/
0316 
0317 int i2cmst_init2(struct drvmgr_dev *dev);
0318 int i2cmst_init3(struct drvmgr_dev *dev);
0319 
0320 struct drvmgr_drv_ops i2cmst_ops = 
0321 {
0322     .init = {NULL, i2cmst_init2, i2cmst_init3, NULL},
0323     .remove = NULL,
0324     .info = NULL
0325 };
0326 
0327 struct amba_dev_id i2cmst_ids[] = 
0328 {
0329     {VENDOR_GAISLER, GAISLER_I2CMST},
0330     {0, 0}      /* Mark end of table */
0331 };
0332 
0333 struct amba_drv_info i2cmst_drv_info =
0334 {
0335     {
0336         DRVMGR_OBJ_DRV,             /* Driver */
0337         NULL,                   /* Next driver */
0338         NULL,                   /* Device list */
0339         DRIVER_AMBAPP_GAISLER_I2CMST_ID,    /* Driver ID */
0340         "I2CMST_DRV",               /* Driver Name */
0341         DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
0342         &i2cmst_ops,
0343         NULL,                   /* Funcs */
0344         0,                  /* No devices yet */
0345         0,
0346     },
0347     &i2cmst_ids[0]
0348 };
0349 
0350 void i2cmst_register_drv (void)
0351 {
0352     DBG("Registering I2CMST driver\n");
0353     drvmgr_drv_register(&i2cmst_drv_info.general);
0354 }
0355 
0356 /* The I2CMST Driver is informed about a new hardware device */
0357 int i2cmst_init2(struct drvmgr_dev *dev)
0358 {
0359     gr_i2cmst_prv_t *priv;
0360 
0361     DBG("I2CMST[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0362 
0363     priv = dev->priv = grlib_calloc(1, sizeof(*priv));
0364     if ( !priv )
0365         return DRVMGR_NOMEM;
0366     priv->dev = dev;
0367 
0368     /* This core will not find other cores, so we wait for init2() */
0369 
0370     return DRVMGR_OK;
0371 }
0372 
0373 /* Init stage 2 */
0374 int i2cmst_init3(struct drvmgr_dev *dev)
0375 {
0376     gr_i2cmst_prv_t *priv;
0377     char prefix[32];
0378     char devName[50];
0379     int rc;
0380 
0381     priv = (gr_i2cmst_prv_t *)dev->priv;
0382 
0383     /* Do initialization */
0384 
0385     /* Initialize i2c library */
0386     rc = rtems_libi2c_initialize();
0387     if (rc != 0) {
0388         DBG("I2CMST: rtems_libi2c_initialize failed, exiting...\n");
0389         free(dev->priv);
0390         dev->priv = NULL;
0391         return DRVMGR_FAIL;
0392     }
0393 
0394     /* I/O system registered and initialized 
0395      * Now we take care of device initialization.
0396      */
0397 
0398     /* Get frequency */
0399     if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->sysfreq) ) {
0400         return DRVMGR_FAIL;
0401     }
0402     priv->sysfreq = priv->sysfreq / 1000; /* Convert to kHz */
0403 
0404     if ( i2cmst_device_init(priv) ) {
0405         free(dev->priv);
0406         dev->priv = NULL;
0407         return DRVMGR_FAIL;
0408     }
0409 
0410     /* Get Filesystem name prefix */
0411     prefix[0] = '\0';
0412     if ( drvmgr_get_dev_prefix(dev, prefix) ) {
0413         /* Failed to get prefix, make sure of a unique FS name
0414          * by using the driver minor.
0415          */
0416         sprintf(devName, "/dev/i2c%d", dev->minor_drv+1);
0417     } else {
0418         /* Got special prefix, this means we have a bus prefix
0419          * And we should use our "bus minor"
0420          */
0421         sprintf(devName, "/dev/%si2c%d", prefix, dev->minor_bus+1);
0422     }
0423 
0424     /* Register Bus for this Device */
0425     rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
0426     if (rc < 0) {
0427         DBG("I2CMST: rtems_libi2c_register_bus(%s) failed, exiting..\n", devName);
0428         free(dev->priv);
0429         dev->priv = NULL;
0430         return DRVMGR_FAIL;
0431     }
0432     priv->minor = rc;
0433 
0434     return DRVMGR_OK;
0435 }