# HG changeset patch # User vae # Date 1331585552 0 # Node ID 103d5fa67c22f9d965749bf6536bb0e444acc0d4 # Parent a9b6ea6f3c092caab878f29448f756a2e37f7a32 New package -- Smartfusion Cortex-M3 I2C driver package. [Bugzilla 1001291] diff --git a/packages/devs/i2c/cortexm/a2fxxx/current/ChangeLog b/packages/devs/i2c/cortexm/a2fxxx/current/ChangeLog new file mode 100644 --- /dev/null +++ b/packages/devs/i2c/cortexm/a2fxxx/current/ChangeLog @@ -0,0 +1,31 @@ +2011-04-01 Christophe Coutand + + * cdl/i2c_a2fxxx.cdl: + * include/i2c_a2fxxx.h: + * src/i2c_a2fxxx.c: + New package -- Smartfusion Cortex-M3 I2C driver package. + [Bugzilla 1001291] + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// This program 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. +// +// This program 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 this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/packages/devs/i2c/cortexm/a2fxxx/current/cdl/i2c_a2fxxx.cdl b/packages/devs/i2c/cortexm/a2fxxx/current/cdl/i2c_a2fxxx.cdl new file mode 100644 --- /dev/null +++ b/packages/devs/i2c/cortexm/a2fxxx/current/cdl/i2c_a2fxxx.cdl @@ -0,0 +1,113 @@ +# ==================================================================== +# +# i2c_a2fxxx.cdl +# +# eCos Smartfusion Cortex-M3 I2C configuration data +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2011 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. +## +## 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): ccoutand +# Contributors: +# Date: 2011-01-18 +# +#####DESCRIPTIONEND#### +# ==================================================================== + +cdl_package CYGPKG_DEVS_I2C_CORTEXM_A2FXXX { + display "Actel Smartfusion I2C driver" + parent CYGPKG_IO_I2C + active_if CYGPKG_IO_I2C + active_if CYGPKG_HAL_CORTEXM_A2FXXX + include_dir cyg/io + description " + This package provides a generic I2C device driver for the on-chip + I2C modules in Smartfusion Cortex-M3 microcontroller." + + compile -library=libextras.a i2c_a2fxxx.c + + cdl_option CYGNUM_HAL_CORTEXM_A2FXXX_I2C_CLK_DIV { + display "I2C channel clock divider" + flavor data + default_value { 256 } + legal_values { 8 60 120 160 192 960 224 256 960} + description " + Set the I2C clock divider." + } + + cdl_option CYGDBG_DEVS_I2C_CORTEXM_A2FXXX_TRACE { + display "Display status messages during I2C operations" + flavor bool + default_value 0 + description " + Selecting this option will cause the I2C driver to print status + messages as various I2C operations are undertaken." + } + + cdl_component CYGPKG_DEVS_I2C_CORTEXM_A2FXXX_OPTIONS { + display "I2C driver build options" + flavor none + active_if { CYGINT_DEVS_I2C_CORTEXM_A2FXXX_BUS_DEVICES > 0 } + description " + Package specific build options including control over + compiler flags used only in building the Smartfusion Cortex-M3 + I2C bus driver." + + cdl_option CYGPKG_DEVS_I2C_CORTEXM_A2FXXX_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the Smartfusion Cortex-M3 I2C bus driver. These + flags are used in addition to the set of global flags." + } + + cdl_option CYGPKG_DEVS_I2C_CORTEXM_A2FXXX_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the Smartfusion Cortex-M3 I2C bus driver. These + flags are removed from the set of global flags if + present." + } + } +} + +# EOF i2c_a2fxxx.cdl diff --git a/packages/devs/i2c/cortexm/a2fxxx/current/include/i2c_a2fxxx.h b/packages/devs/i2c/cortexm/a2fxxx/current/include/i2c_a2fxxx.h new file mode 100644 --- /dev/null +++ b/packages/devs/i2c/cortexm/a2fxxx/current/include/i2c_a2fxxx.h @@ -0,0 +1,128 @@ +//========================================================================== +// +// i2c_a2fxxx.h +// +// I2C driver for Smartfusion Cortex M3 microcontroller +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2010, 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. +// +// 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): ccoutand +// Contributors: +// Date: 2011-01-18 +// Original: Bart Veer +// I2C driver for motorola coldfire processor +// Description: I2C driver for Smartfusion Cortex M3 microcontroller +//####DESCRIPTIONEND#### +//========================================================================== + +#ifndef CYGONCE_I2C_A2FXXX_H +# define CYGONCE_I2C_A2FXXX_H + +# include +# include +# include + +typedef enum a2fxxx_i2c_xfer_mode { + A2FXXX_I2C_XFER_MODE_INVALID = 0x00, + A2FXXX_I2C_XFER_MODE_TX = 0x01, + A2FXXX_I2C_XFER_MODE_RX = 0x02 +} a2fxxx_i2c_xfer_mode; + +typedef struct a2fxxx_i2c_extra { + cyg_uint32 i2c_base; // I2C base address + cyg_uint32 i2c_base_bb; // I2C base address (Bit-band) + cyg_uint32 i2c_periph; // I2C peripheral bit mask + 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 + a2fxxx_i2c_xfer_mode i2c_mode; // TX, RX, ... + + cyg_bool send_stop; + cyg_bool send_start; + cyg_uint8 slave_addr; + cyg_drv_mutex_t i2c_lock; // For synchronizing between DSR and + // foreground + cyg_drv_cond_t i2c_wait; + // For initializing the interrupt + cyg_handle_t i2c_interrupt_handle; + cyg_interrupt i2c_interrupt_data; + cyg_uint32 i2c_isr_id; + cyg_uint32 i2c_isr_pri; + cyg_uint32 i2c_isr_mask; +} a2fxxx_i2c_extra; + +externC void a2fxxx_i2c_init(struct cyg_i2c_bus *); +externC cyg_uint32 a2fxxx_i2c_tx(const cyg_i2c_device *, cyg_bool, + const cyg_uint8 *, cyg_uint32, cyg_bool); +externC cyg_uint32 a2fxxx_i2c_rx(const cyg_i2c_device *, cyg_bool, + cyg_uint8 *, cyg_uint32, cyg_bool, cyg_bool); +externC void a2fxxx_i2c_stop(const cyg_i2c_device *); + +# define CYG_A2FXXX_I2C_BUS( \ + _name_, \ + _init_fn_, \ + _base_, \ + _base_bb_, \ + _periph_, \ + _isr_vec_, \ + _isr_pri_) \ + static a2fxxx_i2c_extra _name_ ## _extra = { \ + .i2c_base = _base_, \ + .i2c_base_bb = _base_bb_, \ + .i2c_periph = _periph_, \ + .i2c_isr_id = _isr_vec_, \ + .i2c_isr_pri = _isr_pri_ \ + }; \ + CYG_I2C_BUS(_name_, \ + _init_fn_, \ + a2fxxx_i2c_tx, \ + a2fxxx_i2c_rx, \ + a2fxxx_i2c_stop, \ + (void*) & ( _name_ ## _extra)) ; + +#endif // CYGONCE_I2C_A2FXXX_H + +// ------------------------------------------------------------------------- +// EOF i2c_a2fxxx.h diff --git a/packages/devs/i2c/cortexm/a2fxxx/current/src/i2c_a2fxxx.c b/packages/devs/i2c/cortexm/a2fxxx/current/src/i2c_a2fxxx.c new file mode 100644 --- /dev/null +++ b/packages/devs/i2c/cortexm/a2fxxx/current/src/i2c_a2fxxx.c @@ -0,0 +1,450 @@ +//========================================================================== +// +// i2c_a2fxxx.c +// +// I2C driver for Smartfusion Cortex M3 microcontroller +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. +// +// 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): ccoutand +// Contributors: +// Date: 2011-01-18 +// Original: Uwe Kindler, Bart Veer +// I2C driver for motorola coldfire processor +// Description: I2C driver for Smartfusion Cortex M3 microcontroller +// The RX part of the driver has not been tested. +// +//####DESCRIPTIONEND#### +//========================================================================== + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CYGDBG_DEVS_I2C_CORTEXM_A2FXXX_TRACE +# define I2C_TRACE(args...) diag_printf(args) +#else +# define I2C_TRACE(args...) +#endif + +#define I2C_DAT(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_DATA) +#define I2C_ADR(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_ADDR) +#define I2C_SR(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_STATUS) +#define I2C_CR(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_CTRL) +#define I2C_FREQ(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_FREQ) +#define I2C_SMBUS(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_SMBUS) +#define I2C_GLITCH(_base_) (_base_ + CYGHWR_HAL_A2FXXX_I2C_GLITCH) + +// Bit-band definition +#define I2C_CR_CR0(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 0*sizeof(cyg_uint32) ) ) +#define I2C_CR_CR1(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 1*sizeof(cyg_uint32) ) ) +#define I2C_CR_AA(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 2*sizeof(cyg_uint32) ) ) +#define I2C_CR_SI(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 3*sizeof(cyg_uint32) ) ) +#define I2C_CR_STO(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 4*sizeof(cyg_uint32) ) ) +#define I2C_CR_STA(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 5*sizeof(cyg_uint32) ) ) +#define I2C_CR_ENS1(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 6*sizeof(cyg_uint32) ) ) +#define I2C_CR_CR2(_base_) (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) + \ + ( 7*sizeof(cyg_uint32) ) ) + +#define I2C_MTX_STATE(x) CYGHWR_HAL_A2FXXX_I2C_STATUS_MTX_##x +#define I2C_MRX_STATE(x) CYGHWR_HAL_A2FXXX_I2C_STATUS_MRX_##x + +// Divider coefficient +static const unsigned int i2c_div[] = { + 256, + 224, + 192, + 160, + 960, + 120, + 60, + 8, + 0 +}; + +static cyg_uint32 +a2fxxx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) data; + cyg_uint32 result = CYG_ISR_HANDLED; + cyg_uint32 sr, + dr; + cyg_uint8 tx_data = *extra->i2c_data.i2c_tx_data; + cyg_uint32 cr = 0; + + // Read the current status of the I2C + HAL_READ_UINT32(I2C_SR(extra->i2c_base), sr); + HAL_READ_UINT32(I2C_CR(extra->i2c_base), cr); + + // What to do next depends on the current transfer mode. + if (A2FXXX_I2C_XFER_MODE_TX == extra->i2c_mode) { + I2C_TRACE("I2C: TX IRQ handling -> 0x%x\n", sr); + switch (sr) { + // Start/Repeated start, write the slave address and clear the + // START and SI bits + case I2C_MTX_STATE(START): + case I2C_MTX_STATE(REPEAT_START): + HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), extra->slave_addr); + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_STA; + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + break; + // ACK is received for the address or data, keep sending + // START and SI bits + case I2C_MTX_STATE(ADDR_ACK): + case I2C_MTX_STATE(DATA_ACK): + if (0 == extra->i2c_count) { + if (extra->send_stop) { + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO; + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + } else { + // For repeated start, we must disable interrupt + extra->i2c_isr_mask = true; + } + // No more bytes to send. + result |= CYG_ISR_CALL_DSR; + } else { + // Send byte + HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), + (cyg_uint32)tx_data); + extra->i2c_data.i2c_tx_data += 1; + extra->i2c_count -= 1; + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + } + break; + case I2C_MTX_STATE(ARBLOST): + case I2C_MTX_STATE(DATA_NACK): + // Lost the bus, abort the transfer. count has already been + // decremented. Assume the byte did not actually arrive. + extra->i2c_count += 1; + case I2C_MTX_STATE(ADDR_NACK): + // For all error type, clear interrupt and send stop bit + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO; + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + extra->i2c_got_nack = 1; + result |= CYG_ISR_CALL_DSR; + break; + default: + HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id); + return result; + } + } else if (A2FXXX_I2C_XFER_MODE_RX == extra->i2c_mode) { + I2C_TRACE("I2C: RX IRQ handling -> 0x%x\n", sr); + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_AA; + switch (sr) { + // Start/Repeated start, write the slave address and clear the + // START and SI bits + case I2C_MRX_STATE(START): + case I2C_MRX_STATE(REPEAT_START): + HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), extra->slave_addr); + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_STA; + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + break; + // ACK is received for the address + case I2C_MRX_STATE(ADDR_ACK): + if (extra->i2c_count > 1) { + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_AA; + } + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + break; + // Receive data + case I2C_MRX_STATE(DATA_ACK): + case I2C_MRX_STATE(DATA_NACK): + cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + if (extra->i2c_count > 2) { + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_AA; + } + if (1 == extra->i2c_count) { + if (extra->send_stop) { + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO; + } else { + // For repeated start, we must disable interrupt + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_SI; + extra->i2c_isr_mask = true; + } + // Received the last byte. + result |= CYG_ISR_CALL_DSR; + } + HAL_READ_UINT32(I2C_DAT(extra->i2c_base), dr); + *(extra->i2c_data.i2c_rx_data) = (cyg_uint8)dr; + extra->i2c_data.i2c_rx_data += 1; + extra->i2c_count -= 1; + break; + case I2C_MRX_STATE(ARBLOST): + case I2C_MRX_STATE(ADDR_NACK): + // Lost the bus? Maybe a spurious stop + cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO; + result |= CYG_ISR_CALL_DSR; + break; + default: + HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id); + return result; + } + } else { + // Invalid state? Some kind of spurious interrupt? + // Just ignore it. + I2C_TRACE("I2C spurious interrupt\n"); + } + + HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), cr); + + HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id); + + if (extra->i2c_isr_mask) + HAL_INTERRUPT_MASK(extra->i2c_isr_id); + + return result; +} + + +static void +a2fxxx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) data; + extra->i2c_completed = 1; + cyg_drv_cond_signal(&(extra->i2c_wait)); +} + + +// A transfer has been started. Wait for completion +static inline void +a2fxxx_i2c_doit(a2fxxx_i2c_extra * extra) +{ + 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 inline void +a2fxxx_i2c_stopit(a2fxxx_i2c_extra * extra) +{ + extra->i2c_lost_arb = 0; + extra->i2c_owner = 0; + extra->i2c_mode = A2FXXX_I2C_XFER_MODE_INVALID; +} + + +void +a2fxxx_i2c_stop(const cyg_i2c_device * dev) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra; + a2fxxx_i2c_stopit(extra); +} + + +cyg_uint32 +a2fxxx_i2c_tx(const cyg_i2c_device * dev, cyg_bool send_start, + const cyg_uint8 *tx_data, cyg_uint32 count, cyg_bool send_stop) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra; + extra->send_stop = send_stop; + extra->send_start = send_start; + extra->i2c_count = count; + extra->slave_addr = ((dev->i2c_address << 1) | 0x00); + cyg_uint32 si = 0; + + if (!extra->i2c_lost_arb) { + extra->i2c_completed = 0; + extra->i2c_mode = A2FXXX_I2C_XFER_MODE_TX; + + if (send_start || !extra->i2c_got_nack) { + I2C_TRACE + ("I2C: TX to %2x, data %2x, count: %4d, START flag: %s, STOP flag: %s\n", + dev->i2c_address, *tx_data, count, + (send_start == true) ? "true" : "false", + (send_stop == true) ? "true" : "false"); + extra->i2c_data.i2c_tx_data = tx_data; + HAL_READ_UINT32(I2C_CR_SI(extra->i2c_base_bb), si); + // Set start bit + HAL_WRITE_UINT32(I2C_CR_STA(extra->i2c_base_bb), + CYGHWR_HAL_A2FXXX_BITSET); + // For repeated start, we need to clear the interrupt + if (si != 0) { + HAL_WRITE_UINT32(I2C_CR_SI(extra->i2c_base_bb), + CYGHWR_HAL_A2FXXX_BITCLEAR); + HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id); + } + // For repeated start, we need to un-mask the interrupt + if (extra->i2c_isr_mask) { + extra->i2c_isr_mask = false; + HAL_INTERRUPT_UNMASK(extra->i2c_isr_id); + } + a2fxxx_i2c_doit(extra); + } + + } + if (send_stop) { + I2C_TRACE("I2C: TX send stop\n"); + a2fxxx_i2c_stopit(extra); + } + + I2C_TRACE("I2C: TX count %d\n", extra->i2c_count); + + // 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 +a2fxxx_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) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra; + extra->i2c_send_nack = send_nack; + extra->i2c_count = count; + extra->send_stop = send_stop; + extra->send_start = send_start; + extra->slave_addr = ((dev->i2c_address << 1) | 0x01); + cyg_uint32 si = 0; + + if (!extra->i2c_lost_arb) { + extra->i2c_completed = 0; + extra->i2c_data.i2c_rx_data = rx_data; + extra->i2c_mode = A2FXXX_I2C_XFER_MODE_RX; + I2C_TRACE + ("I2C: RX to %2x, count: %4d, START flag: %s, STOP flag: %s\n", + dev->i2c_address, count, (send_start == true) ? "true" : "false", + (send_stop == true) ? "true" : "false"); + HAL_READ_UINT32(I2C_CR_SI(extra->i2c_base_bb), si); + // Set start bit + HAL_WRITE_UINT32(I2C_CR_STA(extra->i2c_base_bb), + CYGHWR_HAL_A2FXXX_BITSET); + // For repeated start, we need to clear the interrupt + if (si != 0) { + HAL_WRITE_UINT32(I2C_CR_SI(extra->i2c_base_bb), + CYGHWR_HAL_A2FXXX_BITCLEAR); + HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id); + } + // For repeated start, we need to un-mask the interrupt + if (extra->i2c_isr_mask) { + extra->i2c_isr_mask = false; + HAL_INTERRUPT_UNMASK(extra->i2c_isr_id); + } + a2fxxx_i2c_doit(extra); + } + + if (send_stop) { + I2C_TRACE("I2C: RX send stop\n"); + a2fxxx_i2c_stopit(extra); + } + + return count - extra->i2c_count; +} + + +// ---------------------------------------------------------------------------- +// The functions needed for all I2C devices. + +void +a2fxxx_i2c_init(struct cyg_i2c_bus *bus) +{ + a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) bus->i2c_extra; + cyg_uint8 div = 0; +#ifdef CYGDBG_DEVS_I2C_CORTEXM_A2FXXX_TRACE + cyg_uint32 i2c_freq = + ((hal_a2fxxx_i2c_clock(extra->i2c_base) / + CYGNUM_HAL_CORTEXM_A2FXXX_I2C_CLK_DIV)); +#endif + + while ((i2c_div[div] != CYGNUM_HAL_CORTEXM_A2FXXX_I2C_CLK_DIV) && + i2c_div[div] != 0) { + div++; + } + + I2C_TRACE("\nI2C INIT, divider: %d(%d), frequency: %d\n", i2c_div[div], + div, i2c_freq); + + cyg_drv_mutex_init(&extra->i2c_lock); + cyg_drv_cond_init(&extra->i2c_wait, &extra->i2c_lock); + cyg_drv_interrupt_create(extra->i2c_isr_id, + extra->i2c_isr_pri, + (cyg_addrword_t)extra, + &a2fxxx_i2c_isr, + &a2fxxx_i2c_dsr, + &(extra->i2c_interrupt_handle), + &(extra->i2c_interrupt_data)); + cyg_drv_interrupt_attach(extra->i2c_interrupt_handle); + + // Enable I2C peripheral + CYGHWR_HAL_A2FXXX_PERIPH_RELEASE(extra->i2c_periph); + + // Set I2C bus speed + HAL_WRITE_UINT32(I2C_CR_ENS1(extra->i2c_base_bb), + CYGHWR_HAL_A2FXXX_BITSET); + + HAL_WRITE_UINT32(I2C_CR_CR0(extra->i2c_base_bb), + ((div & 0x1) ? CYGHWR_HAL_A2FXXX_BITSET : + CYGHWR_HAL_A2FXXX_BITCLEAR)); + HAL_WRITE_UINT32(I2C_CR_CR1(extra->i2c_base_bb), + ((div & 0x2) ? CYGHWR_HAL_A2FXXX_BITSET : + CYGHWR_HAL_A2FXXX_BITCLEAR)); + HAL_WRITE_UINT32(I2C_CR_CR2(extra->i2c_base_bb), + ((div & 0x4) ? CYGHWR_HAL_A2FXXX_BITSET : + CYGHWR_HAL_A2FXXX_BITCLEAR)); + + // Interrupts can now be safely unmasked + HAL_INTERRUPT_UNMASK(extra->i2c_isr_id); +} + +//--------------------------------------------------------------------------- +// EOF i2c_a2fxxx.c