/** @file
  I2c Lib to control I2c controller.

  Copyright 2020 NXP

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef I2C_LIB_INTERNAL_H__
#define I2C_LIB_INTERNAL_H__

#include <Pi/PiI2c.h>
#include <Uefi.h>

/** Module Disable
  0b - The module is enabled. You must clear this field before any other IBCR
       fields have any effect.
  1b - The module is reset and disabled. This is the power-on reset situation.
       When high, the interface is held in reset, but registers can still be
       accessed. Status register fields (IBSR) are not valid when the module
       is disabled.
**/
#define I2C_IBCR_MDIS      BIT7
// I2c Bus Interrupt Enable
#define I2C_IBCR_IBIE      BIT6
/** Master / Slave Mode 0b - Slave mode 1b - Master mode
  When you change this field from 0 to 1, the module generates a START signal
  on the bus and selects the master mode. When you change this field from 1 to
  0, the module generates a STOP signal and changes the operation mode from
  master to slave. You should generate a STOP signal only if IBSR[IBIF]=1.
  The module clears this field without generating a STOP signal when the
  master loses arbitration.
*/
#define I2C_IBCR_MSSL      BIT5
// 0b - Receive 1b - Transmit
#define I2C_IBCR_TXRX      BIT4
/** Data acknowledge disable
  Values written to this field are only used when the I2C module is a receiver,
  not a transmitter.
  0b - The module sends an acknowledge signal to the bus at the 9th clock bit
       after receiving one byte of data.
  1b - The module does not send an acknowledge-signal response (that is,
       acknowledge bit = 1).
**/
#define I2C_IBCR_NOACK     BIT3
/**Repeat START
  If the I2C module is the current bus master, and you program RSTA=1, the I2C
  module generates a repeated START condition. This field always reads as a 0.
  If you attempt a repeated START at the wrong time, if the bus is owned by
  another master the result is loss of arbitration.
**/
#define I2C_IBCR_RSTA      BIT2
// DMA enable
#define I2C_IBCR_DMAEN     BIT1

// Transfer Complete
#define I2C_IBSR_TCF       BIT7
// I2C bus Busy. 0b - Bus is idle, 1b - Bus is busy
#define I2C_IBSR_IBB       BIT5
// Arbitration Lost. software must clear this field by writing a one to it.
#define I2C_IBSR_IBAL      BIT4
// I2C bus interrupt flag
#define I2C_IBSR_IBIF      BIT1
// Received acknowledge 0b - Acknowledge received 1b - No acknowledge received
#define I2C_IBSR_RXAK      BIT0

//Bus idle interrupt enable
#define I2C_IBIC_BIIE      BIT7

// Glitch filter enable
#define I2C_IBDBG_GLFLT_EN BIT3

#define I2C_BUS_TEST_BUSY       TRUE
#define I2C_BUS_TEST_IDLE       !I2C_BUS_TEST_BUSY
#define I2C_BUS_TEST_RX_ACK     TRUE
#define I2C_BUS_NO_TEST_RX_ACK  !I2C_BUS_TEST_RX_ACK

#define ARRAY_LAST_ELEM(x)      (x)[ARRAY_SIZE (x) - 1]
#define I2C_NUM_RETRIES         500

typedef struct _I2C_REGS {
  UINT8 Ibad; // I2c Bus Address Register
  UINT8 Ibfd; // I2c Bus Frequency Divider Register
  UINT8 Ibcr; // I2c Bus Control Register
  UINT8 Ibsr; // I2c Bus Status Register
  UINT8 Ibdr; // I2C Bus Data I/O Register
  UINT8 Ibic; // I2C Bus Interrupt Config Register
  UINT8 Ibdbg; // I2C Bus Debug Register
} I2C_REGS;

/*
 * sorted list of clock divisor, Ibfd register value pairs
 */
typedef struct _I2C_CLOCK_DIVISOR_PAIR {
  UINT16  Divisor;
  UINT8   Ibfd; // I2c Bus Frequency Divider Register value
} I2C_CLOCK_DIVISOR_PAIR;

typedef struct {
  UINTN                           OperationCount;
  EFI_I2C_OPERATION               Operation[2];
} I2C_REG_REQUEST;

#endif // I2C_LIB_INTERNAL_H__
