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