1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2020
4 * Arthur Li, Cortina Access, arthur.li@cortina-access.com.
5 */
6
7#include <common.h>
8#include <i2c.h>
9#include <log.h>
10#include <asm/io.h>
11#include <dm.h>
12#include <mapmem.h>
13#include "i2c-cortina.h"
14
15static void set_speed(struct i2c_regs *regs, int i2c_spd)
16{
17	union ca_biw_cfg i2c_cfg;
18
19	i2c_cfg.wrd = readl(&regs->i2c_cfg);
20	i2c_cfg.bf.core_en = 0;
21	writel(i2c_cfg.wrd, &regs->i2c_cfg);
22
23	switch (i2c_spd) {
24	case IC_SPEED_MODE_FAST_PLUS:
25		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
26				  (5 * I2C_SPEED_FAST_PLUS_RATE) - 1;
27		break;
28
29	case IC_SPEED_MODE_STANDARD:
30		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
31				  (5 * I2C_SPEED_STANDARD_RATE) - 1;
32		break;
33
34	case IC_SPEED_MODE_FAST:
35	default:
36		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
37				  (5 * I2C_SPEED_FAST_RATE) - 1;
38		break;
39	}
40
41	i2c_cfg.bf.core_en = 1;
42	writel(i2c_cfg.wrd, &regs->i2c_cfg);
43}
44
45static int ca_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
46{
47	struct ca_i2c *priv = dev_get_priv(bus);
48	int i2c_spd;
49
50	if (speed >= I2C_SPEED_FAST_PLUS_RATE) {
51		i2c_spd = IC_SPEED_MODE_FAST_PLUS;
52		priv->speed = I2C_SPEED_FAST_PLUS_RATE;
53	} else if (speed >= I2C_SPEED_FAST_RATE) {
54		i2c_spd = IC_SPEED_MODE_FAST;
55		priv->speed = I2C_SPEED_FAST_RATE;
56	} else {
57		i2c_spd = IC_SPEED_MODE_STANDARD;
58		priv->speed = I2C_SPEED_STANDARD_RATE;
59	}
60
61	set_speed(priv->regs, i2c_spd);
62
63	return 0;
64}
65
66static int ca_i2c_get_bus_speed(struct udevice *bus)
67{
68	struct ca_i2c *priv = dev_get_priv(bus);
69
70	return priv->speed;
71}
72
73static void ca_i2c_init(struct i2c_regs *regs)
74{
75	union ca_biw_cfg i2c_cfg;
76
77	i2c_cfg.wrd = readl(&regs->i2c_cfg);
78	i2c_cfg.bf.core_en = 0;
79	i2c_cfg.bf.biw_soft_reset = 1;
80	writel(i2c_cfg.wrd, &regs->i2c_cfg);
81	mdelay(10);
82	i2c_cfg.bf.biw_soft_reset = 0;
83	writel(i2c_cfg.wrd, &regs->i2c_cfg);
84
85	set_speed(regs, IC_SPEED_MODE_STANDARD);
86
87	i2c_cfg.wrd = readl(&regs->i2c_cfg);
88	i2c_cfg.bf.core_en = 1;
89	writel(i2c_cfg.wrd, &regs->i2c_cfg);
90}
91
92static int i2c_wait_complete(struct i2c_regs *regs)
93{
94	union ca_biw_ctrl i2c_ctrl;
95	unsigned long start_time_bb = get_timer(0);
96
97	i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
98
99	while (i2c_ctrl.bf.biwdone == 0) {
100		i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
101
102		if (get_timer(start_time_bb) >
103		   (unsigned long)(I2C_BYTE_TO_BB)) {
104			printf("%s not done!!!\n", __func__);
105			return -ETIMEDOUT;
106		}
107	}
108
109	/* Clear done bit */
110	writel(i2c_ctrl.wrd, &regs->i2c_ctrl);
111
112	return 0;
113}
114
115static void i2c_setaddress(struct i2c_regs *regs, unsigned int i2c_addr,
116			   int write_read)
117{
118	writel(i2c_addr | write_read, &regs->i2c_txr);
119
120	writel(BIW_CTRL_START | BIW_CTRL_WRITE,
121	       &regs->i2c_ctrl);
122
123	i2c_wait_complete(regs);
124}
125
126static int i2c_wait_for_bus_busy(struct i2c_regs *regs)
127{
128	union ca_biw_ack i2c_ack;
129	unsigned long start_time_bb = get_timer(0);
130
131	i2c_ack.wrd = readl(&regs->i2c_ack);
132
133	while (i2c_ack.bf.biw_busy) {
134		i2c_ack.wrd = readl(&regs->i2c_ack);
135
136		if (get_timer(start_time_bb) >
137		   (unsigned long)(I2C_BYTE_TO_BB)) {
138			printf("%s: timeout!\n", __func__);
139			return -ETIMEDOUT;
140		}
141	}
142
143	return 0;
144}
145
146static int i2c_xfer_init(struct i2c_regs *regs, uint8_t chip, uint addr,
147			 int alen, int write_read)
148{
149	int addr_len = alen;
150
151	if (i2c_wait_for_bus_busy(regs))
152		return 1;
153
154	/* First cycle must write addr + offset */
155	chip = ((chip & 0x7F) << 1);
156	if (alen == 0 && write_read == I2C_CMD_RD)
157		i2c_setaddress(regs, chip, I2C_CMD_RD);
158	else
159		i2c_setaddress(regs, chip, I2C_CMD_WT);
160
161	while (alen) {
162		alen--;
163		writel(addr, &regs->i2c_txr);
164		if (write_read == I2C_CMD_RD)
165			writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
166			       &regs->i2c_ctrl);
167		else
168			writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
169		i2c_wait_complete(regs);
170	}
171
172	/* Send address again with Read flag if it's read command */
173	if (write_read == I2C_CMD_RD && addr_len > 0)
174		i2c_setaddress(regs, chip, I2C_CMD_RD);
175
176	return 0;
177}
178
179static int i2c_xfer_finish(struct i2c_regs *regs)
180{
181	/* Dummy read makes bus free */
182	writel(BIW_CTRL_READ | BIW_CTRL_STOP, &regs->i2c_ctrl);
183	i2c_wait_complete(regs);
184
185	if (i2c_wait_for_bus_busy(regs)) {
186		printf("Timed out waiting for bus\n");
187		return -ETIMEDOUT;
188	}
189
190	return 0;
191}
192
193static int ca_i2c_read(struct i2c_regs *regs, uint8_t chip, uint addr,
194		       int alen, uint8_t *buffer, int len)
195{
196	unsigned long start_time_rx;
197	int rc = 0;
198
199	rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_RD);
200	if (rc)
201		return rc;
202
203	start_time_rx = get_timer(0);
204	while (len) {
205		/* ACK_IN is ack value to send during read.
206		 * ack high only on the very last byte!
207		 */
208		if (len == 1)
209			writel(BIW_CTRL_READ | BIW_CTRL_ACK_IN | BIW_CTRL_STOP,
210			       &regs->i2c_ctrl);
211		else
212			writel(BIW_CTRL_READ, &regs->i2c_ctrl);
213
214		rc = i2c_wait_complete(regs);
215		udelay(1);
216
217		if (rc == 0) {
218			*buffer++ =
219				(uchar) readl(&regs->i2c_rxr);
220			len--;
221			start_time_rx = get_timer(0);
222
223		} else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
224			return -ETIMEDOUT;
225		}
226	}
227	i2c_xfer_finish(regs);
228	return rc;
229}
230
231static int ca_i2c_write(struct i2c_regs *regs, uint8_t chip, uint addr,
232			int alen, uint8_t *buffer, int len)
233{
234	int rc, nb = len;
235	unsigned long start_time_tx;
236
237	rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_WT);
238	if (rc)
239		return rc;
240
241	start_time_tx = get_timer(0);
242	while (len) {
243		writel(*buffer, &regs->i2c_txr);
244		if (len == 1)
245			writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
246			       &regs->i2c_ctrl);
247		else
248			writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
249
250		rc = i2c_wait_complete(regs);
251
252		if (rc == 0) {
253			len--;
254			buffer++;
255			start_time_tx = get_timer(0);
256		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
257			return -ETIMEDOUT;
258		}
259	}
260
261	return 0;
262}
263
264static int ca_i2c_probe_chip(struct udevice *bus, uint chip_addr,
265			     uint chip_flags)
266{
267	struct ca_i2c *priv = dev_get_priv(bus);
268	int ret;
269	u32 tmp;
270
271	/* Try to read the first location of the chip */
272	ret = ca_i2c_read(priv->regs, chip_addr, 0, 1, (uchar *)&tmp, 1);
273	if (ret)
274		ca_i2c_init(priv->regs);
275
276	return ret;
277}
278
279static int ca_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
280{
281	struct ca_i2c *priv = dev_get_priv(bus);
282	int ret;
283
284	debug("i2c_xfer: %d messages\n", nmsgs);
285	for (; nmsgs > 0; nmsgs--, msg++) {
286		debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
287		if (msg->flags & I2C_M_RD)
288			ret = ca_i2c_read(priv->regs, msg->addr, 0, 0,
289					  msg->buf, msg->len);
290		else
291			ret = ca_i2c_write(priv->regs, msg->addr, 0, 0,
292					   msg->buf, msg->len);
293
294		if (ret) {
295			printf("i2c_xfer: %s error\n",
296			       msg->flags & I2C_M_RD ? "read" : "write");
297			return ret;
298		}
299	}
300
301	return 0;
302}
303
304static const struct dm_i2c_ops ca_i2c_ops = {
305	.xfer		= ca_i2c_xfer,
306	.probe_chip	= ca_i2c_probe_chip,
307	.set_bus_speed	= ca_i2c_set_bus_speed,
308	.get_bus_speed	= ca_i2c_get_bus_speed,
309};
310
311static const struct udevice_id ca_i2c_ids[] = {
312	{ .compatible = "cortina,ca-i2c", },
313	{ }
314};
315
316static int ca_i2c_probe(struct udevice *bus)
317{
318	struct ca_i2c *priv = dev_get_priv(bus);
319
320	ca_i2c_init(priv->regs);
321
322	return 0;
323}
324
325static int ca_i2c_of_to_plat(struct udevice *bus)
326{
327	struct ca_i2c *priv = dev_get_priv(bus);
328
329	priv->regs = map_sysmem(dev_read_addr(bus), sizeof(struct i2c_regs));
330	if (!priv->regs) {
331		printf("I2C: base address is invalid\n");
332		return -EINVAL;
333	}
334
335	return 0;
336}
337
338U_BOOT_DRIVER(i2c_cortina) = {
339	.name	= "i2c_cortina",
340	.id	= UCLASS_I2C,
341	.of_match = ca_i2c_ids,
342	.of_to_plat = ca_i2c_of_to_plat,
343	.probe	= ca_i2c_probe,
344	.priv_auto	= sizeof(struct ca_i2c),
345	.ops	= &ca_i2c_ops,
346	.flags  = DM_FLAG_PRE_RELOC,
347};
348