From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.34.95; helo=nam01-by2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM01-BY2-obe.outbound.protection.outlook.com (mail-by2nam01on0095.outbound.protection.outlook.com [104.47.34.95]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id F2768202E5446 for ; Wed, 18 Jul 2018 21:11:23 -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=kzYK2JHrhOjpSdCKntbk3XMxDxTYwoph+NVGMksJxBU=; b=E2YXR95GA7AUV729kbmuA2LZtHvt58AKLqWCTutrpbEWZUpn3UETBadJE8j3g82wU8kS6laPR3ZVta6YpleS3oxZMEpFGVD6sr/wwRDvWO9G5/yQcWGY8WmoCVkguKVLVYPu++LXwSyCEZX9VYxxbvZ7pvsyLB3WP7/t/sk46WU= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0983.namprd21.prod.outlook.com (52.132.133.29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.995.0; Thu, 19 Jul 2018 04:11:22 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::b4d3:dabb:9372:9740]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::b4d3:dabb:9372:9740%2]) with mapi id 15.20.0995.008; Thu, 19 Jul 2018 04:11:21 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms Thread-Index: AQHUHxaNGsc6U0zT7UysKOer2ymtnQ== Date: Thu, 19 Jul 2018 04:11:21 +0000 Message-ID: <20180719041103.9072-4-christopher.co@microsoft.com> References: <20180719041103.9072-1-christopher.co@microsoft.com> In-Reply-To: <20180719041103.9072-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: BN6PR11CA0037.namprd11.prod.outlook.com (2603:10b6:404:4b::23) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:1:d144:e4c:c05:68bd] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0983; 6:w3E7prYMqdKX2hcQuR61Jil9hrpYJhWlRZ0sjMhk4fgLDQKd9PXtC4iM10UT2MIY3gkEu/9S9+LzJglBWpOgo3UtZr6RQxxUyGeTjaLtLtthSVlghpaHA2WQ6FW0jBI/QXwlDs35oO+I0R7UX8JBBrQarrlCodnJc/BFzb+0AWHtgri6XodYCxI6GUFPUGwscIdtsxqr/p3R+URYhNiTtqs9I9RGjcVKrdpjRpZav+SLqVH535I04CgdkGnLu7vo+WB3wMG7nZAlv5MaBtarMZ2c9jLB2bLFcjDMHzV4/mMwI0D408Chwb0HMTaQFUi96ppC18DtAmIrMYBL5pGggjsHBEtsDjs3rEuSx4lARy3eCkM4ZSxUTw+fCbBii0C0uDCvwkz/NCul+lE2V28HZQ/Xf1arb/MFo2p5tKLBgWRyXaxblW0Gbaj9A9U22RLzqzmxIMGUXep183/6dDfL0Q==; 5:8AW6wBUR2F2zbK0LAmXpE4+5NTKQVkf+r9/l+MojpR5gpdhFz08VsxvrQL2uNtACy8by9qZERsOer6jWkcALJbOO7AcnXcm6WFC7JZBFet0RN7Z8/XyVnlE5rvxTHT88xd+7FlGFVlAALwQKulsDqsUl2qC3phy1ESq0lmubtSk=; 7:gBBOxEA8O3NPcXzUfSDHkXFR7rsltONNeaGB5natu9hj332pxJUBmXolOg2QP8q94nDQUaApnTadrHZuwxsNUK51wn+SDsXvzFRI+lC5Swr/sopgjzer5aioTlWAq6SQoI4lyQ2jctXsHOGDIS1/Qm8fyE3cAzntIhBLZCv0yBPdPzYEYJWEZXpeJ2SbfHnPrpRZENUW/OZ7T/w9tCRY+pH4Al/PPRNnooOmgM3natVRouv88LmzkHmmlQZzwUpJ x-ms-office365-filtering-correlation-id: f2d59ef0-ac7b-4526-ffca-08d5ed2daf3c x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989117)(5600067)(711020)(4618075)(4534165)(4627221)(201703031133081)(201702281549075)(8990107)(2017052603328)(7193020); SRVR:DM5PR2101MB0983; x-ms-traffictypediagnostic: DM5PR2101MB0983: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(93006095)(93001095)(3231311)(944501410)(52105095)(2018427008)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011)(7699016); SRVR:DM5PR2101MB0983; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0983; x-forefront-prvs: 0738AF4208 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(136003)(396003)(346002)(366004)(376002)(39860400002)(189003)(199004)(25786009)(8936002)(4326008)(53936002)(386003)(53376002)(6506007)(68736007)(52116002)(86612001)(6916009)(76176011)(5640700003)(6512007)(10090500001)(6436002)(106356001)(6306002)(6486002)(14444005)(5660300001)(105586002)(256004)(2351001)(8676002)(53946003)(81166006)(7736002)(305945005)(81156014)(114624004)(36756003)(478600001)(5250100002)(99286004)(1076002)(19627235002)(14454004)(46003)(54906003)(186003)(2501003)(10290500003)(16799955002)(72206003)(966005)(22452003)(102836004)(486006)(2900100001)(2906002)(6116002)(446003)(2616005)(476003)(316002)(15188155005)(575784001)(86362001)(11346002)(97736004); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0983; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: jmKhYUjiSHfXMGmgVenJk+tx+/CAt0KoKMlAV/43e+zyNnUEGdHFKTYba6erGFLnZZ6dEgNTLltsjLF3K9UMCH9MNY88U83YlD02/jnP4Nojp6Jtcs1ORuMTzwTMkhd9LH7C54rJte6YTl4Xq+WDgjuSvgakeEa2YZSd8SUv6Oq3pP+NZGoIKvi4pAACcz5Z5hQeNTeu0fjLjTjRmNhucho5z5oZhdFADsSw/klS0H2OUGVvThlDB0bOv7/NUUpZoUPAtimsEWzhdompfekhMnott9uChf8jWnFTOr6AJumJoHA+Ggvp/8RLVzn7ZOctoreV27kHXvErLhf/J8foWyasFRYdUb26mFoy7NMRkig= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: f2d59ef0-ac7b-4526-ffca-08d5ed2daf3c X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Jul 2018 04:11:21.8833 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0983 Subject: [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Jul 2018 04:11:24 -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 | 158 ++++++ Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c | 524 +++++++++= +++++++++++ Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf | 35 ++ 3 files changed, 717 insertions(+) diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h b/Silicon/NXP/i= MXPlatformPkg/Include/iMXI2cLib.h new file mode 100644 index 000000000000..e0688d7aa89f --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h @@ -0,0 +1,158 @@ +/** @file +* +* Copyright (c) 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; + +/** Performs 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* Structure containing the targeted i2c control= ler + to be used for i2c operation. The structure contains important informati= on + such as the controller base address, reference frequency. + @param[in] RegisterAddress Targeted device register address to start rea= d. + @param[out] ReadBufferPtr Caller supplied buffer that would be written i= nto + with data from the read operation. + @param[in] ReadBufferSize Size of caller supplied buffer. + + @retval EFI_SUCCESS i2c Read operation succeed. + @retval !EFI_SUCCESS Failure. + +--*/ +RETURN_STATUS +iMXI2cRead ( + IN IMX_I2C_CONFIG* I2cConfigPtr, + IN UINT8 RegisterAddress, + OUT UINT8* ReadBufferPtr, + IN UINT32 ReadBufferSize + ); + +/** Performs 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* Structure containing the targeted i2c control= ler + to be used for i2c operation. The structure contains important informati= on + such as the controller base address, reference frequency. + @param[in] RegisterAddress Targeted device register address to start wri= te. + @param[out] WriteBufferPtr Caller supplied buffer that contained data th= at + would be read from for i2c write operation.. + @param[in] WriteBufferSize Size of caller supplied buffer. + + @retval EFI_SUCCESS i2c Write operation succeed. + @retval !EFI_SUCCESS Failure. + +--*/ +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..00da831ae6b6 --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c @@ -0,0 +1,524 @@ +/** @file +* +* Copyright (c) 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 + +typedef struct { + UINT32 Divider; + UINT32 IC; +} IMX_I2C_DIVIDER; + +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 ( + IMX_I2C_CONFIG* I2cConfigPtr, + UINT16 StatusBits + ) +{ + UINT32 counter =3D I2cConfigPtr->TimeoutInUs; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + while (counter) { + IMX_I2C_I2SR_REG i2srReg =3D { MmioRead16((UINTN)&i2cRegsPtr->I2SR) }; + + if ((i2srReg.AsUint16 & StatusBits) =3D=3D StatusBits) { + return TRUE; + } + + MicroSecondDelay(1); + --counter; + } + + return FALSE; +} + +BOOLEAN +iMXI2cWaitStatusUnSet ( + IMX_I2C_CONFIG* I2cConfigPtr, + UINT16 StatusBits +) +{ + UINT32 counter =3D I2cConfigPtr->TimeoutInUs; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + while (counter) { + IMX_I2C_I2SR_REG i2srReg =3D { MmioRead16((UINTN)&i2cRegsPtr->I2SR) }; + + if ((i2srReg.AsUint16 & StatusBits) =3D=3D 0) { + return TRUE; + } + + MicroSecondDelay(1); + --counter; + } + + return FALSE;; +} + +BOOLEAN +iMXI2cSendByte ( + IMX_I2C_CONFIG* I2cConfigPtr, + UINT8 Data +) +{ + UINT16 sendData =3D Data; + UINT32 counter =3D I2cConfigPtr->TimeoutInUs; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + // + // Clear status + // + MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0); + + // + // Transfer byte + // + MmioWrite16((UINTN)&i2cRegsPtr->I2DR, sendData); + + while (counter) { + IMX_I2C_I2SR_REG i2srReg =3D { 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.AsUint16)); + return FALSE; + } + + MicroSecondDelay(1); + --counter; + } + + DEBUG((DEBUG_ERROR, "iMXI2cSendByte: Fail timeout\n")); + + return FALSE; +} + +RETURN_STATUS +iMXI2cSetupController ( + IMX_I2C_CONFIG* I2cConfigPtr, + UINT8 RegisterAddress + ) +{ + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + // + // 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 by + // 1st boot loader + // + if (I2cConfigPtr->ReferenceFreq !=3D 0) { + + UINT32 ifdrDiv =3D 0; + UINT32 dividerCount; + UINT32 divider =3D I2cConfigPtr->ReferenceFreq / I2cConfigPtr->TargetF= req; + + for (dividerCount =3D 0; + dividerCount < DIVIDER_VALUE_TOTAL; + ++dividerCount) { + + 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->ControllerSlaveAddr= ess << 1)); + + // + // Enable controller and set to master mode. + // + { + IMX_I2C_I2CR_REG i2crReg =3D { 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 ( + IMX_I2C_CONFIG* I2cConfigPtr, + UINT8 RegisterAddress, + BOOLEAN Read + ) +{ + BOOLEAN result; + RETURN_STATUS status; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + status =3D iMXI2cSetupController( + I2cConfigPtr, + RegisterAddress); + if (RETURN_ERROR(status)) { + DEBUG((DEBUG_ERROR, "iMXI2cGenerateStart: Fail to setup controller %r\= n", status)); + return status; + } + + // + // Send slave address so set controller to transmit mode + // + { + IMX_I2C_I2CR_REG i2crReg =3D { 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 + // + 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 ( + IMX_I2C_CONFIG* I2cConfigPtr + ) +{ + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + IMX_I2C_I2CR_REG i2crReg =3D { 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; +} + +RETURN_STATUS +iMXI2cRead ( + IN IMX_I2C_CONFIG* I2cConfigPtr, + IN UINT8 RegisterAddress, + OUT UINT8* ReadBufferPtr, + IN UINT32 ReadBufferSize + ) +{ + RETURN_STATUS status; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + status =3D iMXI2cGenerateStart( + I2cConfigPtr, + RegisterAddress, + TRUE); + if (RETURN_ERROR(status)) { + DEBUG((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStart failed %r\n", sta= tus)); + goto Exit; + } + + // + // Send slave address again to begin read + // + { + BOOLEAN result; + IMX_I2C_I2CR_REG i2crReg =3D { 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 + // + { + IMX_I2C_I2CR_REG i2crReg =3D { MmioRead16((UINTN)&i2cRegsPtr->I2CR) }; + + // + // NXP application note AN4481 + // Only one byte so do not send acknowledge + // + 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; + } + + // + // Per spec. Before the last byte is read, a Stop signal must be gener= ated + // + if (ReadBufferSize =3D=3D 1) { + + status =3D iMXI2cGenerateStop( + I2cConfigPtr); + if (RETURN_ERROR(status)) { + DEBUG((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStop fail %r\n", st= atus)); + goto Exit; + } + } + + if (ReadBufferSize =3D=3D 2) { + IMX_I2C_I2CR_REG i2crReg =3D { 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; +} + +RETURN_STATUS +iMXI2cWrite ( + IN IMX_I2C_CONFIG* I2cConfigPtr, + IN UINT8 RegisterAddress, + IN UINT8* WriteBufferPtr, + IN UINT32 WriteBufferSize + ) +{ + RETURN_STATUS status; + IMX_I2C_REGS* i2cRegsPtr =3D (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddr= ess; + + status =3D iMXI2cGenerateStart( + I2cConfigPtr, + RegisterAddress, + FALSE); + if (RETURN_ERROR(status)) { + DEBUG((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStart fail %r\n", stat= us)); + goto Exit; + } + + while (WriteBufferSize > 0) { + + BOOLEAN 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", statu= s)); + } + + 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..409fc8f14166 --- /dev/null +++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf @@ -0,0 +1,35 @@ +## @file +# +# Copyright (c) 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 0x00010005 + 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] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec + +[LibraryClasses] + DebugLib + IoLib + TimerLib + BaseMemoryLib + +[Sources.common] + iMXI2cLib.c --=20 2.16.2.gvfs.1.33.gf5370f1