summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-24 17:12:23 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-24 17:12:23 -0800
commit008128cd5948bd3589a9c300e426af4d834029bb (patch)
treebbcb4308c9d7004ced3bd87ca213d60a8760753e /drivers
parent39f013440dbf5b1f209eadb3b4665d4f0e840b5b (diff)
parente8444bb9fd77f153adcc263eab28e3c2bc1cf540 (diff)
Merge tag 'i2c-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - new drivers for HPE GXP and Loongson 2K/LS7A - bigger refactorings for i801 and xiic - gpio driver gained ACPI and SDA-write only support - the core converted some OF helpers to fwnode helpers - usual bunch of driver updates * tag 'i2c-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (52 commits) MAINTAINERS: Add HPE GXP I2C Support i2c: Add GXP SoC I2C Controller dt-bindings: i2c: Add hpe,gxp-i2c i2c: xiic: Remove some dead code i2c: xiic: Add SCL frequency configuration support i2c: xiic: Update compatible with new IP version dt-bindings: i2c: xiic: Add 'xlnx,axi-iic-2.1' to compatible i2c: i801: Call i801_check_post() from i801_access() i2c: i801: Call i801_check_pre() from i801_access() i2c: i801: Centralize configuring block commands in i801_block_transaction i2c: i801: Centralize configuring non-block commands in i801_simple_transaction i2c: i801: Handle SMBAUXCTL_E32B in i801_block_transaction_by_block only i2c: i801: Add i801_simple_transaction(), complementing i801_block_transaction() Documentation: i2c: correct spelling dt-bindings: i2c: i2c-st: convert to DT schema i2c: i801: add helper i801_set_hstadd() i2c: i801: make FEATURE_BLOCK_PROC dependent on FEATURE_BLOCK_BUFFER i2c: i801: make FEATURE_HOST_NOTIFY dependent on FEATURE_IRQ i2c: i801: improve interrupt handler i2c: st: use pm_sleep_ptr to avoid ifdef CONFIG_PM_SLEEP ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c77
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c4
-rw-r--r--drivers/i2c/busses/i2c-au1550.c4
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c4
-rw-r--r--drivers/i2c/busses/i2c-cadence.c23
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c13
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h5
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c33
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c4
-rw-r--r--drivers/i2c/busses/i2c-gpio.c47
-rw-r--r--drivers/i2c/busses/i2c-gxp.c620
-rw-r--r--drivers/i2c/busses/i2c-i801.c310
-rw-r--r--drivers/i2c/busses/i2c-ls2x.c370
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c7
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c8
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c2
-rw-r--r--drivers/i2c/busses/i2c-st.c9
-rw-r--r--drivers/i2c/busses/i2c-xiic.c586
-rw-r--r--drivers/i2c/i2c-core-base.c5
-rw-r--r--drivers/i2c/i2c-dev.c16
22 files changed, 1833 insertions, 334 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index fc90293afcbf..eddf25b90ca8 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -184,8 +184,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
+ * Always report ACK if SDA is write-only.
*/
- ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ ack = !adap->getsda || !getsda(adap); /* ack: sda is pulled low -> success */
bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
ack ? "A" : "NA");
@@ -238,71 +239,55 @@ static int test_bus(struct i2c_adapter *i2c_adap)
return -ENODEV;
}
+ if (adap->getsda == NULL)
+ pr_info("%s: SDA is write-only, testing not possible\n", name);
if (adap->getscl == NULL)
- pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+ pr_info("%s: SCL is write-only, testing not possible\n", name);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ sda = adap->getsda ? getsda(adap) : 1;
+ scl = adap->getscl ? getscl(adap) : 1;
if (!scl || !sda) {
- printk(KERN_WARNING
- "%s: bus seems to be busy (scl=%d, sda=%d)\n",
- name, scl, sda);
+ pr_warn("%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda);
goto bailout;
}
sdalo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (sda) {
- printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ if (adap->getsda && getsda(adap)) {
+ pr_warn("%s: SDA stuck high!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING
- "%s: SCL unexpected low while pulling SDA low!\n",
- name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA low!\n", name);
goto bailout;
}
sdahi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!sda) {
- printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA stuck low!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING
- "%s: SCL unexpected low while pulling SDA high!\n",
- name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA high!\n", name);
goto bailout;
}
scllo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 0 : getscl(adap);
- if (scl) {
- printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ if (adap->getscl && getscl(adap)) {
+ pr_warn("%s: SCL stuck high!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING
- "%s: SDA unexpected low while pulling SCL low!\n",
- name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL low!\n", name);
goto bailout;
}
sclhi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!scl) {
- printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL stuck low!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING
- "%s: SDA unexpected low while pulling SCL high!\n",
- name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL high!\n", name);
goto bailout;
}
@@ -420,6 +405,10 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ if (!adap->getsda)
+ return -EOPNOTSUPP;
while (count > 0) {
inval = i2c_inb(i2c_adap);
@@ -670,11 +659,15 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (ret < 0)
return ret;
- /* Complain if SCL can't be read */
- if (bit_adap->getscl == NULL) {
+ if (bit_adap->getsda == NULL)
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SDA\n");
+
+ if (bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+
+ if (bit_adap->getsda == NULL || bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Bus may be unreliable\n");
- }
+
return 0;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d4975444a32d..9b8e84f20604 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -659,6 +659,13 @@ config I2C_GPIO_FAULT_INJECTOR
faults to an I2C bus, so another bus master can be stress-tested.
This is for debugging. If unsure, say 'no'.
+config I2C_GXP
+ tristate "GXP I2C Interface"
+ depends on ARCH_HPE_GXP || COMPILE_TEST
+ help
+ This enables support for GXP I2C interface. The I2C engines can be
+ either I2C master or I2C slaves.
+
config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER || COMPILE_TEST
@@ -761,6 +768,17 @@ config I2C_LPC2K
This driver can also be built as a module. If so, the module
will be called i2c-lpc2k.
+config I2C_LS2X
+ tristate "Loongson LS2X I2C adapter"
+ depends on MACH_LOONGSON64 || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge
+ chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ls2x.
+
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on MELLANOX_PLATFORM && ARM64
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e73cdb1d2b5a..af56fe2c75c0 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
+obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
@@ -127,6 +128,7 @@ obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
+obj-$(CONFIG_I2C_GXP) += i2c-gxp.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index c64c381b69b7..d3c99c5b3247 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -979,15 +979,13 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
const struct of_device_id *match;
struct aspeed_i2c_bus *bus;
struct clk *parent_clk;
- struct resource *res;
int irq, ret;
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- bus->base = devm_ioremap_resource(&pdev->dev, res);
+ bus->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(bus->base))
return PTR_ERR(bus->base);
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 99bd24d0e6a5..7b42d35b1294 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -302,7 +302,6 @@ static int
i2c_au1550_probe(struct platform_device *pdev)
{
struct i2c_au1550_data *priv;
- struct resource *r;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
@@ -310,8 +309,7 @@ i2c_au1550_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
+ priv->psc_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->psc_base))
return PTR_ERR(priv->psc_base);
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index f72c6576d8a3..09a077b31bfe 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -407,7 +407,6 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
- struct resource *mem;
int ret;
struct i2c_adapter *adap;
struct clk *mclk;
@@ -420,8 +419,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
i2c_dev->dev = &pdev->dev;
init_completion(&i2c_dev->completion);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
+ i2c_dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c_dev->regs))
return PTR_ERR(i2c_dev->regs);
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index f58943cb1341..b5d22e7282c2 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -115,8 +115,6 @@
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16
-/* FIFO depth at which the DATA interrupt occurs */
-#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
@@ -175,7 +173,6 @@ enum cdns_i2c_slave_state {
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
- * @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
@@ -200,7 +197,6 @@ struct cdns_i2c {
unsigned int send_count;
unsigned int recv_count;
unsigned int curr_recv_count;
- int irq;
unsigned long input_clk;
unsigned int i2c_clk;
unsigned int bus_hold_flag;
@@ -616,9 +612,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
}
/* Determine hold_clear based on number of bytes to receive and hold flag */
- if (!id->bus_hold_flag &&
- ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
- (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
+ if (!id->bus_hold_flag && id->recv_count <= CDNS_I2C_FIFO_DEPTH) {
if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
hold_clear = true;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
@@ -1246,7 +1240,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
{
struct resource *r_mem;
struct cdns_i2c *id;
- int ret;
+ int ret, irq;
const struct of_device_id *match;
id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
@@ -1277,10 +1271,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
- id->irq = ret;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
id->adap.owner = THIS_MODULE;
id->adap.dev.of_node = pdev->dev.of_node;
@@ -1331,10 +1324,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
}
- ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
+ ret = devm_request_irq(&pdev->dev, irq, cdns_i2c_isr, 0,
DRIVER_NAME, id);
if (ret) {
- dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ dev_err(&pdev->dev, "cannot get irq %d\n", irq);
goto err_clk_dis;
}
cdns_i2c_init(id);
@@ -1344,7 +1337,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
- id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
+ id->i2c_clk / 1000, (unsigned long)r_mem->start, irq);
return 0;
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 581e02cc979a..0dc6b1ce663f 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -391,7 +391,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
{
- u32 reg;
+ unsigned int reg;
int ret;
ret = i2c_dw_acquire_lock(dev);
@@ -442,7 +442,7 @@ err_release_lock:
void __i2c_dw_disable(struct dw_i2c_dev *dev)
{
int timeout = 100;
- u32 status;
+ unsigned int status;
do {
__i2c_dw_disable_nowait(dev);
@@ -465,7 +465,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
dev_warn(dev->dev, "timeout in disabling adapter\n");
}
-unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev)
{
/*
* Clock is not necessary if we got LCNT/HCNT values directly from
@@ -527,7 +527,7 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev)
*/
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
{
- u32 status;
+ unsigned int status;
int ret;
ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
@@ -571,7 +571,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
{
- u32 param, tx_fifo_depth, rx_fifo_depth;
+ u32 tx_fifo_depth, rx_fifo_depth;
+ unsigned int param;
int ret;
/*
@@ -611,7 +612,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
- u32 dummy;
+ unsigned int dummy;
int ret;
ret = i2c_dw_acquire_lock(dev);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 95ebc5eaa5d1..050d8c63ad3c 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -37,6 +37,7 @@
#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
#define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
+#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11)
#define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
@@ -264,7 +265,7 @@ struct dw_i2c_dev {
u8 *rx_buf;
int msg_err;
unsigned int status;
- u32 abort_source;
+ unsigned int abort_source;
int irq;
u32 flags;
struct i2c_adapter adapter;
@@ -320,7 +321,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
-unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
+u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev);
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 45f569155bfe..55ea91a63382 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -39,7 +39,7 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
- u32 comp_param1;
+ unsigned int comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
const char *fp_str = "";
@@ -211,7 +211,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
u32 ic_con = 0, ic_tar = 0;
- u32 dummy;
+ unsigned int dummy;
/* Disable the adapter */
__i2c_dw_disable(dev);
@@ -287,7 +287,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
int cmd = 0, status;
u8 *tx_buf;
- u32 val;
+ unsigned int val;
/*
* In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card,
@@ -505,7 +505,8 @@ i2c_dw_read(struct dw_i2c_dev *dev)
unsigned int rx_valid;
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
- u32 len, tmp;
+ unsigned int tmp;
+ u32 len;
u8 *buf;
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
@@ -653,7 +654,7 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
- u32 stat, dummy;
+ unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -714,7 +715,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
- u32 stat, enabled;
+ unsigned int stat, enabled;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
@@ -865,6 +866,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
unsigned long irq_flags;
+ unsigned int ic_con;
int ret;
init_completion(&dev->cmd_complete);
@@ -884,6 +886,25 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
if (ret)
return ret;
+ /* Lock the bus for accessing DW_IC_CON */
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * On AMD platforms BIOS advertises the bus clear feature
+ * and enables the SCL/SDA stuck low. SMU FW does the
+ * bus recovery process. Driver should not ignore this BIOS
+ * advertisement of bus clear feature.
+ */
+ ret = regmap_read(dev->map, DW_IC_CON, &ic_con);
+ i2c_dw_release_lock(dev);
+ if (ret)
+ return ret;
+
+ if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL)
+ dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL;
+
ret = dev->init(dev);
if (ret)
return ret;
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index c6d2e4c2ac23..cec25054bb24 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -98,7 +98,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
{
- u32 stat, dummy;
+ unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -150,7 +150,7 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
- u32 raw_stat, stat, enabled, tmp;
+ unsigned int raw_stat, stat, enabled, tmp;
u8 val = 0, slave_activity;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 0e4385a9bcf7..1794c0399f22 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -13,9 +13,9 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
struct i2c_gpio_private_data {
@@ -300,22 +300,29 @@ static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
-static void of_i2c_gpio_get_props(struct device_node *np,
- struct i2c_gpio_platform_data *pdata)
+/* Get i2c-gpio properties from DT or ACPI table */
+static void i2c_gpio_get_properties(struct device *dev,
+ struct i2c_gpio_platform_data *pdata)
{
u32 reg;
- of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+ device_property_read_u32(dev, "i2c-gpio,delay-us", &pdata->udelay);
- if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+ if (!device_property_read_u32(dev, "i2c-gpio,timeout-ms", &reg))
pdata->timeout = msecs_to_jiffies(reg);
pdata->sda_is_open_drain =
- of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+ device_property_read_bool(dev, "i2c-gpio,sda-open-drain");
pdata->scl_is_open_drain =
- of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+ device_property_read_bool(dev, "i2c-gpio,scl-open-drain");
pdata->scl_is_output_only =
- of_property_read_bool(np, "i2c-gpio,scl-output-only");
+ device_property_read_bool(dev, "i2c-gpio,scl-output-only");
+ pdata->sda_is_output_only =
+ device_property_read_bool(dev, "i2c-gpio,sda-output-only");
+ pdata->sda_has_no_pullup =
+ device_property_read_bool(dev, "i2c-gpio,sda-has-no-pullup");
+ pdata->scl_has_no_pullup =
+ device_property_read_bool(dev, "i2c-gpio,scl-has-no-pullup");
}
static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
@@ -361,7 +368,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
enum gpiod_flags gflags;
int ret;
@@ -373,8 +380,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data = &priv->bit_data;
pdata = &priv->pdata;
- if (np) {
- of_i2c_gpio_get_props(np, pdata);
+ if (fwnode) {
+ i2c_gpio_get_properties(dev, pdata);
} else {
/*
* If all platform data settings are zero it is OK
@@ -392,7 +399,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
* handle them as we handle any other output. Else we enforce open
* drain as this is required for an I2C bus.
*/
- if (pdata->sda_is_open_drain)
+ if (pdata->sda_is_open_drain || pdata->sda_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
@@ -400,7 +407,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->sda))
return PTR_ERR(priv->sda);
- if (pdata->scl_is_open_drain)
+ if (pdata->scl_is_open_drain || pdata->scl_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
@@ -418,7 +425,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
- bit_data->getsda = i2c_gpio_getsda;
+ if (!pdata->sda_is_output_only)
+ bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
@@ -435,7 +443,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data->data = priv;
adap->owner = THIS_MODULE;
- if (np)
+ if (fwnode)
strscpy(adap->name, dev_name(dev), sizeof(adap->name));
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
@@ -443,7 +451,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->dev.parent = dev;
- adap->dev.of_node = np;
+ device_set_node(&adap->dev, fwnode);
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
@@ -489,10 +497,17 @@ static const struct of_device_id i2c_gpio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+static const struct acpi_device_id i2c_gpio_acpi_match[] = {
+ { "LOON0005" }, /* LoongArch */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, i2c_gpio_acpi_match);
+
static struct platform_driver i2c_gpio_driver = {
.driver = {
.name = "i2c-gpio",
.of_match_table = i2c_gpio_dt_ids,
+ .acpi_match_table = i2c_gpio_acpi_match,
},
.probe = i2c_gpio_probe,
.remove = i2c_gpio_remove,
diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c
new file mode 100644
index 000000000000..da4c8e5a8039
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gxp.c
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define GXP_MAX_I2C_ENGINE 10
+static const char * const gxp_i2c_name[] = {
+ "gxp-i2c0", "gxp-i2c1", "gxp-i2c2", "gxp-i2c3",
+ "gxp-i2c4", "gxp-i2c5", "gxp-i2c6", "gxp-i2c7",
+ "gxp-i2c8", "gxp-i2c9" };
+
+/* GXP I2C Global interrupt status/enable register*/
+#define GXP_I2CINTSTAT 0x00
+#define GXP_I2CINTEN 0x04
+
+/* GXP I2C registers */
+#define GXP_I2CSTAT 0x00
+#define MASK_STOP_EVENT 0x20
+#define MASK_ACK 0x08
+#define MASK_RW 0x04
+#define GXP_I2CEVTERR 0x01
+#define MASK_SLAVE_CMD_EVENT 0x01
+#define MASK_SLAVE_DATA_EVENT 0x02
+#define MASK_MASTER_EVENT 0x10
+#define GXP_I2CSNPDAT 0x02
+#define GXP_I2CMCMD 0x04
+#define GXP_I2CSCMD 0x06
+#define GXP_I2CSNPAA 0x09
+#define GXP_I2CADVFEAT 0x0A
+#define GXP_I2COWNADR 0x0B
+#define GXP_I2CFREQDIV 0x0C
+#define GXP_I2CFLTFAIR 0x0D
+#define GXP_I2CTMOEDG 0x0E
+#define GXP_I2CCYCTIM 0x0F
+
+/* I2CSCMD Bits */
+#define SNOOP_EVT_CLR 0x80
+#define SLAVE_EVT_CLR 0x40
+#define SNOOP_EVT_MASK 0x20
+#define SLAVE_EVT_MASK 0x10
+#define SLAVE_ACK_ENAB 0x08
+#define SLAVE_EVT_STALL 0x01
+
+/* I2CMCMD Bits */
+#define MASTER_EVT_CLR 0x80
+#define MASTER_ACK_ENAB 0x08
+#define RW_CMD 0x04
+#define STOP_CMD 0x02
+#define START_CMD 0x01
+
+/* I2CTMOEDG value */
+#define GXP_DATA_EDGE_RST_CTRL 0x0a /* 30ns */
+
+/* I2CFLTFAIR Bits */
+#define FILTER_CNT 0x30
+#define FAIRNESS_CNT 0x02
+
+enum {
+ GXP_I2C_IDLE = 0,
+ GXP_I2C_ADDR_PHASE,
+ GXP_I2C_RDATA_PHASE,
+ GXP_I2C_WDATA_PHASE,
+ GXP_I2C_ADDR_NACK,
+ GXP_I2C_DATA_NACK,
+ GXP_I2C_ERROR,
+ GXP_I2C_COMP
+};
+
+struct gxp_i2c_drvdata {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_timings t;
+ u32 engine;
+ int irq;
+ struct completion completion;
+ struct i2c_adapter adapter;
+ struct i2c_msg *curr_msg;
+ int msgs_remaining;
+ int msgs_num;
+ u8 *buf;
+ size_t buf_remaining;
+ unsigned char state;
+ struct i2c_client *slave;
+ unsigned char stopped;
+};
+
+static struct regmap *i2cg_map;
+
+static void gxp_i2c_start(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ drvdata->buf = drvdata->curr_msg->buf;
+ drvdata->buf_remaining = drvdata->curr_msg->len;
+
+ /* Note: Address in struct i2c_msg is 7 bits */
+ value = drvdata->curr_msg->addr << 9;
+
+ /* Read or Write */
+ value |= drvdata->curr_msg->flags & I2C_M_RD ? RW_CMD | START_CMD : START_CMD;
+
+ drvdata->state = GXP_I2C_ADDR_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+static int gxp_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ int ret;
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(adapter);
+ unsigned long time_left;
+
+ drvdata->msgs_remaining = num;
+ drvdata->curr_msg = msgs;
+ drvdata->msgs_num = num;
+ reinit_completion(&drvdata->completion);
+
+ gxp_i2c_start(drvdata);
+
+ time_left = wait_for_completion_timeout(&drvdata->completion,
+ adapter->timeout);
+ ret = num - drvdata->msgs_remaining;
+ if (time_left == 0) {
+ switch (drvdata->state) {
+ case GXP_I2C_WDATA_PHASE:
+ break;
+ case GXP_I2C_RDATA_PHASE:
+ break;
+ case GXP_I2C_ADDR_PHASE:
+ break;
+ default:
+ break;
+ }
+ return -ETIMEDOUT;
+ }
+
+ if (drvdata->state == GXP_I2C_ADDR_NACK ||
+ drvdata->state == GXP_I2C_DATA_NACK)
+ return -EIO;
+
+ return ret;
+}
+
+static u32 gxp_i2c_func(struct i2c_adapter *adap)
+{
+ if (IS_ENABLED(CONFIG_I2C_SLAVE))
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static int gxp_i2c_reg_slave(struct i2c_client *slave)
+{
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
+
+ if (drvdata->slave)
+ return -EBUSY;
+
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ drvdata->slave = slave;
+
+ writeb(slave->addr << 1, drvdata->base + GXP_I2COWNADR);
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | SLAVE_ACK_ENAB |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+
+ return 0;
+}
+
+static int gxp_i2c_unreg_slave(struct i2c_client *slave)
+{
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
+
+ WARN_ON(!drvdata->slave);
+
+ writeb(0x00, drvdata->base + GXP_I2COWNADR);
+ writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
+
+ drvdata->slave = NULL;
+
+ return 0;
+}
+#endif
+
+static const struct i2c_algorithm gxp_i2c_algo = {
+ .master_xfer = gxp_i2c_master_xfer,
+ .functionality = gxp_i2c_func,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_slave = gxp_i2c_reg_slave,
+ .unreg_slave = gxp_i2c_unreg_slave,
+#endif
+};
+
+static void gxp_i2c_stop(struct gxp_i2c_drvdata *drvdata)
+{
+ /* Clear event and send stop */
+ writeb(MASTER_EVT_CLR | STOP_CMD, drvdata->base + GXP_I2CMCMD);
+
+ complete(&drvdata->completion);
+}
+
+static void gxp_i2c_restart(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ drvdata->buf = drvdata->curr_msg->buf;
+ drvdata->buf_remaining = drvdata->curr_msg->len;
+
+ value = drvdata->curr_msg->addr << 9;
+
+ if (drvdata->curr_msg->flags & I2C_M_RD) {
+ /* Read and clear master event */
+ value |= MASTER_EVT_CLR | RW_CMD | START_CMD;
+ } else {
+ /* Write and clear master event */
+ value |= MASTER_EVT_CLR | START_CMD;
+ }
+
+ drvdata->state = GXP_I2C_ADDR_PHASE;
+
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+static void gxp_i2c_chk_addr_ack(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ if (!(value & MASK_ACK)) {
+ /* Got no ack, stop */
+ drvdata->state = GXP_I2C_ADDR_NACK;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+
+ if (drvdata->curr_msg->flags & I2C_M_RD) {
+ /* Start to read data from slave */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data to read, stop */
+ drvdata->msgs_remaining--;
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ drvdata->state = GXP_I2C_RDATA_PHASE;
+
+ if (drvdata->buf_remaining == 1) {
+ /* The last data, do not ack */
+ writeb(MASTER_EVT_CLR | RW_CMD,
+ drvdata->base + GXP_I2CMCMD);
+ } else {
+ /* Read data and ack it */
+ writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
+ RW_CMD, drvdata->base + GXP_I2CMCMD);
+ }
+ } else {
+ /* Start to write first data to slave */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data to write, stop */
+ drvdata->msgs_remaining--;
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ value = *drvdata->buf;
+ value = value << 8;
+ /* Clear master event */
+ value |= MASTER_EVT_CLR;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+ drvdata->state = GXP_I2C_WDATA_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+ }
+}
+
+static void gxp_i2c_ack_data(struct gxp_i2c_drvdata *drvdata)
+{
+ u8 value;
+
+ /* Store the data returned */
+ value = readb(drvdata->base + GXP_I2CSNPDAT);
+ *drvdata->buf = value;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+
+ if (drvdata->buf_remaining == 0) {
+ /* No more data, this message is completed. */
+ drvdata->msgs_remaining--;
+
+ if (drvdata->msgs_remaining == 0) {
+ /* No more messages, stop */
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ /* Move to next message and start transfer */
+ drvdata->curr_msg++;
+ gxp_i2c_restart(drvdata);
+ return;
+ }
+
+ /* Ack the slave to make it send next byte */
+ drvdata->state = GXP_I2C_RDATA_PHASE;
+ if (drvdata->buf_remaining == 1) {
+ /* The last data, do not ack */
+ writeb(MASTER_EVT_CLR | RW_CMD,
+ drvdata->base + GXP_I2CMCMD);
+ } else {
+ /* Read data and ack it */
+ writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
+ RW_CMD, drvdata->base + GXP_I2CMCMD);
+ }
+}
+
+static void gxp_i2c_chk_data_ack(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ if (!(value & MASK_ACK)) {
+ /* Received No ack, stop */
+ drvdata->state = GXP_I2C_DATA_NACK;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+
+ /* Got ack, check if there is more data to write */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data, this message is completed */
+ drvdata->msgs_remaining--;
+
+ if (drvdata->msgs_remaining == 0) {
+ /* No more messages, stop */
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ /* Move to next message and start transfer */
+ drvdata->curr_msg++;
+ gxp_i2c_restart(drvdata);
+ return;
+ }
+
+ /* Write data to slave */
+ value = *drvdata->buf;
+ value = value << 8;
+
+ /* Clear master event */
+ value |= MASTER_EVT_CLR;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+ drvdata->state = GXP_I2C_WDATA_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata)
+{
+ u8 value;
+ u8 buf;
+ int ret;
+
+ value = readb(drvdata->base + GXP_I2CEVTERR);
+
+ /* Received start or stop event */
+ if (value & MASK_SLAVE_CMD_EVENT) {
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ /* Master sent stop */
+ if (value & MASK_STOP_EVENT) {
+ if (drvdata->stopped == 0)
+ i2c_slave_event(drvdata->slave, I2C_SLAVE_STOP, &buf);
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ drvdata->stopped = 1;
+ } else {
+ /* Master sent start and wants to read */
+ drvdata->stopped = 0;
+ if (value & MASK_RW) {
+ i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_READ_REQUESTED, &buf);
+ value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL);
+ writew(value, drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Master wants to write to us */
+ ret = i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_WRITE_REQUESTED, &buf);
+ if (!ret) {
+ /* Ack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Nack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ }
+ }
+ }
+ } else if (value & MASK_SLAVE_DATA_EVENT) {
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ /* Master wants to read */
+ if (value & MASK_RW) {
+ /* Master wants another byte */
+ if (value & MASK_ACK) {
+ i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_READ_PROCESSED, &buf);
+ value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL);
+ writew(value, drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* No more bytes needed */
+ writew(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ }
+ } else {
+ /* Master wants to write to us */
+ value = readb(drvdata->base + GXP_I2CSNPDAT);
+ buf = (uint8_t)value;
+ ret = i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &buf);
+ if (!ret) {
+ /* Ack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Nack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+static irqreturn_t gxp_i2c_irq_handler(int irq, void *_drvdata)
+{
+ struct gxp_i2c_drvdata *drvdata = (struct gxp_i2c_drvdata *)_drvdata;
+ u32 value;
+
+ /* Check if the interrupt is for the current engine */
+ regmap_read(i2cg_map, GXP_I2CINTSTAT, &value);
+ if (!(value & BIT(drvdata->engine)))
+ return IRQ_NONE;
+
+ value = readb(drvdata->base + GXP_I2CEVTERR);
+
+ /* Error */
+ if (value & ~(MASK_MASTER_EVENT | MASK_SLAVE_CMD_EVENT |
+ MASK_SLAVE_DATA_EVENT)) {
+ /* Clear all events */
+ writeb(0x00, drvdata->base + GXP_I2CEVTERR);
+ drvdata->state = GXP_I2C_ERROR;
+ gxp_i2c_stop(drvdata);
+ return IRQ_HANDLED;
+ }
+
+ if (IS_ENABLED(CONFIG_I2C_SLAVE)) {
+ /* Slave mode */
+ if (value & (MASK_SLAVE_CMD_EVENT | MASK_SLAVE_DATA_EVENT)) {
+ if (gxp_i2c_slave_irq_handler(drvdata))
+ return IRQ_HANDLED;
+ return IRQ_NONE;
+ }
+ }
+
+ /* Master mode */
+ switch (drvdata->state) {
+ case GXP_I2C_ADDR_PHASE:
+ gxp_i2c_chk_addr_ack(drvdata);
+ break;
+
+ case GXP_I2C_RDATA_PHASE:
+ gxp_i2c_ack_data(drvdata);
+ break;
+
+ case GXP_I2C_WDATA_PHASE:
+ gxp_i2c_chk_data_ack(drvdata);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void gxp_i2c_init(struct gxp_i2c_drvdata *drvdata)
+{
+ drvdata->state = GXP_I2C_IDLE;
+ writeb(2000000 / drvdata->t.bus_freq_hz,
+ drvdata->base + GXP_I2CFREQDIV);
+ writeb(FILTER_CNT | FAIRNESS_CNT,
+ drvdata->base + GXP_I2CFLTFAIR);
+ writeb(GXP_DATA_EDGE_RST_CTRL, drvdata->base + GXP_I2CTMOEDG);
+ writeb(0x00, drvdata->base + GXP_I2CCYCTIM);
+ writeb(0x00, drvdata->base + GXP_I2CSNPAA);
+ writeb(0x00, drvdata->base + GXP_I2CADVFEAT);
+ writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
+ writeb(MASTER_EVT_CLR, drvdata->base + GXP_I2CMCMD);
+ writeb(0x00, drvdata->base + GXP_I2CEVTERR);
+ writeb(0x00, drvdata->base + GXP_I2COWNADR);
+}
+
+static int gxp_i2c_probe(struct platform_device *pdev)
+{
+ struct gxp_i2c_drvdata *drvdata;
+ int rc;
+ struct i2c_adapter *adapter;
+
+ if (!i2cg_map) {
+ i2cg_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "hpe,sysreg");
+ if (IS_ERR(i2cg_map)) {
+ return dev_err_probe(&pdev->dev, IS_ERR(i2cg_map),
+ "failed to map i2cg_handle\n");
+ }
+
+ /* Disable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, 0x00000FFF, 0);
+ }
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata),
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drvdata);
+ drvdata->dev = &pdev->dev;
+ init_completion(&drvdata->completion);
+
+ drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(drvdata->base))
+ return PTR_ERR(drvdata->base);
+
+ /* Use physical memory address to determine which I2C engine this is. */
+ drvdata->engine = ((size_t)drvdata->base & 0xf00) >> 8;
+
+ if (drvdata->engine >= GXP_MAX_I2C_ENGINE) {
+ return dev_err_probe(&pdev->dev, -EINVAL, "i2c engine% is unsupported\n",
+ drvdata->engine);
+ }
+
+ rc = platform_get_irq(pdev, 0);
+ if (rc < 0)
+ return rc;
+
+ drvdata->irq = rc;
+ rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler,
+ IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata);
+ if (rc < 0)
+ return dev_err_probe(&pdev->dev, rc, "irq request failed\n");
+
+ i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true);
+
+ gxp_i2c_init(drvdata);
+
+ /* Enable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine),
+ BIT(drvdata->engine));
+
+ adapter = &drvdata->adapter;
+ i2c_set_adapdata(adapter, drvdata);
+
+ adapter->owner = THIS_MODULE;
+ strscpy(adapter->name, "HPE GXP I2C adapter", sizeof(adapter->name));
+ adapter->algo = &gxp_i2c_algo;
+ adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = pdev->dev.of_node;
+
+ rc = i2c_add_adapter(adapter);
+ if (rc)
+ return dev_err_probe(&pdev->dev, rc, "i2c add adapter failed\n");
+
+ return 0;
+}
+
+static int gxp_i2c_remove(struct platform_device *pdev)
+{
+ struct gxp_i2c_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ /* Disable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine), 0);
+ i2c_del_adapter(&drvdata->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id gxp_i2c_of_match[] = {
+ { .compatible = "hpe,gxp-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gxp_i2c_of_match);
+
+static struct platform_driver gxp_i2c_driver = {
+ .probe = gxp_i2c_probe,
+ .remove = gxp_i2c_remove,
+ .driver = {
+ .name = "gxp-i2c",
+ .of_match_table = gxp_i2c_of_match,
+ },
+};
+module_platform_driver(gxp_i2c_driver);
+
+MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
+MODULE_DESCRIPTION("HPE GXP I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 1fda1eaa6d6a..ac5326747c51 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -434,7 +434,7 @@ static int i801_wait_intr(struct i801_priv *priv)
busy = status & SMBHSTSTS_HOST_BUSY;
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
if (!busy && status)
- return status;
+ return status & STATUS_ERROR_FLAGS;
} while (time_is_after_eq_jiffies(timeout));
return -ETIMEDOUT;
@@ -458,26 +458,20 @@ static int i801_wait_byte_done(struct i801_priv *priv)
static int i801_transaction(struct i801_priv *priv, int xact)
{
- int status;
unsigned long result;
const struct i2c_adapter *adap = &priv->adapter;
- status = i801_check_pre(priv);
- if (status < 0)
- return status;
-
if (priv->features & FEATURE_IRQ) {
reinit_completion(&priv->done);
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
- return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
+ return result ? priv->status : -ETIMEDOUT;
}
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
- status = i801_wait_intr(priv);
- return i801_check_post(priv, status);
+ return i801_wait_intr(priv);
}
static int i801_block_transaction_by_block(struct i801_priv *priv,
@@ -511,19 +505,23 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
status = i801_transaction(priv, xact);
if (status)
- return status;
+ goto out;
if (read_write == I2C_SMBUS_READ ||
command == I2C_SMBUS_BLOCK_PROC_CALL) {
len = inb_p(SMBHSTDAT0(priv));
- if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
- return -EPROTO;
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ status = -EPROTO;
+ goto out;
+ }
data->block[0] = len;
for (i = 0; i < len; i++)
data->block[i + 1] = inb_p(SMBBLKDAT(priv));
}
- return 0;
+out:
+ outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ return status;
}
static void i801_isr_byte_done(struct i801_priv *priv)
@@ -558,9 +556,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
/* Write next byte, except for IRQ after last byte */
outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
}
-
- /* Clear BYTE_DONE to continue with next byte */
- outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
@@ -590,7 +585,6 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
* BUS_ERR - SMI# transaction collision
* FAILED - transaction was canceled due to a KILL request
* When any of these occur, update ->status and signal completion.
- * ->status must be cleared before kicking off the next transaction.
*
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
* occurs for each byte of a byte-by-byte to prepare the next byte.
@@ -615,25 +609,20 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
}
status = inb_p(SMBHSTSTS(priv));
- if (status & SMBHSTSTS_BYTE_DONE)
+ if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv);
/*
- * Clear remaining IRQ sources: Completion of last command, errors
- * and the SMB_ALERT signal. SMB_ALERT status is set after signal
- * assertion independently of the interrupt generation being blocked
- * or not so clear it always when the status is set.
- */
- status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS | SMBHSTSTS_SMBALERT_STS;
- if (status)
- outb_p(status, SMBHSTSTS(priv));
- status &= ~SMBHSTSTS_SMBALERT_STS; /* SMB_ALERT not reported */
- /*
- * Report transaction result.
- * ->status must be cleared before the next transaction is started.
+ * Clear IRQ sources: SMB_ALERT status is set after signal assertion
+ * independently of the interrupt generation being blocked or not
+ * so clear it always when the status is set.
*/
+ status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS;
+ outb_p(status, SMBHSTSTS(priv));
+
+ status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
if (status) {
- priv->status = status;
+ priv->status = status & STATUS_ERROR_FLAGS;
complete(&priv->done);
}
@@ -658,10 +647,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
if (command == I2C_SMBUS_BLOCK_PROC_CALL)
return -EOPNOTSUPP;
- status = i801_check_pre(priv);
- if (status < 0)
- return status;
-
len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
@@ -687,7 +672,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
reinit_completion(&priv->done);
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
- return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
+ return result ? priv->status : -ETIMEDOUT;
}
for (i = 1; i <= len; i++) {
@@ -701,7 +686,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
status = i801_wait_byte_done(priv);
if (status)
- goto exit;
+ return status;
if (i == 1 && read_write == I2C_SMBUS_READ
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
@@ -731,14 +716,82 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
- status = i801_wait_intr(priv);
-exit:
- return i801_check_post(priv, status);
+ return i801_wait_intr(priv);
+}
+
+static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
+{
+ outb_p((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
+}
+
+/* Single value transaction function */
+static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
+ u8 addr, u8 hstcmd, char read_write, int command)
+{
+ int xact, ret;
+
+ switch (command) {
+ case I2C_SMBUS_QUICK:
+ i801_set_hstadd(priv, addr, read_write);
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0(priv));
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ }
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ read_write = I2C_SMBUS_READ;
+ xact = I801_PROC_CALL;
+ break;
+ default:
+ pci_err(priv->pci_dev, "Unsupported transaction %d\n", command);
+ return -EOPNOTSUPP;
+ }
+
+ ret = i801_transaction(priv, xact);
+ if (ret || read_write == I2C_SMBUS_WRITE)
+ return ret;
+
+ switch (command) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0(priv));
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = inb_p(SMBHSTDAT0(priv)) +
+ (inb_p(SMBHSTDAT1(priv)) << 8);
+ break;
+ }
+
+ return 0;
}
/* Block transaction function */
static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
- char read_write, int command)
+ u8 addr, u8 hstcmd, char read_write, int command)
{
int result = 0;
unsigned char hostc;
@@ -748,7 +801,29 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *
else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ switch (command) {
+ case I2C_SMBUS_BLOCK_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /*
+ * NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading.
+ * However if SPD Write Disable is set (Lynx Point and later),
+ * the read will fail if we don't set the R/#W bit.
+ */
+ i801_set_hstadd(priv, addr,
+ priv->original_hstcfg & SMBHSTCFG_SPD_WD ?
+ read_write : I2C_SMBUS_WRITE);
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading
+ */
+ outb_p(hstcmd, SMBHSTDAT1(priv));
+ } else
+ outb_p(hstcmd, SMBHSTCMD(priv));
+
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
@@ -759,6 +834,12 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *
"I2C block read is unsupported!\n");
return -EOPNOTSUPP;
}
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ /* Needs to be flagged as write transaction */
+ i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ break;
}
/* Experience has shown that the block buffer can only be used for
@@ -787,9 +868,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
- int hwpec;
- int block = 0;
- int ret, xact;
+ int hwpec, ret;
struct i801_priv *priv = i2c_get_adapdata(adap);
mutex_lock(&priv->acpi_lock);
@@ -800,127 +879,34 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
pm_runtime_get_sync(&priv->pci_dev->dev);
+ ret = i801_check_pre(priv);
+ if (ret)
+ goto out;
+
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
- switch (size) {
- case I2C_SMBUS_QUICK:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- xact = I801_QUICK;
- break;
- case I2C_SMBUS_BYTE:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_WRITE)
- outb_p(command, SMBHSTCMD(priv));
- xact = I801_BYTE;
- break;
- case I2C_SMBUS_BYTE_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE)
- outb_p(data->byte, SMBHSTDAT0(priv));
- xact = I801_BYTE_DATA;
- break;
- case I2C_SMBUS_WORD_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- }
- xact = I801_WORD_DATA;
- break;
- case I2C_SMBUS_PROC_CALL:
- outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- xact = I801_PROC_CALL;
- read_write = I2C_SMBUS_READ;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- case I2C_SMBUS_I2C_BLOCK_DATA:
- /*
- * NB: page 240 of ICH5 datasheet shows that the R/#W
- * bit should be cleared here, even when reading.
- * However if SPD Write Disable is set (Lynx Point and later),
- * the read will fail if we don't set the R/#W bit.
- */
- outb_p(((addr & 0x7f) << 1) |
- ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ?
- (read_write & 0x01) : 0),
- SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_READ) {
- /* NB: page 240 of ICH5 datasheet also shows
- * that DATA1 is the cmd field when reading */
- outb_p(command, SMBHSTDAT1(priv));
- } else
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- case I2C_SMBUS_BLOCK_PROC_CALL:
- /*
- * Bit 0 of the slave address register always indicate a write
- * command.
- */
- outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- default:
- dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
- size);
- ret = -EOPNOTSUPP;
- goto out;
- }
-
if (hwpec) /* enable/disable hardware PEC */
outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
else
outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
SMBAUXCTL(priv));
- if (block)
- ret = i801_block_transaction(priv, data, read_write, size);
+ if (size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA ||
+ size == I2C_SMBUS_BLOCK_PROC_CALL)
+ ret = i801_block_transaction(priv, data, addr, command, read_write, size);
else
- ret = i801_transaction(priv, xact);
-
- /* Some BIOSes don't like it when PEC is enabled at reboot or resume
- time, so we forcibly disable it after every transaction. Turn off
- E32B for the same reason. */
- if (hwpec || block)
- outb_p(inb_p(SMBAUXCTL(priv)) &
- ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
-
- if (block)
- goto out;
- if (ret)
- goto out;
- if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
- goto out;
+ ret = i801_simple_transaction(priv, data, addr, command, read_write, size);
- switch (xact) {
- case I801_BYTE: /* Result put in SMBHSTDAT0 */
- case I801_BYTE_DATA:
- data->byte = inb_p(SMBHSTDAT0(priv));
- break;
- case I801_WORD_DATA:
- case I801_PROC_CALL:
- data->word = inb_p(SMBHSTDAT0(priv)) +
- (inb_p(SMBHSTDAT1(priv)) << 8);
- break;
- }
+ ret = i801_check_post(priv, ret);
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ * time, so we forcibly disable it after every transaction.
+ */
+ if (hwpec)
+ outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
@@ -1667,6 +1653,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
priv->features &= ~disable_features;
+ /* The block process call uses block buffer mode */
+ if (!(priv->features & FEATURE_BLOCK_BUFFER))
+ priv->features &= ~FEATURE_BLOCK_PROC;
+
err = pcim_enable_device(dev);
if (err) {
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
@@ -1714,11 +1704,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
outb_p(inb_p(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
- /* Remember original Interrupt and Host Notify settings */
- priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
- if (priv->features & FEATURE_HOST_NOTIFY)
- priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
-
/* Default timeout in interrupt mode: 200 ms */
priv->adapter.timeout = HZ / 5;
@@ -1748,6 +1733,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
dev_info(&dev->dev, "SMBus using %s\n",
priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
+ /* Host notification uses an interrupt */
+ if (!(priv->features & FEATURE_IRQ))
+ priv->features &= ~FEATURE_HOST_NOTIFY;
+
+ /* Remember original Interrupt and Host Notify settings */
+ priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
+ if (priv->features & FEATURE_HOST_NOTIFY)
+ priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
+
i801_add_tco(priv);
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
new file mode 100644
index 000000000000..ebae6035701d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ls2x.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Loongson-2K/Loongson LS7A I2C master mode driver
+ *
+ * Copyright (C) 2013 Loongson Technology Corporation Limited.
+ * Copyright (C) 2014-2017 Lemote, Inc.
+ * Copyright (C) 2018-2022 Loongson Technology Corporation Limited.
+ *
+ * Originally written by liushaozong
+ * Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn>
+ */
+
+#include <linux/bits.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/units.h>
+
+/* I2C Registers */
+#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */
+#define I2C_LS2X_CTR 0x2 /* Control Register */
+#define I2C_LS2X_TXR 0x3 /* Transport Data Register */
+#define I2C_LS2X_RXR 0x3 /* Receive Data Register */
+#define I2C_LS2X_CR 0x4 /* Command Control Register */
+#define I2C_LS2X_SR 0x4 /* State Register */
+
+/* Command Control Register Bit */
+#define LS2X_CR_START BIT(7) /* Start signal */
+#define LS2X_CR_STOP BIT(6) /* Stop signal */
+#define LS2X_CR_READ BIT(5) /* Read signal */
+#define LS2X_CR_WRITE BIT(4) /* Write signal */
+#define LS2X_CR_ACK BIT(3) /* Response signal */
+#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */
+
+/* State Register Bit */
+#define LS2X_SR_NOACK BIT(7) /* Receive NACK */
+#define LS2X_SR_BUSY BIT(6) /* Bus busy state */
+#define LS2X_SR_AL BIT(5) /* Arbitration lost */
+#define LS2X_SR_TIP BIT(1) /* Transmission state */
+#define LS2X_SR_IF BIT(0) /* Interrupt flag */
+
+/* Control Register Bit */
+#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */
+#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */
+#define LS2X_CTR_MST BIT(5) /* 0: Slave mode 1: Master mode */
+#define CTR_FREQ_MASK GENMASK(7, 6)
+#define CTR_READY_MASK GENMASK(7, 5)
+
+/* The PCLK frequency from LPB */
+#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ)
+
+/* The default bus frequency, which is an empirical value */
+#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
+
+struct ls2x_i2c_priv {
+ struct i2c_adapter adapter;
+ void __iomem *base;
+ struct i2c_timings i2c_t;
+ struct completion cmd_complete;
+};
+
+/*
+ * Interrupt service routine.
+ * This gets called whenever an I2C interrupt occurs.
+ */
+static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
+{
+ struct ls2x_i2c_priv *priv = dev_id;
+
+ if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF))
+ return IRQ_NONE;
+
+ writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR);
+ complete(&priv->cmd_complete);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The ls2x i2c controller supports standard mode and fast mode, so the
+ * maximum bus frequency is '400kHz'.
+ * The bus frequency is set to the empirical value of '33KHz' by default,
+ * but it can also be taken from ACPI or FDT for compatibility with more
+ * devices.
+ */
+static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
+{
+ struct i2c_timings *t = &priv->i2c_t;
+ struct device *dev = priv->adapter.dev.parent;
+ u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
+
+ i2c_parse_fw_timings(dev, t, false);
+
+ if (acpi_speed || t->bus_freq_hz)
+ t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
+ else
+ t->bus_freq_hz = LS2X_I2C_FREQ_STD;
+
+ /* Calculate and set i2c frequency. */
+ writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1,
+ priv->base + I2C_LS2X_PRER);
+}
+
+static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
+{
+ /* Set i2c frequency setting mode and disable interrupts. */
+ writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK,
+ priv->base + I2C_LS2X_CTR);
+
+ ls2x_i2c_adjust_bus_speed(priv);
+
+ /* Set i2c normal operating mode and enable interrupts. */
+ writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK,
+ priv->base + I2C_LS2X_CTR);
+}
+
+static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap)
+{
+ u8 rxdata;
+ unsigned long time_left;
+
+ writeb(txdata, priv->base + I2C_LS2X_CR);
+
+ time_left = wait_for_completion_timeout(&priv->cmd_complete,
+ priv->adapter.timeout);
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ rxdata = readb(priv->base + I2C_LS2X_SR);
+ if (rxdatap)
+ *rxdatap = rxdata;
+
+ return 0;
+}
+
+static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata)
+{
+ int ret;
+ u8 rxdata;
+
+ ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata);
+ if (ret)
+ return ret;
+
+ if (rxdata & LS2X_SR_AL)
+ return -EAGAIN;
+
+ if (rxdata & LS2X_SR_NOACK)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv)
+{
+ u8 value;
+
+ writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR);
+ return readb_poll_timeout(priv->base + I2C_LS2X_SR, value,
+ !(value & LS2X_SR_BUSY), 100,
+ jiffies_to_usecs(priv->adapter.timeout));
+}
+
+static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs)
+{
+ reinit_completion(&priv->cmd_complete);
+
+ writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR);
+ return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE);
+}
+
+static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
+{
+ int ret;
+ u8 rxdata, *buf = msg->buf;
+ u16 len = msg->len;
+
+ /* Contains steps to send start condition and address. */
+ ret = ls2x_i2c_start(priv, msg);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ ret = ls2x_i2c_xfer_byte(priv,
+ LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK),
+ &rxdata);
+ if (ret)
+ return ret;
+
+ *buf++ = readb(priv->base + I2C_LS2X_RXR);
+ }
+
+ return 0;
+}
+
+static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
+{
+ int ret;
+ u8 *buf = msg->buf;
+ u16 len = msg->len;
+
+ /* Contains steps to send start condition and address. */
+ ret = ls2x_i2c_start(priv, msg);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ writeb(*buf++, priv->base + I2C_LS2X_TXR);
+
+ ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv,
+ struct i2c_msg *msg, bool stop)
+{
+ int ret;
+
+ if (msg->flags & I2C_M_RD)
+ ret = ls2x_i2c_rx(priv, msg);
+ else
+ ret = ls2x_i2c_tx(priv, msg);
+
+ if (ret < 0) {
+ /* Fatel error. Needs reinit. */
+ if (ret == -ETIMEDOUT)
+ ls2x_i2c_init(priv);
+
+ return ret;
+ }
+
+ if (stop) {
+ /* Failed to issue STOP. Needs reinit. */
+ ret = ls2x_i2c_stop(priv);
+ if (ret)
+ ls2x_i2c_init(priv);
+ }
+
+ return ret;
+}
+
+static int ls2x_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ int ret;
+ struct i2c_msg *msg, *emsg = msgs + num;
+ struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ for (msg = msgs; msg < emsg; msg++) {
+ ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static unsigned int ls2x_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ls2x_i2c_algo = {
+ .master_xfer = ls2x_i2c_master_xfer,
+ .functionality = ls2x_i2c_func,
+};
+
+static int ls2x_i2c_probe(struct platform_device *pdev)
+{
+ int ret, irq;
+ struct i2c_adapter *adap;
+ struct ls2x_i2c_priv *priv;
+ struct device *dev = &pdev->dev;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Map hardware registers */
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Add the i2c adapter */
+ adap = &priv->adapter;
+ adap->retries = 5;
+ adap->nr = pdev->id;
+ adap->dev.parent = dev;
+ adap->owner = THIS_MODULE;
+ adap->algo = &ls2x_i2c_algo;
+ adap->timeout = msecs_to_jiffies(100);
+ device_set_node(&adap->dev, dev_fwnode(dev));
+ i2c_set_adapdata(adap, priv);
+ strscpy(adap->name, pdev->name, sizeof(adap->name));
+ init_completion(&priv->cmd_complete);
+ platform_set_drvdata(pdev, priv);
+
+ ls2x_i2c_init(priv);
+
+ ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
+ priv);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+
+ return devm_i2c_add_adapter(dev, adap);
+}
+
+static int ls2x_i2c_suspend(struct device *dev)
+{
+ struct ls2x_i2c_priv *priv = dev_get_drvdata(dev);
+
+ /* Disable interrupts */
+ writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN,
+ priv->base + I2C_LS2X_CTR);
+
+ return 0;
+}
+
+static int ls2x_i2c_resume(struct device *dev)
+{
+ ls2x_i2c_init(dev_get_drvdata(dev));
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
+ ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
+
+static const struct of_device_id ls2x_i2c_id_table[] = {
+ { .compatible = "loongson,ls2k-i2c" },
+ { .compatible = "loongson,ls7a-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);
+
+static const struct acpi_device_id ls2x_i2c_acpi_match[] = {
+ { "LOON0004" }, /* Loongson LS7A */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match);
+
+static struct platform_driver ls2x_i2c_driver = {
+ .probe = ls2x_i2c_probe,
+ .driver = {
+ .name = "ls2x-i2c",
+ .pm = pm_sleep_ptr(&ls2x_i2c_pm_ops),
+ .of_match_table = ls2x_i2c_id_table,
+ .acpi_match_table = ls2x_i2c_acpi_match,
+ },
+};
+module_platform_driver(ls2x_i2c_driver);
+
+MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index d80e59340d97..43dd966d5ef5 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -1366,20 +1366,17 @@ static int mtk_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mtk_i2c *i2c;
- struct resource *res;
int i, irq, speed_clk;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
+ i2c->pdmabase = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(i2c->pdmabase))
return PTR_ERR(i2c->pdmabase);
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index a4b97fe3c3a5..01358472680c 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -811,9 +811,15 @@ static const struct cci_data cci_v2_data = {
static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8226-cci", .data = &cci_v1_data},
- { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
+
+
+ /*
+ * Legacy compatibles kept for backwards compatibility.
+ * Do not add any new ones unless they introduce a new config
+ */
+ { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8450-cci", .data = &cci_v2_data},
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 80d586b0be7a..83909b02a03e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1025,7 +1025,7 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
NULL)
};
-const struct geni_i2c_desc i2c_master_hub = {
+static const struct geni_i2c_desc i2c_master_hub = {
.has_core_clk = true,
.icc_ddr = NULL,
.no_dma_support = true,
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 88482316d22a..f823913b75a6 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -740,7 +740,6 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
return (ret < 0) ? ret : i;
}
-#ifdef CONFIG_PM_SLEEP
static int st_i2c_suspend(struct device *dev)
{
struct st_i2c_dev *i2c_dev = dev_get_drvdata(dev);
@@ -762,11 +761,7 @@ static int st_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
-#define ST_I2C_PM (&st_i2c_pm)
-#else
-#define ST_I2C_PM NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
static u32 st_i2c_func(struct i2c_adapter *adap)
{
@@ -901,7 +896,7 @@ static struct platform_driver st_i2c_driver = {
.driver = {
.name = "st-i2c",
.of_match_table = st_i2c_match,
- .pm = ST_I2C_PM,
+ .pm = pm_sleep_ptr(&st_i2c_pm),
},
.probe = st_i2c_probe,
.remove = st_i2c_remove,
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index bee5a2ef1f22..dbb792fc197e 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -32,6 +32,8 @@
#include <linux/pm_runtime.h>
#define DRIVER_NAME "xiic-i2c"
+#define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0)
+#define SMBUS_BLOCK_READ_MIN_LEN 3
enum xilinx_i2c_state {
STATE_DONE,
@@ -44,6 +46,12 @@ enum xiic_endian {
BIG
};
+enum i2c_scl_freq {
+ REG_VALUES_100KHZ = 0,
+ REG_VALUES_400KHZ = 1,
+ REG_VALUES_1MHZ = 2
+};
+
/**
* struct xiic_i2c - Internal representation of the XIIC I2C bus
* @dev: Pointer to device structure
@@ -60,6 +68,12 @@ enum xiic_endian {
* @clk: Pointer to AXI4-lite input clock
* @state: See STATE_
* @singlemaster: Indicates bus is single master
+ * @dynamic: Mode of controller
+ * @prev_msg_tx: Previous message is Tx
+ * @quirks: To hold platform specific bug info
+ * @smbus_block_read: Flag to handle block read
+ * @input_clk: Input clock to I2C controller
+ * @i2c_clk: I2C SCL frequency
*/
struct xiic_i2c {
struct device *dev;
@@ -76,6 +90,39 @@ struct xiic_i2c {
struct clk *clk;
enum xilinx_i2c_state state;
bool singlemaster;
+ bool dynamic;
+ bool prev_msg_tx;
+ u32 quirks;
+ bool smbus_block_read;
+ unsigned long input_clk;
+ unsigned int i2c_clk;
+};
+
+struct xiic_version_data {
+ u32 quirks;
+};
+
+/**
+ * struct timing_regs - AXI I2C timing registers that depend on I2C spec
+ * @tsusta: setup time for a repeated START condition
+ * @tsusto: setup time for a STOP condition
+ * @thdsta: hold time for a repeated START condition
+ * @tsudat: setup time for data
+ * @tbuf: bus free time between STOP and START
+ */
+struct timing_regs {
+ unsigned int tsusta;
+ unsigned int tsusto;
+ unsigned int thdsta;
+ unsigned int tsudat;
+ unsigned int tbuf;
+};
+
+/* Reg values in ns derived from I2C spec and AXI I2C PG for different frequencies */
+static const struct timing_regs timing_reg_values[] = {
+ { 5700, 5000, 4300, 550, 5000 }, /* Reg values for 100KHz */
+ { 900, 900, 900, 400, 1600 }, /* Reg values for 400KHz */
+ { 380, 380, 380, 170, 620 }, /* Reg values for 1MHz */
};
#define XIIC_MSB_OFFSET 0
@@ -96,6 +143,19 @@ struct xiic_i2c {
#define XIIC_RFD_REG_OFFSET (0x20 + XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
#define XIIC_GPO_REG_OFFSET (0x24 + XIIC_REG_OFFSET) /* Output Register */
+/*
+ * Timing register offsets from RegisterBase. These are used only for
+ * setting i2c clock frequency for the line.
+ */
+#define XIIC_TSUSTA_REG_OFFSET (0x28 + XIIC_REG_OFFSET) /* TSUSTA Register */
+#define XIIC_TSUSTO_REG_OFFSET (0x2C + XIIC_REG_OFFSET) /* TSUSTO Register */
+#define XIIC_THDSTA_REG_OFFSET (0x30 + XIIC_REG_OFFSET) /* THDSTA Register */
+#define XIIC_TSUDAT_REG_OFFSET (0x34 + XIIC_REG_OFFSET) /* TSUDAT Register */
+#define XIIC_TBUF_REG_OFFSET (0x38 + XIIC_REG_OFFSET) /* TBUF Register */
+#define XIIC_THIGH_REG_OFFSET (0x3C + XIIC_REG_OFFSET) /* THIGH Register */
+#define XIIC_TLOW_REG_OFFSET (0x40 + XIIC_REG_OFFSET) /* TLOW Register */
+#define XIIC_THDDAT_REG_OFFSET (0x44 + XIIC_REG_OFFSET) /* THDDAT 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 */
@@ -143,6 +203,9 @@ struct xiic_i2c {
#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+/* Dynamic mode constants */
+#define MAX_READ_LENGTH_DYNAMIC 255 /* Max length for dynamic read */
+
/*
* The following constants define the register offsets for the Interrupt
* registers. There are some holes in the memory map for reserved addresses
@@ -275,12 +338,120 @@ static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
return 0;
}
+static int xiic_wait_tx_empty(struct xiic_i2c *i2c)
+{
+ u8 isr;
+ unsigned long timeout;
+
+ timeout = jiffies + XIIC_I2C_TIMEOUT;
+ for (isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ !(isr & XIIC_INTR_TX_EMPTY_MASK);
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET)) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(i2c->dev, "Timeout waiting at Tx empty\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * xiic_setclk - Sets the configured clock rate
+ * @i2c: Pointer to the xiic device structure
+ *
+ * The timing register values are calculated according to the input clock
+ * frequency and configured scl frequency. For details, please refer the
+ * AXI I2C PG and NXP I2C Spec.
+ * Supported frequencies are 100KHz, 400KHz and 1MHz.
+ *
+ * Return: 0 on success (Supported frequency selected or not configurable in SW)
+ * -EINVAL on failure (scl frequency not supported or THIGH is 0)
+ */
+static int xiic_setclk(struct xiic_i2c *i2c)
+{
+ unsigned int clk_in_mhz;
+ unsigned int index = 0;
+ u32 reg_val;
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n",
+ __func__, i2c->input_clk, i2c->i2c_clk);
+
+ /* If not specified in DT, do not configure in SW. Rely only on Vivado design */
+ if (!i2c->i2c_clk || !i2c->input_clk)
+ return 0;
+
+ clk_in_mhz = DIV_ROUND_UP(i2c->input_clk, 1000000);
+
+ switch (i2c->i2c_clk) {
+ case I2C_MAX_FAST_MODE_PLUS_FREQ:
+ index = REG_VALUES_1MHZ;
+ break;
+ case I2C_MAX_FAST_MODE_FREQ:
+ index = REG_VALUES_400KHZ;
+ break;
+ case I2C_MAX_STANDARD_MODE_FREQ:
+ index = REG_VALUES_100KHZ;
+ break;
+ default:
+ dev_warn(i2c->adap.dev.parent, "Unsupported scl frequency\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Value to be stored in a register is the number of clock cycles required
+ * for the time duration. So the time is divided by the input clock time
+ * period to get the number of clock cycles required. Refer Xilinx AXI I2C
+ * PG document and I2C specification for further details.
+ */
+
+ /* THIGH - Depends on SCL clock frequency(i2c_clk) as below */
+ reg_val = (DIV_ROUND_UP(i2c->input_clk, 2 * i2c->i2c_clk)) - 7;
+ if (reg_val == 0)
+ return -EINVAL;
+
+ xiic_setreg32(i2c, XIIC_THIGH_REG_OFFSET, reg_val - 1);
+
+ /* TLOW - Value same as THIGH */
+ xiic_setreg32(i2c, XIIC_TLOW_REG_OFFSET, reg_val - 1);
+
+ /* TSUSTA */
+ reg_val = (timing_reg_values[index].tsusta * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUSTA_REG_OFFSET, reg_val - 1);
+
+ /* TSUSTO */
+ reg_val = (timing_reg_values[index].tsusto * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUSTO_REG_OFFSET, reg_val - 1);
+
+ /* THDSTA */
+ reg_val = (timing_reg_values[index].thdsta * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_THDSTA_REG_OFFSET, reg_val - 1);
+
+ /* TSUDAT */
+ reg_val = (timing_reg_values[index].tsudat * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUDAT_REG_OFFSET, reg_val - 1);
+
+ /* TBUF */
+ reg_val = (timing_reg_values[index].tbuf * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TBUF_REG_OFFSET, reg_val - 1);
+
+ /* THDDAT */
+ xiic_setreg32(i2c, XIIC_THDDAT_REG_OFFSET, 1);
+
+ return 0;
+}
+
static int xiic_reinit(struct xiic_i2c *i2c)
{
int ret;
xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+ ret = xiic_setclk(i2c);
+ if (ret)
+ return ret;
+
/* Set receive Fifo depth to maximum (zero based). */
xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
@@ -314,15 +485,72 @@ static void xiic_deinit(struct xiic_i2c *i2c)
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
}
+static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
+{
+ u8 rxmsg_len, rfd_set = 0;
+
+ /*
+ * Clear the I2C_M_RECV_LEN flag to avoid setting
+ * message length again
+ */
+ i2c->rx_msg->flags &= ~I2C_M_RECV_LEN;
+
+ /* Set smbus_block_read flag to identify in isr */
+ i2c->smbus_block_read = true;
+
+ /* Read byte from rx fifo and set message length */
+ rxmsg_len = xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ i2c->rx_msg->buf[i2c->rx_pos++] = rxmsg_len;
+
+ /* Check if received length is valid */
+ if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) {
+ /* Set Receive fifo depth */
+ if (rxmsg_len > IIC_RX_FIFO_DEPTH) {
+ /*
+ * When Rx msg len greater than or equal to Rx fifo capacity
+ * Receive fifo depth should set to Rx fifo capacity minus 1
+ */
+ rfd_set = IIC_RX_FIFO_DEPTH - 1;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ } else if ((rxmsg_len == 1) ||
+ (rxmsg_len == 0)) {
+ /*
+ * Minimum of 3 bytes required to exit cleanly. 1 byte
+ * already received, Second byte is being received. Have
+ * to set NACK in read_rx before receiving the last byte
+ */
+ rfd_set = 0;
+ i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN;
+ } else {
+ /*
+ * When Rx msg len less than Rx fifo capacity
+ * Receive fifo depth should set to Rx msg len minus 2
+ */
+ rfd_set = rxmsg_len - 2;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ }
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
+
+ return;
+ }
+
+ /* Invalid message length, trigger STATE_ERROR with tx_msg_len in ISR */
+ i2c->tx_msg->len = 3;
+ i2c->smbus_block_read = false;
+ dev_err(i2c->adap.dev.parent, "smbus_block_read Invalid msg length\n");
+}
+
static void xiic_read_rx(struct xiic_i2c *i2c)
{
- u8 bytes_in_fifo;
+ u8 bytes_in_fifo, cr = 0, bytes_to_read = 0;
+ u32 bytes_rem = 0;
int i;
bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
dev_dbg(i2c->adap.dev.parent,
- "%s entry, bytes in fifo: %d, msg: %d, SR: 0x%x, CR: 0x%x\n",
+ "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n",
__func__, bytes_in_fifo, xiic_rx_space(i2c),
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
@@ -330,13 +558,58 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
if (bytes_in_fifo > xiic_rx_space(i2c))
bytes_in_fifo = xiic_rx_space(i2c);
- for (i = 0; i < bytes_in_fifo; i++)
+ bytes_to_read = bytes_in_fifo;
+
+ if (!i2c->dynamic) {
+ bytes_rem = xiic_rx_space(i2c) - bytes_in_fifo;
+
+ /* Set msg length if smbus_block_read */
+ if (i2c->rx_msg->flags & I2C_M_RECV_LEN) {
+ xiic_smbus_block_read_setup(i2c);
+ return;
+ }
+
+ if (bytes_rem > IIC_RX_FIFO_DEPTH) {
+ bytes_to_read = bytes_in_fifo;
+ } else if (bytes_rem > 1) {
+ bytes_to_read = bytes_rem - 1;
+ } else if (bytes_rem == 1) {
+ bytes_to_read = 1;
+ /* Set NACK in CR to indicate slave transmitter */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr |
+ XIIC_CR_NO_ACK_MASK);
+ } else if (bytes_rem == 0) {
+ bytes_to_read = bytes_in_fifo;
+
+ /* Generate stop on the bus if it is last message */
+ if (i2c->nmsgs == 1) {
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_MSMS_MASK);
+ }
+
+ /* Make TXACK=0, clean up for next transaction */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_NO_ACK_MASK);
+ }
+ }
+
+ /* Read the fifo */
+ for (i = 0; i < bytes_to_read; i++) {
i2c->rx_msg->buf[i2c->rx_pos++] =
xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+ }
- xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
- (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
- IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1);
+ if (i2c->dynamic) {
+ u8 bytes;
+
+ /* Receive remaining bytes if less than fifo depth */
+ bytes = min_t(u8, xiic_rx_space(i2c), IIC_RX_FIFO_DEPTH);
+ bytes--;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
+ }
}
static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
@@ -360,7 +633,22 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) {
/* last message in transfer -> STOP */
- data |= XIIC_TX_DYN_STOP_MASK;
+ if (i2c->dynamic) {
+ data |= XIIC_TX_DYN_STOP_MASK;
+ } else {
+ u8 cr;
+ int status;
+
+ /* Wait till FIFO is empty so STOP is sent last */
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+
+ /* Write to CR to stop */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_MSMS_MASK);
+ }
dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
}
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
@@ -401,7 +689,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n",
__func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
i2c->tx_msg, i2c->nmsgs);
-
+ dev_dbg(i2c->adap.dev.parent, "%s, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
/* Service requesting interrupt */
if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
@@ -512,6 +802,12 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
/* The bus is not busy, disable BusNotBusy interrupt */
xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+ if (i2c->tx_msg && i2c->smbus_block_read) {
+ i2c->smbus_block_read = false;
+ /* Set requested message len=1 to indicate STATE_DONE */
+ i2c->tx_msg->len = 1;
+ }
+
if (!i2c->tx_msg)
goto out;
@@ -579,31 +875,113 @@ static int xiic_busy(struct xiic_i2c *i2c)
static void xiic_start_recv(struct xiic_i2c *i2c)
{
u16 rx_watermark;
+ u8 cr = 0, rfd_set = 0;
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
- /* Clear and enable Rx full interrupt. */
- xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
- /* 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;
- xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, (u8)(rx_watermark - 1));
+ /* Disable Tx interrupts */
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK | XIIC_INTR_TX_EMPTY_MASK);
+
+ if (i2c->dynamic) {
+ u8 bytes;
+ u16 val;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr_en(i2c, 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 indicate 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;
+ bytes = min_t(u8, rx_watermark, IIC_RX_FIFO_DEPTH);
+
+ if (rx_watermark > 0)
+ bytes--;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
- if (!(msg->flags & I2C_M_NOSTART))
/* write the address */
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
- i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK);
+ i2c_8bit_addr_from_msg(msg) |
+ XIIC_TX_DYN_START_MASK);
+
+ /* If last message, include dynamic stop bit with length */
+ val = (i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0;
+ val |= msg->len;
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, val);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+ } else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
- xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
- xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
- msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ /* Set Receive fifo depth */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH) {
+ rfd_set = IIC_RX_FIFO_DEPTH - 1;
+ } else if (rx_watermark == 1) {
+ rfd_set = rx_watermark - 1;
+
+ /* Set No_ACK, except for smbus_block_read */
+ if (!(i2c->rx_msg->flags & I2C_M_RECV_LEN)) {
+ /* Handle single byte transfer separately */
+ cr |= XIIC_CR_NO_ACK_MASK;
+ }
+ } else if (rx_watermark == 0) {
+ rfd_set = rx_watermark;
+ } else {
+ rfd_set = rx_watermark - 2;
+ }
+ /* Check if RSTA should be set */
+ if (cr & XIIC_CR_MSMS_MASK) {
+ /* Already a master, RSTA should be set */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_REPEATED_START_MASK) &
+ ~(XIIC_CR_DIR_IS_TX_MASK));
+ }
+
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
+
+ /* Clear and enable Rx full and transmit complete interrupts */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
+ XIIC_INTR_TX_ERROR_MASK);
+
+ /* Write the address */
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ i2c_8bit_addr_from_msg(msg));
+
+ /* Write to Control Register,to start transaction in Rx mode */
+ if ((cr & XIIC_CR_MSMS_MASK) == 0) {
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_MSMS_MASK)
+ & ~(XIIC_CR_DIR_IS_TX_MASK));
+ }
+ dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ }
if (i2c->nmsgs == 1)
/* very last, enable bus not busy as well */
@@ -611,10 +989,17 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
/* the message is tx:ed */
i2c->tx_pos = msg->len;
+
+ /* Enable interrupts */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ i2c->prev_msg_tx = false;
}
static void xiic_start_send(struct xiic_i2c *i2c)
{
+ u8 cr = 0;
+ u16 data;
struct i2c_msg *msg = i2c->tx_msg;
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
@@ -623,24 +1008,70 @@ static void xiic_start_send(struct xiic_i2c *i2c)
__func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
- if (!(msg->flags & I2C_M_NOSTART)) {
+ if (i2c->dynamic) {
/* write the address */
- u16 data = i2c_8bit_addr_from_msg(msg) |
- XIIC_TX_DYN_START_MASK;
- if ((i2c->nmsgs == 1) && msg->len == 0)
+ data = i2c_8bit_addr_from_msg(msg) |
+ XIIC_TX_DYN_START_MASK;
+
+ if (i2c->nmsgs == 1 && msg->len == 0)
/* no data and last message -> add STOP */
data |= XIIC_TX_DYN_STOP_MASK;
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
- }
- /* Clear any pending Tx empty, Tx Error and then enable them. */
- xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
- XIIC_INTR_BNB_MASK |
- ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ?
- XIIC_INTR_TX_HALF_MASK : 0));
+ /* Clear any pending Tx empty, Tx Error and then enable them */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK |
+ XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK |
+ ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ?
+ XIIC_INTR_TX_HALF_MASK : 0));
+
+ xiic_fill_tx_fifo(i2c);
+ } else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
+ /* Check if RSTA should be set */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ if (cr & XIIC_CR_MSMS_MASK) {
+ /* Already a master, RSTA should be set */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_REPEATED_START_MASK |
+ XIIC_CR_DIR_IS_TX_MASK) &
+ ~(XIIC_CR_NO_ACK_MASK));
+ }
+
+ /* Write address to FIFO */
+ data = i2c_8bit_addr_from_msg(msg);
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+
+ /* Fill fifo */
+ xiic_fill_tx_fifo(i2c);
- xiic_fill_tx_fifo(i2c);
+ if ((cr & XIIC_CR_MSMS_MASK) == 0) {
+ /* Start Tx by writing to CR */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr |
+ XIIC_CR_MSMS_MASK |
+ XIIC_CR_DIR_IS_TX_MASK);
+ }
+
+ /* Clear any pending Tx empty, Tx Error and then enable them */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK |
+ XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+ }
+ i2c->prev_msg_tx = true;
}
static void __xiic_start_xfer(struct xiic_i2c *i2c)
@@ -666,7 +1097,8 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
{
- int ret;
+ bool broken_read, max_read_len, smbus_blk_read;
+ int ret, count;
mutex_lock(&i2c->lock);
@@ -679,6 +1111,34 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
i2c->nmsgs = num;
init_completion(&i2c->completion);
+ /* Decide standard mode or Dynamic mode */
+ i2c->dynamic = true;
+
+ /* Initialize prev message type */
+ i2c->prev_msg_tx = false;
+
+ /*
+ * Scan through nmsgs, use dynamic mode when none of the below three
+ * conditions occur. We need standard mode even if one condition holds
+ * true in the entire array of messages in a single transfer.
+ * If read transaction as dynamic mode is broken for delayed reads
+ * in xlnx,axi-iic-2.0 / xlnx,xps-iic-2.00.a IP versions.
+ * If read length is > 255 bytes.
+ * If smbus_block_read transaction.
+ */
+ for (count = 0; count < i2c->nmsgs; count++) {
+ broken_read = (i2c->quirks & DYNAMIC_MODE_READ_BROKEN_BIT) &&
+ (i2c->tx_msg[count].flags & I2C_M_RD);
+ max_read_len = (i2c->tx_msg[count].flags & I2C_M_RD) &&
+ (i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC);
+ smbus_blk_read = (i2c->tx_msg[count].flags & I2C_M_RECV_LEN);
+
+ if (broken_read || max_read_len || smbus_blk_read) {
+ i2c->dynamic = false;
+ break;
+ }
+ }
+
ret = xiic_reinit(i2c);
if (!ret)
__xiic_start_xfer(i2c);
@@ -714,10 +1174,6 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
i2c->rx_msg = NULL;
i2c->nmsgs = 0;
err = -ETIMEDOUT;
- } else if (err < 0) { /* Completion error */
- i2c->tx_msg = NULL;
- i2c->rx_msg = NULL;
- i2c->nmsgs = 0;
} else {
err = (i2c->state == STATE_DONE) ? num : -EIO;
}
@@ -729,7 +1185,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
static u32 xiic_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm xiic_algorithm = {
@@ -737,21 +1193,30 @@ static const struct i2c_algorithm xiic_algorithm = {
.functionality = xiic_func,
};
-static const struct i2c_adapter_quirks xiic_quirks = {
- .max_read_len = 255,
-};
-
static const struct i2c_adapter xiic_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_DEPRECATED,
.algo = &xiic_algorithm,
- .quirks = &xiic_quirks,
};
+static const struct xiic_version_data xiic_2_00 = {
+ .quirks = DYNAMIC_MODE_READ_BROKEN_BIT,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id xiic_of_match[] = {
+ { .compatible = "xlnx,xps-iic-2.00.a", .data = &xiic_2_00 },
+ { .compatible = "xlnx,axi-iic-2.1", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xiic_of_match);
+#endif
+
static int xiic_i2c_probe(struct platform_device *pdev)
{
struct xiic_i2c *i2c;
struct xiic_i2c_platform_data *pdata;
+ const struct of_device_id *match;
struct resource *res;
int ret, irq;
u8 i;
@@ -761,6 +1226,13 @@ static int xiic_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
+ match = of_match_node(xiic_of_match, pdev->dev.of_node);
+ if (match && match->data) {
+ const struct xiic_version_data *data = match->data;
+
+ i2c->quirks = data->quirks;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
@@ -798,6 +1270,15 @@ static int xiic_i2c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(i2c->dev);
pm_runtime_set_active(i2c->dev);
pm_runtime_enable(i2c->dev);
+
+ /* SCL frequency configuration */
+ i2c->input_clk = clk_get_rate(i2c->clk);
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->i2c_clk);
+ /* If clock-frequency not specified in DT, do not configure in SW */
+ if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ)
+ i2c->i2c_clk = 0;
+
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
xiic_process, IRQF_ONESHOT,
pdev->name, i2c);
@@ -841,6 +1322,9 @@ static int xiic_i2c_probe(struct platform_device *pdev)
i2c_new_client_device(&i2c->adap, pdata->devices + i);
}
+ dev_dbg(&pdev->dev, "mmio %08lx irq %d scl clock frequency %d\n",
+ (unsigned long)res->start, irq, i2c->i2c_clk);
+
return 0;
err_clk_dis:
@@ -875,14 +1359,6 @@ static int xiic_i2c_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_OF)
-static const struct of_device_id xiic_of_match[] = {
- { .compatible = "xlnx,xps-iic-2.00.a", },
- {},
-};
-MODULE_DEVICE_TABLE(of, xiic_of_match);
-#endif
-
static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev)
{
struct xiic_i2c *i2c = dev_get_drvdata(dev);
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 734d8e6ad4a9..cb5fa971d67e 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -34,6 +34,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/devinfo.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
@@ -282,7 +283,9 @@ static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
struct device *dev = &adap->dev;
- struct pinctrl *p = bri->pinctrl;
+ struct pinctrl *p = bri->pinctrl ?: dev_pinctrl(dev->parent);
+
+ bri->pinctrl = p;
/*
* we can't change states without pinctrl, so remove the states if
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index ab0adaa130da..107623c4cc14 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -653,12 +653,12 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
int res;
if (dev->type != &i2c_adapter_type)
- return 0;
+ return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
- return PTR_ERR(i2c_dev);
+ return NOTIFY_DONE;
cdev_init(&i2c_dev->cdev, &i2cdev_fops);
i2c_dev->cdev.owner = THIS_MODULE;
@@ -678,11 +678,11 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
goto err_put_i2c_dev;
pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr);
- return 0;
+ return NOTIFY_OK;
err_put_i2c_dev:
put_i2c_dev(i2c_dev, false);
- return res;
+ return NOTIFY_DONE;
}
static int i2cdev_detach_adapter(struct device *dev, void *dummy)
@@ -691,17 +691,17 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
struct i2c_dev *i2c_dev;
if (dev->type != &i2c_adapter_type)
- return 0;
+ return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = i2c_dev_get_by_minor(adap->nr);
if (!i2c_dev) /* attach_adapter must have failed */
- return 0;
+ return NOTIFY_DONE;
put_i2c_dev(i2c_dev, true);
pr_debug("adapter [%s] unregistered\n", adap->name);
- return 0;
+ return NOTIFY_OK;
}
static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
@@ -716,7 +716,7 @@ static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
return i2cdev_detach_adapter(dev, NULL);
}
- return 0;
+ return NOTIFY_DONE;
}
static struct notifier_block i2cdev_notifier = {