summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/i2c
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2011-12-20 16:27:54 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3681925508c0da88fee6325ea35ead7b112856c6 (patch)
tree0886351bec0218ed4689c68e5442b75341cbc169 /c/src/lib/libbsp/sparc/shared/i2c
parentLEON: updated and added PCI peripherals for LEON BSPs (diff)
downloadrtems-3681925508c0da88fee6325ea35ead7b112856c6.tar.bz2
LEON: updated shared drivers to Driver Manger framework
Some bugfixes at the same time. After this patch the drivers may be used on RASTA systems having a big-endian PCI layout. Removed not up to date changelogs, rely on git log instead.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/i2c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c355
1 files changed, 205 insertions, 150 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
index 02710e1b84..f71af0be61 100644
--- a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
+++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
@@ -1,7 +1,7 @@
/*
* Driver for GRLIB port of OpenCores I2C-master
*
- * COPYRIGHT (c) 2007 Gaisler Research
+ * COPYRIGHT (c) 2007 Cobham Gaisler AB
* based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH.
*
* The license and distribution terms for this file may be
@@ -9,27 +9,41 @@
* http://www.rtems.org/license/LICENSE.
*
* This file contains the driver and initialization code
- *
- * 2007-09-27: First version of driver (jan@gaisler.com)
*/
-
#include <bsp.h>
-#include <i2cmst.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <ambapp.h>
-#include <grlib.h>
#include <rtems/libi2c.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <i2cmst.h>
/* Enable debug printks? */
-/* #define DEBUG */
+/*#define DEBUG*/
-/* Default to 40 MHz system clock? */
-/*
- #ifndef SYS_FREQ_kHZ
- #define SYS_FREQ_kHZ 40000
- #endif
-*/
+#ifdef DEBUG
+ #define DBG(args...) printk(args)
+#else
+ #define DBG(args...)
+#endif
+/* The OC I2C core will perform a write after a start unless the RD bit
+ in the command register has been set. Since the rtems framework has
+ a send_start function we buffer that command and use it when the first
+ data is written. The START is buffered in the sendstart member below */
+typedef struct gr_i2cmst_prv {
+ rtems_libi2c_bus_t i2clib_desc;
+ struct drvmgr_dev *dev;
+ gr_i2cmst_regs_t *reg_ptr;
+ unsigned int sysfreq; /* System clock frequency in kHz */
+ int minor;
+ unsigned char sendstart; /* START events are buffered here */
+ /* rtems_irq_number irq_number; */
+ /* rtems_id irq_sema_id; */
+} gr_i2cmst_prv_t;
/* Calculates the scaler value for 100 kHz operation */
static int gr_i2cmst_calc_scaler(int sysfreq)
@@ -42,12 +56,12 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
{
uint32_t tout = 0;
int current_sts;
-#if defined(DEBUG)
- printk("(gr_i2cmst_wait called...");
-#endif
+
+ DBG("(gr_i2cmst_wait called...");
do {
if (tout++ > 1000000) {
+ DBG("gr_i2cmst_wait: TIMEOUT\n");
return RTEMS_TIMEOUT;
}
} while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP);
@@ -57,32 +71,31 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
if (current_sts != expected_sts) {
#if defined(DEBUG)
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) {
- printk("Transfer NAKed..");
+ DBG("Transfer NAKed..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) {
- printk("arbitration lost..");
+ DBG("arbitration lost..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) {
- printk("transfer still in progress, huh?..");
+ DBG("transfer still in progress, huh?..");
}
- printk("exited with IO error..)");
+ DBG("exited with IO error..)");
#endif
+ DBG("gr_i2cmst_wait: IO-ERROR\n");
return RTEMS_IO_ERROR;
}
-#if defined(DEBUG)
- printk("exited...)");
-#endif
+ DBG("exited...)");
+
return RTEMS_SUCCESSFUL;
}
/* Initialize hardware core */
static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_init called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_init called...");
/* Disable core before changing prescale register */
prv_ptr->reg_ptr->ctrl = 0;
@@ -96,54 +109,48 @@ static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
/* Clear possible START condition */
prv_ptr->sendstart = 0;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_start called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_start called...");
/* The OC I2C core does not work with stand alone START events,
instead the event is buffered */
prv_ptr->sendstart = GRI2C_CMD_STA;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_stop called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_stop called...");
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
uint32_t addr, int rw)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
uint8_t addr_byte;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
+
+ DBG("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
addr, rw);
-#endif
/* Check if long address is needed */
if (addr > 0x7f) {
@@ -156,9 +163,9 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+
+ DBG("exited with error\n");
+
return -rc;
}
}
@@ -176,16 +183,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
- }
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
return rc;
}
@@ -193,13 +196,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
unsigned char expected_sts = GRI2C_STATUS_IDLE;
-#if defined(DEBUG)
- printk("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
if (nbytes == 0) {
@@ -214,34 +216,30 @@ static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
/* Wait until end of transfer */
rc = gr_i2cmst_wait(prv_ptr, expected_sts);
if (rc != RTEMS_SUCCESSFUL) {
+ DBG("exited with error\n");
return -rc;
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
}
*buf++ = prv_ptr->reg_ptr->tdrd;
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
-#if defined(DEBUG)
- printk("writing byte 0x%02X...", *buf);
-#endif
+
+ DBG("writing byte 0x%02X...", *buf);
+
prv_ptr->reg_ptr->tdrd = *buf++;
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
prv_ptr->sendstart = 0;
@@ -250,16 +248,13 @@ static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
@@ -272,88 +267,148 @@ static rtems_libi2c_bus_ops_t gr_i2cmst_ops = {
write_bytes: gr_i2cmst_write_bytes,
};
+/* Get Hardware and disable it */
+int i2cmst_device_init(gr_i2cmst_prv_t *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
-static gr_i2cmst_desc_t gr_i2cmst_desc = {
- { /* rtems_libi2c_bus_t */
- ops : &gr_i2cmst_ops,
- size : sizeof(gr_i2cmst_ops),
- },
- { /* gr_i2cmst_prv_t, private data */
- reg_ptr : NULL,
- sysfreq : 40000,
- }
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->reg_ptr = (gr_i2cmst_regs_t *)pnpinfo->apb_slv->start;
+
+ /* Disable core */
+ priv->reg_ptr->ctrl = 0;
+
+ priv->i2clib_desc.ops = &gr_i2cmst_ops;
+ priv->i2clib_desc.size = sizeof(gr_i2cmst_ops);
+ return 0;
+}
+
+
+/******************* Driver Manager Part ***********************/
+
+int i2cmst_init2(struct drvmgr_dev *dev);
+int i2cmst_init3(struct drvmgr_dev *dev);
+struct drvmgr_drv_ops i2cmst_ops =
+{
+ .init = {NULL, i2cmst_init2, i2cmst_init3, NULL},
+ .remove = NULL,
+ .info = NULL
};
-/* Scans for I2CMST core and initalizes i2c library */
-rtems_status_code leon_register_i2c(struct ambapp_bus *abus)
+struct amba_dev_id i2cmst_ids[] =
{
-#if defined(DEBUG)
- printk("leon_register_i2c called...");
-#endif
+ {VENDOR_GAISLER, GAISLER_I2CMST},
+ {0, 0} /* Mark end of table */
+};
- int rc;
- int device_found = 0;
- struct ambapp_apb_info apbi2cmst;
+struct amba_drv_info i2cmst_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_I2CMST_ID, /* Driver ID */
+ "I2CMST_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &i2cmst_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &i2cmst_ids[0]
+};
- /* Scan AMBA bus for I2CMST core */
- device_found = ambapp_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST,
- &apbi2cmst);
+void i2cmst_register_drv (void)
+{
+ DBG("Registering I2CMST driver\n");
+ drvmgr_drv_register(&i2cmst_drv_info.general);
+}
- if (device_found == 1) {
+/* The I2CMST Driver is informed about a new hardware device */
+int i2cmst_init2(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
- /* Initialize i2c library */
- rc = rtems_libi2c_initialize();
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2x_initialize failed, exiting...\n");
-#endif
- return rc;
- }
+ DBG("I2CMST[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
- gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start;
+ priv = dev->priv = malloc(sizeof(gr_i2cmst_prv_t));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
- /* Detect system frequency, same as in apbuart_initialize */
-#ifndef SYS_FREQ_kHZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- struct ambapp_apb_info gptimer;
- struct gptimer_regs *tregs;
-
- if (ambapp_find_apbslv(abus, VENDOR_GAISLER,
- GAISLER_GPTIMER, &gptimer) == 1 ) {
- tregs = (struct gptimer_regs *)gptimer.start;
- gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000;
- } else {
- gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */
- }
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+/* Init stage 2 */
+int i2cmst_init3(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
+ char prefix[32];
+ char devName[32];
+ int rc;
+
+ priv = (gr_i2cmst_prv_t *)dev->priv;
+
+ /* Do initialization */
+
+ /* Initialize i2c library */
+ rc = rtems_libi2c_initialize();
+ if (rc != 0) {
+ DBG("I2CMST: rtems_libi2c_initialize failed, exiting...\n");
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- gr_i2cmst_desc.prv.sysfreq = (regs->Scaler_Reload+1)*1000;
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->sysfreq) ) {
+ return DRVMGR_FAIL;
}
-#else
-#error CPU not supported for I2CMST driver */
-#endif
-#else
- /* Use hardcoded frequency */
- gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ;
-#endif
+ priv->sysfreq = priv->sysfreq / 1000; /* Convert to kHz */
- rc = rtems_libi2c_register_bus("/dev/i2c1", &gr_i2cmst_desc.bus_desc);
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2c_register_bus failed, exiting..\n");
-#endif
- return -rc;
- }
- }
+ if ( i2cmst_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
- return 0;
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(devName, "/dev/i2c%d", dev->minor_drv+1);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(devName, "/dev/%si2c%d", prefix, dev->minor_bus+1);
+ }
+
+ /* Register Bus for this Device */
+ rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
+ if (rc < 0) {
+ DBG("I2CMST: rtems_libi2c_register_bus(%s) failed, exiting..\n", devName);
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+ priv->minor = rc;
+
+ return DRVMGR_OK;
}