xref: /rk3399_ARM-atf/drivers/mentor/i2c/mi2cv.c (revision dfc0fb272554ea5829fa74c6b75b9e656f55d0b3)
17e4d5620SIcenowy Zheng /*
27e4d5620SIcenowy Zheng  * Copyright (C) 2018 Marvell International Ltd.
37e4d5620SIcenowy Zheng  * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
47e4d5620SIcenowy Zheng  *
57e4d5620SIcenowy Zheng  * SPDX-License-Identifier:     BSD-3-Clause
67e4d5620SIcenowy Zheng  * https://spdx.org/licenses
77e4d5620SIcenowy Zheng  */
87e4d5620SIcenowy Zheng 
97e4d5620SIcenowy Zheng /*
107e4d5620SIcenowy Zheng  * This driver is for Mentor Graphics Inventra MI2CV IP core, which is used
117e4d5620SIcenowy Zheng  * for Marvell and Allwinner SoCs in ATF.
127e4d5620SIcenowy Zheng  */
137e4d5620SIcenowy Zheng 
147e4d5620SIcenowy Zheng #include <debug.h>
157e4d5620SIcenowy Zheng #include <delay_timer.h>
167e4d5620SIcenowy Zheng #include <errno.h>
177e4d5620SIcenowy Zheng #include <mentor/mi2cv.h>
18*dfc0fb27SAndre Przywara #include <mentor_i2c_plat.h>
197e4d5620SIcenowy Zheng #include <mmio.h>
207e4d5620SIcenowy Zheng 
217e4d5620SIcenowy Zheng #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
227e4d5620SIcenowy Zheng #define DEBUG_I2C
237e4d5620SIcenowy Zheng #endif
247e4d5620SIcenowy Zheng 
257e4d5620SIcenowy Zheng #define I2C_TIMEOUT_VALUE		0x500
267e4d5620SIcenowy Zheng #define I2C_MAX_RETRY_CNT		1000
277e4d5620SIcenowy Zheng #define I2C_CMD_WRITE			0x0
287e4d5620SIcenowy Zheng #define I2C_CMD_READ			0x1
297e4d5620SIcenowy Zheng 
307e4d5620SIcenowy Zheng #define I2C_DATA_ADDR_7BIT_OFFS		0x1
317e4d5620SIcenowy Zheng #define I2C_DATA_ADDR_7BIT_MASK		(0xFF << I2C_DATA_ADDR_7BIT_OFFS)
327e4d5620SIcenowy Zheng 
337e4d5620SIcenowy Zheng #define I2C_CONTROL_ACK			0x00000004
347e4d5620SIcenowy Zheng #define I2C_CONTROL_IFLG		0x00000008
357e4d5620SIcenowy Zheng #define I2C_CONTROL_STOP		0x00000010
367e4d5620SIcenowy Zheng #define I2C_CONTROL_START		0x00000020
377e4d5620SIcenowy Zheng #define I2C_CONTROL_TWSIEN		0x00000040
387e4d5620SIcenowy Zheng #define I2C_CONTROL_INTEN		0x00000080
397e4d5620SIcenowy Zheng 
407e4d5620SIcenowy Zheng #define I2C_STATUS_START			0x08
417e4d5620SIcenowy Zheng #define I2C_STATUS_REPEATED_START		0x10
427e4d5620SIcenowy Zheng #define I2C_STATUS_ADDR_W_ACK			0x18
437e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_W_ACK			0x28
447e4d5620SIcenowy Zheng #define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER	0x38
457e4d5620SIcenowy Zheng #define I2C_STATUS_ADDR_R_ACK			0x40
467e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_R_ACK			0x50
477e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_R_NAK			0x58
487e4d5620SIcenowy Zheng #define I2C_STATUS_LOST_ARB_GENERAL_CALL	0x78
497e4d5620SIcenowy Zheng #define I2C_STATUS_IDLE				0xF8
507e4d5620SIcenowy Zheng 
517e4d5620SIcenowy Zheng #define I2C_UNSTUCK_TRIGGER			0x1
527e4d5620SIcenowy Zheng #define I2C_UNSTUCK_ONGOING			0x2
537e4d5620SIcenowy Zheng #define I2C_UNSTUCK_ERROR			0x4
547e4d5620SIcenowy Zheng 
557e4d5620SIcenowy Zheng static struct mentor_i2c_regs *base;
567e4d5620SIcenowy Zheng 
577e4d5620SIcenowy Zheng static int mentor_i2c_lost_arbitration(uint32_t *status)
587e4d5620SIcenowy Zheng {
597e4d5620SIcenowy Zheng 	*status = mmio_read_32((uintptr_t)&base->status);
607e4d5620SIcenowy Zheng 	if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
617e4d5620SIcenowy Zheng 	    (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
627e4d5620SIcenowy Zheng 		return -EAGAIN;
637e4d5620SIcenowy Zheng 
647e4d5620SIcenowy Zheng 	return 0;
657e4d5620SIcenowy Zheng }
667e4d5620SIcenowy Zheng 
677e4d5620SIcenowy Zheng static void mentor_i2c_interrupt_clear(void)
687e4d5620SIcenowy Zheng {
697e4d5620SIcenowy Zheng 	uint32_t reg;
707e4d5620SIcenowy Zheng 
717e4d5620SIcenowy Zheng 	reg = mmio_read_32((uintptr_t)&base->control);
7220719914SIcenowy Zheng #ifndef I2C_INTERRUPT_CLEAR_INVERTED
737e4d5620SIcenowy Zheng 	reg &= ~(I2C_CONTROL_IFLG);
7420719914SIcenowy Zheng #else
7520719914SIcenowy Zheng 	reg |= I2C_CONTROL_IFLG;
7620719914SIcenowy Zheng #endif
777e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control, reg);
787e4d5620SIcenowy Zheng 	/* Wait for 1 us for the clear to take effect */
797e4d5620SIcenowy Zheng 	udelay(1);
807e4d5620SIcenowy Zheng }
817e4d5620SIcenowy Zheng 
827e4d5620SIcenowy Zheng static int mentor_i2c_interrupt_get(void)
837e4d5620SIcenowy Zheng {
847e4d5620SIcenowy Zheng 	uint32_t reg;
857e4d5620SIcenowy Zheng 
867e4d5620SIcenowy Zheng 	/* get the interrupt flag bit */
877e4d5620SIcenowy Zheng 	reg = mmio_read_32((uintptr_t)&base->control);
887e4d5620SIcenowy Zheng 	reg &= I2C_CONTROL_IFLG;
897e4d5620SIcenowy Zheng 	return reg && I2C_CONTROL_IFLG;
907e4d5620SIcenowy Zheng }
917e4d5620SIcenowy Zheng 
927e4d5620SIcenowy Zheng static int mentor_i2c_wait_interrupt(void)
937e4d5620SIcenowy Zheng {
947e4d5620SIcenowy Zheng 	uint32_t timeout = 0;
957e4d5620SIcenowy Zheng 
967e4d5620SIcenowy Zheng 	while (!mentor_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
977e4d5620SIcenowy Zheng 		;
987e4d5620SIcenowy Zheng 	if (timeout >= I2C_TIMEOUT_VALUE)
997e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
1007e4d5620SIcenowy Zheng 
1017e4d5620SIcenowy Zheng 	return 0;
1027e4d5620SIcenowy Zheng }
1037e4d5620SIcenowy Zheng 
1047e4d5620SIcenowy Zheng static int mentor_i2c_start_bit_set(void)
1057e4d5620SIcenowy Zheng {
1067e4d5620SIcenowy Zheng 	int is_int_flag = 0;
1077e4d5620SIcenowy Zheng 	uint32_t status;
1087e4d5620SIcenowy Zheng 
1097e4d5620SIcenowy Zheng 	if (mentor_i2c_interrupt_get())
1107e4d5620SIcenowy Zheng 		is_int_flag = 1;
1117e4d5620SIcenowy Zheng 
1127e4d5620SIcenowy Zheng 	/* set start bit */
1137e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control,
1147e4d5620SIcenowy Zheng 		      mmio_read_32((uintptr_t)&base->control) |
1157e4d5620SIcenowy Zheng 		      I2C_CONTROL_START);
1167e4d5620SIcenowy Zheng 
1177e4d5620SIcenowy Zheng 	/* in case that the int flag was set before i.e. repeated start bit */
1187e4d5620SIcenowy Zheng 	if (is_int_flag) {
1197e4d5620SIcenowy Zheng 		VERBOSE("%s: repeated start Bit\n", __func__);
1207e4d5620SIcenowy Zheng 		mentor_i2c_interrupt_clear();
1217e4d5620SIcenowy Zheng 	}
1227e4d5620SIcenowy Zheng 
1237e4d5620SIcenowy Zheng 	if (mentor_i2c_wait_interrupt()) {
1247e4d5620SIcenowy Zheng 		ERROR("Start clear bit timeout\n");
1257e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
1267e4d5620SIcenowy Zheng 	}
1277e4d5620SIcenowy Zheng 
1287e4d5620SIcenowy Zheng 	/* check that start bit went down */
1297e4d5620SIcenowy Zheng 	if ((mmio_read_32((uintptr_t)&base->control) &
1307e4d5620SIcenowy Zheng 	    I2C_CONTROL_START) != 0) {
1317e4d5620SIcenowy Zheng 		ERROR("Start bit didn't went down\n");
1327e4d5620SIcenowy Zheng 		return -EPERM;
1337e4d5620SIcenowy Zheng 	}
1347e4d5620SIcenowy Zheng 
1357e4d5620SIcenowy Zheng 	/* check the status */
1367e4d5620SIcenowy Zheng 	if (mentor_i2c_lost_arbitration(&status)) {
1377e4d5620SIcenowy Zheng 		ERROR("%s - %d: Lost arbitration, got status %x\n",
1387e4d5620SIcenowy Zheng 		      __func__, __LINE__, status);
1397e4d5620SIcenowy Zheng 		return -EAGAIN;
1407e4d5620SIcenowy Zheng 	}
1417e4d5620SIcenowy Zheng 	if ((status != I2C_STATUS_START) &&
1427e4d5620SIcenowy Zheng 	    (status != I2C_STATUS_REPEATED_START)) {
1437e4d5620SIcenowy Zheng 		ERROR("Got status %x after enable start bit.\n", status);
1447e4d5620SIcenowy Zheng 		return -EPERM;
1457e4d5620SIcenowy Zheng 	}
1467e4d5620SIcenowy Zheng 
1477e4d5620SIcenowy Zheng 	return 0;
1487e4d5620SIcenowy Zheng }
1497e4d5620SIcenowy Zheng 
1507e4d5620SIcenowy Zheng static int mentor_i2c_stop_bit_set(void)
1517e4d5620SIcenowy Zheng {
1527e4d5620SIcenowy Zheng 	int timeout;
1537e4d5620SIcenowy Zheng 	uint32_t status;
1547e4d5620SIcenowy Zheng 
1557e4d5620SIcenowy Zheng 	/* Generate stop bit */
1567e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control,
1577e4d5620SIcenowy Zheng 		      mmio_read_32((uintptr_t)&base->control) |
1587e4d5620SIcenowy Zheng 		      I2C_CONTROL_STOP);
1597e4d5620SIcenowy Zheng 	mentor_i2c_interrupt_clear();
1607e4d5620SIcenowy Zheng 
1617e4d5620SIcenowy Zheng 	timeout = 0;
1627e4d5620SIcenowy Zheng 	/* Read control register, check the control stop bit */
1637e4d5620SIcenowy Zheng 	while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
1647e4d5620SIcenowy Zheng 	       (timeout++ < I2C_TIMEOUT_VALUE))
1657e4d5620SIcenowy Zheng 		;
1667e4d5620SIcenowy Zheng 	if (timeout >= I2C_TIMEOUT_VALUE) {
1677e4d5620SIcenowy Zheng 		ERROR("Stop bit didn't went down\n");
1687e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
1697e4d5620SIcenowy Zheng 	}
1707e4d5620SIcenowy Zheng 
1717e4d5620SIcenowy Zheng 	/* check that stop bit went down */
1727e4d5620SIcenowy Zheng 	if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
1737e4d5620SIcenowy Zheng 		ERROR("Stop bit didn't went down\n");
1747e4d5620SIcenowy Zheng 		return -EPERM;
1757e4d5620SIcenowy Zheng 	}
1767e4d5620SIcenowy Zheng 
1777e4d5620SIcenowy Zheng 	/* check the status */
1787e4d5620SIcenowy Zheng 	if (mentor_i2c_lost_arbitration(&status)) {
1797e4d5620SIcenowy Zheng 		ERROR("%s - %d: Lost arbitration, got status %x\n",
1807e4d5620SIcenowy Zheng 		      __func__, __LINE__, status);
1817e4d5620SIcenowy Zheng 		return -EAGAIN;
1827e4d5620SIcenowy Zheng 	}
1837e4d5620SIcenowy Zheng 	if (status != I2C_STATUS_IDLE) {
1847e4d5620SIcenowy Zheng 		ERROR("Got status %x after enable stop bit.\n", status);
1857e4d5620SIcenowy Zheng 		return -EPERM;
1867e4d5620SIcenowy Zheng 	}
1877e4d5620SIcenowy Zheng 
1887e4d5620SIcenowy Zheng 	return 0;
1897e4d5620SIcenowy Zheng }
1907e4d5620SIcenowy Zheng 
1917e4d5620SIcenowy Zheng static int mentor_i2c_address_set(uint8_t chain, int command)
1927e4d5620SIcenowy Zheng {
1937e4d5620SIcenowy Zheng 	uint32_t reg, status;
1947e4d5620SIcenowy Zheng 
1957e4d5620SIcenowy Zheng 	reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
1967e4d5620SIcenowy Zheng 	reg |= command;
1977e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->data, reg);
1987e4d5620SIcenowy Zheng 	udelay(1);
1997e4d5620SIcenowy Zheng 
2007e4d5620SIcenowy Zheng 	mentor_i2c_interrupt_clear();
2017e4d5620SIcenowy Zheng 
2027e4d5620SIcenowy Zheng 	if (mentor_i2c_wait_interrupt()) {
2037e4d5620SIcenowy Zheng 		ERROR("Start clear bit timeout\n");
2047e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
2057e4d5620SIcenowy Zheng 	}
2067e4d5620SIcenowy Zheng 
2077e4d5620SIcenowy Zheng 	/* check the status */
2087e4d5620SIcenowy Zheng 	if (mentor_i2c_lost_arbitration(&status)) {
2097e4d5620SIcenowy Zheng 		ERROR("%s - %d: Lost arbitration, got status %x\n",
2107e4d5620SIcenowy Zheng 		      __func__, __LINE__, status);
2117e4d5620SIcenowy Zheng 		return -EAGAIN;
2127e4d5620SIcenowy Zheng 	}
2137e4d5620SIcenowy Zheng 	if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
2147e4d5620SIcenowy Zheng 	   ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
2157e4d5620SIcenowy Zheng 		/* only in debug, since in boot we try to read the SPD
2167e4d5620SIcenowy Zheng 		 * of both DRAM, and we don't want error messages in cas
2177e4d5620SIcenowy Zheng 		 * DIMM doesn't exist.
2187e4d5620SIcenowy Zheng 		 */
2197e4d5620SIcenowy Zheng 		INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
2207e4d5620SIcenowy Zheng 		     status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
2217e4d5620SIcenowy Zheng 		return -EPERM;
2227e4d5620SIcenowy Zheng 	}
2237e4d5620SIcenowy Zheng 
2247e4d5620SIcenowy Zheng 	return 0;
2257e4d5620SIcenowy Zheng }
2267e4d5620SIcenowy Zheng 
2277e4d5620SIcenowy Zheng /*
2287e4d5620SIcenowy Zheng  * The I2C module contains a clock divider to generate the SCL clock.
2297e4d5620SIcenowy Zheng  * This function calculates and sets the <N> and <M> fields in the I2C Baud
2307e4d5620SIcenowy Zheng  * Rate Register (t=01) to obtain given 'requested_speed'.
2317e4d5620SIcenowy Zheng  * The requested_speed will be equal to:
2327e4d5620SIcenowy Zheng  * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
2337e4d5620SIcenowy Zheng  * Where M is the value represented by bits[6:3] and N is the value represented
2347e4d5620SIcenowy Zheng  * by bits[2:0] of "I2C Baud Rate Register".
2357e4d5620SIcenowy Zheng  * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
2367e4d5620SIcenowy Zheng  * lowest possible baudrate is:
2377e4d5620SIcenowy Zheng  * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
2387e4d5620SIcenowy Zheng  * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
2397e4d5620SIcenowy Zheng  * possible frequency is ~2,872KHz.
2407e4d5620SIcenowy Zheng  */
2417e4d5620SIcenowy Zheng static unsigned int mentor_i2c_bus_speed_set(unsigned int requested_speed)
2427e4d5620SIcenowy Zheng {
2437e4d5620SIcenowy Zheng 	unsigned int n, m, freq, margin, min_margin = 0xffffffff;
2447e4d5620SIcenowy Zheng 	unsigned int actual_n = 0, actual_m = 0;
2457e4d5620SIcenowy Zheng 	int val;
2467e4d5620SIcenowy Zheng 
2477e4d5620SIcenowy Zheng 	/* Calculate N and M for the TWSI clock baud rate */
2487e4d5620SIcenowy Zheng 	for (n = 0; n < 8; n++) {
2497e4d5620SIcenowy Zheng 		for (m = 0; m < 16; m++) {
2507e4d5620SIcenowy Zheng 			freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
2517e4d5620SIcenowy Zheng 			val = requested_speed - freq;
2527e4d5620SIcenowy Zheng 			margin = (val > 0) ? val : -val;
2537e4d5620SIcenowy Zheng 
2547e4d5620SIcenowy Zheng 			if ((freq <= requested_speed) &&
2557e4d5620SIcenowy Zheng 			    (margin < min_margin)) {
2567e4d5620SIcenowy Zheng 				min_margin = margin;
2577e4d5620SIcenowy Zheng 				actual_n = n;
2587e4d5620SIcenowy Zheng 				actual_m = m;
2597e4d5620SIcenowy Zheng 			}
2607e4d5620SIcenowy Zheng 		}
2617e4d5620SIcenowy Zheng 	}
2627e4d5620SIcenowy Zheng 	VERBOSE("%s: actual_n = %u, actual_m = %u\n",
2637e4d5620SIcenowy Zheng 		__func__, actual_n, actual_m);
2647e4d5620SIcenowy Zheng 	/* Set the baud rate */
2657e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->baudrate, (actual_m << 3) | actual_n);
2667e4d5620SIcenowy Zheng 
2677e4d5620SIcenowy Zheng 	return 0;
2687e4d5620SIcenowy Zheng }
2697e4d5620SIcenowy Zheng 
2707e4d5620SIcenowy Zheng #ifdef DEBUG_I2C
2717e4d5620SIcenowy Zheng static int mentor_i2c_probe(uint8_t chip)
2727e4d5620SIcenowy Zheng {
2737e4d5620SIcenowy Zheng 	int ret = 0;
2747e4d5620SIcenowy Zheng 
2757e4d5620SIcenowy Zheng 	ret = mentor_i2c_start_bit_set();
2767e4d5620SIcenowy Zheng 	if (ret != 0) {
2777e4d5620SIcenowy Zheng 		mentor_i2c_stop_bit_set();
2787e4d5620SIcenowy Zheng 		ERROR("%s - %d: %s", __func__, __LINE__,
2797e4d5620SIcenowy Zheng 		      "mentor_i2c_start_bit_set failed\n");
2807e4d5620SIcenowy Zheng 		return -EPERM;
2817e4d5620SIcenowy Zheng 	}
2827e4d5620SIcenowy Zheng 
2837e4d5620SIcenowy Zheng 	ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
2847e4d5620SIcenowy Zheng 	if (ret != 0) {
2857e4d5620SIcenowy Zheng 		mentor_i2c_stop_bit_set();
2867e4d5620SIcenowy Zheng 		ERROR("%s - %d: %s", __func__, __LINE__,
2877e4d5620SIcenowy Zheng 		      "mentor_i2c_address_set failed\n");
2887e4d5620SIcenowy Zheng 		return -EPERM;
2897e4d5620SIcenowy Zheng 	}
2907e4d5620SIcenowy Zheng 
2917e4d5620SIcenowy Zheng 	mentor_i2c_stop_bit_set();
2927e4d5620SIcenowy Zheng 
2937e4d5620SIcenowy Zheng 	VERBOSE("%s: successful I2C probe\n", __func__);
2947e4d5620SIcenowy Zheng 
2957e4d5620SIcenowy Zheng 	return ret;
2967e4d5620SIcenowy Zheng }
2977e4d5620SIcenowy Zheng #endif
2987e4d5620SIcenowy Zheng 
2997e4d5620SIcenowy Zheng /* regular i2c transaction */
3007e4d5620SIcenowy Zheng static int mentor_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
3017e4d5620SIcenowy Zheng {
3027e4d5620SIcenowy Zheng 	uint32_t reg, status, block_size_read = block_size;
3037e4d5620SIcenowy Zheng 
3047e4d5620SIcenowy Zheng 	/* Wait for cause interrupt */
3057e4d5620SIcenowy Zheng 	if (mentor_i2c_wait_interrupt()) {
3067e4d5620SIcenowy Zheng 		ERROR("Start clear bit timeout\n");
3077e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
3087e4d5620SIcenowy Zheng 	}
3097e4d5620SIcenowy Zheng 	while (block_size_read) {
3107e4d5620SIcenowy Zheng 		if (block_size_read == 1) {
3117e4d5620SIcenowy Zheng 			reg = mmio_read_32((uintptr_t)&base->control);
3127e4d5620SIcenowy Zheng 			reg &= ~(I2C_CONTROL_ACK);
3137e4d5620SIcenowy Zheng 			mmio_write_32((uintptr_t)&base->control, reg);
3147e4d5620SIcenowy Zheng 		}
3157e4d5620SIcenowy Zheng 		mentor_i2c_interrupt_clear();
3167e4d5620SIcenowy Zheng 
3177e4d5620SIcenowy Zheng 		if (mentor_i2c_wait_interrupt()) {
3187e4d5620SIcenowy Zheng 			ERROR("Start clear bit timeout\n");
3197e4d5620SIcenowy Zheng 			return -ETIMEDOUT;
3207e4d5620SIcenowy Zheng 		}
3217e4d5620SIcenowy Zheng 		/* check the status */
3227e4d5620SIcenowy Zheng 		if (mentor_i2c_lost_arbitration(&status)) {
3237e4d5620SIcenowy Zheng 			ERROR("%s - %d: Lost arbitration, got status %x\n",
3247e4d5620SIcenowy Zheng 			      __func__, __LINE__, status);
3257e4d5620SIcenowy Zheng 			return -EAGAIN;
3267e4d5620SIcenowy Zheng 		}
3277e4d5620SIcenowy Zheng 		if ((status != I2C_STATUS_DATA_R_ACK) &&
3287e4d5620SIcenowy Zheng 		    (block_size_read != 1)) {
3297e4d5620SIcenowy Zheng 			ERROR("Status %x in read transaction\n", status);
3307e4d5620SIcenowy Zheng 			return -EPERM;
3317e4d5620SIcenowy Zheng 		}
3327e4d5620SIcenowy Zheng 		if ((status != I2C_STATUS_DATA_R_NAK) &&
3337e4d5620SIcenowy Zheng 		    (block_size_read == 1)) {
3347e4d5620SIcenowy Zheng 			ERROR("Status %x in Rd Terminate\n", status);
3357e4d5620SIcenowy Zheng 			return -EPERM;
3367e4d5620SIcenowy Zheng 		}
3377e4d5620SIcenowy Zheng 
3387e4d5620SIcenowy Zheng 		/* read the data */
3397e4d5620SIcenowy Zheng 		*p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
3407e4d5620SIcenowy Zheng 		VERBOSE("%s: place %d read %x\n", __func__,
3417e4d5620SIcenowy Zheng 			block_size - block_size_read, *p_block);
3427e4d5620SIcenowy Zheng 		p_block++;
3437e4d5620SIcenowy Zheng 		block_size_read--;
3447e4d5620SIcenowy Zheng 	}
3457e4d5620SIcenowy Zheng 
3467e4d5620SIcenowy Zheng 	return 0;
3477e4d5620SIcenowy Zheng }
3487e4d5620SIcenowy Zheng 
3497e4d5620SIcenowy Zheng static int mentor_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
3507e4d5620SIcenowy Zheng {
3517e4d5620SIcenowy Zheng 	uint32_t status, block_size_write = block_size;
3527e4d5620SIcenowy Zheng 
3537e4d5620SIcenowy Zheng 	if (mentor_i2c_wait_interrupt()) {
3547e4d5620SIcenowy Zheng 		ERROR("Start clear bit timeout\n");
3557e4d5620SIcenowy Zheng 		return -ETIMEDOUT;
3567e4d5620SIcenowy Zheng 	}
3577e4d5620SIcenowy Zheng 
3587e4d5620SIcenowy Zheng 	while (block_size_write) {
3597e4d5620SIcenowy Zheng 		/* write the data */
3607e4d5620SIcenowy Zheng 		mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
3617e4d5620SIcenowy Zheng 		VERBOSE("%s: index = %d, data = %x\n", __func__,
3627e4d5620SIcenowy Zheng 			block_size - block_size_write, *p_block);
3637e4d5620SIcenowy Zheng 		p_block++;
3647e4d5620SIcenowy Zheng 		block_size_write--;
3657e4d5620SIcenowy Zheng 
3667e4d5620SIcenowy Zheng 		mentor_i2c_interrupt_clear();
3677e4d5620SIcenowy Zheng 
3687e4d5620SIcenowy Zheng 		if (mentor_i2c_wait_interrupt()) {
3697e4d5620SIcenowy Zheng 			ERROR("Start clear bit timeout\n");
3707e4d5620SIcenowy Zheng 			return -ETIMEDOUT;
3717e4d5620SIcenowy Zheng 		}
3727e4d5620SIcenowy Zheng 
3737e4d5620SIcenowy Zheng 		/* check the status */
3747e4d5620SIcenowy Zheng 		if (mentor_i2c_lost_arbitration(&status)) {
3757e4d5620SIcenowy Zheng 			ERROR("%s - %d: Lost arbitration, got status %x\n",
3767e4d5620SIcenowy Zheng 			      __func__, __LINE__, status);
3777e4d5620SIcenowy Zheng 			return -EAGAIN;
3787e4d5620SIcenowy Zheng 		}
3797e4d5620SIcenowy Zheng 		if (status != I2C_STATUS_DATA_W_ACK) {
3807e4d5620SIcenowy Zheng 			ERROR("Status %x in write transaction\n", status);
3817e4d5620SIcenowy Zheng 			return -EPERM;
3827e4d5620SIcenowy Zheng 		}
3837e4d5620SIcenowy Zheng 	}
3847e4d5620SIcenowy Zheng 
3857e4d5620SIcenowy Zheng 	return 0;
3867e4d5620SIcenowy Zheng }
3877e4d5620SIcenowy Zheng 
3887e4d5620SIcenowy Zheng static int mentor_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
3897e4d5620SIcenowy Zheng {
3907e4d5620SIcenowy Zheng 	uint8_t off_block[2];
3917e4d5620SIcenowy Zheng 	uint32_t off_size;
3927e4d5620SIcenowy Zheng 
3937e4d5620SIcenowy Zheng 	if (alen == 2) { /* 2-byte addresses support */
3947e4d5620SIcenowy Zheng 		off_block[0] = (addr >> 8) & 0xff;
3957e4d5620SIcenowy Zheng 		off_block[1] = addr & 0xff;
3967e4d5620SIcenowy Zheng 		off_size = 2;
3977e4d5620SIcenowy Zheng 	} else { /* 1-byte addresses support */
3987e4d5620SIcenowy Zheng 		off_block[0] = addr & 0xff;
3997e4d5620SIcenowy Zheng 		off_size = 1;
4007e4d5620SIcenowy Zheng 	}
4017e4d5620SIcenowy Zheng 	VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
4027e4d5620SIcenowy Zheng 		off_size, off_block[0], off_block[1]);
4037e4d5620SIcenowy Zheng 	return mentor_i2c_data_transmit(off_block, off_size);
4047e4d5620SIcenowy Zheng }
4057e4d5620SIcenowy Zheng 
4067e4d5620SIcenowy Zheng #ifdef I2C_CAN_UNSTUCK
4077e4d5620SIcenowy Zheng static int mentor_i2c_unstuck(int ret)
4087e4d5620SIcenowy Zheng {
4097e4d5620SIcenowy Zheng 	uint32_t v;
4107e4d5620SIcenowy Zheng 
4117e4d5620SIcenowy Zheng 	if (ret != -ETIMEDOUT)
4127e4d5620SIcenowy Zheng 		return ret;
4137e4d5620SIcenowy Zheng 	VERBOSE("Trying to \"unstuck i2c\"... ");
4147e4d5620SIcenowy Zheng 	i2c_init(base);
4157e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
4167e4d5620SIcenowy Zheng 	do {
4177e4d5620SIcenowy Zheng 		v = mmio_read_32((uintptr_t)&base->unstuck);
4187e4d5620SIcenowy Zheng 	} while (v & I2C_UNSTUCK_ONGOING);
4197e4d5620SIcenowy Zheng 
4207e4d5620SIcenowy Zheng 	if (v & I2C_UNSTUCK_ERROR) {
4217e4d5620SIcenowy Zheng 		VERBOSE("failed - soft reset i2c\n");
4227e4d5620SIcenowy Zheng 		ret = -EPERM;
4237e4d5620SIcenowy Zheng 	} else {
4247e4d5620SIcenowy Zheng 		VERBOSE("ok\n");
4257e4d5620SIcenowy Zheng 		i2c_init(base);
4267e4d5620SIcenowy Zheng 		ret = -EAGAIN;
4277e4d5620SIcenowy Zheng 	}
4287e4d5620SIcenowy Zheng 	return ret;
4297e4d5620SIcenowy Zheng }
4307e4d5620SIcenowy Zheng #else
4317e4d5620SIcenowy Zheng static int mentor_i2c_unstuck(int ret)
4327e4d5620SIcenowy Zheng {
4337e4d5620SIcenowy Zheng 	VERBOSE("Cannot \"unstuck i2c\" - soft reset i2c\n");
4347e4d5620SIcenowy Zheng 	return -EPERM;
4357e4d5620SIcenowy Zheng }
4367e4d5620SIcenowy Zheng #endif
4377e4d5620SIcenowy Zheng 
4387e4d5620SIcenowy Zheng /*
4397e4d5620SIcenowy Zheng  * API Functions
4407e4d5620SIcenowy Zheng  */
4417e4d5620SIcenowy Zheng void i2c_init(void *i2c_base)
4427e4d5620SIcenowy Zheng {
4437e4d5620SIcenowy Zheng 	/* For I2C speed and slave address, now we do not set them since
4447e4d5620SIcenowy Zheng 	 * we just provide the working speed and slave address otherwhere
4457e4d5620SIcenowy Zheng 	 * for i2c_init
4467e4d5620SIcenowy Zheng 	 */
4477e4d5620SIcenowy Zheng 	base = (struct mentor_i2c_regs *)i2c_base;
4487e4d5620SIcenowy Zheng 
4497e4d5620SIcenowy Zheng 	/* Reset the I2C logic */
4507e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->soft_reset, 0);
4517e4d5620SIcenowy Zheng 
4527e4d5620SIcenowy Zheng 	udelay(200);
4537e4d5620SIcenowy Zheng 
4547e4d5620SIcenowy Zheng 	mentor_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
4557e4d5620SIcenowy Zheng 
4567e4d5620SIcenowy Zheng 	/* Enable the I2C and slave */
4577e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control,
4587e4d5620SIcenowy Zheng 		      I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
4597e4d5620SIcenowy Zheng 
4607e4d5620SIcenowy Zheng 	/* set the I2C slave address */
4617e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
4627e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
4637e4d5620SIcenowy Zheng 
4647e4d5620SIcenowy Zheng 	/* unmask I2C interrupt */
4657e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control,
4667e4d5620SIcenowy Zheng 		      mmio_read_32((uintptr_t)&base->control) |
4677e4d5620SIcenowy Zheng 		      I2C_CONTROL_INTEN);
4687e4d5620SIcenowy Zheng 
4697e4d5620SIcenowy Zheng 	udelay(10);
4707e4d5620SIcenowy Zheng }
4717e4d5620SIcenowy Zheng 
4727e4d5620SIcenowy Zheng /*
4737e4d5620SIcenowy Zheng  * i2c_read: - Read multiple bytes from an i2c device
4747e4d5620SIcenowy Zheng  *
4757e4d5620SIcenowy Zheng  * The higher level routines take into account that this function is only
4767e4d5620SIcenowy Zheng  * called with len < page length of the device (see configuration file)
4777e4d5620SIcenowy Zheng  *
4787e4d5620SIcenowy Zheng  * @chip:	address of the chip which is to be read
4797e4d5620SIcenowy Zheng  * @addr:	i2c data address within the chip
4807e4d5620SIcenowy Zheng  * @alen:	length of the i2c data address (1..2 bytes)
4817e4d5620SIcenowy Zheng  * @buffer:	where to write the data
4827e4d5620SIcenowy Zheng  * @len:	how much byte do we want to read
4837e4d5620SIcenowy Zheng  * @return:	0 in case of success
4847e4d5620SIcenowy Zheng  */
4857e4d5620SIcenowy Zheng int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
4867e4d5620SIcenowy Zheng {
4877e4d5620SIcenowy Zheng 	int ret = 0;
4887e4d5620SIcenowy Zheng 	uint32_t counter = 0;
4897e4d5620SIcenowy Zheng 
4907e4d5620SIcenowy Zheng #ifdef DEBUG_I2C
4917e4d5620SIcenowy Zheng 	mentor_i2c_probe(chip);
4927e4d5620SIcenowy Zheng #endif
4937e4d5620SIcenowy Zheng 
4947e4d5620SIcenowy Zheng 	do {
4957e4d5620SIcenowy Zheng 		if (ret != -EAGAIN && ret) {
4967e4d5620SIcenowy Zheng 			ERROR("i2c transaction failed, after %d retries\n",
4977e4d5620SIcenowy Zheng 			      counter);
4987e4d5620SIcenowy Zheng 			mentor_i2c_stop_bit_set();
4997e4d5620SIcenowy Zheng 			return ret;
5007e4d5620SIcenowy Zheng 		}
5017e4d5620SIcenowy Zheng 
5027e4d5620SIcenowy Zheng 		/* wait for 1 us for the interrupt clear to take effect */
5037e4d5620SIcenowy Zheng 		if (counter > 0)
5047e4d5620SIcenowy Zheng 			udelay(1);
5057e4d5620SIcenowy Zheng 		counter++;
5067e4d5620SIcenowy Zheng 
5077e4d5620SIcenowy Zheng 		ret = mentor_i2c_start_bit_set();
5087e4d5620SIcenowy Zheng 		if (ret) {
5097e4d5620SIcenowy Zheng 			ret = mentor_i2c_unstuck(ret);
5107e4d5620SIcenowy Zheng 			continue;
5117e4d5620SIcenowy Zheng 		}
5127e4d5620SIcenowy Zheng 
5137e4d5620SIcenowy Zheng 		/* if EEPROM device */
5147e4d5620SIcenowy Zheng 		if (alen != 0) {
5157e4d5620SIcenowy Zheng 			ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
5167e4d5620SIcenowy Zheng 			if (ret)
5177e4d5620SIcenowy Zheng 				continue;
5187e4d5620SIcenowy Zheng 
5197e4d5620SIcenowy Zheng 			ret = mentor_i2c_target_offset_set(chip, addr, alen);
5207e4d5620SIcenowy Zheng 			if (ret)
5217e4d5620SIcenowy Zheng 				continue;
5227e4d5620SIcenowy Zheng 			ret = mentor_i2c_start_bit_set();
5237e4d5620SIcenowy Zheng 			if (ret)
5247e4d5620SIcenowy Zheng 				continue;
5257e4d5620SIcenowy Zheng 		}
5267e4d5620SIcenowy Zheng 
5277e4d5620SIcenowy Zheng 		ret =  mentor_i2c_address_set(chip, I2C_CMD_READ);
5287e4d5620SIcenowy Zheng 		if (ret)
5297e4d5620SIcenowy Zheng 			continue;
5307e4d5620SIcenowy Zheng 
5317e4d5620SIcenowy Zheng 		ret = mentor_i2c_data_receive(buffer, len);
5327e4d5620SIcenowy Zheng 		if (ret)
5337e4d5620SIcenowy Zheng 			continue;
5347e4d5620SIcenowy Zheng 
5357e4d5620SIcenowy Zheng 		ret =  mentor_i2c_stop_bit_set();
5367e4d5620SIcenowy Zheng 	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
5377e4d5620SIcenowy Zheng 
5387e4d5620SIcenowy Zheng 	if (counter == I2C_MAX_RETRY_CNT) {
5397e4d5620SIcenowy Zheng 		ERROR("I2C transactions failed, got EAGAIN %d times\n",
5407e4d5620SIcenowy Zheng 		      I2C_MAX_RETRY_CNT);
5417e4d5620SIcenowy Zheng 		ret = -EPERM;
5427e4d5620SIcenowy Zheng 	}
5437e4d5620SIcenowy Zheng 	mmio_write_32((uintptr_t)&base->control,
5447e4d5620SIcenowy Zheng 		      mmio_read_32((uintptr_t)&base->control) |
5457e4d5620SIcenowy Zheng 		      I2C_CONTROL_ACK);
5467e4d5620SIcenowy Zheng 
5477e4d5620SIcenowy Zheng 	udelay(1);
5487e4d5620SIcenowy Zheng 	return ret;
5497e4d5620SIcenowy Zheng }
5507e4d5620SIcenowy Zheng 
5517e4d5620SIcenowy Zheng /*
5527e4d5620SIcenowy Zheng  * i2c_write: -  Write multiple bytes to an i2c device
5537e4d5620SIcenowy Zheng  *
5547e4d5620SIcenowy Zheng  * The higher level routines take into account that this function is only
5557e4d5620SIcenowy Zheng  * called with len < page length of the device (see configuration file)
5567e4d5620SIcenowy Zheng  *
5577e4d5620SIcenowy Zheng  * @chip:	address of the chip which is to be written
5587e4d5620SIcenowy Zheng  * @addr:	i2c data address within the chip
5597e4d5620SIcenowy Zheng  * @alen:	length of the i2c data address (1..2 bytes)
5607e4d5620SIcenowy Zheng  * @buffer:	where to find the data to be written
5617e4d5620SIcenowy Zheng  * @len:	how much byte do we want to read
5627e4d5620SIcenowy Zheng  * @return:	0 in case of success
5637e4d5620SIcenowy Zheng  */
5647e4d5620SIcenowy Zheng int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
5657e4d5620SIcenowy Zheng {
5667e4d5620SIcenowy Zheng 	int ret = 0;
5677e4d5620SIcenowy Zheng 	uint32_t counter = 0;
5687e4d5620SIcenowy Zheng 
5697e4d5620SIcenowy Zheng 	do {
5707e4d5620SIcenowy Zheng 		if (ret != -EAGAIN && ret) {
5717e4d5620SIcenowy Zheng 			ERROR("i2c transaction failed\n");
5727e4d5620SIcenowy Zheng 			mentor_i2c_stop_bit_set();
5737e4d5620SIcenowy Zheng 			return ret;
5747e4d5620SIcenowy Zheng 		}
5757e4d5620SIcenowy Zheng 		/* wait for 1 us for the interrupt clear to take effect */
5767e4d5620SIcenowy Zheng 		if (counter > 0)
5777e4d5620SIcenowy Zheng 			udelay(1);
5787e4d5620SIcenowy Zheng 		counter++;
5797e4d5620SIcenowy Zheng 
5807e4d5620SIcenowy Zheng 		ret = mentor_i2c_start_bit_set();
5817e4d5620SIcenowy Zheng 		if (ret) {
5827e4d5620SIcenowy Zheng 			ret = mentor_i2c_unstuck(ret);
5837e4d5620SIcenowy Zheng 			continue;
5847e4d5620SIcenowy Zheng 		}
5857e4d5620SIcenowy Zheng 
5867e4d5620SIcenowy Zheng 		ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
5877e4d5620SIcenowy Zheng 		if (ret)
5887e4d5620SIcenowy Zheng 			continue;
5897e4d5620SIcenowy Zheng 
5907e4d5620SIcenowy Zheng 		/* if EEPROM device */
5917e4d5620SIcenowy Zheng 		if (alen != 0) {
5927e4d5620SIcenowy Zheng 			ret = mentor_i2c_target_offset_set(chip, addr, alen);
5937e4d5620SIcenowy Zheng 			if (ret)
5947e4d5620SIcenowy Zheng 				continue;
5957e4d5620SIcenowy Zheng 		}
5967e4d5620SIcenowy Zheng 
5977e4d5620SIcenowy Zheng 		ret = mentor_i2c_data_transmit(buffer, len);
5987e4d5620SIcenowy Zheng 		if (ret)
5997e4d5620SIcenowy Zheng 			continue;
6007e4d5620SIcenowy Zheng 
6017e4d5620SIcenowy Zheng 		ret = mentor_i2c_stop_bit_set();
6027e4d5620SIcenowy Zheng 	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
6037e4d5620SIcenowy Zheng 
6047e4d5620SIcenowy Zheng 	if (counter == I2C_MAX_RETRY_CNT) {
6057e4d5620SIcenowy Zheng 		ERROR("I2C transactions failed, got EAGAIN %d times\n",
6067e4d5620SIcenowy Zheng 		      I2C_MAX_RETRY_CNT);
6077e4d5620SIcenowy Zheng 		ret = -EPERM;
6087e4d5620SIcenowy Zheng 	}
6097e4d5620SIcenowy Zheng 
6107e4d5620SIcenowy Zheng 	udelay(1);
6117e4d5620SIcenowy Zheng 	return ret;
6127e4d5620SIcenowy Zheng }
613