This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
coldfire I2C driver
- From: Bart Veer <bartv at ecoscentric dot com>
- To: ecos-patches at ecos dot sourceware dot org
- Date: 06 Aug 2006 23:33:01 +0100
- Subject: 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 <pkgconf/hal_m68k_dnp5280.h>
+…
+#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 <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/io/i2c.h>
+#include <cyg/io/i2c_mcf52xx.h>
+
+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 &= ~(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,
+ &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,
+ &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