From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ed1-f42.google.com (mail-ed1-f42.google.com [209.85.208.42]) by mx.groups.io with SMTP id smtpd.web09.9535.1636631972256755271 for ; Thu, 11 Nov 2021 03:59:32 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20210112.gappssmtp.com header.s=20210112 header.b=Rf0aQTsr; spf=pass (domain: nuviainc.com, ip: 209.85.208.42, mailfrom: leif@nuviainc.com) Received: by mail-ed1-f42.google.com with SMTP id o8so23082022edc.3 for ; Thu, 11 Nov 2021 03:59:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2XWc9NzQG8qi078AxFPWloBz2X9ZW6dM+xrr7uRJJj8=; b=Rf0aQTsrAmojMvGVPuuQ7zjDmFFV4ATl8eL/g2ZoiavC+HTraQLaoSKS8Gt6YStOA4 4/+LEDgBNXKcWQK2TDUCJVbouVZFCjwe2Ur/wm/bOeptAL//enS1FH0Ya2dUAiyWQR2I aQspYTaRTAvcfqMDoyGZ91ISjUANT3LoxOPJYlrTHG6r9Ic78f4ehdtsOgSAjRC6neNY 6FDBE+AeGugFfx2zlGH66Bla0/13sv4wcT2LuBPHkowY58E0UxpS5v4PBFkCHoNb8uPQ WBffI0umZnIElyT3dXWilT2uh8QwL5vfLPOW3j4tMbizyO12lO7OCYZl7LzdrviZ3wH6 qvTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2XWc9NzQG8qi078AxFPWloBz2X9ZW6dM+xrr7uRJJj8=; b=CA8nd77aGEZO0N+wVbPCsf7QndxuFbTEn3egac23ovbcygEzo4IQggVwDgDLIpSFzG nlGHm+r/f0fL6AbsonulCq1Rn39i8YrfJNhynY0uUawXCLNIGoP7zb0ZVOx8ymg0N0fz Lzb4ODIfTSIBCU/qNPbMyOj9a1vCR5K+5KxQ3sfjNTXiCHu2+YM/yfj8nhFclWCDKvYP 9W3WuVHIcRO8jQEGuDSaHvI+yK4GcE8egHtI8vnEUSCsx+OWVSUuBeIWO3d8tT3ezOqM bMkTfI6mIPh8VgDdYX2lLd/kXXqINssydDZF/meFlspnED5beIBomtsQ4Qx21LSRDkPQ GpBQ== X-Gm-Message-State: AOAM532qDp+8gvxw95s9Ifp0JGMMjzWq3HkJxs8Ku7YkuLe5y6lytoDa LZHmAAcHB4YfXBc51p9vJNa88PNGaY/TSU+Jyy8fI4eqe8UW5ERauBC6censV2atDZf8SAF2cvO yk1bC+N0wXt3HMPiUNOntMNVjuvBt0MOxs67y9Dfw9tdbAyKAeAjojbwq4EYYyBRtr3dr X-Google-Smtp-Source: ABdhPJyUNgNZoYLW1cA4o2NgtnEbs3nUFcK5rQEwCxCEefzghpKax3gtN2HnbamAtKSoOXR5D62/ig== X-Received: by 2002:a05:6402:4396:: with SMTP id o22mr9085471edc.353.1636631969801; Thu, 11 Nov 2021 03:59:29 -0800 (PST) Return-Path: Received: from qc-i7.qualcomm.com (cpc92314-cmbg19-2-0-cust559.5-4.cable.virginm.net. [82.11.186.48]) by smtp.gmail.com with ESMTPSA id j21sm833442edp.21.2021.11.11.03.59.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Nov 2021 03:59:29 -0800 (PST) From: "Leif Lindholm" To: devel@edk2.groups.io Cc: Ard Biesheuvel , Masami Hiramatsu Subject: [PATCH edk2-platforms 2/2] Silicon/Socionext: fix line endings Date: Thu, 11 Nov 2021 11:59:26 +0000 Message-Id: <20211111115926.2317981-3-leif@nuviainc.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20211111115926.2317981-1-leif@nuviainc.com> References: <20211111115926.2317981-1-leif@nuviainc.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit SynQuacerI2cDxe.c (and no other Socionext source files) has LF instead of CRLF line endings, so fix that. Signed-off-by: Leif Lindholm Cc: Masami Hiramatsu --- Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c | 1162 ++++++++++---------- 1 file changed, 581 insertions(+), 581 deletions(-) diff --git a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c index 31f6e3072f4d..8aa979901837 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c +++ b/Silicon/Socionext/SynQuacer/Drivers/SynQuacerI2cDxe/SynQuacerI2cDxe.c @@ -1,581 +1,581 @@ -/** @file - - Copyright (c) 2017, Linaro, Ltd. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include "SynQuacerI2cDxe.h" - -// -// We cannot use Stall () or timer events at runtime, so we need to busy-wait -// for the controller to signal the completion interrupts. This value was -// arbitrarily chosen, and does not appear to produce any premature timeouts -// nor does it result in noticeable stalls in case of bus errors. -// -#define WAIT_FOR_INTERRUPT_TIMEOUT 50000 - -/** - Set the frequency for the I2C clock line. - - This routine must be called at or below TPL_NOTIFY. - - The software and controller do a best case effort of using the specified - frequency for the I2C bus. If the frequency does not match exactly then - the I2C master protocol selects the next lower frequency to avoid - exceeding the operating conditions for any of the I2C devices on the bus. - For example if 400 KHz was specified and the controller's divide network - only supports 402 KHz or 398 KHz then the I2C master protocol selects 398 - KHz. If there are not lower frequencies available, then return - EFI_UNSUPPORTED. - - @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure - @param[in] BusClockHertz Pointer to the requested I2C bus clock frequency - in Hertz. Upon return this value contains the - actual frequency in use by the I2C controller. - - @retval EFI_SUCCESS The bus frequency was set successfully. - @retval EFI_ALREADY_STARTED The controller is busy with another transaction. - @retval EFI_INVALID_PARAMETER BusClockHertz is NULL - @retval EFI_UNSUPPORTED The controller does not support this frequency. - -**/ -STATIC -EFI_STATUS -EFIAPI -SynQuacerI2cSetBusFrequency ( - IN CONST EFI_I2C_MASTER_PROTOCOL *This, - IN OUT UINTN *BusClockHertz - ) -{ - SYNQUACER_I2C_MASTER *I2c; - UINT8 Ccr, Csr; - - I2c = SYNQUACER_I2C_FROM_THIS (This); - - if (BusClockHertz == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (*BusClockHertz >= F_I2C_SPEED_FM) { - if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { - Ccr = F_I2C_CCR_CS_FAST_MAX_18M (REFCLK_RATE); - Csr = F_I2C_CSR_CS_FAST_MAX_18M (REFCLK_RATE); - } else { - Ccr = F_I2C_CCR_CS_FAST_MIN_18M (REFCLK_RATE); - Csr = F_I2C_CSR_CS_FAST_MIN_18M (REFCLK_RATE); - } - - // Set Clock and enable, Set fast mode - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, - Ccr | F_I2C_CCR_FM | F_I2C_CCR_EN); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); - - *BusClockHertz = F_I2C_SPEED_FM; - - } else if (*BusClockHertz >= F_I2C_SPEED_SM) { - if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { - Ccr = F_I2C_CCR_CS_STANDARD_MAX_18M (REFCLK_RATE); - Csr = F_I2C_CSR_CS_STANDARD_MAX_18M (REFCLK_RATE); - } else { - Ccr = F_I2C_CCR_CS_STANDARD_MIN_18M (REFCLK_RATE); - Csr = F_I2C_CSR_CS_STANDARD_MIN_18M (REFCLK_RATE); - } - - // Set Clock and enable, Set standard mode - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, Ccr | F_I2C_CCR_EN); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); - - *BusClockHertz = F_I2C_SPEED_SM; - } else { - return EFI_UNSUPPORTED; - } - - MemoryFence (); - - return EFI_SUCCESS; -} - -/** - Reset the I2C controller and configure it for use - - This routine must be called at or below TPL_NOTIFY. - - The I2C controller is reset. The caller must call SetBusFrequench() after - calling Reset(). - - @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. - - @retval EFI_SUCCESS The reset completed successfully. - @retval EFI_ALREADY_STARTED The controller is busy with another transaction. - @retval EFI_DEVICE_ERROR The reset operation failed. - -**/ -STATIC -EFI_STATUS -EFIAPI -SynQuacerI2cReset ( - IN CONST EFI_I2C_MASTER_PROTOCOL *This - ) -{ - SYNQUACER_I2C_MASTER *I2c; - - I2c = SYNQUACER_I2C_FROM_THIS (This); - - // Disable the clock - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, 0); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, 0); - - MemoryFence (); - - // Set own Address - MmioWrite8 (I2c->MmioBase + F_I2C_REG_ADR, 0); - - // Set PCLK frequency - MmioWrite8 (I2c->MmioBase + F_I2C_REG_FSR, F_I2C_BUS_CLK_FR (REFCLK_RATE)); - - // clear IRQ (INT=0, BER=0), Interrupt Disable - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BC2R, 0); - - MemoryFence (); - - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -SynQuacerI2cMasterStart ( - IN SYNQUACER_I2C_MASTER *I2c, - IN UINTN SlaveAddress, - IN EFI_I2C_OPERATION *Op - ) -{ - UINT8 Bsr; - UINT8 Bcr; - - if (Op->Flags & I2C_FLAG_READ) { - MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, (SlaveAddress << 1) | 1); - } else { - MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, SlaveAddress << 1); - } - - DEBUG ((DEBUG_INFO, "%a: slave:0x%02x\n", __FUNCTION__, - SlaveAddress)); - - Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); - Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); - - if ((Bsr & F_I2C_BSR_BB) && !(Bcr & F_I2C_BCR_MSS)) { - DEBUG ((DEBUG_INFO, "%a: bus is busy\n", __FUNCTION__)); - return EFI_ALREADY_STARTED; - } - - if (Bsr & F_I2C_BSR_BB) { // Bus is busy - DEBUG ((DEBUG_INFO, "%a: Continuous Start\n", __FUNCTION__)); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, Bcr | F_I2C_BCR_SCC); - } else { - if (Bcr & F_I2C_BCR_MSS) { - DEBUG ((DEBUG_WARN, - "%a: is not in master mode\n", __FUNCTION__)); - return EFI_DEVICE_ERROR; - } - DEBUG ((DEBUG_INFO, "%a: Start Condition\n", __FUNCTION__)); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, - Bcr | F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); - } - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -WaitForInterrupt ( - IN SYNQUACER_I2C_MASTER *I2c - ) -{ - UINT8 Bsr; - UINTN Timeout = WAIT_FOR_INTERRUPT_TIMEOUT; - - do { - MemoryFence (); - - Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); - if (Bsr & F_I2C_BCR_INT) { - return EFI_SUCCESS; - } - } while (Timeout--); - - return EFI_DEVICE_ERROR; -} - -/** - Start an I2C transaction on the host controller. - - This routine must be called at or below TPL_NOTIFY. For synchronous - requests this routine must be called at or below TPL_CALLBACK. - - This function initiates an I2C transaction on the controller. To - enable proper error handling by the I2C protocol stack, the I2C - master protocol does not support queuing but instead only manages - one I2C transaction at a time. This API requires that the I2C bus - is in the correct configuration for the I2C transaction. - - The transaction is performed by sending a start-bit and selecting the - I2C device with the specified I2C slave address and then performing - the specified I2C operations. When multiple operations are requested - they are separated with a repeated start bit and the slave address. - The transaction is terminated with a stop bit. - - When Event is NULL, StartRequest operates synchronously and returns - the I2C completion status as its return value. - - When Event is not NULL, StartRequest synchronously returns EFI_SUCCESS - indicating that the I2C transaction was started asynchronously. The - transaction status value is returned in the buffer pointed to by - I2cStatus upon the completion of the I2C transaction when I2cStatus - is not NULL. After the transaction status is returned the Event is - signaled. - - Note: The typical consumer of this API is the I2C host protocol. - Extreme care must be taken by other consumers of this API to prevent - confusing the third party I2C drivers due to a state change at the - I2C device which the third party I2C drivers did not initiate. I2C - platform specific code may use this API within these guidelines. - - @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. - @param[in] SlaveAddress Address of the device on the I2C bus. Set the - I2C_ADDRESSING_10_BIT when using 10-bit addresses, - clear this bit for 7-bit addressing. Bits 0-6 - are used for 7-bit I2C slave addresses and bits - 0-9 are used for 10-bit I2C slave addresses. - @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET - structure describing the I2C transaction. - @param[in] Event Event to signal for asynchronous transactions, - NULL for synchronous transactions - @param[out] I2cStatus Optional buffer to receive the I2C transaction - completion status - - @retval EFI_SUCCESS The asynchronous transaction was successfully - started when Event is not NULL. - @retval EFI_SUCCESS The transaction completed successfully when - Event is NULL. - @retval EFI_ALREADY_STARTED The controller is busy with another transaction. - @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too - large. - @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the - transaction. - @retval EFI_INVALID_PARAMETER RequestPacket is NULL - @retval EFI_NOT_FOUND Reserved bit set in the SlaveAddress parameter - @retval EFI_NO_RESPONSE The I2C device is not responding to the slave - address. EFI_DEVICE_ERROR will be returned if - the controller cannot distinguish when the NACK - occurred. - @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction - @retval EFI_UNSUPPORTED The controller does not support the requested - transaction. - -**/ -STATIC -EFI_STATUS -EFIAPI -SynQuacerI2cStartRequest ( - IN CONST EFI_I2C_MASTER_PROTOCOL *This, - IN UINTN SlaveAddress, - IN EFI_I2C_REQUEST_PACKET *RequestPacket, - IN EFI_EVENT Event OPTIONAL, - OUT EFI_STATUS *I2cStatus OPTIONAL - ) -{ - SYNQUACER_I2C_MASTER *I2c; - UINTN Idx; - EFI_I2C_OPERATION *Op; - UINTN BufIdx; - EFI_STATUS Status; - EFI_TPL Tpl; - BOOLEAN AtRuntime; - UINT8 Bsr; - UINT8 Bcr; - - I2c = SYNQUACER_I2C_FROM_THIS (This); - - // - // We can only do synchronous operations at runtime - // - AtRuntime = EfiAtRuntime (); - if (AtRuntime && Event != NULL) { - return EFI_UNSUPPORTED; - } - - if (!AtRuntime) { - Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); - } - - for (Idx = 0, Op = RequestPacket->Operation, Status = EFI_SUCCESS; - Idx < RequestPacket->OperationCount && !EFI_ERROR (Status); - Idx++, Op++) { - - Status = SynQuacerI2cMasterStart (I2c, SlaveAddress, Op); - if (EFI_ERROR (Status)) { - break; - } - - Status = WaitForInterrupt (I2c); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "%a: Timeout waiting for interrupt - %r\n", - __FUNCTION__, Status)); - break; - } - - if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { - DEBUG ((DEBUG_WARN, "%a: No ack received\n", __FUNCTION__)); - Status = EFI_DEVICE_ERROR; - break; - } - - BufIdx = 0; - do { - Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); - Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); - - if (Bcr & F_I2C_BCR_BER) { - DEBUG ((DEBUG_WARN, "%a: Bus error detected\n", __FUNCTION__)); - Status = EFI_DEVICE_ERROR; - break; - } - - if ((Bsr & F_I2C_BSR_AL) || !(Bcr & F_I2C_BCR_MSS)) { - DEBUG ((DEBUG_WARN, "%a: Arbitration lost\n", __FUNCTION__)); - Status = EFI_DEVICE_ERROR; - break; - } - - if (Op->Flags & I2C_FLAG_READ) { - if (BufIdx == Op->LengthInBytes - 1) { - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, - F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); - } else { - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, - F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE | F_I2C_BCR_ACK); - } - - Status = WaitForInterrupt (I2c); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, - "%a: Timeout waiting for interrupt - %r\n", __FUNCTION__, Status)); - break; - } - - if (!(MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_FBT)) { - Op->Buffer [BufIdx++] = MmioRead8 (I2c->MmioBase + F_I2C_REG_DAR); - } - } else { - MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, Op->Buffer [BufIdx++]); - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, - F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); - - Status = WaitForInterrupt (I2c); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, - "%a: Timeout waiting for interrupt - %r\n", __FUNCTION__, Status)); - break; - } - - if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { - DEBUG ((DEBUG_WARN, "%a: No ack received\n", __FUNCTION__)); - Status = EFI_DEVICE_ERROR; - break; - } - } - } while (BufIdx < Op->LengthInBytes); - } - - // Force bus state to idle, terminating any ongoing transfer - MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); - - if (!AtRuntime) { - gBS->RestoreTPL (Tpl); - } - - if (Event) { - *I2cStatus = Status; - gBS->SignalEvent (Event); - } - return Status; -} - -STATIC CONST EFI_I2C_CONTROLLER_CAPABILITIES mI2cControllerCapabilities = { - sizeof (EFI_I2C_CONTROLLER_CAPABILITIES), // StructureSizeInBytes - MAX_UINT32, // MaximumReceiveBytes - MAX_UINT32, // MaximumTransmitBytes - MAX_UINT32, // MaximumTotalBytes -}; - -STATIC -VOID -EFIAPI -SynQuacerI2cVirtualNotifyEvent ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - SYNQUACER_I2C_MASTER *I2c = Context; - - EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.SetBusFrequency); - EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.Reset); - EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.StartRequest); - EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.I2cControllerCapabilities); - EfiConvertPointer (0x0, (VOID **)&I2c->MmioBase); -} - -EFI_STATUS -SynQuacerI2cInit ( - IN EFI_HANDLE DriverBindingHandle, - IN EFI_HANDLE ControllerHandle - ) -{ - EFI_STATUS Status; - NON_DISCOVERABLE_DEVICE *Dev; - SYNQUACER_I2C_MASTER *I2c; - BOOLEAN Runtime; - - Status = gBS->OpenProtocol (ControllerHandle, - &gEdkiiNonDiscoverableDeviceProtocolGuid, - (VOID **)&Dev, DriverBindingHandle, - ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); - if (EFI_ERROR (Status)) { - return Status; - } - - Runtime = CompareGuid (Dev->Type, - &gSynQuacerNonDiscoverableRuntimeI2cMasterGuid); - - // Allocate Resources - if (Runtime) { - I2c = AllocateRuntimeZeroPool (sizeof (SYNQUACER_I2C_MASTER)); - } else { - I2c = AllocateZeroPool (sizeof (SYNQUACER_I2C_MASTER)); - } - if (I2c == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto CloseProtocol; - } - - I2c->Signature = SYNQUACER_I2C_SIGNATURE; - I2c->I2cMaster.SetBusFrequency = SynQuacerI2cSetBusFrequency; - I2c->I2cMaster.Reset = SynQuacerI2cReset; - I2c->I2cMaster.StartRequest = SynQuacerI2cStartRequest; - I2c->I2cMaster.I2cControllerCapabilities = &mI2cControllerCapabilities; - I2c->MmioBase = Dev->Resources[0].AddrRangeMin; - I2c->Dev = Dev; - - if (Runtime) { - I2c->Runtime = TRUE; - - // Declare the controller as EFI_MEMORY_RUNTIME - Status = gDS->AddMemorySpace ( - EfiGcdMemoryTypeMemoryMappedIo, - Dev->Resources[0].AddrRangeMin, - Dev->Resources[0].AddrLen, - EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "%a: failed to add memory space - %r\n", - __FUNCTION__, Status)); - } - - Status = gDS->SetMemorySpaceAttributes ( - Dev->Resources[0].AddrRangeMin, - Dev->Resources[0].AddrLen, - EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); - if (EFI_ERROR (Status)) { - goto FreeDevice; - } - - // - // Register for the virtual address change event - // - Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, - SynQuacerI2cVirtualNotifyEvent, I2c, - &gEfiEventVirtualAddressChangeGuid, - &I2c->VirtualAddressChangeEvent); - if (EFI_ERROR (Status)) { - goto FreeDevice; - } - } - - CopyGuid (&I2c->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); - I2c->DevicePath.MmioBase = I2c->MmioBase; - SetDevicePathNodeLength (&I2c->DevicePath.Vendor, - sizeof (I2c->DevicePath) - sizeof (I2c->DevicePath.End)); - SetDevicePathEndNode (&I2c->DevicePath.End); - - Status = gBS->InstallMultipleProtocolInterfaces (&ControllerHandle, - &gEfiI2cMasterProtocolGuid, &I2c->I2cMaster, - &gEfiDevicePathProtocolGuid, &I2c->DevicePath, - NULL); - if (EFI_ERROR (Status)) { - goto CloseEvent; - } - return EFI_SUCCESS; - -CloseEvent: - if (Runtime) { - gBS->CloseEvent (I2c->VirtualAddressChangeEvent); - } - -FreeDevice: - FreePool (I2c); - -CloseProtocol: - gBS->CloseProtocol (ControllerHandle, - &gEdkiiNonDiscoverableDeviceProtocolGuid, - DriverBindingHandle, - ControllerHandle); - return Status; -} - -EFI_STATUS -SynQuacerI2cRelease ( - IN EFI_HANDLE DriverBindingHandle, - IN EFI_HANDLE ControllerHandle - ) -{ - EFI_I2C_MASTER_PROTOCOL *I2cMaster; - SYNQUACER_I2C_MASTER *I2c; - EFI_STATUS Status; - - Status = gBS->HandleProtocol (ControllerHandle, - &gEfiI2cMasterProtocolGuid, - (VOID **)&I2cMaster); - ASSERT_EFI_ERROR (Status); - if (EFI_ERROR (Status)) { - return Status; - } - - I2c = SYNQUACER_I2C_FROM_THIS (I2cMaster); - - Status = gBS->UninstallMultipleProtocolInterfaces (ControllerHandle, - &gEfiI2cMasterProtocolGuid, I2cMaster, - &gEfiDevicePathProtocolGuid, &I2c->DevicePath, - NULL); - if (EFI_ERROR (Status)) { - return Status; - } - - if (I2c->Runtime) { - gBS->CloseEvent (I2c->VirtualAddressChangeEvent); - } - - Status = gBS->CloseProtocol (ControllerHandle, - &gEdkiiNonDiscoverableDeviceProtocolGuid, - DriverBindingHandle, - ControllerHandle); - ASSERT_EFI_ERROR (Status); - if (EFI_ERROR (Status)) { - return Status; - } - - gBS->FreePool (I2c); - - return EFI_SUCCESS; -} +/** @file + + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SynQuacerI2cDxe.h" + +// +// We cannot use Stall () or timer events at runtime, so we need to busy-wait +// for the controller to signal the completion interrupts. This value was +// arbitrarily chosen, and does not appear to produce any premature timeouts +// nor does it result in noticeable stalls in case of bus errors. +// +#define WAIT_FOR_INTERRUPT_TIMEOUT 50000 + +/** + Set the frequency for the I2C clock line. + + This routine must be called at or below TPL_NOTIFY. + + The software and controller do a best case effort of using the specified + frequency for the I2C bus. If the frequency does not match exactly then + the I2C master protocol selects the next lower frequency to avoid + exceeding the operating conditions for any of the I2C devices on the bus. + For example if 400 KHz was specified and the controller's divide network + only supports 402 KHz or 398 KHz then the I2C master protocol selects 398 + KHz. If there are not lower frequencies available, then return + EFI_UNSUPPORTED. + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure + @param[in] BusClockHertz Pointer to the requested I2C bus clock frequency + in Hertz. Upon return this value contains the + actual frequency in use by the I2C controller. + + @retval EFI_SUCCESS The bus frequency was set successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_INVALID_PARAMETER BusClockHertz is NULL + @retval EFI_UNSUPPORTED The controller does not support this frequency. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cSetBusFrequency ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN OUT UINTN *BusClockHertz + ) +{ + SYNQUACER_I2C_MASTER *I2c; + UINT8 Ccr, Csr; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + if (BusClockHertz == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*BusClockHertz >= F_I2C_SPEED_FM) { + if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { + Ccr = F_I2C_CCR_CS_FAST_MAX_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_FAST_MAX_18M (REFCLK_RATE); + } else { + Ccr = F_I2C_CCR_CS_FAST_MIN_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_FAST_MIN_18M (REFCLK_RATE); + } + + // Set Clock and enable, Set fast mode + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, + Ccr | F_I2C_CCR_FM | F_I2C_CCR_EN); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); + + *BusClockHertz = F_I2C_SPEED_FM; + + } else if (*BusClockHertz >= F_I2C_SPEED_SM) { + if (REFCLK_RATE <= F_I2C_CLK_RATE_18M) { + Ccr = F_I2C_CCR_CS_STANDARD_MAX_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_STANDARD_MAX_18M (REFCLK_RATE); + } else { + Ccr = F_I2C_CCR_CS_STANDARD_MIN_18M (REFCLK_RATE); + Csr = F_I2C_CSR_CS_STANDARD_MIN_18M (REFCLK_RATE); + } + + // Set Clock and enable, Set standard mode + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, Ccr | F_I2C_CCR_EN); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, Csr); + + *BusClockHertz = F_I2C_SPEED_SM; + } else { + return EFI_UNSUPPORTED; + } + + MemoryFence (); + + return EFI_SUCCESS; +} + +/** + Reset the I2C controller and configure it for use + + This routine must be called at or below TPL_NOTIFY. + + The I2C controller is reset. The caller must call SetBusFrequench() after + calling Reset(). + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. + + @retval EFI_SUCCESS The reset completed successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_DEVICE_ERROR The reset operation failed. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ) +{ + SYNQUACER_I2C_MASTER *I2c; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + // Disable the clock + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CCR, 0); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_CSR, 0); + + MemoryFence (); + + // Set own Address + MmioWrite8 (I2c->MmioBase + F_I2C_REG_ADR, 0); + + // Set PCLK frequency + MmioWrite8 (I2c->MmioBase + F_I2C_REG_FSR, F_I2C_BUS_CLK_FR (REFCLK_RATE)); + + // clear IRQ (INT=0, BER=0), Interrupt Disable + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BC2R, 0); + + MemoryFence (); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SynQuacerI2cMasterStart ( + IN SYNQUACER_I2C_MASTER *I2c, + IN UINTN SlaveAddress, + IN EFI_I2C_OPERATION *Op + ) +{ + UINT8 Bsr; + UINT8 Bcr; + + if (Op->Flags & I2C_FLAG_READ) { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, (SlaveAddress << 1) | 1); + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, SlaveAddress << 1); + } + + DEBUG ((DEBUG_INFO, "%a: slave:0x%02x\n", __FUNCTION__, + SlaveAddress)); + + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); + Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + + if ((Bsr & F_I2C_BSR_BB) && !(Bcr & F_I2C_BCR_MSS)) { + DEBUG ((DEBUG_INFO, "%a: bus is busy\n", __FUNCTION__)); + return EFI_ALREADY_STARTED; + } + + if (Bsr & F_I2C_BSR_BB) { // Bus is busy + DEBUG ((DEBUG_INFO, "%a: Continuous Start\n", __FUNCTION__)); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, Bcr | F_I2C_BCR_SCC); + } else { + if (Bcr & F_I2C_BCR_MSS) { + DEBUG ((DEBUG_WARN, + "%a: is not in master mode\n", __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + DEBUG ((DEBUG_INFO, "%a: Start Condition\n", __FUNCTION__)); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + Bcr | F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +WaitForInterrupt ( + IN SYNQUACER_I2C_MASTER *I2c + ) +{ + UINT8 Bsr; + UINTN Timeout = WAIT_FOR_INTERRUPT_TIMEOUT; + + do { + MemoryFence (); + + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + if (Bsr & F_I2C_BCR_INT) { + return EFI_SUCCESS; + } + } while (Timeout--); + + return EFI_DEVICE_ERROR; +} + +/** + Start an I2C transaction on the host controller. + + This routine must be called at or below TPL_NOTIFY. For synchronous + requests this routine must be called at or below TPL_CALLBACK. + + This function initiates an I2C transaction on the controller. To + enable proper error handling by the I2C protocol stack, the I2C + master protocol does not support queuing but instead only manages + one I2C transaction at a time. This API requires that the I2C bus + is in the correct configuration for the I2C transaction. + + The transaction is performed by sending a start-bit and selecting the + I2C device with the specified I2C slave address and then performing + the specified I2C operations. When multiple operations are requested + they are separated with a repeated start bit and the slave address. + The transaction is terminated with a stop bit. + + When Event is NULL, StartRequest operates synchronously and returns + the I2C completion status as its return value. + + When Event is not NULL, StartRequest synchronously returns EFI_SUCCESS + indicating that the I2C transaction was started asynchronously. The + transaction status value is returned in the buffer pointed to by + I2cStatus upon the completion of the I2C transaction when I2cStatus + is not NULL. After the transaction status is returned the Event is + signaled. + + Note: The typical consumer of this API is the I2C host protocol. + Extreme care must be taken by other consumers of this API to prevent + confusing the third party I2C drivers due to a state change at the + I2C device which the third party I2C drivers did not initiate. I2C + platform specific code may use this API within these guidelines. + + @param[in] This Pointer to an EFI_I2C_MASTER_PROTOCOL structure. + @param[in] SlaveAddress Address of the device on the I2C bus. Set the + I2C_ADDRESSING_10_BIT when using 10-bit addresses, + clear this bit for 7-bit addressing. Bits 0-6 + are used for 7-bit I2C slave addresses and bits + 0-9 are used for 10-bit I2C slave addresses. + @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET + structure describing the I2C transaction. + @param[in] Event Event to signal for asynchronous transactions, + NULL for synchronous transactions + @param[out] I2cStatus Optional buffer to receive the I2C transaction + completion status + + @retval EFI_SUCCESS The asynchronous transaction was successfully + started when Event is not NULL. + @retval EFI_SUCCESS The transaction completed successfully when + Event is NULL. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too + large. + @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the + transaction. + @retval EFI_INVALID_PARAMETER RequestPacket is NULL + @retval EFI_NOT_FOUND Reserved bit set in the SlaveAddress parameter + @retval EFI_NO_RESPONSE The I2C device is not responding to the slave + address. EFI_DEVICE_ERROR will be returned if + the controller cannot distinguish when the NACK + occurred. + @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction + @retval EFI_UNSUPPORTED The controller does not support the requested + transaction. + +**/ +STATIC +EFI_STATUS +EFIAPI +SynQuacerI2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ) +{ + SYNQUACER_I2C_MASTER *I2c; + UINTN Idx; + EFI_I2C_OPERATION *Op; + UINTN BufIdx; + EFI_STATUS Status; + EFI_TPL Tpl; + BOOLEAN AtRuntime; + UINT8 Bsr; + UINT8 Bcr; + + I2c = SYNQUACER_I2C_FROM_THIS (This); + + // + // We can only do synchronous operations at runtime + // + AtRuntime = EfiAtRuntime (); + if (AtRuntime && Event != NULL) { + return EFI_UNSUPPORTED; + } + + if (!AtRuntime) { + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + } + + for (Idx = 0, Op = RequestPacket->Operation, Status = EFI_SUCCESS; + Idx < RequestPacket->OperationCount && !EFI_ERROR (Status); + Idx++, Op++) { + + Status = SynQuacerI2cMasterStart (I2c, SlaveAddress, Op); + if (EFI_ERROR (Status)) { + break; + } + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: Timeout waiting for interrupt - %r\n", + __FUNCTION__, Status)); + break; + } + + if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { + DEBUG ((DEBUG_WARN, "%a: No ack received\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + BufIdx = 0; + do { + Bsr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR); + Bcr = MmioRead8 (I2c->MmioBase + F_I2C_REG_BCR); + + if (Bcr & F_I2C_BCR_BER) { + DEBUG ((DEBUG_WARN, "%a: Bus error detected\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + if ((Bsr & F_I2C_BSR_AL) || !(Bcr & F_I2C_BCR_MSS)) { + DEBUG ((DEBUG_WARN, "%a: Arbitration lost\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + + if (Op->Flags & I2C_FLAG_READ) { + if (BufIdx == Op->LengthInBytes - 1) { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE | F_I2C_BCR_ACK); + } + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, + "%a: Timeout waiting for interrupt - %r\n", __FUNCTION__, Status)); + break; + } + + if (!(MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_FBT)) { + Op->Buffer [BufIdx++] = MmioRead8 (I2c->MmioBase + F_I2C_REG_DAR); + } + } else { + MmioWrite8 (I2c->MmioBase + F_I2C_REG_DAR, Op->Buffer [BufIdx++]); + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, + F_I2C_BCR_MSS | F_I2C_BCR_INTE | F_I2C_BCR_BEIE); + + Status = WaitForInterrupt (I2c); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, + "%a: Timeout waiting for interrupt - %r\n", __FUNCTION__, Status)); + break; + } + + if (MmioRead8 (I2c->MmioBase + F_I2C_REG_BSR) & F_I2C_BSR_LRB) { + DEBUG ((DEBUG_WARN, "%a: No ack received\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + break; + } + } + } while (BufIdx < Op->LengthInBytes); + } + + // Force bus state to idle, terminating any ongoing transfer + MmioWrite8 (I2c->MmioBase + F_I2C_REG_BCR, 0); + + if (!AtRuntime) { + gBS->RestoreTPL (Tpl); + } + + if (Event) { + *I2cStatus = Status; + gBS->SignalEvent (Event); + } + return Status; +} + +STATIC CONST EFI_I2C_CONTROLLER_CAPABILITIES mI2cControllerCapabilities = { + sizeof (EFI_I2C_CONTROLLER_CAPABILITIES), // StructureSizeInBytes + MAX_UINT32, // MaximumReceiveBytes + MAX_UINT32, // MaximumTransmitBytes + MAX_UINT32, // MaximumTotalBytes +}; + +STATIC +VOID +EFIAPI +SynQuacerI2cVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + SYNQUACER_I2C_MASTER *I2c = Context; + + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.SetBusFrequency); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.Reset); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.StartRequest); + EfiConvertPointer (0x0, (VOID **)&I2c->I2cMaster.I2cControllerCapabilities); + EfiConvertPointer (0x0, (VOID **)&I2c->MmioBase); +} + +EFI_STATUS +SynQuacerI2cInit ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + NON_DISCOVERABLE_DEVICE *Dev; + SYNQUACER_I2C_MASTER *I2c; + BOOLEAN Runtime; + + Status = gBS->OpenProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **)&Dev, DriverBindingHandle, + ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + return Status; + } + + Runtime = CompareGuid (Dev->Type, + &gSynQuacerNonDiscoverableRuntimeI2cMasterGuid); + + // Allocate Resources + if (Runtime) { + I2c = AllocateRuntimeZeroPool (sizeof (SYNQUACER_I2C_MASTER)); + } else { + I2c = AllocateZeroPool (sizeof (SYNQUACER_I2C_MASTER)); + } + if (I2c == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto CloseProtocol; + } + + I2c->Signature = SYNQUACER_I2C_SIGNATURE; + I2c->I2cMaster.SetBusFrequency = SynQuacerI2cSetBusFrequency; + I2c->I2cMaster.Reset = SynQuacerI2cReset; + I2c->I2cMaster.StartRequest = SynQuacerI2cStartRequest; + I2c->I2cMaster.I2cControllerCapabilities = &mI2cControllerCapabilities; + I2c->MmioBase = Dev->Resources[0].AddrRangeMin; + I2c->Dev = Dev; + + if (Runtime) { + I2c->Runtime = TRUE; + + // Declare the controller as EFI_MEMORY_RUNTIME + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + Dev->Resources[0].AddrRangeMin, + Dev->Resources[0].AddrLen, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to add memory space - %r\n", + __FUNCTION__, Status)); + } + + Status = gDS->SetMemorySpaceAttributes ( + Dev->Resources[0].AddrRangeMin, + Dev->Resources[0].AddrLen, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + goto FreeDevice; + } + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, + SynQuacerI2cVirtualNotifyEvent, I2c, + &gEfiEventVirtualAddressChangeGuid, + &I2c->VirtualAddressChangeEvent); + if (EFI_ERROR (Status)) { + goto FreeDevice; + } + } + + CopyGuid (&I2c->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); + I2c->DevicePath.MmioBase = I2c->MmioBase; + SetDevicePathNodeLength (&I2c->DevicePath.Vendor, + sizeof (I2c->DevicePath) - sizeof (I2c->DevicePath.End)); + SetDevicePathEndNode (&I2c->DevicePath.End); + + Status = gBS->InstallMultipleProtocolInterfaces (&ControllerHandle, + &gEfiI2cMasterProtocolGuid, &I2c->I2cMaster, + &gEfiDevicePathProtocolGuid, &I2c->DevicePath, + NULL); + if (EFI_ERROR (Status)) { + goto CloseEvent; + } + return EFI_SUCCESS; + +CloseEvent: + if (Runtime) { + gBS->CloseEvent (I2c->VirtualAddressChangeEvent); + } + +FreeDevice: + FreePool (I2c); + +CloseProtocol: + gBS->CloseProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + DriverBindingHandle, + ControllerHandle); + return Status; +} + +EFI_STATUS +SynQuacerI2cRelease ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_I2C_MASTER_PROTOCOL *I2cMaster; + SYNQUACER_I2C_MASTER *I2c; + EFI_STATUS Status; + + Status = gBS->HandleProtocol (ControllerHandle, + &gEfiI2cMasterProtocolGuid, + (VOID **)&I2cMaster); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + I2c = SYNQUACER_I2C_FROM_THIS (I2cMaster); + + Status = gBS->UninstallMultipleProtocolInterfaces (ControllerHandle, + &gEfiI2cMasterProtocolGuid, I2cMaster, + &gEfiDevicePathProtocolGuid, &I2c->DevicePath, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + if (I2c->Runtime) { + gBS->CloseEvent (I2c->VirtualAddressChangeEvent); + } + + Status = gBS->CloseProtocol (ControllerHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + DriverBindingHandle, + ControllerHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->FreePool (I2c); + + return EFI_SUCCESS; +} -- 2.30.2