162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/err.h>
562306a36Sopenharmony_ci#include <linux/io.h>
662306a36Sopenharmony_ci#include <linux/i2c.h>
762306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/regmap.h>
1162306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define GXP_MAX_I2C_ENGINE 10
1462306a36Sopenharmony_cistatic const char * const gxp_i2c_name[] = {
1562306a36Sopenharmony_ci	"gxp-i2c0", "gxp-i2c1", "gxp-i2c2", "gxp-i2c3",
1662306a36Sopenharmony_ci	"gxp-i2c4", "gxp-i2c5", "gxp-i2c6", "gxp-i2c7",
1762306a36Sopenharmony_ci	"gxp-i2c8", "gxp-i2c9" };
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* GXP I2C Global interrupt status/enable register*/
2062306a36Sopenharmony_ci#define GXP_I2CINTSTAT		0x00
2162306a36Sopenharmony_ci#define GXP_I2CINTEN		0x04
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* GXP I2C registers */
2462306a36Sopenharmony_ci#define GXP_I2CSTAT		0x00
2562306a36Sopenharmony_ci#define MASK_STOP_EVENT		0x20
2662306a36Sopenharmony_ci#define MASK_ACK		0x08
2762306a36Sopenharmony_ci#define MASK_RW			0x04
2862306a36Sopenharmony_ci#define GXP_I2CEVTERR		0x01
2962306a36Sopenharmony_ci#define MASK_SLAVE_CMD_EVENT	0x01
3062306a36Sopenharmony_ci#define MASK_SLAVE_DATA_EVENT	0x02
3162306a36Sopenharmony_ci#define MASK_MASTER_EVENT	0x10
3262306a36Sopenharmony_ci#define GXP_I2CSNPDAT		0x02
3362306a36Sopenharmony_ci#define GXP_I2CMCMD		0x04
3462306a36Sopenharmony_ci#define GXP_I2CSCMD		0x06
3562306a36Sopenharmony_ci#define GXP_I2CSNPAA		0x09
3662306a36Sopenharmony_ci#define GXP_I2CADVFEAT		0x0A
3762306a36Sopenharmony_ci#define GXP_I2COWNADR		0x0B
3862306a36Sopenharmony_ci#define GXP_I2CFREQDIV		0x0C
3962306a36Sopenharmony_ci#define GXP_I2CFLTFAIR		0x0D
4062306a36Sopenharmony_ci#define GXP_I2CTMOEDG		0x0E
4162306a36Sopenharmony_ci#define GXP_I2CCYCTIM		0x0F
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* I2CSCMD Bits */
4462306a36Sopenharmony_ci#define SNOOP_EVT_CLR		0x80
4562306a36Sopenharmony_ci#define SLAVE_EVT_CLR		0x40
4662306a36Sopenharmony_ci#define	SNOOP_EVT_MASK		0x20
4762306a36Sopenharmony_ci#define SLAVE_EVT_MASK		0x10
4862306a36Sopenharmony_ci#define SLAVE_ACK_ENAB		0x08
4962306a36Sopenharmony_ci#define SLAVE_EVT_STALL		0x01
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* I2CMCMD Bits */
5262306a36Sopenharmony_ci#define MASTER_EVT_CLR		0x80
5362306a36Sopenharmony_ci#define MASTER_ACK_ENAB		0x08
5462306a36Sopenharmony_ci#define RW_CMD			0x04
5562306a36Sopenharmony_ci#define STOP_CMD		0x02
5662306a36Sopenharmony_ci#define START_CMD		0x01
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* I2CTMOEDG value */
5962306a36Sopenharmony_ci#define GXP_DATA_EDGE_RST_CTRL	0x0a /* 30ns */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* I2CFLTFAIR Bits */
6262306a36Sopenharmony_ci#define FILTER_CNT		0x30
6362306a36Sopenharmony_ci#define FAIRNESS_CNT		0x02
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cienum {
6662306a36Sopenharmony_ci	GXP_I2C_IDLE = 0,
6762306a36Sopenharmony_ci	GXP_I2C_ADDR_PHASE,
6862306a36Sopenharmony_ci	GXP_I2C_RDATA_PHASE,
6962306a36Sopenharmony_ci	GXP_I2C_WDATA_PHASE,
7062306a36Sopenharmony_ci	GXP_I2C_ADDR_NACK,
7162306a36Sopenharmony_ci	GXP_I2C_DATA_NACK,
7262306a36Sopenharmony_ci	GXP_I2C_ERROR,
7362306a36Sopenharmony_ci	GXP_I2C_COMP
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistruct gxp_i2c_drvdata {
7762306a36Sopenharmony_ci	struct device *dev;
7862306a36Sopenharmony_ci	void __iomem *base;
7962306a36Sopenharmony_ci	struct i2c_timings t;
8062306a36Sopenharmony_ci	u32 engine;
8162306a36Sopenharmony_ci	int irq;
8262306a36Sopenharmony_ci	struct completion completion;
8362306a36Sopenharmony_ci	struct i2c_adapter adapter;
8462306a36Sopenharmony_ci	struct i2c_msg *curr_msg;
8562306a36Sopenharmony_ci	int msgs_remaining;
8662306a36Sopenharmony_ci	int msgs_num;
8762306a36Sopenharmony_ci	u8 *buf;
8862306a36Sopenharmony_ci	size_t buf_remaining;
8962306a36Sopenharmony_ci	unsigned char state;
9062306a36Sopenharmony_ci	struct i2c_client *slave;
9162306a36Sopenharmony_ci	unsigned char stopped;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct regmap *i2cg_map;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void gxp_i2c_start(struct gxp_i2c_drvdata *drvdata)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	u16 value;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	drvdata->buf = drvdata->curr_msg->buf;
10162306a36Sopenharmony_ci	drvdata->buf_remaining = drvdata->curr_msg->len;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Note: Address in struct i2c_msg is 7 bits */
10462306a36Sopenharmony_ci	value = drvdata->curr_msg->addr << 9;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* Read or Write */
10762306a36Sopenharmony_ci	value |= drvdata->curr_msg->flags & I2C_M_RD ? RW_CMD | START_CMD : START_CMD;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	drvdata->state = GXP_I2C_ADDR_PHASE;
11062306a36Sopenharmony_ci	writew(value, drvdata->base + GXP_I2CMCMD);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int gxp_i2c_master_xfer(struct i2c_adapter *adapter,
11462306a36Sopenharmony_ci			       struct i2c_msg *msgs, int num)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	int ret;
11762306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(adapter);
11862306a36Sopenharmony_ci	unsigned long time_left;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	drvdata->msgs_remaining = num;
12162306a36Sopenharmony_ci	drvdata->curr_msg = msgs;
12262306a36Sopenharmony_ci	drvdata->msgs_num = num;
12362306a36Sopenharmony_ci	reinit_completion(&drvdata->completion);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	gxp_i2c_start(drvdata);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&drvdata->completion,
12862306a36Sopenharmony_ci						adapter->timeout);
12962306a36Sopenharmony_ci	ret = num - drvdata->msgs_remaining;
13062306a36Sopenharmony_ci	if (time_left == 0)
13162306a36Sopenharmony_ci		return -ETIMEDOUT;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (drvdata->state == GXP_I2C_ADDR_NACK)
13462306a36Sopenharmony_ci		return -ENXIO;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (drvdata->state == GXP_I2C_DATA_NACK)
13762306a36Sopenharmony_ci		return -EIO;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return ret;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic u32 gxp_i2c_func(struct i2c_adapter *adap)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_I2C_SLAVE))
14562306a36Sopenharmony_ci		return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
15162306a36Sopenharmony_cistatic int gxp_i2c_reg_slave(struct i2c_client *slave)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (drvdata->slave)
15662306a36Sopenharmony_ci		return -EBUSY;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (slave->flags & I2C_CLIENT_TEN)
15962306a36Sopenharmony_ci		return -EAFNOSUPPORT;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	drvdata->slave = slave;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	writeb(slave->addr << 1, drvdata->base + GXP_I2COWNADR);
16462306a36Sopenharmony_ci	writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | SLAVE_ACK_ENAB |
16562306a36Sopenharmony_ci	       SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int gxp_i2c_unreg_slave(struct i2c_client *slave)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	WARN_ON(!drvdata->slave);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2COWNADR);
17762306a36Sopenharmony_ci	writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
17862306a36Sopenharmony_ci	       SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	drvdata->slave = NULL;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci#endif
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic const struct i2c_algorithm gxp_i2c_algo = {
18762306a36Sopenharmony_ci	.master_xfer   = gxp_i2c_master_xfer,
18862306a36Sopenharmony_ci	.functionality = gxp_i2c_func,
18962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
19062306a36Sopenharmony_ci	.reg_slave     = gxp_i2c_reg_slave,
19162306a36Sopenharmony_ci	.unreg_slave   = gxp_i2c_unreg_slave,
19262306a36Sopenharmony_ci#endif
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void gxp_i2c_stop(struct gxp_i2c_drvdata *drvdata)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	/* Clear event and send stop */
19862306a36Sopenharmony_ci	writeb(MASTER_EVT_CLR | STOP_CMD, drvdata->base + GXP_I2CMCMD);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	complete(&drvdata->completion);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void gxp_i2c_restart(struct gxp_i2c_drvdata *drvdata)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	u16 value;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	drvdata->buf = drvdata->curr_msg->buf;
20862306a36Sopenharmony_ci	drvdata->buf_remaining = drvdata->curr_msg->len;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	value = drvdata->curr_msg->addr << 9;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (drvdata->curr_msg->flags & I2C_M_RD) {
21362306a36Sopenharmony_ci		/* Read and clear master event */
21462306a36Sopenharmony_ci		value |= MASTER_EVT_CLR | RW_CMD | START_CMD;
21562306a36Sopenharmony_ci	} else {
21662306a36Sopenharmony_ci		/* Write and clear master event */
21762306a36Sopenharmony_ci		value |= MASTER_EVT_CLR | START_CMD;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	drvdata->state = GXP_I2C_ADDR_PHASE;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	writew(value, drvdata->base + GXP_I2CMCMD);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void gxp_i2c_chk_addr_ack(struct gxp_i2c_drvdata *drvdata)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	u16 value;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	value = readb(drvdata->base + GXP_I2CSTAT);
23062306a36Sopenharmony_ci	if (!(value & MASK_ACK)) {
23162306a36Sopenharmony_ci		/* Got no ack, stop */
23262306a36Sopenharmony_ci		drvdata->state = GXP_I2C_ADDR_NACK;
23362306a36Sopenharmony_ci		gxp_i2c_stop(drvdata);
23462306a36Sopenharmony_ci		return;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (drvdata->curr_msg->flags & I2C_M_RD) {
23862306a36Sopenharmony_ci		/* Start to read data from slave */
23962306a36Sopenharmony_ci		if (drvdata->buf_remaining == 0) {
24062306a36Sopenharmony_ci			/* No more data to read, stop */
24162306a36Sopenharmony_ci			drvdata->msgs_remaining--;
24262306a36Sopenharmony_ci			drvdata->state = GXP_I2C_COMP;
24362306a36Sopenharmony_ci			gxp_i2c_stop(drvdata);
24462306a36Sopenharmony_ci			return;
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci		drvdata->state = GXP_I2C_RDATA_PHASE;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if (drvdata->buf_remaining == 1) {
24962306a36Sopenharmony_ci			/* The last data, do not ack */
25062306a36Sopenharmony_ci			writeb(MASTER_EVT_CLR | RW_CMD,
25162306a36Sopenharmony_ci			       drvdata->base + GXP_I2CMCMD);
25262306a36Sopenharmony_ci		} else {
25362306a36Sopenharmony_ci			/* Read data and ack it */
25462306a36Sopenharmony_ci			writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
25562306a36Sopenharmony_ci			       RW_CMD, drvdata->base + GXP_I2CMCMD);
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci	} else {
25862306a36Sopenharmony_ci		/* Start to write first data to slave */
25962306a36Sopenharmony_ci		if (drvdata->buf_remaining == 0) {
26062306a36Sopenharmony_ci			/* No more data to write, stop */
26162306a36Sopenharmony_ci			drvdata->msgs_remaining--;
26262306a36Sopenharmony_ci			drvdata->state = GXP_I2C_COMP;
26362306a36Sopenharmony_ci			gxp_i2c_stop(drvdata);
26462306a36Sopenharmony_ci			return;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		value = *drvdata->buf;
26762306a36Sopenharmony_ci		value = value << 8;
26862306a36Sopenharmony_ci		/* Clear master event */
26962306a36Sopenharmony_ci		value |= MASTER_EVT_CLR;
27062306a36Sopenharmony_ci		drvdata->buf++;
27162306a36Sopenharmony_ci		drvdata->buf_remaining--;
27262306a36Sopenharmony_ci		drvdata->state = GXP_I2C_WDATA_PHASE;
27362306a36Sopenharmony_ci		writew(value, drvdata->base + GXP_I2CMCMD);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void gxp_i2c_ack_data(struct gxp_i2c_drvdata *drvdata)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	u8 value;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* Store the data returned */
28262306a36Sopenharmony_ci	value = readb(drvdata->base + GXP_I2CSNPDAT);
28362306a36Sopenharmony_ci	*drvdata->buf = value;
28462306a36Sopenharmony_ci	drvdata->buf++;
28562306a36Sopenharmony_ci	drvdata->buf_remaining--;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (drvdata->buf_remaining == 0) {
28862306a36Sopenharmony_ci		/* No more data, this message is completed. */
28962306a36Sopenharmony_ci		drvdata->msgs_remaining--;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		if (drvdata->msgs_remaining == 0) {
29262306a36Sopenharmony_ci			/* No more messages, stop */
29362306a36Sopenharmony_ci			drvdata->state = GXP_I2C_COMP;
29462306a36Sopenharmony_ci			gxp_i2c_stop(drvdata);
29562306a36Sopenharmony_ci			return;
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci		/* Move to next message and start transfer */
29862306a36Sopenharmony_ci		drvdata->curr_msg++;
29962306a36Sopenharmony_ci		gxp_i2c_restart(drvdata);
30062306a36Sopenharmony_ci		return;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* Ack the slave to make it send next byte */
30462306a36Sopenharmony_ci	drvdata->state = GXP_I2C_RDATA_PHASE;
30562306a36Sopenharmony_ci	if (drvdata->buf_remaining == 1) {
30662306a36Sopenharmony_ci		/* The last data, do not ack */
30762306a36Sopenharmony_ci		writeb(MASTER_EVT_CLR | RW_CMD,
30862306a36Sopenharmony_ci		       drvdata->base + GXP_I2CMCMD);
30962306a36Sopenharmony_ci	} else {
31062306a36Sopenharmony_ci		/* Read data and ack it */
31162306a36Sopenharmony_ci		writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
31262306a36Sopenharmony_ci		       RW_CMD, drvdata->base + GXP_I2CMCMD);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void gxp_i2c_chk_data_ack(struct gxp_i2c_drvdata *drvdata)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	u16 value;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	value = readb(drvdata->base + GXP_I2CSTAT);
32162306a36Sopenharmony_ci	if (!(value & MASK_ACK)) {
32262306a36Sopenharmony_ci		/* Received No ack, stop */
32362306a36Sopenharmony_ci		drvdata->state = GXP_I2C_DATA_NACK;
32462306a36Sopenharmony_ci		gxp_i2c_stop(drvdata);
32562306a36Sopenharmony_ci		return;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Got ack, check if there is more data to write */
32962306a36Sopenharmony_ci	if (drvdata->buf_remaining == 0) {
33062306a36Sopenharmony_ci		/* No more data, this message is completed */
33162306a36Sopenharmony_ci		drvdata->msgs_remaining--;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		if (drvdata->msgs_remaining == 0) {
33462306a36Sopenharmony_ci			/* No more messages, stop */
33562306a36Sopenharmony_ci			drvdata->state = GXP_I2C_COMP;
33662306a36Sopenharmony_ci			gxp_i2c_stop(drvdata);
33762306a36Sopenharmony_ci			return;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci		/* Move to next message and start transfer */
34062306a36Sopenharmony_ci		drvdata->curr_msg++;
34162306a36Sopenharmony_ci		gxp_i2c_restart(drvdata);
34262306a36Sopenharmony_ci		return;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Write data to slave */
34662306a36Sopenharmony_ci	value = *drvdata->buf;
34762306a36Sopenharmony_ci	value = value << 8;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Clear master event */
35062306a36Sopenharmony_ci	value |= MASTER_EVT_CLR;
35162306a36Sopenharmony_ci	drvdata->buf++;
35262306a36Sopenharmony_ci	drvdata->buf_remaining--;
35362306a36Sopenharmony_ci	drvdata->state = GXP_I2C_WDATA_PHASE;
35462306a36Sopenharmony_ci	writew(value, drvdata->base + GXP_I2CMCMD);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	u8 value;
36062306a36Sopenharmony_ci	u8 buf;
36162306a36Sopenharmony_ci	int ret;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	value = readb(drvdata->base + GXP_I2CEVTERR);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Received start or stop event */
36662306a36Sopenharmony_ci	if (value & MASK_SLAVE_CMD_EVENT) {
36762306a36Sopenharmony_ci		value = readb(drvdata->base + GXP_I2CSTAT);
36862306a36Sopenharmony_ci		/* Master sent stop */
36962306a36Sopenharmony_ci		if (value & MASK_STOP_EVENT) {
37062306a36Sopenharmony_ci			if (drvdata->stopped == 0)
37162306a36Sopenharmony_ci				i2c_slave_event(drvdata->slave, I2C_SLAVE_STOP, &buf);
37262306a36Sopenharmony_ci			writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
37362306a36Sopenharmony_ci			       SLAVE_ACK_ENAB | SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
37462306a36Sopenharmony_ci			drvdata->stopped = 1;
37562306a36Sopenharmony_ci		} else {
37662306a36Sopenharmony_ci			/* Master sent start and  wants to read */
37762306a36Sopenharmony_ci			drvdata->stopped = 0;
37862306a36Sopenharmony_ci			if (value & MASK_RW) {
37962306a36Sopenharmony_ci				i2c_slave_event(drvdata->slave,
38062306a36Sopenharmony_ci						I2C_SLAVE_READ_REQUESTED, &buf);
38162306a36Sopenharmony_ci				value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
38262306a36Sopenharmony_ci						    SLAVE_EVT_STALL);
38362306a36Sopenharmony_ci				writew(value, drvdata->base + GXP_I2CSCMD);
38462306a36Sopenharmony_ci			} else {
38562306a36Sopenharmony_ci				/* Master wants to write to us */
38662306a36Sopenharmony_ci				ret = i2c_slave_event(drvdata->slave,
38762306a36Sopenharmony_ci						      I2C_SLAVE_WRITE_REQUESTED, &buf);
38862306a36Sopenharmony_ci				if (!ret) {
38962306a36Sopenharmony_ci					/* Ack next byte from master */
39062306a36Sopenharmony_ci					writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
39162306a36Sopenharmony_ci					       SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
39262306a36Sopenharmony_ci					       drvdata->base + GXP_I2CSCMD);
39362306a36Sopenharmony_ci				} else {
39462306a36Sopenharmony_ci					/* Nack next byte from master */
39562306a36Sopenharmony_ci					writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
39662306a36Sopenharmony_ci					       SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
39762306a36Sopenharmony_ci				}
39862306a36Sopenharmony_ci			}
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci	} else if (value & MASK_SLAVE_DATA_EVENT) {
40162306a36Sopenharmony_ci		value = readb(drvdata->base + GXP_I2CSTAT);
40262306a36Sopenharmony_ci		/* Master wants to read */
40362306a36Sopenharmony_ci		if (value & MASK_RW) {
40462306a36Sopenharmony_ci			/* Master wants another byte */
40562306a36Sopenharmony_ci			if (value & MASK_ACK) {
40662306a36Sopenharmony_ci				i2c_slave_event(drvdata->slave,
40762306a36Sopenharmony_ci						I2C_SLAVE_READ_PROCESSED, &buf);
40862306a36Sopenharmony_ci				value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
40962306a36Sopenharmony_ci						    SLAVE_EVT_STALL);
41062306a36Sopenharmony_ci				writew(value, drvdata->base + GXP_I2CSCMD);
41162306a36Sopenharmony_ci			} else {
41262306a36Sopenharmony_ci				/* No more bytes needed */
41362306a36Sopenharmony_ci				writew(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
41462306a36Sopenharmony_ci				       SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
41562306a36Sopenharmony_ci				       drvdata->base + GXP_I2CSCMD);
41662306a36Sopenharmony_ci			}
41762306a36Sopenharmony_ci		} else {
41862306a36Sopenharmony_ci			/* Master wants to write to us */
41962306a36Sopenharmony_ci			value = readb(drvdata->base + GXP_I2CSNPDAT);
42062306a36Sopenharmony_ci			buf = (uint8_t)value;
42162306a36Sopenharmony_ci			ret = i2c_slave_event(drvdata->slave,
42262306a36Sopenharmony_ci					      I2C_SLAVE_WRITE_RECEIVED, &buf);
42362306a36Sopenharmony_ci			if (!ret) {
42462306a36Sopenharmony_ci				/* Ack next byte from master */
42562306a36Sopenharmony_ci				writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
42662306a36Sopenharmony_ci				       SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
42762306a36Sopenharmony_ci				       drvdata->base + GXP_I2CSCMD);
42862306a36Sopenharmony_ci			} else {
42962306a36Sopenharmony_ci				/* Nack next byte from master */
43062306a36Sopenharmony_ci				writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
43162306a36Sopenharmony_ci				       SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
43262306a36Sopenharmony_ci			}
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci	} else {
43562306a36Sopenharmony_ci		return false;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return true;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic irqreturn_t gxp_i2c_irq_handler(int irq, void *_drvdata)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata = (struct gxp_i2c_drvdata *)_drvdata;
44462306a36Sopenharmony_ci	u32 value;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* Check if the interrupt is for the current engine */
44762306a36Sopenharmony_ci	regmap_read(i2cg_map, GXP_I2CINTSTAT, &value);
44862306a36Sopenharmony_ci	if (!(value & BIT(drvdata->engine)))
44962306a36Sopenharmony_ci		return IRQ_NONE;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	value = readb(drvdata->base + GXP_I2CEVTERR);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* Error */
45462306a36Sopenharmony_ci	if (value & ~(MASK_MASTER_EVENT | MASK_SLAVE_CMD_EVENT |
45562306a36Sopenharmony_ci				MASK_SLAVE_DATA_EVENT)) {
45662306a36Sopenharmony_ci		/* Clear all events */
45762306a36Sopenharmony_ci		writeb(0x00, drvdata->base + GXP_I2CEVTERR);
45862306a36Sopenharmony_ci		drvdata->state = GXP_I2C_ERROR;
45962306a36Sopenharmony_ci		gxp_i2c_stop(drvdata);
46062306a36Sopenharmony_ci		return IRQ_HANDLED;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_I2C_SLAVE)) {
46462306a36Sopenharmony_ci		/* Slave mode */
46562306a36Sopenharmony_ci		if (value & (MASK_SLAVE_CMD_EVENT | MASK_SLAVE_DATA_EVENT)) {
46662306a36Sopenharmony_ci			if (gxp_i2c_slave_irq_handler(drvdata))
46762306a36Sopenharmony_ci				return IRQ_HANDLED;
46862306a36Sopenharmony_ci			return IRQ_NONE;
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/*  Master mode */
47362306a36Sopenharmony_ci	switch (drvdata->state) {
47462306a36Sopenharmony_ci	case GXP_I2C_ADDR_PHASE:
47562306a36Sopenharmony_ci		gxp_i2c_chk_addr_ack(drvdata);
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	case GXP_I2C_RDATA_PHASE:
47962306a36Sopenharmony_ci		gxp_i2c_ack_data(drvdata);
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	case GXP_I2C_WDATA_PHASE:
48362306a36Sopenharmony_ci		gxp_i2c_chk_data_ack(drvdata);
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return IRQ_HANDLED;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic void gxp_i2c_init(struct gxp_i2c_drvdata *drvdata)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	drvdata->state = GXP_I2C_IDLE;
49362306a36Sopenharmony_ci	writeb(2000000 / drvdata->t.bus_freq_hz,
49462306a36Sopenharmony_ci	       drvdata->base + GXP_I2CFREQDIV);
49562306a36Sopenharmony_ci	writeb(FILTER_CNT | FAIRNESS_CNT,
49662306a36Sopenharmony_ci	       drvdata->base + GXP_I2CFLTFAIR);
49762306a36Sopenharmony_ci	writeb(GXP_DATA_EDGE_RST_CTRL, drvdata->base + GXP_I2CTMOEDG);
49862306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2CCYCTIM);
49962306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2CSNPAA);
50062306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2CADVFEAT);
50162306a36Sopenharmony_ci	writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
50262306a36Sopenharmony_ci	       SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
50362306a36Sopenharmony_ci	writeb(MASTER_EVT_CLR, drvdata->base + GXP_I2CMCMD);
50462306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2CEVTERR);
50562306a36Sopenharmony_ci	writeb(0x00, drvdata->base + GXP_I2COWNADR);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int gxp_i2c_probe(struct platform_device *pdev)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata;
51162306a36Sopenharmony_ci	int rc;
51262306a36Sopenharmony_ci	struct i2c_adapter *adapter;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (!i2cg_map) {
51562306a36Sopenharmony_ci		i2cg_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
51662306a36Sopenharmony_ci							   "hpe,sysreg");
51762306a36Sopenharmony_ci		if (IS_ERR(i2cg_map)) {
51862306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, PTR_ERR(i2cg_map),
51962306a36Sopenharmony_ci					     "failed to map i2cg_handle\n");
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		/* Disable interrupt */
52362306a36Sopenharmony_ci		regmap_update_bits(i2cg_map, GXP_I2CINTEN, 0x00000FFF, 0);
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata),
52762306a36Sopenharmony_ci			       GFP_KERNEL);
52862306a36Sopenharmony_ci	if (!drvdata)
52962306a36Sopenharmony_ci		return -ENOMEM;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	platform_set_drvdata(pdev, drvdata);
53262306a36Sopenharmony_ci	drvdata->dev = &pdev->dev;
53362306a36Sopenharmony_ci	init_completion(&drvdata->completion);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	drvdata->base = devm_platform_ioremap_resource(pdev, 0);
53662306a36Sopenharmony_ci	if (IS_ERR(drvdata->base))
53762306a36Sopenharmony_ci		return PTR_ERR(drvdata->base);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* Use physical memory address to determine which I2C engine this is. */
54062306a36Sopenharmony_ci	drvdata->engine = ((size_t)drvdata->base & 0xf00) >> 8;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (drvdata->engine >= GXP_MAX_I2C_ENGINE) {
54362306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, -EINVAL, "i2c engine% is unsupported\n",
54462306a36Sopenharmony_ci			drvdata->engine);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	rc = platform_get_irq(pdev, 0);
54862306a36Sopenharmony_ci	if (rc < 0)
54962306a36Sopenharmony_ci		return rc;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	drvdata->irq = rc;
55262306a36Sopenharmony_ci	rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler,
55362306a36Sopenharmony_ci			      IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata);
55462306a36Sopenharmony_ci	if (rc < 0)
55562306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, rc, "irq request failed\n");
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	gxp_i2c_init(drvdata);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* Enable interrupt */
56262306a36Sopenharmony_ci	regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine),
56362306a36Sopenharmony_ci			   BIT(drvdata->engine));
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	adapter = &drvdata->adapter;
56662306a36Sopenharmony_ci	i2c_set_adapdata(adapter, drvdata);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	adapter->owner = THIS_MODULE;
56962306a36Sopenharmony_ci	strscpy(adapter->name, "HPE GXP I2C adapter", sizeof(adapter->name));
57062306a36Sopenharmony_ci	adapter->algo = &gxp_i2c_algo;
57162306a36Sopenharmony_ci	adapter->dev.parent = &pdev->dev;
57262306a36Sopenharmony_ci	adapter->dev.of_node = pdev->dev.of_node;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	rc = i2c_add_adapter(adapter);
57562306a36Sopenharmony_ci	if (rc)
57662306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, rc, "i2c add adapter failed\n");
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	return 0;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic void gxp_i2c_remove(struct platform_device *pdev)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct gxp_i2c_drvdata *drvdata = platform_get_drvdata(pdev);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Disable interrupt */
58662306a36Sopenharmony_ci	regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine), 0);
58762306a36Sopenharmony_ci	i2c_del_adapter(&drvdata->adapter);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic const struct of_device_id gxp_i2c_of_match[] = {
59162306a36Sopenharmony_ci	{ .compatible = "hpe,gxp-i2c" },
59262306a36Sopenharmony_ci	{},
59362306a36Sopenharmony_ci};
59462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, gxp_i2c_of_match);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic struct platform_driver gxp_i2c_driver = {
59762306a36Sopenharmony_ci	.probe	= gxp_i2c_probe,
59862306a36Sopenharmony_ci	.remove_new = gxp_i2c_remove,
59962306a36Sopenharmony_ci	.driver = {
60062306a36Sopenharmony_ci		.name = "gxp-i2c",
60162306a36Sopenharmony_ci		.of_match_table = gxp_i2c_of_match,
60262306a36Sopenharmony_ci	},
60362306a36Sopenharmony_ci};
60462306a36Sopenharmony_cimodule_platform_driver(gxp_i2c_driver);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ciMODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
60762306a36Sopenharmony_ciMODULE_DESCRIPTION("HPE GXP I2C bus driver");
60862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
609