/********************************************************************************
|
Copyright (C) 2016 Marvell International Ltd.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*******************************************************************************/
|
|
#include <Protocol/DriverBinding.h>
|
#include <Protocol/I2cIo.h>
|
#include <Protocol/I2cDemo.h>
|
#include <Protocol/I2c.h>
|
|
#include <Library/BaseLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
#include <Library/IoLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/PcdLib.h>
|
#include <Library/UefiLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Pi/PiI2c.h>
|
|
#include "I2cDemoDxe.h"
|
|
STATIC CONST EFI_GUID I2cGuid = I2C_GUID;
|
|
EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = {
|
I2cDemoSupported,
|
I2cDemoStart,
|
I2cDemoStop
|
};
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoSupported (
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
IN EFI_HANDLE ControllerHandle,
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
)
|
{
|
EFI_STATUS Status = EFI_UNSUPPORTED;
|
EFI_I2C_IO_PROTOCOL *TmpI2cIo;
|
UINT8 *I2cDemoAddresses;
|
UINT8 *I2cDemoBuses;
|
UINTN i;
|
|
Status = gBS->OpenProtocol (
|
ControllerHandle,
|
&gEfiI2cIoProtocolGuid,
|
(VOID **) &TmpI2cIo,
|
gImageHandle,
|
ControllerHandle,
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
);
|
if (EFI_ERROR(Status)) {
|
DEBUG ((DEBUG_INFO, "I2cDemoSupported Error status: %d\n", Status));
|
return EFI_UNSUPPORTED;
|
}
|
|
/* get I2CDEMO devices' addresses from PCD */
|
I2cDemoAddresses = PcdGetPtr (PcdI2cDemoAddresses);
|
I2cDemoBuses = PcdGetPtr (PcdI2cDemoBuses);
|
if (I2cDemoAddresses == 0) {
|
Status = EFI_UNSUPPORTED;
|
DEBUG((DEBUG_INFO, "I2cDemoSupported: I2C device found, but it's not I2CDEMO\n"));
|
goto out;
|
}
|
|
Status = EFI_UNSUPPORTED;
|
for (i = 0; I2cDemoAddresses[i] != '\0'; i++) {
|
/* I2C guid must fit and valid DeviceIndex must be provided */
|
if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) &&
|
TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(I2cDemoBuses[i],
|
I2cDemoAddresses[i])) {
|
DEBUG ((DEBUG_INFO, "I2cDemoSupported: attached to I2CDEMO device\n"));
|
Status = EFI_SUCCESS;
|
break;
|
}
|
}
|
|
out:
|
gBS->CloseProtocol (
|
ControllerHandle,
|
&gEfiI2cIoProtocolGuid,
|
gImageHandle,
|
ControllerHandle
|
);
|
|
return Status;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoRead (
|
IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This,
|
IN UINT8 *RegAddress,
|
IN UINT16 RegAddressLength,
|
IN UINT8 *Buffer,
|
IN UINT16 Length
|
)
|
{
|
EFI_I2C_REQUEST_PACKET *RequestPacket;
|
UINTN RequestPacketSize;
|
EFI_STATUS Status = EFI_SUCCESS;
|
I2CDEMO_CONTEXT *I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(This);
|
|
ASSERT(I2cDemoContext != NULL);
|
ASSERT(I2cDemoContext->I2cIo != NULL);
|
|
RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2;
|
RequestPacket = AllocateZeroPool (RequestPacketSize);
|
if (RequestPacket == NULL)
|
return EFI_OUT_OF_RESOURCES;
|
|
RequestPacket->OperationCount = 2;
|
|
RequestPacket->Operation[0].Flags = 0;
|
RequestPacket->Operation[0].LengthInBytes = RegAddressLength;
|
RequestPacket->Operation[0].Buffer = RegAddress;
|
|
RequestPacket->Operation[1].Flags = I2C_FLAG_READ;
|
RequestPacket->Operation[1].LengthInBytes = Length;
|
RequestPacket->Operation[1].Buffer = Buffer;
|
|
Status = I2cDemoContext->I2cIo->QueueRequest(I2cDemoContext->I2cIo, 0, NULL, RequestPacket, NULL);
|
if (EFI_ERROR(Status))
|
DEBUG((DEBUG_INFO, "I2cDemoTransfer: error %d during transmission\n", Status));
|
|
FreePool(RequestPacket);
|
|
return Status;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoWrite (
|
IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This,
|
IN UINT8 *RegAddress,
|
IN UINT16 RegAddressLength,
|
IN UINT8 *Buffer,
|
IN UINT16 Length
|
)
|
{
|
EFI_I2C_REQUEST_PACKET *RequestPacket;
|
UINTN RequestPacketSize;
|
EFI_STATUS Status = EFI_SUCCESS;
|
I2CDEMO_CONTEXT *I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(This);
|
UINT8 *Data;
|
UINT16 i;
|
|
ASSERT(I2cDemoContext != NULL);
|
ASSERT(I2cDemoContext->I2cIo != NULL);
|
|
RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION);
|
RequestPacket = AllocateZeroPool (RequestPacketSize);
|
if (RequestPacket == NULL)
|
return EFI_OUT_OF_RESOURCES;
|
|
Data = AllocateZeroPool ( RegAddressLength + Length );
|
if (Data == NULL)
|
return EFI_OUT_OF_RESOURCES;
|
|
for (i = 0; i < RegAddressLength; i++)
|
Data[i] = RegAddress[i] & 0xff;
|
|
for (i = RegAddressLength; i < RegAddressLength + Length; i++)
|
Data[i] = Buffer[i - RegAddressLength] & 0xff;
|
|
RequestPacket->OperationCount = 1;
|
|
RequestPacket->Operation[0].Flags = 0;
|
RequestPacket->Operation[0].LengthInBytes = RegAddressLength + Length;
|
RequestPacket->Operation[0].Buffer = Data;
|
|
Status = I2cDemoContext->I2cIo->QueueRequest(I2cDemoContext->I2cIo, 0, NULL, RequestPacket, NULL);
|
if (EFI_ERROR(Status))
|
DEBUG((DEBUG_INFO, "I2cDemoTransfer: error %d during transmission\n", Status));
|
|
FreePool(Data);
|
FreePool(RequestPacket);
|
|
return Status;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoStart (
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
IN EFI_HANDLE ControllerHandle,
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
)
|
{
|
EFI_STATUS Status = EFI_SUCCESS;
|
I2CDEMO_CONTEXT *I2cDemoContext;
|
|
I2cDemoContext = AllocateZeroPool (sizeof(I2CDEMO_CONTEXT));
|
if (I2cDemoContext == NULL) {
|
DEBUG((DEBUG_ERROR, "I2cDemo: allocation fail\n"));
|
return EFI_OUT_OF_RESOURCES;
|
}
|
|
I2cDemoContext->ControllerHandle = ControllerHandle;
|
I2cDemoContext->Signature = I2CDEMO_SIGNATURE;
|
I2cDemoContext->I2cDemoProtocol.Read = I2cDemoRead;
|
I2cDemoContext->I2cDemoProtocol.Write = I2cDemoWrite;
|
|
Status = gBS->OpenProtocol (
|
ControllerHandle,
|
&gEfiI2cIoProtocolGuid,
|
(VOID **) &I2cDemoContext->I2cIo,
|
gImageHandle,
|
ControllerHandle,
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
);
|
if (EFI_ERROR(Status)) {
|
DEBUG((DEBUG_ERROR, "I2cDemo: failed to open I2cIo\n"));
|
FreePool(I2cDemoContext);
|
return EFI_UNSUPPORTED;
|
}
|
|
I2cDemoContext->I2cDemoProtocol.Identifier = I2cDemoContext->I2cIo->DeviceIndex;
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
&ControllerHandle,
|
&gRockchipI2cDemoProtocolGuid, &I2cDemoContext->I2cDemoProtocol,
|
NULL
|
);
|
if (EFI_ERROR(Status)) {
|
DEBUG((DEBUG_ERROR, "I2cDemo: failed to install I2CDEMO protocol\n"));
|
goto fail;
|
}
|
|
return Status;
|
|
fail:
|
FreePool(I2cDemoContext);
|
gBS->CloseProtocol (
|
ControllerHandle,
|
&gEfiI2cIoProtocolGuid,
|
gImageHandle,
|
ControllerHandle
|
);
|
|
return Status;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoStop (
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
IN EFI_HANDLE ControllerHandle,
|
IN UINTN NumberOfChildren,
|
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
)
|
{
|
ROCKCHIP_I2CDEMO_PROTOCOL *I2cDemoProtocol;
|
EFI_STATUS Status;
|
I2CDEMO_CONTEXT *I2cDemoContext;
|
|
Status = gBS->OpenProtocol (
|
ControllerHandle,
|
&gRockchipI2cDemoProtocolGuid,
|
(VOID **) &I2cDemoProtocol,
|
This->DriverBindingHandle,
|
ControllerHandle,
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
);
|
|
if (EFI_ERROR (Status)) {
|
return EFI_DEVICE_ERROR;
|
}
|
I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(I2cDemoProtocol);
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
&ControllerHandle,
|
&gRockchipI2cDemoProtocolGuid, &I2cDemoContext->I2cDemoProtocol,
|
&gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
|
NULL
|
);
|
gBS->CloseProtocol (
|
ControllerHandle,
|
&gEfiI2cIoProtocolGuid,
|
gImageHandle,
|
ControllerHandle
|
);
|
FreePool(I2cDemoContext);
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
I2cDemoInitialise (
|
IN EFI_HANDLE ImageHandle,
|
IN EFI_SYSTEM_TABLE *SystemTable
|
)
|
{
|
EFI_STATUS Status;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
&ImageHandle,
|
&gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
|
NULL
|
);
|
|
return Status;
|
}
|