162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the Renesas RZ/V2M I2C unit
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016-2022 Renesas Electronics Corporation
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bits.h>
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/iopoll.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci#include <linux/jiffies.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/math64.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2362306a36Sopenharmony_ci#include <linux/reset.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Register offsets */
2662306a36Sopenharmony_ci#define IICB0DAT	0x00		/* Data Register */
2762306a36Sopenharmony_ci#define IICB0CTL0	0x08		/* Control Register 0 */
2862306a36Sopenharmony_ci#define IICB0TRG	0x0C		/* Trigger Register */
2962306a36Sopenharmony_ci#define IICB0STR0	0x10		/* Status Register 0 */
3062306a36Sopenharmony_ci#define IICB0CTL1	0x20		/* Control Register 1 */
3162306a36Sopenharmony_ci#define IICB0WL		0x24		/* Low Level Width Setting Reg */
3262306a36Sopenharmony_ci#define IICB0WH		0x28		/* How Level Width Setting Reg */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* IICB0CTL0 */
3562306a36Sopenharmony_ci#define IICB0IICE	BIT(7)		/* I2C Enable */
3662306a36Sopenharmony_ci#define IICB0SLWT	BIT(1)		/* Interrupt Request Timing */
3762306a36Sopenharmony_ci#define IICB0SLAC	BIT(0)		/* Acknowledge */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* IICB0TRG */
4062306a36Sopenharmony_ci#define IICB0WRET	BIT(2)		/* Quit Wait Trigger */
4162306a36Sopenharmony_ci#define IICB0STT	BIT(1)		/* Create Start Condition Trigger */
4262306a36Sopenharmony_ci#define IICB0SPT	BIT(0)		/* Create Stop Condition Trigger */
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* IICB0STR0 */
4562306a36Sopenharmony_ci#define IICB0SSAC	BIT(8)		/* Ack Flag */
4662306a36Sopenharmony_ci#define IICB0SSBS	BIT(6)		/* Bus Flag */
4762306a36Sopenharmony_ci#define IICB0SSSP	BIT(4)		/* Stop Condition Flag */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* IICB0CTL1 */
5062306a36Sopenharmony_ci#define IICB0MDSC	BIT(7)		/* Bus Mode */
5162306a36Sopenharmony_ci#define IICB0SLSE	BIT(1)		/* Start condition output */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct rzv2m_i2c_priv {
5462306a36Sopenharmony_ci	void __iomem *base;
5562306a36Sopenharmony_ci	struct i2c_adapter adap;
5662306a36Sopenharmony_ci	struct clk *clk;
5762306a36Sopenharmony_ci	int bus_mode;
5862306a36Sopenharmony_ci	struct completion msg_tia_done;
5962306a36Sopenharmony_ci	u32 iicb0wl;
6062306a36Sopenharmony_ci	u32 iicb0wh;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum bcr_index {
6462306a36Sopenharmony_ci	RZV2M_I2C_100K = 0,
6562306a36Sopenharmony_ci	RZV2M_I2C_400K,
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct bitrate_config {
6962306a36Sopenharmony_ci	unsigned int percent_low;
7062306a36Sopenharmony_ci	unsigned int min_hold_time_ns;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic const struct bitrate_config bitrate_configs[] = {
7462306a36Sopenharmony_ci	[RZV2M_I2C_100K] = { 47, 3450 },
7562306a36Sopenharmony_ci	[RZV2M_I2C_400K] = { 52, 900 },
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline void bit_setl(void __iomem *addr, u32 val)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	writel(readl(addr) | val, addr);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline void bit_clrl(void __iomem *addr, u32 val)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	writel(readl(addr) & ~val, addr);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic irqreturn_t rzv2m_i2c_tia_irq_handler(int this_irq, void *dev_id)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv = dev_id;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	complete(&priv->msg_tia_done);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return IRQ_HANDLED;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* Calculate IICB0WL and IICB0WH */
9862306a36Sopenharmony_cistatic int rzv2m_i2c_clock_calculate(struct device *dev,
9962306a36Sopenharmony_ci				     struct rzv2m_i2c_priv *priv)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	const struct bitrate_config *config;
10262306a36Sopenharmony_ci	unsigned int hold_time_ns;
10362306a36Sopenharmony_ci	unsigned int total_pclks;
10462306a36Sopenharmony_ci	unsigned int trf_pclks;
10562306a36Sopenharmony_ci	unsigned long pclk_hz;
10662306a36Sopenharmony_ci	struct i2c_timings t;
10762306a36Sopenharmony_ci	u32 trf_ns;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	i2c_parse_fw_timings(dev, &t, true);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	pclk_hz = clk_get_rate(priv->clk);
11262306a36Sopenharmony_ci	total_pclks = pclk_hz / t.bus_freq_hz;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	trf_ns = t.scl_rise_ns + t.scl_fall_ns;
11562306a36Sopenharmony_ci	trf_pclks = mul_u64_u32_div(pclk_hz, trf_ns, NSEC_PER_SEC);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Config setting */
11862306a36Sopenharmony_ci	switch (t.bus_freq_hz) {
11962306a36Sopenharmony_ci	case I2C_MAX_FAST_MODE_FREQ:
12062306a36Sopenharmony_ci		priv->bus_mode = RZV2M_I2C_400K;
12162306a36Sopenharmony_ci		break;
12262306a36Sopenharmony_ci	case I2C_MAX_STANDARD_MODE_FREQ:
12362306a36Sopenharmony_ci		priv->bus_mode = RZV2M_I2C_100K;
12462306a36Sopenharmony_ci		break;
12562306a36Sopenharmony_ci	default:
12662306a36Sopenharmony_ci		dev_err(dev, "transfer speed is invalid\n");
12762306a36Sopenharmony_ci		return -EINVAL;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	config = &bitrate_configs[priv->bus_mode];
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* IICB0WL = (percent_low / Transfer clock) x PCLK */
13262306a36Sopenharmony_ci	priv->iicb0wl = total_pclks * config->percent_low / 100;
13362306a36Sopenharmony_ci	if (priv->iicb0wl > (BIT(10) - 1))
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */
13762306a36Sopenharmony_ci	priv->iicb0wh = total_pclks - priv->iicb0wl - trf_pclks;
13862306a36Sopenharmony_ci	if (priv->iicb0wh > (BIT(10) - 1))
13962306a36Sopenharmony_ci		return -EINVAL;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/*
14262306a36Sopenharmony_ci	 * Data hold time must be less than 0.9us in fast mode and
14362306a36Sopenharmony_ci	 * 3.45us in standard mode.
14462306a36Sopenharmony_ci	 * Data hold time = IICB0WL[9:2] / PCLK
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	hold_time_ns = div64_ul((u64)(priv->iicb0wl >> 2) * NSEC_PER_SEC, pclk_hz);
14762306a36Sopenharmony_ci	if (hold_time_ns > config->min_hold_time_ns) {
14862306a36Sopenharmony_ci		dev_err(dev, "data hold time %dns is over %dns\n",
14962306a36Sopenharmony_ci			hold_time_ns, config->min_hold_time_ns);
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void rzv2m_i2c_init(struct rzv2m_i2c_priv *priv)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u32 i2c_ctl0;
15962306a36Sopenharmony_ci	u32 i2c_ctl1;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* i2c disable */
16262306a36Sopenharmony_ci	writel(0, priv->base + IICB0CTL0);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* IICB0CTL1 setting */
16562306a36Sopenharmony_ci	i2c_ctl1 = IICB0SLSE;
16662306a36Sopenharmony_ci	if (priv->bus_mode == RZV2M_I2C_400K)
16762306a36Sopenharmony_ci		i2c_ctl1 |= IICB0MDSC;
16862306a36Sopenharmony_ci	writel(i2c_ctl1, priv->base + IICB0CTL1);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* IICB0WL IICB0WH setting */
17162306a36Sopenharmony_ci	writel(priv->iicb0wl, priv->base + IICB0WL);
17262306a36Sopenharmony_ci	writel(priv->iicb0wh, priv->base + IICB0WH);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* i2c enable after setting */
17562306a36Sopenharmony_ci	i2c_ctl0 = IICB0SLWT | IICB0SLAC | IICB0IICE;
17662306a36Sopenharmony_ci	writel(i2c_ctl0, priv->base + IICB0CTL0);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int rzv2m_i2c_write_with_ack(struct rzv2m_i2c_priv *priv, u32 data)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	unsigned long time_left;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	reinit_completion(&priv->msg_tia_done);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	writel(data, priv->base + IICB0DAT);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&priv->msg_tia_done,
18862306a36Sopenharmony_ci						priv->adap.timeout);
18962306a36Sopenharmony_ci	if (!time_left)
19062306a36Sopenharmony_ci		return -ETIMEDOUT;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Confirm ACK */
19362306a36Sopenharmony_ci	if ((readl(priv->base + IICB0STR0) & IICB0SSAC) != IICB0SSAC)
19462306a36Sopenharmony_ci		return -ENXIO;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int rzv2m_i2c_read_with_ack(struct rzv2m_i2c_priv *priv, u8 *data,
20062306a36Sopenharmony_ci				   bool last)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	unsigned long time_left;
20362306a36Sopenharmony_ci	u32 data_tmp;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	reinit_completion(&priv->msg_tia_done);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Interrupt request timing : 8th clock */
20862306a36Sopenharmony_ci	bit_clrl(priv->base + IICB0CTL0, IICB0SLWT);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Exit the wait state */
21162306a36Sopenharmony_ci	writel(IICB0WRET, priv->base + IICB0TRG);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* Wait for transaction */
21462306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&priv->msg_tia_done,
21562306a36Sopenharmony_ci						priv->adap.timeout);
21662306a36Sopenharmony_ci	if (!time_left)
21762306a36Sopenharmony_ci		return -ETIMEDOUT;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (last) {
22062306a36Sopenharmony_ci		/* Disable ACK */
22162306a36Sopenharmony_ci		bit_clrl(priv->base + IICB0CTL0, IICB0SLAC);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		/* Read data*/
22462306a36Sopenharmony_ci		data_tmp = readl(priv->base + IICB0DAT);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		/* Interrupt request timing : 9th clock */
22762306a36Sopenharmony_ci		bit_setl(priv->base + IICB0CTL0, IICB0SLWT);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		/* Exit the wait state */
23062306a36Sopenharmony_ci		writel(IICB0WRET, priv->base + IICB0TRG);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		/* Wait for transaction */
23362306a36Sopenharmony_ci		time_left = wait_for_completion_timeout(&priv->msg_tia_done,
23462306a36Sopenharmony_ci							priv->adap.timeout);
23562306a36Sopenharmony_ci		if (!time_left)
23662306a36Sopenharmony_ci			return -ETIMEDOUT;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		/* Enable ACK */
23962306a36Sopenharmony_ci		bit_setl(priv->base + IICB0CTL0, IICB0SLAC);
24062306a36Sopenharmony_ci	} else {
24162306a36Sopenharmony_ci		/* Read data */
24262306a36Sopenharmony_ci		data_tmp = readl(priv->base + IICB0DAT);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	*data = data_tmp;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int rzv2m_i2c_send(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
25162306a36Sopenharmony_ci			  unsigned int *count)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	unsigned int i;
25462306a36Sopenharmony_ci	int ret;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++) {
25762306a36Sopenharmony_ci		ret = rzv2m_i2c_write_with_ack(priv, msg->buf[i]);
25862306a36Sopenharmony_ci		if (ret < 0)
25962306a36Sopenharmony_ci			return ret;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	*count = i;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return 0;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int rzv2m_i2c_receive(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
26762306a36Sopenharmony_ci			     unsigned int *count)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	unsigned int i;
27062306a36Sopenharmony_ci	int ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++) {
27362306a36Sopenharmony_ci		ret = rzv2m_i2c_read_with_ack(priv, &msg->buf[i],
27462306a36Sopenharmony_ci					      (msg->len - 1) == i);
27562306a36Sopenharmony_ci		if (ret < 0)
27662306a36Sopenharmony_ci			return ret;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci	*count = i;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv,
28462306a36Sopenharmony_ci				  struct i2c_msg *msg)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	u32 addr;
28762306a36Sopenharmony_ci	int ret;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (msg->flags & I2C_M_TEN) {
29062306a36Sopenharmony_ci		/*
29162306a36Sopenharmony_ci		 * 10-bit address
29262306a36Sopenharmony_ci		 *   addr_1: 5'b11110 | addr[9:8] | (R/nW)
29362306a36Sopenharmony_ci		 *   addr_2: addr[7:0]
29462306a36Sopenharmony_ci		 */
29562306a36Sopenharmony_ci		addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7);
29662306a36Sopenharmony_ci		addr |= !!(msg->flags & I2C_M_RD);
29762306a36Sopenharmony_ci		/* Send 1st address(extend code) */
29862306a36Sopenharmony_ci		ret = rzv2m_i2c_write_with_ack(priv, addr);
29962306a36Sopenharmony_ci		if (ret)
30062306a36Sopenharmony_ci			return ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* Send 2nd address */
30362306a36Sopenharmony_ci		ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff);
30462306a36Sopenharmony_ci	} else {
30562306a36Sopenharmony_ci		/* 7-bit address */
30662306a36Sopenharmony_ci		addr = i2c_8bit_addr_from_msg(msg);
30762306a36Sopenharmony_ci		ret = rzv2m_i2c_write_with_ack(priv, addr);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return ret;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int rzv2m_i2c_stop_condition(struct rzv2m_i2c_priv *priv)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	u32 value;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Send stop condition */
31862306a36Sopenharmony_ci	writel(IICB0SPT, priv->base + IICB0TRG);
31962306a36Sopenharmony_ci	return readl_poll_timeout(priv->base + IICB0STR0,
32062306a36Sopenharmony_ci				  value, value & IICB0SSSP,
32162306a36Sopenharmony_ci				  100, jiffies_to_usecs(priv->adap.timeout));
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int rzv2m_i2c_master_xfer_msg(struct rzv2m_i2c_priv *priv,
32562306a36Sopenharmony_ci				  struct i2c_msg *msg, int stop)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	unsigned int count = 0;
32862306a36Sopenharmony_ci	int ret, read = !!(msg->flags & I2C_M_RD);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Send start condition */
33162306a36Sopenharmony_ci	writel(IICB0STT, priv->base + IICB0TRG);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = rzv2m_i2c_send_address(priv, msg);
33462306a36Sopenharmony_ci	if (!ret) {
33562306a36Sopenharmony_ci		if (read)
33662306a36Sopenharmony_ci			ret = rzv2m_i2c_receive(priv, msg, &count);
33762306a36Sopenharmony_ci		else
33862306a36Sopenharmony_ci			ret = rzv2m_i2c_send(priv, msg, &count);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		if (!ret && stop)
34162306a36Sopenharmony_ci			ret = rzv2m_i2c_stop_condition(priv);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (ret == -ENXIO)
34562306a36Sopenharmony_ci		rzv2m_i2c_stop_condition(priv);
34662306a36Sopenharmony_ci	else if (ret < 0)
34762306a36Sopenharmony_ci		rzv2m_i2c_init(priv);
34862306a36Sopenharmony_ci	else
34962306a36Sopenharmony_ci		ret = count;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return ret;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int rzv2m_i2c_master_xfer(struct i2c_adapter *adap,
35562306a36Sopenharmony_ci				 struct i2c_msg *msgs, int num)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv = i2c_get_adapdata(adap);
35862306a36Sopenharmony_ci	struct device *dev = priv->adap.dev.parent;
35962306a36Sopenharmony_ci	unsigned int i;
36062306a36Sopenharmony_ci	int ret;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
36362306a36Sopenharmony_ci	if (ret < 0)
36462306a36Sopenharmony_ci		return ret;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (readl(priv->base + IICB0STR0) & IICB0SSBS) {
36762306a36Sopenharmony_ci		ret = -EAGAIN;
36862306a36Sopenharmony_ci		goto out;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* I2C main transfer */
37262306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
37362306a36Sopenharmony_ci		ret = rzv2m_i2c_master_xfer_msg(priv, &msgs[i], i == (num - 1));
37462306a36Sopenharmony_ci		if (ret < 0)
37562306a36Sopenharmony_ci			goto out;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	ret = num;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ciout:
38062306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
38162306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return ret;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic u32 rzv2m_i2c_func(struct i2c_adapter *adap)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
38962306a36Sopenharmony_ci	       I2C_FUNC_10BIT_ADDR;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int rzv2m_i2c_disable(struct device *dev, struct rzv2m_i2c_priv *priv)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int ret;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
39762306a36Sopenharmony_ci	if (ret < 0)
39862306a36Sopenharmony_ci		return ret;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	bit_clrl(priv->base + IICB0CTL0, IICB0IICE);
40162306a36Sopenharmony_ci	pm_runtime_put(dev);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic const struct i2c_adapter_quirks rzv2m_i2c_quirks = {
40762306a36Sopenharmony_ci	.flags = I2C_AQ_NO_ZERO_LEN,
40862306a36Sopenharmony_ci};
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic struct i2c_algorithm rzv2m_i2c_algo = {
41162306a36Sopenharmony_ci	.master_xfer = rzv2m_i2c_master_xfer,
41262306a36Sopenharmony_ci	.functionality = rzv2m_i2c_func,
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int rzv2m_i2c_probe(struct platform_device *pdev)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
41862306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv;
41962306a36Sopenharmony_ci	struct reset_control *rstc;
42062306a36Sopenharmony_ci	struct i2c_adapter *adap;
42162306a36Sopenharmony_ci	struct resource *res;
42262306a36Sopenharmony_ci	int irq, ret;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
42562306a36Sopenharmony_ci	if (!priv)
42662306a36Sopenharmony_ci		return -ENOMEM;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
42962306a36Sopenharmony_ci	if (IS_ERR(priv->base))
43062306a36Sopenharmony_ci		return PTR_ERR(priv->base);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	priv->clk = devm_clk_get(dev, NULL);
43362306a36Sopenharmony_ci	if (IS_ERR(priv->clk))
43462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(priv->clk), "Can't get clock\n");
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	rstc = devm_reset_control_get_shared(dev, NULL);
43762306a36Sopenharmony_ci	if (IS_ERR(rstc))
43862306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(rstc), "Missing reset ctrl\n");
43962306a36Sopenharmony_ci	/*
44062306a36Sopenharmony_ci	 * The reset also affects other HW that is not under the control
44162306a36Sopenharmony_ci	 * of Linux. Therefore, all we can do is deassert the reset.
44262306a36Sopenharmony_ci	 */
44362306a36Sopenharmony_ci	reset_control_deassert(rstc);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
44662306a36Sopenharmony_ci	if (irq < 0)
44762306a36Sopenharmony_ci		return irq;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0,
45062306a36Sopenharmony_ci			       dev_name(dev), priv);
45162306a36Sopenharmony_ci	if (ret < 0)
45262306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	adap = &priv->adap;
45562306a36Sopenharmony_ci	adap->nr = pdev->id;
45662306a36Sopenharmony_ci	adap->algo = &rzv2m_i2c_algo;
45762306a36Sopenharmony_ci	adap->quirks = &rzv2m_i2c_quirks;
45862306a36Sopenharmony_ci	adap->dev.parent = dev;
45962306a36Sopenharmony_ci	adap->owner = THIS_MODULE;
46062306a36Sopenharmony_ci	device_set_node(&adap->dev, dev_fwnode(dev));
46162306a36Sopenharmony_ci	i2c_set_adapdata(adap, priv);
46262306a36Sopenharmony_ci	strscpy(adap->name, pdev->name, sizeof(adap->name));
46362306a36Sopenharmony_ci	init_completion(&priv->msg_tia_done);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	ret = rzv2m_i2c_clock_calculate(dev, priv);
46662306a36Sopenharmony_ci	if (ret < 0)
46762306a36Sopenharmony_ci		return ret;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	pm_runtime_enable(dev);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
47262306a36Sopenharmony_ci	rzv2m_i2c_init(priv);
47362306a36Sopenharmony_ci	pm_runtime_put(dev);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ret = i2c_add_numbered_adapter(adap);
47862306a36Sopenharmony_ci	if (ret < 0) {
47962306a36Sopenharmony_ci		rzv2m_i2c_disable(dev, priv);
48062306a36Sopenharmony_ci		pm_runtime_disable(dev);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return ret;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void rzv2m_i2c_remove(struct platform_device *pdev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv = platform_get_drvdata(pdev);
48962306a36Sopenharmony_ci	struct device *dev = priv->adap.dev.parent;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	i2c_del_adapter(&priv->adap);
49262306a36Sopenharmony_ci	rzv2m_i2c_disable(dev, priv);
49362306a36Sopenharmony_ci	pm_runtime_disable(dev);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int rzv2m_i2c_suspend(struct device *dev)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	return rzv2m_i2c_disable(dev, priv);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int rzv2m_i2c_resume(struct device *dev)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
50662306a36Sopenharmony_ci	int ret;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ret = rzv2m_i2c_clock_calculate(dev, priv);
50962306a36Sopenharmony_ci	if (ret < 0)
51062306a36Sopenharmony_ci		return ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
51362306a36Sopenharmony_ci	if (ret < 0)
51462306a36Sopenharmony_ci		return ret;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	rzv2m_i2c_init(priv);
51762306a36Sopenharmony_ci	pm_runtime_put(dev);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic const struct of_device_id rzv2m_i2c_ids[] = {
52362306a36Sopenharmony_ci	{ .compatible = "renesas,rzv2m-i2c" },
52462306a36Sopenharmony_ci	{ }
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rzv2m_i2c_ids);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic const struct dev_pm_ops rzv2m_i2c_pm_ops = {
52962306a36Sopenharmony_ci	SYSTEM_SLEEP_PM_OPS(rzv2m_i2c_suspend, rzv2m_i2c_resume)
53062306a36Sopenharmony_ci};
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic struct platform_driver rzv2m_i2c_driver = {
53362306a36Sopenharmony_ci	.driver = {
53462306a36Sopenharmony_ci		.name = "rzv2m-i2c",
53562306a36Sopenharmony_ci		.of_match_table = rzv2m_i2c_ids,
53662306a36Sopenharmony_ci		.pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops),
53762306a36Sopenharmony_ci	},
53862306a36Sopenharmony_ci	.probe	= rzv2m_i2c_probe,
53962306a36Sopenharmony_ci	.remove_new = rzv2m_i2c_remove,
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_cimodule_platform_driver(rzv2m_i2c_driver);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ciMODULE_DESCRIPTION("RZ/V2M I2C bus driver");
54462306a36Sopenharmony_ciMODULE_AUTHOR("Renesas Electronics Corporation");
54562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
546