From patchwork Fri Nov 22 21:20:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Olovyannikov X-Patchwork-Id: 1199647 X-Patchwork-Delegate: hs@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=broadcom.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=broadcom.com header.i=@broadcom.com header.b="hJBc5FDh"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 47KTrs6t7lz9sPK for ; Sat, 23 Nov 2019 08:21:49 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 90E76C21C4A; Fri, 22 Nov 2019 21:21:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_MSPIKE_H2, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 84CB2C21C27; Fri, 22 Nov 2019 21:21:37 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id A05D8C21C27; Fri, 22 Nov 2019 21:21:35 +0000 (UTC) Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) by lists.denx.de (Postfix) with ESMTPS id B4F7CC21BE5 for ; Fri, 22 Nov 2019 21:21:34 +0000 (UTC) Received: by mail-wm1-f42.google.com with SMTP id n188so7285412wme.1 for ; Fri, 22 Nov 2019 13:21:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id; bh=q25DvzBFSjIBcer7SGxAX3vFqH1vTkunBoCPofy/PXw=; b=hJBc5FDhRUPAvAWodEjBk4rtcFyUkt3JXmT4+11OJP1glDpda0xvLtJYbSWuoPRphZ fJRu86VWSH3spll+YwBB6uYSL9B97UesxZrUJR/m+BWUQLs+lm8btWOc3oyrusYTzj5I LVYUMoFJRcuRqgZQprr8MIcm2g5xrQ7E1VmKw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=q25DvzBFSjIBcer7SGxAX3vFqH1vTkunBoCPofy/PXw=; b=Y1m70a7lZL3hQmE4LCqZeGdx8d5ZunKSwSXu3NKkJLDWdasaVFEmaFvbMf9WRSRuEe ORzvREKCk+63pUfcamCzOHIpZKqyl7cJoyzNe8XGkuXBIy2VbM07UVWaggveEf0UcyYc HBXnkFLIKlcDbRtkvCdTn7YHxPQWx8bFJtiHIvxkVI3YVzbWPzl5XD7+BYNqCe6o9yTP 2g19splOJZRBZWDrOerPonH1lfVPPV3qYOtu0W0pjwC3Y+soQx/VbWd6AKUEoF+9d0ZD DozGJnvjPySp5LOHk6Z2+08C0RRaMdjnatSu3eHqeqNQBPjvvMEzjNSxVNmMQJglNqD7 MGLg== X-Gm-Message-State: APjAAAWt5JEMMnvCpeoaWrkp7BpqHpEQ63UJAed/63lT8YIuPOIZbvkW HSVo+V9yGYyRcKcepIgFlSDWeQpXaxMOaFlrCKQqMFkK7iJCi0Iv7z32XbFoRc4S+ldJcvu9eod n37h6AbG4JLQyHucRjnmp7DCKKx8Id+XtwrC46J63pF/jV+NDNMWd5RHp+v7GFDo2q3671HfeST L9SmK/uZNQpx0= X-Google-Smtp-Source: APXvYqy4rE16ITMSSkvVIPbZI/Z/1bKSBgp21aPW/2X2AQeC1O2ZK6/wOzXoNBUnX537eM75bpV9yQ== X-Received: by 2002:a1c:98c5:: with SMTP id a188mr18215877wme.133.1574457692587; Fri, 22 Nov 2019 13:21:32 -0800 (PST) Received: from LBRMN-LNXUB114.ric.broadcom.com ([192.19.228.250]) by smtp.gmail.com with ESMTPSA id h97sm6516114wrh.56.2019.11.22.13.21.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Nov 2019 13:21:31 -0800 (PST) From: Vladimir Olovyannikov To: u-boot@lists.denx.de Date: Fri, 22 Nov 2019 13:20:52 -0800 Message-Id: <20191122212052.27053-1-vladimir.olovyannikov@broadcom.com> X-Mailer: git-send-email 2.17.1 Cc: Arjun Jyothi , Rayagonda Kokatanur , Sheetal Tigadoli Subject: [U-Boot] [PATCH 1/1] drivers: i2c: Add brcm iproc I2C driver support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Arjun Jyothi Add I2C driver support for Broadcom iproc-based socs. Signed-off-by: Arjun Jyothi Signed-off-by: Rayagonda Kokatanur Signed-off-by: Sheetal Tigadoli Signed-off-by: Vladimir Olovyannikov --- drivers/i2c/Kconfig | 623 ++++++++++++++++---------------- drivers/i2c/Makefile | 2 +- drivers/i2c/iproc_i2c.c | 765 ++++++++++++++++++++++++++++++++++++++++ drivers/i2c/iproc_i2c.h | 356 +++++++++++++++++++ 4 files changed, 1437 insertions(+), 309 deletions(-) create mode 100644 drivers/i2c/iproc_i2c.c create mode 100644 drivers/i2c/iproc_i2c.h diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 03d2fed341..7a80971b12 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -5,454 +5,461 @@ menu "I2C support" config DM_I2C - bool "Enable Driver Model for I2C drivers" - depends on DM - help - Enable driver model for I2C. The I2C uclass interface: probe, read, - write and speed, is implemented with the bus drivers operations, - which provide methods for bus setting and data transfer. Each chip - device (bus child) info is kept as parent platdata. The interface - is defined in include/i2c.h. + bool "Enable Driver Model for I2C drivers" + depends on DM + help + Enable driver model for I2C. The I2C uclass interface: probe, read, + write and speed, is implemented with the bus drivers operations, + which provide methods for bus setting and data transfer. Each chip + device (bus child) info is kept as parent platdata. The interface + is defined in include/i2c.h. config I2C_CROS_EC_TUNNEL - tristate "Chrome OS EC tunnel I2C bus" - depends on CROS_EC - help - This provides an I2C bus that will tunnel i2c commands through to - the other side of the Chrome OS EC to the I2C bus connected there. - This will work whatever the interface used to talk to the EC (SPI, - I2C or LPC). Some Chromebooks use this when the hardware design - does not allow direct access to the main PMIC from the AP. + tristate "Chrome OS EC tunnel I2C bus" + depends on CROS_EC + help + This provides an I2C bus that will tunnel i2c commands through to + the other side of the Chrome OS EC to the I2C bus connected there. + This will work whatever the interface used to talk to the EC (SPI, + I2C or LPC). Some Chromebooks use this when the hardware design + does not allow direct access to the main PMIC from the AP. config I2C_CROS_EC_LDO - bool "Provide access to LDOs on the Chrome OS EC" - depends on CROS_EC - ---help--- - On many Chromebooks the main PMIC is inaccessible to the AP. This is - often dealt with by using an I2C pass-through interface provided by - the EC. On some unfortunate models (e.g. Spring) the pass-through - is not available, and an LDO message is available instead. This - option enables a driver which provides very basic access to those - regulators, via the EC. We implement this as an I2C bus which - emulates just the TPS65090 messages we know about. This is done to - avoid duplicating the logic in the TPS65090 regulator driver for - enabling/disabling an LDO. + bool "Provide access to LDOs on the Chrome OS EC" + depends on CROS_EC + ---help--- + On many Chromebooks the main PMIC is inaccessible to the AP. This is + often dealt with by using an I2C pass-through interface provided by + the EC. On some unfortunate models (e.g. Spring) the pass-through + is not available, and an LDO message is available instead. This + option enables a driver which provides very basic access to those + regulators, via the EC. We implement this as an I2C bus which + emulates just the TPS65090 messages we know about. This is done to + avoid duplicating the logic in the TPS65090 regulator driver for + enabling/disabling an LDO. config I2C_SET_DEFAULT_BUS_NUM - bool "Set default I2C bus number" - depends on DM_I2C - help - Set default number of I2C bus to be accessed. This option provides - behaviour similar to old (i.e. pre DM) I2C bus driver. + bool "Set default I2C bus number" + depends on DM_I2C + help + Set default number of I2C bus to be accessed. This option provides + behaviour similar to old (i.e. pre DM) I2C bus driver. config I2C_DEFAULT_BUS_NUMBER - hex "I2C default bus number" - depends on I2C_SET_DEFAULT_BUS_NUM - default 0x0 - help - Number of default I2C bus to use + hex "I2C default bus number" + depends on I2C_SET_DEFAULT_BUS_NUM + default 0x0 + help + Number of default I2C bus to use config DM_I2C_GPIO - bool "Enable Driver Model for software emulated I2C bus driver" - depends on DM_I2C && DM_GPIO - help - Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO - configuration is given by the device tree. Kernel-style device tree - bindings are supported. - Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt + bool "Enable Driver Model for software emulated I2C bus driver" + depends on DM_I2C && DM_GPIO + help + Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO + configuration is given by the device tree. Kernel-style device tree + bindings are supported. + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt config SYS_I2C_AT91 - bool "Atmel I2C driver" - depends on DM_I2C && ARCH_AT91 - help - Add support for the Atmel I2C driver. A serious problem is that there - is no documented way to issue repeated START conditions for more than - two messages, as needed to support combined I2C messages. Use the - i2c-gpio driver unless your system can cope with this limitation. - Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt + bool "Atmel I2C driver" + depends on DM_I2C && ARCH_AT91 + help + Add support for the Atmel I2C driver. A serious problem is that there + is no documented way to issue repeated START conditions for more than + two messages, as needed to support combined I2C messages. Use the + i2c-gpio driver unless your system can cope with this limitation. + Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt + +config IPROC_I2C + bool "Broadcom iProc I2C driver" + depends on DM_I2C + help + Add support for Broadcom iProc I2C driver. + The driver is used in iProc SoCs. config SYS_I2C_FSL bool "Freescale I2C bus driver" depends on DM_I2C help - Add support for Freescale I2C busses as used on MPC8240, MPC8245, and - MPC85xx processors. + Add support for Freescale I2C busses as used on MPC8240, MPC8245, and + MPC85xx processors. config SYS_I2C_CADENCE - tristate "Cadence I2C Controller" - depends on DM_I2C && (ARCH_ZYNQ || ARM64) - help - Say yes here to select Cadence I2C Host Controller. This controller is - e.g. used by Xilinx Zynq. + tristate "Cadence I2C Controller" + depends on DM_I2C && (ARCH_ZYNQ || ARM64) + help + Say yes here to select Cadence I2C Host Controller. This controller is + e.g. used by Xilinx Zynq. config SYS_I2C_DAVINCI - bool "Davinci I2C Controller" - depends on (ARCH_KEYSTONE || ARCH_DAVINCI) - help - Say yes here to add support for Davinci and Keystone I2C controller + bool "Davinci I2C Controller" + depends on (ARCH_KEYSTONE || ARCH_DAVINCI) + help + Say yes here to add support for Davinci and Keystone I2C controller config SYS_I2C_DW - bool "Designware I2C Controller" - default n - help - Say yes here to select the Designware I2C Host Controller. This - controller is used in various SoCs, e.g. the ST SPEAr, Altera - SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. + bool "Designware I2C Controller" + default n + help + Say yes here to select the Designware I2C Host Controller. This + controller is used in various SoCs, e.g. the ST SPEAr, Altera + SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED - bool "DW I2C Enable Status Register not supported" - depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ - TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) - default y - help - Some versions of the Designware I2C controller do not support the - enable status register. This config option can be enabled in such - cases. + bool "DW I2C Enable Status Register not supported" + depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ + TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) + default y + help + Some versions of the Designware I2C controller do not support the + enable status register. This config option can be enabled in such + cases. config SYS_I2C_ASPEED - bool "Aspeed I2C Controller" - depends on DM_I2C && ARCH_ASPEED - help - Say yes here to select Aspeed I2C Host Controller. The driver - supports AST2500 and AST2400 controllers, but is very limited. - Only single master mode is supported and only byte-by-byte - synchronous reads and writes are supported, no Pool Buffers or DMA. + bool "Aspeed I2C Controller" + depends on DM_I2C && ARCH_ASPEED + help + Say yes here to select Aspeed I2C Host Controller. The driver + supports AST2500 and AST2400 controllers, but is very limited. + Only single master mode is supported and only byte-by-byte + synchronous reads and writes are supported, no Pool Buffers or DMA. config SYS_I2C_INTEL - bool "Intel I2C/SMBUS driver" - depends on DM_I2C - help - Add support for the Intel SMBUS driver. So far this driver is just - a stub which perhaps some basic init. There is no implementation of - the I2C API meaning that any I2C operations will immediately fail - for now. + bool "Intel I2C/SMBUS driver" + depends on DM_I2C + help + Add support for the Intel SMBUS driver. So far this driver is just + a stub which perhaps some basic init. There is no implementation of + the I2C API meaning that any I2C operations will immediately fail + for now. config SYS_I2C_IMX_LPI2C - bool "NXP i.MX LPI2C driver" - help - Add support for the NXP i.MX LPI2C driver. + bool "NXP i.MX LPI2C driver" + help + Add support for the NXP i.MX LPI2C driver. config SYS_I2C_MESON - bool "Amlogic Meson I2C driver" - depends on DM_I2C && ARCH_MESON - help - Add support for the I2C controller available in Amlogic Meson - SoCs. The controller supports programmable bus speed including - standard (100kbits/s) and fast (400kbit/s) speed and allows the - software to define a flexible format of the bit streams. It has an - internal buffer holding up to 8 bytes for transfers and supports - both 7-bit and 10-bit addresses. + bool "Amlogic Meson I2C driver" + depends on DM_I2C && ARCH_MESON + help + Add support for the I2C controller available in Amlogic Meson + SoCs. The controller supports programmable bus speed including + standard (100kbits/s) and fast (400kbit/s) speed and allows the + software to define a flexible format of the bit streams. It has an + internal buffer holding up to 8 bytes for transfers and supports + both 7-bit and 10-bit addresses. config SYS_I2C_MXC - bool "NXP MXC I2C driver" - help - Add support for the NXP I2C driver. This supports up to four bus - channels and operating on standard mode up to 100 kbits/s and fast - mode up to 400 kbits/s. + bool "NXP MXC I2C driver" + help + Add support for the NXP I2C driver. This supports up to four bus + channels and operating on standard mode up to 100 kbits/s and fast + mode up to 400 kbits/s. # These settings are not used with DM_I2C, however SPL doesn't use # DM_I2C even if DM_I2C is enabled, and so might use these settings even # when main u-boot does not! if SYS_I2C_MXC && (!DM_I2C || SPL) config SYS_I2C_MXC_I2C1 - bool "NXP MXC I2C1" - help - Add support for NXP MXC I2C Controller 1. - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A + bool "NXP MXC I2C1" + help + Add support for NXP MXC I2C Controller 1. + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C2 - bool "NXP MXC I2C2" - help - Add support for NXP MXC I2C Controller 2. - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A + bool "NXP MXC I2C2" + help + Add support for NXP MXC I2C Controller 2. + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C3 - bool "NXP MXC I2C3" - help - Add support for NXP MXC I2C Controller 3. - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A + bool "NXP MXC I2C3" + help + Add support for NXP MXC I2C Controller 3. + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C4 - bool "NXP MXC I2C4" - help - Add support for NXP MXC I2C Controller 4. - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A + bool "NXP MXC I2C4" + help + Add support for NXP MXC I2C Controller 4. + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C5 - bool "NXP MXC I2C5" - help - Add support for NXP MXC I2C Controller 5. - Required for SoCs which have I2C MXC controller 5 eg LX2160A + bool "NXP MXC I2C5" + help + Add support for NXP MXC I2C Controller 5. + Required for SoCs which have I2C MXC controller 5 eg LX2160A config SYS_I2C_MXC_I2C6 - bool "NXP MXC I2C6" - help - Add support for NXP MXC I2C Controller 6. - Required for SoCs which have I2C MXC controller 6 eg LX2160A + bool "NXP MXC I2C6" + help + Add support for NXP MXC I2C Controller 6. + Required for SoCs which have I2C MXC controller 6 eg LX2160A config SYS_I2C_MXC_I2C7 - bool "NXP MXC I2C7" - help - Add support for NXP MXC I2C Controller 7. - Required for SoCs which have I2C MXC controller 7 eg LX2160A + bool "NXP MXC I2C7" + help + Add support for NXP MXC I2C Controller 7. + Required for SoCs which have I2C MXC controller 7 eg LX2160A config SYS_I2C_MXC_I2C8 - bool "NXP MXC I2C8" - help - Add support for NXP MXC I2C Controller 8. - Required for SoCs which have I2C MXC controller 8 eg LX2160A + bool "NXP MXC I2C8" + help + Add support for NXP MXC I2C Controller 8. + Required for SoCs which have I2C MXC controller 8 eg LX2160A endif if SYS_I2C_MXC_I2C1 config SYS_MXC_I2C1_SPEED - int "I2C Channel 1 speed" - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU - default 100000 - help - MXC I2C Channel 1 speed + int "I2C Channel 1 speed" + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU + default 100000 + help + MXC I2C Channel 1 speed config SYS_MXC_I2C1_SLAVE - int "I2C1 Slave" - default 0 - help - MXC I2C1 Slave + int "I2C1 Slave" + default 0 + help + MXC I2C1 Slave endif if SYS_I2C_MXC_I2C2 config SYS_MXC_I2C2_SPEED - int "I2C Channel 2 speed" - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU - default 100000 - help - MXC I2C Channel 2 speed + int "I2C Channel 2 speed" + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU + default 100000 + help + MXC I2C Channel 2 speed config SYS_MXC_I2C2_SLAVE - int "I2C2 Slave" - default 0 - help - MXC I2C2 Slave + int "I2C2 Slave" + default 0 + help + MXC I2C2 Slave endif if SYS_I2C_MXC_I2C3 config SYS_MXC_I2C3_SPEED - int "I2C Channel 3 speed" - default 100000 - help - MXC I2C Channel 3 speed + int "I2C Channel 3 speed" + default 100000 + help + MXC I2C Channel 3 speed config SYS_MXC_I2C3_SLAVE - int "I2C3 Slave" - default 0 - help - MXC I2C3 Slave + int "I2C3 Slave" + default 0 + help + MXC I2C3 Slave endif if SYS_I2C_MXC_I2C4 config SYS_MXC_I2C4_SPEED - int "I2C Channel 4 speed" - default 100000 - help - MXC I2C Channel 4 speed + int "I2C Channel 4 speed" + default 100000 + help + MXC I2C Channel 4 speed config SYS_MXC_I2C4_SLAVE - int "I2C4 Slave" - default 0 - help - MXC I2C4 Slave + int "I2C4 Slave" + default 0 + help + MXC I2C4 Slave endif if SYS_I2C_MXC_I2C5 config SYS_MXC_I2C5_SPEED - int "I2C Channel 5 speed" - default 100000 - help - MXC I2C Channel 5 speed + int "I2C Channel 5 speed" + default 100000 + help + MXC I2C Channel 5 speed config SYS_MXC_I2C5_SLAVE - int "I2C5 Slave" - default 0 - help - MXC I2C5 Slave + int "I2C5 Slave" + default 0 + help + MXC I2C5 Slave endif if SYS_I2C_MXC_I2C6 config SYS_MXC_I2C6_SPEED - int "I2C Channel 6 speed" - default 100000 - help - MXC I2C Channel 6 speed + int "I2C Channel 6 speed" + default 100000 + help + MXC I2C Channel 6 speed config SYS_MXC_I2C6_SLAVE - int "I2C6 Slave" - default 0 - help - MXC I2C6 Slave + int "I2C6 Slave" + default 0 + help + MXC I2C6 Slave endif if SYS_I2C_MXC_I2C7 config SYS_MXC_I2C7_SPEED - int "I2C Channel 7 speed" - default 100000 - help - MXC I2C Channel 7 speed + int "I2C Channel 7 speed" + default 100000 + help + MXC I2C Channel 7 speed config SYS_MXC_I2C7_SLAVE - int "I2C7 Slave" - default 0 - help - MXC I2C7 Slave + int "I2C7 Slave" + default 0 + help + MXC I2C7 Slave endif if SYS_I2C_MXC_I2C8 config SYS_MXC_I2C8_SPEED - int "I2C Channel 8 speed" - default 100000 - help - MXC I2C Channel 8 speed + int "I2C Channel 8 speed" + default 100000 + help + MXC I2C Channel 8 speed config SYS_MXC_I2C8_SLAVE - int "I2C8 Slave" - default 0 - help - MXC I2C8 Slave + int "I2C8 Slave" + default 0 + help + MXC I2C8 Slave endif config SYS_I2C_OMAP24XX - bool "TI OMAP2+ I2C driver" - depends on ARCH_OMAP2PLUS || ARCH_K3 - help - Add support for the OMAP2+ I2C driver. + bool "TI OMAP2+ I2C driver" + depends on ARCH_OMAP2PLUS || ARCH_K3 + help + Add support for the OMAP2+ I2C driver. if SYS_I2C_OMAP24XX config SYS_OMAP24_I2C_SLAVE - int "I2C Slave addr channel 0" - default 1 - help - OMAP24xx I2C Slave address channel 0 + int "I2C Slave addr channel 0" + default 1 + help + OMAP24xx I2C Slave address channel 0 config SYS_OMAP24_I2C_SPEED - int "I2C Slave channel 0 speed" - default 100000 - help - OMAP24xx Slave speed channel 0 + int "I2C Slave channel 0 speed" + default 100000 + help + OMAP24xx Slave speed channel 0 endif config SYS_I2C_RCAR_I2C - bool "Renesas RCar I2C driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C - help - Support for Renesas RCar I2C controller. + bool "Renesas RCar I2C driver" + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + help + Support for Renesas RCar I2C controller. config SYS_I2C_RCAR_IIC - bool "Renesas RCar Gen3 IIC driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C - help - Support for Renesas RCar Gen3 IIC controller. + bool "Renesas RCar Gen3 IIC driver" + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + help + Support for Renesas RCar Gen3 IIC controller. config SYS_I2C_ROCKCHIP - bool "Rockchip I2C driver" - depends on DM_I2C - help - Add support for the Rockchip I2C driver. This is used with various - Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips - have several I2C ports and all are provided, controlled by the - device tree. + bool "Rockchip I2C driver" + depends on DM_I2C + help + Add support for the Rockchip I2C driver. This is used with various + Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips + have several I2C ports and all are provided, controlled by the + device tree. config SYS_I2C_SANDBOX - bool "Sandbox I2C driver" - depends on SANDBOX && DM_I2C - help - Enable I2C support for sandbox. This is an emulation of a real I2C - bus. Devices can be attached to the bus using the device tree - which specifies the driver to use. See sandbox.dts as an example. + bool "Sandbox I2C driver" + depends on SANDBOX && DM_I2C + help + Enable I2C support for sandbox. This is an emulation of a real I2C + bus. Devices can be attached to the bus using the device tree + which specifies the driver to use. See sandbox.dts as an example. config SYS_I2C_S3C24X0 - bool "Samsung I2C driver" - depends on ARCH_EXYNOS4 && DM_I2C - help - Support for Samsung I2C controller as Samsung SoCs. + bool "Samsung I2C driver" + depends on ARCH_EXYNOS4 && DM_I2C + help + Support for Samsung I2C controller as Samsung SoCs. config SYS_I2C_STM32F7 - bool "STMicroelectronics STM32F7 I2C support" - depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C - help - Enable this option to add support for STM32 I2C controller - introduced with STM32F7/H7 SoCs. This I2C controller supports : - _ Slave and master modes - _ Multimaster capability - _ Standard-mode (up to 100 kHz) - _ Fast-mode (up to 400 kHz) - _ Fast-mode Plus (up to 1 MHz) - _ 7-bit and 10-bit addressing mode - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) - _ All 7-bit addresses acknowledge mode - _ General call - _ Programmable setup and hold times - _ Easy to use event management - _ Optional clock stretching - _ Software reset + bool "STMicroelectronics STM32F7 I2C support" + depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C + help + Enable this option to add support for STM32 I2C controller + introduced with STM32F7/H7 SoCs. This I2C controller supports : + _ Slave and master modes + _ Multimaster capability + _ Standard-mode (up to 100 kHz) + _ Fast-mode (up to 400 kHz) + _ Fast-mode Plus (up to 1 MHz) + _ 7-bit and 10-bit addressing mode + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) + _ All 7-bit addresses acknowledge mode + _ General call + _ Programmable setup and hold times + _ Easy to use event management + _ Optional clock stretching + _ Software reset config SYS_I2C_TEGRA - bool "NVIDIA Tegra internal I2C controller" - depends on TEGRA - help - Support for NVIDIA I2C controller available in Tegra SoCs. + bool "NVIDIA Tegra internal I2C controller" + depends on TEGRA + help + Support for NVIDIA I2C controller available in Tegra SoCs. config SYS_I2C_UNIPHIER - bool "UniPhier I2C driver" - depends on ARCH_UNIPHIER && DM_I2C - default y - help - Support for UniPhier I2C controller driver. This I2C controller - is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. + bool "UniPhier I2C driver" + depends on ARCH_UNIPHIER && DM_I2C + default y + help + Support for UniPhier I2C controller driver. This I2C controller + is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. config SYS_I2C_UNIPHIER_F - bool "UniPhier FIFO-builtin I2C driver" - depends on ARCH_UNIPHIER && DM_I2C - default y - help - Support for UniPhier FIFO-builtin I2C controller driver. - This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. + bool "UniPhier FIFO-builtin I2C driver" + depends on ARCH_UNIPHIER && DM_I2C + default y + help + Support for UniPhier FIFO-builtin I2C controller driver. + This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. config SYS_I2C_VERSATILE - bool "Arm Ltd Versatile I2C bus driver" - depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) - help - Add support for the Arm Ltd Versatile Express I2C driver. The I2C host - controller is present in the development boards manufactured by Arm Ltd. + bool "Arm Ltd Versatile I2C bus driver" + depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) + help + Add support for the Arm Ltd Versatile Express I2C driver. The I2C host + controller is present in the development boards manufactured by Arm Ltd. config SYS_I2C_MVTWSI - bool "Marvell I2C driver" - depends on DM_I2C - help - Support for Marvell I2C controllers as used on the orion5x and - kirkwood SoC families. + bool "Marvell I2C driver" + depends on DM_I2C + help + Support for Marvell I2C controllers as used on the orion5x and + kirkwood SoC families. config TEGRA186_BPMP_I2C - bool "Enable Tegra186 BPMP-based I2C driver" - depends on TEGRA186_BPMP - help - Support for Tegra I2C controllers managed by the BPMP (Boot and - Power Management Processor). On Tegra186, some I2C controllers are - directly controlled by the main CPU, whereas others are controlled - by the BPMP, and can only be accessed by the main CPU via IPC - requests to the BPMP. This driver covers the latter case. + bool "Enable Tegra186 BPMP-based I2C driver" + depends on TEGRA186_BPMP + help + Support for Tegra I2C controllers managed by the BPMP (Boot and + Power Management Processor). On Tegra186, some I2C controllers are + directly controlled by the main CPU, whereas others are controlled + by the BPMP, and can only be accessed by the main CPU via IPC + requests to the BPMP. This driver covers the latter case. config SYS_I2C_BUS_MAX - int "Max I2C busses" - depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA - default 2 if TI816X - default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE - default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X - default 5 if OMAP54XX - help - Define the maximum number of available I2C buses. + int "Max I2C busses" + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA + default 2 if TI816X + default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE + default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X + default 5 if OMAP54XX + help + Define the maximum number of available I2C buses. config SYS_I2C_XILINX_XIIC - bool "Xilinx AXI I2C driver" - depends on DM_I2C - help - Support for Xilinx AXI I2C controller. + bool "Xilinx AXI I2C driver" + depends on DM_I2C + help + Support for Xilinx AXI I2C controller. config SYS_I2C_IHS bool "gdsys IHS I2C driver" diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c2f75d8755..7cfe68e088 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -38,5 +38,5 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o - +obj-$(CONFIG_IPROC_I2C) += iproc_i2c.o obj-$(CONFIG_I2C_MUX) += muxes/ diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c new file mode 100644 index 0000000000..692035666c --- /dev/null +++ b/drivers/i2c/iproc_i2c.c @@ -0,0 +1,765 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C)) 2018 Broadcom + */ + +#include +#include +#include +#include +#include +#include "errno.h" +#include "iproc_i2c.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int i2c_init_done; + +struct iproc_i2c_regs { + u32 cfg_reg; + u32 timg_cfg; + u32 addr_reg; + u32 mstr_fifo_ctrl; + u32 slv_fifo_ctrl; + u32 bitbng_ctrl; + u32 blnks[6]; /* Not to be used */ + u32 mstr_cmd; + u32 slv_cmd; + u32 evt_en; + u32 evt_sts; + u32 mstr_datawr; + u32 mstr_datard; + u32 slv_datawr; + u32 slv_datard; +}; + +struct iproc_i2c { + struct iproc_i2c_regs __iomem *base; /* register base */ + int bus_speed; +}; + +/* Function to read a value from specified register. */ +static unsigned int iproc_i2c_reg_read(u32 *reg_addr) +{ + unsigned int val; + + val = readl((void *)(reg_addr)); + return cpu_to_le32(val); +} + +/* Function to write a value ('val') in to a specified register. */ +static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val) +{ + val = cpu_to_le32(val); + writel(val, (void *)(reg_addr)); + return 0; +} + +#ifdef IPROC_I2C_DBG +static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + debug("\n----------------------------------------------\n"); + debug("%s: Dumping SMBus registers...\n", __func__); + + regval = iproc_i2c_reg_read(&base->cfg_reg); + debug("CCB_SMB_CFG_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->timg_cfg); + debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->addr_reg); + debug("CCB_SMB_ADDR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl); + debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl); + debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->bitbng_ctrl); + debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_cmd); + debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->evt_en); + debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->evt_sts); + debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_datawr); + debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_datard); + debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_datawr); + debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_datard); + debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval); + + debug("----------------------------------------------\n\n"); + return 0; +} +#endif + +/* + * Function to ensure that the previous transaction was completed before + * initiating a new transaction. It can also be used in polling mode to + * check status of completion of a command + */ +static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + /* Check if an operation is in progress. During probe it won't be. + * But when shutdown/remove was called we want to make sure that + * the transaction in progress completed + */ + if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + unsigned int i = 0; + + do { + mdelay(10); /* Wait for 10 msec */ + i++; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + /* If start-busy bit cleared, exit the loop */ + } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) && + (i < IPROC_SMB_MAX_RETRIES)); + + if (i >= IPROC_SMB_MAX_RETRIES) { + pr_err("%s: START_BUSY bit didn't clear, exiting\n", + __func__); + + return -ETIMEDOUT; + } + } + return 0; +} + +/* + * This function set clock frequency for SMBus block. As per hardware + * engineering, the clock frequency can be changed dynamically. + */ +static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + regval = iproc_i2c_reg_read(&base->timg_cfg); + + switch (bus_prvdata->bus_speed) { + case I2C_SPEED_100KHZ: + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_100, + CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + break; + + case I2C_SPEED_400KHZ: + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_400, + CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + break; + + default: + return -EINVAL; + } + + iproc_i2c_reg_write(&base->timg_cfg, regval); + return 0; +} + +static int iproc_i2c_init(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + +#ifdef IPROC_I2C_DBG + debug("\n%s: Entering", __func__); +#endif /* IPROC_I2C_DBG */ + + /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0. + * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts + */ + regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK; + iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval); + + /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero + * since there will be only one master + */ + + regval = iproc_i2c_reg_read(&base->cfg_reg); + regval |= CCB_SMB_CFG_SMBEN_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + regval = iproc_i2c_reg_read(&base->cfg_reg); + regval |= CCB_SMB_CFG_RST_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); + regval &= ~CCB_SMB_CFG_RST_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); +#endif + /* Wait a minimum of 50 Usec, as per SMB hw doc */ + udelay(50); + + /* Set default clock frequency */ + iproc_i2c_set_clk_freq(bus_prvdata); + + /* Disable intrs */ + iproc_i2c_reg_write(&base->evt_en, 0); + + /* Clear intrs (W1TC) */ + regval = iproc_i2c_reg_read(&base->evt_sts); + iproc_i2c_reg_write(&base->evt_sts, regval); + + i2c_init_done = 1; + +#ifdef IPROC_I2C_DBG + iproc_dump_i2c_regs(bus_prvdata); + + debug("%s: Init successful\n", __func__); +#endif /* IPROC_I2C_DBG */ + + return 0; +} + +/* + * This function copies data to SMBus's Tx FIFO. Valid for write transactions + * only + * + * base_addr: Mapped address of this SMBus instance + * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses + * initially + * info: Data to copy in to Tx FIFO. For read commands, the size should be + * set to zero by the caller + * + */ +static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata, + unsigned short dev_addr, + struct iproc_xact_info *info) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + unsigned int i; + unsigned int num_data_bytes = 0; + +#ifdef IPROC_I2C_DBG + debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d\n" + "buf[] %x\n", + __func__, + dev_addr, + info->cmd_valid, + info->command, + info->size, + info->smb_proto, + info->data[0]); +#endif /* IPROC_I2C_DBG */ + + /* Write SMBus device address first */ + /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses, + * we may have one more write to send the upper 3 bits of 10-bit addr + */ + iproc_i2c_reg_write(&base->mstr_datawr, dev_addr); + + /* If the protocol needs command code, copy it */ + if (info->cmd_valid) + iproc_i2c_reg_write(&base->mstr_datawr, info->command); + + /* Depending on the SMBus protocol, we need to write additional + * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus + * spec for sequence for a transaction + */ + switch (info->smb_proto) { + case SMBUS_PROT_RECV_BYTE: + /* No additional data to be written */ + num_data_bytes = 0; + break; + + case SMBUS_PROT_SEND_BYTE: + num_data_bytes = info->size; + break; + + case SMBUS_PROT_RD_BYTE: + case SMBUS_PROT_RD_WORD: + case SMBUS_PROT_BLK_RD: + /* Write slave address with R/W~ set (bit #0) */ + iproc_i2c_reg_write(&base->mstr_datawr, + dev_addr | 0x1); + num_data_bytes = 0; + break; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL: + iproc_i2c_reg_write(&base->mstr_datawr, + dev_addr | 0x1 | + CCB_SMB_MSTRWRSTS_MASK); + num_data_bytes = 0; + break; +#endif + case SMBUS_PROT_WR_BYTE: + case SMBUS_PROT_WR_WORD: + /* No additional bytes to be written. + * Data portion is written in the + * 'for' loop below + */ + num_data_bytes = info->size; + break; + + case SMBUS_PROT_BLK_WR: + /* 3rd byte is byte count */ + iproc_i2c_reg_write(&base->mstr_datawr, info->size); + num_data_bytes = info->size; + break; + + default: + break; + } + + /* Copy actual data from caller, next. In general, for reads, no data is + * copied + */ + for (i = 0; num_data_bytes; --num_data_bytes, i++) { + /* For the last byte, set MASTER_WR_STATUS bit */ + regval = (num_data_bytes == 1) ? + info->data[i] | CCB_SMB_MSTRWRSTS_MASK : + info->data[i]; + + iproc_i2c_reg_write(&base->mstr_datawr, regval); + } +} + +static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata, + unsigned short addr, + struct iproc_xact_info *info) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + int rc, retry = 3; unsigned int regval; + + /* Make sure the previous transaction completed */ + rc = iproc_i2c_startbusy_wait(bus_prvdata); + + if (rc < 0) { + pr_err("%s: Send: bus is busy, exiting\n", __func__); + return rc; + } + + /* Write transaction bytes to Tx FIFO */ + iproc_i2c_write_trans_data(bus_prvdata, addr, info); + + /* Program master command register (0x30) with protocol type and set + * start_busy_command bit to initiate the write transaction + */ + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + CCB_SMB_MSTRSTARTBUSYCMD_MASK; + + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + /* Check for Master status */ + regval = iproc_i2c_reg_read(&base->mstr_cmd); + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + mdelay(10); + if (retry-- <= 0) + break; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + } + + /* If start_busy bit cleared, check if there are any errors */ + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { + /* start_busy bit cleared, check master_status field now */ + regval &= CCB_SMB_MSTRSTS_MASK; + regval >>= CCB_SMB_MSTRSTS_SHIFT; + + if (regval != MSTR_STS_XACT_SUCCESS) { + /* Error We can flush Tx FIFO here */ + pr_err("%s: ERROR: Error in transaction %u, exiting\n", + __func__, regval); + return -EREMOTEIO; + } + } + + return 0; +} + +static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata, + unsigned short addr, + struct iproc_xact_info *info, + unsigned int *num_bytes_read) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + int rc, retry = 3; + unsigned int regval; + + /* Make sure the previous transaction completed */ + rc = iproc_i2c_startbusy_wait(bus_prvdata); + + if (rc < 0) { + pr_err("%s: Receive: Bus is busy, exiting\n", __func__); + return rc; + } + + /* Program all transaction bytes into master Tx FIFO */ + iproc_i2c_write_trans_data(bus_prvdata, addr, info); + + /* Program master command register (0x30) with protocol type and set + * start_busy_command bit to initiate the write transaction + */ + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; + + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + /* Check for Master status */ + regval = iproc_i2c_reg_read(&base->mstr_cmd); + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + udelay(1000); + if (retry-- <= 0) + break; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + } + + /* If start_busy bit cleared, check if there are any errors */ + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { + /* start_busy bit cleared, check master_status field now */ + regval &= CCB_SMB_MSTRSTS_MASK; + regval >>= CCB_SMB_MSTRSTS_SHIFT; + + if (regval != MSTR_STS_XACT_SUCCESS) { + /* We can flush Tx FIFO here */ + pr_err("%s: Error in transaction %d, exiting\n", + __func__, regval); + return -EREMOTEIO; + } + } + + /* Read received byte(s), after TX out address etc */ + regval = iproc_i2c_reg_read(&base->mstr_datard); + + /* For block read, protocol (hw) returns byte count, + * as the first byte + */ + if (info->smb_proto == SMBUS_PROT_BLK_RD) { + int i; + + *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; + + /* Limit to reading a max of 32 bytes only; just a safeguard. + * If # bytes read is a number > 32, check transaction set up, + * and contact hw engg. Assumption: PEC is disabled + */ + for (i = 0; + (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); + i++) { + /* Read Rx FIFO for data bytes */ + regval = iproc_i2c_reg_read(&base->mstr_datard); + info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; + } + } else { + /* 1 Byte data */ + *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; + *num_bytes_read = 1; + } + + return 0; +} + +static int i2c_write_byte(struct iproc_i2c *bus_prvdata, + u8 devaddr, + u8 regoffset, + u8 value) +{ + int rc; + struct iproc_xact_info info; + + devaddr <<= 1; + + info.cmd_valid = 1; + info.command = (unsigned char)regoffset; + info.data = &value; + info.size = 1; + info.flags = 0; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + info.smb_proto = SMBUS_PROT_WR_WORD;/*SMBUS_PROT_WR_BYTE;*/ +#else + info.smb_proto = SMBUS_PROT_WR_BYTE; +#endif + /* Refer to i2c_smbus_write_byte params passed. */ + rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info); + + if (rc < 0) { + pr_err("%s: %s error accessing device 0x%X\n", + __func__, "Write", devaddr); + return -EREMOTEIO; + } + + return 0; +} + +int i2c_write(struct iproc_i2c *bus_prvdata, + uchar chip, + uint regaddr, + int alen, + uchar *buffer, + int len) +{ + int i, data_len; + u8 *data; + + if (alen > 1) { + pr_err("I2C write: addr len %d not supported\n", alen); + return 1; + } + + if (regaddr + len > 256) { + pr_err("I2C write: address out of range\n"); + return 1; + } + + if (len < 1) { + pr_err("I2C write: Need offset addr and value\n"); + return 1; + } + + /* buffer contains offset addr followed by value to be written */ + regaddr = buffer[0]; + data = &buffer[1]; + data_len = len - 1; + + for (i = 0; i < data_len; i++) { + if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) { + pr_err("I2C write (%d): I/O error\n", i); + iproc_i2c_init(bus_prvdata); + return 1; + } + } + + return 0; +} + +static int i2c_read_byte(struct iproc_i2c *bus_prvdata, + u8 devaddr, + u8 regoffset, + u8 *value) +{ + int rc; + struct iproc_xact_info info; + unsigned int num_bytes_read = 0; + + devaddr <<= 1; + + info.cmd_valid = 1; + info.command = (unsigned char)regoffset; + info.data = value; + info.size = 1; + info.flags = 0; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL; +#else + info.smb_proto = SMBUS_PROT_RD_BYTE; +#endif + /* Refer to i2c_smbus_read_byte for params passed. */ + rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read); + + if (rc < 0) { + pr_err("%s: %s error accessing device 0x%X\n", + __func__, "Read", devaddr); + return -EREMOTEIO; + } + + return 0; +} + +int i2c_read(struct iproc_i2c *bus_prvdata, + uchar chip, + uint addr, + int alen, + uchar *buffer, + int len) +{ + int i; + + if (alen > 1) { + pr_err("I2C read: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + pr_err("I2C read: address out of range\n"); + return 1; + } + + for (i = 0; i < len; i++) { + if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) { + pr_err("I2C read: I/O error\n"); + iproc_i2c_init(bus_prvdata); + return 1; + } + } + + return 0; +} + +static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + int ret = 0; + +#ifdef IPROC_I2C_DBG + debug("%s: %d messages\n", __func__, nmsgs); +#endif + + for (; nmsgs > 0; nmsgs--, msg++) { + if (msg->flags & I2C_M_RD) + ret = i2c_read(bus_prvdata, + msg->addr, + 0, + 0, + msg->buf, + msg->len); + else + ret = i2c_write(bus_prvdata, + msg->addr, + 0, + 0, + msg->buf, + msg->len); + } + + return ret; +} + +static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + struct iproc_i2c_regs *base = bus_prvdata->base; + u32 regval; + +#ifdef IPROC_I2C_DBG + debug("\n%s: Entering chip probe\n", __func__); +#endif /* IPROC_I2C_DBG */ + + /* Init internal regs, disable intrs (and then clear intrs), set fifo + * thresholds, etc. + */ + if (!i2c_init_done) + iproc_i2c_init(bus_prvdata); + + regval = (chip_addr << 1); + iproc_i2c_reg_write(&base->mstr_datawr, regval); + regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT)); + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + do { + udelay(100); + regval = iproc_i2c_reg_read(&base->mstr_cmd); + regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK; + } while (regval); + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + if ((regval & CCB_SMB_MSTRSTS_MASK) != 0) + return -1; + +#ifdef IPROC_I2C_DBG + iproc_dump_i2c_regs(bus_prvdata); + + debug("%s: chip probe successful\n", __func__); +#endif /* IPROC_I2C_DBG */ + + return 0; +} + +static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + + bus_prvdata->bus_speed = speed; + if (iproc_i2c_set_clk_freq(bus_prvdata)) + return -EINVAL; + + return 0; +} + +/** + * i2c_get_bus_speed - get i2c bus speed + * + * This function returns the speed of operation in Hz + */ +int iproc_i2c_get_bus_speed(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + unsigned int val; + + regval = iproc_i2c_reg_read(&base->timg_cfg); + val = GETREGFLDVAL(regval, CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + switch (val) { + case 0: + return I2C_SPEED_100KHZ; + case 1: + return I2C_SPEED_400KHZ; + default: + return -EINVAL; + } + return -EINVAL; +} + +static int iproc_i2c_probe(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + + return iproc_i2c_init(bus_prvdata); +} + +static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + int node = dev_of_offset(bus); + const void *blob = gd->fdt_blob; + + bus_prvdata->base = map_physmem(devfdt_get_addr(bus), + sizeof(void *), + MAP_NOCACHE); + + /* default 100KHz freq */ + bus_prvdata->bus_speed = fdtdec_get_int(blob, node, "bus-frequency", + I2C_SPEED_100KHZ); + + return 0; +} + +static const struct dm_i2c_ops iproc_i2c_ops = { + .xfer = iproc_i2c_xfer, + .probe_chip = iproc_i2c_probe_chip, + .set_bus_speed = iproc_i2c_set_bus_speed, + .get_bus_speed = iproc_i2c_get_bus_speed, +}; + +static const struct udevice_id iproc_i2c_ids[] = { + { .compatible = "brcm,iproc-i2c" }, + { } +}; + +U_BOOT_DRIVER(iproc_i2c) = { + .name = "iproc_i2c", + .id = UCLASS_I2C, + .of_match = iproc_i2c_ids, + .ofdata_to_platdata = iproc_i2c_ofdata_to_platdata, + .probe = iproc_i2c_probe, + .priv_auto_alloc_size = sizeof(struct iproc_i2c), + .ops = &iproc_i2c_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/i2c/iproc_i2c.h b/drivers/i2c/iproc_i2c.h new file mode 100644 index 0000000000..4f8d6ba2b2 --- /dev/null +++ b/drivers/i2c/iproc_i2c.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (C) 2018 Broadcom */ + +#ifndef __IPROC_I2C_H__ +#define __IPROC_I2C_H__ + +#if (defined(CONFIG_NS_PLUS) || defined(CONFIG_HELIX4)) +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 +#define IPROC_SMBUS_BASE_ADDR1 0x18038000 +#define IPROC_SMBUS_BASE_ADDR2 0x1803B000 +#elif (defined(CONFIG_CYGNUS)) +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 +#define IPROC_SMBUS_BASE_ADDR1 0x18008000 +#define IPROC_SMBUS_BASE_ADDR2 0x1800B000 +#endif + +/* Registers */ +#define CCB_SMB_CFG_REG 0x0 + +#define CCB_SMB_CFG_RST_MASK 0x80000000 +#define CCB_SMB_CFG_RST_SHIFT 31 + +#define CCB_SMB_CFG_SMBEN_MASK 0x40000000 +#define CCB_SMB_CFG_SMBEN_SHIFT 30 + +#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000 +#define CCB_SMB_CFG_BITBANGEN_SHIFT 29 + +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000 +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28 + +#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000 +#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27 + +#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000 +#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26 + +#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000 +#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16 + +#define CCB_SMB_TIMGCFG_REG 0x4 + +#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000 +#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31 + +#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000 +#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24 + +#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000 +#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16 + +#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00 +#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8 + +#define CCB_SMB_ADDR_REG 0x8 + +#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000 +#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31 + +#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000 +#define CCB_SMB_NIC_SMBADDR3_SHIFT 24 + +#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000 +#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23 + +#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000 +#define CCB_SMB_NIC_SMBADDR2_SHIFT 16 + +#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000 +#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15 + +#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00 +#define CCB_SMB_NIC_SMBADDR1_SHIFT 8 + +#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080 +#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7 + +#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F +#define CCB_SMB_NIC_SMBADDR0_SHIFT 0 + +#define CCB_SMB_MSTRFIFOCTL_REG 0xC + +#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31 + +#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000 +#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30 + +#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000 +#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16 + +#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00 +#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8 + +#define CCB_SMB_SLVFIFOCTL_REG 0x10 + +#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000 +#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31 + +#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000 +#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30 + +#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000 +#define CCB_SMB_SLVRXPKTCNT_SHIFT 16 + +#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00 +#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8 + +#define CCB_SMB_BITBANGCTL_REG 0x14 + +#define CCB_SMB_SMBCLKIN_MASK 0x80000000 +#define CCB_SMB_SMBCLKIN_SHIFT 31 + +#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000 +#define CCB_SMB_SMBCLKOUTEN_SHIFT 30 + +#define CCB_SMB_SMBDATAIN_MASK 0x20000000 +#define CCB_SMB_SMBDATAIN_SHIFT 29 + +#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000 +#define CCB_SMB_SMBDATAOUTEN_SHIFT 28 + +#define CCB_SMB_MSTRCMD_REG 0x30 + +#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000 +#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31 + +#define CCB_SMB_MSTRABORT_MASK 0x40000000 +#define CCB_SMB_MSTRABORT_SHIFT 30 + +#define CCB_SMB_MSTRSTS_MASK 0x0E000000 +#define CCB_SMB_MSTRSTS_SHIFT 25 + +#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00 +#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9 + +#define CCB_SMB_MSTRPEC_MASK 0x00000100 +#define CCB_SMB_MSTRPEC_SHIFT 8 + +#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF +#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0 + +#define CCB_SMB_SLVCMD_REG 0x34 + +#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000 +#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31 + +#define CCB_SMB_SLVABORT_MASK 0x40000000 +#define CCB_SMB_SLVABORT_SHIFT 30 + +#define CCB_SMB_SLVSTS_MASK 0x03800000 +#define CCB_SMB_SLVSTS_SHIFT 23 + +#define CCB_SMB_SLVPEC_MASK 0x00000100 +#define CCB_SMB_SLVPEC_SHIFT 8 + +#define CCB_SMB_EVTEN_REG 0x38 + +#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31 + +#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000 +#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30 + +#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000 +#define CCB_SMB_MSTRRXEVTEN_SHIFT 29 + +#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000 +#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28 + +#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000 +#define CCB_SMB_MSTRTXUNDEN_SHIFT 27 + +#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000 +#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26 + +#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000 +#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25 + +#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000 +#define CCB_SMB_SLVRXEVTEN_SHIFT 24 + +#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000 +#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23 + +#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000 +#define CCB_SMB_SLVTXUNDEN_SHIFT 22 + +#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000 +#define CCB_SMB_SLVRDEVTEN_SHIFT 21 + +#define CCB_SMB_EVTSTS_REG 0x3C + +#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31 + +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000 +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30 + +#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000 +#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29 + +#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000 +#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28 + +#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000 +#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27 + +#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000 +#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26 + +#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000 +#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25 + +#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000 +#define CCB_SMB_SLVRXEVTSTS_SHIFT 24 + +#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000 +#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23 + +#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000 +#define CCB_SMB_SLVTXUNDSTS_SHIFT 22 + +#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000 +#define CCB_SMB_SLVRDEVTSTS_SHIFT 21 + +#define CCB_SMB_MSTRDATAWR_REG 0x40 + +#define CCB_SMB_MSTRWRSTS_MASK 0x80000000 +#define CCB_SMB_MSTRWRSTS_SHIFT 31 + +#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF +#define CCB_SMB_MSTRWRDATA_SHIFT 0 + +#define CCB_SMB_MSTRDATARD_REG 0x44 + +#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000 +#define CCB_SMB_MSTRRDSTS_SHIFT 30 + +#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000 +#define CCB_SMB_MSTRRDPECERR_SHIFT 29 + +#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF +#define CCB_SMB_MSTRRDDATA_SHIFT 0 + +#define CCB_SMB_SLVDATAWR_REG 0x48 + +#define CCB_SMB_SLVWRSTS_MASK 0x80000000 +#define CCB_SMB_SLVWRSTS_SHIFT 31 + +#define CCB_SMB_SLVWRDATA_MASK 0x000000FF +#define CCB_SMB_SLVWRDATA_SHIFT 0 + +#define CCB_SMB_SLVDATARD_REG 0x4C + +#define CCB_SMB_SLVRDSTS_MASK 0xC0000000 +#define CCB_SMB_SLVRDSTS_SHIFT 30 + +#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000 +#define CCB_SMB_SLVRDERRSTS_SHIFT 28 + +#define CCB_SMB_SLVRDDATA_MASK 0x000000FF +#define CCB_SMB_SLVRDDATA_SHIFT 0 + +/* --Registers-- */ + +/* Transaction error codes defined in Master command register (0x30) */ +#define MSTR_STS_XACT_SUCCESS 0 +#define MSTR_STS_LOST_ARB 1 +#define MSTR_STS_NACK_FIRST_BYTE 2 + +/* NACK on a byte other than + * the first byte + */ +#define MSTR_STS_NACK_NON_FIRST_BYTE 3 + +#define MSTR_STS_TTIMEOUT_EXCEEDED 4 +#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5 +#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6 + +/* SMBUS protocol values defined in register 0x30 */ +#define SMBUS_PROT_QUICK_CMD 0 +#define SMBUS_PROT_SEND_BYTE 1 +#define SMBUS_PROT_RECV_BYTE 2 +#define SMBUS_PROT_WR_BYTE 3 +#define SMBUS_PROT_RD_BYTE 4 +#define SMBUS_PROT_WR_WORD 5 +#define SMBUS_PROT_RD_WORD 6 +#define SMBUS_PROT_BLK_WR 7 +#define SMBUS_PROT_BLK_RD 8 +#define SMBUS_PROT_PROC_CALL 9 +#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10 + +/* SMBUS Block speed mode */ +#define SMBUS_BLOCK_MODE_100 0 +#define SMBUS_BLOCK_MODE_400 1 + +#define BUS_BUSY_COUNT 100000 /* Number can be changed later */ +#define IPROC_I2C_INVALID_ADDR 0xFF +#define IPROC_SMB_MAX_RETRIES 35 +#define I2C_SMBUS_BLOCK_MAX 32 +#define GETREGFLDVAL(regval, mask, startbit) \ + (((regval) & (mask)) >> (startbit)) +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ + ((regval) & ~(mask)) | \ + ((fldval) << (startbit)) + +/* Enum to specify clock speed. The user will provide it during initialization + * If needed, it can be changed dynamically + */ +enum iproc_smb_clk_freq { + I2C_SPEED_100KHZ = 100000, + I2C_SPEED_400KHZ = 400000, + I2C_SPEED_INVALID = 255 +}; + +/* This enum will be used to notify the user of status of a data transfer + * request + */ +enum iproc_smb_error_code { + I2C_NO_ERR = 0, + I2C_TIMEOUT_ERR = 1, + + /* Invalid parameter(s) passed to the driver */ + I2C_INVALID_PARAM_ERR = 2, + + /* The driver API was called before the present + * transfer was completed + */ + I2C_OPER_IN_PROGRESS = 3, + + /* Transfer aborted unexpectedly, for example a NACK + * received, before last byte was read/written + */ + I2C_OPER_ABORT_ERR = 4, + + /* Feature or function not supported + * (e.g., 10-bit addresses, or clock speeds + * other than 100KHz, 400KHz) + */ + I2C_FUNC_NOT_SUPPORTED = 5, +}; + +/* Structure used to pass information to read/write functions. */ +struct iproc_xact_info { + unsigned char command; + unsigned char *data; + unsigned int size; + unsigned short flags; /* used for specifying PEC, 10-bit addresses */ + unsigned char smb_proto; /* SMBus protocol */ + unsigned int cmd_valid; /* true if command is valid else false */ +}; + +#endif /* __IPROC_I2C_H__ */