xref: /openbmc/linux/drivers/i2c/busses/i2c-owl.c (revision 8759500cbdfcaf825316bc8d466d11462d7efbda)
1d211e62aSManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0-or-later
2d211e62aSManivannan Sadhasivam /*
3d211e62aSManivannan Sadhasivam  * Actions Semiconductor Owl SoC's I2C driver
4d211e62aSManivannan Sadhasivam  *
5d211e62aSManivannan Sadhasivam  * Copyright (c) 2014 Actions Semi Inc.
6d211e62aSManivannan Sadhasivam  * Author: David Liu <liuwei@actions-semi.com>
7d211e62aSManivannan Sadhasivam  *
8d211e62aSManivannan Sadhasivam  * Copyright (c) 2018 Linaro Ltd.
9d211e62aSManivannan Sadhasivam  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
10d211e62aSManivannan Sadhasivam  */
11d211e62aSManivannan Sadhasivam 
12d211e62aSManivannan Sadhasivam #include <linux/clk.h>
13d211e62aSManivannan Sadhasivam #include <linux/delay.h>
14d211e62aSManivannan Sadhasivam #include <linux/i2c.h>
15d211e62aSManivannan Sadhasivam #include <linux/interrupt.h>
16d211e62aSManivannan Sadhasivam #include <linux/io.h>
17b8be24ecSCristian Ciocaltea #include <linux/iopoll.h>
18d211e62aSManivannan Sadhasivam #include <linux/module.h>
19d211e62aSManivannan Sadhasivam #include <linux/of_device.h>
20d211e62aSManivannan Sadhasivam 
21d211e62aSManivannan Sadhasivam /* I2C registers */
22d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CTL		0x0000
23d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CLKDIV	0x0004
24d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_STAT	0x0008
25d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_ADDR	0x000C
26d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_TXDAT	0x0010
27d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_RXDAT	0x0014
28d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CMD		0x0018
29d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_FIFOCTL	0x001C
30d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_FIFOSTAT	0x0020
31d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_DATCNT	0x0024
32d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_RCNT	0x0028
33d211e62aSManivannan Sadhasivam 
34d211e62aSManivannan Sadhasivam /* I2Cx_CTL Bit Mask */
35d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_RB		BIT(1)
36d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC(x)	(((x) & 0x3) << 2)
37d211e62aSManivannan Sadhasivam #define	OWL_I2C_CTL_GBCC_NONE	OWL_I2C_CTL_GBCC(0)
38d211e62aSManivannan Sadhasivam #define	OWL_I2C_CTL_GBCC_START	OWL_I2C_CTL_GBCC(1)
39d211e62aSManivannan Sadhasivam #define	OWL_I2C_CTL_GBCC_STOP	OWL_I2C_CTL_GBCC(2)
40d211e62aSManivannan Sadhasivam #define	OWL_I2C_CTL_GBCC_RSTART	OWL_I2C_CTL_GBCC(3)
41d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_IRQE	BIT(5)
42d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_EN		BIT(7)
43d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_AE		BIT(8)
44d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_SHSM	BIT(10)
45d211e62aSManivannan Sadhasivam 
46d211e62aSManivannan Sadhasivam #define OWL_I2C_DIV_FACTOR(x)	((x) & 0xff)
47d211e62aSManivannan Sadhasivam 
48d211e62aSManivannan Sadhasivam /* I2Cx_STAT Bit Mask */
49d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_RACK	BIT(0)
50d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_BEB	BIT(1)
51d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_IRQP	BIT(2)
52d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_LAB	BIT(3)
53d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_STPD	BIT(4)
54d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_STAD	BIT(5)
55d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_BBB	BIT(6)
56d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_TCB	BIT(7)
57d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_LBST	BIT(8)
58d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_SAMB	BIT(9)
59d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_SRGC	BIT(10)
60d211e62aSManivannan Sadhasivam 
61d211e62aSManivannan Sadhasivam /* I2Cx_CMD Bit Mask */
62d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SBE		BIT(0)
63d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_RBE		BIT(4)
64d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_DE		BIT(8)
65d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_NS		BIT(9)
66d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SE		BIT(10)
67d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_MSS		BIT(11)
68d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_WRS		BIT(12)
69d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SECL	BIT(15)
70d211e62aSManivannan Sadhasivam 
71d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_AS(x)	(((x) & 0x7) << 1)
72d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SAS(x)	(((x) & 0x7) << 5)
73d211e62aSManivannan Sadhasivam 
74d211e62aSManivannan Sadhasivam /* I2Cx_FIFOCTL Bit Mask */
75d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_NIB	BIT(0)
76d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_RFR	BIT(1)
77d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_TFR	BIT(2)
78d211e62aSManivannan Sadhasivam 
79d211e62aSManivannan Sadhasivam /* I2Cc_FIFOSTAT Bit Mask */
80b8be24ecSCristian Ciocaltea #define OWL_I2C_FIFOSTAT_CECB	BIT(0)
81d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RNB	BIT(1)
82d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RFE	BIT(2)
83d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_TFF	BIT(5)
84d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_TFD	GENMASK(23, 16)
85d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RFD	GENMASK(15, 8)
86d211e62aSManivannan Sadhasivam 
87d211e62aSManivannan Sadhasivam /* I2C bus timeout */
88b8be24ecSCristian Ciocaltea #define OWL_I2C_TIMEOUT_MS	(4 * 1000)
89b8be24ecSCristian Ciocaltea #define OWL_I2C_TIMEOUT		msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
90d211e62aSManivannan Sadhasivam 
91d211e62aSManivannan Sadhasivam #define OWL_I2C_MAX_RETRIES	50
92d211e62aSManivannan Sadhasivam 
93d211e62aSManivannan Sadhasivam struct owl_i2c_dev {
94d211e62aSManivannan Sadhasivam 	struct i2c_adapter	adap;
95d211e62aSManivannan Sadhasivam 	struct i2c_msg		*msg;
96d211e62aSManivannan Sadhasivam 	struct completion	msg_complete;
97d211e62aSManivannan Sadhasivam 	struct clk		*clk;
98d211e62aSManivannan Sadhasivam 	spinlock_t		lock;
99d211e62aSManivannan Sadhasivam 	void __iomem		*base;
100d211e62aSManivannan Sadhasivam 	unsigned long		clk_rate;
101d211e62aSManivannan Sadhasivam 	u32			bus_freq;
102d211e62aSManivannan Sadhasivam 	u32			msg_ptr;
103d211e62aSManivannan Sadhasivam 	int			err;
104d211e62aSManivannan Sadhasivam };
105d211e62aSManivannan Sadhasivam 
106d211e62aSManivannan Sadhasivam static void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state)
107d211e62aSManivannan Sadhasivam {
108d211e62aSManivannan Sadhasivam 	unsigned int regval;
109d211e62aSManivannan Sadhasivam 
110d211e62aSManivannan Sadhasivam 	regval = readl(reg);
111d211e62aSManivannan Sadhasivam 
112d211e62aSManivannan Sadhasivam 	if (state)
113d211e62aSManivannan Sadhasivam 		regval |= val;
114d211e62aSManivannan Sadhasivam 	else
115d211e62aSManivannan Sadhasivam 		regval &= ~val;
116d211e62aSManivannan Sadhasivam 
117d211e62aSManivannan Sadhasivam 	writel(regval, reg);
118d211e62aSManivannan Sadhasivam }
119d211e62aSManivannan Sadhasivam 
120d211e62aSManivannan Sadhasivam static void owl_i2c_reset(struct owl_i2c_dev *i2c_dev)
121d211e62aSManivannan Sadhasivam {
122d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
123d211e62aSManivannan Sadhasivam 			   OWL_I2C_CTL_EN, false);
124d211e62aSManivannan Sadhasivam 	mdelay(1);
125d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
126d211e62aSManivannan Sadhasivam 			   OWL_I2C_CTL_EN, true);
127d211e62aSManivannan Sadhasivam 
128d211e62aSManivannan Sadhasivam 	/* Clear status registers */
129d211e62aSManivannan Sadhasivam 	writel(0, i2c_dev->base + OWL_I2C_REG_STAT);
130d211e62aSManivannan Sadhasivam }
131d211e62aSManivannan Sadhasivam 
132d211e62aSManivannan Sadhasivam static int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev)
133d211e62aSManivannan Sadhasivam {
134d211e62aSManivannan Sadhasivam 	unsigned int val, timeout = 0;
135d211e62aSManivannan Sadhasivam 
136d211e62aSManivannan Sadhasivam 	/* Reset FIFO */
137d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
138d211e62aSManivannan Sadhasivam 			   OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR,
139d211e62aSManivannan Sadhasivam 			   true);
140d211e62aSManivannan Sadhasivam 
141d211e62aSManivannan Sadhasivam 	/* Wait 50ms for FIFO reset complete */
142d211e62aSManivannan Sadhasivam 	do {
143d211e62aSManivannan Sadhasivam 		val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL);
144d211e62aSManivannan Sadhasivam 		if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR)))
145d211e62aSManivannan Sadhasivam 			break;
146d211e62aSManivannan Sadhasivam 		usleep_range(500, 1000);
147d211e62aSManivannan Sadhasivam 	} while (timeout++ < OWL_I2C_MAX_RETRIES);
148d211e62aSManivannan Sadhasivam 
149d211e62aSManivannan Sadhasivam 	if (timeout > OWL_I2C_MAX_RETRIES) {
150d211e62aSManivannan Sadhasivam 		dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n");
151d211e62aSManivannan Sadhasivam 		return -ETIMEDOUT;
152d211e62aSManivannan Sadhasivam 	}
153d211e62aSManivannan Sadhasivam 
154d211e62aSManivannan Sadhasivam 	return 0;
155d211e62aSManivannan Sadhasivam }
156d211e62aSManivannan Sadhasivam 
157d211e62aSManivannan Sadhasivam static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
158d211e62aSManivannan Sadhasivam {
159d211e62aSManivannan Sadhasivam 	unsigned int val;
160d211e62aSManivannan Sadhasivam 
161d211e62aSManivannan Sadhasivam 	val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16);
162d211e62aSManivannan Sadhasivam 
163d211e62aSManivannan Sadhasivam 	/* Set clock divider factor */
164d211e62aSManivannan Sadhasivam 	writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
165d211e62aSManivannan Sadhasivam }
166d211e62aSManivannan Sadhasivam 
167b8be24ecSCristian Ciocaltea static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
168d211e62aSManivannan Sadhasivam {
169d211e62aSManivannan Sadhasivam 	struct i2c_msg *msg = i2c_dev->msg;
170d211e62aSManivannan Sadhasivam 	unsigned int stat, fifostat;
171d211e62aSManivannan Sadhasivam 
172d211e62aSManivannan Sadhasivam 	i2c_dev->err = 0;
173d211e62aSManivannan Sadhasivam 
174d211e62aSManivannan Sadhasivam 	/* Handle NACK from slave */
175d211e62aSManivannan Sadhasivam 	fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
176d211e62aSManivannan Sadhasivam 	if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
177d211e62aSManivannan Sadhasivam 		i2c_dev->err = -ENXIO;
178f5b3f433SCristian Ciocaltea 		/* Clear NACK error bit by writing "1" */
179f5b3f433SCristian Ciocaltea 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
180f5b3f433SCristian Ciocaltea 				   OWL_I2C_FIFOSTAT_RNB, true);
181b8be24ecSCristian Ciocaltea 		return;
182d211e62aSManivannan Sadhasivam 	}
183d211e62aSManivannan Sadhasivam 
184d211e62aSManivannan Sadhasivam 	/* Handle bus error */
185d211e62aSManivannan Sadhasivam 	stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
186d211e62aSManivannan Sadhasivam 	if (stat & OWL_I2C_STAT_BEB) {
187d211e62aSManivannan Sadhasivam 		i2c_dev->err = -EIO;
188f5b3f433SCristian Ciocaltea 		/* Clear BUS error bit by writing "1" */
189f5b3f433SCristian Ciocaltea 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
190f5b3f433SCristian Ciocaltea 				   OWL_I2C_STAT_BEB, true);
191b8be24ecSCristian Ciocaltea 		return;
192d211e62aSManivannan Sadhasivam 	}
193d211e62aSManivannan Sadhasivam 
194d211e62aSManivannan Sadhasivam 	/* Handle FIFO read */
195d211e62aSManivannan Sadhasivam 	if (msg->flags & I2C_M_RD) {
196d211e62aSManivannan Sadhasivam 		while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
197d211e62aSManivannan Sadhasivam 			OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) {
198d211e62aSManivannan Sadhasivam 			msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base +
199d211e62aSManivannan Sadhasivam 							     OWL_I2C_REG_RXDAT);
200d211e62aSManivannan Sadhasivam 		}
201d211e62aSManivannan Sadhasivam 	} else {
202d211e62aSManivannan Sadhasivam 		/* Handle the remaining bytes which were not sent */
203d211e62aSManivannan Sadhasivam 		while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
204d211e62aSManivannan Sadhasivam 			 OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) {
205d211e62aSManivannan Sadhasivam 			writel(msg->buf[i2c_dev->msg_ptr++],
206d211e62aSManivannan Sadhasivam 			       i2c_dev->base + OWL_I2C_REG_TXDAT);
207d211e62aSManivannan Sadhasivam 		}
208d211e62aSManivannan Sadhasivam 	}
209b8be24ecSCristian Ciocaltea }
210d211e62aSManivannan Sadhasivam 
211b8be24ecSCristian Ciocaltea static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
212b8be24ecSCristian Ciocaltea {
213b8be24ecSCristian Ciocaltea 	struct owl_i2c_dev *i2c_dev = _dev;
214b8be24ecSCristian Ciocaltea 
215b8be24ecSCristian Ciocaltea 	spin_lock(&i2c_dev->lock);
216b8be24ecSCristian Ciocaltea 
217b8be24ecSCristian Ciocaltea 	owl_i2c_xfer_data(i2c_dev);
218b8be24ecSCristian Ciocaltea 
219d211e62aSManivannan Sadhasivam 	/* Clear pending interrupts */
220d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
221d211e62aSManivannan Sadhasivam 			   OWL_I2C_STAT_IRQP, true);
222d211e62aSManivannan Sadhasivam 
223d211e62aSManivannan Sadhasivam 	complete_all(&i2c_dev->msg_complete);
22406856269SBarry Song 	spin_unlock(&i2c_dev->lock);
225d211e62aSManivannan Sadhasivam 
226d211e62aSManivannan Sadhasivam 	return IRQ_HANDLED;
227d211e62aSManivannan Sadhasivam }
228d211e62aSManivannan Sadhasivam 
229d211e62aSManivannan Sadhasivam static u32 owl_i2c_func(struct i2c_adapter *adap)
230d211e62aSManivannan Sadhasivam {
231d211e62aSManivannan Sadhasivam 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
232d211e62aSManivannan Sadhasivam }
233d211e62aSManivannan Sadhasivam 
234d211e62aSManivannan Sadhasivam static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
235d211e62aSManivannan Sadhasivam {
236d211e62aSManivannan Sadhasivam 	struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
237d211e62aSManivannan Sadhasivam 	unsigned long timeout;
238d211e62aSManivannan Sadhasivam 
239d211e62aSManivannan Sadhasivam 	/* Check for Bus busy */
240d211e62aSManivannan Sadhasivam 	timeout = jiffies + OWL_I2C_TIMEOUT;
241d211e62aSManivannan Sadhasivam 	while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) {
242d211e62aSManivannan Sadhasivam 		if (time_after(jiffies, timeout)) {
243d211e62aSManivannan Sadhasivam 			dev_err(&adap->dev, "Bus busy timeout\n");
244d211e62aSManivannan Sadhasivam 			return -ETIMEDOUT;
245d211e62aSManivannan Sadhasivam 		}
246d211e62aSManivannan Sadhasivam 	}
247d211e62aSManivannan Sadhasivam 
248d211e62aSManivannan Sadhasivam 	return 0;
249d211e62aSManivannan Sadhasivam }
250d211e62aSManivannan Sadhasivam 
251b8be24ecSCristian Ciocaltea static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
252b8be24ecSCristian Ciocaltea 			       int num, bool atomic)
253d211e62aSManivannan Sadhasivam {
254d211e62aSManivannan Sadhasivam 	struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
255d211e62aSManivannan Sadhasivam 	struct i2c_msg *msg;
256d211e62aSManivannan Sadhasivam 	unsigned long time_left, flags;
257d211e62aSManivannan Sadhasivam 	unsigned int i2c_cmd, val;
258d211e62aSManivannan Sadhasivam 	unsigned int addr;
259d211e62aSManivannan Sadhasivam 	int ret, idx;
260d211e62aSManivannan Sadhasivam 
261d211e62aSManivannan Sadhasivam 	spin_lock_irqsave(&i2c_dev->lock, flags);
262d211e62aSManivannan Sadhasivam 
263d211e62aSManivannan Sadhasivam 	/* Reset I2C controller */
264d211e62aSManivannan Sadhasivam 	owl_i2c_reset(i2c_dev);
265d211e62aSManivannan Sadhasivam 
266d211e62aSManivannan Sadhasivam 	/* Set bus frequency */
267d211e62aSManivannan Sadhasivam 	owl_i2c_set_freq(i2c_dev);
268d211e62aSManivannan Sadhasivam 
269d211e62aSManivannan Sadhasivam 	/*
270d211e62aSManivannan Sadhasivam 	 * Spinlock should be released before calling reset FIFO and
271d211e62aSManivannan Sadhasivam 	 * bus busy check since those functions may sleep
272d211e62aSManivannan Sadhasivam 	 */
273d211e62aSManivannan Sadhasivam 	spin_unlock_irqrestore(&i2c_dev->lock, flags);
274d211e62aSManivannan Sadhasivam 
275d211e62aSManivannan Sadhasivam 	/* Reset FIFO */
276d211e62aSManivannan Sadhasivam 	ret = owl_i2c_reset_fifo(i2c_dev);
277d211e62aSManivannan Sadhasivam 	if (ret)
278d211e62aSManivannan Sadhasivam 		goto unlocked_err_exit;
279d211e62aSManivannan Sadhasivam 
280d211e62aSManivannan Sadhasivam 	/* Check for bus busy */
281d211e62aSManivannan Sadhasivam 	ret = owl_i2c_check_bus_busy(adap);
282d211e62aSManivannan Sadhasivam 	if (ret)
283d211e62aSManivannan Sadhasivam 		goto unlocked_err_exit;
284d211e62aSManivannan Sadhasivam 
285d211e62aSManivannan Sadhasivam 	spin_lock_irqsave(&i2c_dev->lock, flags);
286d211e62aSManivannan Sadhasivam 
287d211e62aSManivannan Sadhasivam 	/* Check for Arbitration lost */
288d211e62aSManivannan Sadhasivam 	val = readl(i2c_dev->base + OWL_I2C_REG_STAT);
289d211e62aSManivannan Sadhasivam 	if (val & OWL_I2C_STAT_LAB) {
290d211e62aSManivannan Sadhasivam 		val &= ~OWL_I2C_STAT_LAB;
291d211e62aSManivannan Sadhasivam 		writel(val, i2c_dev->base + OWL_I2C_REG_STAT);
292d211e62aSManivannan Sadhasivam 		ret = -EAGAIN;
293d211e62aSManivannan Sadhasivam 		goto err_exit;
294d211e62aSManivannan Sadhasivam 	}
295d211e62aSManivannan Sadhasivam 
296b8be24ecSCristian Ciocaltea 	if (!atomic)
297d211e62aSManivannan Sadhasivam 		reinit_completion(&i2c_dev->msg_complete);
298d211e62aSManivannan Sadhasivam 
299b8be24ecSCristian Ciocaltea 	/* Enable/disable I2C controller interrupt */
300d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
301b8be24ecSCristian Ciocaltea 			   OWL_I2C_CTL_IRQE, !atomic);
302d211e62aSManivannan Sadhasivam 
303d211e62aSManivannan Sadhasivam 	/*
304d211e62aSManivannan Sadhasivam 	 * Select: FIFO enable, Master mode, Stop enable, Data count enable,
305d211e62aSManivannan Sadhasivam 	 * Send start bit
306d211e62aSManivannan Sadhasivam 	 */
307d211e62aSManivannan Sadhasivam 	i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE |
308d211e62aSManivannan Sadhasivam 		  OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE;
309d211e62aSManivannan Sadhasivam 
310d211e62aSManivannan Sadhasivam 	/* Handle repeated start condition */
311d211e62aSManivannan Sadhasivam 	if (num > 1) {
312d211e62aSManivannan Sadhasivam 		/* Set internal address length and enable repeated start */
313d211e62aSManivannan Sadhasivam 		i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) |
314d211e62aSManivannan Sadhasivam 			   OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE;
315d211e62aSManivannan Sadhasivam 
316d211e62aSManivannan Sadhasivam 		/* Write slave address */
317d211e62aSManivannan Sadhasivam 		addr = i2c_8bit_addr_from_msg(&msgs[0]);
318d211e62aSManivannan Sadhasivam 		writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);
319d211e62aSManivannan Sadhasivam 
320d211e62aSManivannan Sadhasivam 		/* Write internal register address */
321d211e62aSManivannan Sadhasivam 		for (idx = 0; idx < msgs[0].len; idx++)
322d211e62aSManivannan Sadhasivam 			writel(msgs[0].buf[idx],
323d211e62aSManivannan Sadhasivam 			       i2c_dev->base + OWL_I2C_REG_TXDAT);
324d211e62aSManivannan Sadhasivam 
325d211e62aSManivannan Sadhasivam 		msg = &msgs[1];
326d211e62aSManivannan Sadhasivam 	} else {
327d211e62aSManivannan Sadhasivam 		/* Set address length */
328d211e62aSManivannan Sadhasivam 		i2c_cmd |= OWL_I2C_CMD_AS(1);
329d211e62aSManivannan Sadhasivam 		msg = &msgs[0];
330d211e62aSManivannan Sadhasivam 	}
331d211e62aSManivannan Sadhasivam 
332d211e62aSManivannan Sadhasivam 	i2c_dev->msg = msg;
333d211e62aSManivannan Sadhasivam 	i2c_dev->msg_ptr = 0;
334d211e62aSManivannan Sadhasivam 
335d211e62aSManivannan Sadhasivam 	/* Set data count for the message */
336d211e62aSManivannan Sadhasivam 	writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT);
337d211e62aSManivannan Sadhasivam 
338d211e62aSManivannan Sadhasivam 	addr = i2c_8bit_addr_from_msg(msg);
339d211e62aSManivannan Sadhasivam 	writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);
340d211e62aSManivannan Sadhasivam 
341d211e62aSManivannan Sadhasivam 	if (!(msg->flags & I2C_M_RD)) {
342d211e62aSManivannan Sadhasivam 		/* Write data to FIFO */
343d211e62aSManivannan Sadhasivam 		for (idx = 0; idx < msg->len; idx++) {
344d211e62aSManivannan Sadhasivam 			/* Check for FIFO full */
345d211e62aSManivannan Sadhasivam 			if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
346d211e62aSManivannan Sadhasivam 			    OWL_I2C_FIFOSTAT_TFF)
347d211e62aSManivannan Sadhasivam 				break;
348d211e62aSManivannan Sadhasivam 
349d211e62aSManivannan Sadhasivam 			writel(msg->buf[idx],
350d211e62aSManivannan Sadhasivam 			       i2c_dev->base + OWL_I2C_REG_TXDAT);
351d211e62aSManivannan Sadhasivam 		}
352d211e62aSManivannan Sadhasivam 
353d211e62aSManivannan Sadhasivam 		i2c_dev->msg_ptr = idx;
354d211e62aSManivannan Sadhasivam 	}
355d211e62aSManivannan Sadhasivam 
356d211e62aSManivannan Sadhasivam 	/* Ignore the NACK if needed */
357d211e62aSManivannan Sadhasivam 	if (msg->flags & I2C_M_IGNORE_NAK)
358d211e62aSManivannan Sadhasivam 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
359d211e62aSManivannan Sadhasivam 				   OWL_I2C_FIFOCTL_NIB, true);
360d211e62aSManivannan Sadhasivam 	else
361d211e62aSManivannan Sadhasivam 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
362d211e62aSManivannan Sadhasivam 				   OWL_I2C_FIFOCTL_NIB, false);
363d211e62aSManivannan Sadhasivam 
364d211e62aSManivannan Sadhasivam 	/* Start the transfer */
365d211e62aSManivannan Sadhasivam 	writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD);
366d211e62aSManivannan Sadhasivam 
367d211e62aSManivannan Sadhasivam 	spin_unlock_irqrestore(&i2c_dev->lock, flags);
368d211e62aSManivannan Sadhasivam 
369b8be24ecSCristian Ciocaltea 	if (atomic) {
370b8be24ecSCristian Ciocaltea 		/* Wait for Command Execute Completed or NACK Error bits */
371b8be24ecSCristian Ciocaltea 		ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
372b8be24ecSCristian Ciocaltea 						val, val & (OWL_I2C_FIFOSTAT_CECB |
373b8be24ecSCristian Ciocaltea 							    OWL_I2C_FIFOSTAT_RNB),
374b8be24ecSCristian Ciocaltea 						10, OWL_I2C_TIMEOUT_MS * 1000);
375b8be24ecSCristian Ciocaltea 	} else {
376d211e62aSManivannan Sadhasivam 		time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
377d211e62aSManivannan Sadhasivam 							adap->timeout);
378b8be24ecSCristian Ciocaltea 		if (!time_left)
379b8be24ecSCristian Ciocaltea 			ret = -ETIMEDOUT;
380b8be24ecSCristian Ciocaltea 	}
381d211e62aSManivannan Sadhasivam 
382d211e62aSManivannan Sadhasivam 	spin_lock_irqsave(&i2c_dev->lock, flags);
383b8be24ecSCristian Ciocaltea 
384b8be24ecSCristian Ciocaltea 	if (ret) {
385d211e62aSManivannan Sadhasivam 		dev_err(&adap->dev, "Transaction timed out\n");
386d211e62aSManivannan Sadhasivam 		/* Send stop condition and release the bus */
387d211e62aSManivannan Sadhasivam 		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
388d211e62aSManivannan Sadhasivam 				   OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
389d211e62aSManivannan Sadhasivam 				   true);
390d211e62aSManivannan Sadhasivam 		goto err_exit;
391d211e62aSManivannan Sadhasivam 	}
392d211e62aSManivannan Sadhasivam 
393b8be24ecSCristian Ciocaltea 	if (atomic)
394b8be24ecSCristian Ciocaltea 		owl_i2c_xfer_data(i2c_dev);
395b8be24ecSCristian Ciocaltea 
396d211e62aSManivannan Sadhasivam 	ret = i2c_dev->err < 0 ? i2c_dev->err : num;
397d211e62aSManivannan Sadhasivam 
398d211e62aSManivannan Sadhasivam err_exit:
399d211e62aSManivannan Sadhasivam 	spin_unlock_irqrestore(&i2c_dev->lock, flags);
400d211e62aSManivannan Sadhasivam 
401d211e62aSManivannan Sadhasivam unlocked_err_exit:
402d211e62aSManivannan Sadhasivam 	/* Disable I2C controller */
403d211e62aSManivannan Sadhasivam 	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
404d211e62aSManivannan Sadhasivam 			   OWL_I2C_CTL_EN, false);
405d211e62aSManivannan Sadhasivam 
406d211e62aSManivannan Sadhasivam 	return ret;
407d211e62aSManivannan Sadhasivam }
408d211e62aSManivannan Sadhasivam 
409b8be24ecSCristian Ciocaltea static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
410b8be24ecSCristian Ciocaltea 			int num)
411b8be24ecSCristian Ciocaltea {
412b8be24ecSCristian Ciocaltea 	return owl_i2c_xfer_common(adap, msgs, num, false);
413b8be24ecSCristian Ciocaltea }
414b8be24ecSCristian Ciocaltea 
415b8be24ecSCristian Ciocaltea static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
416b8be24ecSCristian Ciocaltea 			       struct i2c_msg *msgs, int num)
417b8be24ecSCristian Ciocaltea {
418b8be24ecSCristian Ciocaltea 	return owl_i2c_xfer_common(adap, msgs, num, true);
419b8be24ecSCristian Ciocaltea }
420b8be24ecSCristian Ciocaltea 
421d211e62aSManivannan Sadhasivam static const struct i2c_algorithm owl_i2c_algorithm = {
422b8be24ecSCristian Ciocaltea 	.master_xfer	     = owl_i2c_xfer,
423b8be24ecSCristian Ciocaltea 	.master_xfer_atomic  = owl_i2c_xfer_atomic,
424d211e62aSManivannan Sadhasivam 	.functionality	     = owl_i2c_func,
425d211e62aSManivannan Sadhasivam };
426d211e62aSManivannan Sadhasivam 
427d211e62aSManivannan Sadhasivam static const struct i2c_adapter_quirks owl_i2c_quirks = {
428d211e62aSManivannan Sadhasivam 	.flags		= I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST,
429d211e62aSManivannan Sadhasivam 	.max_read_len   = 240,
430d211e62aSManivannan Sadhasivam 	.max_write_len  = 240,
431d211e62aSManivannan Sadhasivam 	.max_comb_1st_msg_len = 6,
432d211e62aSManivannan Sadhasivam 	.max_comb_2nd_msg_len = 240,
433d211e62aSManivannan Sadhasivam };
434d211e62aSManivannan Sadhasivam 
435d211e62aSManivannan Sadhasivam static int owl_i2c_probe(struct platform_device *pdev)
436d211e62aSManivannan Sadhasivam {
437d211e62aSManivannan Sadhasivam 	struct device *dev = &pdev->dev;
438d211e62aSManivannan Sadhasivam 	struct owl_i2c_dev *i2c_dev;
439d211e62aSManivannan Sadhasivam 	int ret, irq;
440d211e62aSManivannan Sadhasivam 
441d211e62aSManivannan Sadhasivam 	i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL);
442d211e62aSManivannan Sadhasivam 	if (!i2c_dev)
443d211e62aSManivannan Sadhasivam 		return -ENOMEM;
444d211e62aSManivannan Sadhasivam 
445e0442d76SDejin Zheng 	i2c_dev->base = devm_platform_ioremap_resource(pdev, 0);
446d211e62aSManivannan Sadhasivam 	if (IS_ERR(i2c_dev->base))
447d211e62aSManivannan Sadhasivam 		return PTR_ERR(i2c_dev->base);
448d211e62aSManivannan Sadhasivam 
449d211e62aSManivannan Sadhasivam 	irq = platform_get_irq(pdev, 0);
450e42688edSDejin Zheng 	if (irq < 0)
451d211e62aSManivannan Sadhasivam 		return irq;
452d211e62aSManivannan Sadhasivam 
453d211e62aSManivannan Sadhasivam 	if (of_property_read_u32(dev->of_node, "clock-frequency",
454d211e62aSManivannan Sadhasivam 				 &i2c_dev->bus_freq))
45590224e64SAndy Shevchenko 		i2c_dev->bus_freq = I2C_MAX_STANDARD_MODE_FREQ;
456d211e62aSManivannan Sadhasivam 
457d211e62aSManivannan Sadhasivam 	/* We support only frequencies of 100k and 400k for now */
45890224e64SAndy Shevchenko 	if (i2c_dev->bus_freq != I2C_MAX_STANDARD_MODE_FREQ &&
45990224e64SAndy Shevchenko 	    i2c_dev->bus_freq != I2C_MAX_FAST_MODE_FREQ) {
460d211e62aSManivannan Sadhasivam 		dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq);
461d211e62aSManivannan Sadhasivam 		return -EINVAL;
462d211e62aSManivannan Sadhasivam 	}
463d211e62aSManivannan Sadhasivam 
464d211e62aSManivannan Sadhasivam 	i2c_dev->clk = devm_clk_get(dev, NULL);
465d211e62aSManivannan Sadhasivam 	if (IS_ERR(i2c_dev->clk)) {
466d211e62aSManivannan Sadhasivam 		dev_err(dev, "failed to get clock\n");
467d211e62aSManivannan Sadhasivam 		return PTR_ERR(i2c_dev->clk);
468d211e62aSManivannan Sadhasivam 	}
469d211e62aSManivannan Sadhasivam 
470d211e62aSManivannan Sadhasivam 	ret = clk_prepare_enable(i2c_dev->clk);
471d211e62aSManivannan Sadhasivam 	if (ret)
472d211e62aSManivannan Sadhasivam 		return ret;
473d211e62aSManivannan Sadhasivam 
474d211e62aSManivannan Sadhasivam 	i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk);
475d211e62aSManivannan Sadhasivam 	if (!i2c_dev->clk_rate) {
476d211e62aSManivannan Sadhasivam 		dev_err(dev, "input clock rate should not be zero\n");
477d211e62aSManivannan Sadhasivam 		ret = -EINVAL;
478d211e62aSManivannan Sadhasivam 		goto disable_clk;
479d211e62aSManivannan Sadhasivam 	}
480d211e62aSManivannan Sadhasivam 
481d211e62aSManivannan Sadhasivam 	init_completion(&i2c_dev->msg_complete);
482d211e62aSManivannan Sadhasivam 	spin_lock_init(&i2c_dev->lock);
483d211e62aSManivannan Sadhasivam 	i2c_dev->adap.owner = THIS_MODULE;
484d211e62aSManivannan Sadhasivam 	i2c_dev->adap.algo = &owl_i2c_algorithm;
485d211e62aSManivannan Sadhasivam 	i2c_dev->adap.timeout = OWL_I2C_TIMEOUT;
486d211e62aSManivannan Sadhasivam 	i2c_dev->adap.quirks = &owl_i2c_quirks;
487d211e62aSManivannan Sadhasivam 	i2c_dev->adap.dev.parent = dev;
488d211e62aSManivannan Sadhasivam 	i2c_dev->adap.dev.of_node = dev->of_node;
489d211e62aSManivannan Sadhasivam 	snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
490d211e62aSManivannan Sadhasivam 		 "%s", "OWL I2C adapter");
491d211e62aSManivannan Sadhasivam 	i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
492d211e62aSManivannan Sadhasivam 
493d211e62aSManivannan Sadhasivam 	platform_set_drvdata(pdev, i2c_dev);
494d211e62aSManivannan Sadhasivam 
495d211e62aSManivannan Sadhasivam 	ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name,
496d211e62aSManivannan Sadhasivam 			       i2c_dev);
497d211e62aSManivannan Sadhasivam 	if (ret) {
498d211e62aSManivannan Sadhasivam 		dev_err(dev, "failed to request irq %d\n", irq);
499d211e62aSManivannan Sadhasivam 		goto disable_clk;
500d211e62aSManivannan Sadhasivam 	}
501d211e62aSManivannan Sadhasivam 
502d211e62aSManivannan Sadhasivam 	return i2c_add_adapter(&i2c_dev->adap);
503d211e62aSManivannan Sadhasivam 
504d211e62aSManivannan Sadhasivam disable_clk:
505d211e62aSManivannan Sadhasivam 	clk_disable_unprepare(i2c_dev->clk);
506d211e62aSManivannan Sadhasivam 
507d211e62aSManivannan Sadhasivam 	return ret;
508d211e62aSManivannan Sadhasivam }
509d211e62aSManivannan Sadhasivam 
510d211e62aSManivannan Sadhasivam static const struct of_device_id owl_i2c_of_match[] = {
51104fd6f0aSCristian Ciocaltea 	{ .compatible = "actions,s500-i2c" },
51281482d13SParthiban Nallathambi 	{ .compatible = "actions,s700-i2c" },
513d211e62aSManivannan Sadhasivam 	{ .compatible = "actions,s900-i2c" },
514d211e62aSManivannan Sadhasivam 	{ /* sentinel */ }
515d211e62aSManivannan Sadhasivam };
516d211e62aSManivannan Sadhasivam MODULE_DEVICE_TABLE(of, owl_i2c_of_match);
517d211e62aSManivannan Sadhasivam 
518d211e62aSManivannan Sadhasivam static struct platform_driver owl_i2c_driver = {
519d211e62aSManivannan Sadhasivam 	.probe		= owl_i2c_probe,
520d211e62aSManivannan Sadhasivam 	.driver		= {
521d211e62aSManivannan Sadhasivam 		.name	= "owl-i2c",
522*8759500cSKrzysztof Kozlowski 		.of_match_table = owl_i2c_of_match,
52346f8bfebSCristian Ciocaltea 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
524d211e62aSManivannan Sadhasivam 	},
525d211e62aSManivannan Sadhasivam };
526d211e62aSManivannan Sadhasivam module_platform_driver(owl_i2c_driver);
527d211e62aSManivannan Sadhasivam 
528d211e62aSManivannan Sadhasivam MODULE_AUTHOR("David Liu <liuwei@actions-semi.com>");
529d211e62aSManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
530d211e62aSManivannan Sadhasivam MODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver");
531d211e62aSManivannan Sadhasivam MODULE_LICENSE("GPL");
532