xref: /rk3399_rockchip-uboot/drivers/i2c/mvtwsi.c (revision c68c624320e315ec79e78fef1d7baaaa3c64b790)
101ec99d9SAlbert Aribaud /*
2306563a7SAlbert Aribaud  * Driver for the TWSI (i2c) controller found on the Marvell
3306563a7SAlbert Aribaud  * orion5x and kirkwood SoC families.
401ec99d9SAlbert Aribaud  *
557b4bce9SAlbert ARIBAUD  * Author: Albert Aribaud <albert.u.boot@aribaud.net>
6306563a7SAlbert Aribaud  * Copyright (c) 2010 Albert Aribaud.
701ec99d9SAlbert Aribaud  *
81a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
901ec99d9SAlbert Aribaud  */
10306563a7SAlbert Aribaud 
1101ec99d9SAlbert Aribaud #include <common.h>
1201ec99d9SAlbert Aribaud #include <i2c.h>
1301ec99d9SAlbert Aribaud #include <asm/errno.h>
1401ec99d9SAlbert Aribaud #include <asm/io.h>
15*c68c6243Smario.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>
326620377eSHans de Goede #elif defined(CONFIG_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 /*
40306563a7SAlbert Aribaud  * TWSI register structure
4101ec99d9SAlbert Aribaud  */
4201ec99d9SAlbert Aribaud 
436620377eSHans de Goede #ifdef CONFIG_SUNXI
446620377eSHans de Goede 
456620377eSHans de Goede struct  mvtwsi_registers {
466620377eSHans de Goede 	u32 slave_address;
476620377eSHans de Goede 	u32 xtnd_slave_addr;
486620377eSHans de Goede 	u32 data;
496620377eSHans de Goede 	u32 control;
506620377eSHans de Goede 	u32 status;
516620377eSHans de Goede 	u32 baudrate;
526620377eSHans de Goede 	u32 soft_reset;
536620377eSHans de Goede };
546620377eSHans de Goede 
556620377eSHans de Goede #else
566620377eSHans de Goede 
57306563a7SAlbert Aribaud struct  mvtwsi_registers {
58306563a7SAlbert Aribaud 	u32 slave_address;
59306563a7SAlbert Aribaud 	u32 data;
60306563a7SAlbert Aribaud 	u32 control;
61306563a7SAlbert Aribaud 	union {
6249c801bfSmario.six@gdsys.cc 		u32 status;	/* When reading */
6349c801bfSmario.six@gdsys.cc 		u32 baudrate;	/* When writing */
64306563a7SAlbert Aribaud 	};
65306563a7SAlbert Aribaud 	u32 xtnd_slave_addr;
66306563a7SAlbert Aribaud 	u32 reserved[2];
67306563a7SAlbert Aribaud 	u32 soft_reset;
68306563a7SAlbert Aribaud };
69306563a7SAlbert Aribaud 
706620377eSHans de Goede #endif
716620377eSHans de Goede 
7214a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
7314a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
7414a6ff2cSmario.six@gdsys.cc 	/* TWSI Register base for the device */
7514a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_registers *base;
7614a6ff2cSmario.six@gdsys.cc 	/* Number of the device (determined from cell-index property) */
7714a6ff2cSmario.six@gdsys.cc 	int index;
7814a6ff2cSmario.six@gdsys.cc 	/* The I2C slave address for the device */
7914a6ff2cSmario.six@gdsys.cc 	u8 slaveadd;
8014a6ff2cSmario.six@gdsys.cc 	/* The configured I2C speed in Hz */
8114a6ff2cSmario.six@gdsys.cc 	uint speed;
82*c68c6243Smario.six@gdsys.cc 	/* The current length of a clock period (depending on speed) */
83*c68c6243Smario.six@gdsys.cc 	uint tick;
8414a6ff2cSmario.six@gdsys.cc };
8514a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
8614a6ff2cSmario.six@gdsys.cc 
87306563a7SAlbert Aribaud /*
88dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
89dfc3958cSmario.six@gdsys.cc  * register
90306563a7SAlbert Aribaud  */
91dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
92dfc3958cSmario.six@gdsys.cc 	/* Acknowledge bit */
93dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_ACK	= 0x00000004,
94dfc3958cSmario.six@gdsys.cc 	/* Interrupt flag */
95dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_IFLG	= 0x00000008,
96dfc3958cSmario.six@gdsys.cc 	/* Stop bit */
97dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_STOP	= 0x00000010,
98dfc3958cSmario.six@gdsys.cc 	/* Start bit */
99dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_START	= 0x00000020,
100dfc3958cSmario.six@gdsys.cc 	/* I2C enable */
101dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_TWSIEN	= 0x00000040,
102dfc3958cSmario.six@gdsys.cc 	/* Interrupt enable */
103dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_INTEN	= 0x00000080,
104dfc3958cSmario.six@gdsys.cc };
105306563a7SAlbert Aribaud 
106306563a7SAlbert Aribaud /*
10749c801bfSmario.six@gdsys.cc  * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
10849c801bfSmario.six@gdsys.cc  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
109904dfbfdSHans de Goede  */
110904dfbfdSHans de Goede 
111904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
112904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
113904dfbfdSHans de Goede #else
114904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
115904dfbfdSHans de Goede #endif
116904dfbfdSHans de Goede 
117904dfbfdSHans de Goede /*
118dfc3958cSmario.six@gdsys.cc  * enum mvstwsi_status_values - Possible values of I2C controller's status
119dfc3958cSmario.six@gdsys.cc  * register
120dfc3958cSmario.six@gdsys.cc  *
121dfc3958cSmario.six@gdsys.cc  * Only those statuses expected in normal master operation on
122dfc3958cSmario.six@gdsys.cc  * non-10-bit-address devices are specified.
123dfc3958cSmario.six@gdsys.cc  *
124dfc3958cSmario.six@gdsys.cc  * Every status that's unexpected during normal operation (bus errors,
125dfc3958cSmario.six@gdsys.cc  * arbitration losses, missing ACKs...) is passed back to the caller as an error
126306563a7SAlbert Aribaud  * code.
127306563a7SAlbert Aribaud  */
128dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
129dfc3958cSmario.six@gdsys.cc 	/* START condition transmitted */
130dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_START		= 0x08,
131dfc3958cSmario.six@gdsys.cc 	/* Repeated START condition transmitted */
132dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_REPEATED_START	= 0x10,
133dfc3958cSmario.six@gdsys.cc 	/* Address + write bit transmitted, ACK received */
134dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_W_ACK	= 0x18,
135dfc3958cSmario.six@gdsys.cc 	/* Data transmitted, ACK received */
136dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_W_ACK	= 0x28,
137dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK received */
138dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_ACK	= 0x40,
139dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK not received */
140dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_NAK	= 0x48,
141dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK transmitted */
142dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_ACK	= 0x50,
143dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK not transmitted */
144dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_NAK	= 0x58,
145dfc3958cSmario.six@gdsys.cc 	/* No relevant status */
146dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_IDLE		= 0xF8,
147dfc3958cSmario.six@gdsys.cc };
148306563a7SAlbert Aribaud 
149306563a7SAlbert Aribaud /*
150670514f5Smario.six@gdsys.cc  * enum mvstwsi_ack_flags - Determine whether a read byte should be
151670514f5Smario.six@gdsys.cc  * acknowledged or not.
152670514f5Smario.six@gdsys.cc  */
153670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
154670514f5Smario.six@gdsys.cc 	/* Send NAK after received byte */
155670514f5Smario.six@gdsys.cc 	MVTWSI_READ_NAK = 0,
156670514f5Smario.six@gdsys.cc 	/* Send ACK after received byte */
157670514f5Smario.six@gdsys.cc 	MVTWSI_READ_ACK = 1,
158670514f5Smario.six@gdsys.cc };
159670514f5Smario.six@gdsys.cc 
160*c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed)
161*c68c6243Smario.six@gdsys.cc {
162*c68c6243Smario.six@gdsys.cc 	/* One tick = the duration of a period at the specified speed in ns (we
163*c68c6243Smario.six@gdsys.cc 	 * add 100 ns to be on the safe side) */
164*c68c6243Smario.six@gdsys.cc 	return (1000000000u / speed) + 100;
165*c68c6243Smario.six@gdsys.cc }
166*c68c6243Smario.six@gdsys.cc 
16714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
168*c68c6243Smario.six@gdsys.cc 
169670514f5Smario.six@gdsys.cc /*
170dd82242bSPaul Kocialkowski  * MVTWSI controller base
171306563a7SAlbert Aribaud  */
172306563a7SAlbert Aribaud 
173dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
174dd82242bSPaul Kocialkowski {
175dd82242bSPaul Kocialkowski 	switch (adap->hwadapnr) {
176dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
177dd82242bSPaul Kocialkowski 	case 0:
178dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
179dd82242bSPaul Kocialkowski #endif
180dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
181dd82242bSPaul Kocialkowski 	case 1:
182dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
183dd82242bSPaul Kocialkowski #endif
184dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
185dd82242bSPaul Kocialkowski 	case 2:
186dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
187dd82242bSPaul Kocialkowski #endif
188dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
189dd82242bSPaul Kocialkowski 	case 3:
190dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
191dd82242bSPaul Kocialkowski #endif
192dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
193dd82242bSPaul Kocialkowski 	case 4:
194dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
195dd82242bSPaul Kocialkowski #endif
1969d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
1979d082687SJelle van der Waa 	case 5:
1989d082687SJelle van der Waa 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
1999d082687SJelle van der Waa #endif
200dd82242bSPaul Kocialkowski 	default:
201dd82242bSPaul Kocialkowski 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
202dd82242bSPaul Kocialkowski 		break;
203dd82242bSPaul Kocialkowski 	}
204dd82242bSPaul Kocialkowski 
205dd82242bSPaul Kocialkowski 	return NULL;
206dd82242bSPaul Kocialkowski }
20714a6ff2cSmario.six@gdsys.cc #endif
208306563a7SAlbert Aribaud 
209306563a7SAlbert Aribaud /*
210dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_error_class - types of I2C errors
211306563a7SAlbert Aribaud  */
212dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
213dfc3958cSmario.six@gdsys.cc 	/* The controller returned a different status than expected */
214dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_WRONG_STATUS       = 0x01,
215dfc3958cSmario.six@gdsys.cc 	/* The controller timed out */
216dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_TIMEOUT            = 0x02,
217dfc3958cSmario.six@gdsys.cc };
218306563a7SAlbert Aribaud 
219dfc3958cSmario.six@gdsys.cc /*
220dfc3958cSmario.six@gdsys.cc  * mvtwsi_error() - Build I2C return code from error information
221dfc3958cSmario.six@gdsys.cc  *
222dfc3958cSmario.six@gdsys.cc  * For debugging purposes, this function packs some information of an occurred
223dfc3958cSmario.six@gdsys.cc  * error into a return code. These error codes are returned from I2C API
224dfc3958cSmario.six@gdsys.cc  * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
225dfc3958cSmario.six@gdsys.cc  *
226dfc3958cSmario.six@gdsys.cc  * @ec:		The error class of the error (enum mvtwsi_error_class).
227dfc3958cSmario.six@gdsys.cc  * @lc:		The last value of the control register.
228dfc3958cSmario.six@gdsys.cc  * @ls:		The last value of the status register.
229dfc3958cSmario.six@gdsys.cc  * @es:		The expected value of the status register.
230dfc3958cSmario.six@gdsys.cc  * @return The generated error code.
231dfc3958cSmario.six@gdsys.cc  */
232dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
233dfc3958cSmario.six@gdsys.cc {
234dfc3958cSmario.six@gdsys.cc 	return ((ec << 24) & 0xFF000000)
235dfc3958cSmario.six@gdsys.cc 	       | ((lc << 16) & 0x00FF0000)
236dfc3958cSmario.six@gdsys.cc 	       | ((ls << 8) & 0x0000FF00)
237dfc3958cSmario.six@gdsys.cc 	       | (es & 0xFF);
238dfc3958cSmario.six@gdsys.cc }
239306563a7SAlbert Aribaud 
240306563a7SAlbert Aribaud /*
24149c801bfSmario.six@gdsys.cc  * Wait for IFLG to raise, or return 'timeout.' Then, if the status is as
24249c801bfSmario.six@gdsys.cc  * expected, return 0 (ok) or 'wrong status' otherwise.
243306563a7SAlbert Aribaud  */
244*c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
245*c68c6243Smario.six@gdsys.cc 		     uint tick)
24601ec99d9SAlbert Aribaud {
247306563a7SAlbert Aribaud 	int control, status;
248306563a7SAlbert Aribaud 	int timeout = 1000;
249306563a7SAlbert Aribaud 
250306563a7SAlbert Aribaud 	do {
251306563a7SAlbert Aribaud 		control = readl(&twsi->control);
252306563a7SAlbert Aribaud 		if (control & MVTWSI_CONTROL_IFLG) {
253306563a7SAlbert Aribaud 			status = readl(&twsi->status);
254306563a7SAlbert Aribaud 			if (status == expected_status)
255306563a7SAlbert Aribaud 				return 0;
25601ec99d9SAlbert Aribaud 			else
257dfc3958cSmario.six@gdsys.cc 				return mvtwsi_error(
258306563a7SAlbert Aribaud 					MVTWSI_ERROR_WRONG_STATUS,
259306563a7SAlbert Aribaud 					control, status, expected_status);
260306563a7SAlbert Aribaud 		}
261*c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
262306563a7SAlbert Aribaud 	} while (timeout--);
263306563a7SAlbert Aribaud 	status = readl(&twsi->status);
264dfc3958cSmario.six@gdsys.cc 	return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
265dfc3958cSmario.six@gdsys.cc 			    expected_status);
26601ec99d9SAlbert Aribaud }
26701ec99d9SAlbert Aribaud 
268306563a7SAlbert Aribaud /*
269306563a7SAlbert Aribaud  * Assert the START condition, either in a single I2C transaction
270306563a7SAlbert Aribaud  * or inside back-to-back ones (repeated starts).
271306563a7SAlbert Aribaud  */
272*c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
273*c68c6243Smario.six@gdsys.cc 		      uint tick)
274306563a7SAlbert Aribaud {
27549c801bfSmario.six@gdsys.cc 	/* Assert START */
276670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
2772ca02995SHans de Goede 	       MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
27849c801bfSmario.six@gdsys.cc 	/* Wait for controller to process START */
279*c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
280306563a7SAlbert Aribaud }
281306563a7SAlbert Aribaud 
282306563a7SAlbert Aribaud /*
283306563a7SAlbert Aribaud  * Send a byte (i2c address or data).
284306563a7SAlbert Aribaud  */
2853c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
286*c68c6243Smario.six@gdsys.cc 		     int expected_status, uint tick)
287306563a7SAlbert Aribaud {
28849c801bfSmario.six@gdsys.cc 	/* Write byte to data register for sending */
289306563a7SAlbert Aribaud 	writel(byte, &twsi->data);
29049c801bfSmario.six@gdsys.cc 	/* Clear any pending interrupt -- that will cause sending */
291670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
292670514f5Smario.six@gdsys.cc 	       &twsi->control);
29349c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and check ACK */
294*c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
295306563a7SAlbert Aribaud }
296306563a7SAlbert Aribaud 
297306563a7SAlbert Aribaud /*
298306563a7SAlbert Aribaud  * Receive a byte.
299306563a7SAlbert Aribaud  */
300*c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
301*c68c6243Smario.six@gdsys.cc 		     uint tick)
302306563a7SAlbert Aribaud {
303670514f5Smario.six@gdsys.cc 	int expected_status, status, control;
304306563a7SAlbert Aribaud 
305670514f5Smario.six@gdsys.cc 	/* Compute expected status based on passed ACK flag */
306670514f5Smario.six@gdsys.cc 	expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
307670514f5Smario.six@gdsys.cc 			  MVTWSI_STATUS_DATA_R_NAK;
30849c801bfSmario.six@gdsys.cc 	/* Acknowledge *previous state*, and launch receive */
309670514f5Smario.six@gdsys.cc 	control = MVTWSI_CONTROL_TWSIEN;
310670514f5Smario.six@gdsys.cc 	control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
311670514f5Smario.six@gdsys.cc 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
31249c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and assert ACK or NAK */
313*c68c6243Smario.six@gdsys.cc 	status = twsi_wait(twsi, expected_status, tick);
31449c801bfSmario.six@gdsys.cc 	/* If we did receive the expected byte, store it */
315306563a7SAlbert Aribaud 	if (status == 0)
316306563a7SAlbert Aribaud 		*byte = readl(&twsi->data);
317306563a7SAlbert Aribaud 	return status;
318306563a7SAlbert Aribaud }
319306563a7SAlbert Aribaud 
320306563a7SAlbert Aribaud /*
321306563a7SAlbert Aribaud  * Assert the STOP condition.
32249c801bfSmario.six@gdsys.cc  * This is also used to force the bus back to idle (SDA = SCL = 1).
323306563a7SAlbert Aribaud  */
324*c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
325306563a7SAlbert Aribaud {
326306563a7SAlbert Aribaud 	int control, stop_status;
327059fce9fSmario.six@gdsys.cc 	int status = 0;
328306563a7SAlbert Aribaud 	int timeout = 1000;
329306563a7SAlbert Aribaud 
33049c801bfSmario.six@gdsys.cc 	/* Assert STOP */
331306563a7SAlbert Aribaud 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
332904dfbfdSHans de Goede 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
33349c801bfSmario.six@gdsys.cc 	/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
334306563a7SAlbert Aribaud 	do {
335306563a7SAlbert Aribaud 		stop_status = readl(&twsi->status);
336306563a7SAlbert Aribaud 		if (stop_status == MVTWSI_STATUS_IDLE)
337306563a7SAlbert Aribaud 			break;
338*c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
339306563a7SAlbert Aribaud 	} while (timeout--);
340306563a7SAlbert Aribaud 	control = readl(&twsi->control);
341306563a7SAlbert Aribaud 	if (stop_status != MVTWSI_STATUS_IDLE)
342059fce9fSmario.six@gdsys.cc 		status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
343306563a7SAlbert Aribaud 				      control, status, MVTWSI_STATUS_IDLE);
344306563a7SAlbert Aribaud 	return status;
345306563a7SAlbert Aribaud }
346306563a7SAlbert Aribaud 
347e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
348f582a158SStefan Roese {
349f582a158SStefan Roese #ifdef CONFIG_SUNXI
350f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
351f582a158SStefan Roese #else
352f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
353f582a158SStefan Roese #endif
354f582a158SStefan Roese }
355306563a7SAlbert Aribaud 
356306563a7SAlbert Aribaud /*
357306563a7SAlbert Aribaud  * Reset controller.
358306563a7SAlbert Aribaud  * Controller reset also resets the baud rate and slave address, so
3590db2bbdcSHans de Goede  * they must be re-established afterwards.
360306563a7SAlbert Aribaud  */
3613c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
362306563a7SAlbert Aribaud {
36349c801bfSmario.six@gdsys.cc 	/* Reset controller */
364306563a7SAlbert Aribaud 	writel(0, &twsi->soft_reset);
36549c801bfSmario.six@gdsys.cc 	/* Wait 2 ms -- this is what the Marvell LSP does */
366306563a7SAlbert Aribaud 	udelay(20000);
367306563a7SAlbert Aribaud }
368306563a7SAlbert Aribaud 
369306563a7SAlbert Aribaud /*
37049c801bfSmario.six@gdsys.cc  * Sets baud to the highest possible value not exceeding the requested one.
371306563a7SAlbert Aribaud  */
3723c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
373e0758281Smario.six@gdsys.cc 				     uint requested_speed)
374306563a7SAlbert Aribaud {
375e0758281Smario.six@gdsys.cc 	uint tmp_speed, highest_speed, n, m;
376e0758281Smario.six@gdsys.cc 	uint baud = 0x44; /* Baud rate after controller reset */
377306563a7SAlbert Aribaud 
378306563a7SAlbert Aribaud 	highest_speed = 0;
37949c801bfSmario.six@gdsys.cc 	/* Successively try m, n combinations, and use the combination
38049c801bfSmario.six@gdsys.cc 	 * resulting in the largest speed that's not above the requested
38149c801bfSmario.six@gdsys.cc 	 * speed */
38201ec99d9SAlbert Aribaud 	for (n = 0; n < 8; n++) {
38301ec99d9SAlbert Aribaud 		for (m = 0; m < 16; m++) {
384f582a158SStefan Roese 			tmp_speed = twsi_calc_freq(n, m);
3859ec43b0cSmario.six@gdsys.cc 			if ((tmp_speed <= requested_speed) &&
3869ec43b0cSmario.six@gdsys.cc 			    (tmp_speed > highest_speed)) {
387306563a7SAlbert Aribaud 				highest_speed = tmp_speed;
388306563a7SAlbert Aribaud 				baud = (m << 3) | n;
38901ec99d9SAlbert Aribaud 			}
39001ec99d9SAlbert Aribaud 		}
39101ec99d9SAlbert Aribaud 	}
3920db2bbdcSHans de Goede 	writel(baud, &twsi->baudrate);
393*c68c6243Smario.six@gdsys.cc 
394*c68c6243Smario.six@gdsys.cc 	/* Wait for controller for one tick */
395*c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
396*c68c6243Smario.six@gdsys.cc 	ndelay(calc_tick(highest_speed));
397*c68c6243Smario.six@gdsys.cc #else
398*c68c6243Smario.six@gdsys.cc 	ndelay(10000);
399*c68c6243Smario.six@gdsys.cc #endif
400*c68c6243Smario.six@gdsys.cc 	return highest_speed;
4010db2bbdcSHans de Goede }
4020db2bbdcSHans de Goede 
4033c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
404*c68c6243Smario.six@gdsys.cc 			    int slaveadd, uint *actual_speed)
4050db2bbdcSHans de Goede {
40649c801bfSmario.six@gdsys.cc 	/* Reset controller */
4073c4db636Smario.six@gdsys.cc 	twsi_reset(twsi);
40849c801bfSmario.six@gdsys.cc 	/* Set speed */
409*c68c6243Smario.six@gdsys.cc 	*actual_speed = __twsi_i2c_set_bus_speed(twsi, speed);
41049c801bfSmario.six@gdsys.cc 	/* Set slave address; even though we don't use it */
4110db2bbdcSHans de Goede 	writel(slaveadd, &twsi->slave_address);
4120db2bbdcSHans de Goede 	writel(0, &twsi->xtnd_slave_addr);
41349c801bfSmario.six@gdsys.cc 	/* Assert STOP, but don't care for the result */
414*c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
415*c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, calc_tick(*actual_speed));
416*c68c6243Smario.six@gdsys.cc #else
417*c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, 10000);
418*c68c6243Smario.six@gdsys.cc #endif
41901ec99d9SAlbert Aribaud }
42001ec99d9SAlbert Aribaud 
42101ec99d9SAlbert Aribaud /*
422306563a7SAlbert Aribaud  * Begin I2C transaction with expected start status, at given address.
423306563a7SAlbert Aribaud  * Expected address status will derive from direction bit (bit 0) in addr.
42401ec99d9SAlbert Aribaud  */
4253c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
426*c68c6243Smario.six@gdsys.cc 		     u8 addr, uint tick)
42701ec99d9SAlbert Aribaud {
428306563a7SAlbert Aribaud 	int status, expected_addr_status;
42901ec99d9SAlbert Aribaud 
43049c801bfSmario.six@gdsys.cc 	/* Compute the expected address status from the direction bit in
43149c801bfSmario.six@gdsys.cc 	 * the address byte */
43249c801bfSmario.six@gdsys.cc 	if (addr & 1) /* Reading */
433306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
43449c801bfSmario.six@gdsys.cc 	else /* Writing */
435306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
43649c801bfSmario.six@gdsys.cc 	/* Assert START */
437*c68c6243Smario.six@gdsys.cc 	status = twsi_start(twsi, expected_start_status, tick);
43849c801bfSmario.six@gdsys.cc 	/* Send out the address if the start went well */
439306563a7SAlbert Aribaud 	if (status == 0)
440*c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, addr, expected_addr_status, tick);
44149c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
442306563a7SAlbert Aribaud 	return status;
44301ec99d9SAlbert Aribaud }
44401ec99d9SAlbert Aribaud 
445306563a7SAlbert Aribaud /*
446306563a7SAlbert Aribaud  * Begin read, nak data byte, end.
447306563a7SAlbert Aribaud  */
448*c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
449*c68c6243Smario.six@gdsys.cc 				 uint tick)
45001ec99d9SAlbert Aribaud {
451306563a7SAlbert Aribaud 	u8 dummy_byte;
452306563a7SAlbert Aribaud 	int status;
45301ec99d9SAlbert Aribaud 
45449c801bfSmario.six@gdsys.cc 	/* Begin i2c read */
455*c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
45649c801bfSmario.six@gdsys.cc 	/* Dummy read was accepted: receive byte, but NAK it. */
457306563a7SAlbert Aribaud 	if (status == 0)
458*c68c6243Smario.six@gdsys.cc 		status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
459306563a7SAlbert Aribaud 	/* Stop transaction */
460*c68c6243Smario.six@gdsys.cc 	twsi_stop(twsi, tick);
46149c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
462306563a7SAlbert Aribaud 	return status;
46301ec99d9SAlbert Aribaud }
46401ec99d9SAlbert Aribaud 
465306563a7SAlbert Aribaud /*
466306563a7SAlbert Aribaud  * Begin write, send address byte(s), begin read, receive data bytes, end.
467306563a7SAlbert Aribaud  *
46849c801bfSmario.six@gdsys.cc  * NOTE: Some devices want a stop right before the second start, while some
46949c801bfSmario.six@gdsys.cc  * will choke if it is there. Since deciding this is not yet supported in
47049c801bfSmario.six@gdsys.cc  * higher level APIs, we need to make a decision here, and for the moment that
47149c801bfSmario.six@gdsys.cc  * will be a repeated start without a preceding stop.
472306563a7SAlbert Aribaud  */
4733c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
474*c68c6243Smario.six@gdsys.cc 			   u8 *addr, int alen, uchar *data, int length,
475*c68c6243Smario.six@gdsys.cc 			   uint tick)
47601ec99d9SAlbert Aribaud {
477059fce9fSmario.six@gdsys.cc 	int status = 0;
478059fce9fSmario.six@gdsys.cc 	int stop_status;
47924f9c6bbSmario.six@gdsys.cc 	int expected_start = MVTWSI_STATUS_START;
48001ec99d9SAlbert Aribaud 
48124f9c6bbSmario.six@gdsys.cc 	if (alen > 0) {
48249c801bfSmario.six@gdsys.cc 		/* Begin i2c write to send the address bytes */
483*c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1), tick);
48449c801bfSmario.six@gdsys.cc 		/* Send address bytes */
485306563a7SAlbert Aribaud 		while ((status == 0) && alen--)
48624f9c6bbSmario.six@gdsys.cc 			status = twsi_send(twsi, *(addr++),
487*c68c6243Smario.six@gdsys.cc 					   MVTWSI_STATUS_DATA_W_ACK, tick);
48824f9c6bbSmario.six@gdsys.cc 		/* Send repeated STARTs after the initial START */
48924f9c6bbSmario.six@gdsys.cc 		expected_start = MVTWSI_STATUS_REPEATED_START;
49024f9c6bbSmario.six@gdsys.cc 	}
49149c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
492306563a7SAlbert Aribaud 	if (status == 0)
493*c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
494670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
495670514f5Smario.six@gdsys.cc 	 * read */
496670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
4973c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
498670514f5Smario.six@gdsys.cc 				   length > 0 ?
499*c68c6243Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
500306563a7SAlbert Aribaud 	/* Stop transaction */
501*c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
50249c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
503059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
50401ec99d9SAlbert Aribaud }
50501ec99d9SAlbert Aribaud 
506306563a7SAlbert Aribaud /*
507306563a7SAlbert Aribaud  * Begin write, send address byte(s), send data bytes, end.
508306563a7SAlbert Aribaud  */
5093c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
510*c68c6243Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length,
511*c68c6243Smario.six@gdsys.cc 			    uint tick)
51201ec99d9SAlbert Aribaud {
513059fce9fSmario.six@gdsys.cc 	int status, stop_status;
51401ec99d9SAlbert Aribaud 
51549c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
51649c801bfSmario.six@gdsys.cc 	 * data bytes */
517*c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
51849c801bfSmario.six@gdsys.cc 	/* Send address bytes */
519f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
520*c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK,
521*c68c6243Smario.six@gdsys.cc 				   tick);
52249c801bfSmario.six@gdsys.cc 	/* Send data bytes */
523306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
524*c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
525*c68c6243Smario.six@gdsys.cc 				   tick);
526306563a7SAlbert Aribaud 	/* Stop transaction */
527*c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
52849c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
529059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
53001ec99d9SAlbert Aribaud }
53101ec99d9SAlbert Aribaud 
53214a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
53361bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
53461bc02b2Smario.six@gdsys.cc 			  int slaveadd)
53561bc02b2Smario.six@gdsys.cc {
5363c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
537*c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd, NULL);
53861bc02b2Smario.six@gdsys.cc }
53961bc02b2Smario.six@gdsys.cc 
54061bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
54161bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
54261bc02b2Smario.six@gdsys.cc {
5433c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
544*c68c6243Smario.six@gdsys.cc 	__twsi_i2c_set_bus_speed(twsi, requested_speed);
545*c68c6243Smario.six@gdsys.cc 	return 0;
54661bc02b2Smario.six@gdsys.cc }
54761bc02b2Smario.six@gdsys.cc 
54861bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
54961bc02b2Smario.six@gdsys.cc {
5503c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
551*c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip, 10000);
55261bc02b2Smario.six@gdsys.cc }
55361bc02b2Smario.six@gdsys.cc 
55461bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
55561bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
55661bc02b2Smario.six@gdsys.cc {
5573c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
558f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
559f8a10ed1Smario.six@gdsys.cc 
560f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
561f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
562f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
563f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
564f8a10ed1Smario.six@gdsys.cc 
565*c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
566*c68c6243Smario.six@gdsys.cc 			       10000);
56761bc02b2Smario.six@gdsys.cc }
56861bc02b2Smario.six@gdsys.cc 
56961bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
57061bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
57161bc02b2Smario.six@gdsys.cc {
5723c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
573f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
574f8a10ed1Smario.six@gdsys.cc 
575f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
576f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
577f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
578f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
579f8a10ed1Smario.six@gdsys.cc 
580*c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
581*c68c6243Smario.six@gdsys.cc 				10000);
58261bc02b2Smario.six@gdsys.cc }
58361bc02b2Smario.six@gdsys.cc 
584dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
5850db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
5860db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
5870db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
5880db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
589dd82242bSPaul Kocialkowski #endif
590dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
591dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
592dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
593dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
594dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
595dd82242bSPaul Kocialkowski 
596dd82242bSPaul Kocialkowski #endif
597dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
598dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
599dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
600dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
601dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
602dd82242bSPaul Kocialkowski 
603dd82242bSPaul Kocialkowski #endif
604dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
605dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
606dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
607dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
608dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
609dd82242bSPaul Kocialkowski 
610dd82242bSPaul Kocialkowski #endif
611dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
612dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
613dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
614dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
615dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
616dd82242bSPaul Kocialkowski 
617dd82242bSPaul Kocialkowski #endif
6189d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
6199d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
6209d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
6219d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
6229d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
6239d082687SJelle van der Waa 
6249d082687SJelle van der Waa #endif
62514a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
62614a6ff2cSmario.six@gdsys.cc 
62714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
62814a6ff2cSmario.six@gdsys.cc 				 u32 chip_flags)
62914a6ff2cSmario.six@gdsys.cc {
63014a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
631*c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
63214a6ff2cSmario.six@gdsys.cc }
63314a6ff2cSmario.six@gdsys.cc 
63414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
63514a6ff2cSmario.six@gdsys.cc {
63614a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
637*c68c6243Smario.six@gdsys.cc 
638*c68c6243Smario.six@gdsys.cc 	dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
639*c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
640*c68c6243Smario.six@gdsys.cc 
641*c68c6243Smario.six@gdsys.cc 	return 0;
64214a6ff2cSmario.six@gdsys.cc }
64314a6ff2cSmario.six@gdsys.cc 
64414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
64514a6ff2cSmario.six@gdsys.cc {
64614a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
64714a6ff2cSmario.six@gdsys.cc 
64814a6ff2cSmario.six@gdsys.cc 	dev->base = dev_get_addr_ptr(bus);
64914a6ff2cSmario.six@gdsys.cc 
65014a6ff2cSmario.six@gdsys.cc 	if (!dev->base)
65114a6ff2cSmario.six@gdsys.cc 		return -ENOMEM;
65214a6ff2cSmario.six@gdsys.cc 
65314a6ff2cSmario.six@gdsys.cc 	dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
65414a6ff2cSmario.six@gdsys.cc 				    "cell-index", -1);
65514a6ff2cSmario.six@gdsys.cc 	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
65614a6ff2cSmario.six@gdsys.cc 				       "u-boot,i2c-slave-addr", 0x0);
65714a6ff2cSmario.six@gdsys.cc 	dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
65814a6ff2cSmario.six@gdsys.cc 				    "clock-frequency", 100000);
65914a6ff2cSmario.six@gdsys.cc 	return 0;
66014a6ff2cSmario.six@gdsys.cc }
66114a6ff2cSmario.six@gdsys.cc 
66214a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
66314a6ff2cSmario.six@gdsys.cc {
66414a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
665*c68c6243Smario.six@gdsys.cc 	uint actual_speed;
666*c68c6243Smario.six@gdsys.cc 
667*c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
668*c68c6243Smario.six@gdsys.cc 	dev->speed = actual_speed;
669*c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
67014a6ff2cSmario.six@gdsys.cc 	return 0;
67114a6ff2cSmario.six@gdsys.cc }
67214a6ff2cSmario.six@gdsys.cc 
67314a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
67414a6ff2cSmario.six@gdsys.cc {
67514a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
67614a6ff2cSmario.six@gdsys.cc 	struct i2c_msg *dmsg, *omsg, dummy;
67714a6ff2cSmario.six@gdsys.cc 
67814a6ff2cSmario.six@gdsys.cc 	memset(&dummy, 0, sizeof(struct i2c_msg));
67914a6ff2cSmario.six@gdsys.cc 
68014a6ff2cSmario.six@gdsys.cc 	/* We expect either two messages (one with an offset and one with the
68114a6ff2cSmario.six@gdsys.cc 	 * actual data) or one message (just data or offset/data combined) */
68214a6ff2cSmario.six@gdsys.cc 	if (nmsgs > 2 || nmsgs == 0) {
68314a6ff2cSmario.six@gdsys.cc 		debug("%s: Only one or two messages are supported.", __func__);
68414a6ff2cSmario.six@gdsys.cc 		return -1;
68514a6ff2cSmario.six@gdsys.cc 	}
68614a6ff2cSmario.six@gdsys.cc 
68714a6ff2cSmario.six@gdsys.cc 	omsg = nmsgs == 1 ? &dummy : msg;
68814a6ff2cSmario.six@gdsys.cc 	dmsg = nmsgs == 1 ? msg : msg + 1;
68914a6ff2cSmario.six@gdsys.cc 
69014a6ff2cSmario.six@gdsys.cc 	if (dmsg->flags & I2C_M_RD)
69114a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
692*c68c6243Smario.six@gdsys.cc 				       omsg->len, dmsg->buf, dmsg->len,
693*c68c6243Smario.six@gdsys.cc 				       dev->tick);
69414a6ff2cSmario.six@gdsys.cc 	else
69514a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
696*c68c6243Smario.six@gdsys.cc 					omsg->len, dmsg->buf, dmsg->len,
697*c68c6243Smario.six@gdsys.cc 					dev->tick);
69814a6ff2cSmario.six@gdsys.cc }
69914a6ff2cSmario.six@gdsys.cc 
70014a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
70114a6ff2cSmario.six@gdsys.cc 	.xfer		= mvtwsi_i2c_xfer,
70214a6ff2cSmario.six@gdsys.cc 	.probe_chip	= mvtwsi_i2c_probe_chip,
70314a6ff2cSmario.six@gdsys.cc 	.set_bus_speed	= mvtwsi_i2c_set_bus_speed,
70414a6ff2cSmario.six@gdsys.cc };
70514a6ff2cSmario.six@gdsys.cc 
70614a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
70714a6ff2cSmario.six@gdsys.cc 	{ .compatible = "marvell,mv64xxx-i2c", },
70814a6ff2cSmario.six@gdsys.cc 	{ /* sentinel */ }
70914a6ff2cSmario.six@gdsys.cc };
71014a6ff2cSmario.six@gdsys.cc 
71114a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
71214a6ff2cSmario.six@gdsys.cc 	.name = "i2c_mvtwsi",
71314a6ff2cSmario.six@gdsys.cc 	.id = UCLASS_I2C,
71414a6ff2cSmario.six@gdsys.cc 	.of_match = mvtwsi_i2c_ids,
71514a6ff2cSmario.six@gdsys.cc 	.probe = mvtwsi_i2c_probe,
71614a6ff2cSmario.six@gdsys.cc 	.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
71714a6ff2cSmario.six@gdsys.cc 	.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
71814a6ff2cSmario.six@gdsys.cc 	.ops = &mvtwsi_i2c_ops,
71914a6ff2cSmario.six@gdsys.cc };
72014a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
721