summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-designware.c
blob: 8508fac7171fb8c9a205a8cdc81a5503c98b28a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
/*
 * Synopsys DesignWare I2C adapter driver (master only).
 *
 * Partly based on code of similar driver from U-Boot:
 *    Copyright (C) 2009 ST Micoelectronics
 *
 * and corresponding code from Linux Kernel
 *    Copyright (C) 2006 Texas Instruments.
 *    Copyright (C) 2007 MontaVista Software Inc.
 *    Copyright (C) 2009 Provigent Ltd.
 *
 * Copyright (C) 2015 Andrey Smirnov <andrew.smirnov@gmail.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 */

#include <clock.h>
#include <common.h>
#include <driver.h>
#include <init.h>
#include <of.h>
#include <malloc.h>
#include <types.h>
#include <xfuncs.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/math64.h>

#include <io.h>
#include <i2c/i2c.h>

#define DW_I2C_BIT_RATE			100000

#define DW_IC_CON			0x0
#define DW_IC_CON_MASTER		(1 << 0)
#define DW_IC_CON_SPEED_STD		(1 << 1)
#define DW_IC_CON_SPEED_FAST		(1 << 2)
#define DW_IC_CON_SLAVE_DISABLE		(1 << 6)

#define DW_IC_TAR			0x4

#define DW_IC_DATA_CMD			0x10
#define DW_IC_DATA_CMD_CMD		(1 << 8)
#define DW_IC_DATA_CMD_STOP		(1 << 9)

#define DW_IC_SS_SCL_HCNT		0x14
#define DW_IC_SS_SCL_LCNT		0x18
#define DW_IC_FS_SCL_HCNT		0x1c
#define DW_IC_FS_SCL_LCNT		0x20

#define DW_IC_INTR_MASK			0x30

#define DW_IC_RAW_INTR_STAT		0x34
#define DW_IC_INTR_RX_UNDER		(1 << 0)
#define DW_IC_INTR_RX_OVER		(1 << 1)
#define DW_IC_INTR_RX_FULL		(1 << 2)
#define DW_IC_INTR_TX_OVER		(1 << 3)
#define DW_IC_INTR_TX_EMPTY		(1 << 4)
#define DW_IC_INTR_RD_REQ		(1 << 5)
#define DW_IC_INTR_TX_ABRT		(1 << 6)
#define DW_IC_INTR_RX_DONE		(1 << 7)
#define DW_IC_INTR_ACTIVITY		(1 << 8)
#define DW_IC_INTR_STOP_DET		(1 << 9)
#define DW_IC_INTR_START_DET		(1 << 10)
#define DW_IC_INTR_GEN_CALL		(1 << 11)

#define DW_IC_RX_TL			0x38
#define DW_IC_TX_TL			0x3c
#define DW_IC_CLR_INTR			0x40
#define DW_IC_CLR_TX_ABRT		0x54
#define DW_IC_SDA_HOLD			0x7c

#define DW_IC_ENABLE			0x6c
#define DW_IC_ENABLE_ENABLE		(1 << 0)

#define DW_IC_STATUS			0x70
#define DW_IC_STATUS_TFNF		(1 << 1)
#define DW_IC_STATUS_TFE		(1 << 2)
#define DW_IC_STATUS_RFNE		(1 << 3)
#define DW_IC_STATUS_MST_ACTIVITY	(1 << 5)

#define DW_IC_TX_ABRT_SOURCE		0x80

#define DW_IC_ENABLE_STATUS		0x9c
#define DW_IC_ENABLE_STATUS_IC_EN	(1 << 0)

#define DW_IC_COMP_VERSION		0xf8
#define DW_IC_SDA_HOLD_MIN_VERS		0x3131312A
#define DW_IC_COMP_TYPE			0xfc
#define DW_IC_COMP_TYPE_VALUE		0x44570140

#define MAX_T_POLL_COUNT		100

#define DW_TIMEOUT_IDLE			(40 * MSECOND)
#define DW_TIMEOUT_TX			(2 * MSECOND)
#define DW_TIMEOUT_RX			(2 * MSECOND)

#define DW_IC_SDA_HOLD_RX_SHIFT		16
#define DW_IC_SDA_HOLD_RX_MASK		GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)


struct dw_i2c_dev {
	void __iomem *base;
	struct clk *clk;
	struct i2c_adapter adapter;
	u32 sda_hold_time;
};

static inline struct dw_i2c_dev *to_dw_i2c_dev(struct i2c_adapter *a)
{
	return container_of(a, struct dw_i2c_dev, adapter);
}

static void i2c_dw_enable(struct dw_i2c_dev *dw, bool enable)
{
	u32 reg = 0;

	/*
	 * This subrotine is an implementation of an algorithm
	 * described in "Cyclone V Hard Processor System Technical
	 * Reference * Manual" p. 20-19, "Disabling the I2C Controller"
	 */
	int timeout = MAX_T_POLL_COUNT;

	if (enable)
		reg |= DW_IC_ENABLE_ENABLE;

	do {
		uint32_t ic_enable_status;

		writel(reg, dw->base + DW_IC_ENABLE);

		ic_enable_status = readl(dw->base + DW_IC_ENABLE_STATUS);
		if ((ic_enable_status & DW_IC_ENABLE_STATUS_IC_EN) == enable)
			return;

		udelay(250);
	} while (timeout--);

	dev_warn(&dw->adapter.dev, "timeout in %sabling adapter\n",
		 enable ? "en" : "dis");
}

/*
 * All of the code pertaining to tming calculation is taken from
 * analogous driver in Linux kernel
 */
static uint32_t
i2c_dw_scl_hcnt(uint32_t ic_clk, uint32_t tSYMBOL, uint32_t tf, int cond,
		int offset)
{
	/*
	 * DesignWare I2C core doesn't seem to have solid strategy to meet
	 * the tHD;STA timing spec.  Configuring _HCNT based on tHIGH spec
	 * will result in violation of the tHD;STA spec.
	 */
	if (cond)
		/*
		 * Conditional expression:
		 *
		 *   IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
		 *
		 * This is based on the DW manuals, and represents an ideal
		 * configuration.  The resulting I2C bus speed will be
		 * faster than any of the others.
		 *
		 * If your hardware is free from tHD;STA issue, try this one.
		 */
		return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
	else
		/*
		 * Conditional expression:
		 *
		 *   IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
		 *
		 * This is just experimental rule; the tHD;STA period turned
		 * out to be proportinal to (_HCNT + 3).  With this setting,
		 * we could meet both tHIGH and tHD;STA timing specs.
		 *
		 * If unsure, you'd better to take this alternative.
		 *
		 * The reason why we need to take into account "tf" here,
		 * is the same as described in i2c_dw_scl_lcnt().
		 */
		return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
			- 3 + offset;
}

static uint32_t
i2c_dw_scl_lcnt(uint32_t ic_clk, uint32_t tLOW, uint32_t tf, int offset)
{
	/*
	 * Conditional expression:
	 *
	 *   IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
	 *
	 * DW I2C core starts counting the SCL CNTs for the LOW period
	 * of the SCL clock (tLOW) as soon as it pulls the SCL line.
	 * In order to meet the tLOW timing spec, we need to take into
	 * account the fall time of SCL signal (tf).  Default tf value
	 * should be 0.3 us, for safety.
	 */
	return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
}

static void i2c_dw_setup_timings(struct dw_i2c_dev *dw)
{
	uint32_t hcnt, lcnt;
	u32 reg;

	const uint32_t sda_falling_time = 300; /* ns */
	const uint32_t scl_falling_time = 300; /* ns */

	const unsigned int input_clock_khz = clk_get_rate(dw->clk) / 1000;

	/* Set SCL timing parameters for standard-mode */
	hcnt = i2c_dw_scl_hcnt(input_clock_khz,
			       4000,	/* tHD;STA = tHIGH = 4.0 us */
			       sda_falling_time,
			       0,	/* 0: DW default, 1: Ideal */
			       0);	/* No offset */
	lcnt = i2c_dw_scl_lcnt(input_clock_khz,
			       4700,	/* tLOW = 4.7 us */
			       scl_falling_time,
			       0);	/* No offset */

	writel(hcnt, dw->base + DW_IC_SS_SCL_HCNT);
	writel(lcnt, dw->base + DW_IC_SS_SCL_LCNT);

	hcnt = i2c_dw_scl_hcnt(input_clock_khz,
			       600,	/* tHD;STA = tHIGH = 0.6 us */
			       sda_falling_time,
			       0,	/* 0: DW default, 1: Ideal */
			       0);	/* No offset */
	lcnt = i2c_dw_scl_lcnt(input_clock_khz,
			       1300,	/* tLOW = 1.3 us */
			       scl_falling_time,
			       0);	/* No offset */

	writel(hcnt, dw->base + DW_IC_FS_SCL_HCNT);
	writel(lcnt, dw->base + DW_IC_FS_SCL_LCNT);

	/* Configure SDA Hold Time if required */
	reg = readl(dw->base + DW_IC_COMP_VERSION);
	if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
		u32 ht;
		int ret;

		ret = of_property_read_u32(dw->adapter.dev.device_node,
					   "i2c-sda-hold-time-ns", &ht);
		if (ret) {
			/* Keep previous hold time setting if no one set it */
			dw->sda_hold_time = readl(dw->base + DW_IC_SDA_HOLD);
		} else if (ht) {
			dw->sda_hold_time = div_u64((u64)input_clock_khz * ht + 500000,
						    1000000);
		}

		/*
		 * Workaround for avoiding TX arbitration lost in case I2C
		 * slave pulls SDA down "too quickly" after falling egde of
		 * SCL by enabling non-zero SDA RX hold. Specification says it
		 * extends incoming SDA low to high transition while SCL is
		 * high but it apprears to help also above issue.
		 */
		if (!(dw->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
			dw->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;

		dev_dbg(dw->adapter.dev.parent, "adjust SDA hold time.\n");
		writel(dw->sda_hold_time, dw->base + DW_IC_SDA_HOLD);
	}
}

static int i2c_dw_wait_for_bits(struct dw_i2c_dev *dw, uint32_t offset,
				uint32_t mask, uint32_t value, uint64_t timeout)
{
	const uint64_t start = get_time_ns();

	do {
		const uint32_t reg = readl(dw->base + offset);

		if ((reg & mask) == value)
			return 0;

	} while (!is_timeout(start, timeout));

	return -ETIMEDOUT;
}

static int i2c_dw_wait_for_idle(struct dw_i2c_dev *dw)
{
	const uint32_t mask  = DW_IC_STATUS_MST_ACTIVITY | DW_IC_STATUS_TFE;
	const uint32_t value = DW_IC_STATUS_TFE;

	return i2c_dw_wait_for_bits(dw, DW_IC_STATUS, mask, value,
				    DW_TIMEOUT_IDLE);
}

static int i2c_dw_wait_for_tx_fifo_not_full(struct dw_i2c_dev *dw)
{
	const uint32_t mask  = DW_IC_STATUS_TFNF;
	const uint32_t value = DW_IC_STATUS_TFNF;

	return i2c_dw_wait_for_bits(dw, DW_IC_STATUS, mask, value,
				    DW_TIMEOUT_TX);
}

static int i2c_dw_wait_for_rx_fifo_not_empty(struct dw_i2c_dev *dw)
{
	const uint32_t mask  = DW_IC_STATUS_RFNE;
	const uint32_t value = DW_IC_STATUS_RFNE;

	return i2c_dw_wait_for_bits(dw, DW_IC_STATUS, mask, value,
				    DW_TIMEOUT_RX);
}

static void i2c_dw_reset(struct dw_i2c_dev *dw)
{
	i2c_dw_enable(dw, false);
	i2c_dw_enable(dw, true);
}

static void i2c_dw_abort_tx(struct dw_i2c_dev *dw)
{
	i2c_dw_reset(dw);
}

static void i2c_dw_abort_rx(struct dw_i2c_dev *dw)
{
	i2c_dw_reset(dw);
}

static int i2c_dw_read(struct dw_i2c_dev *dw,
		       const struct i2c_msg *msg)
{
	int i;
	for (i = 0; i < msg->len; i++) {
		int ret;
		const bool last_byte = i == msg->len - 1;
		uint32_t ic_cmd_data = DW_IC_DATA_CMD_CMD;

		if (last_byte)
			ic_cmd_data |= DW_IC_DATA_CMD_STOP;

		writel(ic_cmd_data, dw->base + DW_IC_DATA_CMD);

		ret = i2c_dw_wait_for_rx_fifo_not_empty(dw);
		if (ret < 0) {
			i2c_dw_abort_rx(dw);
			return ret;
		}

		msg->buf[i] = (uint8_t)readl(dw->base + DW_IC_DATA_CMD);
	}

	return msg->len;
}

static int i2c_dw_write(struct dw_i2c_dev *dw,
			const struct i2c_msg *msg)
{
	int i;
	uint32_t ic_int_stat;

	for (i = 0; i < msg->len; i++) {
		int ret;
		uint32_t ic_cmd_data;
		const bool last_byte = i == msg->len - 1;

		ic_int_stat = readl(dw->base + DW_IC_RAW_INTR_STAT);

		if (ic_int_stat & DW_IC_INTR_TX_ABRT)
			return -EIO;

		ret = i2c_dw_wait_for_tx_fifo_not_full(dw);
		if (ret < 0) {
			i2c_dw_abort_tx(dw);
			return ret;
		}

		ic_cmd_data = msg->buf[i];

		if (last_byte)
			ic_cmd_data |= DW_IC_DATA_CMD_STOP;

		writel(ic_cmd_data, dw->base + DW_IC_DATA_CMD);
	}

	return msg->len;
}

static int i2c_dw_wait_for_stop(struct dw_i2c_dev *dw)
{
	const uint32_t mask  = DW_IC_INTR_STOP_DET;
	const uint32_t value = DW_IC_INTR_STOP_DET;

	return i2c_dw_wait_for_bits(dw, DW_IC_RAW_INTR_STAT, mask, value,
				    DW_TIMEOUT_IDLE);
}

static int i2c_dw_finish_xfer(struct dw_i2c_dev *dw)
{
	int ret;
	uint32_t ic_int_stat;

	/*
	 * We expect the controller to signal STOP condition on the
	 * bus, so we are going to wait for that first.
	 */
	ret = i2c_dw_wait_for_stop(dw);
	if (ret < 0)
		return ret;

	/*
	 * Now that we now that the stop condition has been signaled
	 * we need to wait for controller to go into IDLE state to
	 * make sure all of the possible error conditions on the bus
	 * have been propagated to apporpriate status
	 * registers. Experiment shows that not doing so often results
	 * in false positive "successful" transfers
	*/
	ret = i2c_dw_wait_for_idle(dw);

	if (ret >= 0) {
		ic_int_stat = readl(dw->base + DW_IC_RAW_INTR_STAT);

		if (ic_int_stat & DW_IC_INTR_TX_ABRT)
			return -EIO;
	}

	return ret;
}

static int i2c_dw_set_address(struct dw_i2c_dev *dw, uint8_t address)
{
	int ret;
	uint32_t ic_tar;
	/*
	 * As per "Cyclone V Hard Processor System Technical Reference
	 * Manual" p. 20-19, we have to wait for controller to be in
	 * idle state in order to be able to set the address
	 * dynamically
	 */
	ret = i2c_dw_wait_for_idle(dw);
	if (ret < 0)
		return ret;

	ic_tar = readl(dw->base + DW_IC_TAR);
	ic_tar &= 0xfffffc00;

	writel(ic_tar | address, dw->base + DW_IC_TAR);

	return 0;
}

static int i2c_dw_xfer(struct i2c_adapter *adapter,
		       struct i2c_msg *msgs, int num)
{
	int i, ret = 0;
	struct dw_i2c_dev *dw = to_dw_i2c_dev(adapter);

	for (i = 0; i < num; i++) {
		if (msgs[i].flags & I2C_M_DATA_ONLY)
			return -ENOTSUPP;

		ret = i2c_dw_set_address(dw, msgs[i].addr);
		if (ret < 0)
			break;

		if (msgs[i].flags & I2C_M_RD)
			ret = i2c_dw_read(dw, &msgs[i]);
		else
			ret = i2c_dw_write(dw, &msgs[i]);

		if (ret < 0)
			break;

		ret = i2c_dw_finish_xfer(dw);
		if (ret < 0)
			break;
	}

	if (ret == -EIO) {
		/*
		 * If we got -EIO it means that transfer was for some
		 * reason aborted, so we should figure out the reason
		 * and take steps to clear that condition
		 */
		const uint32_t ic_tx_abrt_source =
			readl(dw->base + DW_IC_TX_ABRT_SOURCE);
		dev_dbg(&dw->adapter.dev,
			"<%s> ic_tx_abrt_source: 0x%04x\n",
			__func__, ic_tx_abrt_source);
		readl(dw->base + DW_IC_CLR_TX_ABRT);

		return ret;
	}

	if (ret < 0) {
		i2c_dw_reset(dw);
		return ret;
	}

	return num;
}


static int i2c_dw_probe(struct device_d *pdev)
{
	struct resource *iores;
	struct dw_i2c_dev *dw;
	struct i2c_platform_data *pdata;
	int ret, bitrate;
	uint32_t ic_con, ic_comp_type_value;

	pdata = pdev->platform_data;

	dw = xzalloc(sizeof(*dw));

	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
		dw->clk = clk_get(pdev, NULL);
		if (IS_ERR(dw->clk)) {
			ret = PTR_ERR(dw->clk);
			goto fail;
		}
	}

	dw->adapter.master_xfer = i2c_dw_xfer;
	dw->adapter.nr = pdev->id;
	dw->adapter.dev.parent = pdev;
	dw->adapter.dev.device_node = pdev->device_node;

	iores = dev_request_mem_resource(pdev, 0);
	if (IS_ERR(iores)) {
		ret = PTR_ERR(iores);
		goto fail;
	}
	dw->base = IOMEM(iores->start);

	ic_comp_type_value = readl(dw->base + DW_IC_COMP_TYPE);
	if (ic_comp_type_value != DW_IC_COMP_TYPE_VALUE) {
		dev_err(pdev, "unknown DesignWare IP block 0x%08x\n", ic_comp_type_value);
		ret = -ENODEV;
		goto fail;
	}

	i2c_dw_enable(dw, false);

	if (IS_ENABLED(CONFIG_COMMON_CLK))
		i2c_dw_setup_timings(dw);

	bitrate = (pdata && pdata->bitrate) ? pdata->bitrate : DW_I2C_BIT_RATE;

	/*
	 * We have to clear 'ic_10bitaddr_master' in 'ic_tar'
	 * register, otherwise 'ic_10bitaddr_master' in 'ic_con'
	 * wouldn't clear. We don't care about preserving the contents
	 * of that register so we set it to zero.
	 */
	writel(0, dw->base + DW_IC_TAR);

	switch (bitrate) {
	case 400000:
		ic_con = DW_IC_CON_SPEED_FAST;
		break;
	default:
		dev_warn(pdev, "requested bitrate (%d) is not supported.\n"
			 " Falling back to 100kHz", bitrate);
	case 100000:		/* FALLTHROUGH */
		ic_con = DW_IC_CON_SPEED_STD;
		break;
	}

	ic_con |= DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE;

	writel(ic_con, dw->base + DW_IC_CON);

	/*
	 * Since we will be working in polling mode set both
	 * thresholds to their minimum
	 */
	writel(0, dw->base + DW_IC_RX_TL);
	writel(0, dw->base + DW_IC_TX_TL);

	/* Disable and clear all interrrupts */
	writel(0, dw->base + DW_IC_INTR_MASK);
	readl(dw->base + DW_IC_CLR_INTR);

	i2c_dw_enable(dw, true);

	ret = i2c_add_numbered_adapter(&dw->adapter);
fail:
	if (ret < 0)
		kfree(dw);

	return ret;
}

static __maybe_unused struct of_device_id i2c_dw_dt_ids[] = {
	{ .compatible = "snps,designware-i2c", },
	{ /* sentinel */ }
};

static struct driver_d i2c_dw_driver = {
	.probe = i2c_dw_probe,
	.name = "i2c-designware",
	.of_compatible = DRV_OF_COMPAT(i2c_dw_dt_ids),
};
coredevice_platform_driver(i2c_dw_driver);