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.biesheu...@linaro.org>
---
 Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c   | 206 ++++++++++++++++++++
 Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.inf |  51 +++++
 2 files changed, 257 insertions(+)

diff --git a/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c 
b/Platform/96Boards/96BoardsI2cDxe/96BoardsI2cDxe.c
new file mode 100644
index 000000000000..79bb9ed5ffee
--- /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 000000000000..7eb1fc503062
--- /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
-- 
2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to