/** @file
Support for IO expander TCA6424.
Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
//
// Addresses of registers inside expander
//
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mInputRegister[3] = {0x0,0x1,0x2};
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mOutputRegister[3] = {0x4,0x5,0x6};
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mConfigRegister[3] = {0xC,0xD,0xE};
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPolarityRegister[3] = {0x8,0x9,0xA};
#define PCH_SERIAL_IO_I2C4 4
#define TCA6424_I2C_ADDRESS 0x22
#define PINS_PER_REGISTER 8
#define GPIO_EXP_PIN_DIRECTION_OUT 1
#define GPIO_EXP_PIN_DIRECTION_IN 0
#define GPIO_EXP_PIN_POLARITY_NORMAL 0
#define GPIO_EXP_PIN_POLARITY_INVERTED 1
#define GPIO_EXP_SET_OUTPUT 0
#define GPIO_EXP_SET_DIR 1
#define GPIO_EXP_GET_INPUT 2
#define GPIO_EXP_SET_POLARITY 3
#define AUTO_INCREMENT 0x80
/**
Returns the Controller on which GPIO expander is present.
This function returns the Controller value
@param[out] Controller Pointer to a Controller value on
which I2C expander is configured.
@retval EFI_SUCCESS non.
**/
EFI_STATUS
GpioExpGetController (
OUT UINT8 *Controller
)
{
*Controller = PCH_SERIAL_IO_I2C4;
return EFI_SUCCESS;
}
/**
Returns the data from register value giving in the input.
This function is to get the data from the Expander
Registers by following the I2C Protocol communication
@param[in] Bar0 Bar address of the SerialIo Controller
@param[in] Address Expander Value with in the Contoller
@param[in] Register Address of Input/Output/Configure/Polarity
registers with in the Expander
@retval UINT8 Value returned from the register
**/
UINT8
GpioExpGetRegister (
IN UINTN Bar0,
IN UINT8 Address,
IN UINT8 Register
)
{
UINT8 WriBuf[1];
UINT8 ReBuf[1] = {0};
WriBuf[0] = Register;
I2cWriteRead (Bar0, TCA6424_I2C_ADDRESS + Address, 1, WriBuf, 1, ReBuf, WAIT_1_SECOND);
return ReBuf[0];
}
/**
Set the input register to a give value mentioned in the function.
This function is to Programm the data value to the Expander
Register by following the I2C Protocol communication.
@param[in] Bar0 Bar address of the SerialIo Controller
@param[in] Address Expander Value with in the Contoller
@param[in] Register Address of Input/Output/Configure/Polarity
registers with in the Expander
@param[in] Value Value to set in the mentioned the register
**/
VOID
GpioExpSetRegister (
IN UINTN Bar0,
IN UINT8 Address,
IN UINT8 Register,
IN UINT8 Value
)
{
UINT8 WriBuf[2];
WriBuf[0] = Register;
WriBuf[1] = Value;
I2cWriteRead (Bar0, TCA6424_I2C_ADDRESS + Address, 2, WriBuf, 0, NULL, WAIT_1_SECOND);
}
/**
Set the input register to a give value mentioned in the function.
This function is to update the status of the Gpio Expander
pin based on the input Operation value of the caller.This
function calculates the exact address of the register with
the help of the Register Bank
@param[in] Controller SerialIo Controller value
@param[in] Expander Expander Value with in the Contoller
@param[in] Pin Pin with in the Expnader Value
@param[in] Value none
@param[in] Operation Type of operation (Setoutput/Setdirection
/Getinput/Setpolarity)
@retval UINT8 Final Value returned from the register
**/
UINT8
GpioExpDecodeRegAccess (
IN UINT8 Controller,
IN UINT8 Expander,
IN UINT8 Pin,
IN UINT8 Value,
IN UINT8 Operation
)
{
UINT8* RegisterBank;
UINT8 OldValue;
UINT8 NewValue;
UINT8 RegisterAddress;
UINT8 PinNumber;
UINT8 ReturnValue = 0;
DEBUG ((DEBUG_INFO, "GpioExpDecodeRegAccess() %x:%x:%x:%x:%x\n", Controller, Expander, Pin, Value, Operation));
ASSERT(Controller<6);
ASSERT(Expander<2);
ASSERT(Pin<24);
ASSERT(Value<2);
ASSERT(Operation<4);
//
// Find the register Address value based on the OPeration
//
switch(Operation) {
case GPIO_EXP_SET_OUTPUT:
RegisterBank = mOutputRegister;
break;
case GPIO_EXP_SET_DIR:
RegisterBank = mConfigRegister;
break;
case GPIO_EXP_GET_INPUT:
RegisterBank = mInputRegister;
break;
case GPIO_EXP_SET_POLARITY:
RegisterBank = mPolarityRegister;
break;
default:
ASSERT(FALSE);
return 0;
}
//
// Each bit of register represents each Pin
// calaulate the register address and Pinnumber(offset with in register)
//
if (Pin >= 24) {
//
// Avoid out-of-bound usage of RegisterBank
//
return 0;
}
RegisterAddress = RegisterBank[(Pin/PINS_PER_REGISTER)];
PinNumber = Pin%PINS_PER_REGISTER;
OldValue = GpioExpGetRegister(FindSerialIoBar(Controller, 0), Expander, RegisterAddress);
//
// If it to get the data ,just returned otherwise mark the input value and write the register
//
if (Operation == GPIO_EXP_GET_INPUT) {
ReturnValue = 0x1 & (OldValue>>PinNumber);
} else {
NewValue = OldValue;
NewValue &= ~(BIT0<>8) & 0xFF;
WriteBuf[3] = (Output>>16) & 0xFF;
I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
WriteBuf[0] = mPolarityRegister[0] + AUTO_INCREMENT;
WriteBuf[1] = Polarity & 0xFF;
WriteBuf[2] = (Polarity>>8) & 0xFF;
WriteBuf[3] = (Polarity>>16) & 0xFF;
I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
WriteBuf[0] = mConfigRegister[0] + AUTO_INCREMENT;
WriteBuf[1] = Direction & 0xFF;
WriteBuf[2] = (Direction>>8) & 0xFF;
WriteBuf[3] = (Direction>>16) & 0xFF;
I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
}