xref: /openbmc/u-boot/drivers/i2c/mvtwsi.c (revision 8da19df5b504f1cbe79e13f859bc229c042aded5)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
201ec99d9SAlbert Aribaud /*
3306563a7SAlbert Aribaud  * Driver for the TWSI (i2c) controller found on the Marvell
4306563a7SAlbert Aribaud  * orion5x and kirkwood SoC families.
501ec99d9SAlbert Aribaud  *
657b4bce9SAlbert ARIBAUD  * Author: Albert Aribaud <albert.u.boot@aribaud.net>
7306563a7SAlbert Aribaud  * Copyright (c) 2010 Albert Aribaud.
801ec99d9SAlbert Aribaud  */
9306563a7SAlbert Aribaud 
1001ec99d9SAlbert Aribaud #include <common.h>
1101ec99d9SAlbert Aribaud #include <i2c.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
1301ec99d9SAlbert Aribaud #include <asm/io.h>
14*173ec351SBaruch Siach #include <linux/bitops.h>
15c68c6243Smario.six@gdsys.cc #include <linux/compat.h>
1614a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
1714a6ff2cSmario.six@gdsys.cc #include <dm.h>
1814a6ff2cSmario.six@gdsys.cc #endif
1914a6ff2cSmario.six@gdsys.cc 
2014a6ff2cSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR;
2101ec99d9SAlbert Aribaud 
22306563a7SAlbert Aribaud /*
2349c801bfSmario.six@gdsys.cc  * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
2449c801bfSmario.six@gdsys.cc  * settings
25306563a7SAlbert Aribaud  */
2601ec99d9SAlbert Aribaud 
2714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
28306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X)
29306563a7SAlbert Aribaud #include <asm/arch/orion5x.h>
3081e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
313dc23f78SStefan Roese #include <asm/arch/soc.h>
32aec9a0f1SJagan Teki #elif defined(CONFIG_ARCH_SUNXI)
336620377eSHans de Goede #include <asm/arch/i2c.h>
34306563a7SAlbert Aribaud #else
35306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board
3601ec99d9SAlbert Aribaud #endif
3714a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
3801ec99d9SAlbert Aribaud 
3901ec99d9SAlbert Aribaud /*
40a8f01ccfSJernej Skrabec  * On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to
41a8f01ccfSJernej Skrabec  * always have it.
42a8f01ccfSJernej Skrabec  */
43a8f01ccfSJernej Skrabec #if defined(CONFIG_DM_I2C) && defined(CONFIG_ARCH_SUNXI)
44a8f01ccfSJernej Skrabec #include <asm/arch/i2c.h>
45a8f01ccfSJernej Skrabec #endif
46a8f01ccfSJernej Skrabec 
47a8f01ccfSJernej Skrabec /*
48306563a7SAlbert Aribaud  * TWSI register structure
4901ec99d9SAlbert Aribaud  */
5001ec99d9SAlbert Aribaud 
51aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI
526620377eSHans de Goede 
536620377eSHans de Goede struct  mvtwsi_registers {
546620377eSHans de Goede 	u32 slave_address;
556620377eSHans de Goede 	u32 xtnd_slave_addr;
566620377eSHans de Goede 	u32 data;
576620377eSHans de Goede 	u32 control;
586620377eSHans de Goede 	u32 status;
596620377eSHans de Goede 	u32 baudrate;
606620377eSHans de Goede 	u32 soft_reset;
61*173ec351SBaruch Siach 	u32 debug; /* Dummy field for build compatibility with mvebu */
626620377eSHans de Goede };
636620377eSHans de Goede 
646620377eSHans de Goede #else
656620377eSHans de Goede 
66306563a7SAlbert Aribaud struct  mvtwsi_registers {
67306563a7SAlbert Aribaud 	u32 slave_address;
68306563a7SAlbert Aribaud 	u32 data;
69306563a7SAlbert Aribaud 	u32 control;
70306563a7SAlbert Aribaud 	union {
7149c801bfSmario.six@gdsys.cc 		u32 status;	/* When reading */
7249c801bfSmario.six@gdsys.cc 		u32 baudrate;	/* When writing */
73306563a7SAlbert Aribaud 	};
74306563a7SAlbert Aribaud 	u32 xtnd_slave_addr;
75*173ec351SBaruch Siach 	u32 reserved0[2];
76306563a7SAlbert Aribaud 	u32 soft_reset;
77*173ec351SBaruch Siach 	u32 reserved1[27];
78*173ec351SBaruch Siach 	u32 debug;
79306563a7SAlbert Aribaud };
80306563a7SAlbert Aribaud 
816620377eSHans de Goede #endif
826620377eSHans de Goede 
8314a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
8414a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
8514a6ff2cSmario.six@gdsys.cc 	/* TWSI Register base for the device */
8614a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_registers *base;
8714a6ff2cSmario.six@gdsys.cc 	/* Number of the device (determined from cell-index property) */
8814a6ff2cSmario.six@gdsys.cc 	int index;
8914a6ff2cSmario.six@gdsys.cc 	/* The I2C slave address for the device */
9014a6ff2cSmario.six@gdsys.cc 	u8 slaveadd;
9114a6ff2cSmario.six@gdsys.cc 	/* The configured I2C speed in Hz */
9214a6ff2cSmario.six@gdsys.cc 	uint speed;
93c68c6243Smario.six@gdsys.cc 	/* The current length of a clock period (depending on speed) */
94c68c6243Smario.six@gdsys.cc 	uint tick;
9514a6ff2cSmario.six@gdsys.cc };
9614a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
9714a6ff2cSmario.six@gdsys.cc 
98306563a7SAlbert Aribaud /*
99dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
100dfc3958cSmario.six@gdsys.cc  * register
101306563a7SAlbert Aribaud  */
102dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
103dfc3958cSmario.six@gdsys.cc 	/* Acknowledge bit */
104dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_ACK	= 0x00000004,
105dfc3958cSmario.six@gdsys.cc 	/* Interrupt flag */
106dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_IFLG	= 0x00000008,
107dfc3958cSmario.six@gdsys.cc 	/* Stop bit */
108dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_STOP	= 0x00000010,
109dfc3958cSmario.six@gdsys.cc 	/* Start bit */
110dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_START	= 0x00000020,
111dfc3958cSmario.six@gdsys.cc 	/* I2C enable */
112dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_TWSIEN	= 0x00000040,
113dfc3958cSmario.six@gdsys.cc 	/* Interrupt enable */
114dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_INTEN	= 0x00000080,
115dfc3958cSmario.six@gdsys.cc };
116306563a7SAlbert Aribaud 
117306563a7SAlbert Aribaud /*
11849c801bfSmario.six@gdsys.cc  * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
11949c801bfSmario.six@gdsys.cc  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
120904dfbfdSHans de Goede  */
121904dfbfdSHans de Goede 
122904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
123904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
124904dfbfdSHans de Goede #else
125904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
126904dfbfdSHans de Goede #endif
127904dfbfdSHans de Goede 
128904dfbfdSHans de Goede /*
129dfc3958cSmario.six@gdsys.cc  * enum mvstwsi_status_values - Possible values of I2C controller's status
130dfc3958cSmario.six@gdsys.cc  * register
131dfc3958cSmario.six@gdsys.cc  *
132dfc3958cSmario.six@gdsys.cc  * Only those statuses expected in normal master operation on
133dfc3958cSmario.six@gdsys.cc  * non-10-bit-address devices are specified.
134dfc3958cSmario.six@gdsys.cc  *
135dfc3958cSmario.six@gdsys.cc  * Every status that's unexpected during normal operation (bus errors,
136dfc3958cSmario.six@gdsys.cc  * arbitration losses, missing ACKs...) is passed back to the caller as an error
137306563a7SAlbert Aribaud  * code.
138306563a7SAlbert Aribaud  */
139dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
140dfc3958cSmario.six@gdsys.cc 	/* START condition transmitted */
141dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_START		= 0x08,
142dfc3958cSmario.six@gdsys.cc 	/* Repeated START condition transmitted */
143dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_REPEATED_START	= 0x10,
144dfc3958cSmario.six@gdsys.cc 	/* Address + write bit transmitted, ACK received */
145dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_W_ACK	= 0x18,
146dfc3958cSmario.six@gdsys.cc 	/* Data transmitted, ACK received */
147dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_W_ACK	= 0x28,
148dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK received */
149dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_ACK	= 0x40,
150dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK not received */
151dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_NAK	= 0x48,
152dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK transmitted */
153dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_ACK	= 0x50,
154dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK not transmitted */
155dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_NAK	= 0x58,
156dfc3958cSmario.six@gdsys.cc 	/* No relevant status */
157dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_IDLE		= 0xF8,
158dfc3958cSmario.six@gdsys.cc };
159306563a7SAlbert Aribaud 
160306563a7SAlbert Aribaud /*
161670514f5Smario.six@gdsys.cc  * enum mvstwsi_ack_flags - Determine whether a read byte should be
162670514f5Smario.six@gdsys.cc  * acknowledged or not.
163670514f5Smario.six@gdsys.cc  */
164670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
165670514f5Smario.six@gdsys.cc 	/* Send NAK after received byte */
166670514f5Smario.six@gdsys.cc 	MVTWSI_READ_NAK = 0,
167670514f5Smario.six@gdsys.cc 	/* Send ACK after received byte */
168670514f5Smario.six@gdsys.cc 	MVTWSI_READ_ACK = 1,
169670514f5Smario.six@gdsys.cc };
170670514f5Smario.six@gdsys.cc 
1716e677cafSmario.six@gdsys.cc /*
1726e677cafSmario.six@gdsys.cc  * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
1736e677cafSmario.six@gdsys.cc  *
1746e677cafSmario.six@gdsys.cc  * @speed:	The speed in Hz to calculate the clock cycle duration for.
1756e677cafSmario.six@gdsys.cc  * @return The duration of a clock cycle in ns.
1766e677cafSmario.six@gdsys.cc  */
calc_tick(uint speed)177c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed)
178c68c6243Smario.six@gdsys.cc {
179c68c6243Smario.six@gdsys.cc 	/* One tick = the duration of a period at the specified speed in ns (we
180c68c6243Smario.six@gdsys.cc 	 * add 100 ns to be on the safe side) */
181c68c6243Smario.six@gdsys.cc 	return (1000000000u / speed) + 100;
182c68c6243Smario.six@gdsys.cc }
183c68c6243Smario.six@gdsys.cc 
18414a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
185c68c6243Smario.six@gdsys.cc 
186670514f5Smario.six@gdsys.cc /*
1876e677cafSmario.six@gdsys.cc  * twsi_get_base() - Get controller register base for specified adapter
1886e677cafSmario.six@gdsys.cc  *
1896e677cafSmario.six@gdsys.cc  * @adap:	Adapter to get the register base for.
1906e677cafSmario.six@gdsys.cc  * @return Register base for the specified adapter.
191306563a7SAlbert Aribaud  */
twsi_get_base(struct i2c_adapter * adap)192dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
193dd82242bSPaul Kocialkowski {
194dd82242bSPaul Kocialkowski 	switch (adap->hwadapnr) {
195dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
196dd82242bSPaul Kocialkowski 	case 0:
197dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
198dd82242bSPaul Kocialkowski #endif
199dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
200dd82242bSPaul Kocialkowski 	case 1:
201dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
202dd82242bSPaul Kocialkowski #endif
203dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
204dd82242bSPaul Kocialkowski 	case 2:
205dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
206dd82242bSPaul Kocialkowski #endif
207dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
208dd82242bSPaul Kocialkowski 	case 3:
209dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
210dd82242bSPaul Kocialkowski #endif
211dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
212dd82242bSPaul Kocialkowski 	case 4:
213dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
214dd82242bSPaul Kocialkowski #endif
2159d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
2169d082687SJelle van der Waa 	case 5:
2179d082687SJelle van der Waa 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
2189d082687SJelle van der Waa #endif
219dd82242bSPaul Kocialkowski 	default:
220dd82242bSPaul Kocialkowski 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
221dd82242bSPaul Kocialkowski 		break;
222dd82242bSPaul Kocialkowski 	}
223dd82242bSPaul Kocialkowski 
224dd82242bSPaul Kocialkowski 	return NULL;
225dd82242bSPaul Kocialkowski }
22614a6ff2cSmario.six@gdsys.cc #endif
227306563a7SAlbert Aribaud 
228306563a7SAlbert Aribaud /*
229dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_error_class - types of I2C errors
230306563a7SAlbert Aribaud  */
231dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
232dfc3958cSmario.six@gdsys.cc 	/* The controller returned a different status than expected */
233dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_WRONG_STATUS       = 0x01,
234dfc3958cSmario.six@gdsys.cc 	/* The controller timed out */
235dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_TIMEOUT            = 0x02,
236dfc3958cSmario.six@gdsys.cc };
237306563a7SAlbert Aribaud 
238dfc3958cSmario.six@gdsys.cc /*
239dfc3958cSmario.six@gdsys.cc  * mvtwsi_error() - Build I2C return code from error information
240dfc3958cSmario.six@gdsys.cc  *
241dfc3958cSmario.six@gdsys.cc  * For debugging purposes, this function packs some information of an occurred
242dfc3958cSmario.six@gdsys.cc  * error into a return code. These error codes are returned from I2C API
243dfc3958cSmario.six@gdsys.cc  * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
244dfc3958cSmario.six@gdsys.cc  *
245dfc3958cSmario.six@gdsys.cc  * @ec:		The error class of the error (enum mvtwsi_error_class).
246dfc3958cSmario.six@gdsys.cc  * @lc:		The last value of the control register.
247dfc3958cSmario.six@gdsys.cc  * @ls:		The last value of the status register.
248dfc3958cSmario.six@gdsys.cc  * @es:		The expected value of the status register.
249dfc3958cSmario.six@gdsys.cc  * @return The generated error code.
250dfc3958cSmario.six@gdsys.cc  */
mvtwsi_error(uint ec,uint lc,uint ls,uint es)251dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
252dfc3958cSmario.six@gdsys.cc {
253dfc3958cSmario.six@gdsys.cc 	return ((ec << 24) & 0xFF000000)
254dfc3958cSmario.six@gdsys.cc 	       | ((lc << 16) & 0x00FF0000)
255dfc3958cSmario.six@gdsys.cc 	       | ((ls << 8) & 0x0000FF00)
256dfc3958cSmario.six@gdsys.cc 	       | (es & 0xFF);
257dfc3958cSmario.six@gdsys.cc }
258306563a7SAlbert Aribaud 
259306563a7SAlbert Aribaud /*
2606e677cafSmario.six@gdsys.cc  * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
2616e677cafSmario.six@gdsys.cc  *
2626e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
2636e677cafSmario.six@gdsys.cc  *	   out occurred, or the status was not the expected one.
264306563a7SAlbert Aribaud  */
twsi_wait(struct mvtwsi_registers * twsi,int expected_status,uint tick)265c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
266c68c6243Smario.six@gdsys.cc 		     uint tick)
26701ec99d9SAlbert Aribaud {
268306563a7SAlbert Aribaud 	int control, status;
269306563a7SAlbert Aribaud 	int timeout = 1000;
270306563a7SAlbert Aribaud 
271306563a7SAlbert Aribaud 	do {
272306563a7SAlbert Aribaud 		control = readl(&twsi->control);
273306563a7SAlbert Aribaud 		if (control & MVTWSI_CONTROL_IFLG) {
274306563a7SAlbert Aribaud 			status = readl(&twsi->status);
275306563a7SAlbert Aribaud 			if (status == expected_status)
276306563a7SAlbert Aribaud 				return 0;
27701ec99d9SAlbert Aribaud 			else
278dfc3958cSmario.six@gdsys.cc 				return mvtwsi_error(
279306563a7SAlbert Aribaud 					MVTWSI_ERROR_WRONG_STATUS,
280306563a7SAlbert Aribaud 					control, status, expected_status);
281306563a7SAlbert Aribaud 		}
282c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
283306563a7SAlbert Aribaud 	} while (timeout--);
284306563a7SAlbert Aribaud 	status = readl(&twsi->status);
285dfc3958cSmario.six@gdsys.cc 	return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
286dfc3958cSmario.six@gdsys.cc 			    expected_status);
28701ec99d9SAlbert Aribaud }
28801ec99d9SAlbert Aribaud 
289306563a7SAlbert Aribaud /*
2906e677cafSmario.six@gdsys.cc  * twsi_start() - Assert a START condition on the bus.
2916e677cafSmario.six@gdsys.cc  *
2926e677cafSmario.six@gdsys.cc  * This function is used in both single I2C transactions and inside
2936e677cafSmario.six@gdsys.cc  * back-to-back transactions (repeated starts).
2946e677cafSmario.six@gdsys.cc  *
2956e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
2966e677cafSmario.six@gdsys.cc  * @expected_status:	The I2C bus status expected to be asserted after the
2976e677cafSmario.six@gdsys.cc  *			operation completion.
2986e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
2996e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
3006e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
301306563a7SAlbert Aribaud  */
twsi_start(struct mvtwsi_registers * twsi,int expected_status,uint tick)302c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
303c68c6243Smario.six@gdsys.cc 		      uint tick)
304306563a7SAlbert Aribaud {
30549c801bfSmario.six@gdsys.cc 	/* Assert START */
306670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
3072ca02995SHans de Goede 	       MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
30849c801bfSmario.six@gdsys.cc 	/* Wait for controller to process START */
309c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
310306563a7SAlbert Aribaud }
311306563a7SAlbert Aribaud 
312306563a7SAlbert Aribaud /*
3136e677cafSmario.six@gdsys.cc  * twsi_send() - Send a byte on the I2C bus.
3146e677cafSmario.six@gdsys.cc  *
3156e677cafSmario.six@gdsys.cc  * The byte may be part of an address byte or data.
3166e677cafSmario.six@gdsys.cc  *
3176e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
3186e677cafSmario.six@gdsys.cc  * @byte:		The byte to send.
3196e677cafSmario.six@gdsys.cc  * @expected_status:	The I2C bus status expected to be asserted after the
3206e677cafSmario.six@gdsys.cc  *			operation completion.
3216e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
3226e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
3236e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
324306563a7SAlbert Aribaud  */
twsi_send(struct mvtwsi_registers * twsi,u8 byte,int expected_status,uint tick)3253c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
326c68c6243Smario.six@gdsys.cc 		     int expected_status, uint tick)
327306563a7SAlbert Aribaud {
32849c801bfSmario.six@gdsys.cc 	/* Write byte to data register for sending */
329306563a7SAlbert Aribaud 	writel(byte, &twsi->data);
33049c801bfSmario.six@gdsys.cc 	/* Clear any pending interrupt -- that will cause sending */
331670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
332670514f5Smario.six@gdsys.cc 	       &twsi->control);
33349c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and check ACK */
334c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
335306563a7SAlbert Aribaud }
336306563a7SAlbert Aribaud 
337306563a7SAlbert Aribaud /*
3386e677cafSmario.six@gdsys.cc  * twsi_recv() - Receive a byte on the I2C bus.
3396e677cafSmario.six@gdsys.cc  *
3406e677cafSmario.six@gdsys.cc  * The static variable mvtwsi_control_flags controls whether we ack or nak.
3416e677cafSmario.six@gdsys.cc  *
3426e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
3436e677cafSmario.six@gdsys.cc  * @byte:		The byte to send.
3446e677cafSmario.six@gdsys.cc  * @ack_flag:		Flag that determines whether the received byte should
3456e677cafSmario.six@gdsys.cc  *			be acknowledged by the controller or not (sent ACK/NAK).
3466e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
3476e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
3486e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
349306563a7SAlbert Aribaud  */
twsi_recv(struct mvtwsi_registers * twsi,u8 * byte,int ack_flag,uint tick)350c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
351c68c6243Smario.six@gdsys.cc 		     uint tick)
352306563a7SAlbert Aribaud {
353670514f5Smario.six@gdsys.cc 	int expected_status, status, control;
354306563a7SAlbert Aribaud 
355670514f5Smario.six@gdsys.cc 	/* Compute expected status based on passed ACK flag */
356670514f5Smario.six@gdsys.cc 	expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
357670514f5Smario.six@gdsys.cc 			  MVTWSI_STATUS_DATA_R_NAK;
35849c801bfSmario.six@gdsys.cc 	/* Acknowledge *previous state*, and launch receive */
359670514f5Smario.six@gdsys.cc 	control = MVTWSI_CONTROL_TWSIEN;
360670514f5Smario.six@gdsys.cc 	control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
361670514f5Smario.six@gdsys.cc 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
36249c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and assert ACK or NAK */
363c68c6243Smario.six@gdsys.cc 	status = twsi_wait(twsi, expected_status, tick);
36449c801bfSmario.six@gdsys.cc 	/* If we did receive the expected byte, store it */
365306563a7SAlbert Aribaud 	if (status == 0)
366306563a7SAlbert Aribaud 		*byte = readl(&twsi->data);
367306563a7SAlbert Aribaud 	return status;
368306563a7SAlbert Aribaud }
369306563a7SAlbert Aribaud 
370306563a7SAlbert Aribaud /*
3716e677cafSmario.six@gdsys.cc  * twsi_stop() - Assert a STOP condition on the bus.
3726e677cafSmario.six@gdsys.cc  *
3736e677cafSmario.six@gdsys.cc  * This function is also used to force the bus back to idle state (SDA =
3746e677cafSmario.six@gdsys.cc  * SCL = 1).
3756e677cafSmario.six@gdsys.cc  *
3766e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
3776e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
3786e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out
3796e677cafSmario.six@gdsys.cc  *	   occurred.
380306563a7SAlbert Aribaud  */
twsi_stop(struct mvtwsi_registers * twsi,uint tick)381c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
382306563a7SAlbert Aribaud {
383306563a7SAlbert Aribaud 	int control, stop_status;
384059fce9fSmario.six@gdsys.cc 	int status = 0;
385306563a7SAlbert Aribaud 	int timeout = 1000;
386306563a7SAlbert Aribaud 
38749c801bfSmario.six@gdsys.cc 	/* Assert STOP */
388306563a7SAlbert Aribaud 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
389904dfbfdSHans de Goede 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
39049c801bfSmario.six@gdsys.cc 	/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
391306563a7SAlbert Aribaud 	do {
392306563a7SAlbert Aribaud 		stop_status = readl(&twsi->status);
393306563a7SAlbert Aribaud 		if (stop_status == MVTWSI_STATUS_IDLE)
394306563a7SAlbert Aribaud 			break;
395c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
396306563a7SAlbert Aribaud 	} while (timeout--);
397306563a7SAlbert Aribaud 	control = readl(&twsi->control);
398306563a7SAlbert Aribaud 	if (stop_status != MVTWSI_STATUS_IDLE)
399059fce9fSmario.six@gdsys.cc 		status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
400306563a7SAlbert Aribaud 				      control, status, MVTWSI_STATUS_IDLE);
401306563a7SAlbert Aribaud 	return status;
402306563a7SAlbert Aribaud }
403306563a7SAlbert Aribaud 
4046e677cafSmario.six@gdsys.cc /*
4056e677cafSmario.six@gdsys.cc  * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
4066e677cafSmario.six@gdsys.cc  *
4076e677cafSmario.six@gdsys.cc  * @n:		Parameter 'n' for the frequency calculation algorithm.
4086e677cafSmario.six@gdsys.cc  * @m:		Parameter 'm' for the frequency calculation algorithm.
4096e677cafSmario.six@gdsys.cc  * @return The I2C frequency corresponding to the passed m and n parameters.
4106e677cafSmario.six@gdsys.cc  */
twsi_calc_freq(const int n,const int m)411e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
412f582a158SStefan Roese {
413aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI
414f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
415f582a158SStefan Roese #else
416f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
417f582a158SStefan Roese #endif
418f582a158SStefan Roese }
419306563a7SAlbert Aribaud 
420306563a7SAlbert Aribaud /*
4216e677cafSmario.six@gdsys.cc  * twsi_reset() - Reset the I2C controller.
4226e677cafSmario.six@gdsys.cc  *
4236e677cafSmario.six@gdsys.cc  * Resetting the controller also resets the baud rate and slave address, hence
4246e677cafSmario.six@gdsys.cc  * they must be re-established after the reset.
4256e677cafSmario.six@gdsys.cc  *
4266e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
427306563a7SAlbert Aribaud  */
twsi_reset(struct mvtwsi_registers * twsi)4283c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
429306563a7SAlbert Aribaud {
43049c801bfSmario.six@gdsys.cc 	/* Reset controller */
431306563a7SAlbert Aribaud 	writel(0, &twsi->soft_reset);
43249c801bfSmario.six@gdsys.cc 	/* Wait 2 ms -- this is what the Marvell LSP does */
433306563a7SAlbert Aribaud 	udelay(20000);
434306563a7SAlbert Aribaud }
435306563a7SAlbert Aribaud 
436306563a7SAlbert Aribaud /*
4376e677cafSmario.six@gdsys.cc  * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
4386e677cafSmario.six@gdsys.cc  *
4396e677cafSmario.six@gdsys.cc  * This function sets baud rate to the highest possible value that does not
4406e677cafSmario.six@gdsys.cc  * exceed the requested rate.
4416e677cafSmario.six@gdsys.cc  *
4426e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
4436e677cafSmario.six@gdsys.cc  * @requested_speed:	The desired frequency the controller should run at
4446e677cafSmario.six@gdsys.cc  *			in Hz.
4456e677cafSmario.six@gdsys.cc  * @return The actual frequency the controller was configured to.
446306563a7SAlbert Aribaud  */
__twsi_i2c_set_bus_speed(struct mvtwsi_registers * twsi,uint requested_speed)4473c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
448e0758281Smario.six@gdsys.cc 				     uint requested_speed)
449306563a7SAlbert Aribaud {
450e0758281Smario.six@gdsys.cc 	uint tmp_speed, highest_speed, n, m;
451e0758281Smario.six@gdsys.cc 	uint baud = 0x44; /* Baud rate after controller reset */
452306563a7SAlbert Aribaud 
453306563a7SAlbert Aribaud 	highest_speed = 0;
45449c801bfSmario.six@gdsys.cc 	/* Successively try m, n combinations, and use the combination
45549c801bfSmario.six@gdsys.cc 	 * resulting in the largest speed that's not above the requested
45649c801bfSmario.six@gdsys.cc 	 * speed */
45701ec99d9SAlbert Aribaud 	for (n = 0; n < 8; n++) {
45801ec99d9SAlbert Aribaud 		for (m = 0; m < 16; m++) {
459f582a158SStefan Roese 			tmp_speed = twsi_calc_freq(n, m);
4609ec43b0cSmario.six@gdsys.cc 			if ((tmp_speed <= requested_speed) &&
4619ec43b0cSmario.six@gdsys.cc 			    (tmp_speed > highest_speed)) {
462306563a7SAlbert Aribaud 				highest_speed = tmp_speed;
463306563a7SAlbert Aribaud 				baud = (m << 3) | n;
46401ec99d9SAlbert Aribaud 			}
46501ec99d9SAlbert Aribaud 		}
46601ec99d9SAlbert Aribaud 	}
4670db2bbdcSHans de Goede 	writel(baud, &twsi->baudrate);
468c68c6243Smario.six@gdsys.cc 
469c68c6243Smario.six@gdsys.cc 	/* Wait for controller for one tick */
470c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
471c68c6243Smario.six@gdsys.cc 	ndelay(calc_tick(highest_speed));
472c68c6243Smario.six@gdsys.cc #else
473c68c6243Smario.six@gdsys.cc 	ndelay(10000);
474c68c6243Smario.six@gdsys.cc #endif
475c68c6243Smario.six@gdsys.cc 	return highest_speed;
4760db2bbdcSHans de Goede }
4770db2bbdcSHans de Goede 
4786e677cafSmario.six@gdsys.cc /*
4796e677cafSmario.six@gdsys.cc  * __twsi_i2c_init() - Initialize the I2C controller.
4806e677cafSmario.six@gdsys.cc  *
4816e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
4826e677cafSmario.six@gdsys.cc  * @speed:		The initial frequency the controller should run at
4836e677cafSmario.six@gdsys.cc  *			in Hz.
4846e677cafSmario.six@gdsys.cc  * @slaveadd:		The I2C address to be set for the I2C master.
4856e677cafSmario.six@gdsys.cc  * @actual_speed:	A output parameter that receives the actual frequency
4866e677cafSmario.six@gdsys.cc  *			in Hz the controller was set to by the function.
4876e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out
4886e677cafSmario.six@gdsys.cc  *	   occurred.
4896e677cafSmario.six@gdsys.cc  */
__twsi_i2c_init(struct mvtwsi_registers * twsi,int speed,int slaveadd,uint * actual_speed)4903c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
491c68c6243Smario.six@gdsys.cc 			    int slaveadd, uint *actual_speed)
4920db2bbdcSHans de Goede {
493004b4cdaSStefan Mavrodiev 	uint tmp_speed;
494004b4cdaSStefan Mavrodiev 
49549c801bfSmario.six@gdsys.cc 	/* Reset controller */
4963c4db636Smario.six@gdsys.cc 	twsi_reset(twsi);
49749c801bfSmario.six@gdsys.cc 	/* Set speed */
498004b4cdaSStefan Mavrodiev 	tmp_speed = __twsi_i2c_set_bus_speed(twsi, speed);
4998bcf12ccSHeinrich Schuchardt 	if (actual_speed)
500004b4cdaSStefan Mavrodiev 		*actual_speed = tmp_speed;
50149c801bfSmario.six@gdsys.cc 	/* Set slave address; even though we don't use it */
5020db2bbdcSHans de Goede 	writel(slaveadd, &twsi->slave_address);
5030db2bbdcSHans de Goede 	writel(0, &twsi->xtnd_slave_addr);
50449c801bfSmario.six@gdsys.cc 	/* Assert STOP, but don't care for the result */
505c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
506c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, calc_tick(*actual_speed));
507c68c6243Smario.six@gdsys.cc #else
508c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, 10000);
509c68c6243Smario.six@gdsys.cc #endif
51001ec99d9SAlbert Aribaud }
51101ec99d9SAlbert Aribaud 
51201ec99d9SAlbert Aribaud /*
5136e677cafSmario.six@gdsys.cc  * i2c_begin() - Start a I2C transaction.
5146e677cafSmario.six@gdsys.cc  *
5156e677cafSmario.six@gdsys.cc  * Begin a I2C transaction with a given expected start status and chip address.
5166e677cafSmario.six@gdsys.cc  * A START is asserted, and the address byte is sent to the I2C controller. The
5176e677cafSmario.six@gdsys.cc  * expected address status will be derived from the direction bit (bit 0) of
5186e677cafSmario.six@gdsys.cc  * the address byte.
5196e677cafSmario.six@gdsys.cc  *
5206e677cafSmario.six@gdsys.cc  * @twsi:			The MVTWSI register structure to use.
5216e677cafSmario.six@gdsys.cc  * @expected_start_status:	The I2C status the controller is expected to
5226e677cafSmario.six@gdsys.cc  *				assert after the address byte was sent.
5236e677cafSmario.six@gdsys.cc  * @addr:			The address byte to be sent.
5246e677cafSmario.six@gdsys.cc  * @tick:			The duration of a clock cycle at the current
5256e677cafSmario.six@gdsys.cc  *				I2C speed.
5266e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5276e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
52801ec99d9SAlbert Aribaud  */
i2c_begin(struct mvtwsi_registers * twsi,int expected_start_status,u8 addr,uint tick)5293c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
530c68c6243Smario.six@gdsys.cc 		     u8 addr, uint tick)
53101ec99d9SAlbert Aribaud {
532306563a7SAlbert Aribaud 	int status, expected_addr_status;
53301ec99d9SAlbert Aribaud 
53449c801bfSmario.six@gdsys.cc 	/* Compute the expected address status from the direction bit in
53549c801bfSmario.six@gdsys.cc 	 * the address byte */
53649c801bfSmario.six@gdsys.cc 	if (addr & 1) /* Reading */
537306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
53849c801bfSmario.six@gdsys.cc 	else /* Writing */
539306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
54049c801bfSmario.six@gdsys.cc 	/* Assert START */
541c68c6243Smario.six@gdsys.cc 	status = twsi_start(twsi, expected_start_status, tick);
54249c801bfSmario.six@gdsys.cc 	/* Send out the address if the start went well */
543306563a7SAlbert Aribaud 	if (status == 0)
544c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, addr, expected_addr_status, tick);
54549c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
546306563a7SAlbert Aribaud 	return status;
54701ec99d9SAlbert Aribaud }
54801ec99d9SAlbert Aribaud 
549306563a7SAlbert Aribaud /*
5506e677cafSmario.six@gdsys.cc  * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
5516e677cafSmario.six@gdsys.cc  *
5526e677cafSmario.six@gdsys.cc  * This function begins a I2C read transaction, does a dummy read and NAKs; if
5536e677cafSmario.six@gdsys.cc  * the procedure succeeds, the chip is considered to be present.
5546e677cafSmario.six@gdsys.cc  *
5556e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
5566e677cafSmario.six@gdsys.cc  * @chip:	The chip address to probe.
5576e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
5586e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5596e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
560306563a7SAlbert Aribaud  */
__twsi_i2c_probe_chip(struct mvtwsi_registers * twsi,uchar chip,uint tick)561c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
562c68c6243Smario.six@gdsys.cc 				 uint tick)
56301ec99d9SAlbert Aribaud {
564306563a7SAlbert Aribaud 	u8 dummy_byte;
565306563a7SAlbert Aribaud 	int status;
56601ec99d9SAlbert Aribaud 
56749c801bfSmario.six@gdsys.cc 	/* Begin i2c read */
568c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
56949c801bfSmario.six@gdsys.cc 	/* Dummy read was accepted: receive byte, but NAK it. */
570306563a7SAlbert Aribaud 	if (status == 0)
571c68c6243Smario.six@gdsys.cc 		status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
572306563a7SAlbert Aribaud 	/* Stop transaction */
573c68c6243Smario.six@gdsys.cc 	twsi_stop(twsi, tick);
57449c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
575306563a7SAlbert Aribaud 	return status;
57601ec99d9SAlbert Aribaud }
57701ec99d9SAlbert Aribaud 
578306563a7SAlbert Aribaud /*
5796e677cafSmario.six@gdsys.cc  * __twsi_i2c_read() - Read data from a I2C chip.
5806e677cafSmario.six@gdsys.cc  *
5816e677cafSmario.six@gdsys.cc  * This function begins a I2C write transaction, and transmits the address
5826e677cafSmario.six@gdsys.cc  * bytes; then begins a I2C read transaction, and receives the data bytes.
583306563a7SAlbert Aribaud  *
58449c801bfSmario.six@gdsys.cc  * NOTE: Some devices want a stop right before the second start, while some
58549c801bfSmario.six@gdsys.cc  * will choke if it is there. Since deciding this is not yet supported in
58649c801bfSmario.six@gdsys.cc  * higher level APIs, we need to make a decision here, and for the moment that
58749c801bfSmario.six@gdsys.cc  * will be a repeated start without a preceding stop.
5886e677cafSmario.six@gdsys.cc  *
5896e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
5906e677cafSmario.six@gdsys.cc  * @chip:	The chip address to read from.
5916e677cafSmario.six@gdsys.cc  * @addr:	The address bytes to send.
5926e677cafSmario.six@gdsys.cc  * @alen:	The length of the address bytes in bytes.
5936e677cafSmario.six@gdsys.cc  * @data:	The buffer to receive the data read from the chip (has to have
5946e677cafSmario.six@gdsys.cc  *		a size of at least 'length' bytes).
5956e677cafSmario.six@gdsys.cc  * @length:	The amount of data to be read from the chip in bytes.
5966e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
5976e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5986e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
599306563a7SAlbert Aribaud  */
__twsi_i2c_read(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)6003c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
601c68c6243Smario.six@gdsys.cc 			   u8 *addr, int alen, uchar *data, int length,
602c68c6243Smario.six@gdsys.cc 			   uint tick)
60301ec99d9SAlbert Aribaud {
604059fce9fSmario.six@gdsys.cc 	int status = 0;
605059fce9fSmario.six@gdsys.cc 	int stop_status;
60624f9c6bbSmario.six@gdsys.cc 	int expected_start = MVTWSI_STATUS_START;
60701ec99d9SAlbert Aribaud 
60824f9c6bbSmario.six@gdsys.cc 	if (alen > 0) {
60949c801bfSmario.six@gdsys.cc 		/* Begin i2c write to send the address bytes */
610c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1), tick);
61149c801bfSmario.six@gdsys.cc 		/* Send address bytes */
612306563a7SAlbert Aribaud 		while ((status == 0) && alen--)
61303d6cd97SStefan Roese 			status = twsi_send(twsi, addr[alen],
614c68c6243Smario.six@gdsys.cc 					   MVTWSI_STATUS_DATA_W_ACK, tick);
61524f9c6bbSmario.six@gdsys.cc 		/* Send repeated STARTs after the initial START */
61624f9c6bbSmario.six@gdsys.cc 		expected_start = MVTWSI_STATUS_REPEATED_START;
61724f9c6bbSmario.six@gdsys.cc 	}
61849c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
619306563a7SAlbert Aribaud 	if (status == 0)
620c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
621670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
622670514f5Smario.six@gdsys.cc 	 * read */
623670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
6243c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
625670514f5Smario.six@gdsys.cc 				   length > 0 ?
626c68c6243Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
627306563a7SAlbert Aribaud 	/* Stop transaction */
628c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
62949c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
630059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
63101ec99d9SAlbert Aribaud }
63201ec99d9SAlbert Aribaud 
633306563a7SAlbert Aribaud /*
6346e677cafSmario.six@gdsys.cc  * __twsi_i2c_write() - Send data to a I2C chip.
6356e677cafSmario.six@gdsys.cc  *
6366e677cafSmario.six@gdsys.cc  * This function begins a I2C write transaction, and transmits the address
6376e677cafSmario.six@gdsys.cc  * bytes; then begins a new I2C write transaction, and sends the data bytes.
6386e677cafSmario.six@gdsys.cc  *
6396e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
6406e677cafSmario.six@gdsys.cc  * @chip:	The chip address to read from.
6416e677cafSmario.six@gdsys.cc  * @addr:	The address bytes to send.
6426e677cafSmario.six@gdsys.cc  * @alen:	The length of the address bytes in bytes.
6436e677cafSmario.six@gdsys.cc  * @data:	The buffer containing the data to be sent to the chip.
6446e677cafSmario.six@gdsys.cc  * @length:	The length of data to be sent to the chip in bytes.
6456e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
6466e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
6476e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
648306563a7SAlbert Aribaud  */
__twsi_i2c_write(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)6493c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
650c68c6243Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length,
651c68c6243Smario.six@gdsys.cc 			    uint tick)
65201ec99d9SAlbert Aribaud {
653059fce9fSmario.six@gdsys.cc 	int status, stop_status;
65401ec99d9SAlbert Aribaud 
65549c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
65649c801bfSmario.six@gdsys.cc 	 * data bytes */
657c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
65849c801bfSmario.six@gdsys.cc 	/* Send address bytes */
659f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
66003d6cd97SStefan Roese 		status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
661c68c6243Smario.six@gdsys.cc 				   tick);
66249c801bfSmario.six@gdsys.cc 	/* Send data bytes */
663306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
664c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
665c68c6243Smario.six@gdsys.cc 				   tick);
666306563a7SAlbert Aribaud 	/* Stop transaction */
667c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
66849c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
669059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
67001ec99d9SAlbert Aribaud }
67101ec99d9SAlbert Aribaud 
67214a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
twsi_i2c_init(struct i2c_adapter * adap,int speed,int slaveadd)67361bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
67461bc02b2Smario.six@gdsys.cc 			  int slaveadd)
67561bc02b2Smario.six@gdsys.cc {
6763c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
677c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd, NULL);
67861bc02b2Smario.six@gdsys.cc }
67961bc02b2Smario.six@gdsys.cc 
twsi_i2c_set_bus_speed(struct i2c_adapter * adap,uint requested_speed)68061bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
68161bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
68261bc02b2Smario.six@gdsys.cc {
6833c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
684c68c6243Smario.six@gdsys.cc 	__twsi_i2c_set_bus_speed(twsi, requested_speed);
685c68c6243Smario.six@gdsys.cc 	return 0;
68661bc02b2Smario.six@gdsys.cc }
68761bc02b2Smario.six@gdsys.cc 
twsi_i2c_probe(struct i2c_adapter * adap,uchar chip)68861bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
68961bc02b2Smario.six@gdsys.cc {
6903c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
691c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip, 10000);
69261bc02b2Smario.six@gdsys.cc }
69361bc02b2Smario.six@gdsys.cc 
twsi_i2c_read(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)69461bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
69561bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
69661bc02b2Smario.six@gdsys.cc {
6973c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
698f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
699f8a10ed1Smario.six@gdsys.cc 
700f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
701f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
702f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
703f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
704f8a10ed1Smario.six@gdsys.cc 
705c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
706c68c6243Smario.six@gdsys.cc 			       10000);
70761bc02b2Smario.six@gdsys.cc }
70861bc02b2Smario.six@gdsys.cc 
twsi_i2c_write(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)70961bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
71061bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
71161bc02b2Smario.six@gdsys.cc {
7123c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
713f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
714f8a10ed1Smario.six@gdsys.cc 
715f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
716f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
717f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
718f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
719f8a10ed1Smario.six@gdsys.cc 
720c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
721c68c6243Smario.six@gdsys.cc 				10000);
72261bc02b2Smario.six@gdsys.cc }
72361bc02b2Smario.six@gdsys.cc 
724dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
7250db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
7260db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
7270db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
7280db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
729dd82242bSPaul Kocialkowski #endif
730dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
731dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
732dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
733dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
734dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
735dd82242bSPaul Kocialkowski 
736dd82242bSPaul Kocialkowski #endif
737dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
738dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
739dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
740dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
741dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
742dd82242bSPaul Kocialkowski 
743dd82242bSPaul Kocialkowski #endif
744dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
745dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
746dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
747dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
748dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
749dd82242bSPaul Kocialkowski 
750dd82242bSPaul Kocialkowski #endif
751dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
752dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
753dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
754dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
755dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
756dd82242bSPaul Kocialkowski 
757dd82242bSPaul Kocialkowski #endif
7589d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
7599d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
7609d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
7619d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
7629d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
7639d082687SJelle van der Waa 
7649d082687SJelle van der Waa #endif
76514a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
76614a6ff2cSmario.six@gdsys.cc 
76714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
76814a6ff2cSmario.six@gdsys.cc 				 u32 chip_flags)
76914a6ff2cSmario.six@gdsys.cc {
77014a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
771c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
77214a6ff2cSmario.six@gdsys.cc }
77314a6ff2cSmario.six@gdsys.cc 
77414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
77514a6ff2cSmario.six@gdsys.cc {
77614a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
777c68c6243Smario.six@gdsys.cc 
778c68c6243Smario.six@gdsys.cc 	dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
779c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
780c68c6243Smario.six@gdsys.cc 
781c68c6243Smario.six@gdsys.cc 	return 0;
78214a6ff2cSmario.six@gdsys.cc }
78314a6ff2cSmario.six@gdsys.cc 
78414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
78514a6ff2cSmario.six@gdsys.cc {
78614a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
78714a6ff2cSmario.six@gdsys.cc 
788a821c4afSSimon Glass 	dev->base = devfdt_get_addr_ptr(bus);
78914a6ff2cSmario.six@gdsys.cc 
79014a6ff2cSmario.six@gdsys.cc 	if (!dev->base)
79114a6ff2cSmario.six@gdsys.cc 		return -ENOMEM;
79214a6ff2cSmario.six@gdsys.cc 
793e160f7d4SSimon Glass 	dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79414a6ff2cSmario.six@gdsys.cc 				    "cell-index", -1);
795e160f7d4SSimon Glass 	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79614a6ff2cSmario.six@gdsys.cc 				       "u-boot,i2c-slave-addr", 0x0);
797e160f7d4SSimon Glass 	dev->speed = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79814a6ff2cSmario.six@gdsys.cc 				    "clock-frequency", 100000);
79914a6ff2cSmario.six@gdsys.cc 	return 0;
80014a6ff2cSmario.six@gdsys.cc }
80114a6ff2cSmario.six@gdsys.cc 
802*173ec351SBaruch Siach static void twsi_disable_i2c_slave(struct mvtwsi_registers *twsi)
803*173ec351SBaruch Siach {
804*173ec351SBaruch Siach 	clrbits_le32(&twsi->debug, BIT(18));
805*173ec351SBaruch Siach }
806*173ec351SBaruch Siach 
807*173ec351SBaruch Siach static int mvtwsi_i2c_bind(struct udevice *bus)
808*173ec351SBaruch Siach {
809*173ec351SBaruch Siach 	struct mvtwsi_registers *twsi = devfdt_get_addr_ptr(bus);
810*173ec351SBaruch Siach 
811*173ec351SBaruch Siach 	/* Disable the hidden slave in i2c0 of these platforms */
812*173ec351SBaruch Siach 	if ((IS_ENABLED(CONFIG_ARMADA_38X) || IS_ENABLED(CONFIG_KIRKWOOD))
813*173ec351SBaruch Siach 			&& bus->req_seq == 0)
814*173ec351SBaruch Siach 		twsi_disable_i2c_slave(twsi);
815*173ec351SBaruch Siach 
816*173ec351SBaruch Siach 	return 0;
817*173ec351SBaruch Siach }
818*173ec351SBaruch Siach 
81914a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
82014a6ff2cSmario.six@gdsys.cc {
82114a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
822c68c6243Smario.six@gdsys.cc 	uint actual_speed;
823c68c6243Smario.six@gdsys.cc 
824c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
825c68c6243Smario.six@gdsys.cc 	dev->speed = actual_speed;
826c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
82714a6ff2cSmario.six@gdsys.cc 	return 0;
82814a6ff2cSmario.six@gdsys.cc }
82914a6ff2cSmario.six@gdsys.cc 
83014a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
83114a6ff2cSmario.six@gdsys.cc {
83214a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
83314a6ff2cSmario.six@gdsys.cc 	struct i2c_msg *dmsg, *omsg, dummy;
83414a6ff2cSmario.six@gdsys.cc 
83514a6ff2cSmario.six@gdsys.cc 	memset(&dummy, 0, sizeof(struct i2c_msg));
83614a6ff2cSmario.six@gdsys.cc 
83714a6ff2cSmario.six@gdsys.cc 	/* We expect either two messages (one with an offset and one with the
83814a6ff2cSmario.six@gdsys.cc 	 * actual data) or one message (just data or offset/data combined) */
83914a6ff2cSmario.six@gdsys.cc 	if (nmsgs > 2 || nmsgs == 0) {
84014a6ff2cSmario.six@gdsys.cc 		debug("%s: Only one or two messages are supported.", __func__);
84114a6ff2cSmario.six@gdsys.cc 		return -1;
84214a6ff2cSmario.six@gdsys.cc 	}
84314a6ff2cSmario.six@gdsys.cc 
84414a6ff2cSmario.six@gdsys.cc 	omsg = nmsgs == 1 ? &dummy : msg;
84514a6ff2cSmario.six@gdsys.cc 	dmsg = nmsgs == 1 ? msg : msg + 1;
84614a6ff2cSmario.six@gdsys.cc 
84714a6ff2cSmario.six@gdsys.cc 	if (dmsg->flags & I2C_M_RD)
84814a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
849c68c6243Smario.six@gdsys.cc 				       omsg->len, dmsg->buf, dmsg->len,
850c68c6243Smario.six@gdsys.cc 				       dev->tick);
85114a6ff2cSmario.six@gdsys.cc 	else
85214a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
853c68c6243Smario.six@gdsys.cc 					omsg->len, dmsg->buf, dmsg->len,
854c68c6243Smario.six@gdsys.cc 					dev->tick);
85514a6ff2cSmario.six@gdsys.cc }
85614a6ff2cSmario.six@gdsys.cc 
85714a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
85814a6ff2cSmario.six@gdsys.cc 	.xfer		= mvtwsi_i2c_xfer,
85914a6ff2cSmario.six@gdsys.cc 	.probe_chip	= mvtwsi_i2c_probe_chip,
86014a6ff2cSmario.six@gdsys.cc 	.set_bus_speed	= mvtwsi_i2c_set_bus_speed,
86114a6ff2cSmario.six@gdsys.cc };
86214a6ff2cSmario.six@gdsys.cc 
86314a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
86414a6ff2cSmario.six@gdsys.cc 	{ .compatible = "marvell,mv64xxx-i2c", },
86587de0eb3SStefan Roese 	{ .compatible = "marvell,mv78230-i2c", },
866a8f01ccfSJernej Skrabec 	{ .compatible = "allwinner,sun6i-a31-i2c", },
86714a6ff2cSmario.six@gdsys.cc 	{ /* sentinel */ }
86814a6ff2cSmario.six@gdsys.cc };
86914a6ff2cSmario.six@gdsys.cc 
87014a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
87114a6ff2cSmario.six@gdsys.cc 	.name = "i2c_mvtwsi",
87214a6ff2cSmario.six@gdsys.cc 	.id = UCLASS_I2C,
87314a6ff2cSmario.six@gdsys.cc 	.of_match = mvtwsi_i2c_ids,
874*173ec351SBaruch Siach 	.bind = mvtwsi_i2c_bind,
87514a6ff2cSmario.six@gdsys.cc 	.probe = mvtwsi_i2c_probe,
87614a6ff2cSmario.six@gdsys.cc 	.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
87714a6ff2cSmario.six@gdsys.cc 	.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
87814a6ff2cSmario.six@gdsys.cc 	.ops = &mvtwsi_i2c_ops,
87914a6ff2cSmario.six@gdsys.cc };
88014a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
881