18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk.h>
78c2ecf20Sopenharmony_ci#include <linux/i2c.h>
88c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
98c2ecf20Sopenharmony_ci#include <linux/io.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_DTRM	0x00	/* TX register */
148c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DTRM_IRQEN	BIT(11)	/* enable interrupt */
158c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DTRM_STA	BIT(10)	/* start condition */
168c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DTRM_STO	BIT(9)	/* stop condition */
178c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DTRM_NACK	BIT(8)	/* do not return ACK */
188c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DTRM_RD	BIT(0)	/* read transaction */
198c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_DREC	0x04	/* RX register */
208c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_MST	BIT(14)	/* 1 = master, 0 = slave */
218c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_TX	BIT(13)	/* 1 = transmit, 0 = receive */
228c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_STS	BIT(12)	/* stop condition detected */
238c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_LRB	BIT(11)	/* no ACK */
248c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_LAB	BIT(9)	/* arbitration lost */
258c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_DREC_BBN	BIT(8)	/* bus not busy */
268c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_MYAD	0x08	/* slave address */
278c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_CLK	0x0c	/* clock frequency control */
288c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_BRST	0x10	/* bus reset */
298c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_BRST_FOEN	BIT(1)	/* normal operation */
308c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_BRST_RSCL	BIT(0)	/* release SCL */
318c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_HOLD	0x14	/* hold time control */
328c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_BSTS	0x18	/* bus status monitor */
338c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_BSTS_SDA	BIT(1)	/* readback of SDA line */
348c2ecf20Sopenharmony_ci#define     UNIPHIER_I2C_BSTS_SCL	BIT(0)	/* readback of SCL line */
358c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_NOISE	0x1c	/* noise filter control */
368c2ecf20Sopenharmony_ci#define UNIPHIER_I2C_SETUP	0x20	/* setup time control */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct uniphier_i2c_priv {
398c2ecf20Sopenharmony_ci	struct completion comp;
408c2ecf20Sopenharmony_ci	struct i2c_adapter adap;
418c2ecf20Sopenharmony_ci	void __iomem *membase;
428c2ecf20Sopenharmony_ci	struct clk *clk;
438c2ecf20Sopenharmony_ci	unsigned int busy_cnt;
448c2ecf20Sopenharmony_ci	unsigned int clk_cycle;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = dev_id;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/*
528c2ecf20Sopenharmony_ci	 * This hardware uses edge triggered interrupt.  Do not touch the
538c2ecf20Sopenharmony_ci	 * hardware registers in this handler to make sure to catch the next
548c2ecf20Sopenharmony_ci	 * interrupt edge.  Just send a complete signal and return.
558c2ecf20Sopenharmony_ci	 */
568c2ecf20Sopenharmony_ci	complete(&priv->comp);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
628c2ecf20Sopenharmony_ci				  u32 *rxdatap)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
658c2ecf20Sopenharmony_ci	unsigned long time_left;
668c2ecf20Sopenharmony_ci	u32 rxdata;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	reinit_completion(&priv->comp);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	txdata |= UNIPHIER_I2C_DTRM_IRQEN;
718c2ecf20Sopenharmony_ci	writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
748c2ecf20Sopenharmony_ci	if (unlikely(!time_left)) {
758c2ecf20Sopenharmony_ci		dev_err(&adap->dev, "transaction timeout\n");
768c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
808c2ecf20Sopenharmony_ci	if (rxdatap)
818c2ecf20Sopenharmony_ci		*rxdatap = rxdata;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return 0;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	u32 rxdata;
898c2ecf20Sopenharmony_ci	int ret;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata);
928c2ecf20Sopenharmony_ci	if (ret)
938c2ecf20Sopenharmony_ci		return ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB))
968c2ecf20Sopenharmony_ci		return -EAGAIN;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB))
998c2ecf20Sopenharmony_ci		return -ENXIO;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
1058c2ecf20Sopenharmony_ci			   const u8 *buf)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int ret;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	ret = uniphier_i2c_send_byte(adap, addr << 1 |
1108c2ecf20Sopenharmony_ci				     UNIPHIER_I2C_DTRM_STA |
1118c2ecf20Sopenharmony_ci				     UNIPHIER_I2C_DTRM_NACK);
1128c2ecf20Sopenharmony_ci	if (ret)
1138c2ecf20Sopenharmony_ci		return ret;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	while (len--) {
1168c2ecf20Sopenharmony_ci		ret = uniphier_i2c_send_byte(adap,
1178c2ecf20Sopenharmony_ci					     UNIPHIER_I2C_DTRM_NACK | *buf++);
1188c2ecf20Sopenharmony_ci		if (ret)
1198c2ecf20Sopenharmony_ci			return ret;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return 0;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
1268c2ecf20Sopenharmony_ci			   u8 *buf)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	int ret;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ret = uniphier_i2c_send_byte(adap, addr << 1 |
1318c2ecf20Sopenharmony_ci				     UNIPHIER_I2C_DTRM_STA |
1328c2ecf20Sopenharmony_ci				     UNIPHIER_I2C_DTRM_NACK |
1338c2ecf20Sopenharmony_ci				     UNIPHIER_I2C_DTRM_RD);
1348c2ecf20Sopenharmony_ci	if (ret)
1358c2ecf20Sopenharmony_ci		return ret;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	while (len--) {
1388c2ecf20Sopenharmony_ci		u32 rxdata;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		ret = uniphier_i2c_xfer_byte(adap,
1418c2ecf20Sopenharmony_ci					     len ? 0 : UNIPHIER_I2C_DTRM_NACK,
1428c2ecf20Sopenharmony_ci					     &rxdata);
1438c2ecf20Sopenharmony_ci		if (ret)
1448c2ecf20Sopenharmony_ci			return ret;
1458c2ecf20Sopenharmony_ci		*buf++ = rxdata;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int uniphier_i2c_stop(struct i2c_adapter *adap)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
1548c2ecf20Sopenharmony_ci				      UNIPHIER_I2C_DTRM_NACK);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
1588c2ecf20Sopenharmony_ci					struct i2c_msg *msg, bool stop)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	bool is_read = msg->flags & I2C_M_RD;
1618c2ecf20Sopenharmony_ci	bool recovery = false;
1628c2ecf20Sopenharmony_ci	int ret;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (is_read)
1658c2ecf20Sopenharmony_ci		ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
1668c2ecf20Sopenharmony_ci	else
1678c2ecf20Sopenharmony_ci		ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */
1708c2ecf20Sopenharmony_ci		return ret;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (ret == -ETIMEDOUT) {
1738c2ecf20Sopenharmony_ci		/* This error is fatal.  Needs recovery. */
1748c2ecf20Sopenharmony_ci		stop = false;
1758c2ecf20Sopenharmony_ci		recovery = true;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (stop) {
1798c2ecf20Sopenharmony_ci		int ret2 = uniphier_i2c_stop(adap);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		if (ret2) {
1828c2ecf20Sopenharmony_ci			/* Failed to issue STOP.  The bus needs recovery. */
1838c2ecf20Sopenharmony_ci			recovery = true;
1848c2ecf20Sopenharmony_ci			ret = ret ?: ret2;
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (recovery)
1898c2ecf20Sopenharmony_ci		i2c_recover_bus(adap);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return ret;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (!(readl(priv->membase + UNIPHIER_I2C_DREC) &
1998c2ecf20Sopenharmony_ci						UNIPHIER_I2C_DREC_BBN)) {
2008c2ecf20Sopenharmony_ci		if (priv->busy_cnt++ > 3) {
2018c2ecf20Sopenharmony_ci			/*
2028c2ecf20Sopenharmony_ci			 * If bus busy continues too long, it is probably
2038c2ecf20Sopenharmony_ci			 * in a wrong state.  Try bus recovery.
2048c2ecf20Sopenharmony_ci			 */
2058c2ecf20Sopenharmony_ci			i2c_recover_bus(adap);
2068c2ecf20Sopenharmony_ci			priv->busy_cnt = 0;
2078c2ecf20Sopenharmony_ci		}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		return -EAGAIN;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	priv->busy_cnt = 0;
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int uniphier_i2c_master_xfer(struct i2c_adapter *adap,
2178c2ecf20Sopenharmony_ci				    struct i2c_msg *msgs, int num)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct i2c_msg *msg, *emsg = msgs + num;
2208c2ecf20Sopenharmony_ci	int ret;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = uniphier_i2c_check_bus_busy(adap);
2238c2ecf20Sopenharmony_ci	if (ret)
2248c2ecf20Sopenharmony_ci		return ret;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	for (msg = msgs; msg < emsg; msg++) {
2278c2ecf20Sopenharmony_ci		/* Emit STOP if it is the last message or I2C_M_STOP is set. */
2288c2ecf20Sopenharmony_ci		bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
2318c2ecf20Sopenharmony_ci		if (ret)
2328c2ecf20Sopenharmony_ci			return ret;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return num;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic u32 uniphier_i2c_functionality(struct i2c_adapter *adap)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic const struct i2c_algorithm uniphier_i2c_algo = {
2448c2ecf20Sopenharmony_ci	.master_xfer = uniphier_i2c_master_xfer,
2458c2ecf20Sopenharmony_ci	.functionality = uniphier_i2c_functionality,
2468c2ecf20Sopenharmony_ci};
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	u32 val = UNIPHIER_I2C_BRST_RSCL;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN;
2538c2ecf20Sopenharmony_ci	writel(val, priv->membase + UNIPHIER_I2C_BRST);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic int uniphier_i2c_get_scl(struct i2c_adapter *adap)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
2618c2ecf20Sopenharmony_ci							UNIPHIER_I2C_BSTS_SCL);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	writel(val ? UNIPHIER_I2C_BRST_RSCL : 0,
2698c2ecf20Sopenharmony_ci	       priv->membase + UNIPHIER_I2C_BRST);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int uniphier_i2c_get_sda(struct i2c_adapter *adap)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
2778c2ecf20Sopenharmony_ci							UNIPHIER_I2C_BSTS_SDA);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	uniphier_i2c_reset(i2c_get_adapdata(adap), false);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
2868c2ecf20Sopenharmony_ci	.recover_bus = i2c_generic_scl_recovery,
2878c2ecf20Sopenharmony_ci	.get_scl = uniphier_i2c_get_scl,
2888c2ecf20Sopenharmony_ci	.set_scl = uniphier_i2c_set_scl,
2898c2ecf20Sopenharmony_ci	.get_sda = uniphier_i2c_get_sda,
2908c2ecf20Sopenharmony_ci	.unprepare_recovery = uniphier_i2c_unprepare_recovery,
2918c2ecf20Sopenharmony_ci};
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	unsigned int cyc = priv->clk_cycle;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	uniphier_i2c_reset(priv, true);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * Bit30-16: clock cycles of tLOW.
3018c2ecf20Sopenharmony_ci	 *  Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us
3028c2ecf20Sopenharmony_ci	 *  Fast-mode:     tLOW = 1.3 us, tHIGH = 0.6 us
3038c2ecf20Sopenharmony_ci	 * "tLow/tHIGH = 5/4" meets both.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	writel((cyc * 5 / 9 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	uniphier_i2c_reset(priv, false);
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic int uniphier_i2c_probe(struct platform_device *pdev)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3138c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv;
3148c2ecf20Sopenharmony_ci	u32 bus_speed;
3158c2ecf20Sopenharmony_ci	unsigned long clk_rate;
3168c2ecf20Sopenharmony_ci	int irq, ret;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3198c2ecf20Sopenharmony_ci	if (!priv)
3208c2ecf20Sopenharmony_ci		return -ENOMEM;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	priv->membase = devm_platform_ioremap_resource(pdev, 0);
3238c2ecf20Sopenharmony_ci	if (IS_ERR(priv->membase))
3248c2ecf20Sopenharmony_ci		return PTR_ERR(priv->membase);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
3278c2ecf20Sopenharmony_ci	if (irq < 0)
3288c2ecf20Sopenharmony_ci		return irq;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
3318c2ecf20Sopenharmony_ci		bus_speed = I2C_MAX_STANDARD_MODE_FREQ;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) {
3348c2ecf20Sopenharmony_ci		dev_err(dev, "invalid clock-frequency %d\n", bus_speed);
3358c2ecf20Sopenharmony_ci		return -EINVAL;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	priv->clk = devm_clk_get(dev, NULL);
3398c2ecf20Sopenharmony_ci	if (IS_ERR(priv->clk)) {
3408c2ecf20Sopenharmony_ci		dev_err(dev, "failed to get clock\n");
3418c2ecf20Sopenharmony_ci		return PTR_ERR(priv->clk);
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->clk);
3458c2ecf20Sopenharmony_ci	if (ret)
3468c2ecf20Sopenharmony_ci		return ret;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	clk_rate = clk_get_rate(priv->clk);
3498c2ecf20Sopenharmony_ci	if (!clk_rate) {
3508c2ecf20Sopenharmony_ci		dev_err(dev, "input clock rate should not be zero\n");
3518c2ecf20Sopenharmony_ci		ret = -EINVAL;
3528c2ecf20Sopenharmony_ci		goto disable_clk;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	priv->clk_cycle = clk_rate / bus_speed;
3568c2ecf20Sopenharmony_ci	init_completion(&priv->comp);
3578c2ecf20Sopenharmony_ci	priv->adap.owner = THIS_MODULE;
3588c2ecf20Sopenharmony_ci	priv->adap.algo = &uniphier_i2c_algo;
3598c2ecf20Sopenharmony_ci	priv->adap.dev.parent = dev;
3608c2ecf20Sopenharmony_ci	priv->adap.dev.of_node = dev->of_node;
3618c2ecf20Sopenharmony_ci	strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name));
3628c2ecf20Sopenharmony_ci	priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info;
3638c2ecf20Sopenharmony_ci	i2c_set_adapdata(&priv->adap, priv);
3648c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	uniphier_i2c_hw_init(priv);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
3698c2ecf20Sopenharmony_ci			       priv);
3708c2ecf20Sopenharmony_ci	if (ret) {
3718c2ecf20Sopenharmony_ci		dev_err(dev, "failed to request irq %d\n", irq);
3728c2ecf20Sopenharmony_ci		goto disable_clk;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret = i2c_add_adapter(&priv->adap);
3768c2ecf20Sopenharmony_cidisable_clk:
3778c2ecf20Sopenharmony_ci	if (ret)
3788c2ecf20Sopenharmony_ci		clk_disable_unprepare(priv->clk);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return ret;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int uniphier_i2c_remove(struct platform_device *pdev)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	i2c_del_adapter(&priv->adap);
3888c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->clk);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return 0;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int __maybe_unused uniphier_i2c_suspend(struct device *dev)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->clk);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return 0;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int __maybe_unused uniphier_i2c_resume(struct device *dev)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
4058c2ecf20Sopenharmony_ci	int ret;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->clk);
4088c2ecf20Sopenharmony_ci	if (ret)
4098c2ecf20Sopenharmony_ci		return ret;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	uniphier_i2c_hw_init(priv);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic const struct dev_pm_ops uniphier_i2c_pm_ops = {
4178c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(uniphier_i2c_suspend, uniphier_i2c_resume)
4188c2ecf20Sopenharmony_ci};
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic const struct of_device_id uniphier_i2c_match[] = {
4218c2ecf20Sopenharmony_ci	{ .compatible = "socionext,uniphier-i2c" },
4228c2ecf20Sopenharmony_ci	{ /* sentinel */ }
4238c2ecf20Sopenharmony_ci};
4248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_i2c_match);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic struct platform_driver uniphier_i2c_drv = {
4278c2ecf20Sopenharmony_ci	.probe  = uniphier_i2c_probe,
4288c2ecf20Sopenharmony_ci	.remove = uniphier_i2c_remove,
4298c2ecf20Sopenharmony_ci	.driver = {
4308c2ecf20Sopenharmony_ci		.name  = "uniphier-i2c",
4318c2ecf20Sopenharmony_ci		.of_match_table = uniphier_i2c_match,
4328c2ecf20Sopenharmony_ci		.pm = &uniphier_i2c_pm_ops,
4338c2ecf20Sopenharmony_ci	},
4348c2ecf20Sopenharmony_ci};
4358c2ecf20Sopenharmony_cimodule_platform_driver(uniphier_i2c_drv);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
4388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier I2C bus driver");
4398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
440