This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

coldfire I2C driver


This patch adds an I2C device driver for M68K/MCF5282 coldfire
processors and compatibles. There was an original version by Uwe
Kindler a while back which was rejected for a number of reasons. I
ended up rewriting most of it, giving the version below.

Bart

Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/ChangeLog,v
retrieving revision 1.171
diff -u -r1.171 ChangeLog
--- ChangeLog	18 Jul 2006 16:35:23 -0000	1.171
+++ ChangeLog	6 Aug 2006 22:13:22 -0000
@@ -1,3 +1,7 @@
+2006-08-06  Bart Veer  <bartv@ecoscentric.com>
+
+	* ecos.db: add M68K/MCF52xx ColdFire I2C driver
+
 2006-07-18  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* ecos.db: Add AT-HTTPD package from Anthony Tonizzo.
Index: ecos.db
===================================================================
RCS file: /cvs/ecos/ecos/packages/ecos.db,v
retrieving revision 1.157
diff -u -r1.157 ecos.db
--- ecos.db	18 Jul 2006 16:35:23 -0000	1.157
+++ ecos.db	6 Aug 2006 21:30:26 -0000
@@ -2202,6 +2202,16 @@
             support for bit-banged I2C buses."
 }
 
+package CYGPKG_DEVS_I2C_MCF52xx {
+	alias		{ "MCF52xx I2C driver" devs_i2c_mcf52xx mcf52xx_i2c_driver }
+	hardware
+	directory	devs/i2c/m68k/mcf52xx
+	script		i2c_mcf52xx.cdl
+	description "
+            This packages provides an I2C driver for the on-chip
+	        device provided by the MCF52xx coldfire processor family."
+}
+
 package CYGPKG_KERNEL {
 	alias		{ "eCos kernel" kernel }
 	directory	kernel
Index: devs/i2c/m68k/mcf52xx/current/ChangeLog
===================================================================
RCS file: devs/i2c/m68k/mcf52xx/current/ChangeLog
diff -N devs/i2c/m68k/mcf52xx/current/ChangeLog
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/i2c/m68k/mcf52xx/current/ChangeLog	6 Aug 2006 21:30:41 -0000
@@ -0,0 +1,41 @@
+2006-02-28  Bart Veer  <bartv@ecoscentric.com>
+
+	* doc/mcf52xx_i2c.sgml, include/i2c_mcf52xx.h: new files
+
+	* src/i2c_mcf52xx.c, cdl/i2c_mcf52xx.cdl: various clean-ups
+
+2005-10-23  Uwe Kindler  <uwe_kindler@web.de>
+
+	* mcf52xx I2C driver package created
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2005, 2006 eCosCentric Ltd.
+//
+// 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####
+//===========================================================================
Index: devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl
===================================================================
RCS file: devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl
diff -N devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl	6 Aug 2006 21:30:41 -0000
@@ -0,0 +1,105 @@
+# ====================================================================
+#
+#      i2c_mcf52xx.cdl
+#
+#      eCos MCF52xx I2C configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2005, 2006 eCosCentric Limited
+##
+## 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.
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      Uwe Kindler
+# Contributors:   Bart Veer
+# Date:           2005-10-23
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+
+cdl_package CYGPKG_DEVS_I2C_MCF52xx {
+    display         "I2C driver for coldfire MCF52xx family"
+
+    parent          CYGPKG_IO_I2C
+    active_if       CYGPKG_IO_I2C
+    active_if       CYGPKG_HAL_M68K_MCF52xx
+
+    description   "
+           This package provides a generic I2C device driver for the on-chip
+           I2C modules in MCF52xx ColdFire processors."
+
+    include_dir     cyg/io
+    compile 	    i2c_mcf52xx.c
+
+    cdl_option CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES {
+	display		"Target hardware may have multiple MCF52xx I2C buses"
+	flavor		bool
+	default_value	0
+	description "
+            The MCF52xx I2C driver can support multiple I2C bus devices, but
+          typically the coldfire processor only provides a single device. 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_component CYGPKG_DEVS_I2C_MCF52xx_OPTIONS {
+        display 	"I2C driver build options"
+        flavor  	none
+	active_if	{ CYGINT_DEVS_I2C_MCF52xx_BUS_DEVICES > 0 }
+        description   "
+	    Package specific build options including control over
+	    compiler flags used only in building the MCF52xx I2C
+            bus driver."
+
+        cdl_option CYGPKG_DEVS_I2C_MCF52xx_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the MCF52xx I2C bus driver. These flags are
+                used in addition to the set of global flags."
+        }
+
+        cdl_option CYGPKG_DEVS_I2C_MCF52xx_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the MCF52xx I2C bus driver. These flags are
+                removed from the set of global flags if present."
+        }
+    }
+}
Index: devs/i2c/m68k/mcf52xx/current/doc/mcf52xx_i2c.sgml
===================================================================
RCS file: devs/i2c/m68k/mcf52xx/current/doc/mcf52xx_i2c.sgml
diff -N devs/i2c/m68k/mcf52xx/current/doc/mcf52xx_i2c.sgml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/i2c/m68k/mcf52xx/current/doc/mcf52xx_i2c.sgml	6 Aug 2006 21:30:42 -0000
@@ -0,0 +1,279 @@
+<!-- DOCTYPE refentry  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
+<!-- {{{ Banner                         -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     mcf52xx_i2c.sgml                                            -->
+<!--                                                                 -->
+<!--     Documentation for the mcf52xx I2C bus driver                -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2006 eCosCentric Limited                          -->
+<!-- This material may be distributed only subject to the terms      -->
+<!-- and conditions set forth in the Open Publication License, v1.0  -->
+<!-- or later (the latest version is presently available at          -->
+<!-- http://www.opencontent.org/openpub/)                            -->
+<!-- Distribution of the work or derivative of the work in any       -->
+<!-- standard (paper) book form is prohibited unless prior           -->
+<!-- permission obtained from the copyright holder                   -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- Author(s):   bartv                                              -->
+<!-- Contact(s):  bartv                                              -->
+<!-- Date:        2006/02/19                                         -->
+<!-- Version:     0.01                                               -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+<part id="devs-i2c-m68k-mcf52xx-part"><title>Motorola MCF52xx ColdFire I<superscript>2</superscript>C Bus Driver</title>
+
+<refentry id="devs-i2c-m68k-mcf52xx">
+  <refmeta>
+    <refentrytitle>Motorola MCF52xx Coldfire I<superscript>2</superscript>C Bus  Driver</refentrytitle>
+  </refmeta>
+  <refnamediv>
+    <refname><varname>CYGPKG_DEVS_I2C_MCF52xx</varname></refname>
+    <refpurpose>eCos Support for the Motorola Coldfire I<superscript>2</superscript>C Bus</refpurpose>
+  </refnamediv>
+
+  <refsect1 id="devs-i2c-m68k-mcf52xx-description"><title>Description</title>
+    <para>
+Several processors in the Motorola ColdFire family come with one or
+more on-chip I<superscript>2</superscript>C bus devices. This package
+provides an eCos I<superscript>2</superscript>C bus driver. It was
+originally developed on an MCF5280 but should work with any ColdFire
+processor that uses a compatible bus device. The driver implements the
+functionality defined by the generic I<superscript>2</superscript>C
+package <varname>CYGPKG_IO_I2C</varname>.
+    </para>
+    <caution><para>
+The hardware does not support DMA or fifos, so usually a transfer will
+involve an interrupt for every byte transferred. Since the
+I<superscript>2</superscript>C bus typically runs at 100KHz large
+transfers will consume much of the available cpu time.
+    </para></caution>
+    <para>
+This package does not provide any <structname>cyg_i2c_bus</structname>
+structures. The number of I<superscript>2</superscript>C buses varies
+between ColdFire processors. If multiple buses are available then
+exactly which one(s) are in use on a given hardware platform depends
+entirely on that platform. The desired I<superscript>2</superscript>C
+bus speed also depends on the platform, and there may be other issues
+such as how the processor pins should be set up. Hence it is left to
+other code, usually the platform HAL, to instantiate the bus
+structure(s). This driver package supplies the necessary functions and
+utility macros. Similarly this package does not provide any
+<structname>cyg_i2c_device</structname> structures. Which
+I<superscript>2</superscript>C devices are hooked up to which
+I<superscript>2</superscript>C bus is entirely a characteristic of the
+hardware platform, so again it is up to the platform HAL to
+instantiate the necessary structures.
+    </para>
+    <para>
+The driver will operate in interrupt-driven mode if interrupts are
+enabled when a transfer is initiated. Otherwise it will operate in
+polled mode. This allows the driver to be used in a variety of
+configurations including inside RedBoot.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-i2c-m68k-mcf52xx-config"><title>Configuration Options</title>
+    <para>
+The I<superscript>2</superscript>C bus driver package should be loaded
+automatically when selecting a target containing a suitable ColdFire
+processor, and it should never be necessary to load the package
+explicitly. If the application does not use any of the
+I<superscript>2</superscript>C functionality, directly or indirectly,
+then all the I<superscript>2</superscript>C code should be removed at
+link-time and the application does not suffer any overheads.
+    </para>
+    <para>
+By default the driver assumes a single I<superscript>2</superscript>C
+bus and optimizes for that case. For example options like the ISR
+vector and priority are handled by compile-time
+<literal>#define</literal>'s in the platform HAL's exported header
+files rather than by per-bus structure fields. This helps to reduce
+both code and data overheads. If the driver should support multiple
+I<superscript>2</superscript>C buses then
+<varname>CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES</varname> should be
+enabled. Typically this will be done by the platform HAL using a CDL
+<property>requires</property> property. If bus instantiation happens
+outside the platform HAL and hence the HAL's header files do not
+provide the appropriate definitions, then this configuration option
+should also be defined.
+    </para>
+    <para>
+The only other configuration options in this package provide control
+over the compiler flags used to build the driver code.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-i2c-m68k-mcf52xx-bus-devices"><title>Defining the Bus and Devices</title>
+    <para>
+For most hardware targets the platform HAL will instantiate the
+<structname>cyg_i2c_bus</structname> and
+<structname>cyg_i2c_device</structname> structures, and it will also
+initialize the hardware so that the
+I<superscript>2</superscript>C-related pins are connected
+appropriately. Some development boards have no
+I<superscript>2</superscript>C devices, but the
+I<superscript>2</superscript>C bus signals are accessible via an
+expansion connector and I<superscript>2</superscript>C devices can be
+put on a daughter board. In such cases it may be necessary for the
+application to instantiate both the bus and all the device structures.
+Alternatively the platform HAL may provide a configuration option to
+enable just the bus, with the devices still left to application code.
+    </para>
+    <para>
+To facilitate bus instantiation the header file <filename
+class="headerfile">cyg/io/i2c_mcf52xx.h</filename> provides a utility
+macro <function>CYG_MCF52xx_I2C_BUS</function>. This takes six
+parameters:
+    </para>
+    <orderedlist>
+      <listitem><para>
+The name of the bus, for example
+<varname>hal_dnp5280_i2c_bus</varname>. This name will be used when
+instantiating the I<superscript>2</superscript>C devices.
+      </para></listitem>
+      <listitem><para>
+An initialization function. If no platform-specific initialization is
+needed then this can be the <function>cyg_mcf52xx_i2c_init</function>
+function exported by this driver. Otherwise it can be a
+platform-specific function which, for example, sets up the relevant
+pins appropriately and then chains into
+<function>cyg_mcf52xx_i2c_init</function>.
+      </para></listitem>
+      <listitem><para>
+The base address of the I<superscript>2</superscript>C bus. For
+example on an MCF5282 with the IPSBAR set to its usual value of
+0x40000000, the I<superscript>2</superscript>C bus is at location
+0x40000300.
+      </para></listitem>
+      <listitem><para>
+The interrupt vector, for example
+<varname>CYGNUM_HAL_ISR_I2C_IIF</varname> on an MCF5282.
+      </para></listitem>
+      <listitem><para>
+The interrupt priority. Typically this will be a configurable option
+within the platform HAL.
+      </para></listitem>
+      <listitem><para>
+A value for the I<superscript>2</superscript>C bus's I2FDR register.
+That register controls the bus speed. Typical bus speeds are 100KHz
+and 400KHz, depending on the capabilities of the attached devices.
+There is no simple relationship between the system clock speed, the
+desired bus speed, and the FDR register. Although the driver could
+determine the FDR setting using a lookup table and appropriate code,
+it is better to determine the correct value once during the porting
+process and avoid unnecessary run-time overheads.
+      </para></listitem>
+    </orderedlist>
+    <para>
+For the common case where only a single I<superscript>2</superscript>C
+bus should be supported
+(<varname>CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES</varname> is
+disabled), the last four parameters should be provided by preprocessor
+<literal>#define</literal>'s, typically in <filename
+class="headerfile">cyg/hal/plf_io.h</filename> which gets
+<literal>#include</literal>'d automatically via
+<filename>cyg/hal/hal_io.h</filename>. This header can also define the
+<varname>HAL_I2C_EXPORTED_DEVICES</varname> macro as per the generic
+I<superscript>2</superscript>C package:
+    </para>
+    <programlisting width=72>
+#include &lt;pkgconf/hal_m68k_dnp5280.h&gt;
+&hellip;
+#ifdef CYGHWR_HAL_M68K_DNP5280_I2C
+#define HAL_MCF52xx_I2C_SINGLETON_BASE   (HAL_MCF52xx_MBAR+HAL_MCF5282_I2C0_BASE)
+#define HAL_MCF52xx_I2C_SINGLETON_ISRVEC CYGNUM_HAL_ISR_I2C_IIF
+#define HAL_MCF52xx_I2C_SINGLETON_ISRPRI CYGNUM_HAL_M68K_DNP5280_I2C_ISRPRI
+#define HAL_MCF52xx_I2C_SINGLETON_FDR    CYGNUM_HAL_M68K_DNP5280_I2C_FDR
+
+#define HAL_I2C_EXPORTED_DEVICES \
+    extern cyg_i2c_bus hal_dnp5280_i2c_bus;
+#endif
+    </programlisting>
+    <para>
+On this particular platform the I<superscript>2</superscript>C bus is
+only accessible on an expansion connector so the support is
+conditional on a configuration option
+<varname>CYGHWR_HAL_M68K_DNP5280_I2C</varname>. The interrupt priority
+and I2FDR values are also controlled by configuration options. On
+other platforms the I<superscript>2</superscript>C support may not be
+conditional and the priority and/or FDR values may be hard-wired.
+    </para>
+    <para>
+The I<superscript>2</superscript>C bus instantiation should happen in
+an ordinary C or C++ file, typically in the platform HAL. The
+corresponding object file should go into
+<filename>libtarget.a</filename> and the file should only contain
+I<superscript>2</superscript>C-related code to get the maximum benefit
+of linker garbage collection.
+    </para>
+    <programlisting width=72>
+#include &lt;cyg/infra/cyg_type.h&gt;
+#include &lt;cyg/hal/hal_io.h&gt;
+#include &lt;cyg/io/i2c.h&gt;
+#include &lt;cyg/io/i2c_mcf52xx.h&gt;
+
+static void
+dnp5280_i2c_init(struct cyg_i2c_bus* bus)
+{
+    cyg_uint16   paspar;
+    // Reset GPIO pins PAS0/1 to their alternative SCL/SDA settings
+    HAL_READ_UINT16(HAL_MCF5282_IPSBAR + HAL_MCF5282_GPIO_PASPAR, paspar);
+    paspar &amp;= ~(HAL_MCF5282_GPIO_PASPAR_A0_MASK | HAL_MCF5282_GPIO_PASPAR_A1_MASK);
+    paspar |= (HAL_MCF5282_GPIO_PASPAR_A0_SCL | HAL_MCF5282_GPIO_PASPAR_A1_SDA);
+    HAL_WRITE_UINT16(HAL_MCF5282_IPSBAR + HAL_MCF5282_GPIO_PASPAR, paspar);
+
+    // And leave the driver to take care of the rest.
+    cyg_mcf52xx_i2c_init(bus);
+}
+
+CYG_MCF52xx_I2C_BUS(hal_dnp5280_i2c_bus,
+                    &amp;dnp5280_i2c_init,
+                    HAL_MCF52xx_I2C_SINGLETON_BASE,
+                    HAL_MCF52xx_I2C_SINGLETON_ISRVEC,
+                    HAL_MCF52xx_I2C_SINGLETON_ISRPRI,
+                    HAL_MCF52xx_I2C_SINGLETON_FDR);
+
+    </programlisting>
+    <para>
+Obviously if <varname>CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES</varname>
+is enabled then the singleton macros may not be defined and the
+appropriate numbers should be used directly. This example uses a
+custom initialization function which sets up the relevant pins and
+then chains into the I<superscript>2</superscript>C drivers'
+<function>cyg_mcf52xx_i2c_init</function> function. If the platform
+HAL has already set up the pins correctly then
+<function>cyg_mcf52xx_i2c_init</function> could be used directly in
+the bus instantiation, saving a small amount of code for the custom
+initialization function.
+    </para>
+    <para>
+I<superscript>2</superscript>C device structures can be instantiated
+in the usual way, for example:
+    </para>
+    <programlisting width=72>
+CYG_I2C_DEVICE(cyg_i2c_wallclock_ds1307,
+               &amp;hal_dnp5280_i2c_bus,
+               0x68,
+               0x00,
+               CYG_I2C_DEFAULT_DELAY);
+    </programlisting>
+  </refsect1>
+
+</refentry>  
+</part>
Index: devs/i2c/m68k/mcf52xx/current/include/i2c_mcf52xx.h
===================================================================
RCS file: devs/i2c/m68k/mcf52xx/current/include/i2c_mcf52xx.h
diff -N devs/i2c/m68k/mcf52xx/current/include/i2c_mcf52xx.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/i2c/m68k/mcf52xx/current/include/i2c_mcf52xx.h	6 Aug 2006 21:30:43 -0000
@@ -0,0 +1,117 @@
+//==========================================================================
+//
+//      devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.h
+//
+//      I2C driver for Motorola coldfire processors
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2005, 2006 eCosCentric Ltd.
+//
+// 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):     Bart Veer
+// Contributors:  
+// Date:          2005-11-20
+// Description:   I2C driver for motorola coldfire processor
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/devs_i2c_mcf52xx.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/drv_api.h>
+
+typedef enum cyg_mcf52xx_i2c_xfer_mode {
+    CYG_MCF52xx_I2C_XFER_MODE_INVALID   = 0x00,
+    CYG_MCF52xx_I2C_XFER_MODE_TX        = 0x01,
+    CYG_MCF52xx_I2C_XFER_MODE_RX        = 0x02,
+    CYG_MCF52xx_I2C_XFER_MODE_STARTRX   = 0x03
+} cyg_mcf52xx_i2c_xfer_mode;
+
+typedef struct cyg_mcf52xx_i2c_extra {
+#ifdef CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES    
+    // Put statically initialized fields first.
+    cyg_uint8*                  i2c_base;       // Per-bus h/w details
+    cyg_vector_t                i2c_isrvec;
+    int                         i2c_isrpri;
+    int                         i2c_fdr;
+#endif    
+
+    cyg_uint8                   i2c_owner;      // We have bus ownership
+    cyg_uint8                   i2c_lost_arb;   // Error condition leading to loss of bus ownership
+    cyg_uint8                   i2c_send_nack;  // As per rx send_nack argument
+    cyg_uint8                   i2c_got_nack;   // The last tx resulted in a nack
+    cyg_uint8                   i2c_completed;  // Set by DSR, checked by thread
+    
+    union {
+        const cyg_uint8*        i2c_tx_data;
+        cyg_uint8*              i2c_rx_data;
+    } i2c_data;                                 // The current buffer for rx or tx
+    cyg_uint32                  i2c_count;      // Number of bytes left in buffer
+    cyg_mcf52xx_i2c_xfer_mode   i2c_mode;       // TX, RX, ...
+
+
+    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_mcf52xx_i2c_extra;
+
+externC void        cyg_mcf52xx_i2c_init(struct cyg_i2c_bus*);
+externC cyg_uint32  cyg_mcf52xx_i2c_tx(const cyg_i2c_device*, cyg_bool, const cyg_uint8*, cyg_uint32, cyg_bool);
+externC cyg_uint32  cyg_mcf52xx_i2c_rx(const cyg_i2c_device*, cyg_bool, cyg_uint8*, cyg_uint32, cyg_bool, cyg_bool);
+externC void        cyg_mcf52xx_i2c_stop(const cyg_i2c_device*);
+
+#ifdef CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES
+# define CYG_MCF52xx_I2C_BUS(_name_, _init_fn_, _base_, _isr_vec_, _isr_pri_, _fdr_)    \
+    static cyg_mcf52xx_i2c_extra _name_ ## _extra = {                                   \
+        _base_,                                                                         \
+        _isr_vec_,                                                                      \
+        _isr_pri_,                                                                      \
+        _fdr_                                                                           \
+    } ;                                                                                 \
+    CYG_I2C_BUS(_name_,                                                                 \
+                _init_fn_,                                                              \
+                &cyg_mcf52xx_i2c_tx,                                                    \
+                &cyg_mcf52xx_i2c_rx,                                                    \
+                &cyg_mcf52xx_i2c_stop,                                                  \
+                (void*) & ( _name_ ## _extra)) ;
+
+#else
+# define CYG_MCF52xx_I2C_BUS(_name_, _init_fn_, _base_, _isr_vec_, _isr_pri_, _fdr_)    \
+    static cyg_mcf52xx_i2c_extra _name_ ## _extra;                                      \
+    CYG_I2C_BUS(_name_,                                                                 \
+                _init_fn_,                                                              \
+                cyg_mcf52xx_i2c_tx,                                                     \
+                cyg_mcf52xx_i2c_rx,                                                     \
+                cyg_mcf52xx_i2c_stop,                                                   \
+                (void*) & ( _name_ ## _extra)) ;
+#endif
+
Index: devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c
===================================================================
RCS file: devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c
diff -N devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c	6 Aug 2006 21:30:44 -0000
@@ -0,0 +1,451 @@
+//==========================================================================
+//
+//      devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c
+//
+//      I2C driver for Motorola coldfire processors
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2005, 2006 eCosCentric Ltd.
+//
+// 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):     Uwe Kindler, Bart Veer
+// Contributors:  
+// Date:          2005-10-23
+// Description:   I2C driver for motorola coldfire processor
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/devs_i2c_mcf52xx.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_mcf52xx.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>
+
+// Optimize for the case of a single bus device, while still allowing
+// multiple devices.
+#ifndef CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES
+# define    I2C_BASE(_extra_)       (cyg_uint8*)HAL_MCF52xx_I2C_SINGLETON_BASE
+# define    I2C_ISRVEC(_extra_)     HAL_MCF52xx_I2C_SINGLETON_ISRVEC
+# define    I2C_ISRPRI(_extra_)     HAL_MCF52xx_I2C_SINGLETON_ISRPRI
+# define    I2C_FDR(_extra_)        HAL_MCF52xx_I2C_SINGLETON_FDR
+#else
+# define    I2C_BASE(_extra_)       ((_extra_)->i2c_base)
+# define    I2C_ISRVEC(_extra_)     ((_extra_)->i2c_isrvec)
+# define    I2C_ISRPRI(_extra_)     ((_extra_)->i2c_isrpri)
+# define    I2C_FDR(_extra_)        ((_extra_)->i2c_fdr)
+#endif
+
+// If building for a singleton but the macros are no defined, assume
+// the I2C support is conditional on a disabled platform HAL
+// configuration option. This handles the common case of an I2C bus
+// accessed only via an expansion connector.
+#if defined(CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES) || defined(HAL_MCF52xx_I2C_SINGLETON_BASE)
+
+// ----------------------------------------------------------------------------
+// Interrupt handling and polling
+//
+// The MCF52xx I2C bus device does not have a fifo or any kind of DMA
+// capability, so can generate interrupts at a very high rate: ~10K
+// interrupts per second if the bus is running at the standard 100KHz,
+// or 50K for a high-speed 400KHz bus. To keep the cpu load down to
+// something vaguely reasonable as much work as possible has to be
+// done in the ISR, with the DSR used only for completion.
+static cyg_uint32
+mcf52xx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)data;
+    cyg_uint8               sr, dr;
+    cyg_uint8*              base    = I2C_BASE(extra);
+    cyg_uint32              result  = CYG_ISR_HANDLED;
+
+    // Read the current status, then clear the interrupt and
+    // arbitration-lost flags. No later code will look at the
+    // SR register again.
+    HAL_READ_UINT8( base + HAL_MCF52xx_I2C_SR_OFF, sr);
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0x00);
+
+    // What to do next depends on the current transfer mode.
+    if (CYG_MCF52xx_I2C_XFER_MODE_TX == extra->i2c_mode) {
+        // We are in a transmit, or sending the address byte just
+        // before a transmit.
+        if (sr & HAL_MCF52xx_I2C_SR_IAL) {
+            // Lost the bus, abort the transfer. count has already been
+            // decremented. Assume the byte did not actually arrive.
+            extra->i2c_count    += 1;
+            result              = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+        } else if (sr & HAL_MCF52xx_I2C_SR_RXAK) {
+            // This byte has been sent but the device cannot accept
+            // any more. The nack must be remembered. Otherwise if
+            // we got a nack for the last byte in a tx then the
+            // calling code will think the entire tx succeeded,
+            // and there will be problems if the next call is
+            // another tx without a repeated start.
+            extra->i2c_got_nack = 1;
+            result              = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+        } else if (0 == extra->i2c_count) {
+            // No more bytes to send.
+            result          = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+        } else {
+            HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, *(extra->i2c_data.i2c_tx_data));
+            extra->i2c_data.i2c_tx_data += 1;
+            extra->i2c_count            -= 1;
+        }
+    } else if (CYG_MCF52xx_I2C_XFER_MODE_RX == extra->i2c_mode) {
+        if (sr & HAL_MCF52xx_I2C_SR_IAL) {
+            // Lost the bus? Maybe a spurious stop
+            result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+        } else {
+            if (extra->i2c_send_nack && (2 == extra->i2c_count)) {
+                // Received one, one more to go, and that one should be nacked.
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA |
+                                HAL_MCF52xx_I2C_CR_TXAK);
+            } else if (1 == extra->i2c_count) {
+                // Received the last byte. The docs say to send a stop,
+                // but there may be another transaction_rx() call. We
+                // cannot just read DR again, that would trigger another
+                // read. So instead switch to transmit mode for now,
+                // which should cause the h/w to wait until a byte is
+                // written to DR.
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA |
+                                HAL_MCF52xx_I2C_CR_MTX);
+                result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+            }
+
+            HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, dr);
+            *(extra->i2c_data.i2c_rx_data)  = dr;
+            extra->i2c_data.i2c_rx_data     += 1;
+            extra->i2c_count                -= 1;
+        }
+    } else if (CYG_MCF52xx_I2C_XFER_MODE_STARTRX == extra->i2c_mode) {
+        // Start followed by RX. The address byte has been sent, we
+        // need to switch to receiving.
+        if (sr & HAL_MCF52xx_I2C_SR_IAL) {
+            // Looks like no device acknowledged the address.
+            result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
+        } else {
+            extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_RX;
+            if (extra->i2c_send_nack && (1 == extra->i2c_count)) {
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA |
+                                HAL_MCF52xx_I2C_CR_TXAK);
+            } else {
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA);
+            }
+            // This dummy read causes the next rx to start
+            HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, dr);
+        }
+    } else {
+        // Invalid state? Some kind of spurious interrupt? Just ignore
+        // it.
+        CYG_FAIL("I2C spurious interrupt");
+    }
+
+    // NOTE: this will acknowledge the interrupt even in polled mode.
+    // Probably harmless. Using I2C_ISRVEC rather than the vec arg
+    // means a constant number for the singleton case, which may
+    // allow the HAL to optimize the acknowledge away completely.
+    HAL_INTERRUPT_ACKNOWLEDGE(I2C_ISRVEC(extra));
+    return result;
+}
+
+static void
+mcf52xx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)data;
+    extra->i2c_completed    = 1;
+    cyg_drv_cond_signal(&(extra->i2c_wait));
+}
+
+// A transfer has been started. Wait for completion, allowing for both
+// polled and interrupt-driven mode.
+static inline void
+mcf52xx_i2c_doit(cyg_mcf52xx_i2c_extra* extra)
+{
+    cyg_uint8*  base    = I2C_BASE(extra);
+    int         ints_state;
+    int         sr;
+    
+    HAL_QUERY_INTERRUPTS(ints_state);
+    if (((ints_state >> 8) & 0x07) > CYGNUM_HAL_INTERRUPT_DEFAULT_IPL_LEVEL) {
+        // Interrupts are currently disabled. We'll have to poll.
+        for ( ; ; ) {
+            HAL_READ_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, sr);
+            if (sr & HAL_MCF52xx_I2C_SR_IIF) {
+                if (CYG_ISR_CALL_DSR & mcf52xx_i2c_isr(I2C_ISRVEC(extra), (cyg_addrword_t)extra)) {
+                    break;
+                }
+            }
+        }
+    } else {
+        cyg_drv_mutex_lock(&(extra->i2c_lock));
+        cyg_drv_dsr_lock();
+        while (! extra->i2c_completed) {
+            cyg_drv_cond_wait(&(extra->i2c_wait));
+        }
+        cyg_drv_dsr_unlock();
+        cyg_drv_mutex_unlock(&(extra->i2c_lock));
+    }
+}
+
+static cyg_bool
+mcf52xx_i2c_send_start(cyg_mcf52xx_i2c_extra* extra, int address)
+{
+    cyg_uint8*  base    = I2C_BASE(extra);
+    cyg_uint8   sr;
+    
+    // This may be a repeated start or the beginning of a transaction.
+    // If the former then we still own the bus.
+    if (!extra->i2c_owner) {
+        // The bus is currently in slave mode. See if another master
+        // currently owns the bus and if so fail immediately. It is up
+        // to higher level code to decide when to retry. Alternatively
+        // if the bus has somehow got stuck in busy mode it is again
+        // up to higher level code to sort things out.
+        HAL_READ_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_SR_OFF, sr);
+        if (sr & HAL_MCF52xx_I2C_SR_IBB) {
+            return 0;
+        }
+
+        // Now we can put the bus into master mode
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                        HAL_MCF52xx_I2C_CR_IEN   |
+                        HAL_MCF52xx_I2C_CR_IIEN  |
+                        HAL_MCF52xx_I2C_CR_MSTA  |  // This implicitly generates the start
+                        HAL_MCF52xx_I2C_CR_MTX);    // The address byte needs to be transmitted.
+        extra->i2c_owner    = 1;
+    } else {
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                        HAL_MCF52xx_I2C_CR_IEN   |
+                        HAL_MCF52xx_I2C_CR_IIEN  |
+                        HAL_MCF52xx_I2C_CR_MSTA  |  // Already set so no start generated by this
+                        HAL_MCF52xx_I2C_CR_MTX   |
+                        HAL_MCF52xx_I2C_CR_RSTA);    // Repeated start
+    }
+
+    // Any previous nack is no longer relevant. If the device cannot accept
+    // more data it will nack the address.
+    extra->i2c_got_nack = 0;
+    // Now send the address. The rest of the transfer is handled by the
+    // interrupt/polling code.
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, address);
+    return 1;
+}
+
+static inline void
+mcf52xx_i2c_stopit(cyg_mcf52xx_i2c_extra* extra)
+{
+    // If we still own the bus this releases it (by clearing MSTA) and
+    // generating a stop. If we have lost arbitration then this write
+    // has no effect (other than disabling interrupts). Either way the
+    // bus should end up in a consistent state.
+    HAL_WRITE_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
+    extra->i2c_lost_arb = 0;
+    extra->i2c_owner    = 0;
+    extra->i2c_mode     = CYG_MCF52xx_I2C_XFER_MODE_INVALID;
+}
+
+// ----------------------------------------------------------------------------
+// The functions needed for all I2C devices.
+
+void
+cyg_mcf52xx_i2c_init(struct cyg_i2c_bus* bus)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)bus->i2c_extra;
+    cyg_uint8               reg;
+    cyg_uint8*              base    = I2C_BASE(extra);
+
+    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,
+                             &mcf52xx_i2c_isr,
+                             &mcf52xx_i2c_dsr,
+                             &(extra->i2c_interrupt_handle),
+                             &(extra->i2c_interrupt_data));
+    cyg_drv_interrupt_attach(extra->i2c_interrupt_handle);
+
+    // Before unmasking the interrupt sort out the hardware.
+    //
+    // The bus frequency is set by the platform HAL or user, since
+    // it depends on what mixture of devices are present on the bus.
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_FDR_OFF, I2C_FDR(extra));
+    // The device will operate in slave mode when idle. If there is
+    // another bus master then the coldfire might accidentally accept
+    // requests intended for another device. Address 0 is installed
+    // as the slave address. This is the General Call address, used
+    // for broadcasting. It might be better to use another address
+    // like an Hs-mode one, but conflicts are still possible.
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_ADR_OFF, 0x0);
+    // Enable the I2C device but do not start any transfers and
+    // leave interrupts disabled.
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
+    
+    // As per the documentation, if IBB is set then issue a stop. It
+    // is not really clear this is the right thing to do in
+    // multimaster setups, if another master happens to start a
+    // transfer at this exact time. Presumably it solves more problems
+    // than it might cause.
+    HAL_READ_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, reg);
+    if (reg & HAL_MCF52xx_I2C_SR_IBB) {
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x0000);
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x00A0);
+        HAL_READ_UINT8( base + HAL_MCF52xx_I2C_DR_OFF, reg);
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0x0000);
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x0000);
+
+        // Don't forget to reenable the device.
+        HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
+    }
+    
+    // Clear any pending conditions including interrupts.
+    HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0);
+
+    // Interrupts can now be safely unmasked
+    HAL_INTERRUPT_UNMASK(I2C_ISRVEC(extra));
+}
+
+cyg_uint32
+cyg_mcf52xx_i2c_tx(const cyg_i2c_device* dev, cyg_bool send_start, const cyg_uint8* tx_data, cyg_uint32 count, cyg_bool send_stop)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
+
+    extra->i2c_count        = count;
+    if (! extra->i2c_lost_arb) {
+        extra->i2c_completed    = 0;
+        extra->i2c_mode         = CYG_MCF52xx_I2C_XFER_MODE_TX;
+
+        if (send_start) {
+            extra->i2c_data.i2c_tx_data = tx_data;
+            if (! mcf52xx_i2c_send_start(extra, (dev->i2c_address << 1) | 0x00)) {
+                diag_printf("send_start failed\n");
+                return 0;
+            }
+            mcf52xx_i2c_doit(extra);
+        } else if ( !extra->i2c_got_nack) {
+            // We are in the middle of a transaction and not
+            // generating a repeated start, so the device must already
+            // be set up for writes.
+            extra->i2c_data.i2c_tx_data = &(tx_data[1]);
+            extra->i2c_count            = count - 1;
+            HAL_WRITE_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_DR_OFF, *tx_data);
+            mcf52xx_i2c_doit(extra);
+        }
+    }
+    if (send_stop) {
+        mcf52xx_i2c_stopit(extra);
+    }
+
+    // tx() should return the number of bytes actually transmitted.
+    // ISR() increments extra->count after a failure, which leads to
+    // an edge condition when send_start and there is no acknowledgment
+    // of the address byte.
+    if (extra->i2c_count > count) {
+        return 0;
+    }
+    return count - extra->i2c_count;
+}
+
+cyg_uint32
+cyg_mcf52xx_i2c_rx(const cyg_i2c_device* dev, cyg_bool send_start, cyg_uint8* rx_data, cyg_uint32 count, cyg_bool send_nack, cyg_bool send_stop)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
+    cyg_uint8*              base    = I2C_BASE(extra);
+    cyg_uint8               discard;
+    
+    extra->i2c_count        = count;
+    extra->i2c_send_nack    = send_nack;
+    
+    if (! extra->i2c_lost_arb) {
+        extra->i2c_completed        = 0;
+        extra->i2c_data.i2c_rx_data = rx_data;
+        if (send_start) {
+            extra->i2c_mode     = CYG_MCF52xx_I2C_XFER_MODE_STARTRX;
+            if (! mcf52xx_i2c_send_start(extra, (dev->i2c_address << 1) | 0x01) ) {
+                return 0;
+            }
+        } else {
+            // In the middle of a transaction. The previous transfer
+            // will have left the device in tx mode.
+            extra->i2c_mode     = CYG_MCF52xx_I2C_XFER_MODE_RX;
+            if (send_nack && (1 == count)) {
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA |
+                                HAL_MCF52xx_I2C_CR_TXAK);
+            } else {
+                HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
+                                HAL_MCF52xx_I2C_CR_IEN  |
+                                HAL_MCF52xx_I2C_CR_IIEN |
+                                HAL_MCF52xx_I2C_CR_MSTA);
+            }
+            // So reading the data register here should get the device
+            // reading the next byte.
+            HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, discard);
+        }
+        mcf52xx_i2c_doit(extra);
+    }
+    if (send_stop) {
+        mcf52xx_i2c_stopit(extra);
+    }
+    return count - extra->i2c_count;
+}
+
+void
+cyg_mcf52xx_i2c_stop(const cyg_i2c_device* dev)
+{
+    cyg_mcf52xx_i2c_extra*  extra   = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
+    mcf52xx_i2c_stopit(extra);
+}
+
+#endif  //  defined(CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES) || defined(HAL_MCF52xx_I2C_SINGLETON_BASE)
+//---------------------------------------------------------------------------
+// EOF i2c_mcf52xx.c



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]