162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * I2C bus driver for the Cadence I2C controller.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 - 2014 Xilinx, Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1962306a36Sopenharmony_ci#include <linux/reset.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Register offsets for the I2C device. */
2262306a36Sopenharmony_ci#define CDNS_I2C_CR_OFFSET		0x00 /* Control Register, RW */
2362306a36Sopenharmony_ci#define CDNS_I2C_SR_OFFSET		0x04 /* Status Register, RO */
2462306a36Sopenharmony_ci#define CDNS_I2C_ADDR_OFFSET		0x08 /* I2C Address Register, RW */
2562306a36Sopenharmony_ci#define CDNS_I2C_DATA_OFFSET		0x0C /* I2C Data Register, RW */
2662306a36Sopenharmony_ci#define CDNS_I2C_ISR_OFFSET		0x10 /* IRQ Status Register, RW */
2762306a36Sopenharmony_ci#define CDNS_I2C_XFER_SIZE_OFFSET	0x14 /* Transfer Size Register, RW */
2862306a36Sopenharmony_ci#define CDNS_I2C_TIME_OUT_OFFSET	0x1C /* Time Out Register, RW */
2962306a36Sopenharmony_ci#define CDNS_I2C_IMR_OFFSET		0x20 /* IRQ Mask Register, RO */
3062306a36Sopenharmony_ci#define CDNS_I2C_IER_OFFSET		0x24 /* IRQ Enable Register, WO */
3162306a36Sopenharmony_ci#define CDNS_I2C_IDR_OFFSET		0x28 /* IRQ Disable Register, WO */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Control Register Bit mask definitions */
3462306a36Sopenharmony_ci#define CDNS_I2C_CR_HOLD		BIT(4) /* Hold Bus bit */
3562306a36Sopenharmony_ci#define CDNS_I2C_CR_ACK_EN		BIT(3)
3662306a36Sopenharmony_ci#define CDNS_I2C_CR_NEA			BIT(2)
3762306a36Sopenharmony_ci#define CDNS_I2C_CR_MS			BIT(1)
3862306a36Sopenharmony_ci/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
3962306a36Sopenharmony_ci#define CDNS_I2C_CR_RW			BIT(0)
4062306a36Sopenharmony_ci/* 1 = Auto init FIFO to zeroes */
4162306a36Sopenharmony_ci#define CDNS_I2C_CR_CLR_FIFO		BIT(6)
4262306a36Sopenharmony_ci#define CDNS_I2C_CR_DIVA_SHIFT		14
4362306a36Sopenharmony_ci#define CDNS_I2C_CR_DIVA_MASK		(3 << CDNS_I2C_CR_DIVA_SHIFT)
4462306a36Sopenharmony_ci#define CDNS_I2C_CR_DIVB_SHIFT		8
4562306a36Sopenharmony_ci#define CDNS_I2C_CR_DIVB_MASK		(0x3f << CDNS_I2C_CR_DIVB_SHIFT)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define CDNS_I2C_CR_MASTER_EN_MASK	(CDNS_I2C_CR_NEA | \
4862306a36Sopenharmony_ci					 CDNS_I2C_CR_ACK_EN | \
4962306a36Sopenharmony_ci					 CDNS_I2C_CR_MS)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define CDNS_I2C_CR_SLAVE_EN_MASK	~CDNS_I2C_CR_MASTER_EN_MASK
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Status Register Bit mask definitions */
5462306a36Sopenharmony_ci#define CDNS_I2C_SR_BA		BIT(8)
5562306a36Sopenharmony_ci#define CDNS_I2C_SR_TXDV	BIT(6)
5662306a36Sopenharmony_ci#define CDNS_I2C_SR_RXDV	BIT(5)
5762306a36Sopenharmony_ci#define CDNS_I2C_SR_RXRW	BIT(3)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * I2C Address Register Bit mask definitions
6162306a36Sopenharmony_ci * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
6262306a36Sopenharmony_ci * bits. A write access to this register always initiates a transfer if the I2C
6362306a36Sopenharmony_ci * is in master mode.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci#define CDNS_I2C_ADDR_MASK	0x000003FF /* I2C Address Mask */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * I2C Interrupt Registers Bit mask definitions
6962306a36Sopenharmony_ci * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
7062306a36Sopenharmony_ci * bit definitions.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_ci#define CDNS_I2C_IXR_ARB_LOST		BIT(9)
7362306a36Sopenharmony_ci#define CDNS_I2C_IXR_RX_UNF		BIT(7)
7462306a36Sopenharmony_ci#define CDNS_I2C_IXR_TX_OVF		BIT(6)
7562306a36Sopenharmony_ci#define CDNS_I2C_IXR_RX_OVF		BIT(5)
7662306a36Sopenharmony_ci#define CDNS_I2C_IXR_SLV_RDY		BIT(4)
7762306a36Sopenharmony_ci#define CDNS_I2C_IXR_TO			BIT(3)
7862306a36Sopenharmony_ci#define CDNS_I2C_IXR_NACK		BIT(2)
7962306a36Sopenharmony_ci#define CDNS_I2C_IXR_DATA		BIT(1)
8062306a36Sopenharmony_ci#define CDNS_I2C_IXR_COMP		BIT(0)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define CDNS_I2C_IXR_ALL_INTR_MASK	(CDNS_I2C_IXR_ARB_LOST | \
8362306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_UNF | \
8462306a36Sopenharmony_ci					 CDNS_I2C_IXR_TX_OVF | \
8562306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_OVF | \
8662306a36Sopenharmony_ci					 CDNS_I2C_IXR_SLV_RDY | \
8762306a36Sopenharmony_ci					 CDNS_I2C_IXR_TO | \
8862306a36Sopenharmony_ci					 CDNS_I2C_IXR_NACK | \
8962306a36Sopenharmony_ci					 CDNS_I2C_IXR_DATA | \
9062306a36Sopenharmony_ci					 CDNS_I2C_IXR_COMP)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define CDNS_I2C_IXR_ERR_INTR_MASK	(CDNS_I2C_IXR_ARB_LOST | \
9362306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_UNF | \
9462306a36Sopenharmony_ci					 CDNS_I2C_IXR_TX_OVF | \
9562306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_OVF | \
9662306a36Sopenharmony_ci					 CDNS_I2C_IXR_NACK)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define CDNS_I2C_ENABLED_INTR_MASK	(CDNS_I2C_IXR_ARB_LOST | \
9962306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_UNF | \
10062306a36Sopenharmony_ci					 CDNS_I2C_IXR_TX_OVF | \
10162306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_OVF | \
10262306a36Sopenharmony_ci					 CDNS_I2C_IXR_NACK | \
10362306a36Sopenharmony_ci					 CDNS_I2C_IXR_DATA | \
10462306a36Sopenharmony_ci					 CDNS_I2C_IXR_COMP)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define CDNS_I2C_IXR_SLAVE_INTR_MASK	(CDNS_I2C_IXR_RX_UNF | \
10762306a36Sopenharmony_ci					 CDNS_I2C_IXR_TX_OVF | \
10862306a36Sopenharmony_ci					 CDNS_I2C_IXR_RX_OVF | \
10962306a36Sopenharmony_ci					 CDNS_I2C_IXR_TO | \
11062306a36Sopenharmony_ci					 CDNS_I2C_IXR_NACK | \
11162306a36Sopenharmony_ci					 CDNS_I2C_IXR_DATA | \
11262306a36Sopenharmony_ci					 CDNS_I2C_IXR_COMP)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define CDNS_I2C_TIMEOUT		msecs_to_jiffies(1000)
11562306a36Sopenharmony_ci/* timeout for pm runtime autosuspend */
11662306a36Sopenharmony_ci#define CNDS_I2C_PM_TIMEOUT		1000	/* ms */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define CDNS_I2C_FIFO_DEPTH_DEFAULT	16
11962306a36Sopenharmony_ci#define CDNS_I2C_MAX_TRANSFER_SIZE	255
12062306a36Sopenharmony_ci/* Transfer size in multiples of data interrupt depth */
12162306a36Sopenharmony_ci#define CDNS_I2C_TRANSFER_SIZE(max)	((max) - 3)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define DRIVER_NAME		"cdns-i2c"
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define CDNS_I2C_DIVA_MAX	4
12662306a36Sopenharmony_ci#define CDNS_I2C_DIVB_MAX	64
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define CDNS_I2C_TIMEOUT_MAX	0xFF
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define CDNS_I2C_BROKEN_HOLD_BIT	BIT(0)
13162306a36Sopenharmony_ci#define CDNS_I2C_POLL_US	100000
13262306a36Sopenharmony_ci#define CDNS_I2C_TIMEOUT_US	500000
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define cdns_i2c_readreg(offset)       readl_relaxed(id->membase + offset)
13562306a36Sopenharmony_ci#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
13862306a36Sopenharmony_ci/**
13962306a36Sopenharmony_ci * enum cdns_i2c_mode - I2C Controller current operating mode
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * @CDNS_I2C_MODE_SLAVE:       I2C controller operating in slave mode
14262306a36Sopenharmony_ci * @CDNS_I2C_MODE_MASTER:      I2C Controller operating in master mode
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cienum cdns_i2c_mode {
14562306a36Sopenharmony_ci	CDNS_I2C_MODE_SLAVE,
14662306a36Sopenharmony_ci	CDNS_I2C_MODE_MASTER,
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/**
15062306a36Sopenharmony_ci * enum cdns_i2c_slave_state - Slave state when I2C is operating in slave mode
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle
15362306a36Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master
15462306a36Sopenharmony_ci * @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cienum cdns_i2c_slave_state {
15762306a36Sopenharmony_ci	CDNS_I2C_SLAVE_STATE_IDLE,
15862306a36Sopenharmony_ci	CDNS_I2C_SLAVE_STATE_SEND,
15962306a36Sopenharmony_ci	CDNS_I2C_SLAVE_STATE_RECV,
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci#endif
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * struct cdns_i2c - I2C device private data structure
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * @dev:		Pointer to device structure
16762306a36Sopenharmony_ci * @membase:		Base address of the I2C device
16862306a36Sopenharmony_ci * @adap:		I2C adapter instance
16962306a36Sopenharmony_ci * @p_msg:		Message pointer
17062306a36Sopenharmony_ci * @err_status:		Error status in Interrupt Status Register
17162306a36Sopenharmony_ci * @xfer_done:		Transfer complete status
17262306a36Sopenharmony_ci * @p_send_buf:		Pointer to transmit buffer
17362306a36Sopenharmony_ci * @p_recv_buf:		Pointer to receive buffer
17462306a36Sopenharmony_ci * @send_count:		Number of bytes still expected to send
17562306a36Sopenharmony_ci * @recv_count:		Number of bytes still expected to receive
17662306a36Sopenharmony_ci * @curr_recv_count:	Number of bytes to be received in current transfer
17762306a36Sopenharmony_ci * @input_clk:		Input clock to I2C controller
17862306a36Sopenharmony_ci * @i2c_clk:		Maximum I2C clock speed
17962306a36Sopenharmony_ci * @bus_hold_flag:	Flag used in repeated start for clearing HOLD bit
18062306a36Sopenharmony_ci * @clk:		Pointer to struct clk
18162306a36Sopenharmony_ci * @clk_rate_change_nb:	Notifier block for clock rate changes
18262306a36Sopenharmony_ci * @reset:		Reset control for the device
18362306a36Sopenharmony_ci * @quirks:		flag for broken hold bit usage in r1p10
18462306a36Sopenharmony_ci * @ctrl_reg:		Cached value of the control register.
18562306a36Sopenharmony_ci * @rinfo:		I2C GPIO recovery information
18662306a36Sopenharmony_ci * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
18762306a36Sopenharmony_ci * @slave:		Registered slave instance.
18862306a36Sopenharmony_ci * @dev_mode:		I2C operating role(master/slave).
18962306a36Sopenharmony_ci * @slave_state:	I2C Slave state(idle/read/write).
19062306a36Sopenharmony_ci * @fifo_depth:		The depth of the transfer FIFO
19162306a36Sopenharmony_ci * @transfer_size:	The maximum number of bytes in one transfer
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_cistruct cdns_i2c {
19462306a36Sopenharmony_ci	struct device		*dev;
19562306a36Sopenharmony_ci	void __iomem *membase;
19662306a36Sopenharmony_ci	struct i2c_adapter adap;
19762306a36Sopenharmony_ci	struct i2c_msg *p_msg;
19862306a36Sopenharmony_ci	int err_status;
19962306a36Sopenharmony_ci	struct completion xfer_done;
20062306a36Sopenharmony_ci	unsigned char *p_send_buf;
20162306a36Sopenharmony_ci	unsigned char *p_recv_buf;
20262306a36Sopenharmony_ci	unsigned int send_count;
20362306a36Sopenharmony_ci	unsigned int recv_count;
20462306a36Sopenharmony_ci	unsigned int curr_recv_count;
20562306a36Sopenharmony_ci	unsigned long input_clk;
20662306a36Sopenharmony_ci	unsigned int i2c_clk;
20762306a36Sopenharmony_ci	unsigned int bus_hold_flag;
20862306a36Sopenharmony_ci	struct clk *clk;
20962306a36Sopenharmony_ci	struct notifier_block clk_rate_change_nb;
21062306a36Sopenharmony_ci	struct reset_control *reset;
21162306a36Sopenharmony_ci	u32 quirks;
21262306a36Sopenharmony_ci	u32 ctrl_reg;
21362306a36Sopenharmony_ci	struct i2c_bus_recovery_info rinfo;
21462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
21562306a36Sopenharmony_ci	u16 ctrl_reg_diva_divb;
21662306a36Sopenharmony_ci	struct i2c_client *slave;
21762306a36Sopenharmony_ci	enum cdns_i2c_mode dev_mode;
21862306a36Sopenharmony_ci	enum cdns_i2c_slave_state slave_state;
21962306a36Sopenharmony_ci#endif
22062306a36Sopenharmony_ci	u32 fifo_depth;
22162306a36Sopenharmony_ci	unsigned int transfer_size;
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistruct cdns_platform_data {
22562306a36Sopenharmony_ci	u32 quirks;
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define to_cdns_i2c(_nb)	container_of(_nb, struct cdns_i2c, \
22962306a36Sopenharmony_ci					     clk_rate_change_nb)
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/**
23262306a36Sopenharmony_ci * cdns_i2c_clear_bus_hold - Clear bus hold bit
23362306a36Sopenharmony_ci * @id:	Pointer to driver data struct
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci * Helper to clear the controller's bus hold bit.
23662306a36Sopenharmony_ci */
23762306a36Sopenharmony_cistatic void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
24062306a36Sopenharmony_ci	if (reg & CDNS_I2C_CR_HOLD)
24162306a36Sopenharmony_ci		cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return (hold_wrkaround &&
24762306a36Sopenharmony_ci		(id->curr_recv_count == id->fifo_depth + 1));
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
25162306a36Sopenharmony_cistatic void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c *id)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	/* Disable all interrupts */
25462306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* Clear FIFO and transfer size */
25762306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* Update device mode and state */
26062306a36Sopenharmony_ci	id->dev_mode = mode;
26162306a36Sopenharmony_ci	id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	switch (mode) {
26462306a36Sopenharmony_ci	case CDNS_I2C_MODE_MASTER:
26562306a36Sopenharmony_ci		/* Enable i2c master */
26662306a36Sopenharmony_ci		cdns_i2c_writereg(id->ctrl_reg_diva_divb |
26762306a36Sopenharmony_ci				  CDNS_I2C_CR_MASTER_EN_MASK,
26862306a36Sopenharmony_ci				  CDNS_I2C_CR_OFFSET);
26962306a36Sopenharmony_ci		/*
27062306a36Sopenharmony_ci		 * This delay is needed to give the IP some time to switch to
27162306a36Sopenharmony_ci		 * the master mode. With lower values(like 110 us) i2cdetect
27262306a36Sopenharmony_ci		 * will not detect any slave and without this delay, the IP will
27362306a36Sopenharmony_ci		 * trigger a timeout interrupt.
27462306a36Sopenharmony_ci		 */
27562306a36Sopenharmony_ci		usleep_range(115, 125);
27662306a36Sopenharmony_ci		break;
27762306a36Sopenharmony_ci	case CDNS_I2C_MODE_SLAVE:
27862306a36Sopenharmony_ci		/* Enable i2c slave */
27962306a36Sopenharmony_ci		cdns_i2c_writereg(id->ctrl_reg_diva_divb &
28062306a36Sopenharmony_ci				  CDNS_I2C_CR_SLAVE_EN_MASK,
28162306a36Sopenharmony_ci				  CDNS_I2C_CR_OFFSET);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* Setting slave address */
28462306a36Sopenharmony_ci		cdns_i2c_writereg(id->slave->addr & CDNS_I2C_ADDR_MASK,
28562306a36Sopenharmony_ci				  CDNS_I2C_ADDR_OFFSET);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		/* Enable slave send/receive interrupts */
28862306a36Sopenharmony_ci		cdns_i2c_writereg(CDNS_I2C_IXR_SLAVE_INTR_MASK,
28962306a36Sopenharmony_ci				  CDNS_I2C_IER_OFFSET);
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void cdns_i2c_slave_rcv_data(struct cdns_i2c *id)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	u8 bytes;
29762306a36Sopenharmony_ci	unsigned char data;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* Prepare backend for data reception */
30062306a36Sopenharmony_ci	if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
30162306a36Sopenharmony_ci		id->slave_state = CDNS_I2C_SLAVE_STATE_RECV;
30262306a36Sopenharmony_ci		i2c_slave_event(id->slave, I2C_SLAVE_WRITE_REQUESTED, NULL);
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Fetch number of bytes to receive */
30662306a36Sopenharmony_ci	bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Read data and send to backend */
30962306a36Sopenharmony_ci	while (bytes--) {
31062306a36Sopenharmony_ci		data = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
31162306a36Sopenharmony_ci		i2c_slave_event(id->slave, I2C_SLAVE_WRITE_RECEIVED, &data);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic void cdns_i2c_slave_send_data(struct cdns_i2c *id)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	u8 data;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Prepare backend for data transmission */
32062306a36Sopenharmony_ci	if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
32162306a36Sopenharmony_ci		id->slave_state = CDNS_I2C_SLAVE_STATE_SEND;
32262306a36Sopenharmony_ci		i2c_slave_event(id->slave, I2C_SLAVE_READ_REQUESTED, &data);
32362306a36Sopenharmony_ci	} else {
32462306a36Sopenharmony_ci		i2c_slave_event(id->slave, I2C_SLAVE_READ_PROCESSED, &data);
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* Send data over bus */
32862306a36Sopenharmony_ci	cdns_i2c_writereg(data, CDNS_I2C_DATA_OFFSET);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/**
33262306a36Sopenharmony_ci * cdns_i2c_slave_isr - Interrupt handler for the I2C device in slave role
33362306a36Sopenharmony_ci * @ptr:       Pointer to I2C device private data
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * This function handles the data interrupt and transfer complete interrupt of
33662306a36Sopenharmony_ci * the I2C device in slave role.
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * Return: IRQ_HANDLED always
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_cistatic irqreturn_t cdns_i2c_slave_isr(void *ptr)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct cdns_i2c *id = ptr;
34362306a36Sopenharmony_ci	unsigned int isr_status, i2c_status;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Fetch the interrupt status */
34662306a36Sopenharmony_ci	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
34762306a36Sopenharmony_ci	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Ignore masked interrupts */
35062306a36Sopenharmony_ci	isr_status &= ~cdns_i2c_readreg(CDNS_I2C_IMR_OFFSET);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* Fetch transfer mode (send/receive) */
35362306a36Sopenharmony_ci	i2c_status = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Handle data send/receive */
35662306a36Sopenharmony_ci	if (i2c_status & CDNS_I2C_SR_RXRW) {
35762306a36Sopenharmony_ci		/* Send data to master */
35862306a36Sopenharmony_ci		if (isr_status & CDNS_I2C_IXR_DATA)
35962306a36Sopenharmony_ci			cdns_i2c_slave_send_data(id);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		if (isr_status & CDNS_I2C_IXR_COMP) {
36262306a36Sopenharmony_ci			id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
36362306a36Sopenharmony_ci			i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci	} else {
36662306a36Sopenharmony_ci		/* Receive data from master */
36762306a36Sopenharmony_ci		if (isr_status & CDNS_I2C_IXR_DATA)
36862306a36Sopenharmony_ci			cdns_i2c_slave_rcv_data(id);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (isr_status & CDNS_I2C_IXR_COMP) {
37162306a36Sopenharmony_ci			cdns_i2c_slave_rcv_data(id);
37262306a36Sopenharmony_ci			id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
37362306a36Sopenharmony_ci			i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* Master indicated xfer stop or fifo underflow/overflow */
37862306a36Sopenharmony_ci	if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF |
37962306a36Sopenharmony_ci			  CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) {
38062306a36Sopenharmony_ci		id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
38162306a36Sopenharmony_ci		i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
38262306a36Sopenharmony_ci		cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	return IRQ_HANDLED;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci#endif
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/**
39062306a36Sopenharmony_ci * cdns_i2c_master_isr - Interrupt handler for the I2C device in master role
39162306a36Sopenharmony_ci * @ptr:       Pointer to I2C device private data
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * This function handles the data interrupt, transfer complete interrupt and
39462306a36Sopenharmony_ci * the error interrupts of the I2C device in master role.
39562306a36Sopenharmony_ci *
39662306a36Sopenharmony_ci * Return: IRQ_HANDLED always
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic irqreturn_t cdns_i2c_master_isr(void *ptr)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	unsigned int isr_status, avail_bytes;
40162306a36Sopenharmony_ci	unsigned int bytes_to_send;
40262306a36Sopenharmony_ci	bool updatetx;
40362306a36Sopenharmony_ci	struct cdns_i2c *id = ptr;
40462306a36Sopenharmony_ci	/* Signal completion only after everything is updated */
40562306a36Sopenharmony_ci	int done_flag = 0;
40662306a36Sopenharmony_ci	irqreturn_t status = IRQ_NONE;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
40962306a36Sopenharmony_ci	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
41062306a36Sopenharmony_ci	id->err_status = 0;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* Handling nack and arbitration lost interrupt */
41362306a36Sopenharmony_ci	if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
41462306a36Sopenharmony_ci		done_flag = 1;
41562306a36Sopenharmony_ci		status = IRQ_HANDLED;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/*
41962306a36Sopenharmony_ci	 * Check if transfer size register needs to be updated again for a
42062306a36Sopenharmony_ci	 * large data receive operation.
42162306a36Sopenharmony_ci	 */
42262306a36Sopenharmony_ci	updatetx = id->recv_count > id->curr_recv_count;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* When receiving, handle data interrupt and completion interrupt */
42562306a36Sopenharmony_ci	if (id->p_recv_buf &&
42662306a36Sopenharmony_ci	    ((isr_status & CDNS_I2C_IXR_COMP) ||
42762306a36Sopenharmony_ci	     (isr_status & CDNS_I2C_IXR_DATA))) {
42862306a36Sopenharmony_ci		/* Read data if receive data valid is set */
42962306a36Sopenharmony_ci		while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
43062306a36Sopenharmony_ci		       CDNS_I2C_SR_RXDV) {
43162306a36Sopenharmony_ci			if (id->recv_count > 0) {
43262306a36Sopenharmony_ci				*(id->p_recv_buf)++ =
43362306a36Sopenharmony_ci					cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
43462306a36Sopenharmony_ci				id->recv_count--;
43562306a36Sopenharmony_ci				id->curr_recv_count--;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci				/*
43862306a36Sopenharmony_ci				 * Clear hold bit that was set for FIFO control
43962306a36Sopenharmony_ci				 * if RX data left is less than or equal to
44062306a36Sopenharmony_ci				 * FIFO DEPTH unless repeated start is selected
44162306a36Sopenharmony_ci				 */
44262306a36Sopenharmony_ci				if (id->recv_count <= id->fifo_depth &&
44362306a36Sopenharmony_ci				    !id->bus_hold_flag)
44462306a36Sopenharmony_ci					cdns_i2c_clear_bus_hold(id);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			} else {
44762306a36Sopenharmony_ci				dev_err(id->adap.dev.parent,
44862306a36Sopenharmony_ci					"xfer_size reg rollover. xfer aborted!\n");
44962306a36Sopenharmony_ci				id->err_status |= CDNS_I2C_IXR_TO;
45062306a36Sopenharmony_ci				break;
45162306a36Sopenharmony_ci			}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci			if (cdns_is_holdquirk(id, updatetx))
45462306a36Sopenharmony_ci				break;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/*
45862306a36Sopenharmony_ci		 * The controller sends NACK to the slave when transfer size
45962306a36Sopenharmony_ci		 * register reaches zero without considering the HOLD bit.
46062306a36Sopenharmony_ci		 * This workaround is implemented for large data transfers to
46162306a36Sopenharmony_ci		 * maintain transfer size non-zero while performing a large
46262306a36Sopenharmony_ci		 * receive operation.
46362306a36Sopenharmony_ci		 */
46462306a36Sopenharmony_ci		if (cdns_is_holdquirk(id, updatetx)) {
46562306a36Sopenharmony_ci			/* wait while fifo is full */
46662306a36Sopenharmony_ci			while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
46762306a36Sopenharmony_ci			       (id->curr_recv_count - id->fifo_depth))
46862306a36Sopenharmony_ci				;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci			/*
47162306a36Sopenharmony_ci			 * Check number of bytes to be received against maximum
47262306a36Sopenharmony_ci			 * transfer size and update register accordingly.
47362306a36Sopenharmony_ci			 */
47462306a36Sopenharmony_ci			if (((int)(id->recv_count) - id->fifo_depth) >
47562306a36Sopenharmony_ci			    id->transfer_size) {
47662306a36Sopenharmony_ci				cdns_i2c_writereg(id->transfer_size,
47762306a36Sopenharmony_ci						  CDNS_I2C_XFER_SIZE_OFFSET);
47862306a36Sopenharmony_ci				id->curr_recv_count = id->transfer_size +
47962306a36Sopenharmony_ci						      id->fifo_depth;
48062306a36Sopenharmony_ci			} else {
48162306a36Sopenharmony_ci				cdns_i2c_writereg(id->recv_count -
48262306a36Sopenharmony_ci						  id->fifo_depth,
48362306a36Sopenharmony_ci						  CDNS_I2C_XFER_SIZE_OFFSET);
48462306a36Sopenharmony_ci				id->curr_recv_count = id->recv_count;
48562306a36Sopenharmony_ci			}
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		/* Clear hold (if not repeated start) and signal completion */
48962306a36Sopenharmony_ci		if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
49062306a36Sopenharmony_ci			if (!id->bus_hold_flag)
49162306a36Sopenharmony_ci				cdns_i2c_clear_bus_hold(id);
49262306a36Sopenharmony_ci			done_flag = 1;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		status = IRQ_HANDLED;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* When sending, handle transfer complete interrupt */
49962306a36Sopenharmony_ci	if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
50062306a36Sopenharmony_ci		/*
50162306a36Sopenharmony_ci		 * If there is more data to be sent, calculate the
50262306a36Sopenharmony_ci		 * space available in FIFO and fill with that many bytes.
50362306a36Sopenharmony_ci		 */
50462306a36Sopenharmony_ci		if (id->send_count) {
50562306a36Sopenharmony_ci			avail_bytes = id->fifo_depth -
50662306a36Sopenharmony_ci			    cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
50762306a36Sopenharmony_ci			if (id->send_count > avail_bytes)
50862306a36Sopenharmony_ci				bytes_to_send = avail_bytes;
50962306a36Sopenharmony_ci			else
51062306a36Sopenharmony_ci				bytes_to_send = id->send_count;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci			while (bytes_to_send--) {
51362306a36Sopenharmony_ci				cdns_i2c_writereg(
51462306a36Sopenharmony_ci					(*(id->p_send_buf)++),
51562306a36Sopenharmony_ci					 CDNS_I2C_DATA_OFFSET);
51662306a36Sopenharmony_ci				id->send_count--;
51762306a36Sopenharmony_ci			}
51862306a36Sopenharmony_ci		} else {
51962306a36Sopenharmony_ci			/*
52062306a36Sopenharmony_ci			 * Signal the completion of transaction and
52162306a36Sopenharmony_ci			 * clear the hold bus bit if there are no
52262306a36Sopenharmony_ci			 * further messages to be processed.
52362306a36Sopenharmony_ci			 */
52462306a36Sopenharmony_ci			done_flag = 1;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci		if (!id->send_count && !id->bus_hold_flag)
52762306a36Sopenharmony_ci			cdns_i2c_clear_bus_hold(id);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		status = IRQ_HANDLED;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* Update the status for errors */
53362306a36Sopenharmony_ci	id->err_status |= isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
53462306a36Sopenharmony_ci	if (id->err_status)
53562306a36Sopenharmony_ci		status = IRQ_HANDLED;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (done_flag)
53862306a36Sopenharmony_ci		complete(&id->xfer_done);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return status;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci/**
54462306a36Sopenharmony_ci * cdns_i2c_isr - Interrupt handler for the I2C device
54562306a36Sopenharmony_ci * @irq:	irq number for the I2C device
54662306a36Sopenharmony_ci * @ptr:	void pointer to cdns_i2c structure
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * This function passes the control to slave/master based on current role of
54962306a36Sopenharmony_ci * i2c controller.
55062306a36Sopenharmony_ci *
55162306a36Sopenharmony_ci * Return: IRQ_HANDLED always
55262306a36Sopenharmony_ci */
55362306a36Sopenharmony_cistatic irqreturn_t cdns_i2c_isr(int irq, void *ptr)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
55662306a36Sopenharmony_ci	struct cdns_i2c *id = ptr;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (id->dev_mode == CDNS_I2C_MODE_SLAVE)
55962306a36Sopenharmony_ci		return cdns_i2c_slave_isr(ptr);
56062306a36Sopenharmony_ci#endif
56162306a36Sopenharmony_ci	return cdns_i2c_master_isr(ptr);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/**
56562306a36Sopenharmony_ci * cdns_i2c_mrecv - Prepare and start a master receive operation
56662306a36Sopenharmony_ci * @id:		pointer to the i2c device structure
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_cistatic void cdns_i2c_mrecv(struct cdns_i2c *id)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	unsigned int ctrl_reg;
57162306a36Sopenharmony_ci	unsigned int isr_status;
57262306a36Sopenharmony_ci	unsigned long flags;
57362306a36Sopenharmony_ci	bool hold_clear = false;
57462306a36Sopenharmony_ci	bool irq_save = false;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	u32 addr;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	id->p_recv_buf = id->p_msg->buf;
57962306a36Sopenharmony_ci	id->recv_count = id->p_msg->len;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* Put the controller in master receive mode and clear the FIFO */
58262306a36Sopenharmony_ci	ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
58362306a36Sopenharmony_ci	ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/*
58662306a36Sopenharmony_ci	 * Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length
58762306a36Sopenharmony_ci	 * byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if
58862306a36Sopenharmony_ci	 * PEC is enabled, otherwise 1.
58962306a36Sopenharmony_ci	 */
59062306a36Sopenharmony_ci	if (id->p_msg->flags & I2C_M_RECV_LEN)
59162306a36Sopenharmony_ci		id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	id->curr_recv_count = id->recv_count;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/*
59662306a36Sopenharmony_ci	 * Check for the message size against FIFO depth and set the
59762306a36Sopenharmony_ci	 * 'hold bus' bit if it is greater than FIFO depth.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	if (id->recv_count > id->fifo_depth)
60062306a36Sopenharmony_ci		ctrl_reg |= CDNS_I2C_CR_HOLD;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	/* Clear the interrupts in interrupt status register */
60562306a36Sopenharmony_ci	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
60662306a36Sopenharmony_ci	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/*
60962306a36Sopenharmony_ci	 * The no. of bytes to receive is checked against the limit of
61062306a36Sopenharmony_ci	 * max transfer size. Set transfer size register with no of bytes
61162306a36Sopenharmony_ci	 * receive if it is less than transfer size and transfer size if
61262306a36Sopenharmony_ci	 * it is more. Enable the interrupts.
61362306a36Sopenharmony_ci	 */
61462306a36Sopenharmony_ci	if (id->recv_count > id->transfer_size) {
61562306a36Sopenharmony_ci		cdns_i2c_writereg(id->transfer_size,
61662306a36Sopenharmony_ci				  CDNS_I2C_XFER_SIZE_OFFSET);
61762306a36Sopenharmony_ci		id->curr_recv_count = id->transfer_size;
61862306a36Sopenharmony_ci	} else {
61962306a36Sopenharmony_ci		cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Determine hold_clear based on number of bytes to receive and hold flag */
62362306a36Sopenharmony_ci	if (!id->bus_hold_flag && id->recv_count <= id->fifo_depth) {
62462306a36Sopenharmony_ci		if (ctrl_reg & CDNS_I2C_CR_HOLD) {
62562306a36Sopenharmony_ci			hold_clear = true;
62662306a36Sopenharmony_ci			if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
62762306a36Sopenharmony_ci				irq_save = true;
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	addr = id->p_msg->addr;
63262306a36Sopenharmony_ci	addr &= CDNS_I2C_ADDR_MASK;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (hold_clear) {
63562306a36Sopenharmony_ci		ctrl_reg &= ~CDNS_I2C_CR_HOLD;
63662306a36Sopenharmony_ci		/*
63762306a36Sopenharmony_ci		 * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size
63862306a36Sopenharmony_ci		 * register reaches '0'. This is an IP bug which causes transfer size
63962306a36Sopenharmony_ci		 * register overflow to 0xFF. To satisfy this timing requirement,
64062306a36Sopenharmony_ci		 * disable the interrupts on current processor core between register
64162306a36Sopenharmony_ci		 * writes to slave address register and control register.
64262306a36Sopenharmony_ci		 */
64362306a36Sopenharmony_ci		if (irq_save)
64462306a36Sopenharmony_ci			local_irq_save(flags);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
64762306a36Sopenharmony_ci		cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
64862306a36Sopenharmony_ci		/* Read it back to avoid bufferring and make sure write happens */
64962306a36Sopenharmony_ci		cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (irq_save)
65262306a36Sopenharmony_ci			local_irq_restore(flags);
65362306a36Sopenharmony_ci	} else {
65462306a36Sopenharmony_ci		cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/**
66162306a36Sopenharmony_ci * cdns_i2c_msend - Prepare and start a master send operation
66262306a36Sopenharmony_ci * @id:		pointer to the i2c device
66362306a36Sopenharmony_ci */
66462306a36Sopenharmony_cistatic void cdns_i2c_msend(struct cdns_i2c *id)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	unsigned int avail_bytes;
66762306a36Sopenharmony_ci	unsigned int bytes_to_send;
66862306a36Sopenharmony_ci	unsigned int ctrl_reg;
66962306a36Sopenharmony_ci	unsigned int isr_status;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	id->p_recv_buf = NULL;
67262306a36Sopenharmony_ci	id->p_send_buf = id->p_msg->buf;
67362306a36Sopenharmony_ci	id->send_count = id->p_msg->len;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Set the controller in Master transmit mode and clear the FIFO. */
67662306a36Sopenharmony_ci	ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
67762306a36Sopenharmony_ci	ctrl_reg &= ~CDNS_I2C_CR_RW;
67862306a36Sopenharmony_ci	ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/*
68162306a36Sopenharmony_ci	 * Check for the message size against FIFO depth and set the
68262306a36Sopenharmony_ci	 * 'hold bus' bit if it is greater than FIFO depth.
68362306a36Sopenharmony_ci	 */
68462306a36Sopenharmony_ci	if (id->send_count > id->fifo_depth)
68562306a36Sopenharmony_ci		ctrl_reg |= CDNS_I2C_CR_HOLD;
68662306a36Sopenharmony_ci	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/* Clear the interrupts in interrupt status register. */
68962306a36Sopenharmony_ci	isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
69062306a36Sopenharmony_ci	cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/*
69362306a36Sopenharmony_ci	 * Calculate the space available in FIFO. Check the message length
69462306a36Sopenharmony_ci	 * against the space available, and fill the FIFO accordingly.
69562306a36Sopenharmony_ci	 * Enable the interrupts.
69662306a36Sopenharmony_ci	 */
69762306a36Sopenharmony_ci	avail_bytes = id->fifo_depth -
69862306a36Sopenharmony_ci				cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (id->send_count > avail_bytes)
70162306a36Sopenharmony_ci		bytes_to_send = avail_bytes;
70262306a36Sopenharmony_ci	else
70362306a36Sopenharmony_ci		bytes_to_send = id->send_count;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	while (bytes_to_send--) {
70662306a36Sopenharmony_ci		cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
70762306a36Sopenharmony_ci		id->send_count--;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/*
71162306a36Sopenharmony_ci	 * Clear the bus hold flag if there is no more data
71262306a36Sopenharmony_ci	 * and if it is the last message.
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	if (!id->bus_hold_flag && !id->send_count)
71562306a36Sopenharmony_ci		cdns_i2c_clear_bus_hold(id);
71662306a36Sopenharmony_ci	/* Set the slave address in address register - triggers operation. */
71762306a36Sopenharmony_ci	cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
71862306a36Sopenharmony_ci						CDNS_I2C_ADDR_OFFSET);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci/**
72462306a36Sopenharmony_ci * cdns_i2c_master_reset - Reset the interface
72562306a36Sopenharmony_ci * @adap:	pointer to the i2c adapter driver instance
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci * This function cleanup the fifos, clear the hold bit and status
72862306a36Sopenharmony_ci * and disable the interrupts.
72962306a36Sopenharmony_ci */
73062306a36Sopenharmony_cistatic void cdns_i2c_master_reset(struct i2c_adapter *adap)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct cdns_i2c *id = adap->algo_data;
73362306a36Sopenharmony_ci	u32 regval;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Disable the interrupts */
73662306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
73762306a36Sopenharmony_ci	/* Clear the hold bit and fifos */
73862306a36Sopenharmony_ci	regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
73962306a36Sopenharmony_ci	regval &= ~CDNS_I2C_CR_HOLD;
74062306a36Sopenharmony_ci	regval |= CDNS_I2C_CR_CLR_FIFO;
74162306a36Sopenharmony_ci	cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
74262306a36Sopenharmony_ci	/* Update the transfercount register to zero */
74362306a36Sopenharmony_ci	cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
74462306a36Sopenharmony_ci	/* Clear the interrupt status register */
74562306a36Sopenharmony_ci	regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
74662306a36Sopenharmony_ci	cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
74762306a36Sopenharmony_ci	/* Clear the status register */
74862306a36Sopenharmony_ci	regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
74962306a36Sopenharmony_ci	cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
75362306a36Sopenharmony_ci		struct i2c_adapter *adap)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	unsigned long time_left, msg_timeout;
75662306a36Sopenharmony_ci	u32 reg;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	id->p_msg = msg;
75962306a36Sopenharmony_ci	id->err_status = 0;
76062306a36Sopenharmony_ci	reinit_completion(&id->xfer_done);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* Check for the TEN Bit mode on each msg */
76362306a36Sopenharmony_ci	reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
76462306a36Sopenharmony_ci	if (msg->flags & I2C_M_TEN) {
76562306a36Sopenharmony_ci		if (reg & CDNS_I2C_CR_NEA)
76662306a36Sopenharmony_ci			cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
76762306a36Sopenharmony_ci					CDNS_I2C_CR_OFFSET);
76862306a36Sopenharmony_ci	} else {
76962306a36Sopenharmony_ci		if (!(reg & CDNS_I2C_CR_NEA))
77062306a36Sopenharmony_ci			cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
77162306a36Sopenharmony_ci					CDNS_I2C_CR_OFFSET);
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Check for the R/W flag on each msg */
77562306a36Sopenharmony_ci	if (msg->flags & I2C_M_RD)
77662306a36Sopenharmony_ci		cdns_i2c_mrecv(id);
77762306a36Sopenharmony_ci	else
77862306a36Sopenharmony_ci		cdns_i2c_msend(id);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Minimal time to execute this message */
78162306a36Sopenharmony_ci	msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
78262306a36Sopenharmony_ci	/* Plus some wiggle room */
78362306a36Sopenharmony_ci	msg_timeout += msecs_to_jiffies(500);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (msg_timeout < adap->timeout)
78662306a36Sopenharmony_ci		msg_timeout = adap->timeout;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	/* Wait for the signal of completion */
78962306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
79062306a36Sopenharmony_ci	if (time_left == 0) {
79162306a36Sopenharmony_ci		cdns_i2c_master_reset(adap);
79262306a36Sopenharmony_ci		dev_err(id->adap.dev.parent,
79362306a36Sopenharmony_ci				"timeout waiting on completion\n");
79462306a36Sopenharmony_ci		return -ETIMEDOUT;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,
79862306a36Sopenharmony_ci			  CDNS_I2C_IDR_OFFSET);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/* If it is bus arbitration error, try again */
80162306a36Sopenharmony_ci	if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
80262306a36Sopenharmony_ci		return -EAGAIN;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (msg->flags & I2C_M_RECV_LEN)
80562306a36Sopenharmony_ci		msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/**
81162306a36Sopenharmony_ci * cdns_i2c_master_xfer - The main i2c transfer function
81262306a36Sopenharmony_ci * @adap:	pointer to the i2c adapter driver instance
81362306a36Sopenharmony_ci * @msgs:	pointer to the i2c message structure
81462306a36Sopenharmony_ci * @num:	the number of messages to transfer
81562306a36Sopenharmony_ci *
81662306a36Sopenharmony_ci * Initiates the send/recv activity based on the transfer message received.
81762306a36Sopenharmony_ci *
81862306a36Sopenharmony_ci * Return: number of msgs processed on success, negative error otherwise
81962306a36Sopenharmony_ci */
82062306a36Sopenharmony_cistatic int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
82162306a36Sopenharmony_ci				int num)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	int ret, count;
82462306a36Sopenharmony_ci	u32 reg;
82562306a36Sopenharmony_ci	struct cdns_i2c *id = adap->algo_data;
82662306a36Sopenharmony_ci	bool hold_quirk;
82762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
82862306a36Sopenharmony_ci	bool change_role = false;
82962306a36Sopenharmony_ci#endif
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(id->dev);
83262306a36Sopenharmony_ci	if (ret < 0)
83362306a36Sopenharmony_ci		return ret;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
83662306a36Sopenharmony_ci	/* Check i2c operating mode and switch if possible */
83762306a36Sopenharmony_ci	if (id->dev_mode == CDNS_I2C_MODE_SLAVE) {
83862306a36Sopenharmony_ci		if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) {
83962306a36Sopenharmony_ci			ret = -EAGAIN;
84062306a36Sopenharmony_ci			goto out;
84162306a36Sopenharmony_ci		}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		/* Set mode to master */
84462306a36Sopenharmony_ci		cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		/* Mark flag to change role once xfer is completed */
84762306a36Sopenharmony_ci		change_role = true;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci#endif
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* Check if the bus is free */
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
85462306a36Sopenharmony_ci					 reg,
85562306a36Sopenharmony_ci					 !(reg & CDNS_I2C_SR_BA),
85662306a36Sopenharmony_ci					 CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
85762306a36Sopenharmony_ci	if (ret) {
85862306a36Sopenharmony_ci		ret = -EAGAIN;
85962306a36Sopenharmony_ci		if (id->adap.bus_recovery_info)
86062306a36Sopenharmony_ci			i2c_recover_bus(adap);
86162306a36Sopenharmony_ci		goto out;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
86562306a36Sopenharmony_ci	/*
86662306a36Sopenharmony_ci	 * Set the flag to one when multiple messages are to be
86762306a36Sopenharmony_ci	 * processed with a repeated start.
86862306a36Sopenharmony_ci	 */
86962306a36Sopenharmony_ci	if (num > 1) {
87062306a36Sopenharmony_ci		/*
87162306a36Sopenharmony_ci		 * This controller does not give completion interrupt after a
87262306a36Sopenharmony_ci		 * master receive message if HOLD bit is set (repeated start),
87362306a36Sopenharmony_ci		 * resulting in SW timeout. Hence, if a receive message is
87462306a36Sopenharmony_ci		 * followed by any other message, an error is returned
87562306a36Sopenharmony_ci		 * indicating that this sequence is not supported.
87662306a36Sopenharmony_ci		 */
87762306a36Sopenharmony_ci		for (count = 0; (count < num - 1 && hold_quirk); count++) {
87862306a36Sopenharmony_ci			if (msgs[count].flags & I2C_M_RD) {
87962306a36Sopenharmony_ci				dev_warn(adap->dev.parent,
88062306a36Sopenharmony_ci					 "Can't do repeated start after a receive message\n");
88162306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
88262306a36Sopenharmony_ci				goto out;
88362306a36Sopenharmony_ci			}
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci		id->bus_hold_flag = 1;
88662306a36Sopenharmony_ci		reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
88762306a36Sopenharmony_ci		reg |= CDNS_I2C_CR_HOLD;
88862306a36Sopenharmony_ci		cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
88962306a36Sopenharmony_ci	} else {
89062306a36Sopenharmony_ci		id->bus_hold_flag = 0;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* Process the msg one by one */
89462306a36Sopenharmony_ci	for (count = 0; count < num; count++, msgs++) {
89562306a36Sopenharmony_ci		if (count == (num - 1))
89662306a36Sopenharmony_ci			id->bus_hold_flag = 0;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		ret = cdns_i2c_process_msg(id, msgs, adap);
89962306a36Sopenharmony_ci		if (ret)
90062306a36Sopenharmony_ci			goto out;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		/* Report the other error interrupts to application */
90362306a36Sopenharmony_ci		if (id->err_status) {
90462306a36Sopenharmony_ci			cdns_i2c_master_reset(adap);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci			if (id->err_status & CDNS_I2C_IXR_NACK) {
90762306a36Sopenharmony_ci				ret = -ENXIO;
90862306a36Sopenharmony_ci				goto out;
90962306a36Sopenharmony_ci			}
91062306a36Sopenharmony_ci			ret = -EIO;
91162306a36Sopenharmony_ci			goto out;
91262306a36Sopenharmony_ci		}
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	ret = num;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ciout:
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
92062306a36Sopenharmony_ci	/* Switch i2c mode to slave */
92162306a36Sopenharmony_ci	if (change_role)
92262306a36Sopenharmony_ci		cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
92362306a36Sopenharmony_ci#endif
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	pm_runtime_mark_last_busy(id->dev);
92662306a36Sopenharmony_ci	pm_runtime_put_autosuspend(id->dev);
92762306a36Sopenharmony_ci	return ret;
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci/**
93162306a36Sopenharmony_ci * cdns_i2c_func - Returns the supported features of the I2C driver
93262306a36Sopenharmony_ci * @adap:	pointer to the i2c adapter structure
93362306a36Sopenharmony_ci *
93462306a36Sopenharmony_ci * Return: 32 bit value, each bit corresponding to a feature
93562306a36Sopenharmony_ci */
93662306a36Sopenharmony_cistatic u32 cdns_i2c_func(struct i2c_adapter *adap)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
93962306a36Sopenharmony_ci			(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
94062306a36Sopenharmony_ci			I2C_FUNC_SMBUS_BLOCK_DATA;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
94362306a36Sopenharmony_ci	func |= I2C_FUNC_SLAVE;
94462306a36Sopenharmony_ci#endif
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	return func;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
95062306a36Sopenharmony_cistatic int cdns_reg_slave(struct i2c_client *slave)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	int ret;
95362306a36Sopenharmony_ci	struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c,
95462306a36Sopenharmony_ci									adap);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (id->slave)
95762306a36Sopenharmony_ci		return -EBUSY;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	if (slave->flags & I2C_CLIENT_TEN)
96062306a36Sopenharmony_ci		return -EAFNOSUPPORT;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(id->dev);
96362306a36Sopenharmony_ci	if (ret < 0)
96462306a36Sopenharmony_ci		return ret;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* Store slave information */
96762306a36Sopenharmony_ci	id->slave = slave;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* Enable I2C slave */
97062306a36Sopenharmony_ci	cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	return 0;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int cdns_unreg_slave(struct i2c_client *slave)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c,
97862306a36Sopenharmony_ci									adap);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	pm_runtime_put(id->dev);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	/* Remove slave information */
98362306a36Sopenharmony_ci	id->slave = NULL;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Enable I2C master */
98662306a36Sopenharmony_ci	cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return 0;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci#endif
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic const struct i2c_algorithm cdns_i2c_algo = {
99362306a36Sopenharmony_ci	.master_xfer	= cdns_i2c_master_xfer,
99462306a36Sopenharmony_ci	.functionality	= cdns_i2c_func,
99562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
99662306a36Sopenharmony_ci	.reg_slave	= cdns_reg_slave,
99762306a36Sopenharmony_ci	.unreg_slave	= cdns_unreg_slave,
99862306a36Sopenharmony_ci#endif
99962306a36Sopenharmony_ci};
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci/**
100262306a36Sopenharmony_ci * cdns_i2c_calc_divs - Calculate clock dividers
100362306a36Sopenharmony_ci * @f:		I2C clock frequency
100462306a36Sopenharmony_ci * @input_clk:	Input clock frequency
100562306a36Sopenharmony_ci * @a:		First divider (return value)
100662306a36Sopenharmony_ci * @b:		Second divider (return value)
100762306a36Sopenharmony_ci *
100862306a36Sopenharmony_ci * f is used as input and output variable. As input it is used as target I2C
100962306a36Sopenharmony_ci * frequency. On function exit f holds the actually resulting I2C frequency.
101062306a36Sopenharmony_ci *
101162306a36Sopenharmony_ci * Return: 0 on success, negative errno otherwise.
101262306a36Sopenharmony_ci */
101362306a36Sopenharmony_cistatic int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
101462306a36Sopenharmony_ci		unsigned int *a, unsigned int *b)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
101762306a36Sopenharmony_ci	unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
101862306a36Sopenharmony_ci	unsigned int last_error, current_error;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* calculate (divisor_a+1) x (divisor_b+1) */
102162306a36Sopenharmony_ci	temp = input_clk / (22 * fscl);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	/*
102462306a36Sopenharmony_ci	 * If the calculated value is negative or 0, the fscl input is out of
102562306a36Sopenharmony_ci	 * range. Return error.
102662306a36Sopenharmony_ci	 */
102762306a36Sopenharmony_ci	if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
102862306a36Sopenharmony_ci		return -EINVAL;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	last_error = -1;
103162306a36Sopenharmony_ci	for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
103262306a36Sopenharmony_ci		div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci		if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
103562306a36Sopenharmony_ci			continue;
103662306a36Sopenharmony_ci		div_b--;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		if (actual_fscl > fscl)
104162306a36Sopenharmony_ci			continue;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci		current_error = fscl - actual_fscl;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		if (last_error > current_error) {
104662306a36Sopenharmony_ci			calc_div_a = div_a;
104762306a36Sopenharmony_ci			calc_div_b = div_b;
104862306a36Sopenharmony_ci			best_fscl = actual_fscl;
104962306a36Sopenharmony_ci			last_error = current_error;
105062306a36Sopenharmony_ci		}
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	*a = calc_div_a;
105462306a36Sopenharmony_ci	*b = calc_div_b;
105562306a36Sopenharmony_ci	*f = best_fscl;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	return 0;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci/**
106162306a36Sopenharmony_ci * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device
106262306a36Sopenharmony_ci * @clk_in:	I2C clock input frequency in Hz
106362306a36Sopenharmony_ci * @id:		Pointer to the I2C device structure
106462306a36Sopenharmony_ci *
106562306a36Sopenharmony_ci * The device must be idle rather than busy transferring data before setting
106662306a36Sopenharmony_ci * these device options.
106762306a36Sopenharmony_ci * The data rate is set by values in the control register.
106862306a36Sopenharmony_ci * The formula for determining the correct register values is
106962306a36Sopenharmony_ci *	Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
107062306a36Sopenharmony_ci * See the hardware data sheet for a full explanation of setting the serial
107162306a36Sopenharmony_ci * clock rate. The clock can not be faster than the input clock divide by 22.
107262306a36Sopenharmony_ci * The two most common clock rates are 100KHz and 400KHz.
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci * Return: 0 on success, negative error otherwise
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_cistatic int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	unsigned int div_a, div_b;
107962306a36Sopenharmony_ci	unsigned int ctrl_reg;
108062306a36Sopenharmony_ci	int ret = 0;
108162306a36Sopenharmony_ci	unsigned long fscl = id->i2c_clk;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
108462306a36Sopenharmony_ci	if (ret)
108562306a36Sopenharmony_ci		return ret;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	ctrl_reg = id->ctrl_reg;
108862306a36Sopenharmony_ci	ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
108962306a36Sopenharmony_ci	ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
109062306a36Sopenharmony_ci			(div_b << CDNS_I2C_CR_DIVB_SHIFT));
109162306a36Sopenharmony_ci	id->ctrl_reg = ctrl_reg;
109262306a36Sopenharmony_ci	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
109362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
109462306a36Sopenharmony_ci	id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
109562306a36Sopenharmony_ci				 CDNS_I2C_CR_DIVB_MASK);
109662306a36Sopenharmony_ci#endif
109762306a36Sopenharmony_ci	return 0;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci/**
110162306a36Sopenharmony_ci * cdns_i2c_clk_notifier_cb - Clock rate change callback
110262306a36Sopenharmony_ci * @nb:		Pointer to notifier block
110362306a36Sopenharmony_ci * @event:	Notification reason
110462306a36Sopenharmony_ci * @data:	Pointer to notification data object
110562306a36Sopenharmony_ci *
110662306a36Sopenharmony_ci * This function is called when the cdns_i2c input clock frequency changes.
110762306a36Sopenharmony_ci * The callback checks whether a valid bus frequency can be generated after the
110862306a36Sopenharmony_ci * change. If so, the change is acknowledged, otherwise the change is aborted.
110962306a36Sopenharmony_ci * New dividers are written to the HW in the pre- or post change notification
111062306a36Sopenharmony_ci * depending on the scaling direction.
111162306a36Sopenharmony_ci *
111262306a36Sopenharmony_ci * Return:	NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
111362306a36Sopenharmony_ci *		to acknowledge the change, NOTIFY_DONE if the notification is
111462306a36Sopenharmony_ci *		considered irrelevant.
111562306a36Sopenharmony_ci */
111662306a36Sopenharmony_cistatic int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
111762306a36Sopenharmony_ci		event, void *data)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	struct clk_notifier_data *ndata = data;
112062306a36Sopenharmony_ci	struct cdns_i2c *id = to_cdns_i2c(nb);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (pm_runtime_suspended(id->dev))
112362306a36Sopenharmony_ci		return NOTIFY_OK;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	switch (event) {
112662306a36Sopenharmony_ci	case PRE_RATE_CHANGE:
112762306a36Sopenharmony_ci	{
112862306a36Sopenharmony_ci		unsigned long input_clk = ndata->new_rate;
112962306a36Sopenharmony_ci		unsigned long fscl = id->i2c_clk;
113062306a36Sopenharmony_ci		unsigned int div_a, div_b;
113162306a36Sopenharmony_ci		int ret;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b);
113462306a36Sopenharmony_ci		if (ret) {
113562306a36Sopenharmony_ci			dev_warn(id->adap.dev.parent,
113662306a36Sopenharmony_ci					"clock rate change rejected\n");
113762306a36Sopenharmony_ci			return NOTIFY_STOP;
113862306a36Sopenharmony_ci		}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		/* scale up */
114162306a36Sopenharmony_ci		if (ndata->new_rate > ndata->old_rate)
114262306a36Sopenharmony_ci			cdns_i2c_setclk(ndata->new_rate, id);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		return NOTIFY_OK;
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci	case POST_RATE_CHANGE:
114762306a36Sopenharmony_ci		id->input_clk = ndata->new_rate;
114862306a36Sopenharmony_ci		/* scale down */
114962306a36Sopenharmony_ci		if (ndata->new_rate < ndata->old_rate)
115062306a36Sopenharmony_ci			cdns_i2c_setclk(ndata->new_rate, id);
115162306a36Sopenharmony_ci		return NOTIFY_OK;
115262306a36Sopenharmony_ci	case ABORT_RATE_CHANGE:
115362306a36Sopenharmony_ci		/* scale up */
115462306a36Sopenharmony_ci		if (ndata->new_rate > ndata->old_rate)
115562306a36Sopenharmony_ci			cdns_i2c_setclk(ndata->old_rate, id);
115662306a36Sopenharmony_ci		return NOTIFY_OK;
115762306a36Sopenharmony_ci	default:
115862306a36Sopenharmony_ci		return NOTIFY_DONE;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci/**
116362306a36Sopenharmony_ci * cdns_i2c_runtime_suspend -  Runtime suspend method for the driver
116462306a36Sopenharmony_ci * @dev:	Address of the platform_device structure
116562306a36Sopenharmony_ci *
116662306a36Sopenharmony_ci * Put the driver into low power mode.
116762306a36Sopenharmony_ci *
116862306a36Sopenharmony_ci * Return: 0 always
116962306a36Sopenharmony_ci */
117062306a36Sopenharmony_cistatic int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	struct cdns_i2c *xi2c = dev_get_drvdata(dev);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	clk_disable(xi2c->clk);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	return 0;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci/**
118062306a36Sopenharmony_ci * cdns_i2c_init -  Controller initialisation
118162306a36Sopenharmony_ci * @id:		Device private data structure
118262306a36Sopenharmony_ci *
118362306a36Sopenharmony_ci * Initialise the i2c controller.
118462306a36Sopenharmony_ci *
118562306a36Sopenharmony_ci */
118662306a36Sopenharmony_cistatic void cdns_i2c_init(struct cdns_i2c *id)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
118962306a36Sopenharmony_ci	/*
119062306a36Sopenharmony_ci	 * Cadence I2C controller has a bug wherein it generates
119162306a36Sopenharmony_ci	 * invalid read transaction after HW timeout in master receiver mode.
119262306a36Sopenharmony_ci	 * HW timeout is not used by this driver and the interrupt is disabled.
119362306a36Sopenharmony_ci	 * But the feature itself cannot be disabled. Hence maximum value
119462306a36Sopenharmony_ci	 * is written to this register to reduce the chances of error.
119562306a36Sopenharmony_ci	 */
119662306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci/**
120062306a36Sopenharmony_ci * cdns_i2c_runtime_resume - Runtime resume
120162306a36Sopenharmony_ci * @dev:	Address of the platform_device structure
120262306a36Sopenharmony_ci *
120362306a36Sopenharmony_ci * Runtime resume callback.
120462306a36Sopenharmony_ci *
120562306a36Sopenharmony_ci * Return: 0 on success and error value on error
120662306a36Sopenharmony_ci */
120762306a36Sopenharmony_cistatic int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	struct cdns_i2c *xi2c = dev_get_drvdata(dev);
121062306a36Sopenharmony_ci	int ret;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	ret = clk_enable(xi2c->clk);
121362306a36Sopenharmony_ci	if (ret) {
121462306a36Sopenharmony_ci		dev_err(dev, "Cannot enable clock.\n");
121562306a36Sopenharmony_ci		return ret;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	cdns_i2c_init(xi2c);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
122362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
122462306a36Sopenharmony_ci			   cdns_i2c_runtime_resume, NULL)
122562306a36Sopenharmony_ci};
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_cistatic const struct cdns_platform_data r1p10_i2c_def = {
122862306a36Sopenharmony_ci	.quirks = CDNS_I2C_BROKEN_HOLD_BIT,
122962306a36Sopenharmony_ci};
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic const struct of_device_id cdns_i2c_of_match[] = {
123262306a36Sopenharmony_ci	{ .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def },
123362306a36Sopenharmony_ci	{ .compatible = "cdns,i2c-r1p14",},
123462306a36Sopenharmony_ci	{ /* end of table */ }
123562306a36Sopenharmony_ci};
123662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci/**
123962306a36Sopenharmony_ci * cdns_i2c_detect_transfer_size - Detect the maximum transfer size supported
124062306a36Sopenharmony_ci * @id: Device private data structure
124162306a36Sopenharmony_ci *
124262306a36Sopenharmony_ci * Detect the maximum transfer size that is supported by this instance of the
124362306a36Sopenharmony_ci * Cadence I2C controller.
124462306a36Sopenharmony_ci */
124562306a36Sopenharmony_cistatic void cdns_i2c_detect_transfer_size(struct cdns_i2c *id)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	u32 val;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/*
125062306a36Sopenharmony_ci	 * Writing to the transfer size register is only possible if these two bits
125162306a36Sopenharmony_ci	 * are set in the control register.
125262306a36Sopenharmony_ci	 */
125362306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_CR_MS | CDNS_I2C_CR_RW, CDNS_I2C_CR_OFFSET);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/*
125662306a36Sopenharmony_ci	 * The number of writable bits of the transfer size register can be between
125762306a36Sopenharmony_ci	 * 4 and 8. This is a controlled through a synthesis parameter of the IP
125862306a36Sopenharmony_ci	 * core and can vary from instance to instance. The unused MSBs always read
125962306a36Sopenharmony_ci	 * back as 0. Writing 0xff and then reading the value back will report the
126062306a36Sopenharmony_ci	 * maximum supported transfer size.
126162306a36Sopenharmony_ci	 */
126262306a36Sopenharmony_ci	cdns_i2c_writereg(CDNS_I2C_MAX_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET);
126362306a36Sopenharmony_ci	val = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
126462306a36Sopenharmony_ci	id->transfer_size = CDNS_I2C_TRANSFER_SIZE(val);
126562306a36Sopenharmony_ci	cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
126662306a36Sopenharmony_ci	cdns_i2c_writereg(0, CDNS_I2C_CR_OFFSET);
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci/**
127062306a36Sopenharmony_ci * cdns_i2c_probe - Platform registration call
127162306a36Sopenharmony_ci * @pdev:	Handle to the platform device structure
127262306a36Sopenharmony_ci *
127362306a36Sopenharmony_ci * This function does all the memory allocation and registration for the i2c
127462306a36Sopenharmony_ci * device. User can modify the address mode to 10 bit address mode using the
127562306a36Sopenharmony_ci * ioctl call with option I2C_TENBIT.
127662306a36Sopenharmony_ci *
127762306a36Sopenharmony_ci * Return: 0 on success, negative error otherwise
127862306a36Sopenharmony_ci */
127962306a36Sopenharmony_cistatic int cdns_i2c_probe(struct platform_device *pdev)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct resource *r_mem;
128262306a36Sopenharmony_ci	struct cdns_i2c *id;
128362306a36Sopenharmony_ci	int ret, irq;
128462306a36Sopenharmony_ci	const struct of_device_id *match;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
128762306a36Sopenharmony_ci	if (!id)
128862306a36Sopenharmony_ci		return -ENOMEM;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	id->dev = &pdev->dev;
129162306a36Sopenharmony_ci	platform_set_drvdata(pdev, id);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
129462306a36Sopenharmony_ci	if (match && match->data) {
129562306a36Sopenharmony_ci		const struct cdns_platform_data *data = match->data;
129662306a36Sopenharmony_ci		id->quirks = data->quirks;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	id->rinfo.pinctrl = devm_pinctrl_get(&pdev->dev);
130062306a36Sopenharmony_ci	if (IS_ERR(id->rinfo.pinctrl)) {
130162306a36Sopenharmony_ci		int err = PTR_ERR(id->rinfo.pinctrl);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci		dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
130462306a36Sopenharmony_ci		if (err != -ENODEV)
130562306a36Sopenharmony_ci			return err;
130662306a36Sopenharmony_ci	} else {
130762306a36Sopenharmony_ci		id->adap.bus_recovery_info = &id->rinfo;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem);
131162306a36Sopenharmony_ci	if (IS_ERR(id->membase))
131262306a36Sopenharmony_ci		return PTR_ERR(id->membase);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
131562306a36Sopenharmony_ci	if (irq < 0)
131662306a36Sopenharmony_ci		return irq;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	id->adap.owner = THIS_MODULE;
131962306a36Sopenharmony_ci	id->adap.dev.of_node = pdev->dev.of_node;
132062306a36Sopenharmony_ci	id->adap.algo = &cdns_i2c_algo;
132162306a36Sopenharmony_ci	id->adap.timeout = CDNS_I2C_TIMEOUT;
132262306a36Sopenharmony_ci	id->adap.retries = 3;		/* Default retry value. */
132362306a36Sopenharmony_ci	id->adap.algo_data = id;
132462306a36Sopenharmony_ci	id->adap.dev.parent = &pdev->dev;
132562306a36Sopenharmony_ci	init_completion(&id->xfer_done);
132662306a36Sopenharmony_ci	snprintf(id->adap.name, sizeof(id->adap.name),
132762306a36Sopenharmony_ci		 "Cadence I2C at %08lx", (unsigned long)r_mem->start);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	id->clk = devm_clk_get(&pdev->dev, NULL);
133062306a36Sopenharmony_ci	if (IS_ERR(id->clk))
133162306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(id->clk),
133262306a36Sopenharmony_ci				     "input clock not found.\n");
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	id->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
133562306a36Sopenharmony_ci	if (IS_ERR(id->reset))
133662306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(id->reset),
133762306a36Sopenharmony_ci				     "Failed to request reset.\n");
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	ret = clk_prepare_enable(id->clk);
134062306a36Sopenharmony_ci	if (ret)
134162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to enable clock.\n");
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	ret = reset_control_deassert(id->reset);
134462306a36Sopenharmony_ci	if (ret) {
134562306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret,
134662306a36Sopenharmony_ci			      "Failed to de-assert reset.\n");
134762306a36Sopenharmony_ci		goto err_clk_dis;
134862306a36Sopenharmony_ci	}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
135162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(id->dev);
135262306a36Sopenharmony_ci	pm_runtime_set_active(id->dev);
135362306a36Sopenharmony_ci	pm_runtime_enable(id->dev);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
135662306a36Sopenharmony_ci	if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
135762306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
135862306a36Sopenharmony_ci	id->input_clk = clk_get_rate(id->clk);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
136162306a36Sopenharmony_ci			&id->i2c_clk);
136262306a36Sopenharmony_ci	if (ret || (id->i2c_clk > I2C_MAX_FAST_MODE_FREQ))
136362306a36Sopenharmony_ci		id->i2c_clk = I2C_MAX_STANDARD_MODE_FREQ;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SLAVE)
136662306a36Sopenharmony_ci	/* Set initial mode to master */
136762306a36Sopenharmony_ci	id->dev_mode = CDNS_I2C_MODE_MASTER;
136862306a36Sopenharmony_ci	id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
136962306a36Sopenharmony_ci#endif
137062306a36Sopenharmony_ci	id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
137362306a36Sopenharmony_ci	of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	cdns_i2c_detect_transfer_size(id);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	ret = cdns_i2c_setclk(id->input_clk, id);
137862306a36Sopenharmony_ci	if (ret) {
137962306a36Sopenharmony_ci		dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
138062306a36Sopenharmony_ci		ret = -EINVAL;
138162306a36Sopenharmony_ci		goto err_clk_notifier_unregister;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, cdns_i2c_isr, 0,
138562306a36Sopenharmony_ci				 DRIVER_NAME, id);
138662306a36Sopenharmony_ci	if (ret) {
138762306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot get irq %d\n", irq);
138862306a36Sopenharmony_ci		goto err_clk_notifier_unregister;
138962306a36Sopenharmony_ci	}
139062306a36Sopenharmony_ci	cdns_i2c_init(id);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	ret = i2c_add_adapter(&id->adap);
139362306a36Sopenharmony_ci	if (ret < 0)
139462306a36Sopenharmony_ci		goto err_clk_notifier_unregister;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
139762306a36Sopenharmony_ci		 id->i2c_clk / 1000, (unsigned long)r_mem->start, irq);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	return 0;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cierr_clk_notifier_unregister:
140262306a36Sopenharmony_ci	clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
140362306a36Sopenharmony_ci	reset_control_assert(id->reset);
140462306a36Sopenharmony_cierr_clk_dis:
140562306a36Sopenharmony_ci	clk_disable_unprepare(id->clk);
140662306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
140762306a36Sopenharmony_ci	pm_runtime_set_suspended(&pdev->dev);
140862306a36Sopenharmony_ci	return ret;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci/**
141262306a36Sopenharmony_ci * cdns_i2c_remove - Unregister the device after releasing the resources
141362306a36Sopenharmony_ci * @pdev:	Handle to the platform device structure
141462306a36Sopenharmony_ci *
141562306a36Sopenharmony_ci * This function frees all the resources allocated to the device.
141662306a36Sopenharmony_ci *
141762306a36Sopenharmony_ci * Return: 0 always
141862306a36Sopenharmony_ci */
141962306a36Sopenharmony_cistatic void cdns_i2c_remove(struct platform_device *pdev)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	struct cdns_i2c *id = platform_get_drvdata(pdev);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
142462306a36Sopenharmony_ci	pm_runtime_set_suspended(&pdev->dev);
142562306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	i2c_del_adapter(&id->adap);
142862306a36Sopenharmony_ci	clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
142962306a36Sopenharmony_ci	reset_control_assert(id->reset);
143062306a36Sopenharmony_ci	clk_disable_unprepare(id->clk);
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic struct platform_driver cdns_i2c_drv = {
143462306a36Sopenharmony_ci	.driver = {
143562306a36Sopenharmony_ci		.name  = DRIVER_NAME,
143662306a36Sopenharmony_ci		.of_match_table = cdns_i2c_of_match,
143762306a36Sopenharmony_ci		.pm = &cdns_i2c_dev_pm_ops,
143862306a36Sopenharmony_ci	},
143962306a36Sopenharmony_ci	.probe  = cdns_i2c_probe,
144062306a36Sopenharmony_ci	.remove_new = cdns_i2c_remove,
144162306a36Sopenharmony_ci};
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cimodule_platform_driver(cdns_i2c_drv);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ciMODULE_AUTHOR("Xilinx Inc.");
144662306a36Sopenharmony_ciMODULE_DESCRIPTION("Cadence I2C bus driver");
144762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1448