From 6d10d5deb9b553dde3c7080e05d0cc157b2a4d23 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 4 Apr 2009 20:53:06 +0000 Subject: [PATCH] Add z8 I2C driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1680 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 3 + Documentation/NuttX.html | 9 +- TODO | 10 +- arch/z80/src/z8/Make.defs | 4 +- arch/z80/src/z8/chip.h | 42 +-- arch/z80/src/z8/z8_i2c.c | 603 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 648 insertions(+), 23 deletions(-) create mode 100755 arch/z80/src/z8/z8_i2c.c diff --git a/ChangeLog b/ChangeLog index 94676ceff5..5c3ce1218d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -688,3 +688,6 @@ * eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards. * Add a setmode() method to the SPI interface to handle parts with differing mode requirements. + * include/nuttx/i2c.h: Defined a standard I2C interface + * eZ80Acclaim!: Add an I2C driver. + * eZ8Encore!: Add an I2C driver. diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index e8e9e3e622..ff562da0de 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: March 29, 2009

+

Last Updated: April 4, 2009

@@ -948,7 +948,7 @@ BFD_ASSERT (*plt_offset != (bfd_vma) -1); Integration and testing of NuttX on the ZiLOG ez80f0910200zcog-d is complete. The first integrated version was released in NuttX version 0.4.2 (with important early bugfixes in 0.4.3 and 0.4.4). - As of this writing, that port provides basic board support with a serial console and eZ80F91 EMAC driver. + As of this writing, that port provides basic board support with a serial console, SPI, and eZ80F91 EMAC driver.

@@ -1361,11 +1361,16 @@ nuttx-0.4.5 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards. * Add a setmode() method to the SPI interface to handle parts with differing mode requirements. + * include/nuttx/i2c.h: Defined a standard I2C interface + * eZ80Acclaim!: Add an I2C driver. + * eZ8Encore!: Add an I2C driver. pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> buildroot-0.1.4 2009-xx-xx <spudmonkey@racsa.co.cr> + * Add support for a blackfin toolchain using GCC 4.2.4 and binutils 2.19 + diff --git a/TODO b/TODO index 01c527f3df..751716a0b8 100644 --- a/TODO +++ b/TODO @@ -688,8 +688,14 @@ o z80/z8/ez80 (arch/z80) Status: Open Priority: High if you happen to be working with XTRS. - Description: A "generic" SPI driver has been coded for the eZ80Acclaim! - However, this remains untested since I have no SPI devices for + Description: A "generic" SPI and I2C drivers have been coded for the eZ80Acclaim! + However, these remains untested since I have no SPI or I2C devices for + the board (yet). + Status: Open + Priority: Med + + Description: A "generic" I2C driver has been coded for the eZ8Encore! + However, this remains untested since I have no I2C devices for the board (yet). Status: Open Priority: Med diff --git a/arch/z80/src/z8/Make.defs b/arch/z80/src/z8/Make.defs index a44b029ff0..ae4f2a48c9 100644 --- a/arch/z80/src/z8/Make.defs +++ b/arch/z80/src/z8/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # arch/z80/src/z8/Make.defs # -# Copyright (C) 2008 Gregory Nutt. All rights reserved. +# Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -45,5 +45,5 @@ CMN_CSRCS = up_initialize.c up_allocateheap.c up_createstack.c \ CHIP_SSRCS = z8_vector.S z8_saveusercontext.S z8_restorecontext.S CHIP_CSRCS = z8_initialstate.c z8_irq.c z8_saveirqcontext.c \ z8_schedulesigaction.c z8_sigdeliver.c z8_timerisr.c \ - z8_lowuart.c z8_serial.c z8_registerdump.c + z8_lowuart.c z8_serial.c z8_i2c.c z8_registerdump.c diff --git a/arch/z80/src/z8/chip.h b/arch/z80/src/z8/chip.h index 912dd65e11..702edd5fe9 100644 --- a/arch/z80/src/z8/chip.h +++ b/arch/z80/src/z8/chip.h @@ -2,7 +2,7 @@ * arch/z80/src/z8/chip.h * arch/z80/src/chip/chip.h * - * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -167,27 +167,35 @@ /* I2C Status Register Bit Definitions **********************************************/ #if defined(_Z8FMC16) || defined(_Z8F1680) +# define I2C_ISTAT_NCKI (1 << 0) /* Bit 0: 1=NAK Interrupt */ +# define I2C_ISTAT_SPRS (1 << 1) /* Bit 1: 1=STOP/RESTART condition Interrupt */ +# define I2C_ISTAT_ARBLST (1 << 2) /* Bit 2: 1=Arbitration lost */ +# define I2C_ISTAT_RD (1 << 3) /* Bit 3: 1=Read */ +# define I2C_ISTAT_GCA (1 << 4) /* Bit 4: 1=General Call Address */ +# define I2C_ISTAT_SAM (1 << 5) /* Bit 5: 1=Slave address match */ +# define I2C_ISTAT_RDRF (1 << 6) /* Bit 6: 1=Receive Data Register Full */ +# define I2C_ISTAT_TDRE (1 << 7) /* Bit 7: 1=Transmit Data Register Empty */ #else -# define I2C_STAT_NCKI (1 << 0) /* Bit 0: 1=NACK Interrupt */ -# define I2C_STAT_DSS (1 << 1) /* Bit 1: 1=Data Shift State */ -# define I2C_STAT_TAS (1 << 2) /* Bit 2: 1=Transmit Address State */ -# define I2C_STAT_RD (1 << 3) /* Bit 3: 1=Read */ -# define I2C_STAT_10B (1 << 4) /* Bit 4: 1=10-Bit Address */ -# define I2C_STAT_ACK (1 << 5) /* Bit 5: 1=Acknowledge */ -# define I2C_STAT_RDRF (1 << 6) /* Bit 6: 1=Receive Data Register Full */ -# define I2C_STAT_TDRE (1 << 7) /* Bit 7: 1=Transmit Data Register Empty */ +# define I2C_STAT_NCKI (1 << 0) /* Bit 0: 1=NAK Interrupt */ +# define I2C_STAT_DSS (1 << 1) /* Bit 1: 1=Data Shift State */ +# define I2C_STAT_TAS (1 << 2) /* Bit 2: 1=Transmit Address State */ +# define I2C_STAT_RD (1 << 3) /* Bit 3: 1=Read */ +# define I2C_STAT_10B (1 << 4) /* Bit 4: 1=10-Bit Address */ +# define I2C_STAT_ACK (1 << 5) /* Bit 5: 1=Acknowledge */ +# define I2C_STAT_RDRF (1 << 6) /* Bit 6: 1=Receive Data Register Full */ +# define I2C_STAT_TDRE (1 << 7) /* Bit 7: 1=Transmit Data Register Empty */ #endif /* I2C Control Register Bit Definitions *********************************************/ -#define I2C_CTL_FILTEN (1 << 0) /* Bit 0: 1=I2C Signal Filter Enable */ -#define I2C_CTL_FLUSH (1 << 1) /* Bit 1: 1=Flush Data */ -#define I2C_CTL_NAK (1 << 2) /* Bit 2: 1=Send NAK */ -#define I2C_CTL_TXI (1 << 3) /* Bit 3: 1=Enable TDRE interrupts */ -#define I2C_CTL_BIRQ (1 << 4) /* Bit 4: 1=Baud Rate Generator Interrupt Request */ -#define I2C_CTL_STOP (1 << 5) /* Bit 5: 1=Send Stop Condition */ -#define I2C_CTL_START (1 << 6) /* Bit 6: 1=Send Start Condition */ -#define I2C_CTL_IEN (1 << 7) /* Bit 7: 1=I2C Enable */ +#define I2C_CTL_FILTEN (1 << 0) /* Bit 0: 1=I2C Signal Filter Enable */ +#define I2C_CTL_FLUSH (1 << 1) /* Bit 1: 1=Flush Data */ +#define I2C_CTL_NAK (1 << 2) /* Bit 2: 1=Send NAK */ +#define I2C_CTL_TXI (1 << 3) /* Bit 3: 1=Enable TDRE interrupts */ +#define I2C_CTL_BIRQ (1 << 4) /* Bit 4: 1=Baud Rate Generator Interrupt Request */ +#define I2C_CTL_STOP (1 << 5) /* Bit 5: 1=Send Stop Condition */ +#define I2C_CTL_START (1 << 6) /* Bit 6: 1=Send Start Condition */ +#define I2C_CTL_IEN (1 << 7) /* Bit 7: 1=I2C Enable */ /* Register access macros *********************************************************** * diff --git a/arch/z80/src/z8/z8_i2c.c b/arch/z80/src/z8/z8_i2c.c new file mode 100755 index 0000000000..1fb87d2915 --- /dev/null +++ b/arch/z80/src/z8/z8_i2c.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * arch/z80/src/z8/z8_i2c.c + * + * Copyright(C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include /* eZ8 Register definitions */ +#include "chip.h" /* Register bit definitions */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct z8_i2cdev_s +{ + const struct i2c_ops_s *ops; /* I2C vtable */ + uint16 brg; /* Baud rate generator value */ + ubyte addr; /* 8-bit address */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Misc. Helpers */ + +static void i2c_waittxempty(void); +static void i2c_waitrxavail(void); +static void i2c_setbrg(uint16 brg); +static uint16 i2c_getbrg(uint32 frequency); + +/* I2C methods */ + +static uint32 i2c_setfrequency(FAR struct i2c_dev_s *dev, uint32 frequency); +static int i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits); +static int i2c_write(FAR struct i2c_dev_s *dev, const ubyte *buffer, int buflen); +static int i2c_read(FAR struct i2c_dev_s *dev, ubyte *buffer, int buflen); + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* This function is normally prototyped int the ZiLOG header file sio.h */ + +extern uint32 get_freq(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint16 g_currbrg; /* Current BRG setting */ +static boolean g_initialized; /* TRUE:I2C has been initialized */ +static sem_t g_i2csem; /* Serialize I2C transfers */ + +const struct i2c_ops_s g_ops = +{ + i2c_setfrequency, + i2c_setaddress, + i2c_write, + i2c_read, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: i2c_semtake/i2c_semgive + * + * Description: + * Take/Give the I2C semaphore. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2c_semtake(void) +{ + /* Take the I2C semaphore (perhaps waiting) */ + + while (sem_wait(&g_i2csem) != 0) + { + /* The only case that an error should occr here is if + * the wait was awakened by a signal. + */ + + ASSERT(errno == EINTR); + } +} + +#define i2c_semgive() sem_post(&g_i2csem) + +/**************************************************************************** + * Name: i2c_waittxempty + * + * Description: + * Wait for the transmit data register to become empty. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2c_waittxempty(void) +{ + int i; + for (i = 0; i < 10000 && (I2CSTAT & I2C_STAT_TDRE) == 0; i++); +} + +/**************************************************************************** + * Name: i2c_waitrxavail + * + * Description: + * Wait until we have received a full byte of data. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2c_waitrxavail(void) +{ + int i; + for (i = 0; i <= 10000 && (I2CSTAT & (I2C_STAT_RDRF | I2C_STAT_NCKI)) == 0; i++); +} + +/**************************************************************************** + * Name: i2c_setbrg + * + * Description: + * Set the current BRG value for this transaction + * + * Input Parameters: + * brg - BRG to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2c_setbrg(uint16 brg) +{ + if (g_currbrg != brg) + { + I2CBRH = (ubyte)(brg >> 8); + I2CBRL = (ubyte)(brg & 0xff); + g_currbrg = brg; + } +} + +/**************************************************************************** + * Name: i2c_getbrg + * + * Description: + * Calculate the BRG value + * + * Input Parameters: + * frequency - The I2C frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint16 i2c_getbrg(uint32 frequency) +{ + uint32 sysclock = get_freq(); + + /* Max is 400 Kb/sec */ + + if (frequency > 400*1000) + { + dbg("Invalid inputs\n"); + frequency = 400*1000; + } + + /* BRG = sysclock / (4 * frequency) */ + + return ((sysclock >> 2) + (frequency >> 1)) / frequency; +} + +/**************************************************************************** + * Name: i2c_setfrequency + * + * Description: + * Set the I2C frequency. This frequency will be retained in the struct + * i2c_dev_s instance and will be used with all transfers. Required. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The I2C frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32 i2c_setfrequency(FAR struct i2c_dev_s *dev, uint32 frequency) +{ + FAR struct z8_i2cdev_s *priv = (FAR struct z8_i2cdev_s *)dev; + + /* Sanity Check */ + +#ifdef CONFIG_DEBUG + if (!dev) + { + dbg("Invalid inputs\n"); + return -EINVAL; + } +#endif + + /* Calculate and save the BRG (we won't apply it until the first transfer) */ + + priv->brg = i2c_getbrg(frequency); + return OK; +} + +/**************************************************************************** + * Name: i2c_setaddress + * + * Description: + * Set the I2C slave address. This frequency will be retained in the struct + * i2c_dev_s instance and will be used with all transfers. Required. + * + * Input Parameters: + * dev - Device-specific state data + * address - The I2C slave address + * nbits - The number of address bits provided (7 or 10) + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static int i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits) +{ + FAR struct z8_i2cdev_s *priv = (FAR struct z8_i2cdev_s *)dev; + + /* Sanity Check */ + +#ifdef CONFIG_DEBUG + if (!dev || (unsigned)addr > 0x7f) + { + dbg("Invalid inputs\n"); + return -EINVAL; + } +#endif + + /* Save the 7-bit address (10-bit address not yet supported) */ + + DEBUGASSERT(nbits == 7); + priv->addr = (ubyte)addr; + return OK; +} + +/**************************************************************************** + * Name: i2c_write + * + * Description: + * Send a block of data on I2C using the previously selected I2C + * frequency and slave address. Each write operational will be an 'atomic' + * operation in the sense that any other I2C actions will be serialized + * and pend until this write completes. Required. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the read-only buffer of data to be written to device + * buflen - The number of bytes to send from the buffer + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +static int i2c_write(FAR struct i2c_dev_s *dev, const ubyte *buffer, int buflen) +{ + FAR struct z8_i2cdev_s *priv = (FAR struct z8_i2cdev_s *)dev; + const ubyte *ptr; + int retry; + int count; + +#ifdef CONFIG_DEBUG + if (!priv || !buffer || buflen < 1) + { + dbg("Invalid inputs\n"); + return -EINVAL; + } +#endif + + /* Get exclusive access */ + + i2c_semtake(); + + /* Set the frequency */ + + i2c_setbrg(priv->brg); + + /* Retry as necessary to send this whole message */ + + for (retry = 0; retry < 100; retry++) + { + /* Load the address into the transmit register. It is not sent + * until the START bit is set. + */ + + I2CD = I2C_WRITEADDR8(priv->addr); + I2CCTL |= I2C_CTL_START; + + /* Wait for the xmt buffer to become empty */ + + i2c_waittxempty(); + + /* Then send all of the bytes in the buffer */ + + ptr = buffer; + for (count = buflen; count; count--) + { + /* Send a byte of data and wait for it to be sent */ + + I2CD = *ptr++; + i2c_waittxempty(); + + /* If this was the last byte, then send STOP immediately. This + * is because the ACK will not be valid until the STOP clocks out + * the last bit.. Hmmm. If this true then we will never be + * able to send more than one data byte??? + */ + + if (count == 1) + { + I2CCTL |= I2C_CTL_STOP; + + /* If this last byte was ACKed, then the whole buffer + * was successfully sent and we can return success. + */ + + if ((I2CSTAT & I2C_STAT_ACK) != 0) + { + i2c_semgive(); + return OK; + } + + /* If was was not ACKed, then this inner loop will + * terminated (because count will decrement to zero + * and the whole message will be resent + */ + } + + /* Not the last byte... was this byte ACKed? */ + + else if ((I2CSTAT & I2C_STAT_ACK) == 0) + { + /* No, flush the buffer and toggle the I2C on and off */ + + I2CCTL |= I2C_CTL_FLUSH; + I2CCTL &= ~I2C_CTL_IEN; + I2CCTL |= I2C_CTL_IEN; + + /* Break out of the loop early and try again */ + + break; + } + } + } + i2c_semgive(); + return -ETIMEDOUT; +} + +/**************************************************************************** + * Name: i2c_read + * + * Description: + * Receive a block of data from I2C using the previously selected I2C + * frequency and slave address. Each read operational will be an 'atomic' + * operation in the sense that any other I2C actions will be serialized + * and pend until this read completes. Required. + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to a buffer of data to receive the data from the device + * buflen - The requested number of bytes to be read + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +static int i2c_read(FAR struct i2c_dev_s *dev, ubyte *buffer, int buflen) +{ + FAR struct z8_i2cdev_s *priv = (FAR struct z8_i2cdev_s *)dev; + ubyte *ptr; + int retry; + int count; + +#ifdef CONFIG_DEBUG + if (!priv || !buffer || buflen < 1) + { + dbg("Invalid inputs\n"); + return -EINVAL; + } +#endif + + /* Get exclusive access */ + + i2c_semtake(); + + /* Set the frequency */ + + i2c_setbrg(priv->brg); + + /* Retry as necessary to receive the whole message */ + + for (retry = 0; retry < 100; retry++) + { + /* Load the address into the transmit register. It is not sent + * until the START bit is set. + */ + + I2CD = I2C_READADDR8(priv->addr); + + /* If we want only a single byte of data, then set the NACK + * bit now. + */ + + I2CCTL |= I2C_CTL_NAK; + + /* The START bit begins the transaction */ + + I2CCTL |= I2C_CTL_START; + + /* Now loop to receive each data byte */ + + ptr = buffer; + for (count = buflen; count; count--) + { + /* Wait for the receive buffer to fill */ + + i2c_waitrxavail(); + + /* Did we get a byte? Or did an error occur? */ + + if (I2CSTAT & I2C_STAT_RDRF) + { + /* Save the data byte */ + + *ptr++ = I2CD; + + /* If the next byte is the last byte, then set NAK now */ + + if (count == 2) + { + I2CCTL |= I2C_CTL_NAK; + } + + /* If this was the last byte, then set STOP and return success */ + + else if (count == 1) + { + I2CCTL |= I2C_CTL_STOP; + i2c_semgive(); + return OK; + } + } + /* An error occurred. Clear byte bus and break out of the loop + * to retry now. + */ + + else + { + /* No, flush the buffer and toggle the I2C on and off */ + + I2CCTL |= I2C_CTL_FLUSH; + I2CCTL &= ~I2C_CTL_IEN; + I2CCTL |= I2C_CTL_IEN; + + /* Break out of the loop early and try again */ + + break; + } + } + } + i2c_semgive(); + return -ETIMEDOUT; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_i2cinitialize + * + * Description: + * Initialize the selected I2C port. And return a unique instance of struct + * struct i2c_dev_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameter: + * Port number (for hardware that has mutiple I2C interfaces) + * + * Returned Value: + * Valid I2C device structre reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct i2c_dev_s *up_i2cinitialize(int port) +{ + FAR struct z8_i2cdev_s *i2c; + + if (!g_initialized) + { + /* Set up some initial BRG value */ + + uint16 brg = i2c_getbrg(100*1000); + i2c_setbrg(brg); + + /* Make sure that GPIOs are configured for the alternate function (this + * varies with silicon revisions). + */ + + PAADDR = 0x02; + PACTL |= 0xc0; + + /* This semaphore enforces serialized access for I2C transfers */ + + sem_init(&g_i2csem, 0, 1); + + /* Enable I2C -- no interrupts */ + + I2CCTL = I2C_CTL_IEN; + } + + /* Now, allocate an I2C instance for this caller */ + + i2c = (FAR struct z8_i2cdev_s *)malloc(sizeof(FAR struct z8_i2cdev_s)); + if (i2c) + { + /* Initialize the allocated instance */ + + i2c->ops = &g_ops; + i2c->brg = g_currbrg; + } + return (FAR struct i2c_dev_s *)i2c; +}