GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,465 @@
#
# I2C subsystem configuration
#
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.
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.
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.
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.
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
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
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
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.
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.
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
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.
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.
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.
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.
config SYS_I2C_IMX_LPI2C
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.
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.
# 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
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
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
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
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
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
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
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
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
config SYS_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
config SYS_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
config SYS_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
config SYS_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
config SYS_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
config SYS_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
config SYS_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
config SYS_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.
if SYS_I2C_OMAP24XX
config SYS_OMAP24_I2C_SLAVE
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
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.
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.
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.
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.
config SYS_I2C_S3C24X0
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
config SYS_I2C_TEGRA
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.
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.
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.
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.
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.
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.
config SYS_I2C_XILINX_XIIC
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"
depends on DM_I2C
help
Support for gdsys IHS I2C driver on FPGA bus.
source "drivers/i2c/muxes/Kconfig"
endmenu
@@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
obj-$(CONFIG_SYS_I2C) += i2c_core.o
obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
obj-$(CONFIG_SYS_I2C_IMX_LPI2C) += imx_lpi2c.o
obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o
obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
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_I2C_MUX) += muxes/
@@ -0,0 +1,354 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2020 ASPEED Technology Inc.
* Copyright 2016 IBM Corporation
* Copyright 2017 Google, Inc.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/scu_ast2500.h>
#include "ast_i2c.h"
#define I2C_TIMEOUT_US 100000
#define I2C_SLEEP_STEP_US 20
#define HIGHSPEED_TTIMEOUT 3
/*
* Device private data
*/
struct ast_i2c_priv {
/* This device's clock */
struct clk clk;
/* Device registers */
struct ast_i2c_regs *regs;
/* I2C speed in Hz */
int speed;
};
/*
* Given desired divider ratio, return the value that needs to be set
* in Clock and AC Timing Control register
*/
static u32 get_clk_reg_val(ulong divider_ratio)
{
ulong inc = 0, div;
ulong scl_low, scl_high, data;
for (div = 0; divider_ratio >= 16; div++) {
inc |= (divider_ratio & 1);
divider_ratio >>= 1;
}
divider_ratio += inc;
scl_low = (divider_ratio >> 1) - 1;
scl_high = divider_ratio - scl_low - 2;
data = I2CD_CACTC_BASE
| (scl_high << I2CD_TCKHIGH_SHIFT)
| (scl_low << I2CD_TCKLOW_SHIFT)
| (div << I2CD_BASE_DIV_SHIFT);
return data;
}
static void ast_i2c_clear_interrupts(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
writel(~0, &priv->regs->isr);
}
static void ast_i2c_init_bus(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
/* Reset device */
writel(0, &priv->regs->fcr);
/* Enable Master Mode. Assuming single-master */
writel(I2CD_MASTER_EN
| I2CD_M_SDA_LOCK_EN
| I2CD_MULTI_MASTER_DIS | I2CD_M_SCL_DRIVE_EN,
&priv->regs->fcr);
/* Enable Interrupts */
writel(I2CD_INTR_TX_ACK
| I2CD_INTR_TX_NAK
| I2CD_INTR_RX_DONE
| I2CD_INTR_BUS_RECOVER_DONE
| I2CD_INTR_NORMAL_STOP
| I2CD_INTR_ABNORMAL, &priv->regs->icr);
}
static int ast_i2c_ofdata_to_platdata(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
int ret;
priv->regs = devfdt_get_addr_ptr(dev);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0) {
debug("%s: Can't get clock for %s: %d\n", __func__, dev->name,
ret);
return ret;
}
return 0;
}
static int ast_i2c_probe(struct udevice *dev)
{
struct ast2500_scu *scu;
debug("Enabling I2C%u\n", dev->seq);
/*
* Get all I2C devices out of Reset.
* Only needs to be done once, but doing it for every
* device does not hurt.
*/
scu = ast_get_scu();
ast_scu_unlock(scu);
clrbits_le32(&scu->sysreset_ctrl1, SCU_SYSRESET_I2C);
ast_scu_lock(scu);
ast_i2c_init_bus(dev);
return 0;
}
static int ast_i2c_wait_isr(struct udevice *dev, u32 flag)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
int timeout = I2C_TIMEOUT_US;
while (!(readl(&priv->regs->isr) & flag) && timeout > 0) {
udelay(I2C_SLEEP_STEP_US);
timeout -= I2C_SLEEP_STEP_US;
}
ast_i2c_clear_interrupts(dev);
if (timeout <= 0)
return -ETIMEDOUT;
return 0;
}
static int ast_i2c_send_stop(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
writel(I2CD_M_STOP_CMD, &priv->regs->csr);
return ast_i2c_wait_isr(dev, I2CD_INTR_NORMAL_STOP);
}
static int ast_i2c_wait_tx(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
int timeout = I2C_TIMEOUT_US;
u32 flag = I2CD_INTR_TX_ACK | I2CD_INTR_TX_NAK;
u32 status = readl(&priv->regs->isr) & flag;
int ret = 0;
while (!status && timeout > 0) {
status = readl(&priv->regs->isr) & flag;
udelay(I2C_SLEEP_STEP_US);
timeout -= I2C_SLEEP_STEP_US;
}
if (status == I2CD_INTR_TX_NAK)
ret = -EREMOTEIO;
if (timeout <= 0)
ret = -ETIMEDOUT;
ast_i2c_clear_interrupts(dev);
return ret;
}
static int ast_i2c_start_txn(struct udevice *dev, uint devaddr)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
/* Start and Send Device Address */
writel(devaddr, &priv->regs->trbbr);
writel(I2CD_M_START_CMD | I2CD_M_TX_CMD, &priv->regs->csr);
return ast_i2c_wait_tx(dev);
}
static int ast_i2c_read_data(struct udevice *dev, u8 chip_addr, u8 *buffer,
size_t len, bool send_stop)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
u32 i2c_cmd = I2CD_M_RX_CMD;
int ret;
ret = ast_i2c_start_txn(dev, (chip_addr << 1) | I2C_M_RD);
if (ret < 0)
return ret;
for (; len > 0; len--, buffer++) {
if (len == 1)
i2c_cmd |= I2CD_M_S_RX_CMD_LAST;
writel(i2c_cmd, &priv->regs->csr);
ret = ast_i2c_wait_isr(dev, I2CD_INTR_RX_DONE);
if (ret < 0)
return ret;
*buffer = (readl(&priv->regs->trbbr) & I2CD_RX_DATA_MASK)
>> I2CD_RX_DATA_SHIFT;
}
ast_i2c_clear_interrupts(dev);
if (send_stop)
return ast_i2c_send_stop(dev);
return 0;
}
static int ast_i2c_write_data(struct udevice *dev, u8 chip_addr, u8
*buffer, size_t len, bool send_stop)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
int ret;
ret = ast_i2c_start_txn(dev, (chip_addr << 1));
if (ret < 0)
return ret;
for (; len > 0; len--, buffer++) {
writel(*buffer, &priv->regs->trbbr);
writel(I2CD_M_TX_CMD, &priv->regs->csr);
ret = ast_i2c_wait_tx(dev);
if (ret < 0)
return ret;
}
if (send_stop)
return ast_i2c_send_stop(dev);
return 0;
}
static int ast_i2c_deblock(struct udevice *dev)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
struct ast_i2c_regs *regs = priv->regs;
u32 csr = readl(&regs->csr);
bool sda_high = csr & I2CD_SDA_LINE_STS;
bool scl_high = csr & I2CD_SCL_LINE_STS;
int ret = 0;
if (sda_high && scl_high) {
/* Bus is idle, no deblocking needed. */
return 0;
} else if (sda_high) {
/* Send stop command */
debug("Unterminated TXN in (%x), sending stop\n", csr);
ret = ast_i2c_send_stop(dev);
} else if (scl_high) {
/* Possibly stuck slave */
debug("Bus stuck (%x), attempting recovery\n", csr);
writel(I2CD_BUS_RECOVER_CMD, &regs->csr);
ret = ast_i2c_wait_isr(dev, I2CD_INTR_BUS_RECOVER_DONE);
} else {
/* Just try to reinit the device. */
ast_i2c_init_bus(dev);
}
return ret;
}
static int ast_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
int ret;
ret = ast_i2c_deblock(dev);
if (ret < 0)
return ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD) {
debug("i2c_read: chip=0x%x, len=0x%x, flags=0x%x\n",
msg->addr, msg->len, msg->flags);
ret = ast_i2c_read_data(dev, msg->addr, msg->buf,
msg->len, (nmsgs == 1));
} else {
debug("i2c_write: chip=0x%x, len=0x%x, flags=0x%x\n",
msg->addr, msg->len, msg->flags);
ret = ast_i2c_write_data(dev, msg->addr, msg->buf,
msg->len, (nmsgs == 1));
}
if (ret) {
debug("%s: error (%d)\n", __func__, ret);
return -EREMOTEIO;
}
}
return 0;
}
static int ast_i2c_set_speed(struct udevice *dev, unsigned int speed)
{
struct ast_i2c_priv *priv = dev_get_priv(dev);
struct ast_i2c_regs *regs = priv->regs;
ulong i2c_rate, divider;
debug("Setting speed for I2C%d to <%u>\n", dev->seq, speed);
if (!speed) {
debug("No valid speed specified\n");
return -EINVAL;
}
i2c_rate = clk_get_rate(&priv->clk);
divider = i2c_rate / speed;
priv->speed = speed;
if (speed > I2C_HIGHSPEED_RATE) {
debug("Enable High Speed\n");
setbits_le32(&regs->fcr, I2CD_M_HIGH_SPEED_EN
| I2CD_M_SDA_DRIVE_1T_EN
| I2CD_SDA_DRIVE_1T_EN);
writel(HIGHSPEED_TTIMEOUT, &regs->cactcr2);
} else {
debug("Enabling Normal Speed\n");
writel(I2CD_NO_TIMEOUT_CTRL, &regs->cactcr2);
}
writel(get_clk_reg_val(divider), &regs->cactcr1);
ast_i2c_clear_interrupts(dev);
return 0;
}
static const struct dm_i2c_ops ast_i2c_ops = {
.xfer = ast_i2c_xfer,
.set_bus_speed = ast_i2c_set_speed,
.deblock = ast_i2c_deblock,
};
static const struct udevice_id ast_i2c_ids[] = {
{ .compatible = "aspeed,ast2400-i2c-bus" },
{ .compatible = "aspeed,ast2500-i2c-bus" },
{ },
};
U_BOOT_DRIVER(ast_i2c) = {
.name = "ast_i2c",
.id = UCLASS_I2C,
.of_match = ast_i2c_ids,
.probe = ast_i2c_probe,
.ofdata_to_platdata = ast_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct ast_i2c_priv),
.ops = &ast_i2c_ops,
};
@@ -0,0 +1,131 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2012-2020 ASPEED Technology Inc.
* Copyright 2016 IBM Corporation
* Copyright 2017 Google, Inc.
*/
#ifndef __AST_I2C_H_
#define __AST_I2C_H_
struct ast_i2c_regs {
u32 fcr;
u32 cactcr1;
u32 cactcr2;
u32 icr;
u32 isr;
u32 csr;
u32 sdar;
u32 pbcr;
u32 trbbr;
#ifdef CONFIG_ASPEED_AST2500
u32 dma_mbar;
u32 dma_tlr;
#endif
};
/* Device Register Definition */
/* 0x00 : I2CD Function Control Register */
#define I2CD_BUFF_SEL_MASK (0x7 << 20)
#define I2CD_BUFF_SEL(x) (x << 20)
#define I2CD_M_SDA_LOCK_EN (0x1 << 16)
#define I2CD_MULTI_MASTER_DIS (0x1 << 15)
#define I2CD_M_SCL_DRIVE_EN (0x1 << 14)
#define I2CD_MSB_STS (0x1 << 9)
#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8)
#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7)
#define I2CD_M_HIGH_SPEED_EN (0x1 << 6)
#define I2CD_DEF_ADDR_EN (0x1 << 5)
#define I2CD_DEF_ALERT_EN (0x1 << 4)
#define I2CD_DEF_ARP_EN (0x1 << 3)
#define I2CD_DEF_GCALL_EN (0x1 << 2)
#define I2CD_SLAVE_EN (0x1 << 1)
#define I2CD_MASTER_EN (0x1)
/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
/* Base register value. These bits are always set by the driver. */
#define I2CD_CACTC_BASE 0xfff00300
#define I2CD_TCKHIGH_SHIFT 16
#define I2CD_TCKLOW_SHIFT 12
#define I2CD_THDDAT_SHIFT 10
#define I2CD_TO_DIV_SHIFT 8
#define I2CD_BASE_DIV_SHIFT 0
/* 0x08 : I2CD Clock and AC Timing Control Register #2 */
#define I2CD_tTIMEOUT 1
#define I2CD_NO_TIMEOUT_CTRL 0
/* 0x0c : I2CD Interrupt Control Register &
* 0x10 : I2CD Interrupt Status Register
*
* These share bit definitions, so use the same values for the enable &
* status bits.
*/
#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14)
#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13)
#define I2CD_INTR_SMBUS_ALERT (0x1 << 12)
#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11)
#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10)
#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9)
#define I2CD_INTR_GCALL_ADDR (0x1 << 8)
#define I2CD_INTR_SLAVE_MATCH (0x1 << 7)
#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6)
#define I2CD_INTR_ABNORMAL (0x1 << 5)
#define I2CD_INTR_NORMAL_STOP (0x1 << 4)
#define I2CD_INTR_ARBIT_LOSS (0x1 << 3)
#define I2CD_INTR_RX_DONE (0x1 << 2)
#define I2CD_INTR_TX_NAK (0x1 << 1)
#define I2CD_INTR_TX_ACK (0x1 << 0)
/* 0x14 : I2CD Command/Status Register */
#define I2CD_SDA_OE (0x1 << 28)
#define I2CD_SDA_O (0x1 << 27)
#define I2CD_SCL_OE (0x1 << 26)
#define I2CD_SCL_O (0x1 << 25)
#define I2CD_TX_TIMING (0x1 << 24)
#define I2CD_TX_STATUS (0x1 << 23)
/* Tx State Machine */
#define I2CD_IDLE 0x0
#define I2CD_MACTIVE 0x8
#define I2CD_MSTART 0x9
#define I2CD_MSTARTR 0xa
#define I2CD_MSTOP 0xb
#define I2CD_MTXD 0xc
#define I2CD_MRXACK 0xd
#define I2CD_MRXD 0xe
#define I2CD_MTXACK 0xf
#define I2CD_SWAIT 0x1
#define I2CD_SRXD 0x4
#define I2CD_STXACK 0x5
#define I2CD_STXD 0x6
#define I2CD_SRXACK 0x7
#define I2CD_RECOVER 0x3
#define I2CD_SCL_LINE_STS (0x1 << 18)
#define I2CD_SDA_LINE_STS (0x1 << 17)
#define I2CD_BUS_BUSY_STS (0x1 << 16)
#define I2CD_SDA_OE_OUT_DIR (0x1 << 15)
#define I2CD_SDA_O_OUT_DIR (0x1 << 14)
#define I2CD_SCL_OE_OUT_DIR (0x1 << 13)
#define I2CD_SCL_O_OUT_DIR (0x1 << 12)
#define I2CD_BUS_RECOVER_CMD (0x1 << 11)
#define I2CD_S_ALT_EN (0x1 << 10)
#define I2CD_RX_DMA_ENABLE (0x1 << 9)
#define I2CD_TX_DMA_ENABLE (0x1 << 8)
/* Command Bit */
#define I2CD_RX_BUFF_ENABLE (0x1 << 7)
#define I2CD_TX_BUFF_ENABLE (0x1 << 6)
#define I2CD_M_STOP_CMD (0x1 << 5)
#define I2CD_M_S_RX_CMD_LAST (0x1 << 4)
#define I2CD_M_RX_CMD (0x1 << 3)
#define I2CD_S_TX_CMD (0x1 << 2)
#define I2CD_M_TX_CMD (0x1 << 1)
#define I2CD_M_START_CMD 0x1
#define I2CD_RX_DATA_SHIFT 8
#define I2CD_RX_DATA_MASK (0xff << I2CD_RX_DATA_SHIFT)
#define I2C_HIGHSPEED_RATE 400000
#endif /* __AST_I2C_H_ */
@@ -0,0 +1,323 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Atmel I2C driver.
*
* (C) Copyright 2016 Songjun Wu <songjun.wu@atmel.com>
*/
#include <asm/io.h>
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <linux/bitops.h>
#include <mach/clk.h>
#include "at91_i2c.h"
DECLARE_GLOBAL_DATA_PTR;
#define I2C_TIMEOUT_MS 100
static int at91_wait_for_xfer(struct at91_i2c_bus *bus, u32 status)
{
struct at91_i2c_regs *reg = bus->regs;
ulong start_time = get_timer(0);
u32 sr;
bus->status = 0;
do {
sr = readl(&reg->sr);
bus->status |= sr;
if (sr & TWI_SR_NACK)
return -EREMOTEIO;
else if (sr & status)
return 0;
} while (get_timer(start_time) < I2C_TIMEOUT_MS);
return -ETIMEDOUT;
}
static int at91_i2c_xfer_msg(struct at91_i2c_bus *bus, struct i2c_msg *msg)
{
struct at91_i2c_regs *reg = bus->regs;
bool is_read = msg->flags & I2C_M_RD;
u32 i;
int ret = 0;
readl(&reg->sr);
if (is_read) {
writel(TWI_CR_START, &reg->cr);
for (i = 0; !ret && i < (msg->len - 1); i++) {
ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
msg->buf[i] = readl(&reg->rhr);
}
if (ret)
goto error;
writel(TWI_CR_STOP, &reg->cr);
ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
if (ret)
goto error;
msg->buf[i] = readl(&reg->rhr);
} else {
writel(msg->buf[0], &reg->thr);
ret = at91_wait_for_xfer(bus, TWI_SR_TXRDY);
for (i = 1; !ret && (i < msg->len); i++) {
writel(msg->buf[i], &reg->thr);
ret = at91_wait_for_xfer(bus, TWI_SR_TXRDY);
}
if (ret)
goto error;
writel(TWI_CR_STOP, &reg->cr);
}
if (!ret)
ret = at91_wait_for_xfer(bus, TWI_SR_TXCOMP);
if (ret)
goto error;
if (bus->status & (TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_LOCK)) {
ret = -EIO;
goto error;
}
return 0;
error:
if (bus->status & TWI_SR_LOCK)
writel(TWI_CR_LOCKCLR, &reg->cr);
return ret;
}
static int at91_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
struct at91_i2c_regs *reg = bus->regs;
struct i2c_msg *m_start = msg;
bool is_read;
u32 int_addr_flag = 0;
int ret = 0;
if (nmsgs == 2) {
int internal_address = 0;
int i;
/* 1st msg is put into the internal address, start with 2nd */
m_start = &msg[1];
/* the max length of internal address is 3 bytes */
if (msg->len > 3)
return -EFAULT;
for (i = 0; i < msg->len; ++i) {
const unsigned addr = msg->buf[msg->len - 1 - i];
internal_address |= addr << (8 * i);
int_addr_flag += TWI_MMR_IADRSZ_1;
}
writel(internal_address, &reg->iadr);
}
is_read = m_start->flags & I2C_M_RD;
writel((m_start->addr << 16) | int_addr_flag |
(is_read ? TWI_MMR_MREAD : 0), &reg->mmr);
ret = at91_i2c_xfer_msg(bus, m_start);
return ret;
}
/*
* Calculate symmetric clock as stated in datasheet:
* twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
*/
static void at91_calc_i2c_clock(struct udevice *dev, int i2c_clk)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
const struct at91_i2c_pdata *pdata = bus->pdata;
int offset = pdata->clk_offset;
int max_ckdiv = pdata->clk_max_div;
int ckdiv, cdiv, div;
unsigned long src_rate;
src_rate = bus->bus_clk_rate;
div = max(0, (int)DIV_ROUND_UP(src_rate, 2 * i2c_clk) - offset);
ckdiv = fls(div >> 8);
cdiv = div >> ckdiv;
if (ckdiv > max_ckdiv) {
ckdiv = max_ckdiv;
cdiv = 255;
}
bus->speed = DIV_ROUND_UP(src_rate,
(cdiv * (1 << ckdiv) + offset) * 2);
bus->cwgr_val = (ckdiv << 16) | (cdiv << 8) | cdiv;
}
static int at91_i2c_enable_clk(struct udevice *dev)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
struct clk clk;
ulong clk_rate;
int ret;
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return -EINVAL;
ret = clk_enable(&clk);
if (ret)
return ret;
clk_rate = clk_get_rate(&clk);
if (!clk_rate)
return -EINVAL;
bus->bus_clk_rate = clk_rate;
clk_free(&clk);
return 0;
}
static int at91_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
at91_calc_i2c_clock(dev, speed);
writel(bus->cwgr_val, &bus->regs->cwgr);
return 0;
}
int at91_i2c_get_bus_speed(struct udevice *dev)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
return bus->speed;
}
static int at91_i2c_ofdata_to_platdata(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
struct at91_i2c_bus *bus = dev_get_priv(dev);
int node = dev_of_offset(dev);
bus->regs = (struct at91_i2c_regs *)devfdt_get_addr(dev);
bus->pdata = (struct at91_i2c_pdata *)dev_get_driver_data(dev);
bus->clock_frequency = fdtdec_get_int(blob, node,
"clock-frequency", 100000);
return 0;
}
static const struct dm_i2c_ops at91_i2c_ops = {
.xfer = at91_i2c_xfer,
.set_bus_speed = at91_i2c_set_bus_speed,
.get_bus_speed = at91_i2c_get_bus_speed,
};
static int at91_i2c_probe(struct udevice *dev)
{
struct at91_i2c_bus *bus = dev_get_priv(dev);
struct at91_i2c_regs *reg = bus->regs;
int ret;
ret = at91_i2c_enable_clk(dev);
if (ret)
return ret;
writel(TWI_CR_SWRST, &reg->cr);
at91_calc_i2c_clock(dev, bus->clock_frequency);
writel(bus->cwgr_val, &reg->cwgr);
writel(TWI_CR_MSEN, &reg->cr);
writel(TWI_CR_SVDIS, &reg->cr);
return 0;
}
static const struct at91_i2c_pdata at91rm9200_config = {
.clk_max_div = 5,
.clk_offset = 3,
};
static const struct at91_i2c_pdata at91sam9261_config = {
.clk_max_div = 5,
.clk_offset = 4,
};
static const struct at91_i2c_pdata at91sam9260_config = {
.clk_max_div = 7,
.clk_offset = 4,
};
static const struct at91_i2c_pdata at91sam9g20_config = {
.clk_max_div = 7,
.clk_offset = 4,
};
static const struct at91_i2c_pdata at91sam9g10_config = {
.clk_max_div = 7,
.clk_offset = 4,
};
static const struct at91_i2c_pdata at91sam9x5_config = {
.clk_max_div = 7,
.clk_offset = 4,
};
static const struct at91_i2c_pdata sama5d4_config = {
.clk_max_div = 7,
.clk_offset = 4,
};
static const struct at91_i2c_pdata sama5d2_config = {
.clk_max_div = 7,
.clk_offset = 3,
};
static const struct udevice_id at91_i2c_ids[] = {
{ .compatible = "atmel,at91rm9200-i2c", .data = (long)&at91rm9200_config },
{ .compatible = "atmel,at91sam9260-i2c", .data = (long)&at91sam9260_config },
{ .compatible = "atmel,at91sam9261-i2c", .data = (long)&at91sam9261_config },
{ .compatible = "atmel,at91sam9g20-i2c", .data = (long)&at91sam9g20_config },
{ .compatible = "atmel,at91sam9g10-i2c", .data = (long)&at91sam9g10_config },
{ .compatible = "atmel,at91sam9x5-i2c", .data = (long)&at91sam9x5_config },
{ .compatible = "atmel,sama5d4-i2c", .data = (long)&sama5d4_config },
{ .compatible = "atmel,sama5d2-i2c", .data = (long)&sama5d2_config },
{ }
};
U_BOOT_DRIVER(i2c_at91) = {
.name = "i2c_at91",
.id = UCLASS_I2C,
.of_match = at91_i2c_ids,
.probe = at91_i2c_probe,
.ofdata_to_platdata = at91_i2c_ofdata_to_platdata,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.priv_auto_alloc_size = sizeof(struct at91_i2c_bus),
.ops = &at91_i2c_ops,
};
@@ -0,0 +1,77 @@
#ifndef _AT91_I2C_H
#define _AT91_I2C_H
#define TWI_CR_START BIT(0) /* Send a Start Condition */
#define TWI_CR_MSEN BIT(2) /* Master Transfer Enable */
#define TWI_CR_STOP BIT(1) /* Send a Stop Condition */
#define TWI_CR_SVDIS BIT(5) /* Slave Transfer Disable */
#define TWI_CR_SWRST BIT(7) /* Software Reset */
#define TWI_CR_ACMEN BIT(16) /* Alternative Command Mode Enable */
#define TWI_CR_ACMDIS BIT(17) /* Alternative Command Mode Disable */
#define TWI_CR_LOCKCLR BIT(26) /* Lock Clear */
#define TWI_MMR_MREAD BIT(12) /* Master Read Direction */
#define TWI_MMR_IADRSZ_1 BIT(8) /* Internal Device Address Size */
#define TWI_SR_TXCOMP BIT(0) /* Transmission Complete */
#define TWI_SR_RXRDY BIT(1) /* Receive Holding Register Ready */
#define TWI_SR_TXRDY BIT(2) /* Transmit Holding Register Ready */
#define TWI_SR_OVRE BIT(6) /* Overrun Error */
#define TWI_SR_UNRE BIT(7) /* Underrun Error */
#define TWI_SR_NACK BIT(8) /* Not Acknowledged */
#define TWI_SR_LOCK BIT(23) /* TWI Lock due to Frame Errors */
#define TWI_ACR_DATAL(len) ((len) & 0xff)
#define TWI_ACR_DIR_READ BIT(8)
#define TWI_CWGR_HOLD_MAX 0x1f
#define TWI_CWGR_HOLD(x) (((x) & TWI_CWGR_HOLD_MAX) << 24)
struct at91_i2c_regs {
u32 cr;
u32 mmr;
u32 smr;
u32 iadr;
u32 cwgr;
u32 rev_0[3];
u32 sr;
u32 ier;
u32 idr;
u32 imr;
u32 rhr;
u32 thr;
u32 smbtr;
u32 rev_1;
u32 acr;
u32 filtr;
u32 rev_2;
u32 swmr;
u32 fmr;
u32 flr;
u32 rev_3;
u32 fsr;
u32 fier;
u32 fidr;
u32 fimr;
u32 rev_4[29];
u32 wpmr;
u32 wpsr;
u32 rev_5[6];
};
struct at91_i2c_pdata {
unsigned clk_max_div;
unsigned clk_offset;
};
struct at91_i2c_bus {
struct at91_i2c_regs *regs;
u32 status;
ulong bus_clk_rate;
u32 clock_frequency;
u32 speed;
u32 cwgr_val;
const struct at91_i2c_pdata *pdata;
};
#endif
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
#include <power/tps65090.h>
static int cros_ec_ldo_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_ldo_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
bool is_read = nmsgs > 1;
int fet_id, ret;
/*
* Look for reads and writes of the LDO registers. In either case the
* first message is a write with the register number as the first byte.
*/
if (!nmsgs || !msg->len || (msg->flags & I2C_M_RD)) {
debug("%s: Invalid message\n", __func__);
goto err;
}
fet_id = msg->buf[0] - REG_FET_BASE;
if (fet_id < 1 || fet_id > MAX_FET_NUM) {
debug("%s: Invalid FET %d\n", __func__, fet_id);
goto err;
}
if (is_read) {
uint8_t state;
ret = cros_ec_get_ldo(dev->parent, fet_id, &state);
if (!ret)
msg[1].buf[0] = state ?
FET_CTRL_ENFET | FET_CTRL_PGFET : 0;
} else {
bool on = msg->buf[1] & FET_CTRL_ENFET;
ret = cros_ec_set_ldo(dev->parent, fet_id, on);
}
return ret;
err:
/* Indicate that the message is unimplemented */
return -ENOSYS;
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_ldo_xfer,
.set_bus_speed = cros_ec_ldo_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-ldo-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_ldo) = {
.name = "cros_ec_ldo_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.ops = &cros_ec_i2c_ops,
};
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
DECLARE_GLOBAL_DATA_PTR;
struct cros_ec_i2c_bus {
int remote_bus;
};
static int cros_ec_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct cros_ec_i2c_bus *i2c_bus = dev_get_priv(dev);
return cros_ec_i2c_tunnel(dev->parent, i2c_bus->remote_bus, msg, nmsgs);
}
static int cros_ec_i2c_ofdata_to_platdata(struct udevice *dev)
{
struct cros_ec_i2c_bus *i2c_bus = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
i2c_bus->remote_bus = fdtdec_get_uint(blob, node, "google,remote-bus",
0);
return 0;
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_i2c_xfer,
.set_bus_speed = cros_ec_i2c_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-i2c-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_tunnel) = {
.name = "cros_ec_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.ofdata_to_platdata = cros_ec_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct cros_ec_i2c_bus),
.ops = &cros_ec_i2c_ops,
};
@@ -0,0 +1,509 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* TI DaVinci (TMS320DM644x) I2C driver.
*
* (C) Copyright 2012-2014
* Texas Instruments Incorporated, <www.ti.com>
* (C) Copyright 2007 Sergey Kubushyn <ksi@koi8.net>
* --------------------------------------------------------
*
* NOTE: This driver should be converted to driver model before June 2017.
* Please see doc/driver-model/i2c-howto.txt for instructions.
*/
#include <common.h>
#include <i2c.h>
#include <dm.h>
#include <asm/arch/hardware.h>
#include <asm/arch/i2c_defs.h>
#include <asm/io.h>
#include "davinci_i2c.h"
#ifdef CONFIG_DM_I2C
/* Information about i2c controller */
struct i2c_bus {
int id;
uint speed;
struct i2c_regs *regs;
};
#endif
#define CHECK_NACK() \
do {\
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
REG(&(i2c_base->i2c_con)) = 0;\
return 1;\
} \
} while (0)
static int _wait_for_bus(struct i2c_regs *i2c_base)
{
int stat, timeout;
REG(&(i2c_base->i2c_stat)) = 0xffff;
for (timeout = 0; timeout < 10; timeout++) {
stat = REG(&(i2c_base->i2c_stat));
if (!((stat) & I2C_STAT_BB)) {
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 0;
}
REG(&(i2c_base->i2c_stat)) = stat;
udelay(50000);
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 1;
}
static int _poll_i2c_irq(struct i2c_regs *i2c_base, int mask)
{
int stat, timeout;
for (timeout = 0; timeout < 10; timeout++) {
udelay(1000);
stat = REG(&(i2c_base->i2c_stat));
if (stat & mask)
return stat;
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return stat | I2C_TIMEOUT;
}
static void _flush_rx(struct i2c_regs *i2c_base)
{
while (1) {
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_RRDY))
break;
REG(&(i2c_base->i2c_drr));
REG(&(i2c_base->i2c_stat)) = I2C_STAT_RRDY;
udelay(1000);
}
}
static uint _davinci_i2c_setspeed(struct i2c_regs *i2c_base,
uint speed)
{
uint32_t div, psc;
psc = 2;
/* SCLL + SCLH */
div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;
REG(&(i2c_base->i2c_psc)) = psc; /* 27MHz / (2 + 1) = 9MHz */
REG(&(i2c_base->i2c_scll)) = (div * 50) / 100; /* 50% Duty */
REG(&(i2c_base->i2c_sclh)) = div - REG(&(i2c_base->i2c_scll));
return 0;
}
static void _davinci_i2c_init(struct i2c_regs *i2c_base,
uint speed, int slaveadd)
{
if (REG(&(i2c_base->i2c_con)) & I2C_CON_EN) {
REG(&(i2c_base->i2c_con)) = 0;
udelay(50000);
}
_davinci_i2c_setspeed(i2c_base, speed);
REG(&(i2c_base->i2c_oa)) = slaveadd;
REG(&(i2c_base->i2c_cnt)) = 0;
/* Interrupts must be enabled or I2C module won't work */
REG(&(i2c_base->i2c_ie)) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
/* Now enable I2C controller (get it out of reset) */
REG(&(i2c_base->i2c_con)) = I2C_CON_EN;
udelay(1000);
}
static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (_wait_for_bus(i2c_base))
return 1;
if (alen != 0) {
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
REG(&(i2c_base->i2c_cnt)) = alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
switch (alen) {
case 2:
/* Send address MSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = _poll_i2c_irq(i2c_base,
I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
case 1:
/* Send address LSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY |
I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
if (!(tmp & I2C_STAT_ARDY)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
}
/* Address phase is over, now read 'len' bytes and stop */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
REG(&(i2c_base->i2c_cnt)) = len & 0xffff;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
for (i = 0; i < len; i++) {
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_RRDY | I2C_STAT_NACK |
I2C_STAT_ROVR);
CHECK_NACK();
if (tmp & I2C_STAT_RRDY) {
buf[i] = REG(&(i2c_base->i2c_drr));
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (len < 0) {
printf("%s(): bogus length %x\n", __func__, len);
return 1;
}
if (_wait_for_bus(i2c_base))
return 1;
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_TRX | I2C_CON_STP;
REG(&(i2c_base->i2c_cnt)) = (alen == 0) ?
len & 0xffff : (len & 0xffff) + alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
switch (alen) {
case 2:
/* Send address MSByte */
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
/* No break, fall through */
case 1:
/* Send address LSByte */
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
for (i = 0; i < len; i++) {
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY)
REG(&(i2c_base->i2c_dxr)) = buf[i];
else
return 1;
}
tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, uint8_t chip)
{
int rc = 1;
if (chip == REG(&(i2c_base->i2c_oa)))
return rc;
REG(&(i2c_base->i2c_con)) = 0;
if (_wait_for_bus(i2c_base))
return 1;
/* try to read one byte from current (or only) address */
REG(&(i2c_base->i2c_cnt)) = 1;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_STP);
udelay(50000);
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
rc = 0;
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
} else {
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
udelay(20000);
if (_wait_for_bus(i2c_base))
return 1;
}
_flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
return rc;
}
#ifndef CONFIG_DM_I2C
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if CONFIG_SYS_I2C_BUS_MAX >= 3
case 2:
return (struct i2c_regs *)I2C2_BASE;
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 2
case 1:
return (struct i2c_regs *)I2C1_BASE;
#endif
case 0:
return (struct i2c_regs *)I2C_BASE;
default:
printf("wrong hwadapnr: %d\n", adap->hwadapnr);
}
return NULL;
}
static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
uint ret;
adap->speed = speed;
ret = _davinci_i2c_setspeed(i2c_base, speed);
return ret;
}
static void davinci_i2c_init(struct i2c_adapter *adap, int speed,
int slaveadd)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
adap->speed = speed;
_davinci_i2c_init(i2c_base, speed, slaveadd);
return;
}
static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_read(i2c_base, chip, addr, alen, buf, len);
}
static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_write(i2c_base, chip, addr, alen, buf, len);
}
static int davinci_i2c_probe_chip(struct i2c_adapter *adap, uint8_t chip)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
return _davinci_i2c_probe_chip(i2c_base, chip);
}
U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED,
CONFIG_SYS_DAVINCI_I2C_SLAVE,
0)
#if CONFIG_SYS_I2C_BUS_MAX >= 2
U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED1,
CONFIG_SYS_DAVINCI_I2C_SLAVE1,
1)
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 3
U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED2,
CONFIG_SYS_DAVINCI_I2C_SLAVE2,
2)
#endif
#else /* CONFIG_DM_I2C */
static int davinci_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = _davinci_i2c_read(i2c_bus->regs, msg->addr,
0, 0, msg->buf, msg->len);
} else {
ret = _davinci_i2c_write(i2c_bus->regs, msg->addr,
0, 0, msg->buf, msg->len);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return ret;
}
static int davinci_i2c_set_speed(struct udevice *dev, uint speed)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->speed = speed;
return _davinci_i2c_setspeed(i2c_bus->regs, speed);
}
static int davinci_i2c_probe(struct udevice *dev)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->id = dev->seq;
i2c_bus->regs = (struct i2c_regs *)devfdt_get_addr(dev);
i2c_bus->speed = 100000;
_davinci_i2c_init(i2c_bus->regs, i2c_bus->speed, 0);
return 0;
}
static int davinci_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
return _davinci_i2c_probe_chip(i2c_bus->regs, chip_addr);
}
static const struct dm_i2c_ops davinci_i2c_ops = {
.xfer = davinci_i2c_xfer,
.probe_chip = davinci_i2c_probe_chip,
.set_bus_speed = davinci_i2c_set_speed,
};
static const struct udevice_id davinci_i2c_ids[] = {
{ .compatible = "ti,davinci-i2c"},
{ .compatible = "ti,keystone-i2c"},
{ }
};
U_BOOT_DRIVER(i2c_davinci) = {
.name = "i2c_davinci",
.id = UCLASS_I2C,
.of_match = davinci_i2c_ids,
.probe = davinci_i2c_probe,
.priv_auto_alloc_size = sizeof(struct i2c_bus),
.ops = &davinci_i2c_ops,
};
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2004-2014
* Texas Instruments, <www.ti.com>
*
* Some changes copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
*/
#ifndef _DAVINCI_I2C_H_
#define _DAVINCI_I2C_H_
#define I2C_WRITE 0
#define I2C_READ 1
struct i2c_regs {
u32 i2c_oa;
u32 i2c_ie;
u32 i2c_stat;
u32 i2c_scll;
u32 i2c_sclh;
u32 i2c_cnt;
u32 i2c_drr;
u32 i2c_sa;
u32 i2c_dxr;
u32 i2c_con;
u32 i2c_iv;
u32 res_2c;
u32 i2c_psc;
};
/* I2C masks */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_SCD_IE (1 << 5) /* Stop condition detect interrupt enable */
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_SCD (1 << 5) /* Stop condition detect */
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Code Register (I2C_INTCODE): */
#define I2C_INTCODE_MASK 7
#define I2C_INTCODE_NONE 0
#define I2C_INTCODE_AL 1 /* Arbitration lost */
#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
#define I2C_INTCODE_ARDY 3 /* Register access ready */
#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
#define I2C_INTCODE_SCD 6 /* Stop condition detect */
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 5) /* I2C module enable */
#define I2C_CON_STB (1 << 4) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Tx/Rx mode (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 11) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 13) /* Start condition (master mode only) */
#define I2C_CON_FREE (1 << 14) /* Free run on emulation */
#define I2C_TIMEOUT 0xffff0000 /* Timeout mask for poll_i2c_irq() */
#endif
@@ -0,0 +1,683 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <pci.h>
#include <reset.h>
#include <asm/io.h>
#include "designware_i2c.h"
struct dw_scl_sda_cfg {
u32 ss_hcnt;
u32 fs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
u32 sda_hold;
};
#ifdef CONFIG_X86
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
};
#endif
struct dw_i2c {
struct i2c_regs *regs;
struct dw_scl_sda_cfg *scl_sda_cfg;
struct reset_ctl_bulk resets;
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
};
#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
u32 ena = enable ? IC_ENABLE_0B : 0;
writel(ena, &i2c_base->ic_enable);
return 0;
}
#else
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
u32 ena = enable ? IC_ENABLE_0B : 0;
int timeout = 100;
do {
writel(ena, &i2c_base->ic_enable);
if ((readl(&i2c_base->ic_enable_status) & IC_ENABLE_0B) == ena)
return 0;
/*
* Wait 10 times the signaling period of the highest I2C
* transfer supported by the driver (for 400KHz this is
* 25us) as described in the DesignWare I2C databook.
*/
udelay(25);
} while (timeout--);
printf("timeout in %sabling I2C adapter\n", enable ? "en" : "dis");
return -ETIMEDOUT;
}
#endif
/*
* i2c_set_bus_speed - Set the i2c speed
* @speed: required i2c speed
*
* Set the i2c speed.
*/
static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
struct dw_scl_sda_cfg *scl_sda_cfg,
unsigned int speed,
unsigned int bus_mhz)
{
unsigned int cntl;
unsigned int hcnt, lcnt;
unsigned int ena;
int i2c_spd;
if (speed >= I2C_MAX_SPEED)
i2c_spd = IC_SPEED_MODE_MAX;
else if (speed >= I2C_FAST_SPEED)
i2c_spd = IC_SPEED_MODE_FAST;
else
i2c_spd = IC_SPEED_MODE_STANDARD;
/* Get enable setting for restore later */
ena = readl(&i2c_base->ic_enable) & IC_ENABLE_0B;
/* to set speed cltr must be disabled */
dw_i2c_enable(i2c_base, false);
cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
switch (i2c_spd) {
#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
case IC_SPEED_MODE_MAX:
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (bus_mhz * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (bus_mhz * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
break;
#endif
case IC_SPEED_MODE_STANDARD:
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->ss_hcnt;
lcnt = scl_sda_cfg->ss_lcnt;
} else {
hcnt = (bus_mhz * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (bus_mhz * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_ss_scl_hcnt);
writel(lcnt, &i2c_base->ic_ss_scl_lcnt);
break;
case IC_SPEED_MODE_FAST:
default:
cntl |= IC_CON_SPD_FS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (bus_mhz * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (bus_mhz * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_fs_scl_hcnt);
writel(lcnt, &i2c_base->ic_fs_scl_lcnt);
break;
}
writel(cntl, &i2c_base->ic_con);
/* Configure SDA Hold Time if required */
if (scl_sda_cfg)
writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold);
/* Restore back i2c now speed set */
if (ena == IC_ENABLE_0B)
dw_i2c_enable(i2c_base, true);
return 0;
}
/*
* i2c_setaddress - Sets the target slave address
* @i2c_addr: target i2c address
*
* Sets the target slave address.
*/
static void i2c_setaddress(struct i2c_regs *i2c_base, unsigned int i2c_addr)
{
/* Disable i2c */
dw_i2c_enable(i2c_base, false);
writel(i2c_addr, &i2c_base->ic_tar);
/* Enable i2c */
dw_i2c_enable(i2c_base, true);
}
/*
* i2c_flush_rxfifo - Flushes the i2c RX FIFO
*
* Flushes the i2c RX FIFO
*/
static void i2c_flush_rxfifo(struct i2c_regs *i2c_base)
{
while (readl(&i2c_base->ic_status) & IC_STATUS_RFNE)
readl(&i2c_base->ic_cmd_data);
}
/*
* i2c_wait_for_bb - Waits for bus busy
*
* Waits for bus busy
*/
static int i2c_wait_for_bb(struct i2c_regs *i2c_base)
{
unsigned long start_time_bb = get_timer(0);
while ((readl(&i2c_base->ic_status) & IC_STATUS_MA) ||
!(readl(&i2c_base->ic_status) & IC_STATUS_TFE)) {
/* Evaluate timeout */
if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB))
return 1;
}
return 0;
}
static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr,
int alen)
{
if (i2c_wait_for_bb(i2c_base))
return 1;
i2c_setaddress(i2c_base, chip);
while (alen) {
alen--;
/* high byte address going out first */
writel((addr >> (alen * 8)) & 0xff,
&i2c_base->ic_cmd_data);
}
return 0;
}
static int i2c_xfer_finish(struct i2c_regs *i2c_base)
{
ulong start_stop_det = get_timer(0);
while (1) {
if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) {
readl(&i2c_base->ic_clr_stop_det);
break;
} else if (get_timer(start_stop_det) > I2C_STOPDET_TO) {
break;
}
}
if (i2c_wait_for_bb(i2c_base)) {
printf("Timed out waiting for bus\n");
return 1;
}
i2c_flush_rxfifo(i2c_base);
return 0;
}
/*
* i2c_read - Read from i2c memory
* @chip: target i2c address
* @addr: address to read from
* @alen:
* @buffer: buffer for read data
* @len: no of bytes to be read
*
* Read from i2c memory.
*/
static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
unsigned long start_time_rx;
unsigned int active = 0;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
addr);
#endif
if (i2c_xfer_init(i2c_base, dev, addr, alen))
return 1;
start_time_rx = get_timer(0);
while (len) {
if (!active) {
/*
* Avoid writing to ic_cmd_data multiple times
* in case this loop spins too quickly and the
* ic_status RFNE bit isn't set after the first
* write. Subsequent writes to ic_cmd_data can
* trigger spurious i2c transfer.
*/
if (len == 1)
writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data);
else
writel(IC_CMD, &i2c_base->ic_cmd_data);
active = 1;
}
if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) {
*buffer++ = (uchar)readl(&i2c_base->ic_cmd_data);
len--;
start_time_rx = get_timer(0);
active = 0;
} else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
return 1;
}
}
return i2c_xfer_finish(i2c_base);
}
/*
* i2c_write - Write to i2c memory
* @chip: target i2c address
* @addr: address to read from
* @alen:
* @buffer: buffer for read data
* @len: no of bytes to be read
*
* Write to i2c memory.
*/
static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
int nb = len;
unsigned long start_time_tx;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
addr);
#endif
if (i2c_xfer_init(i2c_base, dev, addr, alen))
return 1;
start_time_tx = get_timer(0);
while (len) {
if (readl(&i2c_base->ic_status) & IC_STATUS_TFNF) {
if (--len == 0) {
writel(*buffer | IC_STOP,
&i2c_base->ic_cmd_data);
} else {
writel(*buffer, &i2c_base->ic_cmd_data);
}
buffer++;
start_time_tx = get_timer(0);
} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
printf("Timed out. i2c write Failed\n");
return 1;
}
}
return i2c_xfer_finish(i2c_base);
}
/*
* __dw_i2c_init - Init function
* @speed: required i2c speed
* @slaveaddr: slave address for the device
*
* Initialization function.
*/
static int __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
{
int ret;
/* Disable i2c */
ret = dw_i2c_enable(i2c_base, false);
if (ret)
return ret;
writel(IC_CON_SD | IC_CON_RE | IC_CON_SPD_FS | IC_CON_MM,
&i2c_base->ic_con);
writel(IC_RX_TL, &i2c_base->ic_rx_tl);
writel(IC_TX_TL, &i2c_base->ic_tx_tl);
writel(IC_STOP_DET, &i2c_base->ic_intr_mask);
#ifndef CONFIG_DM_I2C
__dw_i2c_set_bus_speed(i2c_base, NULL, speed, IC_CLK);
writel(slaveaddr, &i2c_base->ic_sar);
#endif
/* Enable i2c */
ret = dw_i2c_enable(i2c_base, true);
if (ret)
return ret;
return 0;
}
#ifndef CONFIG_DM_I2C
/*
* The legacy I2C functions. These need to get removed once
* all users of this driver are converted to DM.
*/
static struct i2c_regs *i2c_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if CONFIG_SYS_I2C_BUS_MAX >= 4
case 3:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE3;
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 3
case 2:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE2;
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 2
case 1:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE1;
#endif
case 0:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE;
default:
printf("Wrong I2C-adapter number %d\n", adap->hwadapnr);
}
return NULL;
}
static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
adap->speed = speed;
return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed, IC_CLK);
}
static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
__dw_i2c_init(i2c_get_base(adap), speed, slaveaddr);
}
static int dw_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
return __dw_i2c_read(i2c_get_base(adap), dev, addr, alen, buffer, len);
}
static int dw_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
return __dw_i2c_write(i2c_get_base(adap), dev, addr, alen, buffer, len);
}
/* dw_i2c_probe - Probe the i2c chip */
static int dw_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
struct i2c_regs *i2c_base = i2c_get_base(adap);
u32 tmp;
int ret;
/*
* Try to read the first location of the chip.
*/
ret = __dw_i2c_read(i2c_base, dev, 0, 1, (uchar *)&tmp, 1);
if (ret)
dw_i2c_init(adap, adap->speed, adap->slaveaddr);
return ret;
}
U_BOOT_I2C_ADAP_COMPLETE(dw_0, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
#if CONFIG_SYS_I2C_BUS_MAX >= 2
U_BOOT_I2C_ADAP_COMPLETE(dw_1, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED1, CONFIG_SYS_I2C_SLAVE1, 1)
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 3
U_BOOT_I2C_ADAP_COMPLETE(dw_2, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED2, CONFIG_SYS_I2C_SLAVE2, 2)
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 4
U_BOOT_I2C_ADAP_COMPLETE(dw_3, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED3, CONFIG_SYS_I2C_SLAVE3, 3)
#endif
#else /* CONFIG_DM_I2C */
/* The DM I2C functions */
static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct dw_i2c *i2c = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = __dw_i2c_read(i2c->regs, msg->addr, 0, 0,
msg->buf, msg->len);
} else {
ret = __dw_i2c_write(i2c->regs, msg->addr, 0, 0,
msg->buf, msg->len);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dw_i2c *i2c = dev_get_priv(bus);
ulong rate;
#if CONFIG_IS_ENABLED(CLK)
rate = clk_get_rate(&i2c->clk);
if (IS_ERR_VALUE(rate))
return -EINVAL;
/* Convert to MHz */
rate /= 1000000;
#else
rate = IC_CLK;
#endif
return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed,
rate);
}
static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct dw_i2c *i2c = dev_get_priv(bus);
struct i2c_regs *i2c_base = i2c->regs;
u32 tmp;
int ret;
/* Try to read the first location of the chip */
ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1);
if (ret)
__dw_i2c_init(i2c_base, 0, 0);
return ret;
}
static int designware_i2c_probe(struct udevice *bus)
{
struct dw_i2c *priv = dev_get_priv(bus);
int ret;
if (device_is_on_pci_bus(bus)) {
#ifdef CONFIG_DM_PCI
/* Save base address from PCI BAR */
priv->regs = (struct i2c_regs *)
dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
#ifdef CONFIG_X86
/* Use BayTrail specific timing values */
priv->scl_sda_cfg = &byt_config;
#endif
#endif
} else {
priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
}
ret = reset_get_bulk(bus, &priv->resets);
if (ret)
dev_warn(bus, "Can't get reset: %d\n", ret);
else
reset_deassert_bulk(&priv->resets);
#if CONFIG_IS_ENABLED(CLK)
ret = clk_get_by_index(bus, 0, &priv->clk);
if (ret)
return ret;
ret = clk_enable(&priv->clk);
if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
clk_free(&priv->clk);
dev_err(bus, "failed to enable clock\n");
return ret;
}
#endif
return __dw_i2c_init(priv->regs, 0, 0);
}
static int designware_i2c_remove(struct udevice *dev)
{
struct dw_i2c *priv = dev_get_priv(dev);
#if CONFIG_IS_ENABLED(CLK)
clk_disable(&priv->clk);
clk_free(&priv->clk);
#endif
return reset_release_bulk(&priv->resets);
}
static int designware_i2c_bind(struct udevice *dev)
{
static int num_cards;
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "i2c_designware#%u", num_cards++);
device_set_name(dev, name);
}
return 0;
}
static const struct dm_i2c_ops designware_i2c_ops = {
.xfer = designware_i2c_xfer,
.probe_chip = designware_i2c_probe_chip,
.set_bus_speed = designware_i2c_set_bus_speed,
};
static const struct udevice_id designware_i2c_ids[] = {
{ .compatible = "snps,designware-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_designware) = {
.name = "i2c_designware",
.id = UCLASS_I2C,
.of_match = designware_i2c_ids,
.bind = designware_i2c_bind,
.probe = designware_i2c_probe,
.priv_auto_alloc_size = sizeof(struct dw_i2c),
.remove = designware_i2c_remove,
.flags = DM_FLAG_OS_PREPARE,
.ops = &designware_i2c_ops,
};
#ifdef CONFIG_X86
static struct pci_device_id designware_pci_supported[] = {
/* Intel BayTrail has 7 I2C controller located on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f41) },
{ PCI_VDEVICE(INTEL, 0x0f42) },
{ PCI_VDEVICE(INTEL, 0x0f43) },
{ PCI_VDEVICE(INTEL, 0x0f44) },
{ PCI_VDEVICE(INTEL, 0x0f45) },
{ PCI_VDEVICE(INTEL, 0x0f46) },
{ PCI_VDEVICE(INTEL, 0x0f47) },
{},
};
U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
#endif
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,134 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#ifndef __DW_I2C_H_
#define __DW_I2C_H_
struct i2c_regs {
u32 ic_con; /* 0x00 */
u32 ic_tar; /* 0x04 */
u32 ic_sar; /* 0x08 */
u32 ic_hs_maddr; /* 0x0c */
u32 ic_cmd_data; /* 0x10 */
u32 ic_ss_scl_hcnt; /* 0x14 */
u32 ic_ss_scl_lcnt; /* 0x18 */
u32 ic_fs_scl_hcnt; /* 0x1c */
u32 ic_fs_scl_lcnt; /* 0x20 */
u32 ic_hs_scl_hcnt; /* 0x24 */
u32 ic_hs_scl_lcnt; /* 0x28 */
u32 ic_intr_stat; /* 0x2c */
u32 ic_intr_mask; /* 0x30 */
u32 ic_raw_intr_stat; /* 0x34 */
u32 ic_rx_tl; /* 0x38 */
u32 ic_tx_tl; /* 0x3c */
u32 ic_clr_intr; /* 0x40 */
u32 ic_clr_rx_under; /* 0x44 */
u32 ic_clr_rx_over; /* 0x48 */
u32 ic_clr_tx_over; /* 0x4c */
u32 ic_clr_rd_req; /* 0x50 */
u32 ic_clr_tx_abrt; /* 0x54 */
u32 ic_clr_rx_done; /* 0x58 */
u32 ic_clr_activity; /* 0x5c */
u32 ic_clr_stop_det; /* 0x60 */
u32 ic_clr_start_det; /* 0x64 */
u32 ic_clr_gen_call; /* 0x68 */
u32 ic_enable; /* 0x6c */
u32 ic_status; /* 0x70 */
u32 ic_txflr; /* 0x74 */
u32 ic_rxflr; /* 0x78 */
u32 ic_sda_hold; /* 0x7c */
u32 ic_tx_abrt_source; /* 0x80 */
u8 res1[0x18]; /* 0x84 */
u32 ic_enable_status; /* 0x9c */
};
#if !defined(IC_CLK)
#define IC_CLK 166
#endif
#define NANO_TO_MICRO 1000
/* High and low times in different speed modes (in ns) */
#define MIN_SS_SCL_HIGHTIME 4000
#define MIN_SS_SCL_LOWTIME 4700
#define MIN_FS_SCL_HIGHTIME 600
#define MIN_FS_SCL_LOWTIME 1300
#define MIN_HS_SCL_HIGHTIME 60
#define MIN_HS_SCL_LOWTIME 160
/* Worst case timeout for 1 byte is kept as 2ms */
#define I2C_BYTE_TO (CONFIG_SYS_HZ/500)
#define I2C_STOPDET_TO (CONFIG_SYS_HZ/500)
#define I2C_BYTE_TO_BB (I2C_BYTE_TO * 16)
/* i2c control register definitions */
#define IC_CON_SD 0x0040
#define IC_CON_RE 0x0020
#define IC_CON_10BITADDRMASTER 0x0010
#define IC_CON_10BITADDR_SLAVE 0x0008
#define IC_CON_SPD_MSK 0x0006
#define IC_CON_SPD_SS 0x0002
#define IC_CON_SPD_FS 0x0004
#define IC_CON_SPD_HS 0x0006
#define IC_CON_MM 0x0001
/* i2c target address register definitions */
#define TAR_ADDR 0x0050
/* i2c slave address register definitions */
#define IC_SLAVE_ADDR 0x0002
/* i2c data buffer and command register definitions */
#define IC_CMD 0x0100
#define IC_STOP 0x0200
/* i2c interrupt status register definitions */
#define IC_GEN_CALL 0x0800
#define IC_START_DET 0x0400
#define IC_STOP_DET 0x0200
#define IC_ACTIVITY 0x0100
#define IC_RX_DONE 0x0080
#define IC_TX_ABRT 0x0040
#define IC_RD_REQ 0x0020
#define IC_TX_EMPTY 0x0010
#define IC_TX_OVER 0x0008
#define IC_RX_FULL 0x0004
#define IC_RX_OVER 0x0002
#define IC_RX_UNDER 0x0001
/* fifo threshold register definitions */
#define IC_TL0 0x00
#define IC_TL1 0x01
#define IC_TL2 0x02
#define IC_TL3 0x03
#define IC_TL4 0x04
#define IC_TL5 0x05
#define IC_TL6 0x06
#define IC_TL7 0x07
#define IC_RX_TL IC_TL0
#define IC_TX_TL IC_TL0
/* i2c enable register definitions */
#define IC_ENABLE_0B 0x0001
/* i2c status register definitions */
#define IC_STATUS_SA 0x0040
#define IC_STATUS_MA 0x0020
#define IC_STATUS_RFF 0x0010
#define IC_STATUS_RFNE 0x0008
#define IC_STATUS_TFE 0x0004
#define IC_STATUS_TFNF 0x0002
#define IC_STATUS_ACT 0x0001
/* Speed Selection */
#define IC_SPEED_MODE_STANDARD 1
#define IC_SPEED_MODE_FAST 2
#define IC_SPEED_MODE_MAX 3
#define I2C_MAX_SPEED 3400000
#define I2C_FAST_SPEED 400000
#define I2C_STANDARD_SPEED 100000
#endif /* __DW_I2C_H_ */
@@ -0,0 +1,560 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2016, Google Inc
*
* (C) Copyright 2002
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <asm/arch/clk.h>
#include <asm/arch/cpu.h>
#include <asm/arch/pinmux.h>
#include "s3c24x0_i2c.h"
DECLARE_GLOBAL_DATA_PTR;
/* HSI2C-specific register description */
/* I2C_CTL Register bits */
#define HSI2C_FUNC_MODE_I2C (1u << 0)
#define HSI2C_MASTER (1u << 3)
#define HSI2C_RXCHON (1u << 6) /* Write/Send */
#define HSI2C_TXCHON (1u << 7) /* Read/Receive */
#define HSI2C_SW_RST (1u << 31)
/* I2C_FIFO_CTL Register bits */
#define HSI2C_RXFIFO_EN (1u << 0)
#define HSI2C_TXFIFO_EN (1u << 1)
#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16)
#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4)
/* I2C_TRAILING_CTL Register bits */
#define HSI2C_TRAILING_COUNT (0xff)
/* I2C_INT_EN Register bits */
#define HSI2C_TX_UNDERRUN_EN (1u << 2)
#define HSI2C_TX_OVERRUN_EN (1u << 3)
#define HSI2C_RX_UNDERRUN_EN (1u << 4)
#define HSI2C_RX_OVERRUN_EN (1u << 5)
#define HSI2C_INT_TRAILING_EN (1u << 6)
#define HSI2C_INT_I2C_EN (1u << 9)
#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\
HSI2C_TX_OVERRUN_EN |\
HSI2C_RX_UNDERRUN_EN |\
HSI2C_RX_OVERRUN_EN |\
HSI2C_INT_TRAILING_EN)
/* I2C_CONF Register bits */
#define HSI2C_AUTO_MODE (1u << 31)
#define HSI2C_10BIT_ADDR_MODE (1u << 30)
#define HSI2C_HS_MODE (1u << 29)
/* I2C_AUTO_CONF Register bits */
#define HSI2C_READ_WRITE (1u << 16)
#define HSI2C_STOP_AFTER_TRANS (1u << 17)
#define HSI2C_MASTER_RUN (1u << 31)
/* I2C_TIMEOUT Register bits */
#define HSI2C_TIMEOUT_EN (1u << 31)
/* I2C_TRANS_STATUS register bits */
#define HSI2C_MASTER_BUSY (1u << 17)
#define HSI2C_SLAVE_BUSY (1u << 16)
#define HSI2C_TIMEOUT_AUTO (1u << 4)
#define HSI2C_NO_DEV (1u << 3)
#define HSI2C_NO_DEV_ACK (1u << 2)
#define HSI2C_TRANS_ABORT (1u << 1)
#define HSI2C_TRANS_SUCCESS (1u << 0)
#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\
HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\
HSI2C_TRANS_ABORT)
#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS)
/* I2C_FIFO_STAT Register bits */
#define HSI2C_RX_FIFO_EMPTY (1u << 24)
#define HSI2C_RX_FIFO_FULL (1u << 23)
#define HSI2C_TX_FIFO_EMPTY (1u << 8)
#define HSI2C_TX_FIFO_FULL (1u << 7)
#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f)
#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f)
#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
#define HSI2C_TIMEOUT_US 10000 /* 10 ms, finer granularity */
/*
* Wait for transfer completion.
*
* This function reads the interrupt status register waiting for the INT_I2C
* bit to be set, which indicates copletion of a transaction.
*
* @param i2c: pointer to the appropriate register bank
*
* @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case
* the status bits do not get set in time, or an approrpiate error
* value in case of transfer errors.
*/
static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c)
{
int i = HSI2C_TIMEOUT_US;
while (i-- > 0) {
u32 int_status = readl(&i2c->usi_int_stat);
if (int_status & HSI2C_INT_I2C_EN) {
u32 trans_status = readl(&i2c->usi_trans_status);
/* Deassert pending interrupt. */
writel(int_status, &i2c->usi_int_stat);
if (trans_status & HSI2C_NO_DEV_ACK) {
debug("%s: no ACK from device\n", __func__);
return I2C_NACK;
}
if (trans_status & HSI2C_NO_DEV) {
debug("%s: no device\n", __func__);
return I2C_NOK;
}
if (trans_status & HSI2C_TRANS_ABORT) {
debug("%s: arbitration lost\n", __func__);
return I2C_NOK_LA;
}
if (trans_status & HSI2C_TIMEOUT_AUTO) {
debug("%s: device timed out\n", __func__);
return I2C_NOK_TOUT;
}
return I2C_OK;
}
udelay(1);
}
debug("%s: transaction timeout!\n", __func__);
return I2C_NOK_TOUT;
}
static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus)
{
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
ulong clkin;
unsigned int op_clk = i2c_bus->clock_frequency;
unsigned int i = 0, utemp0 = 0, utemp1 = 0;
unsigned int t_ftl_cycle;
#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
clkin = get_i2c_clk();
#else
clkin = get_PCLK();
#endif
/* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
* uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* uTemp1 = (TSCLK_L + TSCLK_H + 2)
* uTemp2 = TSCLK_L + TSCLK_H
*/
t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (i = 0; i < 256; i++) {
utemp1 = utemp0 / (i + 1);
if ((utemp1 < 512) && (utemp1 > 4)) {
i2c_bus->clk_cycle = utemp1 - 2;
i2c_bus->clk_div = i;
return 0;
}
}
return -EINVAL;
}
static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus)
{
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
unsigned int t_sr_release;
unsigned int n_clkdiv;
unsigned int t_start_su, t_start_hd;
unsigned int t_stop_su;
unsigned int t_data_su, t_data_hd;
unsigned int t_scl_l, t_scl_h;
u32 i2c_timing_s1;
u32 i2c_timing_s2;
u32 i2c_timing_s3;
u32 i2c_timing_sla;
n_clkdiv = i2c_bus->clk_div;
t_scl_l = i2c_bus->clk_cycle / 2;
t_scl_h = i2c_bus->clk_cycle / 2;
t_start_su = t_scl_l;
t_start_hd = t_scl_l;
t_stop_su = t_scl_l;
t_data_su = t_scl_l / 2;
t_data_hd = t_scl_l / 2;
t_sr_release = i2c_bus->clk_cycle;
i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8;
i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0;
i2c_timing_sla = t_data_hd << 0;
writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl);
/* Clear to enable Timeout */
clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0);
/* set AUTO mode */
writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf);
/* Enable completion conditions' reporting. */
writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en);
/* Enable FIFOs */
writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl);
/* Currently operating in Fast speed mode. */
writel(i2c_timing_s1, &hsregs->usi_timing_fs1);
writel(i2c_timing_s2, &hsregs->usi_timing_fs2);
writel(i2c_timing_s3, &hsregs->usi_timing_fs3);
writel(i2c_timing_sla, &hsregs->usi_timing_sla);
}
/* SW reset for the high speed bus */
static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus)
{
struct exynos5_hsi2c *i2c = i2c_bus->hsregs;
u32 i2c_ctl;
/* Set and clear the bit for reset */
i2c_ctl = readl(&i2c->usi_ctl);
i2c_ctl |= HSI2C_SW_RST;
writel(i2c_ctl, &i2c->usi_ctl);
i2c_ctl = readl(&i2c->usi_ctl);
i2c_ctl &= ~HSI2C_SW_RST;
writel(i2c_ctl, &i2c->usi_ctl);
/* Initialize the configure registers */
hsi2c_ch_init(i2c_bus);
}
/*
* Poll the appropriate bit of the fifo status register until the interface is
* ready to process the next byte or timeout expires.
*
* In addition to the FIFO status register this function also polls the
* interrupt status register to be able to detect unexpected transaction
* completion.
*
* When FIFO is ready to process the next byte, this function returns I2C_OK.
* If in course of polling the INT_I2C assertion is detected, the function
* returns I2C_NOK. If timeout happens before any of the above conditions is
* met - the function returns I2C_NOK_TOUT;
* @param i2c: pointer to the appropriate i2c register bank.
* @param rx_transfer: set to True if the receive transaction is in progress.
* @return: as described above.
*/
static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer)
{
u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL;
int i = HSI2C_TIMEOUT_US;
while (readl(&i2c->usi_fifo_stat) & fifo_bit) {
if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) {
/*
* There is a chance that assertion of
* HSI2C_INT_I2C_EN and deassertion of
* HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's
* give FIFO status priority and check it one more
* time before reporting interrupt. The interrupt will
* be reported next time this function is called.
*/
if (rx_transfer &&
!(readl(&i2c->usi_fifo_stat) & fifo_bit))
break;
return I2C_NOK;
}
if (!i--) {
debug("%s: FIFO polling timeout!\n", __func__);
return I2C_NOK_TOUT;
}
udelay(1);
}
return I2C_OK;
}
/*
* Preapre hsi2c transaction, either read or write.
*
* Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of
* the 5420 UM.
*
* @param i2c: pointer to the appropriate i2c register bank.
* @param chip: slave address on the i2c bus (with read/write bit exlcuded)
* @param len: number of bytes expected to be sent or received
* @param rx_transfer: set to true for receive transactions
* @param: issue_stop: set to true if i2c stop condition should be generated
* after this transaction.
* @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US,
* I2C_OK otherwise.
*/
static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c,
u8 chip,
u16 len,
bool rx_transfer,
bool issue_stop)
{
u32 conf;
conf = len | HSI2C_MASTER_RUN;
if (issue_stop)
conf |= HSI2C_STOP_AFTER_TRANS;
/* Clear to enable Timeout */
writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout);
/* Set slave address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
if (rx_transfer) {
/* i2c master, read transaction */
writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* read up to len bytes, stop after transaction is finished */
writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf);
} else {
/* i2c master, write transaction */
writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* write up to len bytes, stop after transaction is finished */
writel(conf, &i2c->usi_auto_conf);
}
/* Reset all pending interrupt status bits we care about, if any */
writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat);
return I2C_OK;
}
/*
* Wait while i2c bus is settling down (mostly stop gets completed).
*/
static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c)
{
int i = HSI2C_TIMEOUT_US;
while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) {
if (!i--) {
debug("%s: bus busy\n", __func__);
return I2C_NOK_TOUT;
}
udelay(1);
}
return I2C_OK;
}
static int hsi2c_write(struct exynos5_hsi2c *i2c,
unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len,
bool issue_stop)
{
int i, rv = 0;
if (!(len + alen)) {
/* Writes of zero length not supported in auto mode. */
debug("%s: zero length writes not supported\n", __func__);
return I2C_NOK;
}
rv = hsi2c_prepare_transaction
(i2c, chip, len + alen, false, issue_stop);
if (rv != I2C_OK)
return rv;
/* Move address, if any, and the data, if any, into the FIFO. */
for (i = 0; i < alen; i++) {
rv = hsi2c_poll_fifo(i2c, false);
if (rv != I2C_OK) {
debug("%s: address write failed\n", __func__);
goto write_error;
}
writel(addr[i], &i2c->usi_txdata);
}
for (i = 0; i < len; i++) {
rv = hsi2c_poll_fifo(i2c, false);
if (rv != I2C_OK) {
debug("%s: data write failed\n", __func__);
goto write_error;
}
writel(data[i], &i2c->usi_txdata);
}
rv = hsi2c_wait_for_trx(i2c);
write_error:
if (issue_stop) {
int tmp_ret = hsi2c_wait_while_busy(i2c);
if (rv == I2C_OK)
rv = tmp_ret;
}
writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */
return rv;
}
static int hsi2c_read(struct exynos5_hsi2c *i2c,
unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len)
{
int i, rv, tmp_ret;
bool drop_data = false;
if (!len) {
/* Reads of zero length not supported in auto mode. */
debug("%s: zero length read adjusted\n", __func__);
drop_data = true;
len = 1;
}
if (alen) {
/* Internal register adress needs to be written first. */
rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false);
if (rv != I2C_OK)
return rv;
}
rv = hsi2c_prepare_transaction(i2c, chip, len, true, true);
if (rv != I2C_OK)
return rv;
for (i = 0; i < len; i++) {
rv = hsi2c_poll_fifo(i2c, true);
if (rv != I2C_OK)
goto read_err;
if (drop_data)
continue;
data[i] = readl(&i2c->usi_rxdata);
}
rv = hsi2c_wait_for_trx(i2c);
read_err:
tmp_ret = hsi2c_wait_while_busy(i2c);
if (rv == I2C_OK)
rv = tmp_ret;
writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */
return rv;
}
static int exynos_hs_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD) {
ret = hsi2c_read(hsregs, msg->addr, 0, 0, msg->buf,
msg->len);
} else {
ret = hsi2c_write(hsregs, msg->addr, 0, 0, msg->buf,
msg->len, true);
}
if (ret) {
exynos5_i2c_reset(i2c_bus);
return -EREMOTEIO;
}
}
return 0;
}
static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->clock_frequency = speed;
if (hsi2c_get_clk_details(i2c_bus))
return -EFAULT;
hsi2c_ch_init(i2c_bus);
return 0;
}
static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
uchar buf[1];
int ret;
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buf, 1);
return ret != I2C_OK;
}
static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int node;
node = dev_of_offset(dev);
i2c_bus->hsregs = (struct exynos5_hsi2c *)devfdt_get_addr(dev);
i2c_bus->id = pinmux_decode_periph_id(blob, node);
i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
"clock-frequency", 100000);
i2c_bus->node = node;
i2c_bus->bus_num = dev->seq;
exynos_pinmux_config(i2c_bus->id, PINMUX_FLAG_HS_MODE);
i2c_bus->active = true;
return 0;
}
static const struct dm_i2c_ops exynos_hs_i2c_ops = {
.xfer = exynos_hs_i2c_xfer,
.probe_chip = s3c24x0_i2c_probe,
.set_bus_speed = s3c24x0_i2c_set_bus_speed,
};
static const struct udevice_id exynos_hs_i2c_ids[] = {
{ .compatible = "samsung,exynos5-hsi2c" },
{ }
};
U_BOOT_DRIVER(hs_i2c) = {
.name = "i2c_s3c_hs",
.id = UCLASS_I2C,
.of_match = exynos_hs_i2c_ids,
.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &exynos_hs_i2c_ops,
};
@@ -0,0 +1,654 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2006,2009 Freescale Semiconductor, Inc.
*
* 2012, Heiko Schocher, DENX Software Engineering, hs@denx.de.
* Changes for multibus/multiadapter I2C support.
*/
#include <common.h>
#include <command.h>
#include <i2c.h> /* Functional interface */
#include <time.h>
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
#include <clk.h>
#include <dm.h>
#include <mapmem.h>
/* The maximum number of microseconds we will wait until another master has
* released the bus. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_MBB_TIMEOUT
#define CONFIG_I2C_MBB_TIMEOUT 100000
#endif
/* The maximum number of microseconds we will wait for a read or write
* operation to complete. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_TIMEOUT
#define CONFIG_I2C_TIMEOUT 100000
#endif
#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_DM_I2C
static const struct fsl_i2c_base *i2c_base[4] = {
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET),
#endif
#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C3_OFFSET),
#endif
#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C4_OFFSET)
#endif
};
#endif
/* I2C speed map for a DFSR value of 1 */
#ifdef __M68K__
/*
* Map I2C frequency dividers to FDR and DFSR values
*
* This structure is used to define the elements of a table that maps I2C
* frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
* programmed into the Frequency Divider Ratio (FDR) and Digital Filter
* Sampling Rate (DFSR) registers.
*
* The actual table should be defined in the board file, and it must be called
* fsl_i2c_speed_map[].
*
* The last entry of the table must have a value of {-1, X}, where X is same
* FDR/DFSR values as the second-to-last entry. This guarantees that any
* search through the array will always find a match.
*
* The values of the divider must be in increasing numerical order, i.e.
* fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
*
* For this table, the values are based on a value of 1 for the DFSR
* register. See the application note AN2919 "Determining the I2C Frequency
* Divider Ratio for SCL"
*
* ColdFire I2C frequency dividers for FDR values are different from
* PowerPC. The protocol to use the I2C module is still the same.
* A different table is defined and are based on MCF5xxx user manual.
*
*/
static const struct {
unsigned short divider;
u8 fdr;
} fsl_i2c_speed_map[] = {
{20, 32}, {22, 33}, {24, 34}, {26, 35},
{28, 0}, {28, 36}, {30, 1}, {32, 37},
{34, 2}, {36, 38}, {40, 3}, {40, 39},
{44, 4}, {48, 5}, {48, 40}, {56, 6},
{56, 41}, {64, 42}, {68, 7}, {72, 43},
{80, 8}, {80, 44}, {88, 9}, {96, 41},
{104, 10}, {112, 42}, {128, 11}, {128, 43},
{144, 12}, {160, 13}, {160, 48}, {192, 14},
{192, 49}, {224, 50}, {240, 15}, {256, 51},
{288, 16}, {320, 17}, {320, 52}, {384, 18},
{384, 53}, {448, 54}, {480, 19}, {512, 55},
{576, 20}, {640, 21}, {640, 56}, {768, 22},
{768, 57}, {960, 23}, {896, 58}, {1024, 59},
{1152, 24}, {1280, 25}, {1280, 60}, {1536, 26},
{1536, 61}, {1792, 62}, {1920, 27}, {2048, 63},
{2304, 28}, {2560, 29}, {3072, 30}, {3840, 31},
{-1, 31}
};
#endif
/**
* Set the I2C bus speed for a given I2C device
*
* @param base: the I2C device registers
* @i2c_clk: I2C bus clock frequency
* @speed: the desired speed of the bus
*
* The I2C device must be stopped before calling this function.
*
* The return value is the actual bus speed that is set.
*/
static uint set_i2c_bus_speed(const struct fsl_i2c_base *base,
uint i2c_clk, uint speed)
{
ushort divider = min(i2c_clk / speed, (uint)USHRT_MAX);
/*
* We want to choose an FDR/DFSR that generates an I2C bus speed that
* is equal to or lower than the requested speed. That means that we
* want the first divider that is equal to or greater than the
* calculated divider.
*/
#ifdef __PPC__
u8 dfsr, fdr = 0x31; /* Default if no FDR found */
/* a, b and dfsr matches identifiers A,B and C respectively in AN2919 */
ushort a, b, ga, gb;
ulong c_div, est_div;
#ifdef CONFIG_FSL_I2C_CUSTOM_DFSR
dfsr = CONFIG_FSL_I2C_CUSTOM_DFSR;
#else
/* Condition 1: dfsr <= 50/T */
dfsr = (5 * (i2c_clk / 1000)) / 100000;
#endif
#ifdef CONFIG_FSL_I2C_CUSTOM_FDR
fdr = CONFIG_FSL_I2C_CUSTOM_FDR;
speed = i2c_clk / divider; /* Fake something */
#else
debug("Requested speed:%d, i2c_clk:%d\n", speed, i2c_clk);
if (!dfsr)
dfsr = 1;
est_div = ~0;
for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
for (gb = 0; gb < 8; gb++) {
b = 16 << gb;
c_div = b * (a + ((3 * dfsr) / b) * 2);
if (c_div > divider && c_div < est_div) {
ushort bin_gb, bin_ga;
est_div = c_div;
bin_gb = gb << 2;
bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
fdr = bin_gb | bin_ga;
speed = i2c_clk / est_div;
debug("FDR: 0x%.2x, ", fdr);
debug("div: %ld, ", est_div);
debug("ga: 0x%x, gb: 0x%x, ", ga, gb);
debug("a: %d, b: %d, speed: %d\n", a, b, speed);
/* Condition 2 not accounted for */
debug("Tr <= %d ns\n",
(b - 3 * dfsr) * 1000000 /
(i2c_clk / 1000));
}
}
if (a == 20)
a += 2;
if (a == 24)
a += 4;
}
debug("divider: %d, est_div: %ld, DFSR: %d\n", divider, est_div, dfsr);
debug("FDR: 0x%.2x, speed: %d\n", fdr, speed);
#endif
writeb(dfsr, &base->dfsrr); /* set default filter */
writeb(fdr, &base->fdr); /* set bus speed */
#else
uint i;
for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++)
if (fsl_i2c_speed_map[i].divider >= divider) {
u8 fdr;
fdr = fsl_i2c_speed_map[i].fdr;
speed = i2c_clk / fsl_i2c_speed_map[i].divider;
writeb(fdr, &base->fdr); /* set bus speed */
break;
}
#endif
return speed;
}
#ifndef CONFIG_DM_I2C
static uint get_i2c_clock(int bus)
{
if (bus)
return gd->arch.i2c2_clk; /* I2C2 clock */
else
return gd->arch.i2c1_clk; /* I2C1 clock */
}
#endif
static int fsl_i2c_fixup(const struct fsl_i2c_base *base)
{
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
unsigned long long timeval = 0;
int ret = -1;
uint flags = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
uint svr = get_svr();
if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
(SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV))
flags = I2C_CR_BIT6;
#endif
writeb(I2C_CR_MEN | I2C_CR_MSTA, &base->cr);
timeval = get_ticks();
while (!(readb(&base->sr) & I2C_SR_MBB)) {
if ((get_ticks() - timeval) > timeout)
goto err;
}
if (readb(&base->sr) & I2C_SR_MAL) {
/* SDA is stuck low */
writeb(0, &base->cr);
udelay(100);
writeb(I2C_CR_MSTA | flags, &base->cr);
writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &base->cr);
}
readb(&base->dr);
timeval = get_ticks();
while (!(readb(&base->sr) & I2C_SR_MIF)) {
if ((get_ticks() - timeval) > timeout)
goto err;
}
ret = 0;
err:
writeb(I2C_CR_MEN | flags, &base->cr);
writeb(0, &base->sr);
udelay(100);
return ret;
}
static void __i2c_init(const struct fsl_i2c_base *base, int speed, int
slaveadd, int i2c_clk, int busnum)
{
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
unsigned long long timeval;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
writeb(0, &base->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
set_i2c_bus_speed(base, i2c_clk, speed);
writeb(slaveadd << 1, &base->adr);/* write slave address */
writeb(0x0, &base->sr); /* clear status register */
writeb(I2C_CR_MEN, &base->cr); /* start I2C controller */
timeval = get_ticks();
while (readb(&base->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) < timeout)
continue;
if (fsl_i2c_fixup(base))
debug("i2c_init: BUS#%d failed to init\n",
busnum);
break;
}
}
static int i2c_wait4bus(const struct fsl_i2c_base *base)
{
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
while (readb(&base->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) > timeout)
return -1;
}
return 0;
}
static int i2c_wait(const struct fsl_i2c_base *base, int write)
{
u32 csr;
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
do {
csr = readb(&base->sr);
if (!(csr & I2C_SR_MIF))
continue;
/* Read again to allow register to stabilise */
csr = readb(&base->sr);
writeb(0x0, &base->sr);
if (csr & I2C_SR_MAL) {
debug("%s: MAL\n", __func__);
return -1;
}
if (!(csr & I2C_SR_MCF)) {
debug("%s: unfinished\n", __func__);
return -1;
}
if (write == I2C_WRITE_BIT && (csr & I2C_SR_RXAK)) {
debug("%s: No RXACK\n", __func__);
return -1;
}
return 0;
} while ((get_ticks() - timeval) < timeout);
debug("%s: timed out\n", __func__);
return -1;
}
static int i2c_write_addr(const struct fsl_i2c_base *base, u8 dev,
u8 dir, int rsta)
{
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
| (rsta ? I2C_CR_RSTA : 0),
&base->cr);
writeb((dev << 1) | dir, &base->dr);
if (i2c_wait(base, I2C_WRITE_BIT) < 0)
return 0;
return 1;
}
static int __i2c_write_data(const struct fsl_i2c_base *base, u8 *data,
int length)
{
int i;
for (i = 0; i < length; i++) {
writeb(data[i], &base->dr);
if (i2c_wait(base, I2C_WRITE_BIT) < 0)
break;
}
return i;
}
static int __i2c_read_data(const struct fsl_i2c_base *base, u8 *data,
int length)
{
int i;
writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
&base->cr);
/* dummy read */
readb(&base->dr);
for (i = 0; i < length; i++) {
if (i2c_wait(base, I2C_READ_BIT) < 0)
break;
/* Generate ack on last next to last byte */
if (i == length - 2)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
&base->cr);
/* Do not generate stop on last byte */
if (i == length - 1)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
&base->cr);
data[i] = readb(&base->dr);
}
return i;
}
static int __i2c_read(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset,
int olen, u8 *data, int dlen)
{
int ret = -1; /* signal error */
if (i2c_wait4bus(base) < 0)
return -1;
/* Some drivers use offset lengths in excess of 4 bytes. These drivers
* adhere to the following convention:
* - the offset length is passed as negative (that is, the absolute
* value of olen is the actual offset length)
* - the offset itself is passed in data, which is overwritten by the
* subsequent read operation
*/
if (olen < 0) {
if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0)
ret = __i2c_write_data(base, data, -olen);
if (ret != -olen)
return -1;
if (dlen && i2c_write_addr(base, chip_addr,
I2C_READ_BIT, 1) != 0)
ret = __i2c_read_data(base, data, dlen);
} else {
if ((!dlen || olen > 0) &&
i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
__i2c_write_data(base, offset, olen) == olen)
ret = 0; /* No error so far */
if (dlen && i2c_write_addr(base, chip_addr, I2C_READ_BIT,
olen ? 1 : 0) != 0)
ret = __i2c_read_data(base, data, dlen);
}
writeb(I2C_CR_MEN, &base->cr);
if (i2c_wait4bus(base)) /* Wait until STOP */
debug("i2c_read: wait4bus timed out\n");
if (ret == dlen)
return 0;
return -1;
}
static int __i2c_write(const struct fsl_i2c_base *base, u8 chip_addr,
u8 *offset, int olen, u8 *data, int dlen)
{
int ret = -1; /* signal error */
if (i2c_wait4bus(base) < 0)
return -1;
if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
__i2c_write_data(base, offset, olen) == olen) {
ret = __i2c_write_data(base, data, dlen);
}
writeb(I2C_CR_MEN, &base->cr);
if (i2c_wait4bus(base)) /* Wait until STOP */
debug("i2c_write: wait4bus timed out\n");
if (ret == dlen)
return 0;
return -1;
}
static int __i2c_probe_chip(const struct fsl_i2c_base *base, uchar chip)
{
/* For unknown reason the controller will ACK when
* probing for a slave with the same address, so skip
* it.
*/
if (chip == (readb(&base->adr) >> 1))
return -1;
return __i2c_read(base, chip, 0, 0, NULL, 0);
}
static uint __i2c_set_bus_speed(const struct fsl_i2c_base *base,
uint speed, int i2c_clk)
{
writeb(0, &base->cr); /* stop controller */
set_i2c_bus_speed(base, i2c_clk, speed);
writeb(I2C_CR_MEN, &base->cr); /* start controller */
return 0;
}
#ifndef CONFIG_DM_I2C
static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
__i2c_init(i2c_base[adap->hwadapnr], speed, slaveadd,
get_i2c_clock(adap->hwadapnr), adap->hwadapnr);
}
static int fsl_i2c_probe_chip(struct i2c_adapter *adap, uchar chip)
{
return __i2c_probe_chip(i2c_base[adap->hwadapnr], chip);
}
static int fsl_i2c_read(struct i2c_adapter *adap, u8 chip_addr, uint offset,
int olen, u8 *data, int dlen)
{
u8 *o = (u8 *)&offset;
return __i2c_read(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
olen, data, dlen);
}
static int fsl_i2c_write(struct i2c_adapter *adap, u8 chip_addr, uint offset,
int olen, u8 *data, int dlen)
{
u8 *o = (u8 *)&offset;
return __i2c_write(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
olen, data, dlen);
}
static uint fsl_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
return __i2c_set_bus_speed(i2c_base[adap->hwadapnr], speed,
get_i2c_clock(adap->hwadapnr));
}
/*
* Register fsl i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
0)
#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
1)
#endif
#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_2, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C3_SPEED, CONFIG_SYS_FSL_I2C3_SLAVE,
2)
#endif
#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_3, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C4_SPEED, CONFIG_SYS_FSL_I2C4_SLAVE,
3)
#endif
#else /* CONFIG_DM_I2C */
static int fsl_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
return __i2c_probe_chip(dev->base, chip_addr);
}
static int fsl_i2c_set_bus_speed(struct udevice *bus, uint speed)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
return __i2c_set_bus_speed(dev->base, speed, dev->i2c_clk);
}
static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
struct clk clock;
dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct fsl_i2c_base));
if (!dev->base)
return -ENOMEM;
dev->index = dev_read_u32_default(bus, "cell-index", -1);
dev->slaveadd = dev_read_u32_default(bus, "u-boot,i2c-slave-addr",
0x7f);
dev->speed = dev_read_u32_default(bus, "clock-frequency", 400000);
if (!clk_get_by_index(bus, 0, &clock))
dev->i2c_clk = clk_get_rate(&clock);
else
dev->i2c_clk = dev->index ? gd->arch.i2c2_clk :
gd->arch.i2c1_clk;
return 0;
}
static int fsl_i2c_probe(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
__i2c_init(dev->base, dev->speed, dev->slaveadd, dev->i2c_clk,
dev->index);
return 0;
}
static int fsl_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return __i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
else
return __i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
}
static const struct dm_i2c_ops fsl_i2c_ops = {
.xfer = fsl_i2c_xfer,
.probe_chip = fsl_i2c_probe_chip,
.set_bus_speed = fsl_i2c_set_bus_speed,
};
static const struct udevice_id fsl_i2c_ids[] = {
{ .compatible = "fsl-i2c", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_fsl) = {
.name = "i2c_fsl",
.id = UCLASS_I2C,
.of_match = fsl_i2c_ids,
.probe = fsl_i2c_probe,
.ofdata_to_platdata = fsl_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct fsl_i2c_dev),
.ops = &fsl_i2c_ops,
};
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,506 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Moritz Fischer <moritz.fischer@ettus.com>
* IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2)
*
* This file is based on: drivers/i2c/zynq_i2c.c,
* with added driver-model support and code cleanup.
*/
#include <common.h>
#include <dm.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
#include <mapmem.h>
#include <wait_bit.h>
#include <clk.h>
/* i2c register set */
struct cdns_i2c_regs {
u32 control;
u32 status;
u32 address;
u32 data;
u32 interrupt_status;
u32 transfer_size;
u32 slave_mon_pause;
u32 time_out;
u32 interrupt_mask;
u32 interrupt_enable;
u32 interrupt_disable;
};
/* Control register fields */
#define CDNS_I2C_CONTROL_RW 0x00000001
#define CDNS_I2C_CONTROL_MS 0x00000002
#define CDNS_I2C_CONTROL_NEA 0x00000004
#define CDNS_I2C_CONTROL_ACKEN 0x00000008
#define CDNS_I2C_CONTROL_HOLD 0x00000010
#define CDNS_I2C_CONTROL_SLVMON 0x00000020
#define CDNS_I2C_CONTROL_CLR_FIFO 0x00000040
#define CDNS_I2C_CONTROL_DIV_B_SHIFT 8
#define CDNS_I2C_CONTROL_DIV_B_MASK 0x00003F00
#define CDNS_I2C_CONTROL_DIV_A_SHIFT 14
#define CDNS_I2C_CONTROL_DIV_A_MASK 0x0000C000
/* Status register values */
#define CDNS_I2C_STATUS_RXDV 0x00000020
#define CDNS_I2C_STATUS_TXDV 0x00000040
#define CDNS_I2C_STATUS_RXOVF 0x00000080
#define CDNS_I2C_STATUS_BA 0x00000100
/* Interrupt register fields */
#define CDNS_I2C_INTERRUPT_COMP 0x00000001
#define CDNS_I2C_INTERRUPT_DATA 0x00000002
#define CDNS_I2C_INTERRUPT_NACK 0x00000004
#define CDNS_I2C_INTERRUPT_TO 0x00000008
#define CDNS_I2C_INTERRUPT_SLVRDY 0x00000010
#define CDNS_I2C_INTERRUPT_RXOVF 0x00000020
#define CDNS_I2C_INTERRUPT_TXOVF 0x00000040
#define CDNS_I2C_INTERRUPT_RXUNF 0x00000080
#define CDNS_I2C_INTERRUPT_ARBLOST 0x00000200
#define CDNS_I2C_INTERRUPTS_MASK (CDNS_I2C_INTERRUPT_COMP | \
CDNS_I2C_INTERRUPT_DATA | \
CDNS_I2C_INTERRUPT_NACK | \
CDNS_I2C_INTERRUPT_TO | \
CDNS_I2C_INTERRUPT_SLVRDY | \
CDNS_I2C_INTERRUPT_RXOVF | \
CDNS_I2C_INTERRUPT_TXOVF | \
CDNS_I2C_INTERRUPT_RXUNF | \
CDNS_I2C_INTERRUPT_ARBLOST)
#define CDNS_I2C_FIFO_DEPTH 16
#define CDNS_I2C_TRANSFER_SIZE_MAX 255 /* Controller transfer limit */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_TRANSFER_SIZE_MAX - 3)
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
#define CDNS_I2C_ARB_LOST_MAX_RETRIES 10
#ifdef DEBUG
static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
{
int int_status;
int status;
int_status = readl(&cdns_i2c->interrupt_status);
status = readl(&cdns_i2c->status);
if (int_status || status) {
debug("Status: ");
if (int_status & CDNS_I2C_INTERRUPT_COMP)
debug("COMP ");
if (int_status & CDNS_I2C_INTERRUPT_DATA)
debug("DATA ");
if (int_status & CDNS_I2C_INTERRUPT_NACK)
debug("NACK ");
if (int_status & CDNS_I2C_INTERRUPT_TO)
debug("TO ");
if (int_status & CDNS_I2C_INTERRUPT_SLVRDY)
debug("SLVRDY ");
if (int_status & CDNS_I2C_INTERRUPT_RXOVF)
debug("RXOVF ");
if (int_status & CDNS_I2C_INTERRUPT_TXOVF)
debug("TXOVF ");
if (int_status & CDNS_I2C_INTERRUPT_RXUNF)
debug("RXUNF ");
if (int_status & CDNS_I2C_INTERRUPT_ARBLOST)
debug("ARBLOST ");
if (status & CDNS_I2C_STATUS_RXDV)
debug("RXDV ");
if (status & CDNS_I2C_STATUS_TXDV)
debug("TXDV ");
if (status & CDNS_I2C_STATUS_RXOVF)
debug("RXOVF ");
if (status & CDNS_I2C_STATUS_BA)
debug("BA ");
debug("TS%d ", readl(&cdns_i2c->transfer_size));
debug("\n");
}
}
#endif
struct i2c_cdns_bus {
int id;
unsigned int input_freq;
struct cdns_i2c_regs __iomem *regs; /* register base */
int hold_flag;
u32 quirks;
};
struct cdns_i2c_platform_data {
u32 quirks;
};
/* Wait for an interrupt */
static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask)
{
int timeout, int_status;
for (timeout = 0; timeout < 100; timeout++) {
int_status = readl(&cdns_i2c->interrupt_status);
if (int_status & mask)
break;
udelay(100);
}
/* Clear interrupt status flags */
writel(int_status & mask, &cdns_i2c->interrupt_status);
return int_status & mask;
}
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
unsigned int *a, unsigned int *b)
{
unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
unsigned int last_error, current_error;
/* calculate (divisor_a+1) x (divisor_b+1) */
temp = input_clk / (22 * fscl);
/*
* If the calculated value is negative or 0CDNS_I2C_DIVA_MAX,
* the fscl input is out of range. Return error.
*/
if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
return -EINVAL;
last_error = -1;
for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
continue;
div_b--;
actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
if (actual_fscl > fscl)
continue;
current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
(fscl - actual_fscl));
if (last_error > current_error) {
calc_div_a = div_a;
calc_div_b = div_b;
best_fscl = actual_fscl;
last_error = current_error;
}
}
*a = calc_div_a;
*b = calc_div_b;
*f = best_fscl;
return 0;
}
static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct i2c_cdns_bus *bus = dev_get_priv(dev);
u32 div_a = 0, div_b = 0;
unsigned long speed_p = speed;
int ret = 0;
if (speed > 400000) {
debug("%s, failed to set clock speed to %u\n", __func__,
speed);
return -EINVAL;
}
ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b);
if (ret)
return ret;
debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n",
__func__, div_a, div_b, bus->input_freq, speed, speed_p);
writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
(div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
/* Enable master mode, ack, and 7-bit addressing */
setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA);
return 0;
}
static inline u32 is_arbitration_lost(struct cdns_i2c_regs *regs)
{
return (readl(&regs->interrupt_status) & CDNS_I2C_INTERRUPT_ARBLOST);
}
static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
u32 len)
{
u8 *cur_data = data;
struct cdns_i2c_regs *regs = i2c_bus->regs;
u32 ret;
/* Set the controller in Master transmit mode and clear FIFO */
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO);
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_RW);
/* Check message size against FIFO depth, and set hold bus bit
* if it is greater than FIFO depth
*/
if (len > CDNS_I2C_FIFO_DEPTH)
setbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
/* Clear the interrupts in status register */
writel(CDNS_I2C_INTERRUPTS_MASK, &regs->interrupt_status);
writel(addr, &regs->address);
while (len-- && !is_arbitration_lost(regs)) {
writel(*(cur_data++), &regs->data);
if (len && readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_ARBLOST);
if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
return -EAGAIN;
if (ret & CDNS_I2C_INTERRUPT_COMP)
continue;
/* Release the bus */
clrbits_le32(&regs->control,
CDNS_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
}
if (len && is_arbitration_lost(regs))
return -EAGAIN;
/* All done... release the bus */
if (!i2c_bus->hold_flag)
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
/* Wait for the address and data to be sent */
ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_ARBLOST);
if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST |
CDNS_I2C_INTERRUPT_COMP)))
return -ETIMEDOUT;
if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
return -EAGAIN;
return 0;
}
static inline bool cdns_is_hold_quirk(int hold_quirk, int curr_recv_count)
{
return hold_quirk && (curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1);
}
static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
u32 recv_count)
{
u8 *cur_data = data;
struct cdns_i2c_regs *regs = i2c_bus->regs;
u32 curr_recv_count;
int updatetx, hold_quirk;
u32 ret;
curr_recv_count = recv_count;
/* Check for the message size against the FIFO depth */
if (recv_count > CDNS_I2C_FIFO_DEPTH)
setbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
CDNS_I2C_CONTROL_RW);
if (recv_count > CDNS_I2C_TRANSFER_SIZE) {
curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
writel(curr_recv_count, &regs->transfer_size);
} else {
writel(recv_count, &regs->transfer_size);
}
/* Start reading data */
writel(addr, &regs->address);
updatetx = recv_count > curr_recv_count;
hold_quirk = (i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
while (recv_count && !is_arbitration_lost(regs)) {
while (readl(&regs->status) & CDNS_I2C_STATUS_RXDV) {
if (recv_count < CDNS_I2C_FIFO_DEPTH &&
!i2c_bus->hold_flag) {
clrbits_le32(&regs->control,
CDNS_I2C_CONTROL_HOLD);
}
*(cur_data)++ = readl(&regs->data);
recv_count--;
curr_recv_count--;
if (cdns_is_hold_quirk(hold_quirk, curr_recv_count))
break;
}
if (cdns_is_hold_quirk(hold_quirk, curr_recv_count)) {
/* wait while fifo is full */
while (readl(&regs->transfer_size) !=
(curr_recv_count - CDNS_I2C_FIFO_DEPTH))
;
/*
* Check number of bytes to be received against maximum
* transfer size and update register accordingly.
*/
if ((recv_count - CDNS_I2C_FIFO_DEPTH) >
CDNS_I2C_TRANSFER_SIZE) {
writel(CDNS_I2C_TRANSFER_SIZE,
&regs->transfer_size);
curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
CDNS_I2C_FIFO_DEPTH;
} else {
writel(recv_count - CDNS_I2C_FIFO_DEPTH,
&regs->transfer_size);
curr_recv_count = recv_count;
}
} else if (recv_count && !hold_quirk && !curr_recv_count) {
writel(addr, &regs->address);
if (recv_count > CDNS_I2C_TRANSFER_SIZE) {
writel(CDNS_I2C_TRANSFER_SIZE,
&regs->transfer_size);
curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
} else {
writel(recv_count, &regs->transfer_size);
curr_recv_count = recv_count;
}
}
}
/* Wait for the address and data to be sent */
ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_ARBLOST);
if (!(ret & (CDNS_I2C_INTERRUPT_ARBLOST |
CDNS_I2C_INTERRUPT_COMP)))
return -ETIMEDOUT;
if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
return -EAGAIN;
return 0;
}
static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
int ret = 0;
int count;
bool hold_quirk;
struct i2c_msg *message = msg;
int num_msgs = nmsgs;
hold_quirk = !!(i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
if (nmsgs > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; (count < nmsgs - 1) && hold_quirk; count++) {
if (msg[count].flags & I2C_M_RD) {
printf("Can't do repeated start after a receive message\n");
return -EOPNOTSUPP;
}
}
i2c_bus->hold_flag = 1;
setbits_le32(&i2c_bus->regs->control, CDNS_I2C_CONTROL_HOLD);
} else {
i2c_bus->hold_flag = 0;
}
debug("i2c_xfer: %d messages\n", nmsgs);
for (u8 retry = 0; retry < CDNS_I2C_ARB_LOST_MAX_RETRIES &&
nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = cdns_i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = cdns_i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len);
}
if (ret == -EAGAIN) {
msg = message;
nmsgs = num_msgs;
retry++;
printf("%s,arbitration lost, retrying:%d\n", __func__,
retry);
continue;
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return ret;
}
static int cdns_i2c_ofdata_to_platdata(struct udevice *dev)
{
struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
struct cdns_i2c_platform_data *pdata =
(struct cdns_i2c_platform_data *)dev_get_driver_data(dev);
struct clk clk;
int ret;
i2c_bus->regs = (struct cdns_i2c_regs *)dev_read_addr(dev);
if (!i2c_bus->regs)
return -ENOMEM;
if (pdata)
i2c_bus->quirks = pdata->quirks;
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return ret;
i2c_bus->input_freq = clk_get_rate(&clk);
return 0;
}
static const struct dm_i2c_ops cdns_i2c_ops = {
.xfer = cdns_i2c_xfer,
.set_bus_speed = cdns_i2c_set_bus_speed,
};
static const struct cdns_i2c_platform_data r1p10_i2c_def = {
.quirks = CDNS_I2C_BROKEN_HOLD_BIT,
};
static const struct udevice_id cdns_i2c_of_match[] = {
{ .compatible = "cdns,i2c-r1p10", .data = (ulong)&r1p10_i2c_def },
{ .compatible = "cdns,i2c-r1p14" },
{ /* end of table */ }
};
U_BOOT_DRIVER(cdns_i2c) = {
.name = "i2c-cdns",
.id = UCLASS_I2C,
.of_match = cdns_i2c_of_match,
.ofdata_to_platdata = cdns_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct i2c_cdns_bus),
.ops = &cdns_i2c_ops,
};
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2014 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
/*
* i2c emulation works using an 'emul' node at the bus level. Each device in
* that node is in the UCLASS_I2C_EMUL uclass, and emulates one i2c device. A
* pointer to the device it emulates is in the 'dev' property of the emul device
* uclass platdata (struct i2c_emul_platdata), put there by i2c_emul_find().
* When sandbox wants an emulator for a device, it calls i2c_emul_find() which
* searches for the emulator with the correct address. To find the device for an
* emulator, call i2c_emul_get_device().
*
* The 'emul' node is in the UCLASS_I2C_EMUL_PARENT uclass. We use a separate
* uclass so avoid having strange devices on the I2C bus.
*/
/**
* struct i2c_emul_uc_platdata - information about the emulator for this device
*
* This is used by devices in UCLASS_I2C_EMUL to record information about the
* device being emulated. It is accessible with dev_get_uclass_platdata()
*
* @dev: Device being emulated
*/
struct i2c_emul_uc_platdata {
struct udevice *dev;
};
struct udevice *i2c_emul_get_device(struct udevice *emul)
{
struct i2c_emul_uc_platdata *uc_plat = dev_get_uclass_platdata(emul);
return uc_plat->dev;
}
int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
{
struct i2c_emul_uc_platdata *uc_plat;
struct udevice *emul;
int ret;
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
"sandbox,emul", &emul);
if (ret) {
log_err("No emulators for device '%s'\n", dev->name);
return ret;
}
uc_plat = dev_get_uclass_platdata(emul);
uc_plat->dev = dev;
*emulp = emul;
return device_probe(emul);
}
UCLASS_DRIVER(i2c_emul) = {
.id = UCLASS_I2C_EMUL,
.name = "i2c_emul",
.per_device_platdata_auto_alloc_size =
sizeof(struct i2c_emul_uc_platdata),
};
/*
* This uclass is a child of the i2c bus. Its platdata is not defined here so
* is defined by its parent, UCLASS_I2C, which uses struct dm_i2c_chip. See
* per_child_platdata_auto_alloc_size in UCLASS_DRIVER(i2c).
*/
UCLASS_DRIVER(i2c_emul_parent) = {
.id = UCLASS_I2C_EMUL_PARENT,
.name = "i2c_emul_parent",
.post_bind = dm_scan_fdt_dev,
};
static const struct udevice_id i2c_emul_parent_ids[] = {
{ .compatible = "sandbox,i2c-emul-parent" },
{ }
};
U_BOOT_DRIVER(i2c_emul_parent_drv) = {
.name = "i2c_emul_parent_drv",
.id = UCLASS_I2C_EMUL_PARENT,
.of_match = i2c_emul_parent_ids,
};
@@ -0,0 +1,347 @@
/*
* (C) Copyright 2015, Samsung Electronics
* Przemyslaw Marczak <p.marczak@samsung.com>
*
* This file is based on: drivers/i2c/soft-i2c.c,
* with added driver-model support and code cleanup.
*/
#include <common.h>
#include <errno.h>
#include <dm.h>
#include <i2c.h>
#include <asm/gpio.h>
#define DEFAULT_UDELAY 5
#define RETRIES 0
#define I2C_ACK 0
#define I2C_NOACK 1
DECLARE_GLOBAL_DATA_PTR;
enum {
PIN_SDA = 0,
PIN_SCL,
PIN_COUNT,
};
struct i2c_gpio_bus {
/**
* udelay - delay [us] between GPIO toggle operations,
* which is 1/4 of I2C speed clock period.
*/
int udelay;
/* sda, scl */
struct gpio_desc gpios[PIN_COUNT];
};
static int i2c_gpio_sda_get(struct gpio_desc *sda)
{
return dm_gpio_get_value(sda);
}
static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
{
if (bit)
dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
else
dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
}
static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
{
ulong flags = GPIOD_IS_OUT;
if (bit)
flags |= GPIOD_IS_OUT_ACTIVE;
dm_gpio_set_dir_flags(scl, flags);
}
static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, uchar bit)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, bit);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(2 * delay);
}
static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
int value;
i2c_gpio_scl_set(scl, 1);
udelay(delay);
value = i2c_gpio_sda_get(sda);
udelay(delay);
i2c_gpio_scl_set(scl, 0);
udelay(2 * delay);
return value;
}
/* START: High -> Low on SDA while SCL is High */
static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(delay);
i2c_gpio_sda_set(sda, 0);
udelay(delay);
}
/* STOP: Low -> High on SDA while SCL is High */
static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, 0);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
}
/* ack should be I2C_ACK or I2C_NOACK */
static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, int ack)
{
i2c_gpio_write_bit(scl, sda, delay, ack);
i2c_gpio_scl_set(scl, 0);
udelay(delay);
}
/**
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
int j;
for (j = 0; j < 9; j++)
i2c_gpio_write_bit(scl, sda, delay, 1);
i2c_gpio_send_stop(scl, sda, delay);
}
/* Set sda high with low clock, before reading slave data */
static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
}
/* Send 8 bits and look for an acknowledgement */
static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, uchar data)
{
int j;
int nack;
for (j = 0; j < 8; j++) {
i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
data <<= 1;
}
udelay(delay);
/* Look for an <ACK>(negative logic) and return it */
i2c_gpio_sda_high(scl, sda, delay);
nack = i2c_gpio_read_bit(scl, sda, delay);
return nack; /* not a nack is an ack */
}
/**
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, int ack)
{
int data;
int j;
i2c_gpio_sda_high(scl, sda, delay);
data = 0;
for (j = 0; j < 8; j++) {
data <<= 1;
data |= i2c_gpio_read_bit(scl, sda, delay);
}
i2c_gpio_send_ack(scl, sda, delay, ack);
return data;
}
/* send start and the slave chip address */
int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
uchar chip)
{
i2c_gpio_send_start(scl, sda, delay);
if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
i2c_gpio_send_stop(scl, sda, delay);
return -EIO;
}
return 0;
}
static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len,
bool end_with_repeated_start)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int failures = 0;
debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
while (len-- > 0) {
if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
failures++;
}
if (!end_with_repeated_start) {
i2c_gpio_send_stop(scl, sda, delay);
return failures;
}
if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
return failures;
}
static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
while (len-- > 0)
*buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
i2c_gpio_send_stop(scl, sda, delay);
return 0;
}
static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
if (msg->flags & I2C_M_RD) {
ret = i2c_gpio_read_data(bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int ret;
i2c_gpio_send_start(scl, sda, delay);
ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
i2c_gpio_send_stop(scl, sda, delay);
debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
__func__, dev->seq, dev->name, chip, chip_flags, ret);
return ret;
}
static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
bus->udelay = 1000000 / (speed_hz << 2);
i2c_gpio_send_reset(scl, sda, bus->udelay);
return 0;
}
static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
int ret;
ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
ARRAY_SIZE(bus->gpios), 0);
if (ret < 0)
goto error;
bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
DEFAULT_UDELAY);
return 0;
error:
pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
return ret;
}
static const struct dm_i2c_ops i2c_gpio_ops = {
.xfer = i2c_gpio_xfer,
.probe_chip = i2c_gpio_probe,
.set_bus_speed = i2c_gpio_set_bus_speed,
};
static const struct udevice_id i2c_gpio_ids[] = {
{ .compatible = "i2c-gpio" },
{ }
};
U_BOOT_DRIVER(i2c_gpio) = {
.name = "i2c-gpio",
.id = UCLASS_I2C,
.of_match = i2c_gpio_ids,
.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
.ops = &i2c_gpio_ops,
};
@@ -0,0 +1,715 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2014 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#ifdef CONFIG_DM_GPIO
#include <asm/gpio.h>
#endif
#define I2C_MAX_OFFSET_LEN 4
enum {
PIN_SDA = 0,
PIN_SCL,
PIN_COUNT,
};
/* Useful debugging function */
void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
{
int i;
for (i = 0; i < nmsgs; i++) {
struct i2c_msg *m = &msg[i];
printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
msg->addr, msg->len);
if (!(m->flags & I2C_M_RD))
printf(": %x", m->buf[0]);
printf("\n");
}
}
/**
* i2c_setup_offset() - Set up a new message with a chip offset
*
* @chip: Chip to use
* @offset: Byte offset within chip
* @offset_buf: Place to put byte offset
* @msg: Message buffer
* @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the
* message is still set up but will not contain an offset.
*/
static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
uint8_t offset_buf[], struct i2c_msg *msg)
{
int offset_len;
msg->addr = chip->chip_addr;
msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
msg->len = chip->offset_len;
msg->buf = offset_buf;
if (!chip->offset_len)
return -EADDRNOTAVAIL;
assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
offset_len = chip->offset_len;
while (offset_len--)
*offset_buf++ = offset >> (8 * offset_len);
return 0;
}
static int i2c_read_bytewise(struct udevice *dev, uint offset,
uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
int ret;
int i;
for (i = 0; i < len; i++) {
if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
return -EINVAL;
ptr = msg + 1;
ptr->addr = chip->chip_addr;
ptr->flags = msg->flags | I2C_M_RD;
ptr->len = 1;
ptr->buf = &buffer[i];
ptr++;
ret = ops->xfer(bus, msg, ptr - msg);
if (ret)
return ret;
}
return 0;
}
static int i2c_write_bytewise(struct udevice *dev, uint offset,
const uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
int ret;
int i;
for (i = 0; i < len; i++) {
if (i2c_setup_offset(chip, offset + i, buf, msg))
return -EINVAL;
buf[msg->len++] = buffer[i];
ret = ops->xfer(bus, msg, 1);
if (ret)
return ret;
}
return 0;
}
int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
int msg_count;
if (!ops->xfer)
return -ENOSYS;
if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
return i2c_read_bytewise(dev, offset, buffer, len);
ptr = msg;
if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
ptr++;
if (len) {
ptr->addr = chip->chip_addr;
ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
ptr->flags |= I2C_M_RD;
ptr->len = len;
ptr->buf = buffer;
ptr++;
}
msg_count = ptr - msg;
return ops->xfer(bus, msg, msg_count);
}
int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
if (!ops->xfer)
return -ENOSYS;
if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
return i2c_write_bytewise(dev, offset, buffer, len);
/*
* The simple approach would be to send two messages here: one to
* set the offset and one to write the bytes. However some drivers
* will not be expecting this, and some chips won't like how the
* driver presents this on the I2C bus.
*
* The API does not support separate offset and data. We could extend
* it with a flag indicating that there is data in the next message
* that needs to be processed in the same transaction. We could
* instead add an additional buffer to each message. For now, handle
* this in the uclass since it isn't clear what the impact on drivers
* would be with this extra complication. Unfortunately this means
* copying the message.
*
* Use the stack for small messages, malloc() for larger ones. We
* need to allow space for the offset (up to 4 bytes) and the message
* itself.
*/
if (len < 64) {
uint8_t buf[I2C_MAX_OFFSET_LEN + len];
i2c_setup_offset(chip, offset, buf, msg);
msg->len += len;
memcpy(buf + chip->offset_len, buffer, len);
return ops->xfer(bus, msg, 1);
} else {
uint8_t *buf;
int ret;
buf = malloc(I2C_MAX_OFFSET_LEN + len);
if (!buf)
return -ENOMEM;
i2c_setup_offset(chip, offset, buf, msg);
msg->len += len;
memcpy(buf + chip->offset_len, buffer, len);
ret = ops->xfer(bus, msg, 1);
free(buf);
return ret;
}
}
int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
if (!ops->xfer)
return -ENOSYS;
return ops->xfer(bus, msg, nmsgs);
}
int dm_i2c_reg_read(struct udevice *dev, uint offset)
{
uint8_t val;
int ret;
ret = dm_i2c_read(dev, offset, &val, 1);
if (ret < 0)
return ret;
return val;
}
int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
{
uint8_t val = value;
return dm_i2c_write(dev, offset, &val, 1);
}
/**
* i2c_probe_chip() - probe for a chip on a bus
*
* @bus: Bus to probe
* @chip_addr: Chip address to probe
* @flags: Flags for the chip
* @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip
* does not respond to probe
*/
static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
enum dm_i2c_chip_flags chip_flags)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
int ret;
if (ops->probe_chip) {
ret = ops->probe_chip(bus, chip_addr, chip_flags);
if (!ret || ret != -ENOSYS)
return ret;
}
if (!ops->xfer)
return -ENOSYS;
/* Probe with a zero-length message */
msg->addr = chip_addr;
msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
msg->len = 0;
msg->buf = NULL;
return ops->xfer(bus, msg, 1);
}
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct dm_i2c_chip *chip;
char name[30], *str;
struct udevice *dev;
int ret;
snprintf(name, sizeof(name), "generic_%x", chip_addr);
str = strdup(name);
if (!str)
return -ENOMEM;
ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
debug("%s: device_bind_driver: ret=%d\n", __func__, ret);
if (ret)
goto err_bind;
/* Tell the device what we know about it */
chip = dev_get_parent_platdata(dev);
chip->chip_addr = chip_addr;
chip->offset_len = offset_len;
ret = device_probe(dev);
debug("%s: device_probe: ret=%d\n", __func__, ret);
if (ret)
goto err_probe;
*devp = dev;
return 0;
err_probe:
/*
* If the device failed to probe, unbind it. There is nothing there
* on the bus so we don't want to leave it lying around
*/
device_unbind(dev);
err_bind:
free(str);
return ret;
}
int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *dev;
debug("%s: Searching bus '%s' for address %02x: ", __func__,
bus->name, chip_addr);
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
if (chip->chip_addr == chip_addr) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
if (ret)
return ret;
*devp = dev;
return 0;
}
}
debug("not found\n");
return i2c_bind_driver(bus, chip_addr, offset_len, devp);
}
int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *bus;
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
if (ret) {
debug("Cannot find I2C bus %d\n", busnum);
return ret;
}
/* detect the presence of the chip on the bus */
ret = i2c_probe_chip(bus, chip_addr, 0);
debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
chip_addr, ret);
if (ret) {
debug("Cannot detect I2C chip %02x on bus %d\n", chip_addr,
busnum);
return ret;
}
ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
if (ret) {
debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
busnum);
return ret;
}
return 0;
}
int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
struct udevice **devp)
{
int ret;
*devp = NULL;
/* First probe that chip */
ret = i2c_probe_chip(bus, chip_addr, chip_flags);
debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
chip_addr, ret);
if (ret)
return ret;
/* The chip was found, see if we have a driver, and probe it */
ret = i2c_get_chip(bus, chip_addr, 1, devp);
debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
return ret;
}
int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
int ret;
/*
* If we have a method, call it. If not then the driver probably wants
* to deal with speed changes on the next transfer. It can easily read
* the current speed from this uclass
*/
if (ops->set_bus_speed) {
ret = ops->set_bus_speed(bus, speed);
if (ret)
return ret;
}
i2c->speed_hz = speed;
return 0;
}
int dm_i2c_get_bus_speed(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
if (!ops->get_bus_speed)
return i2c->speed_hz;
return ops->get_bus_speed(bus);
}
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
struct udevice *bus = dev->parent;
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int ret;
if (ops->set_flags) {
ret = ops->set_flags(dev, flags);
if (ret)
return ret;
}
chip->flags = flags;
return 0;
}
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
*flagsp = chip->flags;
return 0;
}
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
return -EINVAL;
chip->offset_len = offset_len;
return 0;
}
int i2c_get_chip_offset_len(struct udevice *dev)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
return chip->offset_len;
}
#ifdef CONFIG_DM_GPIO
static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
{
if (bit)
dm_gpio_set_dir_flags(pin, GPIOD_IS_IN);
else
dm_gpio_set_dir_flags(pin, GPIOD_IS_OUT |
GPIOD_ACTIVE_LOW |
GPIOD_IS_OUT_ACTIVE);
}
static int i2c_gpio_get_pin(struct gpio_desc *pin)
{
return dm_gpio_get_value(pin);
}
static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
struct gpio_desc *scl_pin)
{
int counter = 9;
int ret = 0;
i2c_gpio_set_pin(sda_pin, 1);
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
/* Toggle SCL until slave release SDA */
while (counter-- >= 0) {
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
i2c_gpio_set_pin(scl_pin, 0);
udelay(5);
if (i2c_gpio_get_pin(sda_pin))
break;
}
/* Then, send I2C stop */
i2c_gpio_set_pin(sda_pin, 0);
udelay(5);
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
i2c_gpio_set_pin(sda_pin, 1);
udelay(5);
if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
ret = -EREMOTEIO;
return ret;
}
static int i2c_deblock_gpio(struct udevice *bus)
{
struct gpio_desc gpios[PIN_COUNT];
int ret, ret0;
ret = gpio_request_list_by_name(bus, "gpios", gpios,
ARRAY_SIZE(gpios), GPIOD_IS_IN);
if (ret != ARRAY_SIZE(gpios)) {
debug("%s: I2C Node '%s' has no 'gpios' property %s\n",
__func__, dev_read_name(bus), bus->name);
if (ret >= 0) {
gpio_free_list(bus, gpios, ret);
ret = -ENOENT;
}
goto out;
}
ret = pinctrl_select_state(bus, "gpio");
if (ret) {
debug("%s: I2C Node '%s' has no 'gpio' pinctrl state. %s\n",
__func__, dev_read_name(bus), bus->name);
goto out_no_pinctrl;
}
ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
ret = pinctrl_select_state(bus, "default");
if (ret) {
debug("%s: I2C Node '%s' has no 'default' pinctrl state. %s\n",
__func__, dev_read_name(bus), bus->name);
}
ret = !ret ? ret0 : ret;
out_no_pinctrl:
gpio_free_list(bus, gpios, ARRAY_SIZE(gpios));
out:
return ret;
}
#else
static int i2c_deblock_gpio(struct udevice *bus)
{
return -ENOSYS;
}
#endif // CONFIG_DM_GPIO
int i2c_deblock(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
if (!ops->deblock)
return i2c_deblock_gpio(bus);
return ops->deblock(bus);
}
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip)
{
int addr;
chip->offset_len = dev_read_u32_default(dev, "u-boot,i2c-offset-len",
1);
chip->flags = 0;
addr = dev_read_u32_default(dev, "reg", -1);
if (addr == -1) {
debug("%s: I2C Node '%s' has no 'reg' property %s\n", __func__,
dev_read_name(dev), dev->name);
return -EINVAL;
}
chip->chip_addr = addr;
return 0;
}
#endif
static int i2c_pre_probe(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
unsigned int max = 0;
ofnode node;
int ret;
i2c->max_transaction_bytes = 0;
dev_for_each_subnode(node, dev) {
ret = ofnode_read_u32(node,
"u-boot,i2c-transaction-bytes",
&max);
if (!ret && max > i2c->max_transaction_bytes)
i2c->max_transaction_bytes = max;
}
debug("%s: I2C bus: %s max transaction bytes: %d\n", __func__,
dev->name, i2c->max_transaction_bytes);
#endif
return 0;
}
static int i2c_post_probe(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
i2c->speed_hz = dev_read_u32_default(dev, "clock-frequency", 100000);
return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
#else
return 0;
#endif
}
static int i2c_child_post_bind(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
if (!dev_of_valid(dev))
return 0;
return i2c_chip_ofdata_to_platdata(dev, plat);
#else
return 0;
#endif
}
struct i2c_priv {
int max_id;
};
static int i2c_post_bind(struct udevice *dev)
{
struct uclass *class = dev->uclass;
struct i2c_priv *priv = class->priv;
int ret = 0;
/* Just for sure */
if (!priv)
return -ENOMEM;
debug("%s: %s, req_seq=%d\n", __func__, dev->name, dev->req_seq);
/* if there is no alias ID, use the first free */
if (dev->req_seq == -1)
dev->req_seq = ++priv->max_id;
debug("%s: %s, new req_seq=%d\n", __func__, dev->name, dev->req_seq);
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
ret = dm_scan_fdt_dev(dev);
#endif
return ret;
}
int i2c_uclass_init(struct uclass *class)
{
struct i2c_priv *priv = class->priv;
/* Just for sure */
if (!priv)
return -ENOMEM;
/* Get the last allocated alias. */
#if CONFIG_IS_ENABLED(OF_CONTROL)
priv->max_id = dev_read_alias_highest_id("i2c");
#else
priv->max_id = -1;
#endif
debug("%s: highest alias id is %d\n", __func__, priv->max_id);
return 0;
}
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = i2c_post_bind,
.init = i2c_uclass_init,
.priv_auto_alloc_size = sizeof(struct i2c_priv),
.pre_probe = i2c_pre_probe,
.post_probe = i2c_post_probe,
.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_post_bind = i2c_child_post_bind,
};
UCLASS_DRIVER(i2c_generic) = {
.id = UCLASS_I2C_GENERIC,
.name = "i2c_generic",
};
U_BOOT_DRIVER(i2c_generic_chip_drv) = {
.name = "i2c_generic_chip_drv",
.id = UCLASS_I2C_GENERIC,
};
@@ -0,0 +1,330 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/sizes.h>
#include <linux/types.h>
#include <dm.h>
#include <i2c.h>
#include <fdtdec.h>
struct uniphier_fi2c_regs {
u32 cr; /* control register */
#define I2C_CR_MST (1 << 3) /* master mode */
#define I2C_CR_STA (1 << 2) /* start condition */
#define I2C_CR_STO (1 << 1) /* stop condition */
#define I2C_CR_NACK (1 << 0) /* not ACK */
u32 dttx; /* send FIFO (write-only) */
#define dtrx dttx /* receive FIFO (read-only) */
#define I2C_DTTX_CMD (1 << 8) /* send command (slave addr) */
#define I2C_DTTX_RD (1 << 0) /* read */
u32 __reserved; /* no register at offset 0x08 */
u32 slad; /* slave address */
u32 cyc; /* clock cycle control */
u32 lctl; /* clock low period control */
u32 ssut; /* restart/stop setup time control */
u32 dsut; /* data setup time control */
u32 intr; /* interrupt status */
u32 ie; /* interrupt enable */
u32 ic; /* interrupt clear */
#define I2C_INT_TE (1 << 9) /* TX FIFO empty */
#define I2C_INT_RB (1 << 4) /* received specified bytes */
#define I2C_INT_NA (1 << 2) /* no answer */
#define I2C_INT_AL (1 << 1) /* arbitration lost */
u32 sr; /* status register */
#define I2C_SR_DB (1 << 12) /* device busy */
#define I2C_SR_BB (1 << 8) /* bus busy */
#define I2C_SR_RFF (1 << 3) /* Rx FIFO full */
#define I2C_SR_RNE (1 << 2) /* Rx FIFO not empty */
#define I2C_SR_TNF (1 << 1) /* Tx FIFO not full */
#define I2C_SR_TFE (1 << 0) /* Tx FIFO empty */
u32 __reserved2; /* no register at offset 0x30 */
u32 rst; /* reset control */
#define I2C_RST_TBRST (1 << 2) /* clear Tx FIFO */
#define I2C_RST_RBRST (1 << 1) /* clear Rx FIFO */
#define I2C_RST_RST (1 << 0) /* forcible bus reset */
u32 bm; /* bus monitor */
u32 noise; /* noise filter control */
u32 tbc; /* Tx byte count setting */
u32 rbc; /* Rx byte count setting */
u32 tbcm; /* Tx byte count monitor */
u32 rbcm; /* Rx byte count monitor */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1) /* normal operation */
#define I2C_BRST_RSCLO (1 << 0) /* release SCL low fixing */
};
#define FIOCLK 50000000
struct uniphier_fi2c_priv {
struct udevice *dev;
struct uniphier_fi2c_regs __iomem *regs; /* register base */
unsigned long fioclk; /* internal operation clock */
unsigned long timeout; /* time out (us) */
};
static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
{
writel(I2C_RST_RST, &priv->regs->rst);
}
static int uniphier_fi2c_check_bus_busy(struct uniphier_fi2c_priv *priv)
{
u32 val;
int ret;
ret = readl_poll_timeout(&priv->regs->sr, val, !(val & I2C_SR_DB), 100);
if (ret < 0) {
dev_dbg(priv->dev, "error: device busy too long. reset...\n");
uniphier_fi2c_reset(priv);
}
return ret;
}
static int uniphier_fi2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
struct uniphier_fi2c_priv *priv = dev_get_priv(dev);
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = devm_ioremap(dev, addr, SZ_128);
if (!priv->regs)
return -ENOMEM;
priv->fioclk = FIOCLK;
priv->dev = dev;
/* bus forcible reset */
uniphier_fi2c_reset(priv);
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
return 0;
}
static int wait_for_irq(struct uniphier_fi2c_priv *priv, u32 flags,
bool *stop)
{
u32 irq;
int ret;
ret = readl_poll_timeout(&priv->regs->intr, irq, irq & flags,
priv->timeout);
if (ret < 0) {
dev_dbg(priv->dev, "error: time out\n");
return ret;
}
if (irq & I2C_INT_AL) {
dev_dbg(priv->dev, "error: arbitration lost\n");
*stop = false;
return ret;
}
if (irq & I2C_INT_NA) {
dev_dbg(priv->dev, "error: no answer\n");
return ret;
}
return 0;
}
static int issue_stop(struct uniphier_fi2c_priv *priv, int old_ret)
{
int ret;
dev_dbg(priv->dev, "stop condition\n");
writel(I2C_CR_MST | I2C_CR_STO, &priv->regs->cr);
ret = uniphier_fi2c_check_bus_busy(priv);
if (ret < 0)
dev_dbg(priv->dev, "error: device busy after operation\n");
return old_ret ? old_ret : ret;
}
static int uniphier_fi2c_transmit(struct uniphier_fi2c_priv *priv, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = priv->regs;
dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
dev_dbg(priv->dev, "start condition\n");
writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
ret = wait_for_irq(priv, irq_flags, stop);
if (ret < 0)
goto error;
while (len--) {
dev_dbg(priv->dev, "sending %x\n", *buf);
writel(*buf++, &regs->dttx);
writel(irq_flags, &regs->ic);
ret = wait_for_irq(priv, irq_flags, stop);
if (ret < 0)
goto error;
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(priv, ret);
return ret;
}
static int uniphier_fi2c_receive(struct uniphier_fi2c_priv *priv, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret = 0;
const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = priv->regs;
dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
/*
* In case 'len == 0', only the slave address should be sent
* for probing, which is covered by the transmit function.
*/
if (len == 0)
return uniphier_fi2c_transmit(priv, addr, len, buf, stop);
writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
writel(0, &regs->rbc);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
dev_dbg(priv->dev, "start condition\n");
writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
&regs->cr);
while (len--) {
ret = wait_for_irq(priv, irq_flags, stop);
if (ret < 0)
goto error;
*buf++ = readl(&regs->dtrx);
dev_dbg(priv->dev, "received %x\n", *(buf - 1));
if (len == 1)
writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
writel(irq_flags, &regs->ic);
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(priv, ret);
return ret;
}
static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret;
struct uniphier_fi2c_priv *priv = dev_get_priv(bus);
bool stop;
ret = uniphier_fi2c_check_bus_busy(priv);
if (ret < 0)
return ret;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_fi2c_receive(priv, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_fi2c_transmit(priv, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
int ret;
unsigned int clk_count;
struct uniphier_fi2c_priv *priv = dev_get_priv(bus);
struct uniphier_fi2c_regs __iomem *regs = priv->regs;
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
ret = uniphier_fi2c_check_bus_busy(priv);
if (ret < 0)
return ret;
/* make sure the bus is idle when changing the frequency */
writel(I2C_BRST_RSCLO, &regs->brst);
clk_count = priv->fioclk / speed;
writel(clk_count, &regs->cyc);
writel(clk_count / 2, &regs->lctl);
writel(clk_count / 2, &regs->ssut);
writel(clk_count / 16, &regs->dsut);
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec.
* This time out value is long enough.
*/
priv->timeout = 100000000L / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_fi2c_ops = {
.xfer = uniphier_fi2c_xfer,
.set_bus_speed = uniphier_fi2c_set_bus_speed,
};
static const struct udevice_id uniphier_fi2c_of_match[] = {
{ .compatible = "socionext,uniphier-fi2c" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(uniphier_fi2c) = {
.name = "uniphier-fi2c",
.id = UCLASS_I2C,
.of_match = uniphier_fi2c_of_match,
.probe = uniphier_fi2c_probe,
.priv_auto_alloc_size = sizeof(struct uniphier_fi2c_priv),
.ops = &uniphier_fi2c_ops,
};
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <linux/types.h>
#include <dm.h>
#include <fdtdec.h>
#include <i2c.h>
struct uniphier_i2c_regs {
u32 dtrm; /* data transmission */
#define I2C_DTRM_STA (1 << 10)
#define I2C_DTRM_STO (1 << 9)
#define I2C_DTRM_NACK (1 << 8)
#define I2C_DTRM_RD (1 << 0)
u32 drec; /* data reception */
#define I2C_DREC_STS (1 << 12)
#define I2C_DREC_LRB (1 << 11)
#define I2C_DREC_LAB (1 << 9)
u32 myad; /* slave address */
u32 clk; /* clock frequency control */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1)
#define I2C_BRST_BRST (1 << 0)
u32 hold; /* hold time control */
u32 bsts; /* bus status monitor */
u32 noise; /* noise filter control */
u32 setup; /* setup time control */
};
#define IOBUS_FREQ 100000000
struct uniphier_i2c_priv {
struct udevice *dev;
struct uniphier_i2c_regs __iomem *regs; /* register base */
unsigned long input_clk; /* master clock (Hz) */
unsigned long wait_us; /* wait for every byte transfer (us) */
};
static int uniphier_i2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
struct uniphier_i2c_priv *priv = dev_get_priv(dev);
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = devm_ioremap(dev, addr, SZ_64);
if (!priv->regs)
return -ENOMEM;
priv->input_clk = IOBUS_FREQ;
priv->dev = dev;
/* deassert reset */
writel(0x3, &priv->regs->brst);
return 0;
}
static int send_and_recv_byte(struct uniphier_i2c_priv *priv, u32 dtrm)
{
writel(dtrm, &priv->regs->dtrm);
/*
* This controller only provides interruption to inform the completion
* of each byte transfer. (No status register to poll it.)
* Unfortunately, U-Boot does not have a good support of interrupt.
* Wait for a while.
*/
udelay(priv->wait_us);
return readl(&priv->regs->drec);
}
static int send_byte(struct uniphier_i2c_priv *priv, u32 dtrm, bool *stop)
{
int ret = 0;
u32 drec;
drec = send_and_recv_byte(priv, dtrm);
if (drec & I2C_DREC_LAB) {
dev_dbg(priv->dev, "uniphier_i2c: bus arbitration failed\n");
*stop = false;
ret = -EREMOTEIO;
}
if (drec & I2C_DREC_LRB) {
dev_dbg(priv->dev, "uniphier_i2c: slave did not return ACK\n");
ret = -EREMOTEIO;
}
return ret;
}
static int uniphier_i2c_transmit(struct uniphier_i2c_priv *priv, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--) {
ret = send_byte(priv, I2C_DTRM_NACK | *buf++, stop);
if (ret < 0)
goto fail;
}
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm);
return ret;
}
static int uniphier_i2c_receive(struct uniphier_i2c_priv *priv, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret;
dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK |
I2C_DTRM_RD | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--)
*buf++ = send_and_recv_byte(priv, len ? 0 : I2C_DTRM_NACK);
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm);
return ret;
}
static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret = 0;
struct uniphier_i2c_priv *priv = dev_get_priv(bus);
bool stop;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_i2c_receive(priv, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_i2c_transmit(priv, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct uniphier_i2c_priv *priv = dev_get_priv(bus);
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
/* bus reset: make sure the bus is idle when change the frequency */
writel(0x1, &priv->regs->brst);
writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
&priv->regs->clk);
writel(0x3, &priv->regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec. For safety, wait more than double.
*/
priv->wait_us = 20000000 / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_i2c_ops = {
.xfer = uniphier_i2c_xfer,
.set_bus_speed = uniphier_i2c_set_bus_speed,
};
static const struct udevice_id uniphier_i2c_of_match[] = {
{ .compatible = "socionext,uniphier-i2c" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(uniphier_i2c) = {
.name = "uniphier-i2c",
.id = UCLASS_I2C,
.of_match = uniphier_i2c_of_match,
.probe = uniphier_i2c_probe,
.priv_auto_alloc_size = sizeof(struct uniphier_i2c_priv),
.ops = &uniphier_i2c_ops,
};
@@ -0,0 +1,280 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2018 Arm Ltd.
* Author: Liviu Dudau <liviu.dudau@foss.arm.com>
*
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/io.h>
#include <clk.h>
#include <linux/io.h>
#define I2C_CONTROL_REG 0x00
#define I2C_SET_REG 0x00
#define I2C_CLEAR_REG 0x04
#define SCL BIT(0)
#define SDA BIT(1)
struct versatile_i2c_priv {
phys_addr_t base;
u32 delay;
};
static inline void versatile_sda_set(struct versatile_i2c_priv *priv, u8 state)
{
writel(SDA, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
udelay(priv->delay);
}
static inline int versatile_sda_get(struct versatile_i2c_priv *priv)
{
int v = !!(readl(priv->base + I2C_CONTROL_REG) & SDA);
udelay(priv->delay);
return v;
}
static inline void versatile_scl_set(struct versatile_i2c_priv *priv, u8 state)
{
writel(SCL, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
udelay(priv->delay);
}
static inline int versatile_scl_get(struct versatile_i2c_priv *priv)
{
int v = !!(readl(priv->base + I2C_CONTROL_REG) & SCL);
udelay(priv->delay);
return v;
}
/* start: SDA goes from high to low while SCL is high */
static void versatile_i2c_start(struct versatile_i2c_priv *priv)
{
udelay(priv->delay);
versatile_sda_set(priv, 1);
versatile_scl_set(priv, 1);
versatile_sda_set(priv, 0);
}
/* stop: SDA goes from low to high while SCL is high */
static void versatile_i2c_stop(struct versatile_i2c_priv *priv)
{
versatile_scl_set(priv, 0);
versatile_sda_set(priv, 0);
versatile_scl_set(priv, 1);
versatile_sda_set(priv, 1);
}
/* read a bit from the SDA line (data or ACK/NACK) */
static u8 versatile_i2c_read_bit(struct versatile_i2c_priv *priv)
{
versatile_scl_set(priv, 0);
versatile_sda_set(priv, 1);
versatile_scl_set(priv, 1);
udelay(priv->delay);
return (u8)versatile_sda_get(priv);
}
/* write a bit on the SDA line */
static void versatile_i2c_write_bit(struct versatile_i2c_priv *priv, u8 bit)
{
versatile_scl_set(priv, 0);
versatile_sda_set(priv, bit);
versatile_scl_set(priv, 1);
udelay(priv->delay);
}
/* send a reset sequence of 9 clocks with SDA high */
static void versatile_i2c_reset_bus(struct versatile_i2c_priv *priv)
{
int i;
for (i = 0; i < 9; i++)
versatile_i2c_write_bit(priv, 1);
versatile_i2c_stop(priv);
}
/* write byte without start/stop sequence */
static int versatile_i2c_write_byte(struct versatile_i2c_priv *priv, u8 byte)
{
u8 nak, i;
for (i = 0; i < 8; i++) {
versatile_i2c_write_bit(priv, byte & 0x80);
byte <<= 1;
}
/* read ACK */
nak = versatile_i2c_read_bit(priv);
versatile_scl_set(priv, 0);
return nak; /* not a nack is an ack */
}
static int versatile_i2c_read_byte(struct versatile_i2c_priv *priv,
u8 *byte, u8 ack)
{
u8 i;
*byte = 0;
for (i = 0; i < 8; i++) {
*byte <<= 1;
*byte |= versatile_i2c_read_bit(priv);
}
/* write the nack */
versatile_i2c_write_bit(priv, ack);
return 0;
}
static int versatile_i2c_send_slave_addr(struct versatile_i2c_priv *priv,
struct i2c_msg *msg)
{
u8 addr;
int ret;
if (msg->flags & I2C_M_TEN) {
/* 10-bit address, send extended address code first */
addr = 0xf0 | ((msg->addr >> 7) & 0x06);
ret = versatile_i2c_write_byte(priv, addr);
if (ret) {
versatile_i2c_stop(priv);
return -EIO;
}
/* remaining bits */
ret = versatile_i2c_write_byte(priv, msg->addr & 0xff);
if (ret) {
versatile_i2c_stop(priv);
return -EIO;
}
/* reads need to resend the addr */
if (msg->flags & I2C_M_RD) {
versatile_i2c_start(priv);
addr |= 1;
ret = versatile_i2c_write_byte(priv, addr);
if (ret) {
versatile_i2c_stop(priv);
return -EIO;
}
}
} else {
/* normal 7-bit address */
addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
ret = versatile_i2c_write_byte(priv, addr);
if (ret) {
versatile_i2c_stop(priv);
return -EIO;
}
}
return 0;
}
static int versatile_i2c_message_xfer(struct versatile_i2c_priv *priv,
struct i2c_msg *msg)
{
int i, ret;
u8 ack;
versatile_i2c_start(priv);
if (versatile_i2c_send_slave_addr(priv, msg))
return -EIO;
for (i = 0; i < msg->len; i++) {
if (msg->flags & I2C_M_RD) {
ack = (msg->len - i - 1) == 0 ? 1 : 0;
ret = versatile_i2c_read_byte(priv, &msg->buf[i], ack);
} else {
ret = versatile_i2c_write_byte(priv, msg->buf[i]);
}
if (ret)
break;
}
versatile_i2c_stop(priv);
return ret;
}
static int versatile_i2c_xfer(struct udevice *bus,
struct i2c_msg *msg, int nmsgs)
{
struct versatile_i2c_priv *priv = dev_get_priv(bus);
int ret;
for ( ; nmsgs > 0; nmsgs--, msg++) {
ret = versatile_i2c_message_xfer(priv, msg);
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int versatile_i2c_chip_probe(struct udevice *bus,
uint chip, uint chip_flags)
{
/* probe the presence of a slave by writing a 0-size message */
struct i2c_msg msg = { .addr = chip, .flags = chip_flags,
.len = 0, .buf = NULL };
struct versatile_i2c_priv *priv = dev_get_priv(bus);
return versatile_i2c_message_xfer(priv, &msg);
}
static int versatile_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct versatile_i2c_priv *priv = dev_get_priv(bus);
priv->delay = 1000000 / (speed << 2);
versatile_i2c_reset_bus(priv);
return 0;
}
static int versatile_i2c_probe(struct udevice *dev)
{
struct versatile_i2c_priv *priv = dev_get_priv(dev);
priv->base = (phys_addr_t)dev_read_addr(dev);
priv->delay = 25; /* 25us * 4 = 100kHz */
/*
* U-Boot still doesn't assign automatically
* sequence numbers to devices
*/
dev->req_seq = 1;
return 0;
}
static const struct dm_i2c_ops versatile_i2c_ops = {
.xfer = versatile_i2c_xfer,
.probe_chip = versatile_i2c_chip_probe,
.set_bus_speed = versatile_i2c_set_bus_speed,
};
static const struct udevice_id versatile_i2c_of_match[] = {
{ .compatible = "arm,versatile-i2c" },
{ }
};
U_BOOT_DRIVER(versatile_i2c) = {
.name = "i2c-bus-versatile",
.id = UCLASS_I2C,
.of_match = versatile_i2c_of_match,
.probe = versatile_i2c_probe,
.priv_auto_alloc_size = sizeof(struct versatile_i2c_priv),
.ops = &versatile_i2c_ops,
};
@@ -0,0 +1,348 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
*
* (C) Copyright 2012
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
*
* Multibus/multiadapter I2C core functions (wrappers)
*/
#include <common.h>
#include <i2c.h>
struct i2c_adapter *i2c_get_adapter(int index)
{
struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
i2c);
int max = ll_entry_count(struct i2c_adapter, i2c);
int i;
if (index >= max) {
printf("Error, wrong i2c adapter %d max %d possible\n",
index, max);
return i2c_adap_p;
}
if (index == 0)
return i2c_adap_p;
for (i = 0; i < index; i++)
i2c_adap_p++;
return i2c_adap_p;
}
#if !defined(CONFIG_SYS_I2C_DIRECT_BUS)
struct i2c_bus_hose i2c_bus[CONFIG_SYS_NUM_I2C_BUSES] =
CONFIG_SYS_I2C_BUSES;
#endif
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
/*
* i2c_mux_set()
* -------------
*
* This turns on the given channel on I2C multiplexer chip connected to
* a given I2C adapter directly or via other multiplexers. In the latter
* case the entire multiplexer chain must be initialized first starting
* with the one connected directly to the adapter. When disabling a chain
* muxes must be programmed in reverse order, starting with the one
* farthest from the adapter.
*
* mux_id is the multiplexer chip type from defined in i2c.h. So far only
* NXP (Philips) PCA954x multiplexers are supported. Switches are NOT
* supported (anybody uses them?)
*/
static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
int channel)
{
uint8_t buf;
int ret;
/* channel < 0 - turn off the mux */
if (channel < 0) {
buf = 0;
ret = adap->write(adap, chip, 0, 0, &buf, 1);
if (ret)
printf("%s: Could not turn off the mux.\n", __func__);
return ret;
}
switch (mux_id) {
case I2C_MUX_PCA9540_ID:
case I2C_MUX_PCA9542_ID:
if (channel > 1)
return -1;
buf = (uint8_t)((channel & 0x01) | (1 << 2));
break;
case I2C_MUX_PCA9544_ID:
if (channel > 3)
return -1;
buf = (uint8_t)((channel & 0x03) | (1 << 2));
break;
case I2C_MUX_PCA9547_ID:
if (channel > 7)
return -1;
buf = (uint8_t)((channel & 0x07) | (1 << 3));
break;
case I2C_MUX_PCA9548_ID:
if (channel > 7)
return -1;
buf = (uint8_t)(0x01 << channel);
break;
default:
printf("%s: wrong mux id: %d\n", __func__, mux_id);
return -1;
}
ret = adap->write(adap, chip, 0, 0, &buf, 1);
if (ret)
printf("%s: could not set mux: id: %d chip: %x channel: %d\n",
__func__, mux_id, chip, channel);
return ret;
}
static int i2c_mux_set_all(void)
{
struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
int i;
/* Connect requested bus if behind muxes */
if (i2c_bus_tmp->next_hop[0].chip != 0) {
/* Set all muxes along the path to that bus */
for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) {
int ret;
if (i2c_bus_tmp->next_hop[i].chip == 0)
break;
ret = i2c_mux_set(I2C_ADAP,
i2c_bus_tmp->next_hop[i].mux.id,
i2c_bus_tmp->next_hop[i].chip,
i2c_bus_tmp->next_hop[i].channel);
if (ret != 0)
return ret;
}
}
return 0;
}
static int i2c_mux_disconnect_all(void)
{
struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
int i;
uint8_t buf = 0;
if (I2C_ADAP->init_done == 0)
return 0;
/* Disconnect current bus (turn off muxes if any) */
if ((i2c_bus_tmp->next_hop[0].chip != 0) &&
(I2C_ADAP->init_done != 0)) {
i = CONFIG_SYS_I2C_MAX_HOPS;
do {
uint8_t chip;
int ret;
chip = i2c_bus_tmp->next_hop[--i].chip;
if (chip == 0)
continue;
ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
if (ret != 0) {
printf("i2c: mux disconnect error\n");
return ret;
}
} while (i > 0);
}
return 0;
}
#endif
/*
* i2c_init_bus():
* ---------------
*
* Initializes one bus. Will initialize the parent adapter. No current bus
* changes, no mux (if any) setup.
*/
static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr)
{
if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES)
return;
I2C_ADAP->init(I2C_ADAP, speed, slaveaddr);
if (gd->flags & GD_FLG_RELOC) {
I2C_ADAP->init_done = 1;
I2C_ADAP->speed = speed;
I2C_ADAP->slaveaddr = slaveaddr;
}
}
/* implement possible board specific board init */
__weak void i2c_init_board(void)
{
}
/* implement possible for i2c specific early i2c init */
__weak void i2c_early_init_f(void)
{
}
/*
* i2c_init_all():
*
* not longer needed, will deleted. Actual init the SPD_BUS
* for compatibility.
* i2c_adap[] must be initialized beforehead with function pointers and
* data, including speed and slaveaddr.
*/
void i2c_init_all(void)
{
i2c_init_board();
i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
return;
}
/*
* i2c_get_bus_num():
* ------------------
*
* Returns index of currently active I2C bus. Zero-based.
*/
unsigned int i2c_get_bus_num(void)
{
return gd->cur_i2c_bus;
}
/*
* i2c_set_bus_num():
* ------------------
*
* Change the active I2C bus. Subsequent read/write calls will
* go to this one. Sets all of the muxes in a proper condition
* if that bus is behind muxes.
* If previously selected bus is behind the muxes turns off all the
* muxes along the path to that bus.
*
* bus - bus index, zero based
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_set_bus_num(unsigned int bus)
{
int max;
if ((bus == I2C_BUS) && (I2C_ADAP->init_done > 0))
return 0;
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
if (bus >= CONFIG_SYS_NUM_I2C_BUSES)
return -1;
#endif
max = ll_entry_count(struct i2c_adapter, i2c);
if (I2C_ADAPTER(bus) >= max) {
printf("Error, wrong i2c adapter %d max %d possible\n",
I2C_ADAPTER(bus), max);
return -2;
}
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
i2c_mux_disconnect_all();
#endif
gd->cur_i2c_bus = bus;
if (I2C_ADAP->init_done == 0)
i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr);
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
i2c_mux_set_all();
#endif
return 0;
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uint8_t chip)
{
return I2C_ADAP->probe(I2C_ADAP, chip);
}
/*
* Read/Write interface:
* chip: I2C chip address, range 0..127
* addr: Memory (register) address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Where to read/write the data
* len: How many bytes to read/write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read(uint8_t chip, unsigned int addr, int alen,
uint8_t *buffer, int len)
{
return I2C_ADAP->read(I2C_ADAP, chip, addr, alen, buffer, len);
}
int i2c_write(uint8_t chip, unsigned int addr, int alen,
uint8_t *buffer, int len)
{
return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len);
}
unsigned int i2c_set_bus_speed(unsigned int speed)
{
unsigned int ret;
if (I2C_ADAP->set_bus_speed == NULL)
return 0;
ret = I2C_ADAP->set_bus_speed(I2C_ADAP, speed);
if (gd->flags & GD_FLG_RELOC)
I2C_ADAP->speed = (ret == 0) ? speed : 0;
return ret;
}
unsigned int i2c_get_bus_speed(void)
{
struct i2c_adapter *cur = I2C_ADAP;
return cur->speed;
}
uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
{
uint8_t buf;
i2c_read(addr, reg, 1, &buf, 1);
#ifdef DEBUG
printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
__func__, i2c_get_bus_num(), addr, reg, buf);
#endif
return buf;
}
void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
{
#ifdef DEBUG
printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
__func__, i2c_get_bus_num(), addr, reg, val);
#endif
i2c_write(addr, reg, 1, &val, 1);
}
__weak void i2c_init(int speed, int slaveaddr)
{
i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr);
}
@@ -0,0 +1,473 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2013
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
*/
#include <common.h>
#include <i2c.h>
#ifdef CONFIG_DM_I2C
#include <dm.h>
#include <regmap.h>
#else
#include <gdsys_fpga.h>
#endif
#include <asm/unaligned.h>
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv {
uint speed;
struct regmap *map;
};
struct ihs_i2c_regs {
u16 interrupt_status;
u16 interrupt_enable_control;
u16 write_mailbox_ext;
u16 write_mailbox;
u16 read_mailbox_ext;
u16 read_mailbox;
};
#define ihs_i2c_set(map, member, val) \
regmap_set(map, struct ihs_i2c_regs, member, val)
#define ihs_i2c_get(map, member, valp) \
regmap_get(map, struct ihs_i2c_regs, member, valp)
#else /* !CONFIG_DM_I2C */
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SYS_I2C_IHS_DUAL
#define I2C_SET_REG(fld, val) \
do { \
if (I2C_ADAP_HWNR & 0x10) \
FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
else \
FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
} while (0)
#else
#define I2C_SET_REG(fld, val) \
FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
#endif
#ifdef CONFIG_SYS_I2C_IHS_DUAL
#define I2C_GET_REG(fld, val) \
do { \
if (I2C_ADAP_HWNR & 0x10) \
FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
else \
FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
} while (0)
#else
#define I2C_GET_REG(fld, val) \
FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
#endif
#endif /* CONFIG_DM_I2C */
enum {
I2CINT_ERROR_EV = BIT(13),
I2CINT_TRANSMIT_EV = BIT(14),
I2CINT_RECEIVE_EV = BIT(15),
};
enum {
I2CMB_READ = 0 << 10,
I2CMB_WRITE = 1 << 10,
I2CMB_1BYTE = 0 << 11,
I2CMB_2BYTE = 1 << 11,
I2CMB_DONT_HOLD_BUS = 0 << 13,
I2CMB_HOLD_BUS = 1 << 13,
I2CMB_NATIVE = 2 << 14,
};
enum {
I2COP_WRITE = 0,
I2COP_READ = 1,
};
#ifdef CONFIG_DM_I2C
static int wait_for_int(struct udevice *dev, int read)
#else
static int wait_for_int(bool read)
#endif
{
u16 val;
uint ctr = 0;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
#endif
#ifdef CONFIG_DM_I2C
ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
/* Wait until error or receive/transmit interrupt was raised */
while (!(val & (I2CINT_ERROR_EV
| (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
udelay(10);
if (ctr++ > 5000) {
debug("%s: timed out\n", __func__);
return -ETIMEDOUT;
}
#ifdef CONFIG_DM_I2C
ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
}
return (val & I2CINT_ERROR_EV) ? -EIO : 0;
}
#ifdef CONFIG_DM_I2C
static int ihs_i2c_transfer(struct udevice *dev, uchar chip,
uchar *buffer, int len, int read, bool is_last)
#else
static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
bool is_last)
#endif
{
u16 val;
u16 data;
int res;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
#endif
/* Clear interrupt status */
data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
#ifdef CONFIG_DM_I2C
ihs_i2c_set(priv->map, interrupt_status, data);
ihs_i2c_get(priv->map, interrupt_status, &val);
#else
I2C_SET_REG(interrupt_status, data);
I2C_GET_REG(interrupt_status, &val);
#endif
/* If we want to write and have data, write the bytes to the mailbox */
if (!read && len) {
val = buffer[0];
if (len > 1)
val |= buffer[1] << 8;
#ifdef CONFIG_DM_I2C
ihs_i2c_set(priv->map, write_mailbox_ext, val);
#else
I2C_SET_REG(write_mailbox_ext, val);
#endif
}
data = I2CMB_NATIVE
| (read ? 0 : I2CMB_WRITE)
| (chip << 1)
| ((len > 1) ? I2CMB_2BYTE : 0)
| (is_last ? 0 : I2CMB_HOLD_BUS);
#ifdef CONFIG_DM_I2C
ihs_i2c_set(priv->map, write_mailbox, data);
#else
I2C_SET_REG(write_mailbox, data);
#endif
#ifdef CONFIG_DM_I2C
res = wait_for_int(dev, read);
#else
res = wait_for_int(read);
#endif
if (res) {
if (res == -ETIMEDOUT)
debug("%s: time out while waiting for event\n", __func__);
return res;
}
/* If we want to read, get the bytes from the mailbox */
if (read) {
#ifdef CONFIG_DM_I2C
ihs_i2c_get(priv->map, read_mailbox_ext, &val);
#else
I2C_GET_REG(read_mailbox_ext, &val);
#endif
buffer[0] = val & 0xff;
if (len > 1)
buffer[1] = val >> 8;
}
return 0;
}
#ifdef CONFIG_DM_I2C
static int ihs_i2c_send_buffer(struct udevice *dev, uchar chip, u8 *data, int len, bool hold_bus, int read)
#else
static int ihs_i2c_send_buffer(uchar chip, u8 *data, int len, bool hold_bus,
int read)
#endif
{
int res;
while (len) {
int transfer = min(len, 2);
bool is_last = len <= transfer;
#ifdef CONFIG_DM_I2C
res = ihs_i2c_transfer(dev, chip, data, transfer, read,
hold_bus ? false : is_last);
#else
res = ihs_i2c_transfer(chip, data, transfer, read,
hold_bus ? false : is_last);
#endif
if (res)
return res;
data += transfer;
len -= transfer;
}
return 0;
}
#ifdef CONFIG_DM_I2C
static int ihs_i2c_address(struct udevice *dev, uchar chip, u8 *addr, int alen,
bool hold_bus)
#else
static int ihs_i2c_address(uchar chip, u8 *addr, int alen, bool hold_bus)
#endif
{
#ifdef CONFIG_DM_I2C
return ihs_i2c_send_buffer(dev, chip, addr, alen, hold_bus, I2COP_WRITE);
#else
return ihs_i2c_send_buffer(chip, addr, alen, hold_bus, I2COP_WRITE);
#endif
}
#ifdef CONFIG_DM_I2C
static int ihs_i2c_access(struct udevice *dev, uchar chip, u8 *addr,
int alen, uchar *buffer, int len, int read)
#else
static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, u8 *addr,
int alen, uchar *buffer, int len, int read)
#endif
{
int res;
/* Don't hold the bus if length of data to send/receive is zero */
if (len <= 0)
return -EINVAL;
#ifdef CONFIG_DM_I2C
res = ihs_i2c_address(dev, chip, addr, alen, len);
#else
res = ihs_i2c_address(chip, addr, alen, len);
#endif
if (res)
return res;
#ifdef CONFIG_DM_I2C
return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read);
#else
return ihs_i2c_send_buffer(chip, buffer, len, false, read);
#endif
}
#ifdef CONFIG_DM_I2C
int ihs_i2c_probe(struct udevice *bus)
{
struct ihs_i2c_priv *priv = dev_get_priv(bus);
regmap_init_mem(dev_ofnode(bus), &priv->map);
return 0;
}
static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed)
{
struct ihs_i2c_priv *priv = dev_get_priv(bus);
if (speed != priv->speed && priv->speed != 0)
return -EINVAL;
priv->speed = speed;
return 0;
}
static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actucal data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported\n", __func__);
return -ENOTSUPP;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len,
I2COP_READ);
else
return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len,
I2COP_WRITE);
}
static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
uchar buffer[2];
int res;
res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true);
if (res)
return res;
return 0;
}
static const struct dm_i2c_ops ihs_i2c_ops = {
.xfer = ihs_i2c_xfer,
.probe_chip = ihs_i2c_probe_chip,
.set_bus_speed = ihs_i2c_set_bus_speed,
};
static const struct udevice_id ihs_i2c_ids[] = {
{ .compatible = "gdsys,ihs_i2cmaster", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_ihs) = {
.name = "i2c_ihs",
.id = UCLASS_I2C,
.of_match = ihs_i2c_ids,
.probe = ihs_i2c_probe,
.priv_auto_alloc_size = sizeof(struct ihs_i2c_priv),
.ops = &ihs_i2c_ops,
};
#else /* CONFIG_DM_I2C */
static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
}
static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar buffer[2];
int res;
res = ihs_i2c_transfer(chip, buffer, 0, I2COP_READ, true);
if (res)
return res;
return 0;
}
static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
u8 addr_bytes[4];
put_unaligned_le32(addr, addr_bytes);
return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
I2COP_READ);
}
static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
u8 addr_bytes[4];
put_unaligned_le32(addr, addr_bytes);
return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
I2COP_WRITE);
}
static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
if (speed != adap->speed)
return -EINVAL;
return speed;
}
/*
* Register IHS i2c adapters
*/
#ifdef CONFIG_SYS_I2C_IHS_CH0
U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_0,
CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_0_1,
CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH1
U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_1,
CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_1_1,
CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH2
U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_2,
CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_2_1,
CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH3
U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_3,
CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_3_1,
CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
#endif
#endif
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,522 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2016 Freescale Semiconductors, Inc.
*/
#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <imx_lpi2c.h>
#include <asm/arch/sys_proto.h>
#include <dm.h>
#include <fdtdec.h>
#include <i2c.h>
#define LPI2C_FIFO_SIZE 4
#define LPI2C_NACK_TOUT_MS 1
#define LPI2C_TIMEOUT_MS 100
static int bus_i2c_init(struct udevice *bus, int speed);
/* Weak linked function for overridden by some SoC power function */
int __weak init_i2c_power(unsigned i2c_num)
{
return 0;
}
static int imx_lpci2c_check_busy_bus(const struct imx_lpi2c_reg *regs)
{
lpi2c_status_t result = LPI2C_SUCESS;
u32 status;
status = readl(&regs->msr);
if ((status & LPI2C_MSR_BBF_MASK) && !(status & LPI2C_MSR_MBF_MASK))
result = LPI2C_BUSY;
return result;
}
static int imx_lpci2c_check_clear_error(struct imx_lpi2c_reg *regs)
{
lpi2c_status_t result = LPI2C_SUCESS;
u32 val, status;
status = readl(&regs->msr);
/* errors to check for */
status &= LPI2C_MSR_NDF_MASK | LPI2C_MSR_ALF_MASK |
LPI2C_MSR_FEF_MASK | LPI2C_MSR_PLTF_MASK;
if (status) {
if (status & LPI2C_MSR_PLTF_MASK)
result = LPI2C_PIN_LOW_TIMEOUT_ERR;
else if (status & LPI2C_MSR_ALF_MASK)
result = LPI2C_ARB_LOST_ERR;
else if (status & LPI2C_MSR_NDF_MASK)
result = LPI2C_NAK_ERR;
else if (status & LPI2C_MSR_FEF_MASK)
result = LPI2C_FIFO_ERR;
/* clear status flags */
writel(0x7f00, &regs->msr);
/* reset fifos */
val = readl(&regs->mcr);
val |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
writel(val, &regs->mcr);
}
return result;
}
static int bus_i2c_wait_for_tx_ready(struct imx_lpi2c_reg *regs)
{
lpi2c_status_t result = LPI2C_SUCESS;
u32 txcount = 0;
ulong start_time = get_timer(0);
do {
txcount = LPI2C_MFSR_TXCOUNT(readl(&regs->mfsr));
txcount = LPI2C_FIFO_SIZE - txcount;
result = imx_lpci2c_check_clear_error(regs);
if (result) {
debug("i2c: wait for tx ready: result 0x%x\n", result);
return result;
}
if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
debug("i2c: wait for tx ready: timeout\n");
return -1;
}
} while (!txcount);
return result;
}
static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
{
struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
lpi2c_status_t result = LPI2C_SUCESS;
/* empty tx */
if (!len)
return result;
while (len--) {
result = bus_i2c_wait_for_tx_ready(regs);
if (result) {
debug("i2c: send wait for tx ready: %d\n", result);
return result;
}
writel(*txbuf++, &regs->mtdr);
}
return result;
}
static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
{
struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
lpi2c_status_t result = LPI2C_SUCESS;
u32 val;
ulong start_time = get_timer(0);
/* empty read */
if (!len)
return result;
result = bus_i2c_wait_for_tx_ready(regs);
if (result) {
debug("i2c: receive wait fot tx ready: %d\n", result);
return result;
}
/* clear all status flags */
writel(0x7f00, &regs->msr);
/* send receive command */
val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(len - 1);
writel(val, &regs->mtdr);
while (len--) {
do {
result = imx_lpci2c_check_clear_error(regs);
if (result) {
debug("i2c: receive check clear error: %d\n",
result);
return result;
}
if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
debug("i2c: receive mrdr: timeout\n");
return -1;
}
val = readl(&regs->mrdr);
} while (val & LPI2C_MRDR_RXEMPTY_MASK);
*rxbuf++ = LPI2C_MRDR_DATA(val);
}
return result;
}
static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
{
lpi2c_status_t result;
struct imx_lpi2c_reg *regs =
(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
u32 val;
result = imx_lpci2c_check_busy_bus(regs);
if (result) {
debug("i2c: start check busy bus: 0x%x\n", result);
/* Try to init the lpi2c then check the bus busy again */
bus_i2c_init(bus, 100000);
result = imx_lpci2c_check_busy_bus(regs);
if (result) {
printf("i2c: Error check busy bus: 0x%x\n", result);
return result;
}
}
/* clear all status flags */
writel(0x7f00, &regs->msr);
/* turn off auto-stop condition */
val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_AUTOSTOP_MASK;
writel(val, &regs->mcfgr1);
/* wait tx fifo ready */
result = bus_i2c_wait_for_tx_ready(regs);
if (result) {
debug("i2c: start wait for tx ready: 0x%x\n", result);
return result;
}
/* issue start command */
val = LPI2C_MTDR_CMD(0x4) | (addr << 0x1) | dir;
writel(val, &regs->mtdr);
return result;
}
static int bus_i2c_stop(struct udevice *bus)
{
lpi2c_status_t result;
struct imx_lpi2c_reg *regs =
(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
u32 status;
ulong start_time;
result = bus_i2c_wait_for_tx_ready(regs);
if (result) {
debug("i2c: stop wait for tx ready: 0x%x\n", result);
return result;
}
/* send stop command */
writel(LPI2C_MTDR_CMD(0x2), &regs->mtdr);
start_time = get_timer(0);
while (1) {
status = readl(&regs->msr);
result = imx_lpci2c_check_clear_error(regs);
/* stop detect flag */
if (status & LPI2C_MSR_SDF_MASK) {
/* clear stop flag */
status &= LPI2C_MSR_SDF_MASK;
writel(status, &regs->msr);
break;
}
if (get_timer(start_time) > LPI2C_NACK_TOUT_MS) {
debug("stop timeout\n");
return -ETIMEDOUT;
}
}
return result;
}
static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len)
{
lpi2c_status_t result;
result = bus_i2c_start(bus, chip, 1);
if (result)
return result;
result = bus_i2c_receive(bus, buf, len);
if (result)
return result;
return result;
}
static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)
{
lpi2c_status_t result;
result = bus_i2c_start(bus, chip, 0);
if (result)
return result;
result = bus_i2c_send(bus, buf, len);
if (result)
return result;
return result;
}
u32 __weak imx_get_i2cclk(u32 i2c_num)
{
return 0;
}
static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
{
struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
struct imx_lpi2c_reg *regs;
u32 val;
u32 preescale = 0, best_pre = 0, clkhi = 0;
u32 best_clkhi = 0, abs_error = 0, rate;
u32 error = 0xffffffff;
u32 clock_rate;
bool mode;
int i;
regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
if (IS_ENABLED(CONFIG_CLK)) {
clock_rate = clk_get_rate(&i2c_bus->per_clk);
if (clock_rate <= 0) {
dev_err(bus, "Failed to get i2c clk: %d\n", clock_rate);
return clock_rate;
}
} else {
clock_rate = imx_get_i2cclk(bus->seq);
if (!clock_rate)
return -EPERM;
}
mode = (readl(&regs->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;
/* disable master mode */
val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
writel(val | LPI2C_MCR_MEN(0), &regs->mcr);
for (preescale = 1; (preescale <= 128) &&
(error != 0); preescale = 2 * preescale) {
for (clkhi = 1; clkhi < 32; clkhi++) {
if (clkhi == 1)
rate = (clock_rate / preescale) / (1 + 3 + 2 + 2 / preescale);
else
rate = (clock_rate / preescale / (3 * clkhi + 2 + 2 / preescale));
abs_error = speed > rate ? speed - rate : rate - speed;
if (abs_error < error) {
best_pre = preescale;
best_clkhi = clkhi;
error = abs_error;
if (abs_error == 0)
break;
}
}
}
/* Standard, fast, fast mode plus and ultra-fast transfers. */
val = LPI2C_MCCR0_CLKHI(best_clkhi);
if (best_clkhi < 2)
val |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1);
else
val |= LPI2C_MCCR0_CLKLO(2 * best_clkhi) | LPI2C_MCCR0_SETHOLD(best_clkhi) |
LPI2C_MCCR0_DATAVD(best_clkhi / 2);
writel(val, &regs->mccr0);
for (i = 0; i < 8; i++) {
if (best_pre == (1 << i)) {
best_pre = i;
break;
}
}
val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_PRESCALE_MASK;
writel(val | LPI2C_MCFGR1_PRESCALE(best_pre), &regs->mcfgr1);
if (mode) {
val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
}
return 0;
}
static int bus_i2c_init(struct udevice *bus, int speed)
{
struct imx_lpi2c_reg *regs;
u32 val;
int ret;
regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
/* reset peripheral */
writel(LPI2C_MCR_RST_MASK, &regs->mcr);
writel(0x0, &regs->mcr);
/* Disable Dozen mode */
writel(LPI2C_MCR_DBGEN(0) | LPI2C_MCR_DOZEN(1), &regs->mcr);
/* host request disable, active high, external pin */
val = readl(&regs->mcfgr0);
val &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK |
LPI2C_MCFGR0_HRSEL_MASK));
val |= LPI2C_MCFGR0_HRPOL(0x1);
writel(val, &regs->mcfgr0);
/* pincfg and ignore ack */
val = readl(&regs->mcfgr1);
val &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
val |= LPI2C_MCFGR1_PINCFG(0x0); /* 2 pin open drain */
val |= LPI2C_MCFGR1_IGNACK(0x0); /* ignore nack */
writel(val, &regs->mcfgr1);
ret = bus_i2c_set_bus_speed(bus, speed);
/* enable lpi2c in master mode */
val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
debug("i2c : controller bus %d, speed %d:\n", bus->seq, speed);
return ret;
}
static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
u32 chip_flags)
{
lpi2c_status_t result;
result = bus_i2c_start(bus, chip, 0);
if (result) {
bus_i2c_stop(bus);
bus_i2c_init(bus, 100000);
return result;
}
result = bus_i2c_stop(bus);
if (result)
bus_i2c_init(bus, 100000);
return result;
}
static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
int ret = 0, ret_stop;
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD)
ret = bus_i2c_read(bus, msg->addr, msg->buf, msg->len);
else {
ret = bus_i2c_write(bus, msg->addr, msg->buf,
msg->len);
if (ret)
break;
}
}
if (ret)
debug("i2c_write: error sending\n");
ret_stop = bus_i2c_stop(bus);
if (ret_stop)
debug("i2c_xfer: stop bus error\n");
ret |= ret_stop;
return ret;
}
static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
return bus_i2c_set_bus_speed(bus, speed);
}
__weak int enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
{
return 0;
}
static int imx_lpi2c_probe(struct udevice *bus)
{
struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
fdt_addr_t addr;
int ret;
i2c_bus->driver_data = dev_get_driver_data(bus);
addr = devfdt_get_addr(bus);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
i2c_bus->base = addr;
i2c_bus->index = bus->seq;
i2c_bus->bus = bus;
/* power up i2c resource */
ret = init_i2c_power(bus->seq);
if (ret) {
debug("init_i2c_power err = %d\n", ret);
return ret;
}
if (IS_ENABLED(CONFIG_CLK)) {
ret = clk_get_by_name(bus, "per", &i2c_bus->per_clk);
if (ret) {
dev_err(bus, "Failed to get per clk\n");
return ret;
}
ret = clk_enable(&i2c_bus->per_clk);
if (ret) {
dev_err(bus, "Failed to enable per clk\n");
return ret;
}
ret = clk_get_by_name(bus, "ipg", &i2c_bus->ipg_clk);
if (ret) {
dev_err(bus, "Failed to get ipg clk\n");
return ret;
}
ret = clk_enable(&i2c_bus->ipg_clk);
if (ret) {
dev_err(bus, "Failed to enable ipg clk\n");
return ret;
}
} else {
/* To i.MX7ULP, only i2c4-7 can be handled by A7 core */
ret = enable_i2c_clk(1, bus->seq);
if (ret < 0)
return ret;
}
ret = bus_i2c_init(bus, 100000);
if (ret < 0)
return ret;
debug("i2c : controller bus %d at 0x%lx , speed %d: ",
bus->seq, i2c_bus->base,
i2c_bus->speed);
return 0;
}
static const struct dm_i2c_ops imx_lpi2c_ops = {
.xfer = imx_lpi2c_xfer,
.probe_chip = imx_lpi2c_probe_chip,
.set_bus_speed = imx_lpi2c_set_bus_speed,
};
static const struct udevice_id imx_lpi2c_ids[] = {
{ .compatible = "fsl,imx7ulp-lpi2c", },
{ .compatible = "fsl,imx8qm-lpi2c", },
{}
};
U_BOOT_DRIVER(imx_lpi2c) = {
.name = "imx_lpi2c",
.id = UCLASS_I2C,
.of_match = imx_lpi2c_ids,
.probe = imx_lpi2c_probe,
.priv_auto_alloc_size = sizeof(struct imx_lpi2c_bus),
.ops = &imx_lpi2c_ops,
};
@@ -0,0 +1,321 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SMBus block read/write support added by Stefan Roese:
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <pci.h>
#include <asm/io.h>
/* PCI Configuration Space (D31:F3): SMBus */
#define SMB_BASE 0x20
#define HOSTC 0x40
#define HST_EN (1 << 0)
#define SMB_RCV_SLVA 0x09
/* SMBus I/O bits. */
#define SMBHSTSTAT 0x0
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define SMBHSTDAT1 0x6
#define SMBBLKDAT 0x7
#define SMBTRNSADD 0x9
#define SMBSLVDATA 0xa
#define SMBAUXCTL 0xd
#define SMLINK_PIN_CTL 0xe
#define SMBUS_PIN_CTL 0xf
/* I801 Hosts Status register bits */
#define SMBHSTSTS_BYTE_DONE 0x80
#define SMBHSTSTS_INUSE_STS 0x40
#define SMBHSTSTS_SMBALERT_STS 0x20
#define SMBHSTSTS_FAILED 0x10
#define SMBHSTSTS_BUS_ERR 0x08
#define SMBHSTSTS_DEV_ERR 0x04
#define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01
/* I801 Host Control register bits */
#define SMBHSTCNT_INTREN 0x01
#define SMBHSTCNT_KILL 0x02
#define SMBHSTCNT_LAST_BYTE 0x20
#define SMBHSTCNT_START 0x40
#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
/* Auxiliary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2
#define SMBUS_TIMEOUT 100 /* 100 ms */
struct intel_i2c {
u32 base;
int running;
};
static int smbus_wait_until_ready(u32 base)
{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!(byte & 1))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
}
static int smbus_wait_until_done(u32 base)
{
unsigned long ts;
u8 byte;
ts = get_timer(0);
do {
byte = inb(base + SMBHSTSTAT);
if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0))
return 0;
} while (get_timer(ts) < SMBUS_TIMEOUT);
return -ETIMEDOUT;
}
static int smbus_block_read(u32 base, u8 dev, u8 *buffer,
int offset, int len)
{
u8 buf_temp[32];
int count;
int i;
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Reset the data buffer index */
inb(base + SMBHSTCTL);
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) | 1, base + SMBXMITADD);
/* Set the command/address... */
outb(offset & 0xff, base + SMBHSTCMD);
/* Set up for a block read */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS read transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
count = inb(base + SMBHSTDAT0);
debug("%s (%d): count=%d (len=%d)\n", __func__, __LINE__, count, len);
if (count == 0) {
debug("ERROR: len=0 on read\n");
return -EIO;
}
if (count < len) {
debug("ERROR: too few bytes read\n");
return -EIO;
}
if (count > 32) {
debug("ERROR: count=%d too high\n", count);
return -EIO;
}
/* Read all available bytes from buffer */
for (i = 0; i < count; i++)
buf_temp[i] = inb(base + SMBBLKDAT);
memcpy(buffer, buf_temp, len);
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
}
static int smbus_block_write(u32 base, u8 dev, u8 *buffer,
int offset, int len)
{
int i;
debug("%s (%d): dev=0x%x offs=0x%x len=0x%x\n",
__func__, __LINE__, dev, offset, len);
if (smbus_wait_until_ready(base) < 0)
return -ETIMEDOUT;
/* Setup transaction */
/* Set the device I'm talking too */
outb(((dev & 0x7f) << 1) & ~0x01, base + SMBXMITADD);
/* Set the command/address... */
outb(offset, base + SMBHSTCMD);
/* Set up for a block write */
outb((inb(base + SMBHSTCTL) & (~(0x7) << 2)) | (0x5 << 2),
(base + SMBHSTCTL));
/* Clear any lingering errors, so the transaction will run */
outb(inb(base + SMBHSTSTAT), base + SMBHSTSTAT);
/* Write count in DAT0 register */
outb(len, base + SMBHSTDAT0);
/* Write data bytes... */
for (i = 0; i < len; i++)
outb(*buffer++, base + SMBBLKDAT);
/* Start the command */
outb((inb(base + SMBHSTCTL) | SMBHSTCNT_START), base + SMBHSTCTL);
/* Poll for transaction completion */
if (smbus_wait_until_done(base) < 0) {
printf("SMBUS write transaction timeout (dev=0x%x)\n", dev);
return -ETIMEDOUT;
}
/* Return results of transaction */
if (!(inb(base + SMBHSTSTAT) & SMBHSTSTS_INTR))
return -EIO;
return 0;
}
static int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct intel_i2c *i2c = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
debug("i2c_xfer: %d messages\n", nmsgs);
memset(&dummy, 0, sizeof(struct i2c_msg));
/*
* We expect either two messages (one with an offset and one with the
* actucal data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported", __func__);
return -EIO;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return smbus_block_read(i2c->base, dmsg->addr, &dmsg->buf[0],
omsg->buf[0], dmsg->len);
else
return smbus_block_write(i2c->base, dmsg->addr, &dmsg->buf[1],
dmsg->buf[0], dmsg->len - 1);
}
static int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct intel_i2c *i2c = dev_get_priv(bus);
u8 buf[4];
return smbus_block_read(i2c->base, chip_addr, buf, 0, 1);
}
static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
return 0;
}
static int intel_i2c_probe(struct udevice *dev)
{
struct intel_i2c *priv = dev_get_priv(dev);
ulong base;
/* Save base address from PCI BAR */
priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
PCI_REGION_IO);
base = priv->base;
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Disable interrupts */
outb(inb(base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, base + SMBHSTCTL);
/* Set 32-byte data buffer mode */
outb(inb(base + SMBAUXCTL) | SMBAUXCTL_E32B, base + SMBAUXCTL);
return 0;
}
static int intel_i2c_bind(struct udevice *dev)
{
static int num_cards __attribute__ ((section(".data")));
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "intel_i2c#%u", num_cards++);
device_set_name(dev, name);
}
return 0;
}
static const struct dm_i2c_ops intel_i2c_ops = {
.xfer = intel_i2c_xfer,
.probe_chip = intel_i2c_probe_chip,
.set_bus_speed = intel_i2c_set_bus_speed,
};
static const struct udevice_id intel_i2c_ids[] = {
{ .compatible = "intel,ich-i2c" },
{ }
};
U_BOOT_DRIVER(intel_i2c) = {
.name = "i2c_intel",
.id = UCLASS_I2C,
.of_match = intel_i2c_ids,
.ops = &intel_i2c_ops,
.priv_auto_alloc_size = sizeof(struct intel_i2c),
.bind = intel_i2c_bind,
.probe = intel_i2c_probe,
};
static struct pci_device_id intel_smbus_pci_supported[] = {
/* Intel BayTrail SMBus on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f12) },
/* Intel IvyBridge (Panther Point PCH) SMBus on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x1e22) },
{},
};
U_BOOT_PCI_DEVICE(intel_i2c, intel_smbus_pci_supported);
@@ -0,0 +1,732 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2013 Broadcom Corporation.
*
* NOTE: This driver should be converted to driver model before June 2017.
* Please see doc/driver-model/i2c-howto.txt for instructions.
*/
#include <common.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/sysmap.h>
#include <asm/kona-common/clk.h>
#include <i2c.h>
/* Hardware register offsets and field defintions */
#define CS_OFFSET 0x00000020
#define CS_ACK_SHIFT 3
#define CS_ACK_MASK 0x00000008
#define CS_ACK_CMD_GEN_START 0x00000000
#define CS_ACK_CMD_GEN_RESTART 0x00000001
#define CS_CMD_SHIFT 1
#define CS_CMD_CMD_NO_ACTION 0x00000000
#define CS_CMD_CMD_START_RESTART 0x00000001
#define CS_CMD_CMD_STOP 0x00000002
#define CS_EN_SHIFT 0
#define CS_EN_CMD_ENABLE_BSC 0x00000001
#define TIM_OFFSET 0x00000024
#define TIM_PRESCALE_SHIFT 6
#define TIM_P_SHIFT 3
#define TIM_NO_DIV_SHIFT 2
#define TIM_DIV_SHIFT 0
#define DAT_OFFSET 0x00000028
#define TOUT_OFFSET 0x0000002c
#define TXFCR_OFFSET 0x0000003c
#define TXFCR_FIFO_FLUSH_MASK 0x00000080
#define TXFCR_FIFO_EN_MASK 0x00000040
#define IER_OFFSET 0x00000044
#define IER_READ_COMPLETE_INT_MASK 0x00000010
#define IER_I2C_INT_EN_MASK 0x00000008
#define IER_FIFO_INT_EN_MASK 0x00000002
#define IER_NOACK_EN_MASK 0x00000001
#define ISR_OFFSET 0x00000048
#define ISR_RESERVED_MASK 0xffffff60
#define ISR_CMDBUSY_MASK 0x00000080
#define ISR_READ_COMPLETE_MASK 0x00000010
#define ISR_SES_DONE_MASK 0x00000008
#define ISR_ERR_MASK 0x00000004
#define ISR_TXFIFOEMPTY_MASK 0x00000002
#define ISR_NOACK_MASK 0x00000001
#define CLKEN_OFFSET 0x0000004c
#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080
#define CLKEN_M_SHIFT 4
#define CLKEN_N_SHIFT 1
#define CLKEN_CLKEN_MASK 0x00000001
#define FIFO_STATUS_OFFSET 0x00000054
#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004
#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010
#define HSTIM_OFFSET 0x00000058
#define HSTIM_HS_MODE_MASK 0x00008000
#define HSTIM_HS_HOLD_SHIFT 10
#define HSTIM_HS_HIGH_PHASE_SHIFT 5
#define HSTIM_HS_SETUP_SHIFT 0
#define PADCTL_OFFSET 0x0000005c
#define PADCTL_PAD_OUT_EN_MASK 0x00000004
#define RXFCR_OFFSET 0x00000068
#define RXFCR_NACK_EN_SHIFT 7
#define RXFCR_READ_COUNT_SHIFT 0
#define RXFIFORDOUT_OFFSET 0x0000006c
/* Locally used constants */
#define MAX_RX_FIFO_SIZE 64U /* bytes */
#define MAX_TX_FIFO_SIZE 64U /* bytes */
#define I2C_TIMEOUT 100000 /* usecs */
#define WAIT_INT_CHK 100 /* usecs */
#if I2C_TIMEOUT % WAIT_INT_CHK
#error I2C_TIMEOUT must be a multiple of WAIT_INT_CHK
#endif
/* Operations that can be commanded to the controller */
enum bcm_kona_cmd_t {
BCM_CMD_NOACTION = 0,
BCM_CMD_START,
BCM_CMD_RESTART,
BCM_CMD_STOP,
};
enum bus_speed_index {
BCM_SPD_100K = 0,
BCM_SPD_400K,
BCM_SPD_1MHZ,
};
/* Internal divider settings for standard mode, fast mode and fast mode plus */
struct bus_speed_cfg {
uint8_t time_m; /* Number of cycles for setup time */
uint8_t time_n; /* Number of cycles for hold time */
uint8_t prescale; /* Prescale divider */
uint8_t time_p; /* Timing coefficient */
uint8_t no_div; /* Disable clock divider */
uint8_t time_div; /* Post-prescale divider */
};
static const struct bus_speed_cfg std_cfg_table[] = {
[BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
[BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
[BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
};
struct bcm_kona_i2c_dev {
void *base;
uint speed;
const struct bus_speed_cfg *std_cfg;
};
/* Keep these two defines in sync */
#define DEF_SPD 100000
#define DEF_SPD_ENUM BCM_SPD_100K
#define DEF_DEVICE(num) \
{(void *)CONFIG_SYS_I2C_BASE##num, DEF_SPD, &std_cfg_table[DEF_SPD_ENUM]}
static struct bcm_kona_i2c_dev g_i2c_devs[CONFIG_SYS_MAX_I2C_BUS] = {
#ifdef CONFIG_SYS_I2C_BASE0
DEF_DEVICE(0),
#endif
#ifdef CONFIG_SYS_I2C_BASE1
DEF_DEVICE(1),
#endif
#ifdef CONFIG_SYS_I2C_BASE2
DEF_DEVICE(2),
#endif
#ifdef CONFIG_SYS_I2C_BASE3
DEF_DEVICE(3),
#endif
#ifdef CONFIG_SYS_I2C_BASE4
DEF_DEVICE(4),
#endif
#ifdef CONFIG_SYS_I2C_BASE5
DEF_DEVICE(5),
#endif
};
#define I2C_M_TEN 0x0010 /* ten bit address */
#define I2C_M_RD 0x0001 /* read data */
#define I2C_M_NOSTART 0x4000 /* no restart between msgs */
struct kona_i2c_msg {
uint16_t addr;
uint16_t flags;
uint16_t len;
uint8_t *buf;
};
static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev,
enum bcm_kona_cmd_t cmd)
{
debug("%s, %d\n", __func__, cmd);
switch (cmd) {
case BCM_CMD_NOACTION:
writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_START:
writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) |
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_RESTART:
writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) |
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_STOP:
writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
default:
printf("Unknown command %d\n", cmd);
}
}
static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK,
dev->base + CLKEN_OFFSET);
}
static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK,
dev->base + CLKEN_OFFSET);
}
/* Wait until at least one of the mask bit(s) are set */
static unsigned long wait_for_int_timeout(struct bcm_kona_i2c_dev *dev,
unsigned long time_left,
uint32_t mask)
{
uint32_t status;
while (time_left) {
status = readl(dev->base + ISR_OFFSET);
if ((status & ~ISR_RESERVED_MASK) == 0) {
debug("Bogus I2C interrupt 0x%x\n", status);
continue;
}
/* Must flush the TX FIFO when NAK detected */
if (status & ISR_NOACK_MASK)
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
dev->base + TXFCR_OFFSET);
writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET);
if (status & mask) {
/* We are done since one of the mask bits are set */
return time_left;
}
udelay(WAIT_INT_CHK);
time_left -= WAIT_INT_CHK;
}
return 0;
}
/* Send command to I2C bus */
static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev,
enum bcm_kona_cmd_t cmd)
{
int rc = 0;
unsigned long time_left = I2C_TIMEOUT;
/* Send the command */
bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd);
/* Wait for transaction to finish or timeout */
time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
if (!time_left) {
printf("controller timed out\n");
rc = -ETIMEDOUT;
}
/* Clear command */
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
return rc;
}
/* Read a single RX FIFO worth of data from the i2c bus */
static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev,
uint8_t *buf, unsigned int len,
unsigned int last_byte_nak)
{
unsigned long time_left = I2C_TIMEOUT;
/* Start the RX FIFO */
writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) |
(len << RXFCR_READ_COUNT_SHIFT), dev->base + RXFCR_OFFSET);
/* Wait for FIFO read to complete */
time_left =
wait_for_int_timeout(dev, time_left, IER_READ_COMPLETE_INT_MASK);
if (!time_left) {
printf("RX FIFO time out\n");
return -EREMOTEIO;
}
/* Read data from FIFO */
for (; len > 0; len--, buf++)
*buf = readl(dev->base + RXFIFORDOUT_OFFSET);
return 0;
}
/* Read any amount of data using the RX FIFO from the i2c bus */
static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned int bytes_to_read = MAX_RX_FIFO_SIZE;
unsigned int last_byte_nak = 0;
unsigned int bytes_read = 0;
int rc;
uint8_t *tmp_buf = msg->buf;
while (bytes_read < msg->len) {
if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) {
last_byte_nak = 1; /* NAK last byte of transfer */
bytes_to_read = msg->len - bytes_read;
}
rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read,
last_byte_nak);
if (rc < 0)
return -EREMOTEIO;
bytes_read += bytes_to_read;
tmp_buf += bytes_to_read;
}
return 0;
}
/* Write a single byte of data to the i2c bus */
static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data,
unsigned int nak_expected)
{
unsigned long time_left = I2C_TIMEOUT;
unsigned int nak_received;
/* Clear pending session done interrupt */
writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET);
/* Send one byte of data */
writel(data, dev->base + DAT_OFFSET);
time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
if (!time_left) {
debug("controller timed out\n");
return -ETIMEDOUT;
}
nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0;
if (nak_received ^ nak_expected) {
debug("unexpected NAK/ACK\n");
return -EREMOTEIO;
}
return 0;
}
/* Write a single TX FIFO worth of data to the i2c bus */
static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
uint8_t *buf, unsigned int len)
{
int k;
unsigned long time_left = I2C_TIMEOUT;
unsigned int fifo_status;
/* Write data into FIFO */
for (k = 0; k < len; k++)
writel(buf[k], (dev->base + DAT_OFFSET));
/* Wait for FIFO to empty */
do {
time_left =
wait_for_int_timeout(dev, time_left,
(IER_FIFO_INT_EN_MASK |
IER_NOACK_EN_MASK));
fifo_status = readl(dev->base + FIFO_STATUS_OFFSET);
} while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK));
/* Check if there was a NAK */
if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) {
printf("unexpected NAK\n");
return -EREMOTEIO;
}
/* Check if a timeout occurred */
if (!time_left) {
printf("completion timed out\n");
return -EREMOTEIO;
}
return 0;
}
/* Write any amount of data using TX FIFO to the i2c bus */
static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned int bytes_to_write = MAX_TX_FIFO_SIZE;
unsigned int bytes_written = 0;
int rc;
uint8_t *tmp_buf = msg->buf;
while (bytes_written < msg->len) {
if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE)
bytes_to_write = msg->len - bytes_written;
rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf,
bytes_to_write);
if (rc < 0)
return -EREMOTEIO;
bytes_written += bytes_to_write;
tmp_buf += bytes_to_write;
}
return 0;
}
/* Send i2c address */
static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned char addr;
if (msg->flags & I2C_M_TEN) {
/* First byte is 11110XX0 where XX is upper 2 bits */
addr = 0xf0 | ((msg->addr & 0x300) >> 7);
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
/* Second byte is the remaining 8 bits */
addr = msg->addr & 0xff;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
if (msg->flags & I2C_M_RD) {
/* For read, send restart command */
if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0)
return -EREMOTEIO;
/* Then re-send the first byte with the read bit set */
addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
}
} else {
addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
}
return 0;
}
static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK,
dev->base + CLKEN_OFFSET);
}
static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK,
dev->base + HSTIM_OFFSET);
writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) |
(dev->std_cfg->time_p << TIM_P_SHIFT) |
(dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) |
(dev->std_cfg->time_div << TIM_DIV_SHIFT),
dev->base + TIM_OFFSET);
writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) |
(dev->std_cfg->time_n << CLKEN_N_SHIFT) |
CLKEN_CLKEN_MASK, dev->base + CLKEN_OFFSET);
}
/* Master transfer function */
static int bcm_kona_i2c_xfer(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg msgs[], int num)
{
struct kona_i2c_msg *pmsg;
int rc = 0;
int i;
/* Enable pad output */
writel(0, dev->base + PADCTL_OFFSET);
/* Enable internal clocks */
bcm_kona_i2c_enable_clock(dev);
/* Send start command */
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START);
if (rc < 0) {
printf("Start command failed rc = %d\n", rc);
goto xfer_disable_pad;
}
/* Loop through all messages */
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
/* Send restart for subsequent messages */
if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) {
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
if (rc < 0) {
printf("restart cmd failed rc = %d\n", rc);
goto xfer_send_stop;
}
}
/* Send slave address */
if (!(pmsg->flags & I2C_M_NOSTART)) {
rc = bcm_kona_i2c_do_addr(dev, pmsg);
if (rc < 0) {
debug("NAK from addr %2.2x msg#%d rc = %d\n",
pmsg->addr, i, rc);
goto xfer_send_stop;
}
}
/* Perform data transfer */
if (pmsg->flags & I2C_M_RD) {
rc = bcm_kona_i2c_read_fifo(dev, pmsg);
if (rc < 0) {
printf("read failure\n");
goto xfer_send_stop;
}
} else {
rc = bcm_kona_i2c_write_fifo(dev, pmsg);
if (rc < 0) {
printf("write failure");
goto xfer_send_stop;
}
}
}
rc = num;
xfer_send_stop:
/* Send a STOP command */
bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
xfer_disable_pad:
/* Disable pad output */
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
/* Stop internal clock */
bcm_kona_i2c_disable_clock(dev);
return rc;
}
static uint bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev,
uint speed)
{
switch (speed) {
case 100000:
dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
break;
case 400000:
dev->std_cfg = &std_cfg_table[BCM_SPD_400K];
break;
case 1000000:
dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ];
break;
default:
printf("%d hz bus speed not supported\n", speed);
return -EINVAL;
}
dev->speed = speed;
return 0;
}
static void bcm_kona_i2c_init(struct bcm_kona_i2c_dev *dev)
{
/* Parse bus speed */
bcm_kona_i2c_assign_bus_speed(dev, dev->speed);
/* Enable internal clocks */
bcm_kona_i2c_enable_clock(dev);
/* Configure internal dividers */
bcm_kona_i2c_config_timing(dev);
/* Disable timeout */
writel(0, dev->base + TOUT_OFFSET);
/* Enable autosense */
bcm_kona_i2c_enable_autosense(dev);
/* Enable TX FIFO */
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
dev->base + TXFCR_OFFSET);
/* Mask all interrupts */
writel(0, dev->base + IER_OFFSET);
/* Clear all pending interrupts */
writel(ISR_CMDBUSY_MASK |
ISR_READ_COMPLETE_MASK |
ISR_SES_DONE_MASK |
ISR_ERR_MASK |
ISR_TXFIFOEMPTY_MASK | ISR_NOACK_MASK, dev->base + ISR_OFFSET);
/* Enable the controller but leave it idle */
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
/* Disable pad output */
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
}
/*
* uboot layer
*/
struct bcm_kona_i2c_dev *kona_get_dev(struct i2c_adapter *adap)
{
return &g_i2c_devs[adap->hwadapnr];
}
static void kona_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
if (clk_bsc_enable(dev->base))
return;
bcm_kona_i2c_init(dev);
}
static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
/* msg[0] writes the addr, msg[1] reads the data */
struct kona_i2c_msg msg[2];
unsigned char msgbuf0[64];
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
msg[0].addr = chip;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = msgbuf0; /* msgbuf0 contains incrementing reg addr */
msg[1].addr = chip;
msg[1].flags = I2C_M_RD;
/* msg[1].buf dest ptr increments each read */
msgbuf0[0] = (unsigned char)addr;
msg[1].buf = buffer;
msg[1].len = len;
if (bcm_kona_i2c_xfer(dev, msg, 2) < 0) {
/* Sending 2 i2c messages */
kona_i2c_init(adap, adap->speed, adap->slaveaddr);
debug("I2C read: I/O error\n");
return -EIO;
}
return 0;
}
static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
struct kona_i2c_msg msg[1];
unsigned char msgbuf0[64];
unsigned int i;
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
msg[0].addr = chip;
msg[0].flags = 0;
msg[0].len = 2; /* addr byte plus data */
msg[0].buf = msgbuf0;
for (i = 0; i < len; i++) {
msgbuf0[0] = addr++;
msgbuf0[1] = buffer[i];
if (bcm_kona_i2c_xfer(dev, msg, 1) < 0) {
kona_i2c_init(adap, adap->speed, adap->slaveaddr);
debug("I2C write: I/O error\n");
return -EIO;
}
}
return 0;
}
static int kona_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar tmp;
/*
* read addr 0x0 of the given chip.
*/
return kona_i2c_read(adap, chip, 0x0, 1, &tmp, 1);
}
static uint kona_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
return bcm_kona_i2c_assign_bus_speed(dev, speed);
}
/*
* Register kona i2c adapters. Keep the order below so
* that the bus number matches the adapter number.
*/
#define DEF_ADAPTER(num) \
U_BOOT_I2C_ADAP_COMPLETE(kona##num, kona_i2c_init, kona_i2c_probe, \
kona_i2c_read, kona_i2c_write, \
kona_i2c_set_bus_speed, DEF_SPD, 0x00, num)
#ifdef CONFIG_SYS_I2C_BASE0
DEF_ADAPTER(0)
#endif
#ifdef CONFIG_SYS_I2C_BASE1
DEF_ADAPTER(1)
#endif
#ifdef CONFIG_SYS_I2C_BASE2
DEF_ADAPTER(2)
#endif
#ifdef CONFIG_SYS_I2C_BASE3
DEF_ADAPTER(3)
#endif
#ifdef CONFIG_SYS_I2C_BASE4
DEF_ADAPTER(4)
#endif
#ifdef CONFIG_SYS_I2C_BASE5
DEF_ADAPTER(5)
#endif
@@ -0,0 +1,357 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* LPC32xx I2C interface driver
*
* (C) Copyright 2014-2015 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
*/
#include <common.h>
#include <asm/io.h>
#include <i2c.h>
#include <linux/errno.h>
#include <asm/arch/clk.h>
#include <asm/arch/i2c.h>
#include <dm.h>
#include <mapmem.h>
/*
* Provide default speed and slave if target did not
*/
#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
#endif
#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
#endif
/* TX register fields */
#define LPC32XX_I2C_TX_START 0x00000100
#define LPC32XX_I2C_TX_STOP 0x00000200
/* Control register values */
#define LPC32XX_I2C_SOFT_RESET 0x00000100
/* Status register values */
#define LPC32XX_I2C_STAT_TFF 0x00000400
#define LPC32XX_I2C_STAT_RFE 0x00000200
#define LPC32XX_I2C_STAT_DRMI 0x00000008
#define LPC32XX_I2C_STAT_NAI 0x00000004
#define LPC32XX_I2C_STAT_TDI 0x00000001
#ifndef CONFIG_DM_I2C
static struct lpc32xx_i2c_base *lpc32xx_i2c[] = {
(struct lpc32xx_i2c_base *)I2C1_BASE,
(struct lpc32xx_i2c_base *)I2C2_BASE,
(struct lpc32xx_i2c_base *)(USB_BASE + 0x300)
};
#endif
/* Set I2C bus speed */
static unsigned int __i2c_set_bus_speed(struct lpc32xx_i2c_base *base,
unsigned int speed, unsigned int chip)
{
int half_period;
if (speed == 0)
return -EINVAL;
/* OTG I2C clock source and CLK registers are different */
if (chip == 2) {
half_period = (get_periph_clk_rate() / speed) / 2;
if (half_period > 0xFF)
return -EINVAL;
} else {
half_period = (get_hclk_clk_rate() / speed) / 2;
if (half_period > 0x3FF)
return -EINVAL;
}
writel(half_period, &base->clk_hi);
writel(half_period, &base->clk_lo);
return 0;
}
/* I2C init called by cmd_i2c when doing 'i2c reset'. */
static void __i2c_init(struct lpc32xx_i2c_base *base,
int requested_speed, int slaveadd, unsigned int chip)
{
/* soft reset (auto-clears) */
writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
/* set HI and LO periods for half of the default speed */
__i2c_set_bus_speed(base, requested_speed, chip);
}
/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
static int __i2c_probe_chip(struct lpc32xx_i2c_base *base, u8 dev)
{
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* Addre slave for write with start before and stop after */
writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
&base->tx);
/* wait for end of transation */
while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* was there no acknowledge? */
return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*/
static int __i2c_read(struct lpc32xx_i2c_base *base, u8 dev, uint addr,
int alen, u8 *data, int length)
{
int stat, wlen;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write an address at all? */
if (alen) {
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
/* write address bytes */
while (alen--) {
/* compute address byte + stop for the last one */
int a = (addr >> (8 * alen)) & 0xff;
if (!alen)
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &base->tx);
}
/* wait for end of transation */
while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &base->stat);
}
/* do we have to read data at all? */
if (length) {
/* Address slave in read mode */
writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
wlen = length;
/* get data */
while (length | wlen) {
/* read status for TFF and RFE */
stat = readl(&base->stat);
/* must we, can we write a trigger byte? */
if ((wlen > 0)
& (!(stat & LPC32XX_I2C_STAT_TFF))) {
wlen--;
/* write trigger byte + stop if last */
writel(wlen ? 0 :
LPC32XX_I2C_TX_STOP, &base->tx);
}
/* must we, can we read a data byte? */
if ((length > 0)
& (!(stat & LPC32XX_I2C_STAT_RFE))) {
length--;
/* read byte */
*(data++) = readl(&base->rx);
}
}
/* wait for end of transation */
while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &base->stat);
}
/* success */
return 0;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
static int __i2c_write(struct lpc32xx_i2c_base *base, u8 dev, uint addr,
int alen, u8 *data, int length)
{
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &base->ctrl);
while (readl(&base->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write anything at all? */
if (alen | length)
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &base->tx);
else
return 0;
/* write address bytes */
while (alen) {
/* wait for transmit fifo not full */
stat = readl(&base->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
alen--;
int a = (addr >> (8 * alen)) & 0xff;
if (!(alen | length))
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &base->tx);
}
}
while (length) {
/* wait for transmit fifo not full */
stat = readl(&base->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
/* compute data byte, add stop if length==0 */
length--;
int d = *(data++);
if (!length)
d |= LPC32XX_I2C_TX_STOP;
/* Send data byte */
writel(d, &base->tx);
}
}
/* wait for end of transation */
while (!((stat = readl(&base->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &base->stat);
return 0;
}
#ifndef CONFIG_DM_I2C
static void lpc32xx_i2c_init(struct i2c_adapter *adap,
int requested_speed, int slaveadd)
{
__i2c_init(lpc32xx_i2c[adap->hwadapnr], requested_speed, slaveadd,
adap->hwadapnr);
}
static int lpc32xx_i2c_probe_chip(struct i2c_adapter *adap, u8 dev)
{
return __i2c_probe_chip(lpc32xx_i2c[adap->hwadapnr], dev);
}
static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
return __i2c_read(lpc32xx_i2c[adap->hwadapnr], dev, addr,
alen, data, length);
}
static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
return __i2c_write(lpc32xx_i2c[adap->hwadapnr], dev, addr,
alen, data, length);
}
static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
return __i2c_set_bus_speed(lpc32xx_i2c[adap->hwadapnr], speed,
adap->hwadapnr);
}
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, lpc32xx_i2c_init, lpc32xx_i2c_probe_chip,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
0)
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, lpc32xx_i2c_init, lpc32xx_i2c_probe_chip,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
1)
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_2, lpc32xx_i2c_init, NULL,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
100000,
0,
2)
#else /* CONFIG_DM_I2C */
static int lpc32xx_i2c_probe(struct udevice *bus)
{
struct lpc32xx_i2c_dev *dev = dev_get_platdata(bus);
bus->seq = dev->index;
__i2c_init(dev->base, dev->speed, 0, dev->index);
return 0;
}
static int lpc32xx_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct lpc32xx_i2c_dev *dev = dev_get_platdata(bus);
return __i2c_probe_chip(dev->base, chip_addr);
}
static int lpc32xx_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct lpc32xx_i2c_dev *dev = dev_get_platdata(bus);
struct i2c_msg *dmsg, *omsg, dummy;
uint i = 0, address = 0;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
/* the address is expected to be a uint, not a array. */
address = omsg->buf[0];
for (i = 1; i < omsg->len; i++)
address = (address << 8) + omsg->buf[i];
if (dmsg->flags & I2C_M_RD)
return __i2c_read(dev->base, dmsg->addr, address,
omsg->len, dmsg->buf, dmsg->len);
else
return __i2c_write(dev->base, dmsg->addr, address,
omsg->len, dmsg->buf, dmsg->len);
}
static int lpc32xx_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct lpc32xx_i2c_dev *dev = dev_get_platdata(bus);
return __i2c_set_bus_speed(dev->base, speed, dev->index);
}
static int lpc32xx_i2c_reset(struct udevice *bus)
{
struct lpc32xx_i2c_dev *dev = dev_get_platdata(bus);
__i2c_init(dev->base, dev->speed, 0, dev->index);
return 0;
}
static const struct dm_i2c_ops lpc32xx_i2c_ops = {
.xfer = lpc32xx_i2c_xfer,
.probe_chip = lpc32xx_i2c_probe_chip,
.deblock = lpc32xx_i2c_reset,
.set_bus_speed = lpc32xx_i2c_set_bus_speed,
};
U_BOOT_DRIVER(i2c_lpc32xx) = {
.id = UCLASS_I2C,
.name = "i2c_lpc32xx",
.probe = lpc32xx_i2c_probe,
.ops = &lpc32xx_i2c_ops,
};
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,309 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com>
*/
#include <common.h>
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#define I2C_TIMEOUT_MS 100
/* Control register fields */
#define REG_CTRL_START BIT(0)
#define REG_CTRL_ACK_IGNORE BIT(1)
#define REG_CTRL_STATUS BIT(2)
#define REG_CTRL_ERROR BIT(3)
#define REG_CTRL_CLKDIV_SHIFT 12
#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT_SHIFT 28
#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
enum {
TOKEN_END = 0,
TOKEN_START,
TOKEN_SLAVE_ADDR_WRITE,
TOKEN_SLAVE_ADDR_READ,
TOKEN_DATA,
TOKEN_DATA_LAST,
TOKEN_STOP,
};
struct i2c_regs {
u32 ctrl;
u32 slave_addr;
u32 tok_list0;
u32 tok_list1;
u32 tok_wdata0;
u32 tok_wdata1;
u32 tok_rdata0;
u32 tok_rdata1;
};
struct meson_i2c_data {
unsigned char div_factor;
};
struct meson_i2c {
const struct meson_i2c_data *data;
struct clk clk;
struct i2c_regs *regs;
struct i2c_msg *msg; /* Current I2C message */
bool last; /* Whether the message is the last */
uint count; /* Number of bytes in the current transfer */
uint pos; /* Position of current transfer in message */
u32 tokens[2]; /* Sequence of tokens to be written */
uint num_tokens; /* Number of tokens to be written */
};
static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
{
i2c->tokens[0] = 0;
i2c->tokens[1] = 0;
i2c->num_tokens = 0;
}
static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
{
if (i2c->num_tokens < 8)
i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4);
else
i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4);
i2c->num_tokens++;
}
/*
* Retrieve data for the current transfer (which can be at most 8
* bytes) from the device internal buffer.
*/
static void meson_i2c_get_data(struct meson_i2c *i2c, u8 *buf, int len)
{
u32 rdata0, rdata1;
int i;
rdata0 = readl(&i2c->regs->tok_rdata0);
rdata1 = readl(&i2c->regs->tok_rdata1);
debug("meson i2c: read data %08x %08x len %d\n", rdata0, rdata1, len);
for (i = 0; i < min(4, len); i++)
*buf++ = (rdata0 >> i * 8) & 0xff;
for (i = 4; i < min(8, len); i++)
*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
}
/*
* Write data for the current transfer (which can be at most 8 bytes)
* to the device internal buffer.
*/
static void meson_i2c_put_data(struct meson_i2c *i2c, u8 *buf, int len)
{
u32 wdata0 = 0, wdata1 = 0;
int i;
for (i = 0; i < min(4, len); i++)
wdata0 |= *buf++ << (i * 8);
for (i = 4; i < min(8, len); i++)
wdata1 |= *buf++ << ((i - 4) * 8);
writel(wdata0, &i2c->regs->tok_wdata0);
writel(wdata1, &i2c->regs->tok_wdata1);
debug("meson i2c: write data %08x %08x len %d\n", wdata0, wdata1, len);
}
/*
* Prepare the next transfer: pick the next 8 bytes in the remaining
* part of message and write tokens and data (if needed) to the
* device.
*/
static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
{
bool write = !(i2c->msg->flags & I2C_M_RD);
int i;
i2c->count = min(i2c->msg->len - i2c->pos, 8u);
for (i = 0; i + 1 < i2c->count; i++)
meson_i2c_add_token(i2c, TOKEN_DATA);
if (i2c->count) {
if (write || i2c->pos + i2c->count < i2c->msg->len)
meson_i2c_add_token(i2c, TOKEN_DATA);
else
meson_i2c_add_token(i2c, TOKEN_DATA_LAST);
}
if (write)
meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
meson_i2c_add_token(i2c, TOKEN_STOP);
writel(i2c->tokens[0], &i2c->regs->tok_list0);
writel(i2c->tokens[1], &i2c->regs->tok_list1);
}
static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
{
int token;
token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
TOKEN_SLAVE_ADDR_WRITE;
writel(msg->addr << 1, &i2c->regs->slave_addr);
meson_i2c_add_token(i2c, TOKEN_START);
meson_i2c_add_token(i2c, token);
}
static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
int last)
{
ulong start;
debug("meson i2c: %s addr %u len %u\n",
(msg->flags & I2C_M_RD) ? "read" : "write",
msg->addr, msg->len);
i2c->msg = msg;
i2c->last = last;
i2c->pos = 0;
i2c->count = 0;
meson_i2c_reset_tokens(i2c);
meson_i2c_do_start(i2c, msg);
do {
meson_i2c_prepare_xfer(i2c);
/* start the transfer */
setbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
start = get_timer(0);
while (readl(&i2c->regs->ctrl) & REG_CTRL_STATUS) {
if (get_timer(start) > I2C_TIMEOUT_MS) {
clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
debug("meson i2c: timeout\n");
return -ETIMEDOUT;
}
udelay(1);
}
meson_i2c_reset_tokens(i2c);
clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
if (readl(&i2c->regs->ctrl) & REG_CTRL_ERROR) {
debug("meson i2c: error\n");
return -EREMOTEIO;
}
if ((msg->flags & I2C_M_RD) && i2c->count) {
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
i2c->count);
}
i2c->pos += i2c->count;
} while (i2c->pos < msg->len);
return 0;
}
static int meson_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct meson_i2c *i2c = dev_get_priv(bus);
int i, ret = 0;
for (i = 0; i < nmsgs; i++) {
ret = meson_i2c_xfer_msg(i2c, msg + i, i == nmsgs - 1);
if (ret)
return ret;
}
return 0;
}
static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct meson_i2c *i2c = dev_get_priv(bus);
ulong clk_rate;
unsigned int div;
clk_rate = clk_get_rate(&i2c->clk);
if (IS_ERR_VALUE(clk_rate))
return -EINVAL;
div = DIV_ROUND_UP(clk_rate, speed * i2c->data->div_factor);
/* clock divider has 12 bits */
if (div >= (1 << 12)) {
debug("meson i2c: requested bus frequency too low\n");
div = (1 << 12) - 1;
}
clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIV_MASK,
(div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div);
return 0;
}
static int meson_i2c_probe(struct udevice *bus)
{
struct meson_i2c *i2c = dev_get_priv(bus);
int ret;
i2c->data = (const struct meson_i2c_data *)dev_get_driver_data(bus);
ret = clk_get_by_index(bus, 0, &i2c->clk);
if (ret < 0)
return ret;
ret = clk_enable(&i2c->clk);
if (ret)
return ret;
i2c->regs = dev_read_addr_ptr(bus);
clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
return 0;
}
static const struct dm_i2c_ops meson_i2c_ops = {
.xfer = meson_i2c_xfer,
.set_bus_speed = meson_i2c_set_bus_speed,
};
static const struct meson_i2c_data i2c_meson6_data = {
.div_factor = 4,
};
static const struct meson_i2c_data i2c_gxbb_data = {
.div_factor = 4,
};
static const struct meson_i2c_data i2c_axg_data = {
.div_factor = 3,
};
static const struct udevice_id meson_i2c_ids[] = {
{.compatible = "amlogic,meson6-i2c", .data = (ulong)&i2c_meson6_data},
{.compatible = "amlogic,meson-gx-i2c", .data = (ulong)&i2c_gxbb_data},
{.compatible = "amlogic,meson-gxbb-i2c", .data = (ulong)&i2c_gxbb_data},
{.compatible = "amlogic,meson-axg-i2c", .data = (ulong)&i2c_axg_data},
{}
};
U_BOOT_DRIVER(i2c_meson) = {
.name = "i2c_meson",
.id = UCLASS_I2C,
.of_match = meson_i2c_ids,
.probe = meson_i2c_probe,
.priv_auto_alloc_size = sizeof(struct meson_i2c),
.ops = &meson_i2c_ops,
};
@@ -0,0 +1,46 @@
config I2C_MUX
bool "Support I2C multiplexers"
depends on DM_I2C
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config SPL_I2C_MUX
bool "Support I2C multiplexers on SPL"
depends on I2C_MUX
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config I2C_ARB_GPIO_CHALLENGE
bool "GPIO-based I2C arbitration"
depends on I2C_MUX
help
If you say yes to this option, support will be included for an
I2C multimaster arbitration scheme using GPIOs and a challenge &
response mechanism where masters have to claim the bus by asserting
a GPIO.
config I2C_MUX_PCA954x
tristate "TI PCA954x I2C Mux/switches"
depends on I2C_MUX
help
If you say yes here you get support for the TI PCA954x I2C mux/switch
devices. It is x width I2C multiplexer which enables to partitioning
I2C bus and connect multiple devices with the same address to the same
I2C controller where driver handles proper routing to target i2c
device. Supported chips are PCA9543, PCA9544, PCA9547, PCA9548 and
PCA9646.
config I2C_MUX_GPIO
tristate "GPIO-based I2C multiplexer"
depends on I2C_MUX && DM_GPIO
help
If you say yes to this option, support will be included for
a GPIO based I2C multiplexer. This driver provides access to
I2C busses connected through a MUX, which is controlled
through GPIO pins.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2015 Google, Inc
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o
obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
struct i2c_arbitrator_priv {
struct gpio_desc ap_claim;
struct gpio_desc ec_claim;
uint slew_delay_us;
uint wait_retry_ms;
uint wait_free_ms;
};
int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
ret = dm_gpio_set_value(&priv->ap_claim, 0);
udelay(priv->slew_delay_us);
return ret;
}
int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
unsigned start;
int ret;
debug("%s: %s\n", __func__, mux->name);
/* Start a round of trying to claim the bus */
start = get_timer(0);
do {
unsigned start_retry;
int waiting = 0;
/* Indicate that we want to claim the bus */
ret = dm_gpio_set_value(&priv->ap_claim, 1);
if (ret)
goto err;
udelay(priv->slew_delay_us);
/* Wait for the EC to release it */
start_retry = get_timer(0);
while (get_timer(start_retry) < priv->wait_retry_ms) {
ret = dm_gpio_get_value(&priv->ec_claim);
if (ret < 0) {
goto err;
} else if (!ret) {
/* We got it, so return */
return 0;
}
if (!waiting)
waiting = 1;
}
/* It didn't release, so give up, wait, and try again */
ret = dm_gpio_set_value(&priv->ap_claim, 0);
if (ret)
goto err;
mdelay(priv->wait_retry_ms);
} while (get_timer(start) < priv->wait_free_ms);
/* Give up, release our claim */
printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
ret = -ETIMEDOUT;
ret = 0;
err:
return ret;
}
static int i2c_arbitrator_probe(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
int ret;
debug("%s: %s\n", __func__, dev->name);
priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
1000;
priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
1000;
ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
GPIOD_IS_OUT);
if (ret)
goto err;
ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
GPIOD_IS_IN);
if (ret)
goto err_ec_gpio;
return 0;
err_ec_gpio:
dm_gpio_free(dev, &priv->ap_claim);
err:
debug("%s: ret=%d\n", __func__, ret);
return ret;
}
static int i2c_arbitrator_remove(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
dm_gpio_free(dev, &priv->ap_claim);
dm_gpio_free(dev, &priv->ec_claim);
return 0;
}
static const struct i2c_mux_ops i2c_arbitrator_ops = {
.select = i2c_arbitrator_select,
.deselect = i2c_arbitrator_deselect,
};
static const struct udevice_id i2c_arbitrator_ids[] = {
{ .compatible = "i2c-arb-gpio-challenge" },
{ }
};
U_BOOT_DRIVER(i2c_arbitrator) = {
.name = "i2c_arbitrator",
.id = UCLASS_I2C_MUX,
.of_match = i2c_arbitrator_ids,
.probe = i2c_arbitrator_probe,
.remove = i2c_arbitrator_remove,
.ops = &i2c_arbitrator_ops,
.priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
};
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* I2C multiplexer using GPIO API
*
* Copyright 2017 NXP
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <fdtdec.h>
#include <i2c.h>
#include <linux/errno.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct i2c_mux_gpio_priv - private data for i2c mux gpio
*
* @values: the reg value of each child node
* @n_values: num of regs
* @gpios: the mux-gpios array
* @n_gpios: num of gpios in mux-gpios
* @idle: the value of idle-state
*/
struct i2c_mux_gpio_priv {
u32 *values;
int n_values;
struct gpio_desc *gpios;
int n_gpios;
u32 idle;
};
static int i2c_mux_gpio_select(struct udevice *dev, struct udevice *bus,
uint channel)
{
struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
int i, ret;
for (i = 0; i < priv->n_gpios; i++) {
ret = dm_gpio_set_value(&priv->gpios[i], (channel >> i) & 1);
if (ret)
return ret;
}
return 0;
}
static int i2c_mux_gpio_deselect(struct udevice *dev, struct udevice *bus,
uint channel)
{
struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
int i, ret;
for (i = 0; i < priv->n_gpios; i++) {
ret = dm_gpio_set_value(&priv->gpios[i], (priv->idle >> i) & 1);
if (ret)
return ret;
}
return 0;
}
static int i2c_mux_gpio_probe(struct udevice *dev)
{
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(dev);
struct i2c_mux_gpio_priv *mux = dev_get_priv(dev);
struct gpio_desc *gpios;
u32 *values;
int i = 0, subnode, ret;
mux->n_values = fdtdec_get_child_count(fdt, node);
values = devm_kzalloc(dev, sizeof(*mux->values) * mux->n_values,
GFP_KERNEL);
if (!values) {
dev_err(dev, "Cannot alloc values array");
return -ENOMEM;
}
fdt_for_each_subnode(subnode, fdt, node) {
*(values + i) = fdtdec_get_uint(fdt, subnode, "reg", -1);
i++;
}
mux->values = values;
mux->idle = fdtdec_get_uint(fdt, node, "idle-state", -1);
mux->n_gpios = gpio_get_list_count(dev, "mux-gpios");
if (mux->n_gpios < 0) {
dev_err(dev, "Missing mux-gpios property\n");
return -EINVAL;
}
gpios = devm_kzalloc(dev, sizeof(struct gpio_desc) * mux->n_gpios,
GFP_KERNEL);
if (!gpios) {
dev_err(dev, "Cannot allocate gpios array\n");
return -ENOMEM;
}
ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
if (ret <= 0) {
dev_err(dev, "Failed to request mux-gpios\n");
return ret;
}
mux->gpios = gpios;
return 0;
}
static const struct i2c_mux_ops i2c_mux_gpio_ops = {
.select = i2c_mux_gpio_select,
.deselect = i2c_mux_gpio_deselect,
};
static const struct udevice_id i2c_mux_gpio_ids[] = {
{ .compatible = "i2c-mux-gpio", },
{}
};
U_BOOT_DRIVER(i2c_mux_gpio) = {
.name = "i2c_mux_gpio",
.id = UCLASS_I2C_MUX,
.of_match = i2c_mux_gpio_ids,
.ops = &i2c_mux_gpio_ops,
.probe = i2c_mux_gpio_probe,
.priv_auto_alloc_size = sizeof(struct i2c_mux_gpio_priv),
};
@@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <dm/lists.h>
#include <dm/root.h>
/**
* struct i2c_mux: Information the uclass stores about an I2C mux
*
* @selected: Currently selected mux, or -1 for none
* @i2c_bus: I2C bus to use for communcation
*/
struct i2c_mux {
int selected;
struct udevice *i2c_bus;
};
/**
* struct i2c_mux_bus: Information about each bus the mux controls
*
* @channel: Channel number used to select this bus
*/
struct i2c_mux_bus {
uint channel;
};
/* Find out the mux channel number */
static int i2c_mux_child_post_bind(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
int channel;
channel = dev_read_u32_default(dev, "reg", -1);
if (channel < 0)
return -EINVAL;
plat->channel = channel;
return 0;
}
/* Find the I2C buses selected by this mux */
static int i2c_mux_post_bind(struct udevice *mux)
{
ofnode node;
int ret;
debug("%s: %s\n", __func__, mux->name);
/*
* There is no compatible string in the sub-nodes, so we must manually
* bind these
*/
dev_for_each_subnode(node, mux) {
struct udevice *dev;
const char *name;
const char *arrow = "->";
char *full_name;
int parent_name_len, arrow_len, mux_name_len, name_len;
name = ofnode_get_name(node);
/* Calculate lenghts of strings */
parent_name_len = strlen(mux->parent->name);
arrow_len = strlen(arrow);
mux_name_len = strlen(mux->name);
name_len = strlen(name);
full_name = calloc(1, parent_name_len + arrow_len +
mux_name_len + arrow_len + name_len + 1);
if (!full_name)
return -ENOMEM;
/* Compose bus name */
strcat(full_name, mux->parent->name);
strcat(full_name, arrow);
strcat(full_name, mux->name);
strcat(full_name, arrow);
strcat(full_name, name);
ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv",
full_name, node, &dev);
debug(" - bind ret=%d, %s, req_seq %d\n", ret,
dev ? dev->name : NULL, dev->req_seq);
if (ret)
return ret;
}
return 0;
}
/* Set up the mux ready for use */
static int i2c_mux_post_probe(struct udevice *mux)
{
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
priv->selected = -1;
/* if parent is of i2c uclass already, we'll take that, otherwise
* look if we find an i2c-parent phandle
*/
if (UCLASS_I2C == device_get_uclass_id(mux->parent)) {
priv->i2c_bus = dev_get_parent(mux);
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus,
priv->i2c_bus->name);
return 0;
}
ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
&priv->i2c_bus);
if (ret)
return ret;
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
return 0;
}
int i2c_mux_select(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->select)
return -ENOSYS;
return ops->select(mux, dev, plat->channel);
}
int i2c_mux_deselect(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->deselect)
return -ENOSYS;
return ops->deselect(mux, dev, plat->channel);
}
static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret, ret2;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
uint chip_flags)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->probe_chip)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->xfer)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static const struct dm_i2c_ops i2c_mux_bus_ops = {
.xfer = i2c_mux_bus_xfer,
.probe_chip = i2c_mux_bus_probe,
.set_bus_speed = i2c_mux_bus_set_bus_speed,
};
U_BOOT_DRIVER(i2c_mux_bus) = {
.name = "i2c_mux_bus_drv",
.id = UCLASS_I2C,
.ops = &i2c_mux_bus_ops,
};
UCLASS_DRIVER(i2c_mux) = {
.id = UCLASS_I2C_MUX,
.name = "i2c_mux",
.post_bind = i2c_mux_post_bind,
.post_probe = i2c_mux_post_probe,
.per_device_auto_alloc_size = sizeof(struct i2c_mux),
.per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
.child_post_bind = i2c_mux_child_post_bind,
};
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 - 2016 Xilinx, Inc.
* Copyright (C) 2017 National Instruments Corp
* Written by Michal Simek
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm-generic/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
enum pca_type {
PCA9543,
PCA9544,
PCA9547,
PCA9548,
PCA9646
};
struct chip_desc {
u8 enable; /* Enable mask in ctl register (used for muxes only) */
enum muxtype {
pca954x_ismux = 0,
pca954x_isswi,
} muxtype;
u32 width;
};
struct pca954x_priv {
u32 addr; /* I2C mux address */
u32 width; /* I2C mux width - number of busses */
struct gpio_desc gpio_mux_reset;
};
static const struct chip_desc chips[] = {
[PCA9543] = {
.muxtype = pca954x_isswi,
.width = 2,
},
[PCA9544] = {
.enable = 0x4,
.muxtype = pca954x_ismux,
.width = 4,
},
[PCA9547] = {
.enable = 0x8,
.muxtype = pca954x_ismux,
.width = 8,
},
[PCA9548] = {
.muxtype = pca954x_isswi,
.width = 8,
},
[PCA9646] = {
.muxtype = pca954x_isswi,
.width = 4,
},
};
static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
uchar byte = 0;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static int pca954x_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
uchar byte;
if (chip->muxtype == pca954x_ismux)
byte = channel | chip->enable;
else
byte = 1 << channel;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static const struct i2c_mux_ops pca954x_ops = {
.select = pca954x_select,
.deselect = pca954x_deselect,
};
static const struct udevice_id pca954x_ids[] = {
{ .compatible = "nxp,pca9543", .data = PCA9543 },
{ .compatible = "nxp,pca9544", .data = PCA9544 },
{ .compatible = "nxp,pca9547", .data = PCA9547 },
{ .compatible = "nxp,pca9548", .data = PCA9548 },
{ .compatible = "nxp,pca9646", .data = PCA9646 },
{ }
};
static int pca954x_ofdata_to_platdata(struct udevice *dev)
{
struct pca954x_priv *priv = dev_get_priv(dev);
const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
priv->addr = dev_read_u32_default(dev, "reg", 0);
if (!priv->addr) {
debug("MUX not found\n");
return -ENODEV;
}
priv->width = chip->width;
if (!priv->width) {
debug("No I2C MUX width specified\n");
return -EINVAL;
}
debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
return 0;
}
static int pca954x_probe(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
int err;
err = gpio_request_by_name(dev, "reset-gpios", 0,
&priv->gpio_mux_reset, GPIOD_IS_OUT);
/* it's optional so only bail if we get a real error */
if (err && (err != -ENOENT))
return err;
/* dm will take care of polarity */
if (dm_gpio_is_valid(&priv->gpio_mux_reset))
dm_gpio_set_value(&priv->gpio_mux_reset, 0);
}
return 0;
}
static int pca954x_remove(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
if (dm_gpio_is_valid(&priv->gpio_mux_reset))
dm_gpio_free(dev, &priv->gpio_mux_reset);
}
return 0;
}
U_BOOT_DRIVER(pca954x) = {
.name = "pca954x",
.id = UCLASS_I2C_MUX,
.of_match = pca954x_ids,
.probe = pca954x_probe,
.remove = pca954x_remove,
.ops = &pca954x_ops,
.ofdata_to_platdata = pca954x_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct pca954x_priv),
};
@@ -0,0 +1,604 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2003 Pengutronix e.K.
* Robert Schwebel <r.schwebel@pengutronix.de>
*
* (C) Copyright 2011 Marvell Inc.
* Lei Wen <leiwen@marvell.com>
*
* Back ported to the 8xx platform (from the 8260 platform) by
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <asm/io.h>
#include "mv_i2c.h"
/* All transfers are described by this data structure */
struct mv_i2c_msg {
u8 condition;
u8 acknack;
u8 direction;
u8 data;
};
#ifdef CONFIG_ARMADA_3700
/* Armada 3700 has no padding between the registers */
struct mv_i2c {
u32 ibmr;
u32 idbr;
u32 icr;
u32 isr;
u32 isar;
};
#else
struct mv_i2c {
u32 ibmr;
u32 pad0;
u32 idbr;
u32 pad1;
u32 icr;
u32 pad2;
u32 isr;
u32 pad3;
u32 isar;
};
#endif
/*
* Dummy implementation that can be overwritten by a board
* specific function
*/
__weak void i2c_clk_enable(void)
{
}
/*
* i2c_reset: - reset the host controller
*
*/
static void i2c_reset(struct mv_i2c *base)
{
u32 icr_mode;
/* Save bus mode (standard or fast speed) for later use */
icr_mode = readl(&base->icr) & ICR_MODE_MASK;
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
writel(readl(&base->icr) | ICR_UR, &base->icr); /* reset the unit */
udelay(100);
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
i2c_clk_enable();
writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */
/* set control reg values */
writel(I2C_ICR_INIT | icr_mode, &base->icr);
writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */
writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */
udelay(100);
}
/*
* i2c_isr_set_cleared: - wait until certain bits of the I2C status register
* are set and cleared
*
* @return: 1 in case of success, 0 means timeout (no match within 10 ms).
*/
static int i2c_isr_set_cleared(struct mv_i2c *base, unsigned long set_mask,
unsigned long cleared_mask)
{
int timeout = 1000, isr;
do {
isr = readl(&base->isr);
udelay(10);
if (timeout-- < 0)
return 0;
} while (((isr & set_mask) != set_mask)
|| ((isr & cleared_mask) != 0));
return 1;
}
/*
* i2c_transfer: - Transfer one byte over the i2c bus
*
* This function can tranfer a byte over the i2c bus in both directions.
* It is used by the public API functions.
*
* @return: 0: transfer successful
* -1: message is empty
* -2: transmit timeout
* -3: ACK missing
* -4: receive timeout
* -5: illegal parameters
* -6: bus is busy and couldn't be aquired
*/
static int i2c_transfer(struct mv_i2c *base, struct mv_i2c_msg *msg)
{
int ret;
if (!msg)
goto transfer_error_msg_empty;
switch (msg->direction) {
case I2C_WRITE:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
goto transfer_error_bus_busy;
/* start transmission */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
writel(msg->data, &base->idbr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* transmit register empty? */
if (!i2c_isr_set_cleared(base, ISR_ITE, 0))
goto transfer_error_transmit_timeout;
/* clear 'transmit empty' state */
writel(readl(&base->isr) | ISR_ITE, &base->isr);
/* wait for ACK from slave */
if (msg->acknack == I2C_ACKNAK_WAITACK)
if (!i2c_isr_set_cleared(base, 0, ISR_ACKNAK))
goto transfer_error_ack_missing;
break;
case I2C_READ:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(base, 0, ISR_IBB))
goto transfer_error_bus_busy;
/* start receive */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* receive register full? */
if (!i2c_isr_set_cleared(base, ISR_IRF, 0))
goto transfer_error_receive_timeout;
msg->data = readl(&base->idbr);
/* clear 'receive empty' state */
writel(readl(&base->isr) | ISR_IRF, &base->isr);
break;
default:
goto transfer_error_illegal_param;
}
return 0;
transfer_error_msg_empty:
debug("i2c_transfer: error: 'msg' is empty\n");
ret = -1;
goto i2c_transfer_finish;
transfer_error_transmit_timeout:
debug("i2c_transfer: error: transmit timeout\n");
ret = -2;
goto i2c_transfer_finish;
transfer_error_ack_missing:
debug("i2c_transfer: error: ACK missing\n");
ret = -3;
goto i2c_transfer_finish;
transfer_error_receive_timeout:
debug("i2c_transfer: error: receive timeout\n");
ret = -4;
goto i2c_transfer_finish;
transfer_error_illegal_param:
debug("i2c_transfer: error: illegal parameters\n");
ret = -5;
goto i2c_transfer_finish;
transfer_error_bus_busy:
debug("i2c_transfer: error: bus is busy\n");
ret = -6;
goto i2c_transfer_finish;
i2c_transfer_finish:
debug("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr));
i2c_reset(base);
return ret;
}
static int __i2c_read(struct mv_i2c *base, uchar chip, u8 *addr, int alen,
uchar *buffer, int len)
{
struct mv_i2c_msg msg;
debug("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, *addr, alen, len);
if (len == 0) {
printf("reading zero byte is invalid\n");
return -EINVAL;
}
i2c_reset(base);
/* dummy chip address write */
debug("i2c_read: dummy chip address write\n");
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(base, &msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
while (--alen >= 0) {
debug("i2c_read: send address byte %02x (alen=%d)\n",
*addr, alen);
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr[alen];
if (i2c_transfer(base, &msg))
return -1;
}
/* start read sequence */
debug("i2c_read: start read sequence\n");
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data |= 0x01;
if (i2c_transfer(base, &msg))
return -1;
/* read bytes; send NACK at last byte */
while (len--) {
if (len == 0) {
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
} else {
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_SENDACK;
}
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(base, &msg))
return -1;
*buffer = msg.data;
debug("i2c_read: reading byte (%p)=0x%02x\n",
buffer, *buffer);
buffer++;
}
i2c_reset(base);
return 0;
}
static int __i2c_write(struct mv_i2c *base, uchar chip, u8 *addr, int alen,
uchar *buffer, int len)
{
struct mv_i2c_msg msg;
debug("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, *addr, alen, len);
i2c_reset(base);
/* chip address write */
debug("i2c_write: chip address write\n");
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(base, &msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
while (--alen >= 0) {
debug("i2c_read: send address byte %02x (alen=%d)\n",
*addr, alen);
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr[alen];
if (i2c_transfer(base, &msg))
return -1;
}
/* write bytes; send NACK at last byte */
while (len--) {
debug("i2c_write: writing byte (%p)=0x%02x\n",
buffer, *buffer);
if (len == 0)
msg.condition = I2C_COND_STOP;
else
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = *(buffer++);
if (i2c_transfer(base, &msg))
return -1;
}
i2c_reset(base);
return 0;
}
#ifndef CONFIG_DM_I2C
static struct mv_i2c *base_glob;
static void i2c_board_init(struct mv_i2c *base)
{
#ifdef CONFIG_SYS_I2C_INIT_BOARD
u32 icr;
/*
* call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*
* disable I2C controller first, otherwhise it thinks we want to
* talk to the slave port...
*/
icr = readl(&base->icr);
writel(readl(&base->icr) & ~(ICR_SCLE | ICR_IUE), &base->icr);
i2c_init_board();
writel(icr, &base->icr);
#endif
}
#ifdef CONFIG_I2C_MULTI_BUS
static unsigned long i2c_regs[CONFIG_MV_I2C_NUM] = CONFIG_MV_I2C_REG;
static unsigned int bus_initialized[CONFIG_MV_I2C_NUM];
static unsigned int current_bus;
int i2c_set_bus_num(unsigned int bus)
{
if ((bus < 0) || (bus >= CONFIG_MV_I2C_NUM)) {
printf("Bad bus: %d\n", bus);
return -1;
}
base_glob = (struct mv_i2c *)i2c_regs[bus];
current_bus = bus;
if (!bus_initialized[current_bus]) {
i2c_board_init(base_glob);
bus_initialized[current_bus] = 1;
}
return 0;
}
unsigned int i2c_get_bus_num(void)
{
return current_bus;
}
#endif
/* API Functions */
void i2c_init(int speed, int slaveaddr)
{
u32 val;
#ifdef CONFIG_I2C_MULTI_BUS
current_bus = 0;
base_glob = (struct mv_i2c *)i2c_regs[current_bus];
#else
base_glob = (struct mv_i2c *)CONFIG_MV_I2C_REG;
#endif
if (speed > 100000)
val = ICR_FM;
else
val = ICR_SM;
clrsetbits_le32(&base_glob->icr, ICR_MODE_MASK, val);
i2c_board_init(base_glob);
}
static int __i2c_probe_chip(struct mv_i2c *base, uchar chip)
{
struct mv_i2c_msg msg;
i2c_reset(base);
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1) + 1;
if (i2c_transfer(base, &msg))
return -1;
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(base, &msg))
return -1;
return 0;
}
/*
* i2c_probe: - Test if a chip answers for a given i2c address
*
* @chip: address of the chip which is searched for
* @return: 0 if a chip was found, -1 otherwhise
*/
int i2c_probe(uchar chip)
{
return __i2c_probe_chip(base_glob, chip);
}
/*
* i2c_read: - Read multiple bytes from an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be read
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to write the data
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
u8 addr_bytes[4];
addr_bytes[0] = (addr >> 0) & 0xFF;
addr_bytes[1] = (addr >> 8) & 0xFF;
addr_bytes[2] = (addr >> 16) & 0xFF;
addr_bytes[3] = (addr >> 24) & 0xFF;
return __i2c_read(base_glob, chip, addr_bytes, alen, buffer, len);
}
/*
* i2c_write: - Write multiple bytes to an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be written
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to find the data to be written
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
u8 addr_bytes[4];
addr_bytes[0] = (addr >> 0) & 0xFF;
addr_bytes[1] = (addr >> 8) & 0xFF;
addr_bytes[2] = (addr >> 16) & 0xFF;
addr_bytes[3] = (addr >> 24) & 0xFF;
return __i2c_write(base_glob, chip, addr_bytes, alen, buffer, len);
}
#else /* CONFIG_DM_I2C */
struct mv_i2c_priv {
struct mv_i2c *base;
};
static int mv_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct mv_i2c_priv *i2c = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/*
* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data or offset/data combined)
*/
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return __i2c_read(i2c->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len);
else
return __i2c_write(i2c->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len);
}
static int mv_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct mv_i2c_priv *priv = dev_get_priv(bus);
u32 val;
if (speed > 100000)
val = ICR_FM;
else
val = ICR_SM;
clrsetbits_le32(&priv->base->icr, ICR_MODE_MASK, val);
return 0;
}
static int mv_i2c_probe(struct udevice *bus)
{
struct mv_i2c_priv *priv = dev_get_priv(bus);
priv->base = (void *)devfdt_get_addr_ptr(bus);
return 0;
}
static const struct dm_i2c_ops mv_i2c_ops = {
.xfer = mv_i2c_xfer,
.set_bus_speed = mv_i2c_set_bus_speed,
};
static const struct udevice_id mv_i2c_ids[] = {
{ .compatible = "marvell,armada-3700-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_mv) = {
.name = "i2c_mv",
.id = UCLASS_I2C,
.of_match = mv_i2c_ids,
.probe = mv_i2c_probe,
.priv_auto_alloc_size = sizeof(struct mv_i2c_priv),
.ops = &mv_i2c_ops,
};
#endif /* CONFIG_DM_I2C */
@@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2011
* Marvell Inc, <www.marvell.com>
*/
#ifndef _MV_I2C_H_
#define _MV_I2C_H_
extern void i2c_clk_enable(void);
/* Shall the current transfer have a start/stop condition? */
#define I2C_COND_NORMAL 0
#define I2C_COND_START 1
#define I2C_COND_STOP 2
/* Shall the current transfer be ack/nacked or being waited for it? */
#define I2C_ACKNAK_WAITACK 1
#define I2C_ACKNAK_SENDACK 2
#define I2C_ACKNAK_SENDNAK 4
/* Specify who shall transfer the data (master or slave) */
#define I2C_READ 0
#define I2C_WRITE 1
#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
#define I2C_ISR_INIT 0x7FF
/* ----- Control register bits ---------------------------------------- */
#define ICR_START 0x1 /* start bit */
#define ICR_STOP 0x2 /* stop bit */
#define ICR_ACKNAK 0x4 /* send ACK(0) or NAK(1) */
#define ICR_TB 0x8 /* transfer byte bit */
#define ICR_MA 0x10 /* master abort */
#define ICR_SCLE 0x20 /* master clock enable, mona SCLEA */
#define ICR_IUE 0x40 /* unit enable */
#define ICR_GCD 0x80 /* general call disable */
#define ICR_ITEIE 0x100 /* enable tx interrupts */
#define ICR_IRFIE 0x200 /* enable rx interrupts, mona: DRFIE */
#define ICR_BEIE 0x400 /* enable bus error ints */
#define ICR_SSDIE 0x800 /* slave STOP detected int enable */
#define ICR_ALDIE 0x1000 /* enable arbitration interrupt */
#define ICR_SADIE 0x2000 /* slave address detected int enable */
#define ICR_UR 0x4000 /* unit reset */
#ifdef CONFIG_ARMADA_3700
#define ICR_SM 0x00000 /* Standard Mode */
#define ICR_FM 0x10000 /* Fast Mode */
#define ICR_MODE_MASK 0x30000 /* Mode mask */
#else
#define ICR_SM 0x00000 /* Standard Mode */
#define ICR_FM 0x08000 /* Fast Mode */
#define ICR_MODE_MASK 0x18000 /* Mode mask */
#endif
/* ----- Status register bits ----------------------------------------- */
#define ISR_RWM 0x1 /* read/write mode */
#define ISR_ACKNAK 0x2 /* ack/nak status */
#define ISR_UB 0x4 /* unit busy */
#define ISR_IBB 0x8 /* bus busy */
#define ISR_SSD 0x10 /* slave stop detected */
#define ISR_ALD 0x20 /* arbitration loss detected */
#define ISR_ITE 0x40 /* tx buffer empty */
#define ISR_IRF 0x80 /* rx buffer full */
#define ISR_GCAD 0x100 /* general call address detected */
#define ISR_SAD 0x200 /* slave address detected */
#define ISR_BED 0x400 /* bus error no ACK/NAK */
#endif
@@ -0,0 +1,891 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for the TWSI (i2c) controller found on the Marvell
* orion5x and kirkwood SoC families.
*
* Author: Albert Aribaud <albert.u.boot@aribaud.net>
* Copyright (c) 2010 Albert Aribaud.
*/
#include <common.h>
#include <i2c.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <linux/bitops.h>
#include <linux/compat.h>
#ifdef CONFIG_DM_I2C
#include <dm.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
/*
* Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
* settings
*/
#ifndef CONFIG_DM_I2C
#if defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
#include <asm/arch/soc.h>
#elif defined(CONFIG_ARCH_SUNXI)
#include <asm/arch/i2c.h>
#else
#error Driver mvtwsi not supported by SoC or board
#endif
#endif /* CONFIG_DM_I2C */
/*
* On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to
* always have it.
*/
#if defined(CONFIG_DM_I2C) && defined(CONFIG_ARCH_SUNXI)
#include <asm/arch/i2c.h>
#endif
/*
* TWSI register structure
*/
#ifdef CONFIG_ARCH_SUNXI
struct mvtwsi_registers {
u32 slave_address;
u32 xtnd_slave_addr;
u32 data;
u32 control;
u32 status;
u32 baudrate;
u32 soft_reset;
u32 debug; /* Dummy field for build compatibility with mvebu */
};
#else
struct mvtwsi_registers {
u32 slave_address;
u32 data;
u32 control;
union {
u32 status; /* When reading */
u32 baudrate; /* When writing */
};
u32 xtnd_slave_addr;
u32 reserved0[2];
u32 soft_reset;
u32 reserved1[27];
u32 debug;
};
#endif
#ifdef CONFIG_DM_I2C
struct mvtwsi_i2c_dev {
/* TWSI Register base for the device */
struct mvtwsi_registers *base;
/* Number of the device (determined from cell-index property) */
int index;
/* The I2C slave address for the device */
u8 slaveadd;
/* The configured I2C speed in Hz */
uint speed;
/* The current length of a clock period (depending on speed) */
uint tick;
};
#endif /* CONFIG_DM_I2C */
/*
* enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
* register
*/
enum mvtwsi_ctrl_register_fields {
/* Acknowledge bit */
MVTWSI_CONTROL_ACK = 0x00000004,
/* Interrupt flag */
MVTWSI_CONTROL_IFLG = 0x00000008,
/* Stop bit */
MVTWSI_CONTROL_STOP = 0x00000010,
/* Start bit */
MVTWSI_CONTROL_START = 0x00000020,
/* I2C enable */
MVTWSI_CONTROL_TWSIEN = 0x00000040,
/* Interrupt enable */
MVTWSI_CONTROL_INTEN = 0x00000080,
};
/*
* On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
* on other platforms, it is a normal r/w bit, which is cleared by writing 0.
*/
#ifdef CONFIG_SUNXI_GEN_SUN6I
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
#else
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
#endif
/*
* enum mvstwsi_status_values - Possible values of I2C controller's status
* register
*
* Only those statuses expected in normal master operation on
* non-10-bit-address devices are specified.
*
* Every status that's unexpected during normal operation (bus errors,
* arbitration losses, missing ACKs...) is passed back to the caller as an error
* code.
*/
enum mvstwsi_status_values {
/* START condition transmitted */
MVTWSI_STATUS_START = 0x08,
/* Repeated START condition transmitted */
MVTWSI_STATUS_REPEATED_START = 0x10,
/* Address + write bit transmitted, ACK received */
MVTWSI_STATUS_ADDR_W_ACK = 0x18,
/* Data transmitted, ACK received */
MVTWSI_STATUS_DATA_W_ACK = 0x28,
/* Address + read bit transmitted, ACK received */
MVTWSI_STATUS_ADDR_R_ACK = 0x40,
/* Address + read bit transmitted, ACK not received */
MVTWSI_STATUS_ADDR_R_NAK = 0x48,
/* Data received, ACK transmitted */
MVTWSI_STATUS_DATA_R_ACK = 0x50,
/* Data received, ACK not transmitted */
MVTWSI_STATUS_DATA_R_NAK = 0x58,
/* No relevant status */
MVTWSI_STATUS_IDLE = 0xF8,
};
/*
* enum mvstwsi_ack_flags - Determine whether a read byte should be
* acknowledged or not.
*/
enum mvtwsi_ack_flags {
/* Send NAK after received byte */
MVTWSI_READ_NAK = 0,
/* Send ACK after received byte */
MVTWSI_READ_ACK = 1,
};
/*
* calc_tick() - Calculate the duration of a clock cycle from the I2C speed
*
* @speed: The speed in Hz to calculate the clock cycle duration for.
* @return The duration of a clock cycle in ns.
*/
inline uint calc_tick(uint speed)
{
/* One tick = the duration of a period at the specified speed in ns (we
* add 100 ns to be on the safe side) */
return (1000000000u / speed) + 100;
}
#ifndef CONFIG_DM_I2C
/*
* twsi_get_base() - Get controller register base for specified adapter
*
* @adap: Adapter to get the register base for.
* @return Register base for the specified adapter.
*/
static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#ifdef CONFIG_I2C_MVTWSI_BASE0
case 0:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE1
case 1:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE2
case 2:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE3
case 3:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE4
case 4:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE5
case 5:
return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
#endif
default:
printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
break;
}
return NULL;
}
#endif
/*
* enum mvtwsi_error_class - types of I2C errors
*/
enum mvtwsi_error_class {
/* The controller returned a different status than expected */
MVTWSI_ERROR_WRONG_STATUS = 0x01,
/* The controller timed out */
MVTWSI_ERROR_TIMEOUT = 0x02,
};
/*
* mvtwsi_error() - Build I2C return code from error information
*
* For debugging purposes, this function packs some information of an occurred
* error into a return code. These error codes are returned from I2C API
* functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
*
* @ec: The error class of the error (enum mvtwsi_error_class).
* @lc: The last value of the control register.
* @ls: The last value of the status register.
* @es: The expected value of the status register.
* @return The generated error code.
*/
inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
{
return ((ec << 24) & 0xFF000000)
| ((lc << 16) & 0x00FF0000)
| ((ls << 8) & 0x0000FF00)
| (es & 0xFF);
}
/*
* twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
*
* @return Zero if status is as expected, or a non-zero code if either a time
* out occurred, or the status was not the expected one.
*/
static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
uint tick)
{
int control, status;
int timeout = 1000;
do {
control = readl(&twsi->control);
if (control & MVTWSI_CONTROL_IFLG) {
/*
* On Armada 38x it seems that the controller works as
* if it first set the MVTWSI_CONTROL_IFLAG in the
* control register and only after that it changed the
* status register.
* This sometimes caused weird bugs which only appeared
* on selected I2C speeds and even then only sometimes.
* We therefore add here a simple ndealy(100), which
* seems to fix this weird bug.
*/
ndelay(100);
status = readl(&twsi->status);
if (status == expected_status)
return 0;
else
return mvtwsi_error(
MVTWSI_ERROR_WRONG_STATUS,
control, status, expected_status);
}
ndelay(tick); /* One clock cycle */
} while (timeout--);
status = readl(&twsi->status);
return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
expected_status);
}
/*
* twsi_start() - Assert a START condition on the bus.
*
* This function is used in both single I2C transactions and inside
* back-to-back transactions (repeated starts).
*
* @twsi: The MVTWSI register structure to use.
* @expected_status: The I2C bus status expected to be asserted after the
* operation completion.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if status is as expected, or a non-zero code if either a time
* out occurred or the status was not the expected one.
*/
static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
uint tick)
{
/* Assert START */
writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* Wait for controller to process START */
return twsi_wait(twsi, expected_status, tick);
}
/*
* twsi_send() - Send a byte on the I2C bus.
*
* The byte may be part of an address byte or data.
*
* @twsi: The MVTWSI register structure to use.
* @byte: The byte to send.
* @expected_status: The I2C bus status expected to be asserted after the
* operation completion.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if status is as expected, or a non-zero code if either a time
* out occurred or the status was not the expected one.
*/
static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
int expected_status, uint tick)
{
/* Write byte to data register for sending */
writel(byte, &twsi->data);
/* Clear any pending interrupt -- that will cause sending */
writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
&twsi->control);
/* Wait for controller to receive byte, and check ACK */
return twsi_wait(twsi, expected_status, tick);
}
/*
* twsi_recv() - Receive a byte on the I2C bus.
*
* The static variable mvtwsi_control_flags controls whether we ack or nak.
*
* @twsi: The MVTWSI register structure to use.
* @byte: The byte to send.
* @ack_flag: Flag that determines whether the received byte should
* be acknowledged by the controller or not (sent ACK/NAK).
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if status is as expected, or a non-zero code if either a time
* out occurred or the status was not the expected one.
*/
static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
uint tick)
{
int expected_status, status, control;
/* Compute expected status based on passed ACK flag */
expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
MVTWSI_STATUS_DATA_R_NAK;
/* Acknowledge *previous state*, and launch receive */
control = MVTWSI_CONTROL_TWSIEN;
control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* Wait for controller to receive byte, and assert ACK or NAK */
status = twsi_wait(twsi, expected_status, tick);
/* If we did receive the expected byte, store it */
if (status == 0)
*byte = readl(&twsi->data);
return status;
}
/*
* twsi_stop() - Assert a STOP condition on the bus.
*
* This function is also used to force the bus back to idle state (SDA =
* SCL = 1).
*
* @twsi: The MVTWSI register structure to use.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if the operation succeeded, or a non-zero code if a time out
* occurred.
*/
static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
{
int control, stop_status;
int status = 0;
int timeout = 1000;
/* Assert STOP */
control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
do {
stop_status = readl(&twsi->status);
if (stop_status == MVTWSI_STATUS_IDLE)
break;
ndelay(tick); /* One clock cycle */
} while (timeout--);
control = readl(&twsi->control);
if (stop_status != MVTWSI_STATUS_IDLE)
status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
control, status, MVTWSI_STATUS_IDLE);
return status;
}
/*
* twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
*
* @n: Parameter 'n' for the frequency calculation algorithm.
* @m: Parameter 'm' for the frequency calculation algorithm.
* @return The I2C frequency corresponding to the passed m and n parameters.
*/
static uint twsi_calc_freq(const int n, const int m)
{
#ifdef CONFIG_ARCH_SUNXI
return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
#else
return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
#endif
}
/*
* twsi_reset() - Reset the I2C controller.
*
* Resetting the controller also resets the baud rate and slave address, hence
* they must be re-established after the reset.
*
* @twsi: The MVTWSI register structure to use.
*/
static void twsi_reset(struct mvtwsi_registers *twsi)
{
/* Reset controller */
writel(0, &twsi->soft_reset);
/* Wait 2 ms -- this is what the Marvell LSP does */
udelay(20000);
}
/*
* __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
*
* This function sets baud rate to the highest possible value that does not
* exceed the requested rate.
*
* @twsi: The MVTWSI register structure to use.
* @requested_speed: The desired frequency the controller should run at
* in Hz.
* @return The actual frequency the controller was configured to.
*/
static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
uint requested_speed)
{
uint tmp_speed, highest_speed, n, m;
uint baud = 0x44; /* Baud rate after controller reset */
highest_speed = 0;
/* Successively try m, n combinations, and use the combination
* resulting in the largest speed that's not above the requested
* speed */
for (n = 0; n < 8; n++) {
for (m = 0; m < 16; m++) {
tmp_speed = twsi_calc_freq(n, m);
if ((tmp_speed <= requested_speed) &&
(tmp_speed > highest_speed)) {
highest_speed = tmp_speed;
baud = (m << 3) | n;
}
}
}
writel(baud, &twsi->baudrate);
/* Wait for controller for one tick */
#ifdef CONFIG_DM_I2C
ndelay(calc_tick(highest_speed));
#else
ndelay(10000);
#endif
return highest_speed;
}
/*
* __twsi_i2c_init() - Initialize the I2C controller.
*
* @twsi: The MVTWSI register structure to use.
* @speed: The initial frequency the controller should run at
* in Hz.
* @slaveadd: The I2C address to be set for the I2C master.
* @actual_speed: A output parameter that receives the actual frequency
* in Hz the controller was set to by the function.
* @return Zero if the operation succeeded, or a non-zero code if a time out
* occurred.
*/
static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
int slaveadd, uint *actual_speed)
{
uint tmp_speed;
/* Reset controller */
twsi_reset(twsi);
/* Set speed */
tmp_speed = __twsi_i2c_set_bus_speed(twsi, speed);
if (actual_speed)
*actual_speed = tmp_speed;
/* Set slave address; even though we don't use it */
writel(slaveadd, &twsi->slave_address);
writel(0, &twsi->xtnd_slave_addr);
/* Assert STOP, but don't care for the result */
#ifdef CONFIG_DM_I2C
(void) twsi_stop(twsi, calc_tick(*actual_speed));
#else
(void) twsi_stop(twsi, 10000);
#endif
}
/*
* i2c_begin() - Start a I2C transaction.
*
* Begin a I2C transaction with a given expected start status and chip address.
* A START is asserted, and the address byte is sent to the I2C controller. The
* expected address status will be derived from the direction bit (bit 0) of
* the address byte.
*
* @twsi: The MVTWSI register structure to use.
* @expected_start_status: The I2C status the controller is expected to
* assert after the address byte was sent.
* @addr: The address byte to be sent.
* @tick: The duration of a clock cycle at the current
* I2C speed.
* @return Zero if the operation succeeded, or a non-zero code if a time out or
* unexpected I2C status occurred.
*/
static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
u8 addr, uint tick)
{
int status, expected_addr_status;
/* Compute the expected address status from the direction bit in
* the address byte */
if (addr & 1) /* Reading */
expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
else /* Writing */
expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
/* Assert START */
status = twsi_start(twsi, expected_start_status, tick);
/* Send out the address if the start went well */
if (status == 0)
status = twsi_send(twsi, addr, expected_addr_status, tick);
/* Return 0, or the status of the first failure */
return status;
}
/*
* __twsi_i2c_probe_chip() - Probe the given I2C chip address.
*
* This function begins a I2C read transaction, does a dummy read and NAKs; if
* the procedure succeeds, the chip is considered to be present.
*
* @twsi: The MVTWSI register structure to use.
* @chip: The chip address to probe.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if the operation succeeded, or a non-zero code if a time out or
* unexpected I2C status occurred.
*/
static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
uint tick)
{
u8 dummy_byte;
int status;
/* Begin i2c read */
status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
/* Dummy read was accepted: receive byte, but NAK it. */
if (status == 0)
status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
/* Stop transaction */
twsi_stop(twsi, tick);
/* Return 0, or the status of the first failure */
return status;
}
/*
* __twsi_i2c_read() - Read data from a I2C chip.
*
* This function begins a I2C write transaction, and transmits the address
* bytes; then begins a I2C read transaction, and receives the data bytes.
*
* NOTE: Some devices want a stop right before the second start, while some
* will choke if it is there. Since deciding this is not yet supported in
* higher level APIs, we need to make a decision here, and for the moment that
* will be a repeated start without a preceding stop.
*
* @twsi: The MVTWSI register structure to use.
* @chip: The chip address to read from.
* @addr: The address bytes to send.
* @alen: The length of the address bytes in bytes.
* @data: The buffer to receive the data read from the chip (has to have
* a size of at least 'length' bytes).
* @length: The amount of data to be read from the chip in bytes.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if the operation succeeded, or a non-zero code if a time out or
* unexpected I2C status occurred.
*/
static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
u8 *addr, int alen, uchar *data, int length,
uint tick)
{
int status = 0;
int stop_status;
int expected_start = MVTWSI_STATUS_START;
if (alen > 0) {
/* Begin i2c write to send the address bytes */
status = i2c_begin(twsi, expected_start, (chip << 1), tick);
/* Send address bytes */
while ((status == 0) && alen--)
status = twsi_send(twsi, addr[alen],
MVTWSI_STATUS_DATA_W_ACK, tick);
/* Send repeated STARTs after the initial START */
expected_start = MVTWSI_STATUS_REPEATED_START;
}
/* Begin i2c read to receive data bytes */
if (status == 0)
status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
/* Receive actual data bytes; set NAK if we if we have nothing more to
* read */
while ((status == 0) && length--)
status = twsi_recv(twsi, data++,
length > 0 ?
MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
/* Stop transaction */
stop_status = twsi_stop(twsi, tick);
/* Return 0, or the status of the first failure */
return status != 0 ? status : stop_status;
}
/*
* __twsi_i2c_write() - Send data to a I2C chip.
*
* This function begins a I2C write transaction, and transmits the address
* bytes; then begins a new I2C write transaction, and sends the data bytes.
*
* @twsi: The MVTWSI register structure to use.
* @chip: The chip address to read from.
* @addr: The address bytes to send.
* @alen: The length of the address bytes in bytes.
* @data: The buffer containing the data to be sent to the chip.
* @length: The length of data to be sent to the chip in bytes.
* @tick: The duration of a clock cycle at the current I2C speed.
* @return Zero if the operation succeeded, or a non-zero code if a time out or
* unexpected I2C status occurred.
*/
static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
u8 *addr, int alen, uchar *data, int length,
uint tick)
{
int status, stop_status;
/* Begin i2c write to send first the address bytes, then the
* data bytes */
status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
/* Send address bytes */
while ((status == 0) && (alen-- > 0))
status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
tick);
/* Send data bytes */
while ((status == 0) && (length-- > 0))
status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
tick);
/* Stop transaction */
stop_status = twsi_stop(twsi, tick);
/* Return 0, or the status of the first failure */
return status != 0 ? status : stop_status;
}
#ifndef CONFIG_DM_I2C
static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
int slaveadd)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
__twsi_i2c_init(twsi, speed, slaveadd, NULL);
}
static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
uint requested_speed)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
__twsi_i2c_set_bus_speed(twsi, requested_speed);
return 0;
}
static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
return __twsi_i2c_probe_chip(twsi, chip, 10000);
}
static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *data, int length)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
u8 addr_bytes[4];
addr_bytes[0] = (addr >> 0) & 0xFF;
addr_bytes[1] = (addr >> 8) & 0xFF;
addr_bytes[2] = (addr >> 16) & 0xFF;
addr_bytes[3] = (addr >> 24) & 0xFF;
return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
10000);
}
static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *data, int length)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
u8 addr_bytes[4];
addr_bytes[0] = (addr >> 0) & 0xFF;
addr_bytes[1] = (addr >> 8) & 0xFF;
addr_bytes[2] = (addr >> 16) & 0xFF;
addr_bytes[3] = (addr >> 24) & 0xFF;
return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
10000);
}
#ifdef CONFIG_I2C_MVTWSI_BASE0
U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE1
U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE2
U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE3
U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE4
U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE5
U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
#endif
#else /* CONFIG_DM_I2C */
static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
}
static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
dev->tick = calc_tick(dev->speed);
return 0;
}
static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
dev->base = devfdt_get_addr_ptr(bus);
if (!dev->base)
return -ENOMEM;
dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
"cell-index", -1);
dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
"u-boot,i2c-slave-addr", 0x0);
dev->speed = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
"clock-frequency", 100000);
return 0;
}
static void twsi_disable_i2c_slave(struct mvtwsi_registers *twsi)
{
clrbits_le32(&twsi->debug, BIT(18));
}
static int mvtwsi_i2c_bind(struct udevice *bus)
{
struct mvtwsi_registers *twsi = devfdt_get_addr_ptr(bus);
/* Disable the hidden slave in i2c0 of these platforms */
if ((IS_ENABLED(CONFIG_ARMADA_38X) || IS_ENABLED(CONFIG_KIRKWOOD))
&& bus->req_seq == 0)
twsi_disable_i2c_slave(twsi);
return 0;
}
static int mvtwsi_i2c_probe(struct udevice *bus)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
uint actual_speed;
__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
dev->speed = actual_speed;
dev->tick = calc_tick(dev->speed);
return 0;
}
static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data or offset/data combined) */
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len,
dev->tick);
else
return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len,
dev->tick);
}
static const struct dm_i2c_ops mvtwsi_i2c_ops = {
.xfer = mvtwsi_i2c_xfer,
.probe_chip = mvtwsi_i2c_probe_chip,
.set_bus_speed = mvtwsi_i2c_set_bus_speed,
};
static const struct udevice_id mvtwsi_i2c_ids[] = {
{ .compatible = "marvell,mv64xxx-i2c", },
{ .compatible = "marvell,mv78230-i2c", },
{ .compatible = "allwinner,sun6i-a31-i2c", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_mvtwsi) = {
.name = "i2c_mvtwsi",
.id = UCLASS_I2C,
.of_match = mvtwsi_i2c_ids,
.bind = mvtwsi_i2c_bind,
.probe = mvtwsi_i2c_probe,
.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
.ops = &mvtwsi_i2c_ops,
};
#endif /* CONFIG_DM_I2C */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2004-2010
* Texas Instruments, <www.ti.com>
*/
#ifndef _OMAP2PLUS_I2C_H_
#define _OMAP2PLUS_I2C_H_
/* I2C masks */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_GC_IE (1 << 5)
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_SBD (1 << 15) /* Single byte data */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_GC (1 << 5)
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Code Register (I2C_INTCODE): */
#define I2C_INTCODE_MASK 7
#define I2C_INTCODE_NONE 0
#define I2C_INTCODE_AL 1 /* Arbitration lost */
#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
#define I2C_INTCODE_ARDY 3 /* Register access ready */
#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
/* I2C Buffer Configuration Register (I2C_BUF): */
#define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */
#define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 15) /* I2C module enable */
#define I2C_CON_BE (1 << 14) /* Big endian mode */
#define I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
/* (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
/* I2C System Test Register (I2C_SYSTEST): */
#define I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define I2C_SYSTEST_FREE (1 << 14) /* Free running mode, on brkpoint) */
#define I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
#define I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
#define I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense input value */
#define I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive output value */
#define I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense input value */
#define I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive output value */
/* I2C System Status Register (I2C_SYSS): */
#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
#define I2C_SCLL_SCLL 0
#define I2C_SCLL_SCLL_M 0xFF
#define I2C_SCLL_HSSCLL 8
#define I2C_SCLH_HSSCLL_M 0xFF
#define I2C_SCLH_SCLH 0
#define I2C_SCLH_SCLH_M 0xFF
#define I2C_SCLH_HSSCLH 8
#define I2C_SCLH_HSSCLH_M 0xFF
#define OMAP_I2C_STANDARD 100000
#define OMAP_I2C_FAST_MODE 400000
#define OMAP_I2C_HIGH_SPEED 3400000
#define SYSTEM_CLOCK_12 12000000
#define SYSTEM_CLOCK_13 13000000
#define SYSTEM_CLOCK_192 19200000
#define SYSTEM_CLOCK_96 96000000
/* Use the reference value of 96MHz if not explicitly set by the board */
#ifndef I2C_IP_CLK
#define I2C_IP_CLK SYSTEM_CLOCK_96
#endif
/*
* The reference minimum clock for high speed is 19.2MHz.
* The linux 2.6.30 kernel uses this value.
* The reference minimum clock for fast mode is 9.6MHz
* The reference minimum clock for standard mode is 4MHz
* In TRM, the value of 12MHz is used.
*/
#ifndef I2C_INTERNAL_SAMPLING_CLK
#define I2C_INTERNAL_SAMPLING_CLK 19200000
#endif
/*
* The equation for the low and high time is
* tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
* thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
*
* If the duty cycle is 50%
*
* tlow = scll + scll_trim = sampling clock / (2 * speed)
* thigh = sclh + sclh_trim = sampling clock / (2 * speed)
*
* In TRM
* scll_trim = 7
* sclh_trim = 5
*
* The linux 4.9 kernel uses
* scll_trim = 7
* sclh_trim = 5
*
* These are the trim values for standard and fast speed
*/
#ifndef I2C_FASTSPEED_SCLL_TRIM
#define I2C_FASTSPEED_SCLL_TRIM 7
#endif
#ifndef I2C_FASTSPEED_SCLH_TRIM
#define I2C_FASTSPEED_SCLH_TRIM 5
#endif
/* These are the trim values for high speed */
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#define I2C_PSC_MAX 0x0f
#define I2C_PSC_MIN 0x00
#endif /* _OMAP24XX_I2C_H_ */
@@ -0,0 +1,373 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* drivers/i2c/rcar_i2c.c
*
* Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
*
* Clock configuration based on Linux i2c-rcar.c:
* Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
* Copyright (C) 2011-2015 Renesas Electronics Corporation
* Copyright (C) 2012-14 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#include <asm/io.h>
#include <wait_bit.h>
#define RCAR_I2C_ICSCR 0x00 /* slave ctrl */
#define RCAR_I2C_ICMCR 0x04 /* master ctrl */
#define RCAR_I2C_ICMCR_MDBS BIT(7) /* non-fifo mode switch */
#define RCAR_I2C_ICMCR_FSCL BIT(6) /* override SCL pin */
#define RCAR_I2C_ICMCR_FSDA BIT(5) /* override SDA pin */
#define RCAR_I2C_ICMCR_OBPC BIT(4) /* override pins */
#define RCAR_I2C_ICMCR_MIE BIT(3) /* master if enable */
#define RCAR_I2C_ICMCR_TSBE BIT(2)
#define RCAR_I2C_ICMCR_FSB BIT(1) /* force stop bit */
#define RCAR_I2C_ICMCR_ESG BIT(0) /* enable start bit gen */
#define RCAR_I2C_ICSSR 0x08 /* slave status */
#define RCAR_I2C_ICMSR 0x0c /* master status */
#define RCAR_I2C_ICMSR_MASK 0x7f
#define RCAR_I2C_ICMSR_MNR BIT(6) /* Nack */
#define RCAR_I2C_ICMSR_MAL BIT(5) /* Arbitration lost */
#define RCAR_I2C_ICMSR_MST BIT(4) /* Stop */
#define RCAR_I2C_ICMSR_MDE BIT(3)
#define RCAR_I2C_ICMSR_MDT BIT(2)
#define RCAR_I2C_ICMSR_MDR BIT(1)
#define RCAR_I2C_ICMSR_MAT BIT(0)
#define RCAR_I2C_ICSIER 0x10 /* slave irq enable */
#define RCAR_I2C_ICMIER 0x14 /* master irq enable */
#define RCAR_I2C_ICCCR 0x18 /* clock dividers */
#define RCAR_I2C_ICCCR_SCGD_OFF 3
#define RCAR_I2C_ICSAR 0x1c /* slave address */
#define RCAR_I2C_ICMAR 0x20 /* master address */
#define RCAR_I2C_ICRXD_ICTXD 0x24 /* data port */
/*
* First Bit Setup Cycle (Gen3).
* Defines 1st bit delay between SDA and SCL.
*/
#define RCAR_I2C_ICFBSCR 0x38
#define RCAR_I2C_ICFBSCR_TCYC17 0x0f /* 17*Tcyc */
enum rcar_i2c_type {
RCAR_I2C_TYPE_GEN2,
RCAR_I2C_TYPE_GEN3,
};
struct rcar_i2c_priv {
void __iomem *base;
struct clk clk;
u32 intdelay;
u32 icccr;
enum rcar_i2c_type type;
};
static int rcar_i2c_finish(struct udevice *dev)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
int ret;
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, RCAR_I2C_ICMSR_MST,
true, 10, true);
writel(0, priv->base + RCAR_I2C_ICSSR);
writel(0, priv->base + RCAR_I2C_ICMSR);
writel(0, priv->base + RCAR_I2C_ICMCR);
return ret;
}
static int rcar_i2c_recover(struct udevice *dev)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
u32 mcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_OBPC;
u32 mcra = mcr | RCAR_I2C_ICMCR_FSDA;
int i;
u32 mstat;
/* Send 9 SCL pulses */
for (i = 0; i < 9; i++) {
writel(mcra | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
udelay(5);
writel(mcra, priv->base + RCAR_I2C_ICMCR);
udelay(5);
}
/* Send stop condition */
udelay(5);
writel(mcra, priv->base + RCAR_I2C_ICMCR);
udelay(5);
writel(mcr, priv->base + RCAR_I2C_ICMCR);
udelay(5);
writel(mcr | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
udelay(5);
writel(mcra | RCAR_I2C_ICMCR_FSCL, priv->base + RCAR_I2C_ICMCR);
udelay(5);
mstat = readl(priv->base + RCAR_I2C_ICMSR);
return mstat & RCAR_I2C_ICMCR_FSDA ? -EBUSY : 0;
}
static int rcar_i2c_set_addr(struct udevice *dev, u8 chip, u8 read)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
u32 mask = RCAR_I2C_ICMSR_MAT |
(read ? RCAR_I2C_ICMSR_MDR : RCAR_I2C_ICMSR_MDE);
int ret;
writel(0, priv->base + RCAR_I2C_ICMIER);
writel(RCAR_I2C_ICMCR_MDBS, priv->base + RCAR_I2C_ICMCR);
writel(0, priv->base + RCAR_I2C_ICMSR);
writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
/* Wait for the bus */
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMCR,
RCAR_I2C_ICMCR_FSDA, false, 2, true);
if (ret) {
if (rcar_i2c_recover(dev)) {
dev_err(dev, "Bus busy, aborting\n");
return ret;
}
}
writel((chip << 1) | read, priv->base + RCAR_I2C_ICMAR);
/* Reset */
writel(RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE | RCAR_I2C_ICMCR_ESG,
priv->base + RCAR_I2C_ICMCR);
/* Clear Status */
writel(0, priv->base + RCAR_I2C_ICMSR);
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR, mask,
true, 100, true);
if (ret)
return ret;
/* Check NAK */
if (readl(priv->base + RCAR_I2C_ICMSR) & RCAR_I2C_ICMSR_MNR)
return -EREMOTEIO;
return 0;
}
static int rcar_i2c_read_common(struct udevice *dev, struct i2c_msg *msg)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE;
int i, ret = -EREMOTEIO;
for (i = 0; i < msg->len; i++) {
if (msg->len - 1 == i)
icmcr |= RCAR_I2C_ICMCR_FSB;
writel(icmcr, priv->base + RCAR_I2C_ICMCR);
writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR);
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR,
RCAR_I2C_ICMSR_MDR, true, 100, true);
if (ret)
return ret;
msg->buf[i] = readl(priv->base + RCAR_I2C_ICRXD_ICTXD) & 0xff;
}
writel((u32)~RCAR_I2C_ICMSR_MDR, priv->base + RCAR_I2C_ICMSR);
return rcar_i2c_finish(dev);
}
static int rcar_i2c_write_common(struct udevice *dev, struct i2c_msg *msg)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
u32 icmcr = RCAR_I2C_ICMCR_MDBS | RCAR_I2C_ICMCR_MIE;
int i, ret = -EREMOTEIO;
for (i = 0; i < msg->len; i++) {
writel(msg->buf[i], priv->base + RCAR_I2C_ICRXD_ICTXD);
writel(icmcr, priv->base + RCAR_I2C_ICMCR);
writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR);
ret = wait_for_bit_le32(priv->base + RCAR_I2C_ICMSR,
RCAR_I2C_ICMSR_MDE, true, 100, true);
if (ret)
return ret;
}
writel((u32)~RCAR_I2C_ICMSR_MDE, priv->base + RCAR_I2C_ICMSR);
icmcr |= RCAR_I2C_ICMCR_FSB;
writel(icmcr, priv->base + RCAR_I2C_ICMCR);
return rcar_i2c_finish(dev);
}
static int rcar_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
ret = rcar_i2c_set_addr(dev, msg->addr, 1);
if (ret)
return ret;
if (msg->flags & I2C_M_RD)
ret = rcar_i2c_read_common(dev, msg);
else
ret = rcar_i2c_write_common(dev, msg);
if (ret)
return ret;
}
return 0;
}
static int rcar_i2c_probe_chip(struct udevice *dev, uint addr, uint flags)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
int ret;
/* Ignore address 0, slave address */
if (addr == 0)
return -EINVAL;
ret = rcar_i2c_set_addr(dev, addr, 1);
writel(0, priv->base + RCAR_I2C_ICMSR);
return ret;
}
static int rcar_i2c_set_speed(struct udevice *dev, uint bus_freq_hz)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
u32 scgd, cdf, round, ick, sum, scl;
unsigned long rate;
/*
* calculate SCL clock
* see
* ICCCR
*
* ick = clkp / (1 + CDF)
* SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
*
* ick : I2C internal clock < 20 MHz
* ticf : I2C SCL falling time
* tr : I2C SCL rising time
* intd : LSI internal delay
* clkp : peripheral_clk
* F[] : integer up-valuation
*/
rate = clk_get_rate(&priv->clk);
cdf = rate / 20000000;
if (cdf >= 8) {
dev_err(dev, "Input clock %lu too high\n", rate);
return -EIO;
}
ick = rate / (cdf + 1);
/*
* it is impossible to calculate large scale
* number on u32. separate it
*
* F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd)
* = F[sum * ick / 1000000000]
* = F[(ick / 1000000) * sum / 1000]
*/
sum = 35 + 200 + priv->intdelay;
round = (ick + 500000) / 1000000 * sum;
round = (round + 500) / 1000;
/*
* SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
*
* Calculation result (= SCL) should be less than
* bus_speed for hardware safety
*
* We could use something along the lines of
* div = ick / (bus_speed + 1) + 1;
* scgd = (div - 20 - round + 7) / 8;
* scl = ick / (20 + (scgd * 8) + round);
* (not fully verified) but that would get pretty involved
*/
for (scgd = 0; scgd < 0x40; scgd++) {
scl = ick / (20 + (scgd * 8) + round);
if (scl <= bus_freq_hz)
goto scgd_find;
}
dev_err(dev, "it is impossible to calculate best SCL\n");
return -EIO;
scgd_find:
dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
scl, bus_freq_hz, clk_get_rate(&priv->clk), round, cdf, scgd);
priv->icccr = (scgd << RCAR_I2C_ICCCR_SCGD_OFF) | cdf;
writel(priv->icccr, priv->base + RCAR_I2C_ICCCR);
if (priv->type == RCAR_I2C_TYPE_GEN3) {
/* Set SCL/SDA delay */
writel(RCAR_I2C_ICFBSCR_TCYC17, priv->base + RCAR_I2C_ICFBSCR);
}
return 0;
}
static int rcar_i2c_probe(struct udevice *dev)
{
struct rcar_i2c_priv *priv = dev_get_priv(dev);
int ret;
priv->base = dev_read_addr_ptr(dev);
priv->intdelay = dev_read_u32_default(dev,
"i2c-scl-internal-delay-ns", 5);
priv->type = dev_get_driver_data(dev);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)
return ret;
ret = clk_enable(&priv->clk);
if (ret)
return ret;
/* reset slave mode */
writel(0, priv->base + RCAR_I2C_ICSIER);
writel(0, priv->base + RCAR_I2C_ICSAR);
writel(0, priv->base + RCAR_I2C_ICSCR);
writel(0, priv->base + RCAR_I2C_ICSSR);
/* reset master mode */
writel(0, priv->base + RCAR_I2C_ICMIER);
writel(0, priv->base + RCAR_I2C_ICMCR);
writel(0, priv->base + RCAR_I2C_ICMSR);
writel(0, priv->base + RCAR_I2C_ICMAR);
ret = rcar_i2c_set_speed(dev, 100000);
if (ret)
clk_disable(&priv->clk);
return ret;
}
static const struct dm_i2c_ops rcar_i2c_ops = {
.xfer = rcar_i2c_xfer,
.probe_chip = rcar_i2c_probe_chip,
.set_bus_speed = rcar_i2c_set_speed,
};
static const struct udevice_id rcar_i2c_ids[] = {
{ .compatible = "renesas,rcar-gen2-i2c", .data = RCAR_I2C_TYPE_GEN2 },
{ .compatible = "renesas,rcar-gen3-i2c", .data = RCAR_I2C_TYPE_GEN3 },
{ }
};
U_BOOT_DRIVER(i2c_rcar) = {
.name = "i2c_rcar",
.id = UCLASS_I2C,
.of_match = rcar_i2c_ids,
.probe = rcar_i2c_probe,
.priv_auto_alloc_size = sizeof(struct rcar_i2c_priv),
.ops = &rcar_i2c_ops,
};
@@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Renesas RCar IIC driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
*
* Based on
* Copyright (C) 2011, 2013 Renesas Solutions Corp.
* Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#include <asm/io.h>
struct rcar_iic_priv {
void __iomem *base;
struct clk clk;
u8 iccl;
u8 icch;
};
#define RCAR_IIC_ICDR 0x00
#define RCAR_IIC_ICCR 0x04
#define RCAR_IIC_ICSR 0x08
#define RCAR_IIC_ICIC 0x0c
#define RCAR_IIC_ICCL 0x10
#define RCAR_IIC_ICCH 0x14
/* ICCR */
#define RCAR_IIC_ICCR_ICE BIT(7)
#define RCAR_IIC_ICCR_RACK BIT(6)
#define RCAR_IIC_ICCR_RTS BIT(4)
#define RCAR_IIC_ICCR_BUSY BIT(2)
#define RCAR_IIC_ICCR_SCP BIT(0)
/* ICSR / ICIC */
#define RCAR_IC_BUSY BIT(4)
#define RCAR_IC_TACK BIT(2)
#define RCAR_IC_DTE BIT(0)
#define IRQ_WAIT 1000
static void sh_irq_dte(struct udevice *dev)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (RCAR_IC_DTE & readb(priv->base + RCAR_IIC_ICSR))
break;
udelay(10);
}
}
static int sh_irq_dte_with_tack(struct udevice *dev)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
u8 icsr;
int i;
for (i = 0; i < IRQ_WAIT; i++) {
icsr = readb(priv->base + RCAR_IIC_ICSR);
if (RCAR_IC_DTE & icsr)
break;
if (RCAR_IC_TACK & icsr)
return -ETIMEDOUT;
udelay(10);
}
return 0;
}
static void sh_irq_busy(struct udevice *dev)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (!(RCAR_IC_BUSY & readb(priv->base + RCAR_IIC_ICSR)))
break;
udelay(10);
}
}
static int rcar_iic_set_addr(struct udevice *dev, u8 chip, u8 read)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
setbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
writeb(priv->iccl, priv->base + RCAR_IIC_ICCL);
writeb(priv->icch, priv->base + RCAR_IIC_ICCH);
writeb(RCAR_IC_TACK, priv->base + RCAR_IIC_ICIC);
writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS | RCAR_IIC_ICCR_BUSY,
priv->base + RCAR_IIC_ICCR);
sh_irq_dte(dev);
clrbits_8(priv->base + RCAR_IIC_ICSR, RCAR_IC_TACK);
writeb(chip << 1 | read, priv->base + RCAR_IIC_ICDR);
return sh_irq_dte_with_tack(dev);
}
static void rcar_iic_finish(struct udevice *dev)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
writeb(0, priv->base + RCAR_IIC_ICSR);
clrbits_8(priv->base + RCAR_IIC_ICCR, RCAR_IIC_ICCR_ICE);
}
static int rcar_iic_read_common(struct udevice *dev, struct i2c_msg *msg)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int i, ret = -EREMOTEIO;
if (rcar_iic_set_addr(dev, msg->addr, 1) != 0)
goto err;
udelay(10);
writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
priv->base + RCAR_IIC_ICCR);
for (i = 0; i < msg->len; i++) {
if (sh_irq_dte_with_tack(dev) != 0)
goto err;
msg->buf[i] = readb(priv->base + RCAR_IIC_ICDR) & 0xff;
if (msg->len - 1 == i) {
writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RACK,
priv->base + RCAR_IIC_ICCR);
}
}
sh_irq_busy(dev);
ret = 0;
err:
rcar_iic_finish(dev);
return ret;
}
static int rcar_iic_write_common(struct udevice *dev, struct i2c_msg *msg)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int i, ret = -EREMOTEIO;
if (rcar_iic_set_addr(dev, msg->addr, 0) != 0)
goto err;
udelay(10);
for (i = 0; i < msg->len; i++) {
writeb(msg->buf[i], priv->base + RCAR_IIC_ICDR);
if (sh_irq_dte_with_tack(dev) != 0)
goto err;
}
if (msg->flags & I2C_M_STOP) {
writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_RTS,
priv->base + RCAR_IIC_ICCR);
if (sh_irq_dte_with_tack(dev) != 0)
goto err;
}
sh_irq_busy(dev);
ret = 0;
err:
rcar_iic_finish(dev);
return ret;
}
static int rcar_iic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD)
ret = rcar_iic_read_common(dev, msg);
else
ret = rcar_iic_write_common(dev, msg);
if (ret)
return -EREMOTEIO;
}
return ret;
}
static int rcar_iic_set_speed(struct udevice *dev, uint speed)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
const unsigned int ratio_high = 4;
const unsigned int ratio_low = 5;
int clkrate, denom;
clkrate = clk_get_rate(&priv->clk);
if (clkrate < 0)
return clkrate;
/*
* Calculate the value for ICCL and ICCH. From the data sheet:
* iccl = (p-clock / transfer-rate) * (L / (L + H))
* icch = (p clock / transfer rate) * (H / (L + H))
* where L and H are the SCL low and high ratio.
*/
denom = speed * (ratio_high + ratio_low);
priv->iccl = DIV_ROUND_CLOSEST(clkrate * ratio_low, denom);
priv->icch = DIV_ROUND_CLOSEST(clkrate * ratio_high, denom);
return 0;
}
static int rcar_iic_probe_chip(struct udevice *dev, uint addr, uint flags)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int ret;
rcar_iic_set_addr(dev, addr, 1);
writeb(RCAR_IIC_ICCR_ICE | RCAR_IIC_ICCR_SCP,
priv->base + RCAR_IIC_ICCR);
ret = sh_irq_dte_with_tack(dev);
rcar_iic_finish(dev);
return ret;
}
static int rcar_iic_probe(struct udevice *dev)
{
struct rcar_iic_priv *priv = dev_get_priv(dev);
int ret;
priv->base = dev_read_addr_ptr(dev);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)
return ret;
ret = clk_enable(&priv->clk);
if (ret)
return ret;
rcar_iic_finish(dev);
return rcar_iic_set_speed(dev, 100000);
}
static const struct dm_i2c_ops rcar_iic_ops = {
.xfer = rcar_iic_xfer,
.probe_chip = rcar_iic_probe_chip,
.set_bus_speed = rcar_iic_set_speed,
};
static const struct udevice_id rcar_iic_ids[] = {
{ .compatible = "renesas,rmobile-iic" },
{ }
};
U_BOOT_DRIVER(iic_rcar) = {
.name = "iic_rcar",
.id = UCLASS_I2C,
.of_match = rcar_iic_ids,
.probe = rcar_iic_probe,
.priv_auto_alloc_size = sizeof(struct rcar_iic_priv),
.ops = &rcar_iic_ops,
};
@@ -0,0 +1,494 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015 Google, Inc
*
* (C) Copyright 2008-2014 Rockchip Electronics
* Peter, Software Engineering, <superpeter.cai@gmail.com>.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/i2c.h>
#include <asm/arch-rockchip/periph.h>
#include <dm/pinctrl.h>
#include <linux/sizes.h>
/* i2c timerout */
#define I2C_TIMEOUT_MS 100
#define I2C_RETRY_COUNT 3
/* rk i2c fifo max transfer bytes */
#define RK_I2C_FIFO_SIZE 32
struct rk_i2c {
struct clk clk;
struct i2c_regs *regs;
unsigned int speed;
};
enum {
RK_I2C_LEGACY,
RK_I2C_NEW,
};
/**
* @controller_type: i2c controller type
*/
struct rk_i2c_soc_data {
int controller_type;
};
static inline void rk_i2c_get_div(int div, int *divh, int *divl)
{
*divl = div / 2;
if (div % 2 == 0)
*divh = div / 2;
else
*divh = DIV_ROUND_UP(div, 2);
}
/*
* SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
* SCL = PCLK / SCLK Divisor
* i2c_rate = PCLK
*/
static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
{
uint32_t i2c_rate;
int div, divl, divh;
/* First get i2c rate from pclk */
i2c_rate = clk_get_rate(&i2c->clk);
div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
divh = 0;
divl = 0;
if (div >= 0)
rk_i2c_get_div(div, &divh, &divl);
writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
debug("rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
scl_rate);
debug("set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
debug("set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
}
static void rk_i2c_show_regs(struct i2c_regs *regs)
{
#ifdef DEBUG
uint i;
debug("i2c_con: 0x%08x\n", readl(&regs->con));
debug("i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
debug("i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
debug("i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
debug("i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
debug("i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
debug("i2c_ien: 0x%08x\n", readl(&regs->ien));
debug("i2c_ipd: 0x%08x\n", readl(&regs->ipd));
debug("i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
for (i = 0; i < 8; i++)
debug("i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
for (i = 0; i < 8; i++)
debug("i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
#endif
}
static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
{
struct i2c_regs *regs = i2c->regs;
ulong start;
debug("I2c Send Start bit.\n");
writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
writel(I2C_CON_EN | I2C_CON_START, &regs->con);
writel(I2C_STARTIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_STARTIPD) {
writel(I2C_STARTIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Send Start Bit Timeout\n");
rk_i2c_show_regs(regs);
return -ETIMEDOUT;
}
udelay(1);
}
return 0;
}
static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
{
struct i2c_regs *regs = i2c->regs;
ulong start;
debug("I2c Send Stop bit.\n");
writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
writel(I2C_CON_STOP, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_STOPIPD) {
writel(I2C_STOPIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Send Start Bit Timeout\n");
rk_i2c_show_regs(regs);
return -ETIMEDOUT;
}
udelay(1);
}
return 0;
}
static inline void rk_i2c_disable(struct rk_i2c *i2c)
{
writel(0, &i2c->regs->con);
}
static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
struct i2c_regs *regs = i2c->regs;
uchar *pbuf = buf;
uint bytes_remain_len = b_len;
uint bytes_xferred = 0;
uint words_xferred = 0;
ulong start;
uint con = 0;
uint rxdata;
uint i, j;
int err;
bool snd_chunk = false;
debug("rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
chip, reg, r_len, b_len);
err = rk_i2c_send_start_bit(i2c);
if (err)
return err;
writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
if (r_len == 0) {
writel(0, &regs->mrxraddr);
} else if (r_len < 4) {
writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
} else {
debug("I2C Read: addr len %d not supported\n", r_len);
return -EIO;
}
while (bytes_remain_len) {
if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
con = I2C_CON_EN;
bytes_xferred = 32;
} else {
/*
* The hw can read up to 32 bytes at a time. If we need
* more than one chunk, send an ACK after the last byte.
*/
con = I2C_CON_EN | I2C_CON_LASTACK;
bytes_xferred = bytes_remain_len;
}
words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
/*
* make sure we are in plain RX mode if we read a second chunk
*/
if (snd_chunk)
con |= I2C_CON_MOD(I2C_MODE_RX);
else
con |= I2C_CON_MOD(I2C_MODE_TRX);
writel(con, &regs->con);
writel(bytes_xferred, &regs->mrxcnt);
writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
writel(I2C_NAKRCVIPD, &regs->ipd);
err = -EREMOTEIO;
}
if (readl(&regs->ipd) & I2C_MBRFIPD) {
writel(I2C_MBRFIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Read Data Timeout\n");
err = -ETIMEDOUT;
rk_i2c_show_regs(regs);
goto i2c_exit;
}
udelay(1);
}
for (i = 0; i < words_xferred; i++) {
rxdata = readl(&regs->rxdata[i]);
debug("I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
for (j = 0; j < 4; j++) {
if ((i * 4 + j) == bytes_xferred)
break;
*pbuf++ = (rxdata >> (j * 8)) & 0xff;
}
}
bytes_remain_len -= bytes_xferred;
snd_chunk = true;
debug("I2C Read bytes_remain_len %d\n", bytes_remain_len);
}
i2c_exit:
rk_i2c_disable(i2c);
return err;
}
static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
struct i2c_regs *regs = i2c->regs;
int err;
uchar *pbuf = buf;
uint bytes_remain_len = b_len + r_len + 1;
uint bytes_xferred = 0;
uint words_xferred = 0;
ulong start;
uint txdata;
uint i, j;
debug("rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
chip, reg, r_len, b_len);
err = rk_i2c_send_start_bit(i2c);
if (err)
return err;
while (bytes_remain_len) {
if (bytes_remain_len > RK_I2C_FIFO_SIZE)
bytes_xferred = RK_I2C_FIFO_SIZE;
else
bytes_xferred = bytes_remain_len;
words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
for (i = 0; i < words_xferred; i++) {
txdata = 0;
for (j = 0; j < 4; j++) {
if ((i * 4 + j) == bytes_xferred)
break;
if (i == 0 && j == 0 && pbuf == buf) {
txdata |= (chip << 1);
} else if (i == 0 && j <= r_len && pbuf == buf) {
txdata |= (reg &
(0xff << ((j - 1) * 8))) << 8;
} else {
txdata |= (*pbuf++)<<(j * 8);
}
}
writel(txdata, &regs->txdata[i]);
debug("I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
}
writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
writel(bytes_xferred, &regs->mtxcnt);
writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
writel(I2C_NAKRCVIPD, &regs->ipd);
err = -EREMOTEIO;
}
if (readl(&regs->ipd) & I2C_MBTFIPD) {
writel(I2C_MBTFIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Write Data Timeout\n");
err = -ETIMEDOUT;
rk_i2c_show_regs(regs);
goto i2c_exit;
}
udelay(1);
}
bytes_remain_len -= bytes_xferred;
debug("I2C Write bytes_remain_len %d\n", bytes_remain_len);
}
i2c_exit:
rk_i2c_disable(i2c);
return err;
}
static int rockchip_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct rk_i2c *i2c = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
msg->len);
} else {
ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
msg->len);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
rk_i2c_send_stop_bit(i2c);
rk_i2c_disable(i2c);
return 0;
}
int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct rk_i2c *i2c = dev_get_priv(bus);
rk_i2c_set_clk(i2c, speed);
return 0;
}
static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct rk_i2c *priv = dev_get_priv(bus);
int ret;
ret = clk_get_by_index(bus, 0, &priv->clk);
if (ret < 0) {
debug("%s: Could not get clock for %s: %d\n", __func__,
bus->name, ret);
return ret;
}
return 0;
}
static int rockchip_i2c_probe(struct udevice *bus)
{
struct rk_i2c *priv = dev_get_priv(bus);
struct rk_i2c_soc_data *soc_data;
struct udevice *pinctrl;
int bus_nr;
int ret;
priv->regs = dev_read_addr_ptr(bus);
soc_data = (struct rk_i2c_soc_data*)dev_get_driver_data(bus);
if (soc_data->controller_type == RK_I2C_LEGACY) {
ret = dev_read_alias_seq(bus, &bus_nr);
if (ret < 0) {
debug("%s: Could not get alias for %s: %d\n",
__func__, bus->name, ret);
return ret;
}
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
if (ret) {
debug("%s: Cannot find pinctrl device\n", __func__);
return ret;
}
/* pinctrl will switch I2C to new type */
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_I2C0 + bus_nr);
if (ret) {
debug("%s: Failed to switch I2C to new type %s: %d\n",
__func__, bus->name, ret);
return ret;
}
}
return 0;
}
static const struct dm_i2c_ops rockchip_i2c_ops = {
.xfer = rockchip_i2c_xfer,
.set_bus_speed = rockchip_i2c_set_bus_speed,
};
static const struct rk_i2c_soc_data rk3066_soc_data = {
.controller_type = RK_I2C_LEGACY,
};
static const struct rk_i2c_soc_data rk3188_soc_data = {
.controller_type = RK_I2C_LEGACY,
};
static const struct rk_i2c_soc_data rk3228_soc_data = {
.controller_type = RK_I2C_NEW,
};
static const struct rk_i2c_soc_data rk3288_soc_data = {
.controller_type = RK_I2C_NEW,
};
static const struct rk_i2c_soc_data rk3328_soc_data = {
.controller_type = RK_I2C_NEW,
};
static const struct rk_i2c_soc_data rk3399_soc_data = {
.controller_type = RK_I2C_NEW,
};
static const struct udevice_id rockchip_i2c_ids[] = {
{
.compatible = "rockchip,rk3066-i2c",
.data = (ulong)&rk3066_soc_data,
},
{
.compatible = "rockchip,rk3188-i2c",
.data = (ulong)&rk3188_soc_data,
},
{
.compatible = "rockchip,rk3228-i2c",
.data = (ulong)&rk3228_soc_data,
},
{
.compatible = "rockchip,rk3288-i2c",
.data = (ulong)&rk3288_soc_data,
},
{
.compatible = "rockchip,rk3328-i2c",
.data = (ulong)&rk3328_soc_data,
},
{
.compatible = "rockchip,rk3399-i2c",
.data = (ulong)&rk3399_soc_data,
},
{ }
};
U_BOOT_DRIVER(i2c_rockchip) = {
.name = "i2c_rockchip",
.id = UCLASS_I2C,
.of_match = rockchip_i2c_ids,
.ofdata_to_platdata = rockchip_i2c_ofdata_to_platdata,
.probe = rockchip_i2c_probe,
.priv_auto_alloc_size = sizeof(struct rk_i2c),
.ops = &rockchip_i2c_ops,
};
@@ -0,0 +1,346 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
*/
#include <common.h>
#include <errno.h>
#include <dm.h>
#include <fdtdec.h>
#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
#include <asm/arch/clk.h>
#include <asm/arch/cpu.h>
#include <asm/arch/pinmux.h>
#else
#include <asm/arch/s3c24x0_cpu.h>
#endif
#include <asm/io.h>
#include <i2c.h>
#include "s3c24x0_i2c.h"
#ifndef CONFIG_SYS_I2C_S3C24X0_SLAVE
#define SYS_I2C_S3C24X0_SLAVE_ADDR 0
#else
#define SYS_I2C_S3C24X0_SLAVE_ADDR CONFIG_SYS_I2C_S3C24X0_SLAVE
#endif
DECLARE_GLOBAL_DATA_PTR;
/*
* Wait til the byte transfer is completed.
*
* @param i2c- pointer to the appropriate i2c register bank.
* @return I2C_OK, if transmission was ACKED
* I2C_NACK, if transmission was NACKED
* I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS
*/
static int WaitForXfer(struct s3c24x0_i2c *i2c)
{
ulong start_time = get_timer(0);
do {
if (readl(&i2c->iiccon) & I2CCON_IRPND)
return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
I2C_NACK : I2C_OK;
} while (get_timer(start_time) < I2C_TIMEOUT_MS);
return I2C_NOK_TOUT;
}
static void read_write_byte(struct s3c24x0_i2c *i2c)
{
clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
}
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
{
ulong freq, pres = 16, div;
#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
freq = get_i2c_clk();
#else
freq = get_PCLK();
#endif
/* calculate prescaler and divisor values */
if ((freq / pres / (16 + 1)) > speed)
/* set prescaler to 512 */
pres = 512;
div = 0;
while ((freq / pres / (div + 1)) > speed)
div++;
/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
/* init to SLAVE REVEIVE and set slaveaddr */
writel(0, &i2c->iicstat);
writel(slaveadd, &i2c->iicadd);
/* program Master Transmit (and implicit STOP) */
writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
}
static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->clock_frequency = speed;
i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
SYS_I2C_S3C24X0_SLAVE_ADDR);
return 0;
}
/*
* cmd_type is 0 for write, 1 for read.
*
* addr_len can take any value from 0-255, it is only limited
* by the char, we could make it larger if needed. If it is
* 0 we skip the address write cycle.
*/
static int i2c_transfer(struct s3c24x0_i2c *i2c,
unsigned char cmd_type,
unsigned char chip,
unsigned char addr[],
unsigned char addr_len,
unsigned char data[],
unsigned short data_len)
{
int i = 0, result;
ulong start_time = get_timer(0);
if (data == 0 || data_len == 0) {
/*Don't support data transfer of no length or to address 0 */
debug("i2c_transfer: bad call\n");
return I2C_NOK;
}
while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
if (get_timer(start_time) > I2C_TIMEOUT_MS)
return I2C_NOK_TOUT;
}
writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
/* Get the slave chip address going */
writel(chip, &i2c->iicds);
if ((cmd_type == I2C_WRITE) || (addr && addr_len))
writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
else
writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
/* Wait for chip address to transmit. */
result = WaitForXfer(i2c);
if (result != I2C_OK)
goto bailout;
/* If register address needs to be transmitted - do it now. */
if (addr && addr_len) {
while ((i < addr_len) && (result == I2C_OK)) {
writel(addr[i++], &i2c->iicds);
read_write_byte(i2c);
result = WaitForXfer(i2c);
}
i = 0;
if (result != I2C_OK)
goto bailout;
}
switch (cmd_type) {
case I2C_WRITE:
while ((i < data_len) && (result == I2C_OK)) {
writel(data[i++], &i2c->iicds);
read_write_byte(i2c);
result = WaitForXfer(i2c);
}
break;
case I2C_READ:
if (addr && addr_len) {
/*
* Register address has been sent, now send slave chip
* address again to start the actual read transaction.
*/
writel(chip, &i2c->iicds);
/* Generate a re-START. */
writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
read_write_byte(i2c);
result = WaitForXfer(i2c);
if (result != I2C_OK)
goto bailout;
}
while ((i < data_len) && (result == I2C_OK)) {
/* disable ACK for final READ */
if (i == data_len - 1)
writel(readl(&i2c->iiccon)
& ~I2CCON_ACKGEN,
&i2c->iiccon);
read_write_byte(i2c);
result = WaitForXfer(i2c);
data[i++] = readl(&i2c->iicds);
}
if (result == I2C_NACK)
result = I2C_OK; /* Normal terminated read. */
break;
default:
debug("i2c_transfer: bad call\n");
result = I2C_NOK;
break;
}
bailout:
/* Send STOP. */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
read_write_byte(i2c);
return result;
}
static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
uchar buf[1];
int ret;
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
return ret != I2C_OK;
}
static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
int seq)
{
struct s3c24x0_i2c *i2c = i2c_bus->regs;
bool is_read = msg->flags & I2C_M_RD;
uint status;
uint addr;
int ret, i;
if (!seq)
setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
/* Get the slave chip address going */
addr = msg->addr << 1;
writel(addr, &i2c->iicds);
status = I2C_TXRX_ENA | I2C_START_STOP;
if (is_read)
status |= I2C_MODE_MR;
else
status |= I2C_MODE_MT;
writel(status, &i2c->iicstat);
if (seq)
read_write_byte(i2c);
/* Wait for chip address to transmit */
ret = WaitForXfer(i2c);
if (ret)
goto err;
if (is_read) {
for (i = 0; !ret && i < msg->len; i++) {
/* disable ACK for final READ */
if (i == msg->len - 1)
clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
read_write_byte(i2c);
ret = WaitForXfer(i2c);
msg->buf[i] = readl(&i2c->iicds);
}
if (ret == I2C_NACK)
ret = I2C_OK; /* Normal terminated read */
} else {
for (i = 0; !ret && i < msg->len; i++) {
writel(msg->buf[i], &i2c->iicds);
read_write_byte(i2c);
ret = WaitForXfer(i2c);
}
}
err:
return ret;
}
static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
struct s3c24x0_i2c *i2c = i2c_bus->regs;
ulong start_time;
int ret, i;
start_time = get_timer(0);
while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
if (get_timer(start_time) > I2C_TIMEOUT_MS) {
debug("Timeout\n");
return -ETIMEDOUT;
}
}
for (ret = 0, i = 0; !ret && i < nmsgs; i++)
ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
/* Send STOP */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
read_write_byte(i2c);
return ret ? -EREMOTEIO : 0;
}
static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int node;
node = dev_of_offset(dev);
i2c_bus->regs = (struct s3c24x0_i2c *)devfdt_get_addr(dev);
i2c_bus->id = pinmux_decode_periph_id(blob, node);
i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
"clock-frequency", 100000);
i2c_bus->node = node;
i2c_bus->bus_num = dev->seq;
exynos_pinmux_config(i2c_bus->id, 0);
i2c_bus->active = true;
return 0;
}
static const struct dm_i2c_ops s3c_i2c_ops = {
.xfer = s3c24x0_i2c_xfer,
.probe_chip = s3c24x0_i2c_probe,
.set_bus_speed = s3c24x0_i2c_set_bus_speed,
};
static const struct udevice_id s3c_i2c_ids[] = {
{ .compatible = "samsung,s3c2440-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_s3c) = {
.name = "i2c_s3c",
.id = UCLASS_I2C,
.of_match = s3c_i2c_ids,
.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &s3c_i2c_ops,
};
@@ -0,0 +1,83 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2012 Samsung Electronics
*/
#ifndef _S3C24X0_I2C_H
#define _S3C24X0_I2C_H
struct s3c24x0_i2c {
u32 iiccon;
u32 iicstat;
u32 iicadd;
u32 iicds;
u32 iiclc;
};
struct exynos5_hsi2c {
u32 usi_ctl;
u32 usi_fifo_ctl;
u32 usi_trailing_ctl;
u32 usi_clk_ctl;
u32 usi_clk_slot;
u32 spi_ctl;
u32 uart_ctl;
u32 res1;
u32 usi_int_en;
u32 usi_int_stat;
u32 usi_modem_stat;
u32 usi_error_stat;
u32 usi_fifo_stat;
u32 usi_txdata;
u32 usi_rxdata;
u32 res2;
u32 usi_conf;
u32 usi_auto_conf;
u32 usi_timeout;
u32 usi_manual_cmd;
u32 usi_trans_status;
u32 usi_timing_hs1;
u32 usi_timing_hs2;
u32 usi_timing_hs3;
u32 usi_timing_fs1;
u32 usi_timing_fs2;
u32 usi_timing_fs3;
u32 usi_timing_sla;
u32 i2c_addr;
};
struct s3c24x0_i2c_bus {
bool active; /* port is active and available */
int node; /* device tree node */
int bus_num; /* i2c bus number */
struct s3c24x0_i2c *regs;
struct exynos5_hsi2c *hsregs;
int is_highspeed; /* High speed type, rather than I2C */
unsigned clock_frequency;
int id;
unsigned clk_cycle;
unsigned clk_div;
};
#define I2C_WRITE 0
#define I2C_READ 1
#define I2C_OK 0
#define I2C_NOK 1
#define I2C_NACK 2
#define I2C_NOK_LA 3 /* Lost arbitration */
#define I2C_NOK_TOUT 4 /* time out */
/* S3C I2C Controller bits */
#define I2CSTAT_BSY 0x20 /* Busy bit */
#define I2CSTAT_NACK 0x01 /* Nack bit */
#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
#define I2C_MODE_MR 0x80 /* Master Receive Mode */
#define I2C_START_STOP 0x20 /* START / STOP */
#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
#define I2C_TIMEOUT_MS 10 /* 10 ms */
#endif /* _S3C24X0_I2C_H */
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Simulate an I2C port
*
* Copyright (c) 2014 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/test.h>
#include <dm/lists.h>
#include <dm/device-internal.h>
struct sandbox_i2c_priv {
bool test_mode;
};
static int get_emul(struct udevice *dev, struct udevice **devp,
struct dm_i2c_ops **opsp)
{
struct dm_i2c_chip *plat;
int ret;
*devp = NULL;
*opsp = NULL;
plat = dev_get_parent_platdata(dev);
if (!plat->emul) {
ret = i2c_emul_find(dev, &plat->emul);
if (ret)
return ret;
}
*devp = plat->emul;
*opsp = i2c_get_ops(plat->emul);
return 0;
}
void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
{
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
priv->test_mode = test_mode;
}
static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
struct dm_i2c_ops *ops;
struct udevice *emul, *dev;
bool is_read;
int ret;
/* Special test code to return success but with no emulation */
if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
return 0;
ret = i2c_get_chip(bus, msg->addr, 1, &dev);
if (ret)
return ret;
ret = get_emul(dev, &emul, &ops);
if (ret)
return ret;
if (priv->test_mode) {
/*
* For testing, don't allow writing above 100KHz for writes and
* 400KHz for reads.
*/
is_read = nmsgs > 1;
if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
debug("%s: Max speed exceeded\n", __func__);
return -EINVAL;
}
}
return ops->xfer(emul, msg, nmsgs);
}
static const struct dm_i2c_ops sandbox_i2c_ops = {
.xfer = sandbox_i2c_xfer,
};
static const struct udevice_id sandbox_i2c_ids[] = {
{ .compatible = "sandbox,i2c" },
{ }
};
U_BOOT_DRIVER(i2c_sandbox) = {
.name = "i2c_sandbox",
.id = UCLASS_I2C,
.of_match = sandbox_i2c_ids,
.ops = &sandbox_i2c_ops,
.priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
};
@@ -0,0 +1,310 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011, 2013 Renesas Solutions Corp.
* Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*
* NOTE: This driver should be converted to driver model before June 2017.
* Please see doc/driver-model/i2c-howto.txt for instructions.
*/
#include <common.h>
#include <i2c.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
/* Every register is 32bit aligned, but only 8bits in size */
#define ureg(name) u8 name; u8 __pad_##name##0; u16 __pad_##name##1;
struct sh_i2c {
ureg(icdr);
ureg(iccr);
ureg(icsr);
ureg(icic);
ureg(iccl);
ureg(icch);
};
#undef ureg
/* ICCR */
#define SH_I2C_ICCR_ICE (1 << 7)
#define SH_I2C_ICCR_RACK (1 << 6)
#define SH_I2C_ICCR_RTS (1 << 4)
#define SH_I2C_ICCR_BUSY (1 << 2)
#define SH_I2C_ICCR_SCP (1 << 0)
/* ICSR / ICIC */
#define SH_IC_BUSY (1 << 4)
#define SH_IC_TACK (1 << 2)
#define SH_IC_WAIT (1 << 1)
#define SH_IC_DTE (1 << 0)
#ifdef CONFIG_SH_I2C_8BIT
/* store 8th bit of iccl and icch in ICIC register */
#define SH_I2C_ICIC_ICCLB8 (1 << 7)
#define SH_I2C_ICIC_ICCHB8 (1 << 6)
#endif
static const struct sh_i2c *i2c_dev[CONFIG_SYS_I2C_SH_NUM_CONTROLLERS] = {
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE0,
#ifdef CONFIG_SYS_I2C_SH_BASE1
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE1,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE2
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE2,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE3
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE3,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE4
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE4,
#endif
};
static u16 iccl, icch;
#define IRQ_WAIT 1000
static void sh_irq_dte(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (SH_IC_DTE & readb(&dev->icsr))
break;
udelay(10);
}
}
static int sh_irq_dte_with_tack(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (SH_IC_DTE & readb(&dev->icsr))
break;
if (SH_IC_TACK & readb(&dev->icsr))
return -1;
udelay(10);
}
return 0;
}
static void sh_irq_busy(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (!(SH_IC_BUSY & readb(&dev->icsr)))
break;
udelay(10);
}
}
static int sh_i2c_set_addr(struct sh_i2c *dev, u8 chip, u8 addr, int stop)
{
u8 icic = SH_IC_TACK;
debug("%s: chip: %x, addr: %x iccl: %x, icch %x\n",
__func__, chip, addr, iccl, icch);
clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
setbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
writeb(iccl & 0xff, &dev->iccl);
writeb(icch & 0xff, &dev->icch);
#ifdef CONFIG_SH_I2C_8BIT
if (iccl > 0xff)
icic |= SH_I2C_ICIC_ICCLB8;
if (icch > 0xff)
icic |= SH_I2C_ICIC_ICCHB8;
#endif
writeb(icic, &dev->icic);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
sh_irq_dte(dev);
clrbits_8(&dev->icsr, SH_IC_TACK);
writeb(chip << 1, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
return -1;
writeb(addr, &dev->icdr);
if (stop)
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
return -1;
return 0;
}
static void sh_i2c_finish(struct sh_i2c *dev)
{
writeb(0, &dev->icsr);
clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
}
static int
sh_i2c_raw_write(struct sh_i2c *dev, u8 chip, uint addr, u8 val)
{
int ret = -1;
if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
goto exit0;
udelay(10);
writeb(val, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
sh_irq_busy(dev);
ret = 0;
exit0:
sh_i2c_finish(dev);
return ret;
}
static int sh_i2c_raw_read(struct sh_i2c *dev, u8 chip, u8 addr)
{
int ret = -1;
#if defined(CONFIG_SH73A0)
if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
goto exit0;
#else
if (sh_i2c_set_addr(dev, chip, addr, 1) != 0)
goto exit0;
udelay(100);
#endif
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
sh_irq_dte(dev);
writeb(chip << 1 | 0x01, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
ret = readb(&dev->icdr) & 0xff;
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &dev->iccr);
readb(&dev->icdr); /* Dummy read */
sh_irq_busy(dev);
exit0:
sh_i2c_finish(dev);
return ret;
}
static void
sh_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
int num, denom, tmp;
/* No i2c support prior to relocation */
if (!(gd->flags & GD_FLG_RELOC))
return;
/*
* Calculate the value for iccl. From the data sheet:
* iccl = (p-clock / transfer-rate) * (L / (L + H))
* where L and H are the SCL low and high ratio.
*/
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_LOW;
denom = speed * (CONFIG_SH_I2C_DATA_HIGH + CONFIG_SH_I2C_DATA_LOW);
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
iccl = (u16)((num/denom) + 1);
else
iccl = (u16)(num/denom);
/* Calculate the value for icch. From the data sheet:
icch = (p clock / transfer rate) * (H / (L + H)) */
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_HIGH;
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
icch = (u16)((num/denom) + 1);
else
icch = (u16)(num/denom);
debug("clock: %d, speed %d, iccl: %x, icch: %x\n",
CONFIG_SH_I2C_CLOCK, speed, iccl, icch);
}
static int sh_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, u8 *data, int len)
{
int ret, i;
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
for (i = 0; i < len; i++) {
ret = sh_i2c_raw_read(dev, chip, addr + i);
if (ret < 0)
return -1;
data[i] = ret & 0xff;
debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
}
return 0;
}
static int sh_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr,
int alen, u8 *data, int len)
{
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
int i;
for (i = 0; i < len; i++) {
debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
if (sh_i2c_raw_write(dev, chip, addr + i, data[i]) != 0)
return -1;
}
return 0;
}
static int
sh_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
u8 dummy[1];
return sh_i2c_read(adap, dev, 0, 0, dummy, sizeof dummy);
}
static unsigned int sh_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
sh_i2c_finish(dev);
sh_i2c_init(adap, speed, 0);
return 0;
}
/*
* Register RCAR i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(sh_0, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED0, 0, 0)
#ifdef CONFIG_SYS_I2C_SH_BASE1
U_BOOT_I2C_ADAP_COMPLETE(sh_1, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED1, 0, 1)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE2
U_BOOT_I2C_ADAP_COMPLETE(sh_2, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED2, 0, 2)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE3
U_BOOT_I2C_ADAP_COMPLETE(sh_3, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED3, 0, 3)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE4
U_BOOT_I2C_ADAP_COMPLETE(sh_4, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED4, 0, 4)
#endif
@@ -0,0 +1,515 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
* Changes for multibus/multiadapter I2C support.
*
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* This has been changed substantially by Gerald Van Baren, Custom IDEAS,
* vanbaren@cideas.com. It was heavily influenced by LiMon, written by
* Neil Russell.
*
* NOTE: This driver should be converted to driver model before June 2017.
* Please see doc/driver-model/i2c-howto.txt for instructions.
*/
#include <common.h>
#if defined(CONFIG_AT91FAMILY)
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pio.h>
#ifdef CONFIG_ATMEL_LEGACY
#include <asm/arch/gpio.h>
#endif
#endif
#include <i2c.h>
#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
# include <asm/gpio.h>
# ifndef I2C_GPIO_SYNC
# define I2C_GPIO_SYNC
# endif
# ifndef I2C_INIT
# define I2C_INIT \
do { \
gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
} while (0)
# endif
# ifndef I2C_ACTIVE
# define I2C_ACTIVE do { } while (0)
# endif
# ifndef I2C_TRISTATE
# define I2C_TRISTATE do { } while (0)
# endif
# ifndef I2C_READ
# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
# endif
# ifndef I2C_SDA
# define I2C_SDA(bit) \
do { \
if (bit) \
gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
else \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_SCL
# define I2C_SCL(bit) \
do { \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_DELAY
# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
# endif
#endif
/* #define DEBUG_I2C */
DECLARE_GLOBAL_DATA_PTR;
#ifndef I2C_SOFT_DECLARATIONS
# define I2C_SOFT_DECLARATIONS
#endif
#if !defined(CONFIG_SYS_I2C_SOFT_SPEED)
#define CONFIG_SYS_I2C_SOFT_SPEED CONFIG_SYS_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_I2C_SOFT_SLAVE)
#define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
#endif
/*-----------------------------------------------------------------------
* Definitions
*/
#define RETRIES 0
#define I2C_ACK 0 /* PD_SDA level to ack a byte */
#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
#ifdef DEBUG_I2C
#define PRINTD(fmt,args...) do { \
printf (fmt ,##args); \
} while (0)
#else
#define PRINTD(fmt,args...)
#endif
/*-----------------------------------------------------------------------
* Local functions
*/
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
static void send_reset (void);
#endif
static void send_start (void);
static void send_stop (void);
static void send_ack (int);
static int write_byte (uchar byte);
static uchar read_byte (int);
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
/*-----------------------------------------------------------------------
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void send_reset(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
I2C_SCL(1);
I2C_SDA(1);
#ifdef I2C_INIT
I2C_INIT;
#endif
I2C_TRISTATE;
for(j = 0; j < 9; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
}
send_stop();
I2C_TRISTATE;
}
#endif
/*-----------------------------------------------------------------------
* START: High -> Low on SDA while SCL is High
*/
static void send_start(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_DELAY;
I2C_SDA(1);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* STOP: Low -> High on SDA while SCL is High
*/
static void send_stop(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(0);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(1);
I2C_DELAY;
I2C_TRISTATE;
}
/*-----------------------------------------------------------------------
* ack should be I2C_ACK or I2C_NOACK
*/
static void send_ack(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
I2C_SDA(ack);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* Send 8 bits and look for an acknowledgement.
*/
static int write_byte(uchar data)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
int nack;
I2C_ACTIVE;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(data & 0x80);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
data <<= 1;
}
/*
* Look for an <ACK>(negative logic) and return it.
*/
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(1);
I2C_TRISTATE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
nack = I2C_READ;
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
return(nack); /* not a nack is an ack */
}
/*-----------------------------------------------------------------------
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar read_byte(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int data;
int j;
/*
* Read 8 bits, MSB first.
*/
I2C_TRISTATE;
I2C_SDA(1);
data = 0;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
data <<= 1;
data |= I2C_READ;
I2C_DELAY;
}
send_ack(ack);
return(data);
}
/*-----------------------------------------------------------------------
* Initialization
*/
static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
#if defined(CONFIG_SYS_I2C_INIT_BOARD)
/* call board specific i2c bus reset routine before accessing the */
/* environment, which might be in a chip on that bus. For details */
/* about this problem see doc/I2C_Edge_Conditions. */
i2c_init_board();
#else
/*
* WARNING: Do NOT save speed in a static variable: if the
* I2C routines are called before RAM is initialized (to read
* the DIMM SPD, for instance), RAM won't be usable and your
* system will crash.
*/
send_reset ();
#endif
}
/*-----------------------------------------------------------------------
* Probe to see if a chip is present. Also good for checking for the
* completion of EEPROM writes since the chip stops responding until
* the write completes (typically 10mSec).
*/
static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
{
int rc;
/*
* perform 1 byte write transaction with just address byte
* (fake write)
*/
send_start();
rc = write_byte ((addr << 1) | 0);
send_stop();
return (rc ? 1 : 0);
}
/*-----------------------------------------------------------------------
* Read bytes
*/
static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
int shift;
PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
chip, addr);
#endif
/*
* Do the addressing portion of a write cycle to set the
* chip's address pointer. If the address length is zero,
* don't do the normal write cycle to set the address pointer,
* there is no address pointer in this chip.
*/
send_start();
if(alen > 0) {
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_read, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_read, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
/* Some I2C chips need a stop/start sequence here,
* other chips don't work with a full stop and need
* only a start. Default behaviour is to send the
* stop/start sequence.
*/
#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
send_start();
#else
send_stop();
send_start();
#endif
}
/*
* Send the chip address again, this time for a read cycle.
* Then read the data. On the last byte, we do a NACK instead
* of an ACK(len == 0) to terminate the read.
*/
write_byte((chip << 1) | 1); /* read cycle */
while(len-- > 0) {
*buffer++ = read_byte(len == 0);
}
send_stop();
return(0);
}
/*-----------------------------------------------------------------------
* Write bytes
*/
static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
int shift, failures = 0;
PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
send_start();
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_write, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_write, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
while(len-- > 0) {
if(write_byte(*buffer++)) {
failures++;
}
}
send_stop();
return(failures);
}
/*
* Register soft i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(soft00, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
0)
#if defined(I2C_SOFT_DECLARATIONS2)
U_BOOT_I2C_ADAP_COMPLETE(soft01, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_2,
CONFIG_SYS_I2C_SOFT_SLAVE_2,
1)
#endif
#if defined(I2C_SOFT_DECLARATIONS3)
U_BOOT_I2C_ADAP_COMPLETE(soft02, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_3,
CONFIG_SYS_I2C_SOFT_SLAVE_3,
2)
#endif
#if defined(I2C_SOFT_DECLARATIONS4)
U_BOOT_I2C_ADAP_COMPLETE(soft03, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_4,
CONFIG_SYS_I2C_SOFT_SLAVE_4,
3)
#endif
#if defined(I2C_SOFT_DECLARATIONS5)
U_BOOT_I2C_ADAP_COMPLETE(soft04, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_5,
CONFIG_SYS_I2C_SOFT_SLAVE_5,
4)
#endif
#if defined(I2C_SOFT_DECLARATIONS6)
U_BOOT_I2C_ADAP_COMPLETE(soft05, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_6,
CONFIG_SYS_I2C_SOFT_SLAVE_6,
5)
#endif
#if defined(I2C_SOFT_DECLARATIONS7)
U_BOOT_I2C_ADAP_COMPLETE(soft06, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_7,
CONFIG_SYS_I2C_SOFT_SLAVE_7,
6)
#endif
#if defined(I2C_SOFT_DECLARATIONS8)
U_BOOT_I2C_ADAP_COMPLETE(soft07, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_8,
CONFIG_SYS_I2C_SOFT_SLAVE_8,
7)
#endif
#if defined(I2C_SOFT_DECLARATIONS9)
U_BOOT_I2C_ADAP_COMPLETE(soft08, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_9,
CONFIG_SYS_I2C_SOFT_SLAVE_9,
8)
#endif
#if defined(I2C_SOFT_DECLARATIONS10)
U_BOOT_I2C_ADAP_COMPLETE(soft09, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_10,
CONFIG_SYS_I2C_SOFT_SLAVE_10,
9)
#endif
#if defined(I2C_SOFT_DECLARATIONS11)
U_BOOT_I2C_ADAP_COMPLETE(soft10, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_11,
CONFIG_SYS_I2C_SOFT_SLAVE_11,
10)
#endif
#if defined(I2C_SOFT_DECLARATIONS12)
U_BOOT_I2C_ADAP_COMPLETE(soft11, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_12,
CONFIG_SYS_I2C_SOFT_SLAVE_12,
11)
#endif
@@ -0,0 +1,881 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2017 STMicroelectronics
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#include <reset.h>
#include <dm/device.h>
#include <linux/io.h>
/* STM32 I2C registers */
struct stm32_i2c_regs {
u32 cr1; /* I2C control register 1 */
u32 cr2; /* I2C control register 2 */
u32 oar1; /* I2C own address 1 register */
u32 oar2; /* I2C own address 2 register */
u32 timingr; /* I2C timing register */
u32 timeoutr; /* I2C timeout register */
u32 isr; /* I2C interrupt and status register */
u32 icr; /* I2C interrupt clear register */
u32 pecr; /* I2C packet error checking register */
u32 rxdr; /* I2C receive data register */
u32 txdr; /* I2C transmit data register */
};
#define STM32_I2C_CR1 0x00
#define STM32_I2C_CR2 0x04
#define STM32_I2C_TIMINGR 0x10
#define STM32_I2C_ISR 0x18
#define STM32_I2C_ICR 0x1C
#define STM32_I2C_RXDR 0x24
#define STM32_I2C_TXDR 0x28
/* STM32 I2C control 1 */
#define STM32_I2C_CR1_ANFOFF BIT(12)
#define STM32_I2C_CR1_ERRIE BIT(7)
#define STM32_I2C_CR1_TCIE BIT(6)
#define STM32_I2C_CR1_STOPIE BIT(5)
#define STM32_I2C_CR1_NACKIE BIT(4)
#define STM32_I2C_CR1_ADDRIE BIT(3)
#define STM32_I2C_CR1_RXIE BIT(2)
#define STM32_I2C_CR1_TXIE BIT(1)
#define STM32_I2C_CR1_PE BIT(0)
/* STM32 I2C control 2 */
#define STM32_I2C_CR2_AUTOEND BIT(25)
#define STM32_I2C_CR2_RELOAD BIT(24)
#define STM32_I2C_CR2_NBYTES_MASK GENMASK(23, 16)
#define STM32_I2C_CR2_NBYTES(n) ((n & 0xff) << 16)
#define STM32_I2C_CR2_NACK BIT(15)
#define STM32_I2C_CR2_STOP BIT(14)
#define STM32_I2C_CR2_START BIT(13)
#define STM32_I2C_CR2_HEAD10R BIT(12)
#define STM32_I2C_CR2_ADD10 BIT(11)
#define STM32_I2C_CR2_RD_WRN BIT(10)
#define STM32_I2C_CR2_SADD10_MASK GENMASK(9, 0)
#define STM32_I2C_CR2_SADD10(n) (n & STM32_I2C_CR2_SADD10_MASK)
#define STM32_I2C_CR2_SADD7_MASK GENMASK(7, 1)
#define STM32_I2C_CR2_SADD7(n) ((n & 0x7f) << 1)
#define STM32_I2C_CR2_RESET_MASK (STM32_I2C_CR2_HEAD10R \
| STM32_I2C_CR2_NBYTES_MASK \
| STM32_I2C_CR2_SADD7_MASK \
| STM32_I2C_CR2_RELOAD \
| STM32_I2C_CR2_RD_WRN)
/* STM32 I2C Interrupt Status */
#define STM32_I2C_ISR_BUSY BIT(15)
#define STM32_I2C_ISR_ARLO BIT(9)
#define STM32_I2C_ISR_BERR BIT(8)
#define STM32_I2C_ISR_TCR BIT(7)
#define STM32_I2C_ISR_TC BIT(6)
#define STM32_I2C_ISR_STOPF BIT(5)
#define STM32_I2C_ISR_NACKF BIT(4)
#define STM32_I2C_ISR_ADDR BIT(3)
#define STM32_I2C_ISR_RXNE BIT(2)
#define STM32_I2C_ISR_TXIS BIT(1)
#define STM32_I2C_ISR_TXE BIT(0)
#define STM32_I2C_ISR_ERRORS (STM32_I2C_ISR_BERR \
| STM32_I2C_ISR_ARLO)
/* STM32 I2C Interrupt Clear */
#define STM32_I2C_ICR_ARLOCF BIT(9)
#define STM32_I2C_ICR_BERRCF BIT(8)
#define STM32_I2C_ICR_STOPCF BIT(5)
#define STM32_I2C_ICR_NACKCF BIT(4)
/* STM32 I2C Timing */
#define STM32_I2C_TIMINGR_PRESC(n) ((n & 0xf) << 28)
#define STM32_I2C_TIMINGR_SCLDEL(n) ((n & 0xf) << 20)
#define STM32_I2C_TIMINGR_SDADEL(n) ((n & 0xf) << 16)
#define STM32_I2C_TIMINGR_SCLH(n) ((n & 0xff) << 8)
#define STM32_I2C_TIMINGR_SCLL(n) (n & 0xff)
#define STM32_I2C_MAX_LEN 0xff
#define STM32_I2C_DNF_DEFAULT 0
#define STM32_I2C_DNF_MAX 16
#define STM32_I2C_ANALOG_FILTER_ENABLE 1
#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
#define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */
#define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */
#define STM32_PRESC_MAX BIT(4)
#define STM32_SCLDEL_MAX BIT(4)
#define STM32_SDADEL_MAX BIT(4)
#define STM32_SCLH_MAX BIT(8)
#define STM32_SCLL_MAX BIT(8)
#define STM32_NSEC_PER_SEC 1000000000L
#define STANDARD_RATE 100000
#define FAST_RATE 400000
#define FAST_PLUS_RATE 1000000
enum stm32_i2c_speed {
STM32_I2C_SPEED_STANDARD, /* 100 kHz */
STM32_I2C_SPEED_FAST, /* 400 kHz */
STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
STM32_I2C_SPEED_END,
};
/**
* struct stm32_i2c_spec - private i2c specification timing
* @rate: I2C bus speed (Hz)
* @rate_min: 80% of I2C bus speed (Hz)
* @rate_max: 120% of I2C bus speed (Hz)
* @fall_max: Max fall time of both SDA and SCL signals (ns)
* @rise_max: Max rise time of both SDA and SCL signals (ns)
* @hddat_min: Min data hold time (ns)
* @vddat_max: Max data valid time (ns)
* @sudat_min: Min data setup time (ns)
* @l_min: Min low period of the SCL clock (ns)
* @h_min: Min high period of the SCL clock (ns)
*/
struct stm32_i2c_spec {
u32 rate;
u32 rate_min;
u32 rate_max;
u32 fall_max;
u32 rise_max;
u32 hddat_min;
u32 vddat_max;
u32 sudat_min;
u32 l_min;
u32 h_min;
};
/**
* struct stm32_i2c_setup - private I2C timing setup parameters
* @speed: I2C speed mode (standard, Fast Plus)
* @speed_freq: I2C speed frequency (Hz)
* @clock_src: I2C clock source frequency (Hz)
* @rise_time: Rise time (ns)
* @fall_time: Fall time (ns)
* @dnf: Digital filter coefficient (0-16)
* @analog_filter: Analog filter delay (On/Off)
*/
struct stm32_i2c_setup {
enum stm32_i2c_speed speed;
u32 speed_freq;
u32 clock_src;
u32 rise_time;
u32 fall_time;
u8 dnf;
bool analog_filter;
};
/**
* struct stm32_i2c_timings - private I2C output parameters
* @prec: Prescaler value
* @scldel: Data setup time
* @sdadel: Data hold time
* @sclh: SCL high period (master mode)
* @sclh: SCL low period (master mode)
*/
struct stm32_i2c_timings {
struct list_head node;
u8 presc;
u8 scldel;
u8 sdadel;
u8 sclh;
u8 scll;
};
struct stm32_i2c_priv {
struct stm32_i2c_regs *regs;
struct clk clk;
struct stm32_i2c_setup *setup;
int speed;
};
static const struct stm32_i2c_spec i2c_specs[] = {
[STM32_I2C_SPEED_STANDARD] = {
.rate = STANDARD_RATE,
.rate_min = 8000,
.rate_max = 120000,
.fall_max = 300,
.rise_max = 1000,
.hddat_min = 0,
.vddat_max = 3450,
.sudat_min = 250,
.l_min = 4700,
.h_min = 4000,
},
[STM32_I2C_SPEED_FAST] = {
.rate = FAST_RATE,
.rate_min = 320000,
.rate_max = 480000,
.fall_max = 300,
.rise_max = 300,
.hddat_min = 0,
.vddat_max = 900,
.sudat_min = 100,
.l_min = 1300,
.h_min = 600,
},
[STM32_I2C_SPEED_FAST_PLUS] = {
.rate = FAST_PLUS_RATE,
.rate_min = 800000,
.rate_max = 1200000,
.fall_max = 100,
.rise_max = 120,
.hddat_min = 0,
.vddat_max = 450,
.sudat_min = 50,
.l_min = 500,
.h_min = 260,
},
};
static const struct stm32_i2c_setup stm32f7_setup = {
.rise_time = STM32_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32_I2C_FALL_TIME_DEFAULT,
.dnf = STM32_I2C_DNF_DEFAULT,
.analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
};
static int stm32_i2c_check_device_busy(struct stm32_i2c_priv *i2c_priv)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 status = readl(&regs->isr);
if (status & STM32_I2C_ISR_BUSY)
return -EBUSY;
return 0;
}
static void stm32_i2c_message_start(struct stm32_i2c_priv *i2c_priv,
struct i2c_msg *msg, bool stop)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 cr2 = readl(&regs->cr2);
/* Set transfer direction */
cr2 &= ~STM32_I2C_CR2_RD_WRN;
if (msg->flags & I2C_M_RD)
cr2 |= STM32_I2C_CR2_RD_WRN;
/* Set slave address */
cr2 &= ~(STM32_I2C_CR2_HEAD10R | STM32_I2C_CR2_ADD10);
if (msg->flags & I2C_M_TEN) {
cr2 &= ~STM32_I2C_CR2_SADD10_MASK;
cr2 |= STM32_I2C_CR2_SADD10(msg->addr);
cr2 |= STM32_I2C_CR2_ADD10;
} else {
cr2 &= ~STM32_I2C_CR2_SADD7_MASK;
cr2 |= STM32_I2C_CR2_SADD7(msg->addr);
}
/* Set nb bytes to transfer and reload or autoend bits */
cr2 &= ~(STM32_I2C_CR2_NBYTES_MASK | STM32_I2C_CR2_RELOAD |
STM32_I2C_CR2_AUTOEND);
if (msg->len > STM32_I2C_MAX_LEN) {
cr2 |= STM32_I2C_CR2_NBYTES(STM32_I2C_MAX_LEN);
cr2 |= STM32_I2C_CR2_RELOAD;
} else {
cr2 |= STM32_I2C_CR2_NBYTES(msg->len);
}
/* Write configurations register */
writel(cr2, &regs->cr2);
/* START/ReSTART generation */
setbits_le32(&regs->cr2, STM32_I2C_CR2_START);
}
/*
* RELOAD mode must be selected if total number of data bytes to be
* sent is greater than MAX_LEN
*/
static void stm32_i2c_handle_reload(struct stm32_i2c_priv *i2c_priv,
struct i2c_msg *msg, bool stop)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 cr2 = readl(&regs->cr2);
cr2 &= ~STM32_I2C_CR2_NBYTES_MASK;
if (msg->len > STM32_I2C_MAX_LEN) {
cr2 |= STM32_I2C_CR2_NBYTES(STM32_I2C_MAX_LEN);
} else {
cr2 &= ~STM32_I2C_CR2_RELOAD;
cr2 |= STM32_I2C_CR2_NBYTES(msg->len);
}
writel(cr2, &regs->cr2);
}
static int stm32_i2c_wait_flags(struct stm32_i2c_priv *i2c_priv,
u32 flags, u32 *status)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 time_start = get_timer(0);
*status = readl(&regs->isr);
while (!(*status & flags)) {
if (get_timer(time_start) > CONFIG_SYS_HZ) {
debug("%s: i2c timeout\n", __func__);
return -ETIMEDOUT;
}
*status = readl(&regs->isr);
}
return 0;
}
static int stm32_i2c_check_end_of_message(struct stm32_i2c_priv *i2c_priv)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 mask = STM32_I2C_ISR_ERRORS | STM32_I2C_ISR_NACKF |
STM32_I2C_ISR_STOPF;
u32 status;
int ret;
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
return ret;
if (status & STM32_I2C_ISR_BERR) {
debug("%s: Bus error\n", __func__);
/* Clear BERR flag */
setbits_le32(&regs->icr, STM32_I2C_ICR_BERRCF);
return -EIO;
}
if (status & STM32_I2C_ISR_ARLO) {
debug("%s: Arbitration lost\n", __func__);
/* Clear ARLO flag */
setbits_le32(&regs->icr, STM32_I2C_ICR_ARLOCF);
return -EAGAIN;
}
if (status & STM32_I2C_ISR_NACKF) {
debug("%s: Receive NACK\n", __func__);
/* Clear NACK flag */
setbits_le32(&regs->icr, STM32_I2C_ICR_NACKCF);
/* Wait until STOPF flag is set */
mask = STM32_I2C_ISR_STOPF;
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
return ret;
ret = -EIO;
}
if (status & STM32_I2C_ISR_STOPF) {
/* Clear STOP flag */
setbits_le32(&regs->icr, STM32_I2C_ICR_STOPCF);
/* Clear control register 2 */
setbits_le32(&regs->cr2, STM32_I2C_CR2_RESET_MASK);
}
return ret;
}
static int stm32_i2c_message_xfer(struct stm32_i2c_priv *i2c_priv,
struct i2c_msg *msg, bool stop)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 status;
u32 mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
int bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
STM32_I2C_MAX_LEN : msg->len;
int ret = 0;
/* Add errors */
mask |= STM32_I2C_ISR_ERRORS;
stm32_i2c_message_start(i2c_priv, msg, stop);
while (msg->len) {
/*
* Wait until TXIS/NACKF/BERR/ARLO flags or
* RXNE/BERR/ARLO flags are set
*/
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
break;
if (status & (STM32_I2C_ISR_NACKF | STM32_I2C_ISR_ERRORS))
break;
if (status & STM32_I2C_ISR_RXNE) {
*msg->buf++ = readb(&regs->rxdr);
msg->len--;
bytes_to_rw--;
}
if (status & STM32_I2C_ISR_TXIS) {
writeb(*msg->buf++, &regs->txdr);
msg->len--;
bytes_to_rw--;
}
if (!bytes_to_rw && msg->len) {
/* Wait until TCR flag is set */
mask = STM32_I2C_ISR_TCR;
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
break;
bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
STM32_I2C_MAX_LEN : msg->len;
mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
stm32_i2c_handle_reload(i2c_priv, msg, stop);
} else if (!bytes_to_rw) {
/* Wait until TC flag is set */
mask = STM32_I2C_ISR_TC;
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
break;
if (!stop)
/* Message sent, new message has to be sent */
return 0;
}
}
/* End of transfer, send stop condition */
mask = STM32_I2C_CR2_STOP;
setbits_le32(&regs->cr2, mask);
return stm32_i2c_check_end_of_message(i2c_priv);
}
static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
int ret;
ret = stm32_i2c_check_device_busy(i2c_priv);
if (ret)
return ret;
for (; nmsgs > 0; nmsgs--, msg++) {
ret = stm32_i2c_message_xfer(i2c_priv, msg, nmsgs == 1);
if (ret)
return ret;
}
return 0;
}
static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
struct list_head *solutions)
{
struct stm32_i2c_timings *v;
u32 p_prev = STM32_PRESC_MAX;
u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
setup->clock_src);
u32 af_delay_min, af_delay_max;
u16 p, l, a;
int sdadel_min, sdadel_max, scldel_min;
int ret = 0;
af_delay_min = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
af_delay_max = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
af_delay_max - (setup->dnf + 4) * i2cclk;
scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
if (sdadel_min < 0)
sdadel_min = 0;
if (sdadel_max < 0)
sdadel_max = 0;
debug("%s: SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n", __func__,
sdadel_min, sdadel_max, scldel_min);
/* Compute possible values for PRESC, SCLDEL and SDADEL */
for (p = 0; p < STM32_PRESC_MAX; p++) {
for (l = 0; l < STM32_SCLDEL_MAX; l++) {
int scldel = (l + 1) * (p + 1) * i2cclk;
if (scldel < scldel_min)
continue;
for (a = 0; a < STM32_SDADEL_MAX; a++) {
int sdadel = (a * (p + 1) + 1) * i2cclk;
if (((sdadel >= sdadel_min) &&
(sdadel <= sdadel_max)) &&
(p != p_prev)) {
v = calloc(1, sizeof(*v));
if (!v)
return -ENOMEM;
v->presc = p;
v->scldel = l;
v->sdadel = a;
p_prev = p;
list_add_tail(&v->node, solutions);
break;
}
}
if (p_prev == p)
break;
}
}
if (list_empty(solutions)) {
pr_err("%s: no Prescaler solution\n", __func__);
ret = -EPERM;
}
return ret;
}
static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
struct list_head *solutions,
struct stm32_i2c_timings *s)
{
struct stm32_i2c_timings *v;
u32 i2cbus = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
setup->speed_freq);
u32 clk_error_prev = i2cbus;
u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
setup->clock_src);
u32 clk_min, clk_max;
u32 af_delay_min;
u32 dnf_delay;
u32 tsync;
u16 l, h;
bool sol_found = false;
int ret = 0;
af_delay_min = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
dnf_delay = setup->dnf * i2cclk;
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
/*
* Among Prescaler possibilities discovered above figures out SCL Low
* and High Period. Provided:
* - SCL Low Period has to be higher than Low Period of the SCL Clock
* defined by I2C Specification. I2C Clock has to be lower than
* (SCL Low Period - Analog/Digital filters) / 4.
* - SCL High Period has to be lower than High Period of the SCL Clock
* defined by I2C Specification
* - I2C Clock has to be lower than SCL High Period
*/
list_for_each_entry(v, solutions, node) {
u32 prescaler = (v->presc + 1) * i2cclk;
for (l = 0; l < STM32_SCLL_MAX; l++) {
u32 tscl_l = (l + 1) * prescaler + tsync;
if ((tscl_l < i2c_specs[setup->speed].l_min) ||
(i2cclk >=
((tscl_l - af_delay_min - dnf_delay) / 4))) {
continue;
}
for (h = 0; h < STM32_SCLH_MAX; h++) {
u32 tscl_h = (h + 1) * prescaler + tsync;
u32 tscl = tscl_l + tscl_h +
setup->rise_time + setup->fall_time;
if ((tscl >= clk_min) && (tscl <= clk_max) &&
(tscl_h >= i2c_specs[setup->speed].h_min) &&
(i2cclk < tscl_h)) {
u32 clk_error;
if (tscl > i2cbus)
clk_error = tscl - i2cbus;
else
clk_error = i2cbus - tscl;
if (clk_error < clk_error_prev) {
clk_error_prev = clk_error;
v->scll = l;
v->sclh = h;
sol_found = true;
memcpy(s, v, sizeof(*s));
}
}
}
}
}
if (!sol_found) {
pr_err("%s: no solution at all\n", __func__);
ret = -EPERM;
}
return ret;
}
static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_setup *setup,
struct stm32_i2c_timings *output)
{
struct stm32_i2c_timings *v, *_v;
struct list_head solutions;
int ret;
if (setup->speed >= STM32_I2C_SPEED_END) {
pr_err("%s: speed out of bound {%d/%d}\n", __func__,
setup->speed, STM32_I2C_SPEED_END - 1);
return -EINVAL;
}
if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
(setup->fall_time > i2c_specs[setup->speed].fall_max)) {
pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
__func__,
setup->rise_time, i2c_specs[setup->speed].rise_max,
setup->fall_time, i2c_specs[setup->speed].fall_max);
return -EINVAL;
}
if (setup->dnf > STM32_I2C_DNF_MAX) {
pr_err("%s: DNF out of bound %d/%d\n", __func__,
setup->dnf, STM32_I2C_DNF_MAX);
return -EINVAL;
}
if (setup->speed_freq > i2c_specs[setup->speed].rate) {
pr_err("%s: Freq {%d/%d}\n", __func__,
setup->speed_freq, i2c_specs[setup->speed].rate);
return -EINVAL;
}
INIT_LIST_HEAD(&solutions);
ret = stm32_i2c_compute_solutions(setup, &solutions);
if (ret)
goto exit;
ret = stm32_i2c_choose_solution(setup, &solutions, output);
if (ret)
goto exit;
debug("%s: Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
__func__, output->presc,
output->scldel, output->sdadel,
output->scll, output->sclh);
exit:
/* Release list and memory */
list_for_each_entry_safe(v, _v, &solutions, node) {
list_del(&v->node);
free(v);
}
return ret;
}
static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_timings *timing)
{
struct stm32_i2c_setup *setup = i2c_priv->setup;
int ret = 0;
setup->speed = i2c_priv->speed;
setup->speed_freq = i2c_specs[setup->speed].rate;
setup->clock_src = clk_get_rate(&i2c_priv->clk);
if (!setup->clock_src) {
pr_err("%s: clock rate is 0\n", __func__);
return -EINVAL;
}
do {
ret = stm32_i2c_compute_timing(i2c_priv, setup, timing);
if (ret) {
debug("%s: failed to compute I2C timings.\n",
__func__);
if (i2c_priv->speed > STM32_I2C_SPEED_STANDARD) {
i2c_priv->speed--;
setup->speed = i2c_priv->speed;
setup->speed_freq =
i2c_specs[setup->speed].rate;
debug("%s: downgrade I2C Speed Freq to (%i)\n",
__func__, i2c_specs[setup->speed].rate);
} else {
break;
}
}
} while (ret);
if (ret) {
pr_err("%s: impossible to compute I2C timings.\n", __func__);
return ret;
}
debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__,
setup->speed, setup->speed_freq, setup->clock_src);
debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__,
setup->rise_time, setup->fall_time);
debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__,
setup->analog_filter ? "On" : "Off", setup->dnf);
return 0;
}
static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
struct stm32_i2c_timings t;
int ret;
u32 timing = 0;
ret = stm32_i2c_setup_timing(i2c_priv, &t);
if (ret)
return ret;
/* Disable I2C */
clrbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
/* Timing settings */
timing |= STM32_I2C_TIMINGR_PRESC(t.presc);
timing |= STM32_I2C_TIMINGR_SCLDEL(t.scldel);
timing |= STM32_I2C_TIMINGR_SDADEL(t.sdadel);
timing |= STM32_I2C_TIMINGR_SCLH(t.sclh);
timing |= STM32_I2C_TIMINGR_SCLL(t.scll);
writel(timing, &regs->timingr);
/* Enable I2C */
if (i2c_priv->setup->analog_filter)
clrbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
else
setbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
setbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
return 0;
}
static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
switch (speed) {
case STANDARD_RATE:
i2c_priv->speed = STM32_I2C_SPEED_STANDARD;
break;
case FAST_RATE:
i2c_priv->speed = STM32_I2C_SPEED_FAST;
break;
case FAST_PLUS_RATE:
i2c_priv->speed = STM32_I2C_SPEED_FAST_PLUS;
break;
default:
debug("%s: Speed %d not supported\n", __func__, speed);
return -EINVAL;
}
return stm32_i2c_hw_config(i2c_priv);
}
static int stm32_i2c_probe(struct udevice *dev)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
struct reset_ctl reset_ctl;
fdt_addr_t addr;
int ret;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
i2c_priv->regs = (struct stm32_i2c_regs *)addr;
ret = clk_get_by_index(dev, 0, &i2c_priv->clk);
if (ret)
return ret;
ret = clk_enable(&i2c_priv->clk);
if (ret)
goto clk_free;
ret = reset_get_by_index(dev, 0, &reset_ctl);
if (ret)
goto clk_disable;
reset_assert(&reset_ctl);
udelay(2);
reset_deassert(&reset_ctl);
return 0;
clk_disable:
clk_disable(&i2c_priv->clk);
clk_free:
clk_free(&i2c_priv->clk);
return ret;
}
static int stm32_ofdata_to_platdata(struct udevice *dev)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
u32 rise_time, fall_time;
i2c_priv->setup = (struct stm32_i2c_setup *)dev_get_driver_data(dev);
if (!i2c_priv->setup)
return -EINVAL;
rise_time = dev_read_u32_default(dev, "i2c-scl-rising-time-ns", 0);
if (rise_time)
i2c_priv->setup->rise_time = rise_time;
fall_time = dev_read_u32_default(dev, "i2c-scl-falling-time-ns", 0);
if (fall_time)
i2c_priv->setup->fall_time = fall_time;
return 0;
}
static const struct dm_i2c_ops stm32_i2c_ops = {
.xfer = stm32_i2c_xfer,
.set_bus_speed = stm32_i2c_set_bus_speed,
};
static const struct udevice_id stm32_i2c_of_match[] = {
{ .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup },
{}
};
U_BOOT_DRIVER(stm32f7_i2c) = {
.name = "stm32f7-i2c",
.id = UCLASS_I2C,
.of_match = stm32_i2c_of_match,
.ofdata_to_platdata = stm32_ofdata_to_platdata,
.probe = stm32_i2c_probe,
.priv_auto_alloc_size = sizeof(struct stm32_i2c_priv),
.ops = &stm32_i2c_ops,
};
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <misc.h>
#include <asm/arch-tegra/bpmp_abi.h>
DECLARE_GLOBAL_DATA_PTR;
struct tegra186_bpmp_i2c {
uint32_t bpmp_bus_id;
};
static inline void serialize_u16(uint8_t **p, uint16_t val)
{
(*p)[0] = val & 0xff;
(*p)[1] = val >> 8;
(*p) += 2;
}
/* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
#define SUPPORTED_FLAGS \
(I2C_M_TEN | \
I2C_M_RD | \
I2C_M_STOP | \
I2C_M_NOSTART | \
I2C_M_REV_DIR_ADDR | \
I2C_M_IGNORE_NAK | \
I2C_M_NO_RD_ACK | \
I2C_M_RECV_LEN)
static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
struct mrq_i2c_request req;
struct mrq_i2c_response resp;
uint8_t *p;
int left, i, ret;
req.cmd = CMD_I2C_XFER;
req.xfer.bus_id = priv->bpmp_bus_id;
p = &req.xfer.data_buf[0];
left = ARRAY_SIZE(req.xfer.data_buf);
for (i = 0; i < nmsgs; i++) {
int len = 6;
if (!(msg[i].flags & I2C_M_RD))
len += msg[i].len;
if ((len >= BIT(16)) || (len > left))
return -ENOSPC;
if (msg[i].flags & ~SUPPORTED_FLAGS)
return -EINVAL;
serialize_u16(&p, msg[i].addr);
serialize_u16(&p, msg[i].flags);
serialize_u16(&p, msg[i].len);
if (!(msg[i].flags & I2C_M_RD)) {
memcpy(p, msg[i].buf, msg[i].len);
p += msg[i].len;
}
}
req.xfer.data_size = p - &req.xfer.data_buf[0];
ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
sizeof(resp));
if (ret < 0)
return ret;
p = &resp.xfer.data_buf[0];
left = resp.xfer.data_size;
if (left > ARRAY_SIZE(resp.xfer.data_buf))
return -EINVAL;
for (i = 0; i < nmsgs; i++) {
if (msg[i].flags & I2C_M_RD) {
memcpy(msg[i].buf, p, msg[i].len);
p += msg[i].len;
}
}
return 0;
}
static int tegra186_bpmp_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
return 0;
}
static int tegra186_bpmp_i2c_probe(struct udevice *dev)
{
struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
"nvidia,bpmp-bus-id", U32_MAX);
if (priv->bpmp_bus_id == U32_MAX) {
debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
return -EINVAL;
}
return 0;
}
static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
.xfer = tegra186_bpmp_i2c_xfer,
.probe_chip = tegra186_bpmp_probe_chip,
};
static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
{ .compatible = "nvidia,tegra186-bpmp-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_gpio) = {
.name = "tegra186_bpmp_i2c",
.id = UCLASS_I2C,
.of_match = tegra186_bpmp_i2c_ids,
.probe = tegra186_bpmp_i2c_probe,
.priv_auto_alloc_size = sizeof(struct tegra186_bpmp_i2c),
.ops = &tegra186_bpmp_i2c_ops,
};
@@ -0,0 +1,536 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Copyright (c) 2010-2011 NVIDIA Corporation
* NVIDIA Corporation <www.nvidia.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/io.h>
#include <clk.h>
#include <reset.h>
#ifndef CONFIG_TEGRA186
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
#endif
#include <asm/arch/gpio.h>
#include <asm/arch-tegra/tegra_i2c.h>
enum i2c_type {
TYPE_114,
TYPE_STD,
TYPE_DVC,
};
/* Information about i2c controller */
struct i2c_bus {
int id;
struct reset_ctl reset_ctl;
struct clk clk;
int speed;
int pinmux_config;
struct i2c_control *control;
struct i2c_ctlr *regs;
enum i2c_type type;
int inited; /* bus is inited */
};
static void set_packet_mode(struct i2c_bus *i2c_bus)
{
u32 config;
config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
if (i2c_bus->type == TYPE_DVC) {
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
writel(config, &dvc->cnfg);
} else {
writel(config, &i2c_bus->regs->cnfg);
/*
* program I2C_SL_CNFG.NEWSL to ENABLE. This fixes probe
* issues, i.e., some slaves may be wrongly detected.
*/
setbits_le32(&i2c_bus->regs->sl_cnfg, I2C_SL_CNFG_NEWSL_MASK);
}
}
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
reset_assert(&i2c_bus->reset_ctl);
udelay(1);
reset_deassert(&i2c_bus->reset_ctl);
udelay(1);
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate)
{
int ret;
ret = reset_assert(&i2c_bus->reset_ctl);
if (ret)
return ret;
ret = clk_enable(&i2c_bus->clk);
if (ret)
return ret;
ret = clk_set_rate(&i2c_bus->clk, rate);
if (IS_ERR_VALUE(ret))
return ret;
ret = reset_deassert(&i2c_bus->reset_ctl);
if (ret)
return ret;
return 0;
}
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
if (!i2c_bus->speed)
return;
debug("%s: speed=%d\n", __func__, i2c_bus->speed);
/*
* Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
* here, in section 23.3.1, but in fact we seem to need a factor of
* 16 to get the right frequency.
*/
i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
if (i2c_bus->type == TYPE_114) {
/*
* T114 I2C went to a single clock source for standard/fast and
* HS clock speeds. The new clock rate setting calculation is:
* SCL = CLK_SOURCE.I2C /
* (CLK_MULT_STD_FAST_MODE * (I2C_CLK_DIV_STD_FAST_MODE+1) *
* I2C FREQUENCY DIVISOR) as per the T114 TRM (sec 30.3.1).
*
* NOTE: We do this here, after the initial clock/pll start,
* because if we read the clk_div reg before the controller
* is running, we hang, and we need it for the new calc.
*/
int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
unsigned rate = CLK_MULT_STD_FAST_MODE *
(clk_div_stdfst_mode + 1) * i2c_bus->speed * 2;
debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
clk_div_stdfst_mode);
i2c_init_clock(i2c_bus, rate);
}
/* Reset I2C controller. */
i2c_reset_controller(i2c_bus);
/* Configure I2C controller. */
if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
#ifndef CONFIG_TEGRA186
funcmux_select(i2c_bus->clk.id, i2c_bus->pinmux_config);
#endif
}
static void send_packet_headers(
struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans,
u32 packet_id,
bool end_with_repeated_start)
{
u32 data;
/* prepare header1: Header size = 0 Protocol = I2C, pktType = 0 */
data = PROTOCOL_TYPE_I2C << PKT_HDR1_PROTOCOL_SHIFT;
data |= packet_id << PKT_HDR1_PKT_ID_SHIFT;
data |= i2c_bus->id << PKT_HDR1_CTLR_ID_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 1 sent (0x%x)\n", data);
/* prepare header2 */
data = (trans->num_bytes - 1) << PKT_HDR2_PAYLOAD_SIZE_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 2 sent (0x%x)\n", data);
/* prepare IO specific header: configure the slave address */
data = trans->address << PKT_HDR3_SLAVE_ADDR_SHIFT;
/* Enable Read if it is not a write transaction */
if (!(trans->flags & I2C_IS_WRITE))
data |= PKT_HDR3_READ_MODE_MASK;
if (end_with_repeated_start)
data |= PKT_HDR3_REPEAT_START_MASK;
/* Write I2C specific header */
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 3 sent (0x%x)\n", data);
}
static int wait_for_tx_fifo_empty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_EMPTY_CNT_MASK)
>> TX_FIFO_EMPTY_CNT_SHIFT;
if (count == I2C_FIFO_DEPTH)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_rx_fifo_notempty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_FULL_CNT_MASK)
>> TX_FIFO_FULL_CNT_SHIFT;
if (count)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_transfer_complete(struct i2c_control *control)
{
int int_status;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
int_status = readl(&control->int_status);
if (int_status & I2C_INT_NO_ACK_MASK)
return -int_status;
if (int_status & I2C_INT_ARBITRATION_LOST_MASK)
return -int_status;
if (int_status & I2C_INT_XFER_COMPLETE_MASK)
return 0;
udelay(10);
timeout_us -= 10;
}
return -1;
}
static int send_recv_packets(struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans)
{
struct i2c_control *control = i2c_bus->control;
u32 int_status;
u32 words;
u8 *dptr;
u32 local;
uchar last_bytes;
int error = 0;
int is_write = trans->flags & I2C_IS_WRITE;
/* clear status from previous transaction, XFER_COMPLETE, NOACK, etc. */
int_status = readl(&control->int_status);
writel(int_status, &control->int_status);
send_packet_headers(i2c_bus, trans, 1,
trans->flags & I2C_USE_REPEATED_START);
words = DIV_ROUND_UP(trans->num_bytes, 4);
last_bytes = trans->num_bytes & 3;
dptr = trans->buf;
while (words) {
u32 *wptr = (u32 *)dptr;
if (is_write) {
/* deal with word alignment */
if ((words == 1) && last_bytes) {
local = 0;
memcpy(&local, dptr, last_bytes);
} else if ((unsigned long)dptr & 3) {
memcpy(&local, dptr, sizeof(u32));
} else {
local = *wptr;
}
writel(local, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", local);
if (!wait_for_tx_fifo_empty(control)) {
error = -1;
goto exit;
}
} else {
if (!wait_for_rx_fifo_notempty(control)) {
error = -1;
goto exit;
}
/*
* for the last word, we read into our local buffer,
* in case that caller did not provide enough buffer.
*/
local = readl(&control->rx_fifo);
if ((words == 1) && last_bytes)
memcpy(dptr, (char *)&local, last_bytes);
else if ((unsigned long)dptr & 3)
memcpy(dptr, &local, sizeof(u32));
else
*wptr = local;
debug("pkt data received (0x%x)\n", local);
}
words--;
dptr += sizeof(u32);
}
if (wait_for_transfer_complete(control)) {
error = -1;
goto exit;
}
return 0;
exit:
/* error, reset the controller. */
i2c_reset_controller(i2c_bus);
return error;
}
static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len, bool end_with_repeated_start)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr;
trans_info.buf = data;
trans_info.flags = I2C_IS_WRITE;
if (end_with_repeated_start)
trans_info.flags |= I2C_USE_REPEATED_START;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr | 1;
trans_info.buf = data;
trans_info.flags = 0;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->speed = speed;
i2c_init_controller(i2c_bus);
return 0;
}
static int tegra_i2c_probe(struct udevice *dev)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
int ret;
bool is_dvc;
i2c_bus->id = dev->seq;
i2c_bus->type = dev_get_driver_data(dev);
i2c_bus->regs = (struct i2c_ctlr *)dev_read_addr(dev);
if ((ulong)i2c_bus->regs == FDT_ADDR_T_NONE) {
debug("%s: Cannot get regs address\n", __func__);
return -EINVAL;
}
ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
if (ret) {
pr_err("reset_get_by_name() failed: %d\n", ret);
return ret;
}
ret = clk_get_by_name(dev, "div-clk", &i2c_bus->clk);
if (ret) {
pr_err("clk_get_by_name() failed: %d\n", ret);
return ret;
}
#ifndef CONFIG_TEGRA186
/*
* We don't have a binding for pinmux yet. Leave it out for now. So
* far no one needs anything other than the default.
*/
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
/*
* We can't specify the pinmux config in the fdt, so I2C2 will not
* work on Seaboard. It normally has no devices on it anyway.
* You could add in this little hack if you need to use it.
* The correct solution is a pinmux binding in the fdt.
*
* if (i2c_bus->clk.id == PERIPH_ID_I2C2)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
#endif
is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
} else {
i2c_bus->control = &i2c_bus->regs->control;
}
i2c_init_controller(i2c_bus);
debug("%s: controller bus %d at %p, speed %d: ",
is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, i2c_bus->speed);
return 0;
}
/* i2c write version without the register address */
static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
int len, bool end_with_repeated_start)
{
int rc;
debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
debug("write_data: ");
/* use rc for counter */
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
end_with_repeated_start);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
return rc;
}
/* i2c read version without the register address */
static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
}
debug("i2c_read_data: ");
/* reuse rc for counter*/
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
return 0;
}
/* Probe to see if a chip is present. */
static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
int rc;
u8 reg;
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
false);
return rc;
}
static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
int tegra_i2c_get_dvc_bus(struct udevice **busp)
{
struct udevice *bus;
for (uclass_first_device(UCLASS_I2C, &bus);
bus;
uclass_next_device(&bus)) {
if (dev_get_driver_data(bus) == TYPE_DVC) {
*busp = bus;
return 0;
}
}
return -ENODEV;
}
static const struct dm_i2c_ops tegra_i2c_ops = {
.xfer = tegra_i2c_xfer,
.probe_chip = tegra_i2c_probe_chip,
.set_bus_speed = tegra_i2c_set_bus_speed,
};
static const struct udevice_id tegra_i2c_ids[] = {
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
{ .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
{ }
};
U_BOOT_DRIVER(i2c_tegra) = {
.name = "i2c_tegra",
.id = UCLASS_I2C,
.of_match = tegra_i2c_ids,
.probe = tegra_i2c_probe,
.priv_auto_alloc_size = sizeof(struct i2c_bus),
.ops = &tegra_i2c_ops,
};
@@ -0,0 +1,352 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Xilinx AXI I2C driver
*
* Copyright (C) 2018 Marek Vasut <marex@denx.de>
*
* Based on Linux 4.14.y i2c-xiic.c
* Copyright (c) 2002-2007 Xilinx Inc.
* Copyright (c) 2009-2010 Intel Corporation
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <i2c.h>
#include <wait_bit.h>
#include <asm/io.h>
struct xilinx_xiic_priv {
void __iomem *base;
struct clk clk;
};
#define XIIC_MSB_OFFSET 0
#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
/*
* Register offsets in bytes from RegisterBase. Three is added to the
* base offset to access LSB (IBM style) of the word
*/
#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
/* Control Register masks */
#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
/* Status Register masks */
#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x80 /* 1 = Tx FIFO empty */
/* Interrupt Status Register masks Interrupt occurs when... */
#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete */
#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level */
#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
/* The following constants specify the depth of the FIFOs */
#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
/*
* Tx Fifo upper bit masks.
*/
#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
/*
* The following constants define the register offsets for the Interrupt
* registers. There are some holes in the memory map for reserved addresses
* to allow other registers to be added and still match the memory map of the
* interrupt controller registers
*/
#define XIIC_DGIER_OFFSET 0x1C /* Device Global Interrupt Enable Register */
#define XIIC_IISR_OFFSET 0x20 /* Interrupt Status Register */
#define XIIC_IIER_OFFSET 0x28 /* Interrupt Enable Register */
#define XIIC_RESETR_OFFSET 0x40 /* Reset Register */
#define XIIC_RESET_MASK 0xAUL
static u8 i2c_8bit_addr_from_flags(uint addr, u16 flags)
{
return (addr << 1) | (flags & I2C_M_RD ? 1 : 0);
}
static void xiic_irq_clr(struct xilinx_xiic_priv *priv, u32 mask)
{
u32 isr = readl(priv->base + XIIC_IISR_OFFSET);
writel(isr & mask, priv->base + XIIC_IISR_OFFSET);
}
static int xiic_read_rx(struct xilinx_xiic_priv *priv,
struct i2c_msg *msg, int nmsgs)
{
u8 bytes_in_fifo;
u32 pos = 0;
int i, ret;
while (pos < msg->len) {
ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
XIIC_SR_RX_FIFO_EMPTY_MASK, false,
1000, true);
if (ret)
return ret;
bytes_in_fifo = readb(priv->base + XIIC_RFO_REG_OFFSET) + 1;
if (bytes_in_fifo > msg->len)
bytes_in_fifo = msg->len;
for (i = 0; i < bytes_in_fifo; i++) {
msg->buf[pos++] = readb(priv->base +
XIIC_DRR_REG_OFFSET);
}
}
return 0;
}
static int xiic_tx_fifo_space(struct xilinx_xiic_priv *priv)
{
/* return the actual space left in the FIFO */
return IIC_TX_FIFO_DEPTH - readb(priv->base + XIIC_TFO_REG_OFFSET) - 1;
}
static void xiic_fill_tx_fifo(struct xilinx_xiic_priv *priv,
struct i2c_msg *msg, int nmsgs)
{
u8 fifo_space = xiic_tx_fifo_space(priv);
int len = msg->len;
u32 pos = 0;
len = (len > fifo_space) ? fifo_space : len;
while (len--) {
u16 data = msg->buf[pos++];
if ((msg->len - pos == 0) && nmsgs == 1) {
/* last message in transfer -> STOP */
data |= XIIC_TX_DYN_STOP_MASK;
}
writew(data, priv->base + XIIC_DTR_REG_OFFSET);
}
}
static void xilinx_xiic_set_addr(struct udevice *dev, u8 addr,
u16 flags, u32 len, u32 nmsgs)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
xiic_irq_clr(priv, XIIC_INTR_TX_ERROR_MASK);
if (!(flags & I2C_M_NOSTART)) {
/* write the address */
u16 data = i2c_8bit_addr_from_flags(addr, flags) |
XIIC_TX_DYN_START_MASK;
if (nmsgs == 1 && len == 0)
/* no data and last message -> add STOP */
data |= XIIC_TX_DYN_STOP_MASK;
writew(data, priv->base + XIIC_DTR_REG_OFFSET);
}
}
static int xilinx_xiic_read_common(struct udevice *dev, struct i2c_msg *msg,
u32 nmsgs)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
u8 rx_watermark;
/* Clear and enable Rx full interrupt. */
xiic_irq_clr(priv, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
/* we want to get all but last byte, because the TX_ERROR IRQ is used
* to inidicate error ACK on the address, and negative ack on the last
* received byte, so to not mix them receive all but last.
* In the case where there is only one byte to receive
* we can check if ERROR and RX full is set at the same time
*/
rx_watermark = msg->len;
if (rx_watermark > IIC_RX_FIFO_DEPTH)
rx_watermark = IIC_RX_FIFO_DEPTH;
writeb(rx_watermark - 1, priv->base + XIIC_RFD_REG_OFFSET);
xilinx_xiic_set_addr(dev, msg->addr, msg->flags, msg->len, nmsgs);
xiic_irq_clr(priv, XIIC_INTR_BNB_MASK);
writew((msg->len & 0xff) | ((nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0),
priv->base + XIIC_DTR_REG_OFFSET);
if (nmsgs == 1)
/* very last, enable bus not busy as well */
xiic_irq_clr(priv, XIIC_INTR_BNB_MASK);
return xiic_read_rx(priv, msg, nmsgs);
}
static int xilinx_xiic_write_common(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
int ret;
xilinx_xiic_set_addr(dev, msg->addr, msg->flags, msg->len, nmsgs);
xiic_fill_tx_fifo(priv, msg, nmsgs);
ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
XIIC_SR_TX_FIFO_EMPTY_MASK, false, 1000, true);
if (ret)
return ret;
/* Clear any pending Tx empty, Tx Error and then enable them. */
xiic_irq_clr(priv, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
XIIC_INTR_BNB_MASK);
return 0;
}
static void xiic_clear_rx_fifo(struct xilinx_xiic_priv *priv)
{
u8 sr;
for (sr = readb(priv->base + XIIC_SR_REG_OFFSET);
!(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
sr = readb(priv->base + XIIC_SR_REG_OFFSET))
readb(priv->base + XIIC_DRR_REG_OFFSET);
}
static void xiic_reinit(struct xilinx_xiic_priv *priv)
{
writel(XIIC_RESET_MASK, priv->base + XIIC_RESETR_OFFSET);
/* Set receive Fifo depth to maximum (zero based). */
writeb(IIC_RX_FIFO_DEPTH - 1, priv->base + XIIC_RFD_REG_OFFSET);
/* Reset Tx Fifo. */
writeb(XIIC_CR_TX_FIFO_RESET_MASK, priv->base + XIIC_CR_REG_OFFSET);
/* Enable IIC Device, remove Tx Fifo reset & disable general call. */
writeb(XIIC_CR_ENABLE_DEVICE_MASK, priv->base + XIIC_CR_REG_OFFSET);
/* make sure RX fifo is empty */
xiic_clear_rx_fifo(priv);
/* Disable interrupts */
writel(0, priv->base + XIIC_DGIER_OFFSET);
xiic_irq_clr(priv, XIIC_INTR_ARB_LOST_MASK);
}
static int xilinx_xiic_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
int ret = 0;
ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
XIIC_SR_BUS_BUSY_MASK, false, 1000, true);
if (ret == -ETIMEDOUT)
dev_err(dev, "timeout waiting for bus not busy condition\n");
if (ret)
return ret;
xiic_reinit(priv);
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD)
ret = xilinx_xiic_read_common(dev, msg, nmsgs);
else
ret = xilinx_xiic_write_common(dev, msg, nmsgs);
if (ret)
return -EREMOTEIO;
}
return ret;
}
static int xilinx_xiic_probe_chip(struct udevice *dev, uint addr, uint flags)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
u32 reg;
int ret;
xiic_reinit(priv);
xilinx_xiic_set_addr(dev, addr, 0, 0, 1);
ret = wait_for_bit_8(priv->base + XIIC_SR_REG_OFFSET,
XIIC_SR_BUS_BUSY_MASK, false, 1000, true);
if (ret)
return ret;
reg = readl(priv->base + XIIC_IISR_OFFSET);
if (reg & XIIC_INTR_TX_ERROR_MASK)
return -ENODEV;
return 0;
}
static int xilinx_xiic_set_speed(struct udevice *dev, uint speed)
{
return 0;
}
static int xilinx_xiic_probe(struct udevice *dev)
{
struct xilinx_xiic_priv *priv = dev_get_priv(dev);
priv->base = dev_read_addr_ptr(dev);
writel(XIIC_CR_TX_FIFO_RESET_MASK, priv->base + XIIC_CR_REG_OFFSET);
xiic_reinit(priv);
return 0;
}
static const struct dm_i2c_ops xilinx_xiic_ops = {
.xfer = xilinx_xiic_xfer,
.probe_chip = xilinx_xiic_probe_chip,
.set_bus_speed = xilinx_xiic_set_speed,
};
static const struct udevice_id xilinx_xiic_ids[] = {
{ .compatible = "xlnx,xps-iic-2.00.a" },
{ }
};
U_BOOT_DRIVER(xilinx_xiic) = {
.name = "xilinx_axi_i2c",
.id = UCLASS_I2C,
.of_match = xilinx_xiic_ids,
.probe = xilinx_xiic_probe,
.priv_auto_alloc_size = sizeof(struct xilinx_xiic_priv),
.ops = &xilinx_xiic_ops,
};