diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2007-10-11 12:56:09 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2007-10-11 12:56:09 +0000 |
commit | 0743eaed1c83e9eb73986e15e9f7e8dc9c297a92 (patch) | |
tree | 4b991c8d5e96e9196d15fa52f05373b3bad45fa0 /c/src | |
parent | 2007-10-11 Daniel Hellstrom <daniel@gaisler.com> (diff) | |
download | rtems-0743eaed1c83e9eb73986e15e9f7e8dc9c297a92.tar.bz2 |
2007-10-11 Daniel Hellstrom <daniel@gaisler.com>
* Makefile.am, shared/can/occan.c, shared/include/ambapp.h: Add initial
i2c and update OC-CAN support.
* shared/i2c/i2cmst.c, shared/include/i2cmst.h: New files.
Diffstat (limited to 'c/src')
-rw-r--r-- | c/src/lib/libbsp/sparc/ChangeLog | 6 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/Makefile.am | 4 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/can/occan.c | 30 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c | 358 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/include/ambapp.h | 2 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/include/i2cmst.h | 77 |
6 files changed, 456 insertions, 21 deletions
diff --git a/c/src/lib/libbsp/sparc/ChangeLog b/c/src/lib/libbsp/sparc/ChangeLog index 569854d8c8..cb4e39f6b3 100644 --- a/c/src/lib/libbsp/sparc/ChangeLog +++ b/c/src/lib/libbsp/sparc/ChangeLog @@ -1,3 +1,9 @@ +2007-10-11 Daniel Hellstrom <daniel@gaisler.com> + + * Makefile.am, shared/can/occan.c, shared/include/ambapp.h: Add initial + i2c and update OC-CAN support. + * shared/i2c/i2cmst.c, shared/include/i2cmst.h: New files. + 2007-09-21 Daniel Hellstrom <daniel@gaisler.com> * shared/can/occan.c: Fix warning on Diab compiler. diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am index 3f2bfff9a4..8081d61609 100644 --- a/c/src/lib/libbsp/sparc/Makefile.am +++ b/c/src/lib/libbsp/sparc/Makefile.am @@ -59,5 +59,9 @@ EXTRA_DIST += shared/include/b1553brm.h EXTRA_DIST += shared/include/b1553brm_pci.h EXTRA_DIST += shared/include/b1553brm_rasta.h +# I2C-master (I2CMST) +EXTRA_DIST += shared/i2c/i2cmst.c +EXTRA_DIST += shared/include/i2cmst.h + include $(top_srcdir)/../../../automake/subdirs.am include $(top_srcdir)/../../../automake/local.am diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c index f3318165a8..66e27f2a4b 100644 --- a/c/src/lib/libbsp/sparc/shared/can/occan.c +++ b/c/src/lib/libbsp/sparc/shared/can/occan.c @@ -198,8 +198,8 @@ typedef struct { } pelican_regs; #endif -#define MAX_TSEG1 7 -#define MAX_TSEG2 15 +#define MAX_TSEG2 7 +#define MAX_TSEG1 15 #if 0 typedef struct { @@ -728,16 +728,13 @@ static void occan_stat_print(occan_stats *stats){ } #endif -/* This function calculates BTR0 BTR1 values for a given bitrate. - * Heavily based on mgt_mscan_bitrate() from peak driver, which - * in turn is based on work by Arnaud Westenberg. +/* This function calculates BTR0 and BTR1 values for a given bitrate. * * Set communication parameters. - * baud rate in Hz - * input clock frequency of can core in Hz (system frequency) - * sjw synchronization jump width (0-3) prescaled clock cycles - * sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) - * ratio + * \param clock_hz OC_CAN Core frequency in Hz. + * \param rate Requested baud rate in bits/second. + * \param result Pointer to where resulting BTRs will be stored. + * \return zero if successful to calculate a baud rate. */ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result){ int best_error = 1000000000; @@ -748,7 +745,7 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_ int clock = clock_hz / 2; int sampl_pt = 90; - if ( (rate<10000) || (rate>1000000) ){ + if ( (rate<5000) || (rate>1000000) ){ /* invalid speed mode */ return -1; } @@ -816,12 +813,7 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_ tseg1 = MAX_TSEG1; tseg2 = best_tseg - tseg1 - 2; } -/* - result->sjw = sjw; - result->brp = best_brp; - result->tseg1 = tseg1; - result->tseg2 = tseg2; -*/ + result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP); result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1; @@ -834,10 +826,6 @@ static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing){ priv->regs->bustim0 = timing->btr0; priv->regs->bustim1 = timing->btr1; - /* - priv->regs->bustim0 = (timing->sjw<<OCCAN_BUSTIM_SJW_BIT) | (timing->brp&OCCAN_BUSTIM_BRP); - priv->regs->bustim1 = (timing->sam<<7) | (timing->tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | timing->tseg1; - */ return 0; } diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c new file mode 100644 index 0000000000..2a59d32879 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c @@ -0,0 +1,358 @@ +/* + * Driver for GRLIB port of OpenCores I2C-master + * + * COPYRIGHT (c) 2007 Gaisler Research + * based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/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 <ambapp.h> +#include <rtems/libi2c.h> + +/* Enable debug printks? */ +/* #define DEBUG */ + +/* Default to 40 MHz system clock? */ +/* + #ifndef SYS_FREQ_kHZ + #define SYS_FREQ_kHZ 40000 + #endif +*/ + + +/* Calculates the scaler value for 100 kHz operation */ +static int gr_i2cmst_calc_scaler(int sysfreq) +{ + return sysfreq/500 - 1; +} + +/* Wait for the current transfer to end */ +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 + + do { + if (tout++ > 1000000) { + return RTEMS_TIMEOUT; + } + } while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP); + + current_sts = prv_ptr->reg_ptr->cmdsts & ~GRI2C_STS_IF & ~GRI2C_STS_BUSY; + + if (current_sts != expected_sts) { +#if defined(DEBUG) + if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) { + printk("Transfer NAKed.."); + } + if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) { + printk("arbitration lost.."); + } + if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) { + printk("transfer still in progress, huh?.."); + } + printk("exited with IO error..)"); +#endif + return RTEMS_IO_ERROR; + } + +#if defined(DEBUG) + printk("exited...)"); +#endif + 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 + + /* Disable core before changing prescale register */ + prv_ptr->reg_ptr->ctrl = 0; + + /* Calculate and set prescale value */ + prv_ptr->reg_ptr->prescl = gr_i2cmst_calc_scaler(prv_ptr->sysfreq); + + /* Enable core, interrupts are not enabled */ + prv_ptr->reg_ptr->ctrl = GRI2C_CTRL_EN; + + /* Clear possible START condition */ + prv_ptr->sendstart = 0; + +#if defined(DEBUG) + printk("exited\n"); +#endif + 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 + + /* 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 + 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 + + prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO; + +#if defined(DEBUG) + printk("exited\n"); +#endif + 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); + uint8_t addr_byte; + rtems_status_code rc; +#if defined(DEBUG) + printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...", + addr, rw); +#endif + + /* Check if long address is needed */ + if (addr > 0x7f) { + addr_byte = ((addr >> 7) & 0x06) | (rw ? 1 : 0); + + prv_ptr->reg_ptr->tdrd = addr_byte; + prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart; + prv_ptr->sendstart = 0; + + /* 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 + return -rc; + } + } + + /* For 10-bit adresses the last byte should only be written for a + write operation */ + rc = RTEMS_SUCCESSFUL; + if (addr <= 0x7f || rw == 0) { + addr_byte = (addr << 1) | (rw ? 1 : 0); + + prv_ptr->reg_ptr->tdrd = addr_byte; + prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart; + prv_ptr->sendstart = 0; + + /* 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 + return -rc; + } + } + +#if defined(DEBUG) + printk("exited\n"); +#endif + return rc; +} + + +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); + 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 + + while (nbytes-- > 0) { + if (nbytes == 0) { + /* Respond with NAK to end sequential read */ + prv_ptr->reg_ptr->cmdsts = (GRI2C_CMD_RD | GRI2C_CMD_ACK | + prv_ptr->sendstart); + expected_sts = GRI2C_STS_RXACK; + } else { + prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_RD | prv_ptr->sendstart; + } + prv_ptr->sendstart = 0; + /* Wait until end of transfer */ + rc = gr_i2cmst_wait(prv_ptr, expected_sts); + if (rc != RTEMS_SUCCESSFUL) { + return -rc; +#if defined(DEBUG) + printk("exited with error\n"); +#endif + } + *buf++ = prv_ptr->reg_ptr->tdrd; + } + +#if defined(DEBUG) + printk("exited\n"); +#endif + 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); + unsigned char *buf = bytes; + rtems_status_code rc; +#if defined(DEBUG) + printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes); +#endif + + while (nbytes-- > 0) { +#if defined(DEBUG) + printk("writing byte 0x%02X...", *buf); +#endif + prv_ptr->reg_ptr->tdrd = *buf++; + prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart; + prv_ptr->sendstart = 0; + + /* 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 + return -rc; + } + } + +#if defined(DEBUG) + printk("exited\n"); +#endif + return buf - bytes; +} + +static rtems_libi2c_bus_ops_t gr_i2cmst_ops = { + init: gr_i2cmst_init, + send_start: gr_i2cmst_send_start, + send_stop: gr_i2cmst_send_stop, + send_addr: gr_i2cmst_send_addr, + read_bytes: gr_i2cmst_read_bytes, + write_bytes: gr_i2cmst_write_bytes, +}; + + +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, + } + +}; + +/* Scans for I2CMST core and initalizes i2c library */ +rtems_status_code leon_register_i2c(amba_confarea_type *abus) +{ +#if defined(DEBUG) + printk("leon_register_i2c called..."); +#endif + + int rc; + int device_found = 0; + amba_apb_device apbi2cmst; + + /* Scan AMBA bus for I2CMST core */ + device_found = amba_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST, + &apbi2cmst); + + if (device_found == 1) { + + /* Initialize i2c library */ + rc = rtems_libi2c_initialize(); + if (rc < 0) { +#if defined(DEBUG) + printk("rtems_libi2x_initialize failed, exiting...\n"); +#endif + return rc; + } + + gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start; + + /* Detect system frequency, same as in apbuart_initialize */ +#ifndef SYS_FREQ_kHZ +#if defined(LEON3) + /* LEON3: find timer address via AMBA Plug&Play info */ + { + amba_apb_device gptimer; + LEON3_Timer_Regs_Map *tregs; + + if (amba_find_apbslv(abus,VENDOR_GAISLER, + GAISLER_GPTIMER,&gptimer) == 1 ) { + tregs = (LEON3_Timer_Regs_Map *)gptimer.start; + gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000; + } else { + gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */ + } + } +#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; + } +#else +#error CPU not supported for I2CMST driver */ +#endif +#else + /* Use hardcoded frequency */ + gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ; +#endif + + 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 defined(DEBUG) + printk("exited\n"); +#endif + return 0; +} diff --git a/c/src/lib/libbsp/sparc/shared/include/ambapp.h b/c/src/lib/libbsp/sparc/shared/include/ambapp.h index e63648d13c..bb2066c4da 100644 --- a/c/src/lib/libbsp/sparc/shared/include/ambapp.h +++ b/c/src/lib/libbsp/sparc/shared/include/ambapp.h @@ -58,6 +58,8 @@ extern "C" { #define GAISLER_ETHMAC 0x1D #define GAISLER_SPACEWIRE 0x1f #define GAISLER_AHB2AHB 0x20 +#define GAISLER_I2CMST 0x28 +#define GAISLER_GRSPW2 0x29 #define GAISLER_GRHCAN 0x34 #define GAISLER_GRFIFO 0x35 #define GAISLER_GRPULSE 0x37 diff --git a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h new file mode 100644 index 0000000000..63942a45e6 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h @@ -0,0 +1,77 @@ +/* + * Driver for GRLIB port of OpenCores I2C-master + * + * COPYRIGHT (c) 2007 Gaisler Research + * with parts from the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * This file contains the driver declarations + */ +#ifndef _I2CMST_H +#define _I2CMST_H + +#include <rtems/libi2c.h> +#include <ambapp.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* I2C-master operational registers */ + +typedef struct gr_i2cmst_regs { + volatile unsigned int prescl; /* Prescale register */ + volatile unsigned int ctrl; /* Control register */ + volatile unsigned int tdrd; /* Transmit and Receive registers */ + volatile unsigned int cmdsts; /* Command and Status registers */ +} gr_i2cmst_regs_t; + +/* Control (CTRL) register */ +#define GRI2C_CTRL_EN 0x00000080 /* Enable core */ +#define GRI2C_CTRL_IEN 0x00000040 /* Interrupt enable */ + +/* Command (CMD) register */ +#define GRI2C_CMD_STA 0x00000080 /* Generate START condition */ +#define GRI2C_CMD_STO 0x00000040 /* Generate STOP condition */ +#define GRI2C_CMD_RD 0x00000020 /* Read from slave */ +#define GRI2C_CMD_WR 0x00000010 /* Write to slave */ +#define GRI2C_CMD_ACK 0x00000008 /* Acknowledge */ +#define GRI2C_CMD_IACK 0x00000001 /* Interrupt acknowledge */ + +/* Status (STS) register */ +#define GRI2C_STS_RXACK 0x00000080 /* Receive acknowledge */ +#define GRI2C_STS_BUSY 0x00000040 /* I2C-bus busy */ +#define GRI2C_STS_AL 0x00000020 /* Arbitration lost */ +#define GRI2C_STS_TIP 0x00000002 /* Transfer in progress */ +#define GRI2C_STS_IF 0x00000001 /* Interrupt flag */ + +#define GRI2C_STATUS_IDLE 0x00000000 + +/* 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 { + gr_i2cmst_regs_t *reg_ptr; + unsigned int sysfreq; /* System clock frequency in kHz */ + unsigned char sendstart; /* START events are buffered here */ + /* rtems_irq_number irq_number; */ + /* rtems_id irq_sema_id; */ +} gr_i2cmst_prv_t; + +typedef struct gr_i2cmst_desc { + rtems_libi2c_bus_t bus_desc; + gr_i2cmst_prv_t prv; +} gr_i2cmst_desc_t; + +/* Scans for I2CMST core and initalizes i2c library */ +rtems_status_code leon_register_i2c(amba_confarea_type *abus); + +#ifdef __cplusplus +} +#endif + +#endif /* _I2CMST_H */ |