public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Leif Lindholm <leif.lindholm@linaro.org>
To: Chris Co <Christopher.Co@microsoft.com>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	Michael D Kinney <michael.d.kinney@intel.com>
Subject: Re: [PATCH edk2-platforms 06/27] Silicon/NXP: Add I2C library support for i.MX platforms
Date: Thu, 1 Nov 2018 17:53:16 +0000	[thread overview]
Message-ID: <20181101175315.tfg4zr742bbxmzbh@bivouac.eciton.net> (raw)
In-Reply-To: <20180921082542.35768-7-christopher.co@microsoft.com>

On Fri, Sep 21, 2018 at 08:25:57AM +0000, Chris Co wrote:
> This adds support for I2C controller on NXP i.MX platforms.
> 
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> ---
>  Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h             | 162 +++++++
>  Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c   | 487 ++++++++++++++++++++
>  Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf |  35 ++
>  3 files changed, 684 insertions(+)
> 
> diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h
> new file mode 100644
> index 000000000000..de8a1616fe1b
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h
> @@ -0,0 +1,162 @@
> +/** @file
> +*
> +*  Copyright (c) 2018 Microsoft Corporation. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#ifndef _IMX_I2C_H_
> +#define _IMX_I2C_H_
> +
> +#pragma pack(push, 1)

I don't see where below this has any effect.
If not required, please drop.

> +
> +typedef union {
> +  UINT16 AsUint16;

Not super happy with this name.
Could it be just "Raw"? (That pattern is used frequently in EDK2.)
Same applies to similar situations below.

> +  struct {
> +    UINT16 Reserved0 : 1;
> +    UINT16 ADR : 7;
> +    UINT16 Reserved1 : 8;
> +  };
> +} IMX_I2C_IADR_REG;

IADR is the name I guess, but REG should ideally be fully written out
as REGISTER.

> +
> +typedef union {
> +  UINT16 AsUint16;
> +  struct {
> +    UINT16 IC : 6;
> +    UINT16 Reserved0 : 10;
> +  };
> +} IMX_I2C_IFDR_REG;
> +
> +typedef union {
> +  UINT16 AsUint16;
> +  struct {
> +    UINT16 Reserved0 : 2;
> +    UINT16 RSTA : 1;
> +    UINT16 TXAK : 1;
> +    UINT16 MTX : 1;
> +    UINT16 MSTA : 1;
> +    UINT16 IIEN : 1;
> +    UINT16 IEN : 1;
> +    UINT16 Reserved1 : 8;
> +  };
> +} IMX_I2C_I2CR_REG;
> +
> +#define IMX_I2C_I2SR_RXAK        0x0001
> +#define IMX_I2C_I2SR_IIF         0x0002
> +#define IMX_I2C_I2SR_SRW         0x0004
> +#define IMX_I2C_I2SR_IAL         0x0010
> +#define IMX_I2C_I2SR_IBB         0x0020
> +#define IMX_I2C_I2SR_IAAS        0x0040
> +#define IMX_I2C_I2SR_ICF         0x0080
> +
> +typedef union {
> +  UINT16 AsUint16;
> +  struct {
> +    UINT16 RXAK : 1;
> +    UINT16 IIF : 1;
> +    UINT16 SRW : 1;
> +    UINT16 Reserved0 : 1;
> +    UINT16 IAL : 1;
> +    UINT16 IBB : 1;
> +    UINT16 IAAS : 1;
> +    UINT16 ICF : 1;
> +    UINT16 Reserved1 : 8;
> +  };
> +} IMX_I2C_I2SR_REG;
> +
> +typedef union {
> +  UINT16 AsUint16;
> +  struct {
> +    UINT16 DATA : 8;
> +    UINT16 Reserved0 : 8;
> +  };
> +} IMX_I2C_I2DR_REG;
> +
> +typedef struct {
> +  IMX_I2C_IADR_REG IADR;
> +  UINT16 Pad0;
> +  IMX_I2C_IFDR_REG IFDR;
> +  UINT16 Pad1;
> +  IMX_I2C_I2CR_REG I2CR;
> +  UINT16 Pad2;
> +  IMX_I2C_I2DR_REG I2SR;
> +  UINT16 Pad3;
> +  IMX_I2C_I2DR_REG I2DR;
> +  UINT16 Pad4;
> +} IMX_I2C_REGS;

And here, REGISTERS.

> +
> +#pragma pack(pop)
> +
> +typedef struct {
> +  UINT32 ControllerAddress;
> +  UINT32 ControllerSlaveAddress;
> +  UINT32 ReferenceFreq;
> +  UINT32 TargetFreq;
> +  UINT32 SlaveAddress;
> +  UINT32 TimeoutInUs;
> +} IMX_I2C_CONFIG;
> +
> +typedef struct {
> +  UINT32 Divider;
> +  UINT32 IC;

Please expand to CamelCase.
It's not obvious what IC stands for.

> +} IMX_I2C_DIVIDER;
> +
> +/**
> +  Perform I2C read operation.
> +
> +  The iMXI2cRead perform I2C read operation by programming the I2C controller.
> +  The caller is responsible to provide I2C controller configuration.
> +
> +  @param[in]    IMX_I2C_CONFIG    Pointer to structure containing the targeted
> +                                  I2C controller to be used for I2C operation.
> +  @param[in]    RegisterAddress   Targeted device register address to start read.
> +  @param[out]   ReadBufferPtr     Caller supplied buffer that would be written
> +                                  into with data from the read operation.
> +  @param[in]    ReadBufferSize    Size of caller supplied buffer.
> +
> +  @retval   RETURN_SUCCESS        I2C Read operation succeeded.
> +  @retval   RETURN_DEVICE_ERROR   The I2C device is not functioning correctly.
> +
> +**/
> +RETURN_STATUS
> +iMXI2cRead (
> +  IN IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN UINT8            RegisterAddress,
> +  OUT UINT8          *ReadBufferPtr,
> +  IN UINT32           ReadBufferSize
> +  );
> +
> +/**
> +  Perform I2C write operation.
> +
> +  The iMXI2cWrite perform I2C write operation by programming the I2C
> +  controller. The caller is responsible to provide I2C controller
> +  configuration.
> +
> +  @param[in]    IMX_I2C_CONFIG    Pointer to structure containing the targeted
> +                                  I2C controller to be used for I2C operation.
> +  @param[in]    RegisterAddress   Targeted device register address to start write.
> +  @param[out]   WriteBufferPtr    Caller supplied buffer that contained data that
> +                                  would be read from for I2C write operation.
> +  @param[in]    WriteBufferSize   Size of caller supplied buffer.
> +
> +  @retval   RETURN_SUCCESS        I2C Write operation succeeded.
> +  @retval   RETURN_DEVICE_ERROR   The I2C device is not functioning correctly.
> +
> +**/
> +RETURN_STATUS
> +iMXI2cWrite (
> +  IN IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN UINT8            RegisterAddress,
> +  IN UINT8           *WriteBufferPtr,
> +  IN UINT32           WriteBufferSize
> +  );
> +
> +#endif
> diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c
> new file mode 100644
> index 000000000000..6cfe04dba571
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c
> @@ -0,0 +1,487 @@
> +/** @file
> +*
> +*  Copyright (c) 2018 Microsoft Corporation. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#include <Base.h>
> +#include <Uefi.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/TimerLib.h>
> +
> +#include <iMXI2cLib.h>
> +
> +IMX_I2C_DIVIDER DividerValue[] = {

Global variable should have 'm' prefix if scope is this module or 'g'
if external visibility. If only this file, please also make it STATIC.

I'm not super happy about these live-coded values, but I guess adding
a bunch of defines wouldn't help much. But could you add a comment
block explaining roughly what the fields mean?

> +  { 22, 0x20, },

Please drop the second ',' on all lines - IMX_I2C_DIVIDER only has two
structure members.

> +  { 24, 0x21, },
> +  { 26, 0x22, },
> +  { 28, 0x23, },
> +  { 30, 0x00, },
> +  { 32, 0x24, },
> +  { 36, 0x25, },
> +  { 40, 0x26, },
> +  { 42, 0x03, },
> +  { 44, 0x27, },
> +  { 48, 0x28, },
> +  { 52, 0x05, },
> +  { 56, 0x29, },
> +  { 60, 0x06, },
> +  { 64, 0x2A, },
> +  { 72, 0x2B, },
> +  { 80, 0x2C, },
> +  { 88, 0x09, },
> +  { 96, 0x2D, },
> +  { 104, 0x0A, },
> +  { 112, 0x2E, },
> +  { 128, 0x2F, },
> +  { 144, 0x0C, },
> +  { 160, 0x30, },
> +  { 192, 0x31, },
> +  { 224, 0x32, },
> +  { 240, 0x0F, },
> +  { 256, 0x33, },
> +  { 288, 0x10, },
> +  { 320, 0x34, },
> +  { 384, 0x35, },
> +  { 448, 0x36, },
> +  { 480, 0x13, },
> +  { 512, 0x37, },
> +  { 576, 0x14, },
> +  { 640, 0x38, },
> +  { 768, 0x39, },
> +  { 896, 0x3A, },
> +  { 960, 0x17, },
> +  { 1024, 0x3B, },
> +  { 1152, 0x18, },
> +  { 1280, 0x3C, },
> +  { 1536, 0x3D, },
> +  { 1792, 0x3E, },
> +  { 1920, 0x1B, },
> +  { 2048, 0x3F, },
> +  { 2304, 0x1C, },
> +  { 2560, 0x1D, },
> +  { 3072, 0x1E, },
> +  { 3840, 0x1F, },
> +};
> +
> +#define DIVIDER_VALUE_TOTAL (sizeof(DividerValue) / sizeof(DividerValue[0]))

Can use BaseLib ARRAY_SIZE macro instead of adding this custom one.

> +
> +BOOLEAN
> +iMXI2cWaitStatusSet (
> +  IN  IMX_I2C_CONFIG   *I2cConfigPtr,
> +  IN  UINT16           StatusBits
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  UINT32            Counter;
> +  IMX_I2C_I2SR_REG  I2srReg;

Same as for previous patch - no need to name the variable after the
register it's initialised from.

> +
> +  Counter = I2cConfigPtr->TimeoutInUs;
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  while (Counter) {
> +    I2srReg = (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR);
> +    if ((I2srReg.AsUint16 & StatusBits) == StatusBits) {
> +      return TRUE;
> +    }
> +    MicroSecondDelay (1);
> +    --Counter;
> +  }
> +
> +  return FALSE;
> +}
> +
> +BOOLEAN
> +iMXI2cWaitStatusUnSet (
> +  IN  IMX_I2C_CONFIG   *I2cConfigPtr,
> +  IN  UINT16           StatusBits
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  UINT32            Counter;
> +  IMX_I2C_I2SR_REG  I2srReg;
> +
> +  Counter = I2cConfigPtr->TimeoutInUs;
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  while (Counter) {
> +    I2srReg = (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR);
> +    if ((I2srReg.AsUint16 & StatusBits) == 0) {
> +      return TRUE;
> +    }
> +    MicroSecondDelay (1);
> +    --Counter;
> +  }
> +
> +  return FALSE;
> +}
> +
> +BOOLEAN
> +iMXI2cSendByte (
> +  IN  IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN  UINT8           Data
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  UINT32            Counter;
> +  IMX_I2C_I2SR_REG  I2srReg;
> +  UINT16            SendData;
> +
> +  SendData = Data;
> +  Counter = I2cConfigPtr->TimeoutInUs;
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +
> +  // Clear status and transfer byte
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0);
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2DR, SendData);
> +
> +  while (Counter) {
> +    I2srReg = (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR);
> +    if (I2srReg.IIF == 1) {

What does it mean if it's == 1? Can that 1 be given a descriptively
named #define?

> +      return TRUE;
> +    } else if (I2srReg.IAL == 1) {

What does it mean if it's == 1? Can that 1 be given a descriptively
named #define?

> +      DEBUG ((DEBUG_ERROR, "iMXI2cSendByte: fail 0x%04x\n", I2srReg.AsUint16));
> +      return FALSE;
> +    }
> +    MicroSecondDelay (1);
> +    --Counter;
> +  }
> +
> +  DEBUG ((DEBUG_ERROR, "iMXI2cSendByte: Fail timeout\n"));
> +  return FALSE;
> +}
> +
> +RETURN_STATUS
> +iMXI2cSetupController (
> +  IN  IMX_I2C_CONFIG *I2cConfigPtr
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  UINT32            Divider;
> +  UINT32            DividerCount;
> +  UINT32            IfdrDiv;
> +  IMX_I2C_I2CR_REG  I2crReg;
> +
> +  I2cRegsPtr = (IMX_I2C_REGS *)I2cConfigPtr->ControllerAddress;
> +
> +  // Disable controller and clear any pending interrupt
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, 0);
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0);

A comment as to which operation does which?

> +
> +  // Setup Divider if reference freq is provided. If no, use value setup by
> +  // 1st boot loader

first

> +  if (I2cConfigPtr->ReferenceFreq != 0) {
> +    IfdrDiv = 0;
> +    Divider = I2cConfigPtr->ReferenceFreq / I2cConfigPtr->TargetFreq;
> +
> +    for (DividerCount = 0; DividerCount < DIVIDER_VALUE_TOTAL; ++DividerCount) {
> +      if (DividerValue[DividerCount].Divider >= Divider) {
> +        DEBUG ((
> +                 DEBUG_INFO,
> +                 "iMXI2cSetupController: Divider %d IC 0x%02x\n",
> +                 DividerValue[DividerCount].Divider,
> +                 DividerValue[DividerCount].IC));
> +        IfdrDiv = DividerValue[DividerCount].IC;
> +        break;
> +      }
> +    }
> +
> +    if (IfdrDiv == 0) {
> +      DEBUG ((
> +               DEBUG_ERROR,
> +               "iMXI2cSetupController: could not find Divider for %d\n",
> +               Divider));
> +      return RETURN_INVALID_PARAMETER;
> +    }
> +
> +    MmioWrite16 ((UINTN)&I2cRegsPtr->IFDR, IfdrDiv);
> +  }
> +
> +  // Setup slave address
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->IADR,
> +               (I2cConfigPtr->ControllerSlaveAddress << 1));

Why the shift by 1? Could this use a macro?

> +
> +  // Enable controller and set to master mode.
> +  I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +
> +  // This bit must be set before any other I2C_I2CR bits have an effect

Why?

> +  I2crReg.IEN = 1;
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);

What does this write do?

> +  MicroSecondDelay (100);
> +
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0);

Why this write of 0?

> +
> +  // Wait for bus to be idle
> +  if (iMXI2cWaitStatusUnSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains busy\n"));
> +    return RETURN_DEVICE_ERROR;
> +  }
> +
> +  I2crReg.MSTA = 1;

What does 1 mean?

> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);

What does this write do?

> +
> +  // Now wait for bus to be busy
> +  if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains idle\n"));
> +    return RETURN_DEVICE_ERROR;
> +  }
> +
> +  return RETURN_SUCCESS;
> +}
> +
> +RETURN_STATUS
> +iMXI2cGenerateStart (
> +  IN  IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN  UINT8           RegisterAddress
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  IMX_I2C_I2CR_REG  I2crReg;
> +  BOOLEAN           Result;
> +  RETURN_STATUS     Status;
> +
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  Status = iMXI2cSetupController (I2cConfigPtr);
> +  if (RETURN_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Fail to setup controller %r\n",
> +            Status));
> +    return Status;
> +  }
> +
> +  // Set controller to transmit mode
> +  I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +  I2crReg.MTX = 1;
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);
> +
> +  Result = iMXI2cSendByte (I2cConfigPtr, (I2cConfigPtr->SlaveAddress << 1));

Shift? Macro?

> +  if (Result == FALSE) {
> +    DEBUG ((
> +             DEBUG_ERROR,
> +             "iMXI2cGenerateStart: Slave address transfer fail 0x%04x\n",
> +             MmioRead16 ((UINTN)&I2cRegsPtr->I2SR)));
> +    return RETURN_DEVICE_ERROR;
> +  }
> +
> +  // Send slave register address
> +  Result = iMXI2cSendByte (I2cConfigPtr, RegisterAddress);
> +  if (Result == FALSE) {
> +    DEBUG ((
> +             DEBUG_ERROR,
> +             "iMXI2cGenerateStart: Slave register address transfer fail 0x%04x\n",
> +             MmioRead16 ((UINTN)&I2cRegsPtr->I2SR)));
> +    return RETURN_DEVICE_ERROR;
> +  }
> +
> +  return RETURN_SUCCESS;
> +}
> +
> +RETURN_STATUS
> +iMXI2cGenerateStop (
> +  IN  IMX_I2C_CONFIG *I2cConfigPtr
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  IMX_I2C_I2CR_REG  I2crReg;
> +
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +  I2crReg.MSTA = 0;

I'm getting to the point where I am wanting these fields to be given
useful names. An awful lot of #defines and comments will be necessary
otherwise.

> +  I2crReg.MTX = 0;
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);
> +
> +  // Bus should go idle
> +  if (iMXI2cWaitStatusUnSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStop: Controller remains busy\n"));
> +    return RETURN_DEVICE_ERROR;
> +  }
> +
> +  return RETURN_SUCCESS;
> +}
> +
> +/**
> +  Perform I2C read operation.
> +
> +  The iMXI2cRead perform I2C read operation by programming the I2C controller.
> +  The caller is responsible to provide I2C controller configuration.
> +
> +  @param[in]    IMX_I2C_CONFIG    Pointer to structure containing the targeted
> +                                  I2C controller to be used for I2C operation.
> +  @param[in]    RegisterAddress   Targeted device register address to start read.
> +  @param[out]   ReadBufferPtr     Caller supplied buffer that would be written
> +                                  into with data from the read operation.
> +  @param[in]    ReadBufferSize    Size of caller supplied buffer.
> +
> +  @retval   RETURN_SUCCESS        I2C Read operation succeeded.
> +  @retval   RETURN_DEVICE_ERROR   The I2C device is not functioning correctly.
> +
> +**/
> +RETURN_STATUS
> +iMXI2cRead (
> +  IN IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN UINT8            RegisterAddress,
> +  OUT UINT8          *ReadBufferPtr,
> +  IN UINT32           ReadBufferSize
> +  )
> +{
> +  IMX_I2C_REGS      *I2cRegsPtr;
> +  IMX_I2C_I2CR_REG  I2crReg;
> +  BOOLEAN           Result;
> +  RETURN_STATUS     Status;
> +
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  Status = iMXI2cGenerateStart (I2cConfigPtr, RegisterAddress);
> +  if (RETURN_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStart failed %r\n", Status));
> +    goto Exit;
> +  }
> +
> +  // Send slave address again to begin read
> +  I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +  I2crReg.RSTA = 1; // Repeated start
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);
> +  Result = iMXI2cSendByte (
> +              I2cConfigPtr,
> +              (I2cConfigPtr->SlaveAddress << 1 | 1));

| 1 - the plot thickens.
Macro please.

> +  if (Result == FALSE) {
> +    DEBUG ((
> +              DEBUG_ERROR,
> +              "iMXI2cRead: 2nd Slave address transfer failed 0x%04x\n",
> +              MmioRead16 ((UINTN)&I2cRegsPtr->I2SR)));
> +    Status = RETURN_DEVICE_ERROR;
> +    goto Exit;
> +  }
> +
> +  // Disable master mode
> +  I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +
> +  // NXP application note AN4481 - Only one byte so do not send acknowledge
> +  if (ReadBufferSize == 1) {
> +    I2crReg.TXAK = 1;
> +  } else {
> +    I2crReg.TXAK = 0;
> +  }
> +
> +  I2crReg.MTX = 0;
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);
> +
> +  // A data transfer can now be initiated by a read from I2C_I2DR in Slave
> +  // Receive mode.
> +  MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0);
> +  MmioRead16 ((UINTN)&I2cRegsPtr->I2DR);
> +
> +  do {
> +    // Wait for transfer to complete
> +    if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_IIF) == FALSE) {
> +      DEBUG ((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n"));
> +      Status = RETURN_DEVICE_ERROR;
> +      goto Exit;
> +    }
> +
> +    if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_ICF) == FALSE) {
> +      DEBUG ((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n"));
> +      Status = RETURN_DEVICE_ERROR;
> +      goto Exit;
> +    }
> +
> +    // Before the last byte is read, a Stop signal must be generated
> +    if (ReadBufferSize == 1) {
> +      Status = iMXI2cGenerateStop (
> +                 I2cConfigPtr);

No need to wrap this line.

> +      if (RETURN_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStop fail %r\n", Status));
> +        goto Exit;
> +      }
> +    }
> +
> +    if (ReadBufferSize == 2) {

For second to last byte?
Could use a comment. And possibly comment above at == 1 could be
expanded to explain why.

> +      I2crReg = (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR);
> +      I2crReg.TXAK = 1;

What does this 1 mean? #define?

> +      MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16);
> +    }
> +
> +    MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0);

Why write 0?

> +
> +    *ReadBufferPtr = MmioRead8 ((UINTN)&I2cRegsPtr->I2DR);
> +    ++ReadBufferPtr;
> +    --ReadBufferSize;
> +  } while (ReadBufferSize > 0);
> +
> +Exit:
> +  Status = iMXI2cGenerateStop (I2cConfigPtr);
> +  if (RETURN_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cRead: Final iMXI2cGenerateStop fail %r\n", Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform I2C write operation.
> +
> +  The iMXI2cWrite perform I2C write operation by programming the I2C
> +  controller. The caller is responsible to provide I2C controller
> +  configuration.
> +
> +  @param[in]    IMX_I2C_CONFIG    Pointer to structure containing the targeted
> +                                  I2C controller to be used for I2C operation.
> +  @param[in]    RegisterAddress   Targeted device register address to start write.
> +  @param[out]   WriteBufferPtr    Caller supplied buffer that contained data that
> +                                  would be read from for I2C write operation.
> +  @param[in]    WriteBufferSize   Size of caller supplied buffer.
> +
> +  @retval   RETURN_SUCCESS        I2C Write operation succeeded.
> +  @retval   RETURN_DEVICE_ERROR   The I2C device is not functioning correctly.
> +
> +**/
> +RETURN_STATUS
> +iMXI2cWrite (
> +  IN IMX_I2C_CONFIG  *I2cConfigPtr,
> +  IN UINT8            RegisterAddress,
> +  IN UINT8           *WriteBufferPtr,
> +  IN UINT32           WriteBufferSize
> +  )
> +{
> +  IMX_I2C_REGS    *I2cRegsPtr;
> +  BOOLEAN         Result;
> +  RETURN_STATUS   Status;
> +
> +  I2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
> +  Status = iMXI2cGenerateStart (I2cConfigPtr, RegisterAddress);
> +  if (RETURN_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStart fail %r\n", Status));
> +    goto Exit;
> +  }
> +
> +  while (WriteBufferSize > 0) {
> +    Result = iMXI2cSendByte (I2cConfigPtr, *WriteBufferPtr);
> +    if (Result == FALSE) {
> +      DEBUG ((
> +               DEBUG_ERROR,

Could skip that line break.

/
    Leif

> +               "iMXI2cWrite: Slave address transfer fail 0x%04x\n",
> +               MmioRead16 ((UINTN)&I2cRegsPtr->I2SR)));
> +      Status = RETURN_DEVICE_ERROR;
> +      goto Exit;
> +    }
> +
> +    ++WriteBufferPtr;
> +    --WriteBufferSize;
> +  }
> +
> +Exit:
> +  Status = iMXI2cGenerateStop (I2cConfigPtr);
> +  if (RETURN_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStop fail %r\n", Status));
> +  }
> +
> +  return Status;
> +}
> diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf
> new file mode 100644
> index 000000000000..ad968e88b1da
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf
> @@ -0,0 +1,35 @@
> +## @file
> +#
> +#  Copyright (c) 2018 Microsoft Corporation. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the BSD License
> +#  which accompanies this distribution.  The full text of the license may be found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001A
> +  BASE_NAME                      = iMXI2cLib
> +  FILE_GUID                      = C4E4A003-8AEB-4C9B-8E72-D2BAD2134BDE
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = iMXI2cLib
> +
> +[Packages]
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdePkg/MdePkg.dec
> +  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  IoLib
> +  TimerLib
> +
> +[Sources.common]
> +  iMXI2cLib.c
> -- 
> 2.16.2.gvfs.1.33.gf5370f1
> 


  reply	other threads:[~2018-11-01 17:53 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-21  8:25 [PATCH edk2-platforms 00/27] Import Hummingboard Edge platform for Windows IoT Core Chris Co
2018-09-21  8:25 ` [PATCH edk2-platforms 01/27] Platform/Microsoft: Add OpteeClientPkg dec Chris Co
2018-10-31 20:43   ` Leif Lindholm
2018-11-01 10:55     ` Sumit Garg
2018-11-02  0:41       ` Chris Co
2018-11-02  5:24         ` Sumit Garg
2018-11-02 23:55           ` Chris Co
2018-11-05 10:07             ` Sumit Garg
2018-11-06  1:53               ` Chris Co
2018-11-06 11:09                 ` Sumit Garg
2018-09-21  8:25 ` [PATCH edk2-platforms 02/27] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
2018-09-21  8:25 ` [PATCH edk2-platforms 03/27] Platform/Microsoft: Add MsPkg Chris Co
2018-10-31 21:00   ` Leif Lindholm
2018-09-21  8:25 ` [PATCH edk2-platforms 04/27] Silicon/NXP: Add iMXPlatformPkg dec Chris Co
2018-09-21  8:25 ` [PATCH edk2-platforms 05/27] Silicon/NXP: Add UART library support for i.MX platforms Chris Co
2018-11-01  8:59   ` Leif Lindholm
2018-11-02  1:46     ` Chris Co
2018-09-21  8:25 ` [PATCH edk2-platforms 06/27] Silicon/NXP: Add I2C " Chris Co
2018-11-01 17:53   ` Leif Lindholm [this message]
2018-09-21  8:25 ` [PATCH edk2-platforms 07/27] Silicon/NXP: Add i.MX display library support Chris Co
2018-11-01 18:05   ` Leif Lindholm
2018-11-29  0:55     ` Chris Co
2018-09-21  8:25 ` [PATCH edk2-platforms 08/27] Silicon/NXP: Add Virtual RTC support for i.MX platform Chris Co
2018-12-15 13:26   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 09/27] Silicon/NXP: Add headers for SoC-specific i.MX packages to use Chris Co
2018-11-01 18:20   ` Leif Lindholm
2018-12-01  0:22     ` Chris Co
2018-12-03  9:42       ` Leif Lindholm
2018-12-04  1:44         ` Chris Co
2018-12-04  9:33           ` Ard Biesheuvel
2018-12-04 12:22             ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 10/27] Silicon/NXP: Add iMX6Pkg dec Chris Co
2018-11-01 18:25   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 11/27] Silicon/NXP: Add i.MX6 SoC header files Chris Co
2018-12-13 17:11   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 12/27] Silicon/NXP: Add i.MX6 I/O MUX library Chris Co
2018-11-08 18:00   ` Leif Lindholm
2018-12-04  1:41     ` Chris Co
2018-09-21  8:26 ` [PATCH edk2-platforms 13/27] Silicon/NXP: Add support for iMX SDHC Chris Co
2018-12-05 10:31   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 14/27] Silicon/NXP: Add i.MX6 GPT and EPIT timer headers Chris Co
2018-11-08 18:14   ` Leif Lindholm
2018-12-04  2:06     ` Chris Co
2018-12-04 12:58       ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 15/27] Silicon/NXP: Add i.MX6 GPT Timer library Chris Co
2018-12-13 17:26   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 16/27] Silicon/NXP: Add i.MX6 Timer DXE driver Chris Co
2018-12-13 17:33   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 17/27] Silicon/NXP: Add i.MX6 USB Phy Library Chris Co
2018-12-14 17:10   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 18/27] Silicon/NXP: Add i.MX6 Clock Library Chris Co
2018-12-14 18:12   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 20/27] Silicon/NXP: Add i.MX6 Board init library Chris Co
2018-12-14 20:12   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 19/27] Silicon/NXP: Add i.MX6 ACPI tables Chris Co
2018-12-14 19:53   ` Leif Lindholm
2018-12-17 11:14   ` Ard Biesheuvel
2019-01-08 21:43     ` Chris Co
2019-01-29 14:09       ` Ard Biesheuvel
2018-09-21  8:26 ` [PATCH edk2-platforms 21/27] Silicon/NXP: Add i.MX6 PCIe DXE driver Chris Co
2018-12-14 21:59   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 22/27] Silicon/NXP: Add i.MX6 GOP driver Chris Co
2018-12-14 22:37   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 23/27] Silicon/NXP: Add i.MX6 Smbios Driver Chris Co
2018-12-14 23:07   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 24/27] Silicon/NXP: Add i.MX6 common dsc and fdf files Chris Co
2018-12-14 23:36   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 25/27] Platform/Solidrun: Add Hummingboard Peripheral Initialization Chris Co
2018-12-15 12:12   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 26/27] Platform/SolidRun: Add i.MX 6Quad Hummingboard Edge ACPI tables Chris Co
2018-12-15 12:19   ` Leif Lindholm
2018-09-21  8:26 ` [PATCH edk2-platforms 27/27] Platform/Solidrun: Add i.MX 6Quad Hummingboard Edge dsc and fdf files Chris Co
2018-12-15 12:28   ` Leif Lindholm
2018-12-15 13:32 ` [PATCH edk2-platforms 00/27] Import Hummingboard Edge platform for Windows IoT Core Leif Lindholm
2018-12-19 18:28   ` Chris Co

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181101175315.tfg4zr742bbxmzbh@bivouac.eciton.net \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox