162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/acpi.h>
562306a36Sopenharmony_ci#include <linux/clk.h>
662306a36Sopenharmony_ci#include <linux/dmaengine.h>
762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
862306a36Sopenharmony_ci#include <linux/dma/qcom-gpi-dma.h>
962306a36Sopenharmony_ci#include <linux/err.h>
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1762306a36Sopenharmony_ci#include <linux/soc/qcom/geni-se.h>
1862306a36Sopenharmony_ci#include <linux/spinlock.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define SE_I2C_TX_TRANS_LEN		0x26c
2162306a36Sopenharmony_ci#define SE_I2C_RX_TRANS_LEN		0x270
2262306a36Sopenharmony_ci#define SE_I2C_SCL_COUNTERS		0x278
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define SE_I2C_ERR  (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\
2562306a36Sopenharmony_ci			M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN)
2662306a36Sopenharmony_ci#define SE_I2C_ABORT		BIT(1)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* M_CMD OP codes for I2C */
2962306a36Sopenharmony_ci#define I2C_WRITE		0x1
3062306a36Sopenharmony_ci#define I2C_READ		0x2
3162306a36Sopenharmony_ci#define I2C_WRITE_READ		0x3
3262306a36Sopenharmony_ci#define I2C_ADDR_ONLY		0x4
3362306a36Sopenharmony_ci#define I2C_BUS_CLEAR		0x6
3462306a36Sopenharmony_ci#define I2C_STOP_ON_BUS		0x7
3562306a36Sopenharmony_ci/* M_CMD params for I2C */
3662306a36Sopenharmony_ci#define PRE_CMD_DELAY		BIT(0)
3762306a36Sopenharmony_ci#define TIMESTAMP_BEFORE	BIT(1)
3862306a36Sopenharmony_ci#define STOP_STRETCH		BIT(2)
3962306a36Sopenharmony_ci#define TIMESTAMP_AFTER		BIT(3)
4062306a36Sopenharmony_ci#define POST_COMMAND_DELAY	BIT(4)
4162306a36Sopenharmony_ci#define IGNORE_ADD_NACK		BIT(6)
4262306a36Sopenharmony_ci#define READ_FINISHED_WITH_ACK	BIT(7)
4362306a36Sopenharmony_ci#define BYPASS_ADDR_PHASE	BIT(8)
4462306a36Sopenharmony_ci#define SLV_ADDR_MSK		GENMASK(15, 9)
4562306a36Sopenharmony_ci#define SLV_ADDR_SHFT		9
4662306a36Sopenharmony_ci/* I2C SCL COUNTER fields */
4762306a36Sopenharmony_ci#define HIGH_COUNTER_MSK	GENMASK(29, 20)
4862306a36Sopenharmony_ci#define HIGH_COUNTER_SHFT	20
4962306a36Sopenharmony_ci#define LOW_COUNTER_MSK		GENMASK(19, 10)
5062306a36Sopenharmony_ci#define LOW_COUNTER_SHFT	10
5162306a36Sopenharmony_ci#define CYCLE_COUNTER_MSK	GENMASK(9, 0)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define I2C_PACK_TX		BIT(0)
5462306a36Sopenharmony_ci#define I2C_PACK_RX		BIT(1)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cienum geni_i2c_err_code {
5762306a36Sopenharmony_ci	GP_IRQ0,
5862306a36Sopenharmony_ci	NACK,
5962306a36Sopenharmony_ci	GP_IRQ2,
6062306a36Sopenharmony_ci	BUS_PROTO,
6162306a36Sopenharmony_ci	ARB_LOST,
6262306a36Sopenharmony_ci	GP_IRQ5,
6362306a36Sopenharmony_ci	GENI_OVERRUN,
6462306a36Sopenharmony_ci	GENI_ILLEGAL_CMD,
6562306a36Sopenharmony_ci	GENI_ABORT_DONE,
6662306a36Sopenharmony_ci	GENI_TIMEOUT,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define DM_I2C_CB_ERR		((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
7062306a36Sopenharmony_ci									<< 5)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define I2C_AUTO_SUSPEND_DELAY	250
7362306a36Sopenharmony_ci#define KHZ(freq)		(1000 * freq)
7462306a36Sopenharmony_ci#define PACKING_BYTES_PW	4
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define ABORT_TIMEOUT		HZ
7762306a36Sopenharmony_ci#define XFER_TIMEOUT		HZ
7862306a36Sopenharmony_ci#define RST_TIMEOUT		HZ
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct geni_i2c_dev {
8162306a36Sopenharmony_ci	struct geni_se se;
8262306a36Sopenharmony_ci	u32 tx_wm;
8362306a36Sopenharmony_ci	int irq;
8462306a36Sopenharmony_ci	int err;
8562306a36Sopenharmony_ci	struct i2c_adapter adap;
8662306a36Sopenharmony_ci	struct completion done;
8762306a36Sopenharmony_ci	struct i2c_msg *cur;
8862306a36Sopenharmony_ci	int cur_wr;
8962306a36Sopenharmony_ci	int cur_rd;
9062306a36Sopenharmony_ci	spinlock_t lock;
9162306a36Sopenharmony_ci	struct clk *core_clk;
9262306a36Sopenharmony_ci	u32 clk_freq_out;
9362306a36Sopenharmony_ci	const struct geni_i2c_clk_fld *clk_fld;
9462306a36Sopenharmony_ci	int suspended;
9562306a36Sopenharmony_ci	void *dma_buf;
9662306a36Sopenharmony_ci	size_t xfer_len;
9762306a36Sopenharmony_ci	dma_addr_t dma_addr;
9862306a36Sopenharmony_ci	struct dma_chan *tx_c;
9962306a36Sopenharmony_ci	struct dma_chan *rx_c;
10062306a36Sopenharmony_ci	bool gpi_mode;
10162306a36Sopenharmony_ci	bool abort_done;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct geni_i2c_desc {
10562306a36Sopenharmony_ci	bool has_core_clk;
10662306a36Sopenharmony_ci	char *icc_ddr;
10762306a36Sopenharmony_ci	bool no_dma_support;
10862306a36Sopenharmony_ci	unsigned int tx_fifo_depth;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct geni_i2c_err_log {
11262306a36Sopenharmony_ci	int err;
11362306a36Sopenharmony_ci	const char *msg;
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const struct geni_i2c_err_log gi2c_log[] = {
11762306a36Sopenharmony_ci	[GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"},
11862306a36Sopenharmony_ci	[NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"},
11962306a36Sopenharmony_ci	[GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"},
12062306a36Sopenharmony_ci	[BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unexpected start/stop"},
12162306a36Sopenharmony_ci	[ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"},
12262306a36Sopenharmony_ci	[GP_IRQ5] = {-EIO, "Unknown I2C err GP IRQ5"},
12362306a36Sopenharmony_ci	[GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"},
12462306a36Sopenharmony_ci	[GENI_ILLEGAL_CMD] = {-EIO, "Illegal cmd, check GENI cmd-state machine"},
12562306a36Sopenharmony_ci	[GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"},
12662306a36Sopenharmony_ci	[GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistruct geni_i2c_clk_fld {
13062306a36Sopenharmony_ci	u32	clk_freq_out;
13162306a36Sopenharmony_ci	u8	clk_div;
13262306a36Sopenharmony_ci	u8	t_high_cnt;
13362306a36Sopenharmony_ci	u8	t_low_cnt;
13462306a36Sopenharmony_ci	u8	t_cycle_cnt;
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * Hardware uses the underlying formula to calculate time periods of
13962306a36Sopenharmony_ci * SCL clock cycle. Firmware uses some additional cycles excluded from the
14062306a36Sopenharmony_ci * below formula and it is confirmed that the time periods are within
14162306a36Sopenharmony_ci * specification limits.
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock
14462306a36Sopenharmony_ci * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock
14562306a36Sopenharmony_ci * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock
14662306a36Sopenharmony_ci * clk_freq_out = t / t_cycle
14762306a36Sopenharmony_ci * source_clock = 19.2 MHz
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic const struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
15062306a36Sopenharmony_ci	{KHZ(100), 7, 10, 11, 26},
15162306a36Sopenharmony_ci	{KHZ(400), 2,  5, 12, 24},
15262306a36Sopenharmony_ci	{KHZ(1000), 1, 3,  9, 18},
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	int i;
15862306a36Sopenharmony_ci	const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
16162306a36Sopenharmony_ci		if (itr->clk_freq_out == gi2c->clk_freq_out) {
16262306a36Sopenharmony_ci			gi2c->clk_fld = itr;
16362306a36Sopenharmony_ci			return 0;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	return -EINVAL;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
17262306a36Sopenharmony_ci	u32 val;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN;
17762306a36Sopenharmony_ci	writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	val = itr->t_high_cnt << HIGH_COUNTER_SHFT;
18062306a36Sopenharmony_ci	val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
18162306a36Sopenharmony_ci	val |= itr->t_cycle_cnt;
18262306a36Sopenharmony_ci	writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void geni_i2c_err_misc(struct geni_i2c_dev *gi2c)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0);
18862306a36Sopenharmony_ci	u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
18962306a36Sopenharmony_ci	u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS);
19062306a36Sopenharmony_ci	u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS);
19162306a36Sopenharmony_ci	u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
19262306a36Sopenharmony_ci	u32 rx_st, tx_st;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (dma) {
19562306a36Sopenharmony_ci		rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
19662306a36Sopenharmony_ci		tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
19762306a36Sopenharmony_ci	} else {
19862306a36Sopenharmony_ci		rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
19962306a36Sopenharmony_ci		tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci	dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
20262306a36Sopenharmony_ci		dma, tx_st, rx_st, m_stat);
20362306a36Sopenharmony_ci	dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
20462306a36Sopenharmony_ci		m_cmd, geni_s, geni_ios);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	if (!gi2c->err)
21062306a36Sopenharmony_ci		gi2c->err = gi2c_log[err].err;
21162306a36Sopenharmony_ci	if (gi2c->cur)
21262306a36Sopenharmony_ci		dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
21362306a36Sopenharmony_ci			gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	switch (err) {
21662306a36Sopenharmony_ci	case GENI_ABORT_DONE:
21762306a36Sopenharmony_ci		gi2c->abort_done = true;
21862306a36Sopenharmony_ci		break;
21962306a36Sopenharmony_ci	case NACK:
22062306a36Sopenharmony_ci	case GENI_TIMEOUT:
22162306a36Sopenharmony_ci		dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
22262306a36Sopenharmony_ci		break;
22362306a36Sopenharmony_ci	default:
22462306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
22562306a36Sopenharmony_ci		geni_i2c_err_misc(gi2c);
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic irqreturn_t geni_i2c_irq(int irq, void *dev)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = dev;
23362306a36Sopenharmony_ci	void __iomem *base = gi2c->se.base;
23462306a36Sopenharmony_ci	int j, p;
23562306a36Sopenharmony_ci	u32 m_stat;
23662306a36Sopenharmony_ci	u32 rx_st;
23762306a36Sopenharmony_ci	u32 dm_tx_st;
23862306a36Sopenharmony_ci	u32 dm_rx_st;
23962306a36Sopenharmony_ci	u32 dma;
24062306a36Sopenharmony_ci	u32 val;
24162306a36Sopenharmony_ci	struct i2c_msg *cur;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	spin_lock(&gi2c->lock);
24462306a36Sopenharmony_ci	m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS);
24562306a36Sopenharmony_ci	rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS);
24662306a36Sopenharmony_ci	dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT);
24762306a36Sopenharmony_ci	dm_rx_st = readl_relaxed(base + SE_DMA_RX_IRQ_STAT);
24862306a36Sopenharmony_ci	dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
24962306a36Sopenharmony_ci	cur = gi2c->cur;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (!cur ||
25262306a36Sopenharmony_ci	    m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
25362306a36Sopenharmony_ci	    dm_rx_st & (DM_I2C_CB_ERR)) {
25462306a36Sopenharmony_ci		if (m_stat & M_GP_IRQ_1_EN)
25562306a36Sopenharmony_ci			geni_i2c_err(gi2c, NACK);
25662306a36Sopenharmony_ci		if (m_stat & M_GP_IRQ_3_EN)
25762306a36Sopenharmony_ci			geni_i2c_err(gi2c, BUS_PROTO);
25862306a36Sopenharmony_ci		if (m_stat & M_GP_IRQ_4_EN)
25962306a36Sopenharmony_ci			geni_i2c_err(gi2c, ARB_LOST);
26062306a36Sopenharmony_ci		if (m_stat & M_CMD_OVERRUN_EN)
26162306a36Sopenharmony_ci			geni_i2c_err(gi2c, GENI_OVERRUN);
26262306a36Sopenharmony_ci		if (m_stat & M_ILLEGAL_CMD_EN)
26362306a36Sopenharmony_ci			geni_i2c_err(gi2c, GENI_ILLEGAL_CMD);
26462306a36Sopenharmony_ci		if (m_stat & M_CMD_ABORT_EN)
26562306a36Sopenharmony_ci			geni_i2c_err(gi2c, GENI_ABORT_DONE);
26662306a36Sopenharmony_ci		if (m_stat & M_GP_IRQ_0_EN)
26762306a36Sopenharmony_ci			geni_i2c_err(gi2c, GP_IRQ0);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		/* Disable the TX Watermark interrupt to stop TX */
27062306a36Sopenharmony_ci		if (!dma)
27162306a36Sopenharmony_ci			writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
27262306a36Sopenharmony_ci	} else if (dma) {
27362306a36Sopenharmony_ci		dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
27462306a36Sopenharmony_ci			dm_tx_st, dm_rx_st);
27562306a36Sopenharmony_ci	} else if (cur->flags & I2C_M_RD &&
27662306a36Sopenharmony_ci		   m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
27762306a36Sopenharmony_ci		u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		for (j = 0; j < rxcnt; j++) {
28062306a36Sopenharmony_ci			p = 0;
28162306a36Sopenharmony_ci			val = readl_relaxed(base + SE_GENI_RX_FIFOn);
28262306a36Sopenharmony_ci			while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
28362306a36Sopenharmony_ci				cur->buf[gi2c->cur_rd++] = val & 0xff;
28462306a36Sopenharmony_ci				val >>= 8;
28562306a36Sopenharmony_ci				p++;
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci			if (gi2c->cur_rd == cur->len)
28862306a36Sopenharmony_ci				break;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci	} else if (!(cur->flags & I2C_M_RD) &&
29162306a36Sopenharmony_ci		   m_stat & M_TX_FIFO_WATERMARK_EN) {
29262306a36Sopenharmony_ci		for (j = 0; j < gi2c->tx_wm; j++) {
29362306a36Sopenharmony_ci			u32 temp;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci			val = 0;
29662306a36Sopenharmony_ci			p = 0;
29762306a36Sopenharmony_ci			while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
29862306a36Sopenharmony_ci				temp = cur->buf[gi2c->cur_wr++];
29962306a36Sopenharmony_ci				val |= temp << (p * 8);
30062306a36Sopenharmony_ci				p++;
30162306a36Sopenharmony_ci			}
30262306a36Sopenharmony_ci			writel_relaxed(val, base + SE_GENI_TX_FIFOn);
30362306a36Sopenharmony_ci			/* TX Complete, Disable the TX Watermark interrupt */
30462306a36Sopenharmony_ci			if (gi2c->cur_wr == cur->len) {
30562306a36Sopenharmony_ci				writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
30662306a36Sopenharmony_ci				break;
30762306a36Sopenharmony_ci			}
30862306a36Sopenharmony_ci		}
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (m_stat)
31262306a36Sopenharmony_ci		writel_relaxed(m_stat, base + SE_GENI_M_IRQ_CLEAR);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (dma && dm_tx_st)
31562306a36Sopenharmony_ci		writel_relaxed(dm_tx_st, base + SE_DMA_TX_IRQ_CLR);
31662306a36Sopenharmony_ci	if (dma && dm_rx_st)
31762306a36Sopenharmony_ci		writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* if this is err with done-bit not set, handle that through timeout. */
32062306a36Sopenharmony_ci	if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
32162306a36Sopenharmony_ci	    dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
32262306a36Sopenharmony_ci	    dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
32362306a36Sopenharmony_ci		complete(&gi2c->done);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	spin_unlock(&gi2c->lock);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return IRQ_HANDLED;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	unsigned long time_left = ABORT_TIMEOUT;
33362306a36Sopenharmony_ci	unsigned long flags;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	spin_lock_irqsave(&gi2c->lock, flags);
33662306a36Sopenharmony_ci	geni_i2c_err(gi2c, GENI_TIMEOUT);
33762306a36Sopenharmony_ci	gi2c->cur = NULL;
33862306a36Sopenharmony_ci	gi2c->abort_done = false;
33962306a36Sopenharmony_ci	geni_se_abort_m_cmd(&gi2c->se);
34062306a36Sopenharmony_ci	spin_unlock_irqrestore(&gi2c->lock, flags);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	do {
34362306a36Sopenharmony_ci		time_left = wait_for_completion_timeout(&gi2c->done, time_left);
34462306a36Sopenharmony_ci	} while (!gi2c->abort_done && time_left);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (!time_left)
34762306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	u32 val;
35362306a36Sopenharmony_ci	unsigned long time_left = RST_TIMEOUT;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
35662306a36Sopenharmony_ci	do {
35762306a36Sopenharmony_ci		time_left = wait_for_completion_timeout(&gi2c->done, time_left);
35862306a36Sopenharmony_ci		val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
35962306a36Sopenharmony_ci	} while (!(val & RX_RESET_DONE) && time_left);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (!(val & RX_RESET_DONE))
36262306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	u32 val;
36862306a36Sopenharmony_ci	unsigned long time_left = RST_TIMEOUT;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
37162306a36Sopenharmony_ci	do {
37262306a36Sopenharmony_ci		time_left = wait_for_completion_timeout(&gi2c->done, time_left);
37362306a36Sopenharmony_ci		val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
37462306a36Sopenharmony_ci	} while (!(val & TX_RESET_DONE) && time_left);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!(val & TX_RESET_DONE))
37762306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c,
38162306a36Sopenharmony_ci				     struct i2c_msg *cur)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	gi2c->cur_rd = 0;
38462306a36Sopenharmony_ci	if (gi2c->dma_buf) {
38562306a36Sopenharmony_ci		if (gi2c->err)
38662306a36Sopenharmony_ci			geni_i2c_rx_fsm_rst(gi2c);
38762306a36Sopenharmony_ci		geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
38862306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
39362306a36Sopenharmony_ci				     struct i2c_msg *cur)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	gi2c->cur_wr = 0;
39662306a36Sopenharmony_ci	if (gi2c->dma_buf) {
39762306a36Sopenharmony_ci		if (gi2c->err)
39862306a36Sopenharmony_ci			geni_i2c_tx_fsm_rst(gi2c);
39962306a36Sopenharmony_ci		geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
40062306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
40562306a36Sopenharmony_ci				u32 m_param)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	dma_addr_t rx_dma = 0;
40862306a36Sopenharmony_ci	unsigned long time_left;
40962306a36Sopenharmony_ci	void *dma_buf;
41062306a36Sopenharmony_ci	struct geni_se *se = &gi2c->se;
41162306a36Sopenharmony_ci	size_t len = msg->len;
41262306a36Sopenharmony_ci	struct i2c_msg *cur;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
41562306a36Sopenharmony_ci	if (dma_buf)
41662306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_DMA);
41762306a36Sopenharmony_ci	else
41862306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_FIFO);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
42162306a36Sopenharmony_ci	geni_se_setup_m_cmd(se, I2C_READ, m_param);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
42462306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_FIFO);
42562306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
42662306a36Sopenharmony_ci		dma_buf = NULL;
42762306a36Sopenharmony_ci	} else {
42862306a36Sopenharmony_ci		gi2c->xfer_len = len;
42962306a36Sopenharmony_ci		gi2c->dma_addr = rx_dma;
43062306a36Sopenharmony_ci		gi2c->dma_buf = dma_buf;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	cur = gi2c->cur;
43462306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
43562306a36Sopenharmony_ci	if (!time_left)
43662306a36Sopenharmony_ci		geni_i2c_abort_xfer(gi2c);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	geni_i2c_rx_msg_cleanup(gi2c, cur);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return gi2c->err;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
44462306a36Sopenharmony_ci				u32 m_param)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	dma_addr_t tx_dma = 0;
44762306a36Sopenharmony_ci	unsigned long time_left;
44862306a36Sopenharmony_ci	void *dma_buf;
44962306a36Sopenharmony_ci	struct geni_se *se = &gi2c->se;
45062306a36Sopenharmony_ci	size_t len = msg->len;
45162306a36Sopenharmony_ci	struct i2c_msg *cur;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
45462306a36Sopenharmony_ci	if (dma_buf)
45562306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_DMA);
45662306a36Sopenharmony_ci	else
45762306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_FIFO);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
46062306a36Sopenharmony_ci	geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
46362306a36Sopenharmony_ci		geni_se_select_mode(se, GENI_SE_FIFO);
46462306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
46562306a36Sopenharmony_ci		dma_buf = NULL;
46662306a36Sopenharmony_ci	} else {
46762306a36Sopenharmony_ci		gi2c->xfer_len = len;
46862306a36Sopenharmony_ci		gi2c->dma_addr = tx_dma;
46962306a36Sopenharmony_ci		gi2c->dma_buf = dma_buf;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!dma_buf) /* Get FIFO IRQ */
47362306a36Sopenharmony_ci		writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	cur = gi2c->cur;
47662306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
47762306a36Sopenharmony_ci	if (!time_left)
47862306a36Sopenharmony_ci		geni_i2c_abort_xfer(gi2c);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	geni_i2c_tx_msg_cleanup(gi2c, cur);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return gi2c->err;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = cb;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (result->result != DMA_TRANS_NOERROR) {
49062306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
49162306a36Sopenharmony_ci		gi2c->err = -EIO;
49262306a36Sopenharmony_ci	} else if (result->residue) {
49362306a36Sopenharmony_ci		dev_dbg(gi2c->se.dev, "DMA xfer has pending: %d\n", result->residue);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	complete(&gi2c->done);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
50062306a36Sopenharmony_ci			       void *tx_buf, dma_addr_t tx_addr,
50162306a36Sopenharmony_ci			       void *rx_buf, dma_addr_t rx_addr)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	if (tx_buf) {
50462306a36Sopenharmony_ci		dma_unmap_single(gi2c->se.dev->parent, tx_addr, msg->len, DMA_TO_DEVICE);
50562306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(tx_buf, msg, !gi2c->err);
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (rx_buf) {
50962306a36Sopenharmony_ci		dma_unmap_single(gi2c->se.dev->parent, rx_addr, msg->len, DMA_FROM_DEVICE);
51062306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(rx_buf, msg, !gi2c->err);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
51562306a36Sopenharmony_ci			struct dma_slave_config *config, dma_addr_t *dma_addr_p,
51662306a36Sopenharmony_ci			void **buf, unsigned int op, struct dma_chan *dma_chan)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct gpi_i2c_config *peripheral;
51962306a36Sopenharmony_ci	unsigned int flags;
52062306a36Sopenharmony_ci	void *dma_buf;
52162306a36Sopenharmony_ci	dma_addr_t addr;
52262306a36Sopenharmony_ci	enum dma_data_direction map_dirn;
52362306a36Sopenharmony_ci	enum dma_transfer_direction dma_dirn;
52462306a36Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
52562306a36Sopenharmony_ci	int ret;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	peripheral = config->peripheral_config;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	dma_buf = i2c_get_dma_safe_msg_buf(msg, 1);
53062306a36Sopenharmony_ci	if (!dma_buf)
53162306a36Sopenharmony_ci		return -ENOMEM;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (op == I2C_WRITE)
53462306a36Sopenharmony_ci		map_dirn = DMA_TO_DEVICE;
53562306a36Sopenharmony_ci	else
53662306a36Sopenharmony_ci		map_dirn = DMA_FROM_DEVICE;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn);
53962306a36Sopenharmony_ci	if (dma_mapping_error(gi2c->se.dev->parent, addr)) {
54062306a36Sopenharmony_ci		i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
54162306a36Sopenharmony_ci		return -ENOMEM;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* set the length as message for rx txn */
54562306a36Sopenharmony_ci	peripheral->rx_len = msg->len;
54662306a36Sopenharmony_ci	peripheral->op = op;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = dmaengine_slave_config(dma_chan, config);
54962306a36Sopenharmony_ci	if (ret) {
55062306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "dma config error: %d for op:%d\n", ret, op);
55162306a36Sopenharmony_ci		goto err_config;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	peripheral->set_config = 0;
55562306a36Sopenharmony_ci	peripheral->multi_msg = true;
55662306a36Sopenharmony_ci	flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (op == I2C_WRITE)
55962306a36Sopenharmony_ci		dma_dirn = DMA_MEM_TO_DEV;
56062306a36Sopenharmony_ci	else
56162306a36Sopenharmony_ci		dma_dirn = DMA_DEV_TO_MEM;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags);
56462306a36Sopenharmony_ci	if (!desc) {
56562306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "prep_slave_sg failed\n");
56662306a36Sopenharmony_ci		ret = -EIO;
56762306a36Sopenharmony_ci		goto err_config;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	desc->callback_result = i2c_gpi_cb_result;
57162306a36Sopenharmony_ci	desc->callback_param = gi2c;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	dmaengine_submit(desc);
57462306a36Sopenharmony_ci	*buf = dma_buf;
57562306a36Sopenharmony_ci	*dma_addr_p = addr;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cierr_config:
58062306a36Sopenharmony_ci	dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn);
58162306a36Sopenharmony_ci	i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
58262306a36Sopenharmony_ci	return ret;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], int num)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	struct dma_slave_config config = {};
58862306a36Sopenharmony_ci	struct gpi_i2c_config peripheral = {};
58962306a36Sopenharmony_ci	int i, ret = 0, timeout;
59062306a36Sopenharmony_ci	dma_addr_t tx_addr, rx_addr;
59162306a36Sopenharmony_ci	void *tx_buf = NULL, *rx_buf = NULL;
59262306a36Sopenharmony_ci	const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	config.peripheral_config = &peripheral;
59562306a36Sopenharmony_ci	config.peripheral_size = sizeof(peripheral);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	peripheral.pack_enable = I2C_PACK_TX | I2C_PACK_RX;
59862306a36Sopenharmony_ci	peripheral.cycle_count = itr->t_cycle_cnt;
59962306a36Sopenharmony_ci	peripheral.high_count = itr->t_high_cnt;
60062306a36Sopenharmony_ci	peripheral.low_count = itr->t_low_cnt;
60162306a36Sopenharmony_ci	peripheral.clk_div = itr->clk_div;
60262306a36Sopenharmony_ci	peripheral.set_config = 1;
60362306a36Sopenharmony_ci	peripheral.multi_msg = false;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
60662306a36Sopenharmony_ci		gi2c->cur = &msgs[i];
60762306a36Sopenharmony_ci		gi2c->err = 0;
60862306a36Sopenharmony_ci		dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		peripheral.stretch = 0;
61162306a36Sopenharmony_ci		if (i < num - 1)
61262306a36Sopenharmony_ci			peripheral.stretch = 1;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		peripheral.addr = msgs[i].addr;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
61762306a36Sopenharmony_ci				    &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
61862306a36Sopenharmony_ci		if (ret)
61962306a36Sopenharmony_ci			goto err;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		if (msgs[i].flags & I2C_M_RD) {
62262306a36Sopenharmony_ci			ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
62362306a36Sopenharmony_ci					    &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c);
62462306a36Sopenharmony_ci			if (ret)
62562306a36Sopenharmony_ci				goto err;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci			dma_async_issue_pending(gi2c->rx_c);
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		dma_async_issue_pending(gi2c->tx_c);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
63362306a36Sopenharmony_ci		if (!timeout) {
63462306a36Sopenharmony_ci			dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n",
63562306a36Sopenharmony_ci				gi2c->cur->flags, gi2c->cur->addr);
63662306a36Sopenharmony_ci			gi2c->err = -ETIMEDOUT;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		if (gi2c->err) {
64062306a36Sopenharmony_ci			ret = gi2c->err;
64162306a36Sopenharmony_ci			goto err;
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci		geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return num;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cierr:
65062306a36Sopenharmony_ci	dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret);
65162306a36Sopenharmony_ci	dmaengine_terminate_sync(gi2c->rx_c);
65262306a36Sopenharmony_ci	dmaengine_terminate_sync(gi2c->tx_c);
65362306a36Sopenharmony_ci	geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
65462306a36Sopenharmony_ci	return ret;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
65862306a36Sopenharmony_ci			      struct i2c_msg msgs[], int num)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	int i, ret = 0;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
66362306a36Sopenharmony_ci		u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		gi2c->cur = &msgs[i];
66862306a36Sopenharmony_ci		if (msgs[i].flags & I2C_M_RD)
66962306a36Sopenharmony_ci			ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
67062306a36Sopenharmony_ci		else
67162306a36Sopenharmony_ci			ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		if (ret)
67462306a36Sopenharmony_ci			return ret;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return num;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int geni_i2c_xfer(struct i2c_adapter *adap,
68162306a36Sopenharmony_ci			 struct i2c_msg msgs[],
68262306a36Sopenharmony_ci			 int num)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
68562306a36Sopenharmony_ci	int ret;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	gi2c->err = 0;
68862306a36Sopenharmony_ci	reinit_completion(&gi2c->done);
68962306a36Sopenharmony_ci	ret = pm_runtime_get_sync(gi2c->se.dev);
69062306a36Sopenharmony_ci	if (ret < 0) {
69162306a36Sopenharmony_ci		dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
69262306a36Sopenharmony_ci		pm_runtime_put_noidle(gi2c->se.dev);
69362306a36Sopenharmony_ci		/* Set device in suspended since resume failed */
69462306a36Sopenharmony_ci		pm_runtime_set_suspended(gi2c->se.dev);
69562306a36Sopenharmony_ci		return ret;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	qcom_geni_i2c_conf(gi2c);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (gi2c->gpi_mode)
70162306a36Sopenharmony_ci		ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
70262306a36Sopenharmony_ci	else
70362306a36Sopenharmony_ci		ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	pm_runtime_mark_last_busy(gi2c->se.dev);
70662306a36Sopenharmony_ci	pm_runtime_put_autosuspend(gi2c->se.dev);
70762306a36Sopenharmony_ci	gi2c->cur = NULL;
70862306a36Sopenharmony_ci	gi2c->err = 0;
70962306a36Sopenharmony_ci	return ret;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic u32 geni_i2c_func(struct i2c_adapter *adap)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic const struct i2c_algorithm geni_i2c_algo = {
71862306a36Sopenharmony_ci	.master_xfer	= geni_i2c_xfer,
71962306a36Sopenharmony_ci	.functionality	= geni_i2c_func,
72062306a36Sopenharmony_ci};
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci#ifdef CONFIG_ACPI
72362306a36Sopenharmony_cistatic const struct acpi_device_id geni_i2c_acpi_match[] = {
72462306a36Sopenharmony_ci	{ "QCOM0220"},
72562306a36Sopenharmony_ci	{ },
72662306a36Sopenharmony_ci};
72762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
72862306a36Sopenharmony_ci#endif
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic void release_gpi_dma(struct geni_i2c_dev *gi2c)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	if (gi2c->rx_c)
73362306a36Sopenharmony_ci		dma_release_channel(gi2c->rx_c);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	if (gi2c->tx_c)
73662306a36Sopenharmony_ci		dma_release_channel(gi2c->tx_c);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int setup_gpi_dma(struct geni_i2c_dev *gi2c)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	int ret;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	geni_se_select_mode(&gi2c->se, GENI_GPI_DMA);
74462306a36Sopenharmony_ci	gi2c->tx_c = dma_request_chan(gi2c->se.dev, "tx");
74562306a36Sopenharmony_ci	if (IS_ERR(gi2c->tx_c)) {
74662306a36Sopenharmony_ci		ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->tx_c),
74762306a36Sopenharmony_ci				    "Failed to get tx DMA ch\n");
74862306a36Sopenharmony_ci		goto err_tx;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	gi2c->rx_c = dma_request_chan(gi2c->se.dev, "rx");
75262306a36Sopenharmony_ci	if (IS_ERR(gi2c->rx_c)) {
75362306a36Sopenharmony_ci		ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->rx_c),
75462306a36Sopenharmony_ci				    "Failed to get rx DMA ch\n");
75562306a36Sopenharmony_ci		goto err_rx;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	dev_dbg(gi2c->se.dev, "Grabbed GPI dma channels\n");
75962306a36Sopenharmony_ci	return 0;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cierr_rx:
76262306a36Sopenharmony_ci	dma_release_channel(gi2c->tx_c);
76362306a36Sopenharmony_cierr_tx:
76462306a36Sopenharmony_ci	return ret;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int geni_i2c_probe(struct platform_device *pdev)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c;
77062306a36Sopenharmony_ci	u32 proto, tx_depth, fifo_disable;
77162306a36Sopenharmony_ci	int ret;
77262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
77362306a36Sopenharmony_ci	const struct geni_i2c_desc *desc = NULL;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL);
77662306a36Sopenharmony_ci	if (!gi2c)
77762306a36Sopenharmony_ci		return -ENOMEM;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	gi2c->se.dev = dev;
78062306a36Sopenharmony_ci	gi2c->se.wrapper = dev_get_drvdata(dev->parent);
78162306a36Sopenharmony_ci	gi2c->se.base = devm_platform_ioremap_resource(pdev, 0);
78262306a36Sopenharmony_ci	if (IS_ERR(gi2c->se.base))
78362306a36Sopenharmony_ci		return PTR_ERR(gi2c->se.base);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	desc = device_get_match_data(&pdev->dev);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (desc && desc->has_core_clk) {
78862306a36Sopenharmony_ci		gi2c->core_clk = devm_clk_get(dev, "core");
78962306a36Sopenharmony_ci		if (IS_ERR(gi2c->core_clk))
79062306a36Sopenharmony_ci			return PTR_ERR(gi2c->core_clk);
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	gi2c->se.clk = devm_clk_get(dev, "se");
79462306a36Sopenharmony_ci	if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev))
79562306a36Sopenharmony_ci		return PTR_ERR(gi2c->se.clk);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	ret = device_property_read_u32(dev, "clock-frequency",
79862306a36Sopenharmony_ci				       &gi2c->clk_freq_out);
79962306a36Sopenharmony_ci	if (ret) {
80062306a36Sopenharmony_ci		dev_info(dev, "Bus frequency not specified, default to 100kHz.\n");
80162306a36Sopenharmony_ci		gi2c->clk_freq_out = KHZ(100);
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (has_acpi_companion(dev))
80562306a36Sopenharmony_ci		ACPI_COMPANION_SET(&gi2c->adap.dev, ACPI_COMPANION(dev));
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	gi2c->irq = platform_get_irq(pdev, 0);
80862306a36Sopenharmony_ci	if (gi2c->irq < 0)
80962306a36Sopenharmony_ci		return gi2c->irq;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	ret = geni_i2c_clk_map_idx(gi2c);
81262306a36Sopenharmony_ci	if (ret) {
81362306a36Sopenharmony_ci		dev_err(dev, "Invalid clk frequency %d Hz: %d\n",
81462306a36Sopenharmony_ci			gi2c->clk_freq_out, ret);
81562306a36Sopenharmony_ci		return ret;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	gi2c->adap.algo = &geni_i2c_algo;
81962306a36Sopenharmony_ci	init_completion(&gi2c->done);
82062306a36Sopenharmony_ci	spin_lock_init(&gi2c->lock);
82162306a36Sopenharmony_ci	platform_set_drvdata(pdev, gi2c);
82262306a36Sopenharmony_ci	ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
82362306a36Sopenharmony_ci			       dev_name(dev), gi2c);
82462306a36Sopenharmony_ci	if (ret) {
82562306a36Sopenharmony_ci		dev_err(dev, "Request_irq failed:%d: err:%d\n",
82662306a36Sopenharmony_ci			gi2c->irq, ret);
82762306a36Sopenharmony_ci		return ret;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci	/* Disable the interrupt so that the system can enter low-power mode */
83062306a36Sopenharmony_ci	disable_irq(gi2c->irq);
83162306a36Sopenharmony_ci	i2c_set_adapdata(&gi2c->adap, gi2c);
83262306a36Sopenharmony_ci	gi2c->adap.dev.parent = dev;
83362306a36Sopenharmony_ci	gi2c->adap.dev.of_node = dev->of_node;
83462306a36Sopenharmony_ci	strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory");
83762306a36Sopenharmony_ci	if (ret)
83862306a36Sopenharmony_ci		return ret;
83962306a36Sopenharmony_ci	/*
84062306a36Sopenharmony_ci	 * Set the bus quota for core and cpu to a reasonable value for
84162306a36Sopenharmony_ci	 * register access.
84262306a36Sopenharmony_ci	 * Set quota for DDR based on bus speed.
84362306a36Sopenharmony_ci	 */
84462306a36Sopenharmony_ci	gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
84562306a36Sopenharmony_ci	gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
84662306a36Sopenharmony_ci	if (!desc || desc->icc_ddr)
84762306a36Sopenharmony_ci		gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	ret = geni_icc_set_bw(&gi2c->se);
85062306a36Sopenharmony_ci	if (ret)
85162306a36Sopenharmony_ci		return ret;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ret = clk_prepare_enable(gi2c->core_clk);
85462306a36Sopenharmony_ci	if (ret)
85562306a36Sopenharmony_ci		return ret;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	ret = geni_se_resources_on(&gi2c->se);
85862306a36Sopenharmony_ci	if (ret) {
85962306a36Sopenharmony_ci		dev_err(dev, "Error turning on resources %d\n", ret);
86062306a36Sopenharmony_ci		clk_disable_unprepare(gi2c->core_clk);
86162306a36Sopenharmony_ci		return ret;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci	proto = geni_se_read_proto(&gi2c->se);
86462306a36Sopenharmony_ci	if (proto != GENI_SE_I2C) {
86562306a36Sopenharmony_ci		dev_err(dev, "Invalid proto %d\n", proto);
86662306a36Sopenharmony_ci		geni_se_resources_off(&gi2c->se);
86762306a36Sopenharmony_ci		clk_disable_unprepare(gi2c->core_clk);
86862306a36Sopenharmony_ci		return -ENXIO;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (desc && desc->no_dma_support)
87262306a36Sopenharmony_ci		fifo_disable = false;
87362306a36Sopenharmony_ci	else
87462306a36Sopenharmony_ci		fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (fifo_disable) {
87762306a36Sopenharmony_ci		/* FIFO is disabled, so we can only use GPI DMA */
87862306a36Sopenharmony_ci		gi2c->gpi_mode = true;
87962306a36Sopenharmony_ci		ret = setup_gpi_dma(gi2c);
88062306a36Sopenharmony_ci		if (ret) {
88162306a36Sopenharmony_ci			geni_se_resources_off(&gi2c->se);
88262306a36Sopenharmony_ci			clk_disable_unprepare(gi2c->core_clk);
88362306a36Sopenharmony_ci			return dev_err_probe(dev, ret, "Failed to setup GPI DMA mode\n");
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		dev_dbg(dev, "Using GPI DMA mode for I2C\n");
88762306a36Sopenharmony_ci	} else {
88862306a36Sopenharmony_ci		gi2c->gpi_mode = false;
88962306a36Sopenharmony_ci		tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		/* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
89262306a36Sopenharmony_ci		if (!tx_depth && desc)
89362306a36Sopenharmony_ci			tx_depth = desc->tx_fifo_depth;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		if (!tx_depth) {
89662306a36Sopenharmony_ci			dev_err(dev, "Invalid TX FIFO depth\n");
89762306a36Sopenharmony_ci			geni_se_resources_off(&gi2c->se);
89862306a36Sopenharmony_ci			clk_disable_unprepare(gi2c->core_clk);
89962306a36Sopenharmony_ci			return -EINVAL;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		gi2c->tx_wm = tx_depth - 1;
90362306a36Sopenharmony_ci		geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
90462306a36Sopenharmony_ci		geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
90562306a36Sopenharmony_ci				       PACKING_BYTES_PW, true, true, true);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	clk_disable_unprepare(gi2c->core_clk);
91162306a36Sopenharmony_ci	ret = geni_se_resources_off(&gi2c->se);
91262306a36Sopenharmony_ci	if (ret) {
91362306a36Sopenharmony_ci		dev_err(dev, "Error turning off resources %d\n", ret);
91462306a36Sopenharmony_ci		goto err_dma;
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ret = geni_icc_disable(&gi2c->se);
91862306a36Sopenharmony_ci	if (ret)
91962306a36Sopenharmony_ci		goto err_dma;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	gi2c->suspended = 1;
92262306a36Sopenharmony_ci	pm_runtime_set_suspended(gi2c->se.dev);
92362306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
92462306a36Sopenharmony_ci	pm_runtime_use_autosuspend(gi2c->se.dev);
92562306a36Sopenharmony_ci	pm_runtime_enable(gi2c->se.dev);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	ret = i2c_add_adapter(&gi2c->adap);
92862306a36Sopenharmony_ci	if (ret) {
92962306a36Sopenharmony_ci		dev_err(dev, "Error adding i2c adapter %d\n", ret);
93062306a36Sopenharmony_ci		pm_runtime_disable(gi2c->se.dev);
93162306a36Sopenharmony_ci		goto err_dma;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	dev_dbg(dev, "Geni-I2C adaptor successfully added\n");
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	return 0;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cierr_dma:
93962306a36Sopenharmony_ci	release_gpi_dma(gi2c);
94062306a36Sopenharmony_ci	return ret;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic void geni_i2c_remove(struct platform_device *pdev)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	i2c_del_adapter(&gi2c->adap);
94862306a36Sopenharmony_ci	release_gpi_dma(gi2c);
94962306a36Sopenharmony_ci	pm_runtime_disable(gi2c->se.dev);
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic void geni_i2c_shutdown(struct platform_device *pdev)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/* Make client i2c transfers start failing */
95762306a36Sopenharmony_ci	i2c_mark_adapter_suspended(&gi2c->adap);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	int ret;
96362306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	disable_irq(gi2c->irq);
96662306a36Sopenharmony_ci	ret = geni_se_resources_off(&gi2c->se);
96762306a36Sopenharmony_ci	if (ret) {
96862306a36Sopenharmony_ci		enable_irq(gi2c->irq);
96962306a36Sopenharmony_ci		return ret;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	} else {
97262306a36Sopenharmony_ci		gi2c->suspended = 1;
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	clk_disable_unprepare(gi2c->core_clk);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return geni_icc_disable(&gi2c->se);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	int ret;
98362306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	ret = geni_icc_enable(&gi2c->se);
98662306a36Sopenharmony_ci	if (ret)
98762306a36Sopenharmony_ci		return ret;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	ret = clk_prepare_enable(gi2c->core_clk);
99062306a36Sopenharmony_ci	if (ret)
99162306a36Sopenharmony_ci		return ret;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	ret = geni_se_resources_on(&gi2c->se);
99462306a36Sopenharmony_ci	if (ret)
99562306a36Sopenharmony_ci		return ret;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	enable_irq(gi2c->irq);
99862306a36Sopenharmony_ci	gi2c->suspended = 0;
99962306a36Sopenharmony_ci	return 0;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	i2c_mark_adapter_suspended(&gi2c->adap);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!gi2c->suspended) {
100962306a36Sopenharmony_ci		geni_i2c_runtime_suspend(dev);
101062306a36Sopenharmony_ci		pm_runtime_disable(dev);
101162306a36Sopenharmony_ci		pm_runtime_set_suspended(dev);
101262306a36Sopenharmony_ci		pm_runtime_enable(dev);
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci	return 0;
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int __maybe_unused geni_i2c_resume_noirq(struct device *dev)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	i2c_mark_adapter_resumed(&gi2c->adap);
102262306a36Sopenharmony_ci	return 0;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic const struct dev_pm_ops geni_i2c_pm_ops = {
102662306a36Sopenharmony_ci	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, geni_i2c_resume_noirq)
102762306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume,
102862306a36Sopenharmony_ci									NULL)
102962306a36Sopenharmony_ci};
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic const struct geni_i2c_desc i2c_master_hub = {
103262306a36Sopenharmony_ci	.has_core_clk = true,
103362306a36Sopenharmony_ci	.icc_ddr = NULL,
103462306a36Sopenharmony_ci	.no_dma_support = true,
103562306a36Sopenharmony_ci	.tx_fifo_depth = 16,
103662306a36Sopenharmony_ci};
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic const struct of_device_id geni_i2c_dt_match[] = {
103962306a36Sopenharmony_ci	{ .compatible = "qcom,geni-i2c" },
104062306a36Sopenharmony_ci	{ .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub },
104162306a36Sopenharmony_ci	{}
104262306a36Sopenharmony_ci};
104362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic struct platform_driver geni_i2c_driver = {
104662306a36Sopenharmony_ci	.probe  = geni_i2c_probe,
104762306a36Sopenharmony_ci	.remove_new = geni_i2c_remove,
104862306a36Sopenharmony_ci	.shutdown = geni_i2c_shutdown,
104962306a36Sopenharmony_ci	.driver = {
105062306a36Sopenharmony_ci		.name = "geni_i2c",
105162306a36Sopenharmony_ci		.pm = &geni_i2c_pm_ops,
105262306a36Sopenharmony_ci		.of_match_table = geni_i2c_dt_match,
105362306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(geni_i2c_acpi_match),
105462306a36Sopenharmony_ci	},
105562306a36Sopenharmony_ci};
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cimodule_platform_driver(geni_i2c_driver);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores");
106062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1061