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