/** @file
Copyright (c) 2018, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
STATIC MEZZANINE_PROTOCOL *mMezzanine;
typedef struct {
EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cConfigManagement;
EFI_HANDLE I2cMasterHandle;
UINT32 BusFrequency;
UINTN NumDevices;
CONST EFI_I2C_DEVICE *Devices;
} I2C_BUS;
STATIC
EFI_STATUS
EFIAPI
I2cEnumerate (
IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
IN OUT CONST EFI_I2C_DEVICE **Device
)
{
I2C_BUS *Bus;
if (Device == NULL) {
return EFI_INVALID_PARAMETER;
}
Bus = BASE_CR (This, I2C_BUS, I2cEnumerate);
if (Bus->NumDevices == 0 ||
(Bus->NumDevices > 0 && *Device == &Bus->Devices[Bus->NumDevices - 1])) {
*Device = NULL;
} else if (*Device == NULL) {
*Device = &Bus->Devices[0];
} else if (Bus->NumDevices > 1 &&
*Device >= &Bus->Devices[0] &&
*Device < &Bus->Devices[Bus->NumDevices - 1]) {
++*Device;
} else {
return EFI_NO_MAPPING;
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
EFIAPI
I2cGetBusFrequency (
IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
IN UINTN I2cBusConfiguration,
OUT UINTN *BusClockHertz
)
{
I2C_BUS *Bus;
if (BusClockHertz == NULL) {
return EFI_INVALID_PARAMETER;
}
if (I2cBusConfiguration > 0) {
return EFI_NO_MAPPING;
}
Bus = BASE_CR (This, I2C_BUS, I2cEnumerate);
*BusClockHertz = Bus->BusFrequency;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
EFIAPI
EnableI2cBusConfiguration (
IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
IN UINTN I2cBusConfiguration,
IN EFI_EVENT Event OPTIONAL,
IN EFI_STATUS *I2cStatus OPTIONAL
)
{
EFI_I2C_MASTER_PROTOCOL *I2cMaster;
EFI_STATUS Status;
UINTN BusClockHertz;
I2C_BUS *Bus;
if (I2cBusConfiguration > 0) {
return EFI_NO_MAPPING;
}
Bus = BASE_CR (This, I2C_BUS, I2cConfigManagement);
Status = gBS->HandleProtocol (Bus->I2cMasterHandle,
&gEfiI2cMasterProtocolGuid, (VOID **)&I2cMaster);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: gBS->HandleProtocol() failed - %r\n",
__FUNCTION__, Status));
return Status;
}
BusClockHertz = Bus->BusFrequency;
Status = I2cMaster->SetBusFrequency (I2cMaster, &BusClockHertz);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: I2cMaster->SetBusFrequency() failed - %r\n",
__FUNCTION__, Status));
return Status;
}
if (Event != NULL) {
*I2cStatus = EFI_SUCCESS;
gBS->SignalEvent (Event);
}
return EFI_SUCCESS;
}
STATIC I2C_BUS mI2cBus0 = {
{ I2cEnumerate, I2cGetBusFrequency },
{ EnableI2cBusConfiguration },
NULL,
FixedPcdGet32 (PcdI2c0BusFrequencyHz),
0,
NULL,
};
STATIC I2C_BUS mI2cBus1 = {
{ I2cEnumerate, I2cGetBusFrequency },
{ EnableI2cBusConfiguration },
NULL,
FixedPcdGet32 (PcdI2c1BusFrequencyHz),
0,
NULL,
};
STATIC
VOID
RegisterI2cBus (
IN EFI_GUID *Guid,
IN I2C_BUS *I2cBus,
IN UINTN NumDevices,
IN CONST EFI_I2C_DEVICE *Devices
)
{
EFI_STATUS Status;
UINTN BufferSize;
BufferSize = sizeof (EFI_HANDLE);
Status = gBS->LocateHandle (ByProtocol, Guid, NULL, &BufferSize,
&I2cBus->I2cMasterHandle);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "%a: gBS->LocateHandle() failed - %r\n", __FUNCTION__,
Status));
return;
}
I2cBus->NumDevices = NumDevices;
I2cBus->Devices = Devices;
Status = gBS->InstallMultipleProtocolInterfaces (&I2cBus->I2cMasterHandle,
&gEfiI2cEnumerateProtocolGuid,
&I2cBus->I2cEnumerate,
&gEfiI2cBusConfigurationManagementProtocolGuid,
&I2cBus->I2cConfigManagement,
NULL);
ASSERT_EFI_ERROR (Status);
}
STATIC
VOID
EFIAPI
OnEndOfDxe (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gBS->CloseEvent (Event);
gBS->ConnectController (mI2cBus0.I2cMasterHandle, NULL, NULL, TRUE);
gBS->ConnectController (mI2cBus1.I2cMasterHandle, NULL, NULL, TRUE);
}
EFI_STATUS
EFIAPI
EntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT EndOfDxeEvent;
Status = gBS->LocateProtocol (&g96BoardsMezzanineProtocolGuid, NULL,
(VOID **)&mMezzanine);
ASSERT_EFI_ERROR (Status);
RegisterI2cBus (&g96BoardsI2c0MasterGuid, &mI2cBus0,
mMezzanine->I2c0NumDevices, mMezzanine->I2c0DeviceArray);
RegisterI2cBus (&g96BoardsI2c1MasterGuid, &mI2cBus1,
mMezzanine->I2c1NumDevices, mMezzanine->I2c1DeviceArray);
Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, OnEndOfDxe,
NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}