summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2018-02-20 15:31:35 +0000
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2018-02-23 15:58:19 +0000
commit6a1688c2f8443d3e815da5c95505de533d3f43d5 (patch)
tree4da5fb6feedd1b49064369e4cde5241011e15f06
parentb3d27e224bbf6645a0473246f52695d0c35383d1 (diff)
downloadedk2-platforms-6a1688c2f8443d3e815da5c95505de533d3f43d5.tar.xz
Platform/96Boards: introduce I2C driver
Implement a I2C DXE driver that wires up the I2C devices exposed by a 96boards mezzanine into the EDK2 I2C stack. Note that this requires the platform to identify its I2C master implementations using special GUIDs-as-protocols. It also assumes [for now] that I2C buses are not shared between the 96boards connector and other platform peripherals. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
-rw-r--r--Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c206
-rw-r--r--Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.inf51
2 files changed, 257 insertions, 0 deletions
diff --git a/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c b/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c
new file mode 100644
index 0000000000..79bb9ed5ff
--- /dev/null
+++ b/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c
@@ -0,0 +1,206 @@
+/** @file
+
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+
+ 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 <PiDxe.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/I2cBusConfigurationManagement.h>
+#include <Protocol/I2cEnumerate.h>
+#include <Protocol/I2cMaster.h>
+#include <Protocol/Mezzanine.h>
+
+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);
+}
+
+EFI_STATUS
+EFIAPI
+EntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ 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);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.inf b/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.inf
new file mode 100644
index 0000000000..7eb1fc5030
--- /dev/null
+++ b/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.inf
@@ -0,0 +1,51 @@
+## @file
+#
+# Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+#
+# 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 = 96BoardsI2cDxe
+ FILE_GUID = a59176bc-a151-49c8-b54a-b4ac96f436c3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = EntryPoint
+
+[Sources]
+ 96BoardsI2cDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/96Boards/96Boards.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ g96BoardsMezzanineProtocolGuid ## CONSUMES
+ gEfiI2cBusConfigurationManagementProtocolGuid ## PRODUCES
+ gEfiI2cEnumerateProtocolGuid ## PRODUCES
+ gEfiI2cMasterProtocolGuid ## CONSUMES
+
+[Guids]
+ g96BoardsI2c0MasterGuid
+ g96BoardsI2c1MasterGuid
+
+[FixedPcd]
+ g96BoardsTokenSpaceGuid.PcdI2c0BusFrequencyHz
+ g96BoardsTokenSpaceGuid.PcdI2c1BusFrequencyHz
+
+[Depex]
+ g96BoardsMezzanineProtocolGuid AND g96BoardsI2c0MasterGuid OR g96BoardsI2c1MasterGuid