public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Marcin Wojtas <mw@semihalf.com>
To: edk2-devel@lists.01.org
Cc: leif.lindholm@linaro.org, ard.biesheuvel@linaro.org,
	nadavh@marvell.com, mw@semihalf.com, jsd@semihalf.com,
	jaz@semihalf.com, kostap@marvell.com
Subject: [platforms: PATCH v3 10/12] Marvell/Drivers: MvPca95xxDxe: Introduce GPIO expander driver
Date: Thu, 17 Jan 2019 12:15:13 +0100	[thread overview]
Message-ID: <1547723715-4562-11-git-send-email-mw@semihalf.com> (raw)
In-Reply-To: <1547723715-4562-1-git-send-email-mw@semihalf.com>

Marvell Armada 7k/8k-based platforms may use Pca95xx to extend
amount of the GPIO pins.

This patch introduces support for them. The new driver implements
a generic EMBEDDED_GPIO protocol.

In order to ease description of used PCA9XXX controllers
add a common enum type. It can be used e.g. in the board description
library to specify the expander model on a board (instead of passing
a raw number). Update relevant libraries.

Driver is based on initial work done by Allen Yan <yanwei@marvell.com>.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.inf |  45 ++
 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.h   |  65 ++
 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.c   | 645 ++++++++++++++++++++
 3 files changed, 755 insertions(+)
 create mode 100644 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.inf
 create mode 100644 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.h
 create mode 100644 Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.c

diff --git a/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.inf b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.inf
new file mode 100644
index 0000000..3b1ab4e
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.inf
@@ -0,0 +1,45 @@
+## @file
+#
+#  Copyright (c) 2017, Marvell International 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                      = MvPca95xxDxe
+  FILE_GUID                      = f0e405eb-8407-43b9-88e6-2f7d70715c72
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MvPca95xxEntryPoint
+
+[Sources]
+  MvPca95xxDxe.c
+  MvPca95xxDxe.h
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEfiDriverBindingProtocolGuid
+  gEfiI2cIoProtocolGuid
+  gEmbeddedGpioProtocolGuid
+  gMarvellBoardDescProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.h b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.h
new file mode 100644
index 0000000..29eb123
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.h
@@ -0,0 +1,65 @@
+/**
+*
+*  Copyright (c) 2018, Marvell International Ltd. All rights reserved.
+*
+*  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.
+*
+**/
+#ifndef __MV_PCA953X_H__
+#define __MV_PCA953X_H__
+
+#include <Library/ArmadaBoardDescLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MvGpioLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/BoardDesc.h>
+#include <Protocol/MvI2c.h>
+
+#include <Uefi/UefiBaseType.h>
+
+#define PCA95XX_GPIO_SIGNATURE   SIGNATURE_32 ('I', 'O', 'E', 'X')
+
+#define PCA95XX_INPUT_REG        0x0
+#define PCA95XX_OUTPUT_REG       0x2
+#define PCA95XX_DIRECTION_REG    0x6
+
+#define PCA95XX_BANK_SIZE        8
+#define PCA95XX_OPERATION_COUNT  2
+#define PCA95XX_OPERATION_LENGTH 1
+
+typedef enum {
+  PCA9505_PIN_COUNT = 40,
+  PCA9534_PIN_COUNT = 8,
+  PCA9535_PIN_COUNT = 16,
+  PCA9536_PIN_COUNT = 4,
+  PCA9537_PIN_COUNT = 4,
+  PCA9538_PIN_COUNT = 8,
+  PCA9539_PIN_COUNT = 16,
+  PCA9554_PIN_COUNT = 8,
+  PCA9555_PIN_COUNT = 16,
+  PCA9556_PIN_COUNT = 16,
+  PCA9557_PIN_COUNT = 16,
+} PCA95XX_PIN_COUNT;
+
+typedef struct {
+  EMBEDDED_GPIO      GpioProtocol;
+  MV_GPIO_EXPANDER  *GpioExpanders;
+  UINTN              GpioExpanderCount;
+  UINTN              Signature;
+  EFI_HANDLE         ControllerHandle;
+} PCA95XX;
+
+#endif
diff --git a/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.c b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.c
new file mode 100644
index 0000000..8e7ea77
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Gpio/MvPca95xxDxe/MvPca95xxDxe.c
@@ -0,0 +1,645 @@
+/**
+*
+*  Copyright (c) 2018, Marvell International Ltd. All rights reserved.
+*
+*  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 <Protocol/I2cIo.h>
+
+#include <Pi/PiI2c.h>
+
+#include "MvPca95xxDxe.h"
+
+STATIC PCA95XX *mPca95xxInstance;
+
+STATIC MV_GPIO_DEVICE_PATH mDevicePathTemplate = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH) +
+                 sizeof (MV_GPIO_DRIVER_TYPE)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH) +
+                 sizeof (MV_GPIO_DRIVER_TYPE)) >> 8),
+      },
+    },
+    EFI_CALLER_ID_GUID
+  },
+  MV_GPIO_DRIVER_TYPE_PCA95XX,
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      sizeof(EFI_DEVICE_PATH_PROTOCOL),
+      0
+    }
+  }
+};
+
+STATIC PCA95XX_PIN_COUNT mPca95xxPinCount[PCA95XX_MAX_ID] = {
+  PCA9505_PIN_COUNT,
+  PCA9534_PIN_COUNT,
+  PCA9535_PIN_COUNT,
+  PCA9536_PIN_COUNT,
+  PCA9537_PIN_COUNT,
+  PCA9538_PIN_COUNT,
+  PCA9539_PIN_COUNT,
+  PCA9554_PIN_COUNT,
+  PCA9555_PIN_COUNT,
+  PCA9556_PIN_COUNT,
+  PCA9557_PIN_COUNT,
+};
+
+#if !defined(MDEPKG_NDEBUG)
+/**
+
+Routine Description:
+
+  Verifies if controller index / GPIO pin values
+  are within proper boundaries.
+
+Arguments:
+
+  ControllerIndex - index of controller
+  GpioPin - which pin to read
+
+Returns:
+
+  EFI_SUCCESS           - GPIO pin / controller index are proper
+  EFI_INVALID_PARAMETER - GPIO pin / controller index is out of range
+**/
+STATIC
+EFI_STATUS
+MvPca95xxValidate (
+  IN UINTN ControllerIndex,
+  IN UINTN GpioPin
+  )
+{
+  UINTN ControllerId;
+
+  if (ControllerIndex >= mPca95xxInstance->GpioExpanderCount) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Invalid GPIO ControllerIndex: %d\n",
+      __FUNCTION__,
+      ControllerIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ControllerId = mPca95xxInstance->GpioExpanders[ControllerIndex].ChipId;
+
+  if (GpioPin >= mPca95xxPinCount[ControllerId]) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: GPIO pin #%d not available in Controller#%d\n",
+      __FUNCTION__,
+      GpioPin,
+      ControllerIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+#endif
+
+EFI_STATUS
+EFIAPI
+MvPca95xxGetI2c (
+  IN     UINTN                 ControllerIndex,
+  IN OUT EFI_I2C_IO_PROTOCOL **I2cIo
+  )
+{
+  UINTN        I2cBus, I2cAddress;
+  UINTN        HandleCount, Index;
+  EFI_HANDLE  *HandleBuffer;
+  EFI_STATUS   Status;
+
+  I2cBus = mPca95xxInstance->GpioExpanders[ControllerIndex].I2cBus;
+  I2cAddress = mPca95xxInstance->GpioExpanders[ControllerIndex].I2cAddress;
+
+  /* Locate Handles of all EfiI2cIoProtocol producers */
+  Status = gBS->LocateHandleBuffer (ByProtocol,
+                  &gEfiI2cIoProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Unable to locate handles\n", __FUNCTION__));
+    return Status;
+  }
+
+  /* Iterate over all protocol producers and pick one upon DeviceIndex match */
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->OpenProtocol (HandleBuffer[Index],
+                    &gEfiI2cIoProtocolGuid,
+                    (VOID **)I2cIo,
+                    gImageHandle,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Unable to open protocol\n", __FUNCTION__));
+      gBS->FreePool (HandleBuffer);
+      return Status;
+    }
+    if ((*I2cIo)->DeviceIndex == I2C_DEVICE_INDEX (I2cBus, I2cAddress)) {
+      gBS->FreePool (HandleBuffer);
+      return EFI_SUCCESS;
+    }
+  }
+
+  gBS->FreePool (HandleBuffer);
+
+  return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+MvPca95xxI2cTransfer (
+  IN EFI_I2C_IO_PROTOCOL *I2cIo,
+  IN UINT8                Address,
+  IN UINT8               *Buffer,
+  IN UINT32               Flag
+  )
+{
+  EFI_I2C_REQUEST_PACKET *RequestPacket;
+  UINTN RequestPacketSize;
+  UINT8 AddressBuffer;
+  EFI_STATUS Status;
+
+  RequestPacketSize = sizeof (UINTN) +
+                      sizeof (EFI_I2C_OPERATION) * PCA95XX_OPERATION_COUNT;
+  RequestPacket = AllocateZeroPool (RequestPacketSize);
+  if (RequestPacket == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  /* Operations contain address and payload, consecutively. */
+  RequestPacket->OperationCount = PCA95XX_OPERATION_COUNT;
+  RequestPacket->Operation[0].LengthInBytes = PCA95XX_OPERATION_LENGTH;
+  RequestPacket->Operation[0].Buffer = &AddressBuffer;
+  RequestPacket->Operation[0].Buffer[0] = Address & MAX_UINT8;
+  RequestPacket->Operation[1].LengthInBytes = PCA95XX_OPERATION_LENGTH;
+  RequestPacket->Operation[1].Buffer = Buffer;
+  RequestPacket->Operation[1].Flags = Flag;
+
+  Status = I2cIo->QueueRequest (I2cIo, 0, NULL, RequestPacket, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: transmission error: 0x%d\n",
+      __FUNCTION__,
+      Status));
+  }
+
+  gBS->FreePool(RequestPacket);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+MvPca95xxReadRegs (
+  IN  EFI_I2C_IO_PROTOCOL *I2cIo,
+  IN  UINT8                Reg,
+  OUT UINT8               *RegVal
+  )
+{
+  return MvPca95xxI2cTransfer (I2cIo, Reg, RegVal, I2C_FLAG_READ);
+}
+
+STATIC
+EFI_STATUS
+MvPca95xxWriteRegs (
+  IN  EFI_I2C_IO_PROTOCOL *I2cIo,
+  IN  UINTN                Reg,
+  IN  UINT8                RegVal
+  )
+{
+  return MvPca95xxI2cTransfer (I2cIo, Reg, &RegVal, I2C_FLAG_NORESTART);
+}
+
+STATIC
+EFI_STATUS
+MvPca95xxSetOutputValue (
+  IN UINTN               ControllerIndex,
+  IN UINTN               GpioPin,
+  IN EMBEDDED_GPIO_MODE  Mode
+  )
+{
+  EFI_I2C_IO_PROTOCOL *I2cIo;
+  EFI_STATUS Status;
+  UINT8 RegVal;
+  UINTN Bank;
+
+  Status = MvPca95xxGetI2c (ControllerIndex, &I2cIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Bank = GpioPin / PCA95XX_BANK_SIZE;
+
+  Status = MvPca95xxReadRegs (I2cIo, PCA95XX_OUTPUT_REG + Bank, &RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to read device register\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Mode == GPIO_MODE_OUTPUT_1) {
+    RegVal |= (1 << (GpioPin % PCA95XX_BANK_SIZE));
+  } else {
+    RegVal &= ~(1 << (GpioPin % PCA95XX_BANK_SIZE));
+  }
+
+  Status = MvPca95xxWriteRegs (I2cIo, PCA95XX_OUTPUT_REG + Bank, RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to write device register\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvPca95xxSetDirection (
+  IN UINTN              ControllerIndex,
+  IN UINTN              GpioPin,
+  IN EMBEDDED_GPIO_MODE Mode
+  )
+{
+  EFI_I2C_IO_PROTOCOL *I2cIo;
+  EFI_STATUS Status;
+  UINT8 RegVal;
+  UINTN Bank;
+
+  Status = MvPca95xxGetI2c (ControllerIndex, &I2cIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__));
+    return Status;
+  }
+
+  Bank = GpioPin / PCA95XX_BANK_SIZE;
+
+  Status = MvPca95xxReadRegs (I2cIo, PCA95XX_DIRECTION_REG + Bank, &RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to read device register\n", __FUNCTION__));
+    return Status;
+  }
+
+  if (Mode == GPIO_MODE_INPUT) {
+    RegVal |= (1 << (GpioPin % PCA95XX_BANK_SIZE));
+  } else {
+    RegVal &= ~(1 << (GpioPin % PCA95XX_BANK_SIZE));
+  }
+
+  Status = MvPca95xxWriteRegs (I2cIo, PCA95XX_DIRECTION_REG + Bank, RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to write device register\n", __FUNCTION__));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvPca95xxReadMode (
+  IN  UINTN               ControllerIndex,
+  IN  UINTN               GpioPin,
+  OUT EMBEDDED_GPIO_MODE *Mode
+  )
+{
+  EFI_I2C_IO_PROTOCOL *I2cIo;
+  EFI_STATUS Status;
+  UINT8 RegVal;
+  UINTN Bank;
+
+  ASSERT_EFI_ERROR (MvPca95xxValidate (ControllerIndex, GpioPin));
+
+  Status = MvPca95xxGetI2c (ControllerIndex, &I2cIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__));
+    return Status;
+  }
+
+  Bank = GpioPin / PCA95XX_BANK_SIZE;
+
+  Status = MvPca95xxReadRegs (I2cIo, PCA95XX_DIRECTION_REG + Bank, &RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to read device register\n", __FUNCTION__));
+    return Status;
+  }
+
+  if (RegVal & (1 << (GpioPin % PCA95XX_BANK_SIZE))) {
+    *Mode = GPIO_MODE_INPUT;
+  } else {
+    Status = MvPca95xxReadRegs (I2cIo, PCA95XX_INPUT_REG + Bank, &RegVal);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: fail to read device register\n", __FUNCTION__));
+      return Status;
+    }
+
+    if (RegVal & (1 << (GpioPin % PCA95XX_BANK_SIZE))) {
+      *Mode = GPIO_MODE_OUTPUT_1;
+    } else {
+      *Mode = GPIO_MODE_OUTPUT_0;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+Routine Description:
+
+  Gets the mode (function) of a GPIO pin
+
+Arguments:
+
+  This  - pointer to protocol
+  Gpio  - which pin
+  Mode  - pointer to output mode value
+
+Returns:
+
+  EFI_SUCCESS           - mode value retrieved
+  EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
+
+**/
+STATIC
+EFI_STATUS
+MvPca95xxGetMode (
+  IN  EMBEDDED_GPIO       *This,
+  IN  EMBEDDED_GPIO_PIN    Gpio,
+  OUT EMBEDDED_GPIO_MODE  *Mode
+  )
+{
+  EFI_STATUS Status;
+  UINTN ControllerIndex;
+  UINTN GpioPin;
+
+  GpioPin = GPIO_PIN (Gpio);
+  ControllerIndex = GPIO_PORT (Gpio);
+
+  ASSERT_EFI_ERROR (MvPca95xxValidate (ControllerIndex, GpioPin));
+
+  Status = MvPca95xxReadMode (ControllerIndex, GpioPin, Mode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: fail to get pin %d of controller#%d mode\n",
+      __FUNCTION__,
+      GpioPin,
+      ControllerIndex));
+  }
+
+  return Status;
+}
+
+/**
+
+Routine Description:
+
+  Gets the state of a GPIO pin
+
+Arguments:
+
+  This  - pointer to protocol
+  Gpio  - which pin to read
+  Value - state of the pin
+
+Returns:
+
+  EFI_SUCCESS           - GPIO state returned in Value
+  EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
+**/
+STATIC
+EFI_STATUS
+MvPca95xxGet (
+  IN  EMBEDDED_GPIO      *This,
+  IN  EMBEDDED_GPIO_PIN   Gpio,
+  OUT UINTN              *Value
+  )
+{
+  EFI_I2C_IO_PROTOCOL *I2cIo;
+  EFI_STATUS Status;
+  UINTN ControllerIndex;
+  UINTN GpioPin;
+  UINT8 RegVal;
+  UINTN Bank;
+
+  GpioPin = GPIO_PIN (Gpio);
+  ControllerIndex = GPIO_PORT (Gpio);
+
+  ASSERT_EFI_ERROR (MvPca95xxValidate (ControllerIndex, GpioPin));
+
+  Status = MvPca95xxGetI2c (ControllerIndex, &I2cIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__));
+    return Status;
+  }
+
+  Bank = GpioPin / PCA95XX_BANK_SIZE;
+
+  Status = MvPca95xxReadRegs (I2cIo, PCA95XX_INPUT_REG + Bank, &RegVal);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: fail to read device register\n", __FUNCTION__));
+    return Status;
+  }
+
+  if (RegVal & (1 << (GpioPin % PCA95XX_BANK_SIZE))) {
+    *Value = 1;
+  } else {
+    *Value = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+Routine Description:
+
+  Sets the state of a GPIO pin
+
+Arguments:
+
+  This  - pointer to protocol
+  Gpio  - which pin to modify
+  Mode  - mode to set
+
+Returns:
+
+  EFI_SUCCESS           - GPIO set as requested
+  EFI_UNSUPPORTED       - Mode is not supported
+  EFI_INVALID_PARAMETER - Gpio pin is out of range
+**/
+STATIC
+EFI_STATUS
+MvPca95xxSet (
+  IN EMBEDDED_GPIO       *This,
+  IN EMBEDDED_GPIO_PIN   Gpio,
+  IN EMBEDDED_GPIO_MODE  Mode
+  )
+{
+  EFI_STATUS Status;
+  UINTN ControllerIndex;
+  UINTN GpioPin;
+
+  GpioPin = GPIO_PIN (Gpio);
+  ControllerIndex = GPIO_PORT (Gpio);
+
+  ASSERT_EFI_ERROR (MvPca95xxValidate (ControllerIndex, GpioPin));
+
+  switch (Mode) {
+  case GPIO_MODE_OUTPUT_0:
+  case GPIO_MODE_OUTPUT_1:
+    Status = MvPca95xxSetOutputValue (ControllerIndex, GpioPin, Mode);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: fail to set ouput value\n", __FUNCTION__));
+      return Status;
+    }
+
+  /* Fall-through */
+  case GPIO_MODE_INPUT:
+    Status = MvPca95xxSetDirection (ControllerIndex, GpioPin, Mode);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: fail to set direction\n", __FUNCTION__));
+      return Status;
+    }
+    break;
+
+  default:
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+Routine Description:
+
+  Sets the pull-up / pull-down resistor of a GPIO pin
+
+Arguments:
+
+  This  - pointer to protocol
+  Gpio  - which pin
+  Direction - pull-up, pull-down, or none
+
+Returns:
+
+  EFI_UNSUPPORTED - Can not perform the requested operation
+
+**/
+EFI_STATUS
+EFIAPI
+MvPca95xxSetPull (
+  IN EMBEDDED_GPIO       *This,
+  IN EMBEDDED_GPIO_PIN   Gpio,
+  IN EMBEDDED_GPIO_PULL  Direction
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+VOID
+MvPca95xxInitProtocol (
+  IN EMBEDDED_GPIO *GpioProtocol
+  )
+{
+  GpioProtocol->Get     = MvPca95xxGet;
+  GpioProtocol->Set     = MvPca95xxSet;
+  GpioProtocol->GetMode = MvPca95xxGetMode;
+  GpioProtocol->SetPull = MvPca95xxSetPull;
+}
+
+EFI_STATUS
+EFIAPI
+MvPca95xxEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  MARVELL_BOARD_DESC_PROTOCOL *MvBoardProtocol;
+  MV_BOARD_GPIO_DESCRIPTION *GpioDescription;
+  MV_GPIO_DEVICE_PATH *Pca95xxDevicePath;
+  EFI_STATUS Status;
+
+  /* Obtain list of available controllers */
+  Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid,
+                  NULL,
+                  (VOID **)&MvBoardProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot locate BoardDesc protocol\n",
+      __FUNCTION__));
+    return Status;
+  }
+
+  Status = MvBoardProtocol->GpioDescriptionGet (MvBoardProtocol,
+             &GpioDescription);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot get GPIO board desc from BoardDesc protocol\n",
+      __FUNCTION__));
+    return Status;
+  } else if (GpioDescription->GpioExpanders == NULL) {
+    /* Silently exit, if the board does not support the controllers */
+    return EFI_SUCCESS;
+  }
+
+  Pca95xxDevicePath = AllocateCopyPool (sizeof (MV_GPIO_DEVICE_PATH),
+                        &mDevicePathTemplate);
+  if (Pca95xxDevicePath == NULL) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Fail to allocate Pca95xxDevicePath\n",
+      __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mPca95xxInstance = AllocateZeroPool (sizeof (PCA95XX));
+  if (mPca95xxInstance == NULL) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Fail to allocate mPca95xxInstance\n",
+      __FUNCTION__));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrPca95xxInstanceAlloc;
+  }
+
+  MvPca95xxInitProtocol (&mPca95xxInstance->GpioProtocol);
+
+  mPca95xxInstance->Signature = PCA95XX_GPIO_SIGNATURE;
+  mPca95xxInstance->GpioExpanders = GpioDescription->GpioExpanders;
+  mPca95xxInstance->GpioExpanderCount = GpioDescription->GpioExpanderCount;
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &(mPca95xxInstance->ControllerHandle),
+                  &gEmbeddedGpioProtocolGuid,
+                  &(mPca95xxInstance->GpioProtocol),
+                  &gEfiDevicePathProtocolGuid,
+                  (EFI_DEVICE_PATH_PROTOCOL *)Pca95xxDevicePath,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    goto ErrInstallProtocols;
+  }
+
+  return EFI_SUCCESS;
+
+ErrInstallProtocols:
+  gBS->FreePool (mPca95xxInstance);
+
+ErrPca95xxInstanceAlloc:
+  gBS->FreePool (Pca95xxDevicePath);
+
+  return Status;
+}
-- 
2.7.4



  parent reply	other threads:[~2019-01-17 11:15 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-17 11:15 [platforms: PATCH v3 00/12] Armada 7k8k GPIO support Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 01/12] Marvell/Library: ArmadaSoCDescLib: Add GPIO information Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 02/12] Marvell/Library: ArmadaBoardDescLib: " Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 03/12] Marvell/Library: Introduce MvGpioLib class Marcin Wojtas
2019-01-17 11:33   ` Leif Lindholm
2019-01-17 12:19     ` Marcin Wojtas
2019-01-17 14:18       ` Leif Lindholm
2019-01-17 14:39         ` Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 04/12] SolidRun/Armada80x0McBin: Extend board description library with GPIO Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 05/12] Marvell/Armada70x0Db: " Marcin Wojtas
2019-01-17 11:34   ` Leif Lindholm
2019-01-17 11:15 ` [platforms: PATCH v3 06/12] Marvell/Armada80x0Db: " Marcin Wojtas
2019-01-17 11:34   ` Leif Lindholm
2019-01-17 11:15 ` [platforms: PATCH v3 07/12] Marvell/Drivers: MvBoardDesc: Extend protocol with GPIO support Marcin Wojtas
2019-01-17 11:50   ` Leif Lindholm
2019-01-17 11:15 ` [platforms: PATCH v3 08/12] Marvell/Drivers: MvGpioDxe: Introduce platform GPIO driver Marcin Wojtas
2019-01-17 11:52   ` Leif Lindholm
2019-01-17 11:15 ` [platforms: PATCH v3 09/12] Marvell/Drivers: I2c: Use common header for macros Marcin Wojtas
2019-01-17 11:15 ` Marcin Wojtas [this message]
2019-01-17 11:55   ` [platforms: PATCH v3 10/12] Marvell/Drivers: MvPca95xxDxe: Introduce GPIO expander driver Leif Lindholm
2019-01-17 11:15 ` [platforms: PATCH v3 11/12] Marvell/Armada7k8k: Enable GPIO drivers compilation Marcin Wojtas
2019-01-17 11:15 ` [platforms: PATCH v3 12/12] Marvell/Armada7k8k: Introduce NonDiscoverable device init routines Marcin Wojtas
2019-01-17 12:03 ` [platforms: PATCH v3 00/12] Armada 7k8k GPIO support Leif Lindholm
2019-01-17 12:26   ` Marcin Wojtas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1547723715-4562-11-git-send-email-mw@semihalf.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox