changeset 2560:cec45c19fdcc

* src/i2c_lpc2xxx.c: Implemented support for multiple I2C busses Call DSR only if there is something to signal. Removed declaration of I2C bus via CYG_I2C_BUS() macro - this belongs in the platform HAL. * include/i2c_lpc2xxx.h: New file with macro definition of macro CYG_LPC2XXX_I2C_BUS() for I2C bus declaration by platform HAL * cdl/i2c_lpc2xxx.cdl: Added CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES configuration option to support multiple I2C busses
author asl
date Mon, 22 Sep 2008 19:19:06 +0000
parents 19e4b89dda34
children 55c015cde894
files packages/devs/i2c/arm/lpc2xxx/current/ChangeLog packages/devs/i2c/arm/lpc2xxx/current/cdl/i2c_lpc2xxx.cdl packages/devs/i2c/arm/lpc2xxx/current/include/i2c_lpc2xxx.h packages/devs/i2c/arm/lpc2xxx/current/src/i2c_lpc2xxx.c
diffstat 4 files changed, 609 insertions(+), 342 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/i2c/arm/lpc2xxx/current/ChangeLog
+++ b/packages/devs/i2c/arm/lpc2xxx/current/ChangeLog
@@ -1,3 +1,16 @@
+2008-09-16  Uwe Kindler  <uwe_kindler@web.de>
+
+	* src/i2c_lpc2xxx.c: Implemented support for multiple I2C busses
+	  Call DSR only if there is something to signal. Removed
+	  declaration of I2C bus via CYG_I2C_BUS() macro - this belongs in
+	  the platform HAL.
+	
+	* include/i2c_lpc2xxx.h: New file with macro definition of macro
+	  CYG_LPC2XXX_I2C_BUS() for I2C bus declaration by platform HAL
+	  
+	* cdl/i2c_lpc2xxx.cdl: Added CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
+	  configuration option to support multiple I2C busses
+	
 2007-07-12  Hans Rosenfeld  <rosenfeld@grumpf.hope-2000.org>
 
 	* lpc2xxx: driver for on-chip I2C unit
--- a/packages/devs/i2c/arm/lpc2xxx/current/cdl/i2c_lpc2xxx.cdl
+++ b/packages/devs/i2c/arm/lpc2xxx/current/cdl/i2c_lpc2xxx.cdl
@@ -2,13 +2,13 @@
 #
 #      i2c_lpc2xxx.cdl
 #
-#      I2C driver for LPC2xxx
+#      eCos LPC2xxx I2C configuration data
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
-## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2008 Free Software Foundation, Inc.
 ##
 ## eCos is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free
@@ -38,7 +38,7 @@
 ######DESCRIPTIONBEGIN####
 #
 # Author(s):      Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-# Contributors:   
+# Contributors:   Uwe Kindler <uwe_kindler@web.de>
 # Date:           2007-07-12
 #
 #####DESCRIPTIONEND####
@@ -50,10 +50,45 @@ cdl_package CYGPKG_DEVS_I2C_ARM_LPC2XXX 
     
     parent      CYGPKG_IO_I2C
     active_if   CYGPKG_IO_I2C
-    active_if   CYGPKG_HAL_ARM_LPC2XXX
+    active_if   CYGPKG_HAL_ARM_LPC2XXX || CYGPKG_HAL_ARM_LPC24XX 
 
-    description "This package provides a driver for the I2C module found in
-                 Philips LPC2xxx controllers."
-
+    description " 
+           This package provides a generic I2C device driver for the on-chip
+           I2C peripherals in LPX2xxx processors."
+           
+    include_dir cyg/io
     compile     i2c_lpc2xxx.c
-}
\ No newline at end of file
+    
+    cdl_option CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES {
+	display		"Target hardware may have multiple I2C buses"
+	flavor		bool
+	default_value	0
+	description "
+          The LPC2xxx I2C driver can support multiple I2C bus devices. By
+          default the driver assumes only a single device is present and will
+          optimize for that case, using constant definitions provided by the
+          platform HAL rather than per-device structure fields. If the hardware
+          has multiple I2C bus devices, or if a singleton bus is instantiated
+          by some other package and hence the platform HAL cannot provide the
+          necessary definitions, then this option should be enabled."
+    }
+    
+    cdl_option CYGPKG_DEVS_I2C_ARM_LPC2XXX_DEBUG_LEVEL {
+         display "Driver debug output level"
+         flavor  data
+         legal_values {0 1}
+         default_value 0
+         description   "
+             This option specifies the level of debug data output by
+             the LPC2XXX I2C device driver. A value of 0 signifies
+             no debug data output; 1 signifies normal debug data
+             output. The generic eCos I2C driver functions do not return any 
+             error information if a I2C transfer failed. If this option is
+             1 then the driver prints the status flags if a transfer failed
+             or was aborted. It prints the status flags in case of a missing 
+             data or address acknowledge, in case of lost arbitration and in 
+             case of a bus error. A missing acknowledge does not realy indicate
+             an error and may be part of a normal I2C communication. Therefore
+             this option should only be >0 for debug reasons."         
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/i2c/arm/lpc2xxx/current/include/i2c_lpc2xxx.h
@@ -0,0 +1,141 @@
+#ifndef CYGONCE_I2C_LPC2XXX_H
+#define CYGONCE_I2C_LPC2XXX_H
+//==========================================================================
+//
+//      devs/i2c/arm/lpc2xxx/current/src/i2c_lpc2xxx.h
+//
+//      I2C driver for NXP LPC2xxx ARM processors
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
+// Contributors:  Uwe Kindler <uwe_kindler@web.de>
+// Date:          2008-09-11
+// Description:   I2C driver for LPC2xxx
+//####DESCRIPTIONEND####
+//==========================================================================
+
+
+//==========================================================================
+//                               INCLUDES
+//==========================================================================
+#include <pkgconf/devs_i2c_arm_lpc2xxx.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/drv_api.h>
+
+
+//==========================================================================
+// Single I2C bus sepecififc data
+//==========================================================================
+typedef struct cyg_lpc2xxx_i2c_extra {
+#ifdef CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES    
+    // Put statically initialized fields first.
+    cyg_uint32       i2c_base;    // Per-bus h/w details
+    cyg_vector_t     i2c_isrvec;
+    int              i2c_isrpri;
+    cyg_uint32       i2c_pclk;    // peripheral clock of 
+    cyg_uint32       i2c_bus_freq;// I2C bus frequency (e.g. 100 kHz, 400 kHz)
+#endif // CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES    
+    
+    cyg_uint8        i2c_addr;
+    cyg_uint32       i2c_count;
+    const cyg_uint8* i2c_txbuf;
+    cyg_uint8*       i2c_rxbuf;
+    cyg_bool         i2c_rxnak;
+
+    cyg_uint32       i2c_flag;
+    cyg_uint32       i2c_delay;
+
+    cyg_drv_mutex_t  i2c_lock; // For synchronizing between DSR and foreground
+    cyg_drv_cond_t   i2c_wait;
+    cyg_handle_t     i2c_interrupt_handle;// For initializing the interrupt
+    cyg_interrupt    i2c_interrupt_data;
+} cyg_lpc2xxx_i2c_extra;
+
+
+//==========================================================================
+// I2C driver interface
+//==========================================================================
+externC void        cyg_lpc2xxx_i2c_init(struct cyg_i2c_bus*);
+externC cyg_uint32  cyg_lpc2xxx_i2c_tx(const cyg_i2c_device*, 
+                                       cyg_bool, const cyg_uint8*, 
+                                       cyg_uint32, cyg_bool);
+externC cyg_uint32  cyg_lpc2xxx_i2c_rx(const cyg_i2c_device*, 
+                                       cyg_bool, cyg_uint8*, 
+                                       cyg_uint32, cyg_bool, cyg_bool);
+externC void        cyg_lpc2xxx_i2c_stop(const cyg_i2c_device*);
+
+//==========================================================================
+// I2C bus declaration macros
+//=========================================================================
+#ifdef CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
+# define CYG_LPC2XXX_I2C_BUS(_name_, _init_fn_, _base_, _isr_vec_, _isr_pri_, \
+                             _pclk_, _i2c_bus_freq_)                    \
+  static cyg_lpc2xxx_i2c_extra _name_ ## _extra = {                     \
+  i2c_base     : _base_,                                                \
+  i2c_isrvec   : _isr_vec_,                                             \
+  i2c_isrpri   : _isr_pri_,                                             \
+  i2c_pclk     : _pclk_,                                                \
+  i2c_bus_freq : _i2c_bus_freq_,                                        \
+  i2c_count    :  0,                                                    \
+  i2c_txbuf    :  NULL,                                                 \
+  i2c_rxbuf    :  NULL,                                                 \
+  i2c_flag     :  0                                                     \
+  } ;                                                                   \
+  CYG_I2C_BUS(_name_,                                                   \
+              _init_fn_,                                                \
+              &cyg_lpc2xxx_i2c_tx,                                      \
+              &cyg_lpc2xxx_i2c_rx,                                      \
+              &cyg_lpc2xxx_i2c_stop,                                    \
+              (void*) & ( _name_ ## _extra)) ;
+
+#else // !CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
+# define CYG_LPC2XXX_I2C_BUS(_name_, _init_fn_, _base_, _isr_vec_, _isr_pri_, \
+                             _pclk_, _i2c_bus_freq_)                    \
+  static cyg_lpc2xxx_i2c_extra _name_ ## _extra = {                     \
+  i2c_count    :  0,                                                    \
+  i2c_txbuf    :  NULL,                                                 \
+  i2c_rxbuf    :  NULL,                                                 \
+  i2c_flag     :  0                                                     \
+  } ;                                                                   \
+  CYG_I2C_BUS(_name_,                                                   \
+              _init_fn_,                                                \
+              cyg_lpc2xxx_i2c_tx,                                       \
+              cyg_lpc2xxx_i2c_rx,                                       \
+              cyg_lpc2xxx_i2c_stop,                                     \
+              (void*) & ( _name_ ## _extra)) ;
+#endif // CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
+
+//-----------------------------------------------------------------------------
+#endif // #endif CYGONCE_I2C_LPC2XXX_H
--- a/packages/devs/i2c/arm/lpc2xxx/current/src/i2c_lpc2xxx.c
+++ b/packages/devs/i2c/arm/lpc2xxx/current/src/i2c_lpc2xxx.c
@@ -8,7 +8,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2008 Free Software Foundation, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -41,7 +41,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-// Contributors: 
+// Contributors: Uwe Kindler <uwe_kindler@web.de>
 // Date:         2007-07-12
 // Purpose:      
 // Description:  
@@ -50,365 +50,443 @@
 //
 //==========================================================================
 
+
+//==========================================================================
+//                                 INCLUDES
+//==========================================================================
 #include <pkgconf/system.h>
 #include <pkgconf/devs_i2c_arm_lpc2xxx.h>
 
 #include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
 #include <cyg/infra/diag.h>
 #include <cyg/io/i2c.h>
+#include <cyg/io/i2c_lpc2xxx.h>
 #include <cyg/hal/hal_arch.h>
 #include <cyg/hal/hal_io.h>
 #include <cyg/hal/hal_intr.h>
 #include <cyg/hal/drv_api.h>
 
-/* 
- * According to the Users Manual the LPC2xxx I2C module is very
- * similar to the I2C module of the Philips 8xC552/556 controllers. I
- * guess it is used in other Philips/NXP controllers, too. Using these
- * macros should make it easier to split off the common parts of the
- * driver once it's necessary.
- */
-
-#define I2C_XFER        8
-#define I2C_INTR        CYGNUM_HAL_INTERRUPT_I2C
-#define I2C_FREQ        (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / \
-                         CYGNUM_HAL_ARM_LPC2XXX_VPBDIV)
-#define I2C_BASE        CYGARC_HAL_LPC2XXX_REG_I2_BASE
+//
+// According to the Users Manual the LPC2xxx I2C module is very
+// similar to the I2C module of the Philips 8xC552/556 controllers. I
+// guess it is used in other Philips/NXP controllers, too. Using these
+// macros should make it easier to split off the common parts of the
+// driver once it's necessary.
+//
+// Optimize for the case of a single bus device, while still allowing
+// multiple devices.
+//
+#ifndef CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
+# define    I2C_BASE(_extra_)       (cyg_uint8*)HAL_LPC2XXX_I2C_SINGLETON_BASE
+# define    I2C_ISRVEC(_extra_)     HAL_LPC2XXX_I2C_SINGLETON_ISRVEC
+# define    I2C_ISRPRI(_extra_)     HAL_LPC2XXX_I2C_SINGLETON_ISRPRI
+# define    I2C_CLK(_extra_)        HAL_LPC2XXX_I2C_SINGLETON_CLK
+# define    I2C_BUS_FREQ(_extra_)   HAL_LPC2XXX_I2C_SINGLETON_BUS_FREQ
+#else
+# define    I2C_BASE(_extra_)       ((_extra_)->i2c_base)
+# define    I2C_ISRVEC(_extra_)     ((_extra_)->i2c_isrvec)
+# define    I2C_ISRPRI(_extra_)     ((_extra_)->i2c_isrpri)
+# define    I2C_CLK(_extra_)        ((_extra_)->i2c_pclk)
+# define    I2C_BUS_FREQ(_extra_)   ((_extra_)->i2c_bus_freq)
+#endif // CYGHWR_DEVS_I2C_ARM_LPC2XXX_MULTIPLE_BUSES
 
-#define I2C_CONSET      CYGARC_HAL_LPC2XXX_REG_I2CONSET
-#define I2C_CONCLR      CYGARC_HAL_LPC2XXX_REG_I2CONCLR
-#define I2C_CON         I2C_CONSET
-#define I2C_STAT        CYGARC_HAL_LPC2XXX_REG_I2STAT
-#define I2C_DAT         CYGARC_HAL_LPC2XXX_REG_I2DAT
-#define I2C_ADR         CYGARC_HAL_LPC2XXX_REG_I2ADR
-#define I2C_SCLH        CYGARC_HAL_LPC2XXX_REG_I2SCLH
-#define I2C_SCLL        CYGARC_HAL_LPC2XXX_REG_I2SCLL
+#define I2C_XFER             8
 
-#define I2C_R8(r, x)    HAL_READ_UINT8  (I2C_BASE + (r), (x))
-#define I2C_W8(r, x)    HAL_WRITE_UINT8 (I2C_BASE + (r), (x))
-#define I2C_R16(r, x)   HAL_READ_UINT16 (I2C_BASE + (r), (x))
-#define I2C_W16(r, x)   HAL_WRITE_UINT16(I2C_BASE + (r), (x))
+#define I2C_CONSET(_extra_)  (I2C_BASE(_extra_) + 0x0000)
+#define I2C_CON(_extra_)      I2C_CONSET(_extra_)
+#define I2C_STAT(_extra_)    (I2C_BASE(_extra_) + 0x0004)
+#define I2C_DAT(_extra_)     (I2C_BASE(_extra_) + 0x0008)
+#define I2C_ADR(_extra_)     (I2C_BASE(_extra_) + 0x000C)
+#define I2C_SCLH(_extra_)    (I2C_BASE(_extra_) + 0x0010)
+#define I2C_SCLL(_extra_)    (I2C_BASE(_extra_) + 0x0014)
+#define I2C_CONCLR(_extra_)  (I2C_BASE(_extra_) + 0x0018)
 
-/* Special case for setting/clearing bits in I2C_CON */
-#define SET_CON(x)      I2C_W8(I2C_CONSET, (x))
-#define CLR_CON(x)      I2C_W8(I2C_CONCLR, (x))
+#define I2C_R8(r, x)          HAL_READ_UINT8  ((r), (x))
+#define I2C_W8(r, x)          HAL_WRITE_UINT8 ((r), (x))
+#define I2C_R16(r, x)         HAL_READ_UINT16 ((r), (x))
+#define I2C_W16(r, x)         HAL_WRITE_UINT16((r), (x))
 
-#define CON_EN          CYGARC_HAL_LPC2XXX_REG_I2CONSET_I2EN
-#define CON_STA         CYGARC_HAL_LPC2XXX_REG_I2CONSET_STA
-#define CON_STO         CYGARC_HAL_LPC2XXX_REG_I2CONSET_STO
-#define CON_SI          CYGARC_HAL_LPC2XXX_REG_I2CONSET_SI
-#define CON_AA          CYGARC_HAL_LPC2XXX_REG_I2CONSET_AA
+// Special case for setting/clearing bits in I2C_CON
+#define SET_CON(_extra_, x)   I2C_W8(I2C_CONSET(_extra_), (x))
+#define CLR_CON(_extra_, x)   I2C_W8(I2C_CONCLR(_extra_), (x))
 
-static cyg_uint8        i2c_addr;
-static cyg_uint32       i2c_count = 0;
-static const cyg_uint8* i2c_txbuf = NULL;
-static cyg_uint8*       i2c_rxbuf = NULL;
-static cyg_bool         i2c_rxnak;
+// I2C_CONSET register bits
+#define CON_AA   (1<<2)
+#define CON_SI   (1<<3)
+#define CON_STO  (1<<4)
+#define CON_STA  (1<<5)
+#define CON_EN   (1<<6)
 
-volatile
-static cyg_uint32       i2c_flag = 0;
-static cyg_uint32       i2c_delay;
 
-static cyg_drv_mutex_t  i2c_lock;
-static cyg_drv_cond_t   i2c_wait;
-static cyg_handle_t     i2c_hand;
-static cyg_interrupt    i2c_data;
+#define I2C_FLAG_FINISH  1       // transfer finished                       
+#define I2C_FLAG_ACT     2       // bus still active, no STOP condition send
+#define I2C_FLAG_ERROR  (1<<31)  // one of the following errors occured:    
+#define I2C_FLAG_ADDR   (1<<30)  // - address was not ACKed                 
+#define I2C_FLAG_DATA   (1<<29)  // - data was not ACKed                    
+#define I2C_FLAG_LOST   (1<<28)  // - bus arbitration was lost              
+#define I2C_FLAG_BUF    (1<<27)  // - no buffer for reading or writing      
+#define I2C_FLAG_UNK    (1<<26)  // - unknown I2C status                   
+#define I2C_FLAG_BUS    (1<<25)  // - bus error
 
-#define I2C_FLAG_FINISH 1       /* transfer finished                        */
-#define I2C_FLAG_ACT    2       /* bus still active, no STOP condition sent */
-#define I2C_FLAG_ERROR  (1<<31) /* one of the following errors occured:     */
-#define I2C_FLAG_ADDR   (1<<30) /* - address was not ACKed                  */
-#define I2C_FLAG_DATA   (1<<29) /* - data was not ACKed                     */
-#define I2C_FLAG_LOST   (1<<28) /* - bus arbitration was lost               */
-#define I2C_FLAG_BUF    (1<<27) /* - no buffer for reading or writing       */
-#define I2C_FLAG_UNK    (1<<26) /* - unknown I2C status                     */
+#if CYGPKG_DEVS_I2C_ARM_LPC2XXX_DEBUG_LEVEL > 0
+   #define debug1_printf(args...) diag_printf(args)
+#else
+   #define debug1_printf(args...)
+#endif
+#if CYGPKG_DEVS_I2C_ARM_LPC2XXX_DEBUG_LEVEL > 1
+   #define debug2_printf(args...) diag_printf(args)
+#else
+   #define debug2_printf(args...)
+#endif
 
-/*
- * set up I2C bus timing
- * I2C clock period is in PCLK ticks
- */
-static void
-i2c_lpc2xxx_delay(cyg_uint32 delay)
+//==========================================================================
+// The ISR does the actual work. It is not that much work to justify
+// putting it in the DSR, and it is also not clear whether this would
+// even work.  If an error occurs we try to leave the bus in the same
+// state as we would if there was no error.
+//==========================================================================
+static cyg_uint32 lpc2xxx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
 {
-  cyg_uint32 period;
-  
-  if(delay == i2c_delay)
-    return;
-  
-  period = I2C_FREQ / (1000000000 / delay);
-  period /= 2;
-  
-  I2C_W16(I2C_SCLL, period);
-  I2C_W16(I2C_SCLH, period);
-  i2c_delay = delay;
-}
-
-/*
- * The ISR does the actual work. It is not that much work to justify
- * putting it in the DSR, and it is also not clear whether this would
- * even work.  If an error occurs we try to leave the bus in the same
- * state as we would if there was no error.
- */
-static cyg_uint32
-i2c_lpc2xxx_isr(cyg_vector_t vec, cyg_addrword_t data)
-{
-  cyg_uint8 status;
-  I2C_R8(I2C_STAT, status);
-  
-  switch(status) {
-    case 0x08: /* START sent, send Addr+R/W   */
-    case 0x10: /* ReSTART sent, send Addr+R/W */
-      CLR_CON(CON_STA);
-      I2C_W8(I2C_DAT, i2c_addr);
-      break;
-      
-    case 0x18: /* Addr ACKed, send data       */
-    case 0x28: /* Data ACKed, send more       */
-      if(i2c_count == 0) {
-        i2c_flag = I2C_FLAG_FINISH;
-        cyg_drv_interrupt_mask_intunsafe(vec);
-        cyg_drv_interrupt_acknowledge(vec);
-        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      }
-      
-      if(i2c_txbuf == NULL) {
-        i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
-        cyg_drv_interrupt_mask_intunsafe(vec);
-        cyg_drv_interrupt_acknowledge(vec);
-        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      }
-      
-      I2C_W8(I2C_DAT, *i2c_txbuf);
-      i2c_txbuf++;
-      i2c_count--;
-      break;
-      
-    case 0x50: /* Data ACKed, receive more    */
-    case 0x58: /* Data not ACKed, end reception */
-      if(i2c_rxbuf == NULL) {
-        i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
-        cyg_drv_interrupt_mask_intunsafe(vec);
-        cyg_drv_interrupt_acknowledge(vec);
-        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      }
-      
-      I2C_R8(I2C_DAT, *i2c_rxbuf);
-      i2c_rxbuf++;
-      i2c_count--;
-    case 0x40: /* Addr ACKed, receive data    */
-      if(status == 0x58 || i2c_count == 0) {
-        i2c_flag = I2C_FLAG_FINISH;
-        cyg_drv_interrupt_mask_intunsafe(vec);
-        cyg_drv_interrupt_acknowledge(vec);
-        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      }
-      
-      if(i2c_count == 1 && i2c_rxnak)
-        CLR_CON(CON_AA);
-      else    
-        SET_CON(CON_AA);
-      break;
+    cyg_lpc2xxx_i2c_extra* extra = (cyg_lpc2xxx_i2c_extra*)data;
+    cyg_uint8  status;
+    
+    I2C_R8(I2C_STAT(extra), status);
+    switch(status) 
+    {
+    case 0x00: // bus error, stop transfer
+         SET_CON(extra, CON_STO);
+         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUS;
+         break;
+         
+    case 0x08: // START sent, send Addr+R/W
+    case 0x10: // ReSTART sent, send Addr+R/W
+         CLR_CON(extra, CON_STA);
+         I2C_W8(I2C_DAT(extra), extra->i2c_addr);
+         break;
       
-    case 0x20: /* Addr not ACKed */
-    case 0x48:
-      i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_ADDR;
-      cyg_drv_interrupt_mask_intunsafe(vec);
-      cyg_drv_interrupt_acknowledge(vec);
-      return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      break;
-    case 0x30: /* Data not ACKed */
-      i2c_count++;
-      i2c_txbuf--;
-      i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_DATA;
-      cyg_drv_interrupt_mask_intunsafe(vec);
-      cyg_drv_interrupt_acknowledge(vec);
-      return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-      break;
-    case 0x38: /* Arbitration lost */
-      i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_LOST;
-      break;
-    default: /* lots of unused states... */
-      i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_UNK;
-      break;
-  }
-  
-  CLR_CON(CON_SI);
-  cyg_drv_interrupt_acknowledge(vec);
-  return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
-}
-
-static void
-i2c_lpc2xxx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
-{
-  if(i2c_flag)
-    cyg_drv_cond_signal(&i2c_wait);
-}
-
-/*
- * Initialize driver & hardware state
- */
-static void
-i2c_lpc2xxx_init(struct cyg_i2c_bus *bus)
-{
-  cyg_uint32 addr, tmp;
-  
-  /* enable I2C pins */
-  addr = CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0;
-  HAL_READ_UINT32(addr, tmp);
-  tmp |= 0x50;
-  HAL_WRITE_UINT32(addr, tmp);
-  
-  cyg_drv_mutex_init(&i2c_lock);
-  cyg_drv_cond_init(&i2c_wait, &i2c_lock);
-  cyg_drv_interrupt_create(I2C_INTR, 0, (cyg_addrword_t) 0, &i2c_lpc2xxx_isr,
-                           &i2c_lpc2xxx_dsr, &i2c_hand, &i2c_data);
-  cyg_drv_interrupt_attach(i2c_hand);
-  
-  CLR_CON(CON_EN | CON_STA | CON_SI | CON_AA);
-  I2C_W8(I2C_ADR, 0);
-  SET_CON(CON_EN);
-}
-
-/*
- * transmit a buffer to a device
- */
-static cyg_uint32
-i2c_lpc2xxx_tx(const cyg_i2c_device *dev, 
-               cyg_bool send_start, 
-               const cyg_uint8 *tx_data, 
-               cyg_uint32 count, 
-               cyg_bool send_stop)
-{
-  i2c_lpc2xxx_delay(dev->i2c_delay);
-  
-  i2c_addr  = dev->i2c_address << 1;
-  i2c_count = count;
-  i2c_txbuf = tx_data;
-  
-  /*
-   * for a repeated start the SI bit has to be reset
-   * if we continue a previous transfer, load the next byte
-   */
-  if(send_start && i2c_flag == I2C_FLAG_ACT) {
-    SET_CON(CON_STA);
-    CLR_CON(CON_SI);
-  } else if(send_start) {
-    SET_CON(CON_STA);
-  } else {
-    I2C_W8(I2C_DAT, *i2c_txbuf);
-    i2c_txbuf++;
-    i2c_count--;
-    CLR_CON(CON_SI);
-  }
+    case 0x18: // Addr ACKed, send data
+         if(extra->i2c_txbuf == NULL) 
+         {
+             extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
+             cyg_drv_interrupt_mask_intunsafe(vec);
+             cyg_drv_interrupt_acknowledge(vec);
+             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+         }
+         I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf);
+         extra->i2c_txbuf++;
+         break;
+         
+    case 0x28: // Data ACKed, send more
+         extra->i2c_count--;     
+         if(extra->i2c_count == 0) 
+         {
+             extra->i2c_flag = I2C_FLAG_FINISH;
+             cyg_drv_interrupt_mask_intunsafe(vec);
+             cyg_drv_interrupt_acknowledge(vec);
+             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+         }
+         I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf);
+         extra->i2c_txbuf++;
+         break;
+      
+    case 0x50: // Data ACKed, receive more
+    case 0x58: // Data not ACKed, end reception
+         if(extra->i2c_rxbuf == NULL) 
+         {
+             extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
+             cyg_drv_interrupt_mask_intunsafe(vec);
+             cyg_drv_interrupt_acknowledge(vec);
+             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+         }
+      
+         I2C_R8(I2C_DAT(extra), *extra->i2c_rxbuf);
+         extra->i2c_rxbuf++;
+         extra->i2c_count--;
+         // fall through
+         
+    case 0x40: // Addr ACKed, receive data
+         if(status == 0x58 || extra->i2c_count == 0) 
+         {
+             extra->i2c_flag = I2C_FLAG_FINISH;
+             cyg_drv_interrupt_mask_intunsafe(vec);
+             cyg_drv_interrupt_acknowledge(vec);
+             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+         }
+      
+         if((extra->i2c_count == 1) && extra->i2c_rxnak)
+         {
+             CLR_CON(extra, CON_AA);
+         }
+         else 
+         {   
+             SET_CON(extra, CON_AA);
+         }
+         break;
+      
+    case 0x20: // Addr not ACKed
+    case 0x48: // Addr not ACKed
+         SET_CON(extra, CON_STO); // tranfer failed - force stop
+         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_ADDR;
+         cyg_drv_interrupt_mask_intunsafe(vec);
+         cyg_drv_interrupt_acknowledge(vec);
+         break;
+         
+    case 0x30: // Data not ACKed
+         SET_CON(extra, CON_STO); // tranfer failed - force stop
+         extra->i2c_count++;
+         extra->i2c_txbuf--;
+         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_DATA;
+         cyg_drv_interrupt_mask_intunsafe(vec);
+         cyg_drv_interrupt_acknowledge(vec);
+         return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+         break;
+         
+    case 0x38: // Arbitration lost
+         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_LOST;
+         break;
+         
+    default: // lots of unused states
+         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_UNK;
+         break;
+    } // switch(status)
   
-  i2c_flag  = 0;
-  
-  /*
-   * the isr will do most of the work, and the dsr will signal when an
-   * error occured or the transfer finished
-   */
-  cyg_drv_mutex_lock(&i2c_lock);
-  cyg_drv_dsr_lock();
-  cyg_drv_interrupt_unmask(I2C_INTR);
-  while(!(i2c_flag & (I2C_FLAG_FINISH|I2C_FLAG_ERROR)))
-    cyg_drv_cond_wait(&i2c_wait);
-  cyg_drv_interrupt_mask(I2C_INTR);
-  cyg_drv_dsr_unlock();
-  cyg_drv_mutex_unlock(&i2c_lock);
-  
-  /* too bad we have no way to tell the caller */
-  if(i2c_flag & I2C_FLAG_ERROR)
-    diag_printf("I2C TX error flag: %x\n", i2c_flag);
-  
-  if(send_stop) {
-    SET_CON(CON_STO);
-    CLR_CON(CON_SI | CON_STA);
-  } else  i2c_flag = I2C_FLAG_ACT;
-  
-  count -= i2c_count;
-  
-  i2c_addr  = 0;
-  i2c_count = 0;
-  i2c_txbuf = NULL;
-  
-  return count;
-}
-
-/*
- * receive into a buffer from a device
- */
-static cyg_uint32
-i2c_lpc2xxx_rx(const cyg_i2c_device *dev,
-               cyg_bool send_start,
-               cyg_uint8 *rx_data,
-               cyg_uint32 count,
-               cyg_bool send_nak,
-               cyg_bool send_stop)
-{
-  i2c_lpc2xxx_delay(dev->i2c_delay);
-  
-  i2c_addr  = dev->i2c_address << 1 | 1;
-  i2c_count = count;
-  i2c_rxbuf = rx_data;
-  i2c_rxnak = send_nak;
-  
-  /*
-   * for a repeated start the SI bit has to be reset
-   * if we continue a previous transfer, start reception
-   */
-  if(send_start && i2c_flag == I2C_FLAG_ACT) {
-    SET_CON(CON_STA);
-    CLR_CON(CON_SI);
-  } else if(send_start)
-    SET_CON(CON_STA);
-  
-  i2c_flag  = 0;
-  
-  /*
-   * the isr will do most of the work, and the dsr will signal when an
-   * error occured or the transfer finished
-   */
-  cyg_drv_mutex_lock(&i2c_lock);
-  cyg_drv_dsr_lock();
-  cyg_drv_interrupt_unmask(I2C_INTR);
-  while(!(i2c_flag & (I2C_FLAG_FINISH|I2C_FLAG_ERROR)))
-    cyg_drv_cond_wait(&i2c_wait);
-  cyg_drv_interrupt_mask(I2C_INTR);
-  cyg_drv_dsr_unlock();
-  cyg_drv_mutex_unlock(&i2c_lock);
-  
-  /* too bad we have no way to tell the caller */
-  if(i2c_flag & I2C_FLAG_ERROR)
-    diag_printf("I2C RX error flag: %x\n", i2c_flag);
-  
-  if(send_stop) {
-    SET_CON(CON_STO);
-    CLR_CON(CON_SI | CON_STA);
-  } else  i2c_flag = I2C_FLAG_ACT;
-  
-  count -= i2c_count;
-  
-  i2c_addr  = 0;
-  i2c_count = 0;
-  i2c_rxbuf = NULL;
-  
-  return count;
-  
+    CLR_CON(extra, CON_SI);
+    cyg_drv_interrupt_acknowledge(vec);
+    
+    //
+    // We need to call the DSR only if there is really something to signal,
+    // that means only if extra->i2c_flag != 0
+    //
+    if (extra->i2c_flag)
+    {
+        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+    }
+    else
+    {
+        return CYG_ISR_HANDLED; 
+    }
 }
 
 
-/*
- * generate a STOP
- */
+//==========================================================================
+// DSR signals data
+//==========================================================================
 static void
-i2c_lpc2xxx_stop(const cyg_i2c_device *dev)
+lpc2xxx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+    cyg_lpc2xxx_i2c_extra* extra = (cyg_lpc2xxx_i2c_extra*)data;
+    if(extra->i2c_flag)
+    {
+        cyg_drv_cond_signal(&extra->i2c_wait);
+    }
+}
+
+
+//==========================================================================
+// Initialize driver & hardware state
+//==========================================================================
+void cyg_lpc2xxx_i2c_init(struct cyg_i2c_bus *bus)
 {
-  SET_CON(CON_STO);
+    cyg_lpc2xxx_i2c_extra* extra = (cyg_lpc2xxx_i2c_extra*)bus->i2c_extra;
+    cyg_uint16             duty_cycle;
+  
+    cyg_drv_mutex_init(&extra->i2c_lock);
+    cyg_drv_cond_init(&extra->i2c_wait, &extra->i2c_lock);
+    cyg_drv_interrupt_create(I2C_ISRVEC(extra),
+                             I2C_ISRPRI(extra),
+                             (cyg_addrword_t) extra,
+                             &lpc2xxx_i2c_isr,
+                             &lpc2xxx_i2c_dsr,
+                             &(extra->i2c_interrupt_handle),
+                             &(extra->i2c_interrupt_data));
+    cyg_drv_interrupt_attach(extra->i2c_interrupt_handle);
+  
+   
+    CLR_CON(extra, CON_EN | CON_STA | CON_SI | CON_AA);
+    HAL_WRITE_UINT8(I2C_ADR(extra), 0);
+    
+    //
+    // Setup I2C bus frequency
+    //
+    duty_cycle = (I2C_CLK(extra) / I2C_BUS_FREQ(extra)) / 2;
+    HAL_WRITE_UINT16(I2C_SCLL(extra), duty_cycle);
+    HAL_WRITE_UINT16(I2C_SCLH(extra), duty_cycle);
+    
+    SET_CON(extra, CON_EN);
 }
 
-CYG_I2C_BUS(cyg_i2c_lpc2xxx_bus,
-            &i2c_lpc2xxx_init,
-            &i2c_lpc2xxx_tx,
-            &i2c_lpc2xxx_rx,
-            &i2c_lpc2xxx_stop,
-            (void *) 0);
+
+//==========================================================================
+// transmit a buffer to a device
+//==========================================================================
+cyg_uint32 cyg_lpc2xxx_i2c_tx(const cyg_i2c_device *dev, 
+                              cyg_bool              send_start, 
+                              const cyg_uint8      *tx_data, 
+                              cyg_uint32            count, 
+                              cyg_bool              send_stop)
+{
+    cyg_lpc2xxx_i2c_extra* extra = 
+                           (cyg_lpc2xxx_i2c_extra*)dev->i2c_bus->i2c_extra;
+    extra->i2c_addr  = dev->i2c_address << 1;
+    extra->i2c_count = count;
+    extra->i2c_txbuf = tx_data;
+  
+    //
+    // for a repeated start the SI bit has to be reset
+    // if we continue a previous transfer, load the next byte
+    //
+    if(send_start) 
+    {
+        SET_CON(extra, CON_STA);
+        if (I2C_FLAG_ACT == extra->i2c_flag)
+        {
+            CLR_CON(extra, CON_SI);
+        }
+    } 
+    else 
+    {
+        HAL_WRITE_UINT8(I2C_DAT(extra), *(extra->i2c_txbuf));
+        extra->i2c_txbuf++;
+        CLR_CON(extra, CON_SI);
+    }
+  
+    extra->i2c_flag  = 0;
+  
+    //
+    // the isr will do most of the work, and the dsr will signal when an
+    // error occured or the transfer finished
+    //
+    cyg_drv_mutex_lock(&extra->i2c_lock);
+    cyg_drv_dsr_lock();
+    cyg_drv_interrupt_unmask(I2C_ISRVEC(extra));
+    while(!(extra->i2c_flag & (I2C_FLAG_FINISH | I2C_FLAG_ERROR)))
+    {
+        cyg_drv_cond_wait(&extra->i2c_wait);
+    }
+    cyg_drv_interrupt_mask(I2C_ISRVEC(extra));
+    cyg_drv_dsr_unlock();
+    cyg_drv_mutex_unlock(&extra->i2c_lock);
+  
+    // too bad we have no way to tell the caller
+    if(extra->i2c_flag & I2C_FLAG_ERROR)
+    {
+        debug1_printf("I2C TX error flag: %x\n", extra->i2c_flag);
+        extra->i2c_flag = 0;
+    }
+    else
+    {
+        if(send_stop) 
+        {
+            SET_CON(extra, CON_STO);
+            CLR_CON(extra, CON_SI | CON_STA);
+            extra->i2c_flag = 0;
+        } 
+        else  
+        {
+            extra->i2c_flag = I2C_FLAG_ACT;
+        }
+    }
+   
+    count -= extra->i2c_count;
+  
+    extra->i2c_addr  = 0;
+    extra->i2c_count = 0;
+    extra->i2c_txbuf = NULL;
+  
+    return count;
+}
+
+ 
+//==========================================================================
+// receive into a buffer from a device
+//==========================================================================
+cyg_uint32 cyg_lpc2xxx_i2c_rx(const cyg_i2c_device *dev,
+                              cyg_bool              send_start,
+                              cyg_uint8            *rx_data,
+                              cyg_uint32            count,
+                              cyg_bool              send_nak,
+                              cyg_bool              send_stop)
+{
+    cyg_lpc2xxx_i2c_extra* extra = 
+                           (cyg_lpc2xxx_i2c_extra*)dev->i2c_bus->i2c_extra;
+    extra->i2c_addr  = (dev->i2c_address << 1) | 0x01;
+    extra->i2c_count = count;
+    extra->i2c_rxbuf = rx_data;
+    extra->i2c_rxnak = send_nak;
+  
+    //
+    // for a repeated start the SI bit has to be reset
+    // if we continue a previous transfer, start reception
+    //
+    if(send_start) 
+    {
+        SET_CON(extra, CON_STA);
+        if (I2C_FLAG_ACT == extra->i2c_flag)
+        {
+            CLR_CON(extra, CON_SI);
+        }
+    } 
+  
+    extra->i2c_flag  = 0;
+  
+    //
+    // the isr will do most of the work, and the dsr will signal when an
+    // error occurred or the transfer finished
+    //
+    cyg_drv_mutex_lock(&extra->i2c_lock);
+    cyg_drv_dsr_lock();
+    cyg_drv_interrupt_unmask(I2C_ISRVEC(extra));
+    while(!(extra->i2c_flag & (I2C_FLAG_FINISH | I2C_FLAG_ERROR)))
+    {
+        cyg_drv_cond_wait(&extra->i2c_wait);
+    }
+    cyg_drv_interrupt_mask(I2C_ISRVEC(extra));
+    cyg_drv_dsr_unlock();
+    cyg_drv_mutex_unlock(&extra->i2c_lock);
+  
+    // too bad we have no way to tell the caller 
+    if (extra->i2c_flag & I2C_FLAG_ERROR)
+    {
+        diag_printf("I2C RX error flag: %x\n", extra->i2c_flag);
+        extra->i2c_flag = 0;
+    }
+    else
+    {
+        if(send_stop) 
+        {
+            SET_CON(extra, CON_STO);
+            CLR_CON(extra, CON_SI | CON_STA);
+            extra->i2c_flag = 0;
+        } 
+        else  
+        {
+            extra->i2c_flag = I2C_FLAG_ACT;
+        }
+    }
+    
+    count -= extra->i2c_count;
+  
+    extra->i2c_addr  = 0;
+    extra->i2c_count = 0;
+    extra->i2c_rxbuf = NULL;
+  
+    return count; 
+}
+
+
+//==========================================================================
+//  generate a STOP
+//==========================================================================
+void cyg_lpc2xxx_i2c_stop(const cyg_i2c_device *dev)
+{
+    cyg_lpc2xxx_i2c_extra* extra = 
+                           (cyg_lpc2xxx_i2c_extra*)dev->i2c_bus->i2c_extra;
+    extra = extra; // avoid compiler warning in case of singleton
+    SET_CON(extra, CON_STO);
+    extra->i2c_flag  = 0;
+    extra->i2c_count = 0;
+}
+
+//---------------------------------------------------------------------------
+// eof i2c_lpc2xxx.c