From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.42.129; helo=nam03-by2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM03-BY2-obe.outbound.protection.outlook.com (mail-by2nam03on0129.outbound.protection.outlook.com [104.47.42.129]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7952B211518E0 for ; Fri, 21 Sep 2018 01:25:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=LaMfVoB5k+zh6VWjV+rwBh+5SMPEucX9NGVCLRzCFVc=; b=BriXq3q3SyHheqfpY3ypYdSWTk4+xbldBlns5bMCyJZHwg8twVii1E7ya4ud9V/h0LsBXPcNWdUqgx76RZLnc9EuRVhfQroivLKYYgm9ikwM/ZA5cRGJ0Wf+0Q15OGlkmlPREFNOyzfxhcxUquDO7wLNatBKLCFfkayRBYF/sLM= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB1112.namprd21.prod.outlook.com (52.132.133.139) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1185.5; Fri, 21 Sep 2018 08:25:57 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49%3]) with mapi id 15.20.1164.008; Fri, 21 Sep 2018 08:25:57 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 06/27] Silicon/NXP: Add I2C library support for i.MX platforms Thread-Index: AQHUUYS4KptAO3XPwkaBsiSS01AJZA== Date: Fri, 21 Sep 2018 08:25:57 +0000 Message-ID: <20180921082542.35768-7-christopher.co@microsoft.com> References: <20180921082542.35768-1-christopher.co@microsoft.com> In-Reply-To: <20180921082542.35768-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MWHPR17CA0054.namprd17.prod.outlook.com (2603:10b6:300:93::16) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:8:388a:edc9:7085:c18] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB1112; 6:10EOi6gP90Hxq8J6u+QC6VPp47zTPNasY1+91J8/SBrEZESCkZw58X3quvNsZlGBhRnsu5FEjx/I8aBBWFizWX0+LwygQHf7pTWDlc0fDZghJ0t4eZ4KXKlT9YG6mnuSopxeBKSXWW1Jf+PQ+hSx9OdUHV0wO39gt+92r4n5VpVOOoMMEuTXio+JWjKvjCbHrNd0mPbI1g51O4XX+PminHB+JH7wslzM/5ZEViTGgiTcJsPEmXmo0hOkcR4bvp7ahaNwhIq49KtoYW/nzd0GPP84hIxeKoN51e0e4QaPLQFcvE5Xm78/Guezf3AlR+hnCMNSthTV6D9+Z8S+v+iCtKvTROKU7Qc0Vkbs6oQOwIShQqHImyn9fFvzUQr5zh5WwOdXPrSyX4yNfuPQJkUTCgB+e5/UStlGwXWJBGyD3B9ZyRvx1xrS/QbbwqQIXj7FMQeIUpJSbQJOCM7uIqE24A==; 5:Yk+wZ2UDBbHnNRXjxqlbg0wTnPKphNopbQzWH7+FsfSZeFlwzuKSExLnPlrt1R6VOAmvaC1K3CNg898XZL7IKv7pR9pHGPOfHexo04Z/JR8/p3DsKFmiQ1B+a7EZbaaXUPgQv2zeM0GrKrq1kQyCshH2cDCScBN56KsNLb7wEp4=; 7:qA83YTeP+7DSwK6nkHFcG53aP9WFUPIa/52yOY9kOpihMgSVpD52FvQcgWWCphzoAqtLg7xzhxS1AkUvv2bhDzPgpdd3fRxFOG5GvPogm3UTFBDTwnCtN4ns3qcaKei/xsaje2P1ek7gE0mfCzrYC4iU+vw8/BMc2yzADfWWXBeC/idv2vee1TCyj3LO3y7DU3XvxFlLN4tOF+D9ogQnagaN1EPVY5WgPP7riLiQxOs+84yBWKfxvXBtBsyv9ULY x-ms-office365-filtering-correlation-id: 31bf6deb-555b-4748-95ee-08d61f9bdaf0 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7193020); SRVR:DM5PR2101MB1112; x-ms-traffictypediagnostic: DM5PR2101MB1112: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(12401385986421)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(3002001)(10201501046)(3231355)(2280164)(944501410)(52105095)(2018427008)(93006095)(93001095)(6055026)(149027)(150027)(6041310)(20161123560045)(20161123564045)(20161123558120)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(201708071742011)(7699051)(76991041); SRVR:DM5PR2101MB1112; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB1112; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(136003)(346002)(39860400002)(376002)(366004)(396003)(199004)(189003)(106356001)(6512007)(81166006)(6306002)(7736002)(114624004)(966005)(10090500001)(45954006)(14444005)(15188155005)(186003)(6436002)(6506007)(54906003)(102836004)(386003)(6346003)(6916009)(316002)(19627235002)(256004)(81156014)(5640700003)(86362001)(105586002)(14454004)(86612001)(68736007)(305945005)(8676002)(575784001)(5250100002)(52116002)(5660300001)(25786009)(2501003)(76176011)(6486002)(6116002)(8936002)(486006)(71190400001)(71200400001)(4326008)(11346002)(2616005)(53376002)(476003)(446003)(97736004)(53946003)(53936002)(478600001)(10290500003)(72206003)(22452003)(2351001)(2900100001)(36756003)(16799955002)(1076002)(99286004)(46003)(2906002)(60540400001)(579004); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB1112; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-message-info: LwcB9bXhOI6RYJEJ7GwG+I9i77JpXiC0fP362R99OeXYbsFGSLqApEAf74PaBlGhrTUf8bnLgBvvwfXlOAQz22ssaFQR+BfQbn03ELIBb/uSgCo6Lao6o1Y0XMCN7t7d61QzH2F6QxL5621KBzvZHWT7uEB0lrSgSk+IzjmLKRdl7YKTg2GV7zOssy69sxQiCMX5bthvPNovY+0zRDT86AXS4j+J0qh+/6EPPgpEQC5AjZRrCyx4aC3LkXzztWm8emuV9dQa+rc7dC47rLVKPhE6LCcAmOHO5qDQZIGsCVfxBQnJtB1BoHWuLh7jFmxB4Dlhsekr9xteeDxzhnXdpIM/c+FvK3DcTs2Xzbgqw/JEl3242l+NqAG+6GWL3AtR+8JrkBU9Ec8L7JJXsEEgmquuTtJ9FWfQPVdT0wQeIL+TP1uLRKkGn2zQuFvMn6csQ37PVhK4r8/emNxsj3lIjtb0Vh9MOrE41TkxpQR6+d2yhcuf5NRDPGJ8grSQ3SIUpYrl/mEzmNRoasMZekHRPCrAYxaQbkYvsoprIrb/z8z38OOz73d2fOFV1o2tqoqk spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 31bf6deb-555b-4748-95ee-08d61f9bdaf0 X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 08:25:57.7939 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB1112 Subject: [PATCH edk2-platforms 06/27] Silicon/NXP: Add I2C library support for i.MX platforms X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Sep 2018 08:25:59 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable This adds support for I2C controller on NXP i.MX platforms. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Christopher Co Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Michael D Kinney --- Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h | 162 +++++++ Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c | 487 +++++++++= +++++++++++ Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf | 35 ++ 3 files changed, 684 insertions(+) diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h b/Silicon/NXP/i= MXPlatformPkg/Include/iMXI2cLib.h new file mode 100644 index 000000000000..de8a1616fe1b --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h @@ -0,0 +1,162 @@ +/** @file +* +* Copyright (c) 2018 Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +* +**/ + +#ifndef _IMX_I2C_H_ +#define _IMX_I2C_H_ + +#pragma pack(push, 1) + +typedef union { + UINT16 AsUint16; + struct { + UINT16 Reserved0 : 1; + UINT16 ADR : 7; + UINT16 Reserved1 : 8; + }; +} IMX_I2C_IADR_REG; + +typedef union { + UINT16 AsUint16; + struct { + UINT16 IC : 6; + UINT16 Reserved0 : 10; + }; +} IMX_I2C_IFDR_REG; + +typedef union { + UINT16 AsUint16; + struct { + UINT16 Reserved0 : 2; + UINT16 RSTA : 1; + UINT16 TXAK : 1; + UINT16 MTX : 1; + UINT16 MSTA : 1; + UINT16 IIEN : 1; + UINT16 IEN : 1; + UINT16 Reserved1 : 8; + }; +} IMX_I2C_I2CR_REG; + +#define IMX_I2C_I2SR_RXAK 0x0001 +#define IMX_I2C_I2SR_IIF 0x0002 +#define IMX_I2C_I2SR_SRW 0x0004 +#define IMX_I2C_I2SR_IAL 0x0010 +#define IMX_I2C_I2SR_IBB 0x0020 +#define IMX_I2C_I2SR_IAAS 0x0040 +#define IMX_I2C_I2SR_ICF 0x0080 + +typedef union { + UINT16 AsUint16; + struct { + UINT16 RXAK : 1; + UINT16 IIF : 1; + UINT16 SRW : 1; + UINT16 Reserved0 : 1; + UINT16 IAL : 1; + UINT16 IBB : 1; + UINT16 IAAS : 1; + UINT16 ICF : 1; + UINT16 Reserved1 : 8; + }; +} IMX_I2C_I2SR_REG; + +typedef union { + UINT16 AsUint16; + struct { + UINT16 DATA : 8; + UINT16 Reserved0 : 8; + }; +} IMX_I2C_I2DR_REG; + +typedef struct { + IMX_I2C_IADR_REG IADR; + UINT16 Pad0; + IMX_I2C_IFDR_REG IFDR; + UINT16 Pad1; + IMX_I2C_I2CR_REG I2CR; + UINT16 Pad2; + IMX_I2C_I2DR_REG I2SR; + UINT16 Pad3; + IMX_I2C_I2DR_REG I2DR; + UINT16 Pad4; +} IMX_I2C_REGS; + +#pragma pack(pop) + +typedef struct { + UINT32 ControllerAddress; + UINT32 ControllerSlaveAddress; + UINT32 ReferenceFreq; + UINT32 TargetFreq; + UINT32 SlaveAddress; + UINT32 TimeoutInUs; +} IMX_I2C_CONFIG; + +typedef struct { + UINT32 Divider; + UINT32 IC; +} IMX_I2C_DIVIDER; + +/** + Perform I2C read operation. + + The iMXI2cRead perform I2C read operation by programming the I2C control= ler. + The caller is responsible to provide I2C controller configuration. + + @param[in] IMX_I2C_CONFIG Pointer to structure containing the targ= eted + I2C controller to be used for I2C operat= ion. + @param[in] RegisterAddress Targeted device register address to star= t read. + @param[out] ReadBufferPtr Caller supplied buffer that would be wri= tten + into with data from the read operation. + @param[in] ReadBufferSize Size of caller supplied buffer. + + @retval RETURN_SUCCESS I2C Read operation succeeded. + @retval RETURN_DEVICE_ERROR The I2C device is not functioning correc= tly. + +**/ +RETURN_STATUS +iMXI2cRead ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 RegisterAddress, + OUT UINT8 *ReadBufferPtr, + IN UINT32 ReadBufferSize + ); + +/** + Perform I2C write operation. + + The iMXI2cWrite perform I2C write operation by programming the I2C + controller. The caller is responsible to provide I2C controller + configuration. + + @param[in] IMX_I2C_CONFIG Pointer to structure containing the targ= eted + I2C controller to be used for I2C operat= ion. + @param[in] RegisterAddress Targeted device register address to star= t write. + @param[out] WriteBufferPtr Caller supplied buffer that contained da= ta that + would be read from for I2C write operati= on. + @param[in] WriteBufferSize Size of caller supplied buffer. + + @retval RETURN_SUCCESS I2C Write operation succeeded. + @retval RETURN_DEVICE_ERROR The I2C device is not functioning correc= tly. + +**/ +RETURN_STATUS +iMXI2cWrite ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 RegisterAddress, + IN UINT8 *WriteBufferPtr, + IN UINT32 WriteBufferSize + ); + +#endif diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c b/Sil= icon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c new file mode 100644 index 000000000000..6cfe04dba571 --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c @@ -0,0 +1,487 @@ +/** @file +* +* Copyright (c) 2018 Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +* +**/ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +IMX_I2C_DIVIDER DividerValue[] =3D { + { 22, 0x20, }, + { 24, 0x21, }, + { 26, 0x22, }, + { 28, 0x23, }, + { 30, 0x00, }, + { 32, 0x24, }, + { 36, 0x25, }, + { 40, 0x26, }, + { 42, 0x03, }, + { 44, 0x27, }, + { 48, 0x28, }, + { 52, 0x05, }, + { 56, 0x29, }, + { 60, 0x06, }, + { 64, 0x2A, }, + { 72, 0x2B, }, + { 80, 0x2C, }, + { 88, 0x09, }, + { 96, 0x2D, }, + { 104, 0x0A, }, + { 112, 0x2E, }, + { 128, 0x2F, }, + { 144, 0x0C, }, + { 160, 0x30, }, + { 192, 0x31, }, + { 224, 0x32, }, + { 240, 0x0F, }, + { 256, 0x33, }, + { 288, 0x10, }, + { 320, 0x34, }, + { 384, 0x35, }, + { 448, 0x36, }, + { 480, 0x13, }, + { 512, 0x37, }, + { 576, 0x14, }, + { 640, 0x38, }, + { 768, 0x39, }, + { 896, 0x3A, }, + { 960, 0x17, }, + { 1024, 0x3B, }, + { 1152, 0x18, }, + { 1280, 0x3C, }, + { 1536, 0x3D, }, + { 1792, 0x3E, }, + { 1920, 0x1B, }, + { 2048, 0x3F, }, + { 2304, 0x1C, }, + { 2560, 0x1D, }, + { 3072, 0x1E, }, + { 3840, 0x1F, }, +}; + +#define DIVIDER_VALUE_TOTAL (sizeof(DividerValue) / sizeof(DividerValue[0]= )) + +BOOLEAN +iMXI2cWaitStatusSet ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT16 StatusBits + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + UINT32 Counter; + IMX_I2C_I2SR_REG I2srReg; + + Counter =3D I2cConfigPtr->TimeoutInUs; + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + while (Counter) { + I2srReg =3D (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR); + if ((I2srReg.AsUint16 & StatusBits) =3D=3D StatusBits) { + return TRUE; + } + MicroSecondDelay (1); + --Counter; + } + + return FALSE; +} + +BOOLEAN +iMXI2cWaitStatusUnSet ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT16 StatusBits + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + UINT32 Counter; + IMX_I2C_I2SR_REG I2srReg; + + Counter =3D I2cConfigPtr->TimeoutInUs; + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + while (Counter) { + I2srReg =3D (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR); + if ((I2srReg.AsUint16 & StatusBits) =3D=3D 0) { + return TRUE; + } + MicroSecondDelay (1); + --Counter; + } + + return FALSE; +} + +BOOLEAN +iMXI2cSendByte ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 Data + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + UINT32 Counter; + IMX_I2C_I2SR_REG I2srReg; + UINT16 SendData; + + SendData =3D Data; + Counter =3D I2cConfigPtr->TimeoutInUs; + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + + // Clear status and transfer byte + MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0); + MmioWrite16 ((UINTN)&I2cRegsPtr->I2DR, SendData); + + while (Counter) { + I2srReg =3D (IMX_I2C_I2SR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2SR); + if (I2srReg.IIF =3D=3D 1) { + return TRUE; + } else if (I2srReg.IAL =3D=3D 1) { + DEBUG ((DEBUG_ERROR, "iMXI2cSendByte: fail 0x%04x\n", I2srReg.AsUint= 16)); + return FALSE; + } + MicroSecondDelay (1); + --Counter; + } + + DEBUG ((DEBUG_ERROR, "iMXI2cSendByte: Fail timeout\n")); + return FALSE; +} + +RETURN_STATUS +iMXI2cSetupController ( + IN IMX_I2C_CONFIG *I2cConfigPtr + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + UINT32 Divider; + UINT32 DividerCount; + UINT32 IfdrDiv; + IMX_I2C_I2CR_REG I2crReg; + + I2cRegsPtr =3D (IMX_I2C_REGS *)I2cConfigPtr->ControllerAddress; + + // Disable controller and clear any pending interrupt + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, 0); + MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0); + + // Setup Divider if reference freq is provided. If no, use value setup b= y + // 1st boot loader + if (I2cConfigPtr->ReferenceFreq !=3D 0) { + IfdrDiv =3D 0; + Divider =3D I2cConfigPtr->ReferenceFreq / I2cConfigPtr->TargetFreq; + + for (DividerCount =3D 0; DividerCount < DIVIDER_VALUE_TOTAL; ++Divider= Count) { + if (DividerValue[DividerCount].Divider >=3D Divider) { + DEBUG (( + DEBUG_INFO, + "iMXI2cSetupController: Divider %d IC 0x%02x\n", + DividerValue[DividerCount].Divider, + DividerValue[DividerCount].IC)); + IfdrDiv =3D DividerValue[DividerCount].IC; + break; + } + } + + if (IfdrDiv =3D=3D 0) { + DEBUG (( + DEBUG_ERROR, + "iMXI2cSetupController: could not find Divider for %d\n", + Divider)); + return RETURN_INVALID_PARAMETER; + } + + MmioWrite16 ((UINTN)&I2cRegsPtr->IFDR, IfdrDiv); + } + + // Setup slave address + MmioWrite16 ((UINTN)&I2cRegsPtr->IADR, + (I2cConfigPtr->ControllerSlaveAddress << 1)); + + // Enable controller and set to master mode. + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + + // This bit must be set before any other I2C_I2CR bits have an effect + I2crReg.IEN =3D 1; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + MicroSecondDelay (100); + + MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0); + + // Wait for bus to be idle + if (iMXI2cWaitStatusUnSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) =3D=3D FALSE)= { + DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains busy\n")= ); + return RETURN_DEVICE_ERROR; + } + + I2crReg.MSTA =3D 1; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + + // Now wait for bus to be busy + if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains idle\n")= ); + return RETURN_DEVICE_ERROR; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +iMXI2cGenerateStart ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 RegisterAddress + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + IMX_I2C_I2CR_REG I2crReg; + BOOLEAN Result; + RETURN_STATUS Status; + + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + Status =3D iMXI2cSetupController (I2cConfigPtr); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStart: Fail to setup controller %r= \n", + Status)); + return Status; + } + + // Set controller to transmit mode + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + I2crReg.MTX =3D 1; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + + Result =3D iMXI2cSendByte (I2cConfigPtr, (I2cConfigPtr->SlaveAddress << = 1)); + if (Result =3D=3D FALSE) { + DEBUG (( + DEBUG_ERROR, + "iMXI2cGenerateStart: Slave address transfer fail 0x%04x\n", + MmioRead16 ((UINTN)&I2cRegsPtr->I2SR))); + return RETURN_DEVICE_ERROR; + } + + // Send slave register address + Result =3D iMXI2cSendByte (I2cConfigPtr, RegisterAddress); + if (Result =3D=3D FALSE) { + DEBUG (( + DEBUG_ERROR, + "iMXI2cGenerateStart: Slave register address transfer fail 0x= %04x\n", + MmioRead16 ((UINTN)&I2cRegsPtr->I2SR))); + return RETURN_DEVICE_ERROR; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +iMXI2cGenerateStop ( + IN IMX_I2C_CONFIG *I2cConfigPtr + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + IMX_I2C_I2CR_REG I2crReg; + + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + I2crReg.MSTA =3D 0; + I2crReg.MTX =3D 0; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + + // Bus should go idle + if (iMXI2cWaitStatusUnSet (I2cConfigPtr, IMX_I2C_I2SR_IBB) =3D=3D FALSE)= { + DEBUG ((DEBUG_ERROR, "iMXI2cGenerateStop: Controller remains busy\n"))= ; + return RETURN_DEVICE_ERROR; + } + + return RETURN_SUCCESS; +} + +/** + Perform I2C read operation. + + The iMXI2cRead perform I2C read operation by programming the I2C control= ler. + The caller is responsible to provide I2C controller configuration. + + @param[in] IMX_I2C_CONFIG Pointer to structure containing the targ= eted + I2C controller to be used for I2C operat= ion. + @param[in] RegisterAddress Targeted device register address to star= t read. + @param[out] ReadBufferPtr Caller supplied buffer that would be wri= tten + into with data from the read operation. + @param[in] ReadBufferSize Size of caller supplied buffer. + + @retval RETURN_SUCCESS I2C Read operation succeeded. + @retval RETURN_DEVICE_ERROR The I2C device is not functioning correc= tly. + +**/ +RETURN_STATUS +iMXI2cRead ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 RegisterAddress, + OUT UINT8 *ReadBufferPtr, + IN UINT32 ReadBufferSize + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + IMX_I2C_I2CR_REG I2crReg; + BOOLEAN Result; + RETURN_STATUS Status; + + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + Status =3D iMXI2cGenerateStart (I2cConfigPtr, RegisterAddress); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStart failed %r\n", St= atus)); + goto Exit; + } + + // Send slave address again to begin read + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + I2crReg.RSTA =3D 1; // Repeated start + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + Result =3D iMXI2cSendByte ( + I2cConfigPtr, + (I2cConfigPtr->SlaveAddress << 1 | 1)); + if (Result =3D=3D FALSE) { + DEBUG (( + DEBUG_ERROR, + "iMXI2cRead: 2nd Slave address transfer failed 0x%04x\n", + MmioRead16 ((UINTN)&I2cRegsPtr->I2SR))); + Status =3D RETURN_DEVICE_ERROR; + goto Exit; + } + + // Disable master mode + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + + // NXP application note AN4481 - Only one byte so do not send acknowledg= e + if (ReadBufferSize =3D=3D 1) { + I2crReg.TXAK =3D 1; + } else { + I2crReg.TXAK =3D 0; + } + + I2crReg.MTX =3D 0; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + + // A data transfer can now be initiated by a read from I2C_I2DR in Slave + // Receive mode. + MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0); + MmioRead16 ((UINTN)&I2cRegsPtr->I2DR); + + do { + // Wait for transfer to complete + if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_IIF) =3D=3D FALSE)= { + DEBUG ((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n")); + Status =3D RETURN_DEVICE_ERROR; + goto Exit; + } + + if (iMXI2cWaitStatusSet (I2cConfigPtr, IMX_I2C_I2SR_ICF) =3D=3D FALSE)= { + DEBUG ((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n")); + Status =3D RETURN_DEVICE_ERROR; + goto Exit; + } + + // Before the last byte is read, a Stop signal must be generated + if (ReadBufferSize =3D=3D 1) { + Status =3D iMXI2cGenerateStop ( + I2cConfigPtr); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStop fail %r\n", S= tatus)); + goto Exit; + } + } + + if (ReadBufferSize =3D=3D 2) { + I2crReg =3D (IMX_I2C_I2CR_REG)MmioRead16 ((UINTN)&I2cRegsPtr->I2CR); + I2crReg.TXAK =3D 1; + MmioWrite16 ((UINTN)&I2cRegsPtr->I2CR, I2crReg.AsUint16); + } + + MmioWrite16 ((UINTN)&I2cRegsPtr->I2SR, 0); + + *ReadBufferPtr =3D MmioRead8 ((UINTN)&I2cRegsPtr->I2DR); + ++ReadBufferPtr; + --ReadBufferSize; + } while (ReadBufferSize > 0); + +Exit: + Status =3D iMXI2cGenerateStop (I2cConfigPtr); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cRead: Final iMXI2cGenerateStop fail %r\n",= Status)); + } + + return Status; +} + +/** + Perform I2C write operation. + + The iMXI2cWrite perform I2C write operation by programming the I2C + controller. The caller is responsible to provide I2C controller + configuration. + + @param[in] IMX_I2C_CONFIG Pointer to structure containing the targ= eted + I2C controller to be used for I2C operat= ion. + @param[in] RegisterAddress Targeted device register address to star= t write. + @param[out] WriteBufferPtr Caller supplied buffer that contained da= ta that + would be read from for I2C write operati= on. + @param[in] WriteBufferSize Size of caller supplied buffer. + + @retval RETURN_SUCCESS I2C Write operation succeeded. + @retval RETURN_DEVICE_ERROR The I2C device is not functioning correc= tly. + +**/ +RETURN_STATUS +iMXI2cWrite ( + IN IMX_I2C_CONFIG *I2cConfigPtr, + IN UINT8 RegisterAddress, + IN UINT8 *WriteBufferPtr, + IN UINT32 WriteBufferSize + ) +{ + IMX_I2C_REGS *I2cRegsPtr; + BOOLEAN Result; + RETURN_STATUS Status; + + I2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress; + Status =3D iMXI2cGenerateStart (I2cConfigPtr, RegisterAddress); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStart fail %r\n", Sta= tus)); + goto Exit; + } + + while (WriteBufferSize > 0) { + Result =3D iMXI2cSendByte (I2cConfigPtr, *WriteBufferPtr); + if (Result =3D=3D FALSE) { + DEBUG (( + DEBUG_ERROR, + "iMXI2cWrite: Slave address transfer fail 0x%04x\n", + MmioRead16 ((UINTN)&I2cRegsPtr->I2SR))); + Status =3D RETURN_DEVICE_ERROR; + goto Exit; + } + + ++WriteBufferPtr; + --WriteBufferSize; + } + +Exit: + Status =3D iMXI2cGenerateStop (I2cConfigPtr); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStop fail %r\n", Stat= us)); + } + + return Status; +} diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf b/S= ilicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf new file mode 100644 index 000000000000..ad968e88b1da --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf @@ -0,0 +1,35 @@ +## @file +# +# Copyright (c) 2018 Microsoft Corporation. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D iMXI2cLib + FILE_GUID =3D C4E4A003-8AEB-4C9B-8E72-D2BAD2134BDE + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D iMXI2cLib + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + IoLib + TimerLib + +[Sources.common] + iMXI2cLib.c --=20 2.16.2.gvfs.1.33.gf5370f1