diff -urN ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/ChangeLog ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/ChangeLog --- ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/ChangeLog 1970-01-01 01:00:00.000000000 +0100 +++ ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/ChangeLog 2005-10-23 20:15:54.000000000 +0200 @@ -0,0 +1,38 @@ +2005-10-23 Uwe Kindler + + * mcf52xx I2C driver package created + +//=========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//=========================================================================== diff -urN ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl --- ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl 1970-01-01 01:00:00.000000000 +0100 +++ ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/cdl/i2c_mcf52xx.cdl 2005-12-28 18:36:01.000000000 +0100 @@ -0,0 +1,102 @@ +# ==================================================================== +# +# i2c_mcf52xx.cdl +# +# eCos MCF52xx I2C configuration data +# +# ==================================================================== +#####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2003, 2004 2005 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: +# 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." + + compile -library=libextras.a i2c_mcf52xx.c + + define_proc { + puts $::cdl_system_header "/***** I2C driver proc output start *****/" + puts $::cdl_system_header "#define CYGDAT_IO_I2C_DEVICE_HEADER " + puts $::cdl_system_header "/***** I2C driver proc output end *****/" + } + + # Support up to two on-chip I2C modules. The number varies between + # processor variants - at the moment only coldfire processors + # with one I2C module are known - but this may change + for { set ::i2c_mcf52xx 0 } { $::i2c_mcf52xx < 2 } { incr ::i2c_mcf52xx } { + + cdl_interface CYGINT_DEVS_I2C_MCF52xx_MODULE[set ::i2c_mcf52xx] { + display "Platform provides I2C module [set ::i2c_mcf52xx]" + flavor bool + description " + This interface will be implemented if the specific coldfire + processor being used has an on-chip I2C-module + [set ::i2c_mcf52xx], and if that module is accessible on + the target hardware." + } + + cdl_component CYGPKG_DEVS_I2C_MCF52xx_MODULE[set ::i2c_mcf52xx] { + display "Allow access to the on-chip I2C-module [set ::i2c_mcf52xx] via an I2C driver" + flavor bool + active_if CYGINT_DEVS_I2C_MCF52xx_MODULE[set ::i2c_mcf52xx] + default_value 1 + + description " + If the application needs to access the on-chip I2C-module + [set ::i2c_mcf52xx] via an eCos I2C driver then this option + should be enabled." + + cdl_option CYGNUM_DEVS_I2C_MCF52xx_ISR_PRIORITY_MODULE[set ::i2c_mcf52xx] { + display "Interrupt priority" + flavor data + default_value is_loaded(CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_I2C) ? \ + CYGNUM_HAL_M68K_MCF52xx_ISR_DEFAULT_PRIORITY_I2C : \ + CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN + legal_values CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MIN to CYGNUM_HAL_M68K_MCF52xx_ISR_PRIORITY_MAX + description " + Interrupt priority for this I2C module." + } + } + } +} diff -urN ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c --- ecos_web_cvs/ecos/packages/devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c 1970-01-01 01:00:00.000000000 +0100 +++ ecos/ecos/packages/devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c 2005-10-25 08:26:30.000000000 +0200 @@ -0,0 +1,717 @@ +//========================================================================== +// +// 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) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2005 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 +// Contributors: Uwe Kindler +// Date: 2005-10-23 +// Description: I2C driver for motorola coldfire processor +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include +#include + +#include // assertion macros +#include + +#include +#include + + +//=========================================================================== +// DEFINES +//=========================================================================== + +// +// we define our own set of register bits in order to be independent from +// platform specific names +// + +//--------------------------------------------------------------------------- +// I2CR register bits +// +#define MCF52xx_I2C_CR_IEN (0x01 << 7) // I2C enabled +#define MCF52xx_I2C_CR_IIEN (0x01 << 6) // Interrupt enable +#define MCF52xx_I2C_CR_MSTA (0x01 << 5) // 0 - Slave, 1 - Master +#define MCF52xx_I2C_CR_MTX (0x01 << 4) // 0 - Receive, 1 - Transmit +#define MCF52xx_I2C_CR_TXAK (0x01 << 3) // 0 - Acknowledge, + // 1 - Send no acknowledge +#define MCF52xx_I2C_CR_RSTA (0x01 << 2) // Repeated start + +//--------------------------------------------------------------------------- +// I2SR register bits +// +#define MCF52xx_I2C_SR_ICF (0x01 << 7) // 0 - Transfer in progress, + // 1 - transfer completed +#define MCF52xx_I2C_SR_IAAS (0x01 << 6) // Address as slave +#define MCF52xx_I2C_SR_IBB (0x01 << 5) // I2C busy bit +#define MCF52xx_I2C_SR_IAL (0x01 << 4) // arbitration lost +#define MCF52xx_I2C_SR_SRW (0x01 << 2) // slave read write +#define MCF52xx_I2C_SR_IIF (0x01 << 1) // interrupt flag +#define MCF52xx_I2C_SR_RXAK (0x01 << 0) // receive acknowledge + +// +// When sending the address these two identifiers are used for +// read or write access indication +// +#define MCF52xx_I2C_READ 0x01 // read from I2C device +#define MCF52xx_I2C_WRITE 0x00 // write to I2C device + +//=========================================================================== +// DATA TYPES +//=========================================================================== +// +// Type of data transfer +// +typedef enum mcf52xx_i2c_master_mode_e +{ + MCF52xx_I2C_MASTER_TX, // transmit to slave + MCF52xx_I2C_MASTER_RX, // receive from slave + MCF52xx_I2C_MASTER_TXRX // transmit and then receive from slave (unused) +} +mcf52xx_i2c_master_mode; + +// +// configuration info for I2C hardware driver +// +typedef struct st_mcf52xx_extra +{ + cyg_uint8 *base; // base address of i2c modul + cyg_uint8 *pdata; // points to buffer with data + cyg_drv_cond_t wait; + cyg_drv_mutex_t lock; + cyg_vector_t isr_vec; // isr vector + int isr_priority; // isr priority + cyg_interrupt interrupt; // stores interrupt data + cyg_handle_t interrupt_handle; // stores interrupt number + volatile cyg_uint8 count; // number of bytes in buffer + volatile bool send_nack; + volatile bool send_stop; + volatile bool stopped; // true if last transfer was + // finished by sending a stop + mcf52xx_i2c_master_mode mode; +} +mcf52xx_i2c_extra; + +// +// initialisation macro for I2C hardware info +// +#define MCF52XX_I2C_EXTRA(_label, \ + _baseaddr, \ + _isr_prio, \ + _isr_vec) \ +mcf52xx_i2c_extra _label = { \ + base : (void *)(_baseaddr), \ + isr_vec : _isr_vec, \ + isr_priority : _isr_prio, \ + stopped : true, \ +}; + +// +// i2c register layout for hardware register access of I2C module +// +typedef struct st_mcf52xx_i2c_regs +{ + cyg_uint8 ADR; // 0x00000300 + cyg_uint8 reserved1[3];// 0x00000301 + cyg_uint8 FDR; // 0x00000304 + cyg_uint8 reserved2[3];// 0x00000305 + cyg_uint8 CR; // 0x00000308 + cyg_uint8 reserved3[3];// 0x00000309 + cyg_uint8 SR; // 0x0000030C + cyg_uint8 reserved4[3];// 0x0000030D + cyg_uint8 DR; // 0x00000310 +} mcf52xx_i2c_regs; + +//=========================================================================== +// GLOBAL DATA +//=========================================================================== +// +// hardware driver info initialisation +// +MCF52XX_I2C_EXTRA(mcf52xx_i2c0_extra, + HAL_MCF52xx_MBAR + HAL_MCF52xx_I2C0_BASE, + CYGNUM_DEVS_I2C_MCF52xx_ISR_PRIORITY_MODULE0, + HAL_MCF52xx_I2C0_ISRVEC); + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +static void mcf52xx_i2c_init(struct cyg_i2c_bus* pbus); +static cyg_uint32 mcf52xx_i2c_tx(const cyg_i2c_device*, cyg_bool, + const cyg_uint8*, cyg_uint32, cyg_bool); +static cyg_uint32 mcf52xx_i2c_rx(const cyg_i2c_device*, cyg_bool, cyg_uint8*, + cyg_uint32, cyg_bool, cyg_bool); +static void mcf52xx_i2c_stop(const cyg_i2c_device*); + +static cyg_uint32 mcf52xx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data); +static void mcf52xx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, + cyg_addrword_t data); +static bool mcf52xx_send_start(const cyg_i2c_device* pdev, cyg_uint8 rdwr); + +// +// I2C bus 0 of mcf52xx +// +CYG_I2C_BUS(mcf52xx_i2c0_bus, \ + mcf52xx_i2c_init, \ + mcf52xx_i2c_tx, \ + mcf52xx_i2c_rx, \ + mcf52xx_i2c_stop, \ + &mcf52xx_i2c0_extra); + +// ---------------------------------------------------------------------------- +// Optional debug support, useful while sorting out the hardware driver +// functions +// +#if 1 +# define DEBUG(_format_, ...) +#else +# define DEBUG(_format_, ...) diag_printf(_format_, ## __VA_ARGS__) +#endif + +//=========================================================================== +// Setup I2C hardware +//=========================================================================== +static void mcf52xx_i2c_init(struct cyg_i2c_bus *pbus) +{ + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + + // + // Platform should setup the port pins and the bit rate for the + // I2C bus. The platform HAL should provide the initialisation macros + // for all I2C modules. Currently only one module is supported but we + // are prepared for Coldfire processors with more I2C modules + // +#if defined(CYGPKG_DEVS_I2C_MCF52xx_MODULE0) && defined(HAL_MCF52xx_I2C0_PROC_INIT) + if (extra == &mcf52xx_i2c0_extra) { + HAL_MCF52xx_I2C0_PROC_INIT(); + } +#endif + + // + // initialise synchronisation primitives + // + cyg_drv_mutex_init(&extra->lock); + cyg_drv_cond_init(&extra->wait, &extra->lock); + + // + // prepare i2c bus interrupt + // + cyg_drv_interrupt_create(extra->isr_vec, + extra->isr_priority, + (cyg_addrword_t) pbus, + &mcf52xx_i2c_isr, + &mcf52xx_i2c_dsr, + &(extra->interrupt_handle), + &(extra->interrupt)); + cyg_drv_interrupt_attach(extra->interrupt_handle); + cyg_drv_interrupt_unmask(extra->isr_vec); + + // + // set hardware into operational state - we do not enable + // intertrupts yet because eCos supports only the master mode and + // so every transfer will be initiated by this device and so + // interrupts will be enabled for each single transfer + // + HAL_WRITE_UINT8(&i2c->CR, MCF52xx_I2C_CR_IEN); // enable the I2C + // bus interface + // system + HAL_READ_UINT8(&i2c->SR, reg_val); + + // + // If the busys bit is set we have to execute some extra steps here + // + if (reg_val & MCF52xx_I2C_SR_IBB) + { + HAL_WRITE_UINT8(&i2c->CR, 0xA); // issue a stop command to + // slave device + HAL_READ_UINT8(&i2c->DR, reg_val); // dummy read of data register + HAL_WRITE_UINT8(&i2c->SR, 0x00); + HAL_WRITE_UINT8(&i2c->CR, 0x00); + } +} + +//=========================================================================== +// I2C ISR - does only interrupt flag clearing +//=========================================================================== +static cyg_uint32 mcf52xx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data) +{ + cyg_i2c_bus *pbus = (cyg_i2c_bus *)data; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + + // + // first we disable interrupts - DSR will reenable it later + // + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val &~ MCF52xx_I2C_CR_IIEN); + + // + // clear interrupt status flag + // + HAL_READ_UINT8(&i2c->SR, reg_val); + HAL_WRITE_UINT8(&i2c->SR, reg_val &~ MCF52xx_I2C_SR_IIF); + + // + // On the mcf5272 there is no need to acknowledge internal + // interrupts, only external ones. + // cyg_drv_interrupt_acknowledge(vec); + // + return CYG_ISR_CALL_DSR; +} + +//=========================================================================== +// I2C DSR - does the interrupt processing +//=========================================================================== +static void mcf52xx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, + cyg_addrword_t data) +{ + cyg_i2c_bus *pbus = (cyg_i2c_bus *)data; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 cr_val; // CR register value + cyg_uint8 sr_val; // SR register value + bool enable_int = true; // true if interrupts should + // be reenabled + + // + // Check if this device is in Master or Slave Mode - eCos only + // support master mode. + // + HAL_READ_UINT8(&i2c->CR, cr_val); + + // + // Master Mode - Check if this device is in Transmit or Receive Mode. + // + if (cr_val & MCF52xx_I2C_CR_MTX) + { + // + // We are in master transmit mode - check if there are more bytes + // to transmit or if the last byte was transmitted + // + if (extra->count || (MCF52xx_I2C_MASTER_RX == extra->mode)) + { + // + // more bytes to transmit - check if the acknowledge arrived + // + HAL_READ_UINT8(&i2c->SR, sr_val); + if (sr_val & MCF52xx_I2C_SR_RXAK) + { + // + // no acknowledge arrived - Get the bus back in a + // consistent state + // + HAL_WRITE_UINT8(&i2c->CR, cr_val & ~MCF52xx_I2C_CR_MSTA); + + DEBUG("I2C TX: No acknowledge received (extra->count: %d)\n", + extra->count); + + enable_int = false; + cyg_drv_cond_broadcast(&extra->wait); + } + else + { + // + // acknowledge arrived, send next data byte or switch + // to receive mode if this was the address cycle + // + if (MCF52xx_I2C_MASTER_RX == extra->mode) + { + cyg_uint8 dummy_read; + // + // switch to receive mode and execute dummy read + // into data register + // + cr_val &= ~MCF52xx_I2C_CR_MTX; + HAL_WRITE_UINT8(&i2c->CR, cr_val); + HAL_READ_UINT8(&i2c->DR, dummy_read); + + if ((1 == extra->count) && extra->send_nack) + { + // + // If we have only one single byte then we set + // Transmit Acknowledge Enable bit so no ACK + // is sent after the next byte is received, + // which indicates "end of data" to the slave. + // + HAL_WRITE_UINT8(&i2c->CR, + cr_val | MCF52xx_I2C_CR_TXAK); + DEBUG("I2C RX: Sending nack\n"); + } + + DEBUG("I2C TX: Switch to receive mode\n"); + } + else + { + // TX-Mode - write next data byte + --extra->count; + DEBUG("I2C TX: Count %d Transmitted %x\n", extra->count, + *extra->pdata); + HAL_WRITE_UINT8(&i2c->DR, *extra->pdata++); + } + } + } + else + { + // + // last byte transmitted - signal stop condition + // + if (extra->send_stop) + { + HAL_WRITE_UINT8(&i2c->CR, cr_val & ~MCF52xx_I2C_CR_MSTA); + DEBUG("I2C TX: Sending stop\n"); + } + + enable_int = false; + cyg_drv_cond_broadcast(&extra->wait); + } + } + else // Master receive mode + { + cyg_uint8 data; + + + if (extra->count == 1) + { + if (extra->send_stop) + { + HAL_WRITE_UINT8(&i2c->CR, cr_val & ~MCF52xx_I2C_CR_MSTA); + DEBUG("I2C RX: Sending stop\n"); + } + } + else + { + if ((2 == extra->count) && extra->send_nack) + { + // + // Second to last byte to be read - Set Transmit + // Acknowledge Enable bit so no ACK is sent after the + // next byte is received, which indicates "end of + // data" to the slave. + // + HAL_WRITE_UINT8(&i2c->CR, cr_val | MCF52xx_I2C_CR_TXAK); + DEBUG("I2C RX: Sending nack\n"); + } + } + + // + // store received data in buffer + // + HAL_READ_UINT8(&i2c->DR, data); // store data into buffer + *extra->pdata++ = data; + --extra->count; + DEBUG("I2C RX: Count %d Received %x\n", extra->count, data); + + // + // if we have received all the data bytes then we can wake up the + // waiting thread + // + if (!extra->count) + { + enable_int = false; + cyg_drv_cond_broadcast(&extra->wait); + } + } + + // + // reenable interrupts - we do this step only if the transfer is + // not yet completed + // + if (enable_int) + { + HAL_READ_UINT8(&i2c->CR, cr_val); + HAL_WRITE_UINT8(&i2c->CR, cr_val | MCF52xx_I2C_CR_IIEN); + } +} + +//=========================================================================== +// Send start condition +//=========================================================================== +static bool mcf52xx_send_start(const cyg_i2c_device* pdev, cyg_uint8 rdwr) +{ + cyg_i2c_bus *pbus = pdev->i2c_bus; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + cyg_uint8 i; + + // + // If the last transfer was finished with a stop condition, then + // we initiate a start condition here. If the last transfer was + // not finished with a stop then we initiate a repeated start here + // + if (extra->stopped) + { + // + // make sure bus is idle - we check 50 times so we spend a maximum of + // 10 ms here. + // + for (i = 0; i < 100; ++i) + { + HAL_READ_UINT8(&i2c->SR, reg_val); + if (!(reg_val & MCF52xx_I2C_SR_IBB)) + { + break; + } + HAL_DELAY_US(200); + } + + // + // if the bus is still not idle after 10 ms of time then + // we have a serious problem here + // + if (50 == i) + { + CYG_POSTCONDITION(50 != i, "Bus is not idle"); + return false; + } + + // + // put module into master tx mode + // + HAL_READ_UINT8(&i2c->CR, reg_val); + reg_val |= (MCF52xx_I2C_CR_MTX | MCF52xx_I2C_CR_MSTA); + reg_val &= ~MCF52xx_I2C_CR_RSTA; + HAL_WRITE_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->DR, ((pdev->i2c_address << 1) & 0xFE) | rdwr); + + // + // make sure bus is not idle - we check 50 times so we spend a + // maximum of 10 ms here. + // + for (i = 0; i < 50; ++i) + { + HAL_READ_UINT8(&i2c->SR, reg_val); + if (reg_val & MCF52xx_I2C_SR_IBB) + { + break; + } + HAL_DELAY_US(200); + } + + // + // if the bus is still not busy after 10 ms of time then + // we have a serious problem + // + if (50 == i) + { + CYG_POSTCONDITION(50 != i, "Bus is idle"); + return false; + } + } + else // if (stopped) + { + // + // if the last transfer was not finished by sending a stop + // condition then we have a repeated start and need to execute + // some other steps here + // + HAL_READ_UINT8(&i2c->SR, reg_val); + CYG_POSTCONDITION(reg_val & MCF52xx_I2C_SR_IBB, "Bus is idle"); + + // Set IBCR.RSTA and put in master RX mode + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val | MCF52xx_I2C_CR_RSTA); + HAL_WRITE_UINT8(&i2c->DR, ((pdev->i2c_address << 1) & 0xFE) | rdwr); + } + + return true; +} + +//=========================================================================== +// Transmit data +//=========================================================================== +static cyg_uint32 mcf52xx_i2c_tx(const cyg_i2c_device* pdev, + cyg_bool send_start, + const cyg_uint8* tx_data, + cyg_uint32 count, + cyg_bool send_stop) +{ + cyg_i2c_bus *pbus = pdev->i2c_bus; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + bool abort = false; + + cyg_drv_mutex_lock(&extra->lock); + cyg_drv_dsr_lock(); + + extra->pdata = (cyg_uint8 *)tx_data; + extra->count = count; + extra->send_stop = send_stop; + extra->mode = MCF52xx_I2C_MASTER_TX; + + // + // generate a start condition and send the address and direction bit + // + if (send_start) + { + abort = !mcf52xx_send_start(pdev, MCF52xx_I2C_WRITE); + } + else + { + HAL_WRITE_UINT8(&i2c->DR, *extra->pdata++); + } + + extra->stopped = extra->send_stop; // store stop for next transfer + + if (!abort) + { + // + // enable interrupts + // + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val | MCF52xx_I2C_CR_IIEN); + + // + // wait until the driver sends all the data bytes + // + if (!cyg_drv_cond_wait(&extra->wait)) + { + // Get the bus back into a consistent state + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val & ~MCF52xx_I2C_CR_MSTA); + } + + // + // Restore module to it's idle (but active) state + // + if (extra->send_stop) + { + HAL_WRITE_UINT8(&i2c->CR, MCF52xx_I2C_CR_IEN); + } + } // if (!abort) + + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&extra->lock); + + return (count - extra->count); +} + +//=========================================================================== +// Receive data from bus +//=========================================================================== +static cyg_uint32 mcf52xx_i2c_rx(const cyg_i2c_device* pdev, + cyg_bool send_start, + cyg_uint8* rx_data, + cyg_uint32 count, + cyg_bool send_nack, + cyg_bool send_stop) +{ + cyg_i2c_bus *pbus = pdev->i2c_bus; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + cyg_bool abort = false; + + cyg_drv_mutex_lock(&extra->lock); + cyg_drv_dsr_lock(); + + extra->pdata = rx_data; + extra->count = count; + extra->send_nack = send_nack; + extra->send_stop = send_stop; + extra->mode = MCF52xx_I2C_MASTER_RX; + + // + // genereate a start condition and send the address and direction bit + // + if (send_start) + { + abort = !mcf52xx_send_start(pdev, MCF52xx_I2C_READ); + } + + extra->stopped = extra->send_stop; // store stop for next transfer + + if (!abort) + { + // + // enable interrupts + // + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val | MCF52xx_I2C_CR_IIEN); + + // + // wait until driver received all the data bytes + // + if (!cyg_drv_cond_wait(&extra->wait)) + { + // Get the bus back in a consistent state + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val & ~MCF52xx_I2C_CR_MSTA); + } + + if (extra->send_stop) + { + // + // Restore module to it's idle (but active) state + // + HAL_WRITE_UINT8(&i2c->CR, MCF52xx_I2C_CR_IEN); + } + } // if (!abort) + + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&extra->lock); + + return (count - extra->count); +} + +//=========================================================================== +// Stop - send stop condition +//=========================================================================== +static void mcf52xx_i2c_stop(const cyg_i2c_device* pdev) +{ + cyg_i2c_bus *pbus = pdev->i2c_bus; + mcf52xx_i2c_extra *extra = (mcf52xx_i2c_extra*)pbus->i2c_extra; + mcf52xx_i2c_regs *i2c = (mcf52xx_i2c_regs *)extra->base; + cyg_uint8 reg_val; + + HAL_READ_UINT8(&i2c->CR, reg_val); + HAL_WRITE_UINT8(&i2c->CR, reg_val & ~MCF52xx_I2C_CR_MSTA); +} + +//--------------------------------------------------------------------------- +// EOF i2c_mcf52xx.c