xref: /rk3399_rockchip-uboot/drivers/i2c/mvtwsi.c (revision 24f9c6bbc7d5e5e276dea32a81ade71f0e6b56ae)
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>
1514a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
1614a6ff2cSmario.six@gdsys.cc #include <dm.h>
1714a6ff2cSmario.six@gdsys.cc #endif
1814a6ff2cSmario.six@gdsys.cc 
1914a6ff2cSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR;
2001ec99d9SAlbert Aribaud 
21306563a7SAlbert Aribaud /*
2249c801bfSmario.six@gdsys.cc  * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
2349c801bfSmario.six@gdsys.cc  * settings
24306563a7SAlbert Aribaud  */
2501ec99d9SAlbert Aribaud 
2614a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
27306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X)
28306563a7SAlbert Aribaud #include <asm/arch/orion5x.h>
2981e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
303dc23f78SStefan Roese #include <asm/arch/soc.h>
316620377eSHans de Goede #elif defined(CONFIG_SUNXI)
326620377eSHans de Goede #include <asm/arch/i2c.h>
33306563a7SAlbert Aribaud #else
34306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board
3501ec99d9SAlbert Aribaud #endif
3614a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
3701ec99d9SAlbert Aribaud 
3801ec99d9SAlbert Aribaud /*
39306563a7SAlbert Aribaud  * TWSI register structure
4001ec99d9SAlbert Aribaud  */
4101ec99d9SAlbert Aribaud 
426620377eSHans de Goede #ifdef CONFIG_SUNXI
436620377eSHans de Goede 
446620377eSHans de Goede struct  mvtwsi_registers {
456620377eSHans de Goede 	u32 slave_address;
466620377eSHans de Goede 	u32 xtnd_slave_addr;
476620377eSHans de Goede 	u32 data;
486620377eSHans de Goede 	u32 control;
496620377eSHans de Goede 	u32 status;
506620377eSHans de Goede 	u32 baudrate;
516620377eSHans de Goede 	u32 soft_reset;
526620377eSHans de Goede };
536620377eSHans de Goede 
546620377eSHans de Goede #else
556620377eSHans de Goede 
56306563a7SAlbert Aribaud struct  mvtwsi_registers {
57306563a7SAlbert Aribaud 	u32 slave_address;
58306563a7SAlbert Aribaud 	u32 data;
59306563a7SAlbert Aribaud 	u32 control;
60306563a7SAlbert Aribaud 	union {
6149c801bfSmario.six@gdsys.cc 		u32 status;	/* When reading */
6249c801bfSmario.six@gdsys.cc 		u32 baudrate;	/* When writing */
63306563a7SAlbert Aribaud 	};
64306563a7SAlbert Aribaud 	u32 xtnd_slave_addr;
65306563a7SAlbert Aribaud 	u32 reserved[2];
66306563a7SAlbert Aribaud 	u32 soft_reset;
67306563a7SAlbert Aribaud };
68306563a7SAlbert Aribaud 
696620377eSHans de Goede #endif
706620377eSHans de Goede 
7114a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
7214a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
7314a6ff2cSmario.six@gdsys.cc 	/* TWSI Register base for the device */
7414a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_registers *base;
7514a6ff2cSmario.six@gdsys.cc 	/* Number of the device (determined from cell-index property) */
7614a6ff2cSmario.six@gdsys.cc 	int index;
7714a6ff2cSmario.six@gdsys.cc 	/* The I2C slave address for the device */
7814a6ff2cSmario.six@gdsys.cc 	u8 slaveadd;
7914a6ff2cSmario.six@gdsys.cc 	/* The configured I2C speed in Hz */
8014a6ff2cSmario.six@gdsys.cc 	uint speed;
8114a6ff2cSmario.six@gdsys.cc };
8214a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
8314a6ff2cSmario.six@gdsys.cc 
84306563a7SAlbert Aribaud /*
85dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
86dfc3958cSmario.six@gdsys.cc  * register
87306563a7SAlbert Aribaud  */
88dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
89dfc3958cSmario.six@gdsys.cc 	/* Acknowledge bit */
90dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_ACK	= 0x00000004,
91dfc3958cSmario.six@gdsys.cc 	/* Interrupt flag */
92dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_IFLG	= 0x00000008,
93dfc3958cSmario.six@gdsys.cc 	/* Stop bit */
94dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_STOP	= 0x00000010,
95dfc3958cSmario.six@gdsys.cc 	/* Start bit */
96dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_START	= 0x00000020,
97dfc3958cSmario.six@gdsys.cc 	/* I2C enable */
98dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_TWSIEN	= 0x00000040,
99dfc3958cSmario.six@gdsys.cc 	/* Interrupt enable */
100dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_INTEN	= 0x00000080,
101dfc3958cSmario.six@gdsys.cc };
102306563a7SAlbert Aribaud 
103306563a7SAlbert Aribaud /*
10449c801bfSmario.six@gdsys.cc  * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
10549c801bfSmario.six@gdsys.cc  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
106904dfbfdSHans de Goede  */
107904dfbfdSHans de Goede 
108904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
109904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
110904dfbfdSHans de Goede #else
111904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
112904dfbfdSHans de Goede #endif
113904dfbfdSHans de Goede 
114904dfbfdSHans de Goede /*
115dfc3958cSmario.six@gdsys.cc  * enum mvstwsi_status_values - Possible values of I2C controller's status
116dfc3958cSmario.six@gdsys.cc  * register
117dfc3958cSmario.six@gdsys.cc  *
118dfc3958cSmario.six@gdsys.cc  * Only those statuses expected in normal master operation on
119dfc3958cSmario.six@gdsys.cc  * non-10-bit-address devices are specified.
120dfc3958cSmario.six@gdsys.cc  *
121dfc3958cSmario.six@gdsys.cc  * Every status that's unexpected during normal operation (bus errors,
122dfc3958cSmario.six@gdsys.cc  * arbitration losses, missing ACKs...) is passed back to the caller as an error
123306563a7SAlbert Aribaud  * code.
124306563a7SAlbert Aribaud  */
125dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
126dfc3958cSmario.six@gdsys.cc 	/* START condition transmitted */
127dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_START		= 0x08,
128dfc3958cSmario.six@gdsys.cc 	/* Repeated START condition transmitted */
129dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_REPEATED_START	= 0x10,
130dfc3958cSmario.six@gdsys.cc 	/* Address + write bit transmitted, ACK received */
131dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_W_ACK	= 0x18,
132dfc3958cSmario.six@gdsys.cc 	/* Data transmitted, ACK received */
133dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_W_ACK	= 0x28,
134dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK received */
135dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_ACK	= 0x40,
136dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK not received */
137dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_NAK	= 0x48,
138dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK transmitted */
139dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_ACK	= 0x50,
140dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK not transmitted */
141dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_NAK	= 0x58,
142dfc3958cSmario.six@gdsys.cc 	/* No relevant status */
143dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_IDLE		= 0xF8,
144dfc3958cSmario.six@gdsys.cc };
145306563a7SAlbert Aribaud 
146306563a7SAlbert Aribaud /*
147670514f5Smario.six@gdsys.cc  * enum mvstwsi_ack_flags - Determine whether a read byte should be
148670514f5Smario.six@gdsys.cc  * acknowledged or not.
149670514f5Smario.six@gdsys.cc  */
150670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
151670514f5Smario.six@gdsys.cc 	/* Send NAK after received byte */
152670514f5Smario.six@gdsys.cc 	MVTWSI_READ_NAK = 0,
153670514f5Smario.six@gdsys.cc 	/* Send ACK after received byte */
154670514f5Smario.six@gdsys.cc 	MVTWSI_READ_ACK = 1,
155670514f5Smario.six@gdsys.cc };
156670514f5Smario.six@gdsys.cc 
15714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
158670514f5Smario.six@gdsys.cc /*
159dd82242bSPaul Kocialkowski  * MVTWSI controller base
160306563a7SAlbert Aribaud  */
161306563a7SAlbert Aribaud 
162dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
163dd82242bSPaul Kocialkowski {
164dd82242bSPaul Kocialkowski 	switch (adap->hwadapnr) {
165dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
166dd82242bSPaul Kocialkowski 	case 0:
167dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
168dd82242bSPaul Kocialkowski #endif
169dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
170dd82242bSPaul Kocialkowski 	case 1:
171dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
172dd82242bSPaul Kocialkowski #endif
173dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
174dd82242bSPaul Kocialkowski 	case 2:
175dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
176dd82242bSPaul Kocialkowski #endif
177dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
178dd82242bSPaul Kocialkowski 	case 3:
179dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
180dd82242bSPaul Kocialkowski #endif
181dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
182dd82242bSPaul Kocialkowski 	case 4:
183dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
184dd82242bSPaul Kocialkowski #endif
1859d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
1869d082687SJelle van der Waa 	case 5:
1879d082687SJelle van der Waa 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
1889d082687SJelle van der Waa #endif
189dd82242bSPaul Kocialkowski 	default:
190dd82242bSPaul Kocialkowski 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
191dd82242bSPaul Kocialkowski 		break;
192dd82242bSPaul Kocialkowski 	}
193dd82242bSPaul Kocialkowski 
194dd82242bSPaul Kocialkowski 	return NULL;
195dd82242bSPaul Kocialkowski }
19614a6ff2cSmario.six@gdsys.cc #endif
197306563a7SAlbert Aribaud 
198306563a7SAlbert Aribaud /*
199dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_error_class - types of I2C errors
200306563a7SAlbert Aribaud  */
201dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
202dfc3958cSmario.six@gdsys.cc 	/* The controller returned a different status than expected */
203dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_WRONG_STATUS       = 0x01,
204dfc3958cSmario.six@gdsys.cc 	/* The controller timed out */
205dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_TIMEOUT            = 0x02,
206dfc3958cSmario.six@gdsys.cc };
207306563a7SAlbert Aribaud 
208dfc3958cSmario.six@gdsys.cc /*
209dfc3958cSmario.six@gdsys.cc  * mvtwsi_error() - Build I2C return code from error information
210dfc3958cSmario.six@gdsys.cc  *
211dfc3958cSmario.six@gdsys.cc  * For debugging purposes, this function packs some information of an occurred
212dfc3958cSmario.six@gdsys.cc  * error into a return code. These error codes are returned from I2C API
213dfc3958cSmario.six@gdsys.cc  * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
214dfc3958cSmario.six@gdsys.cc  *
215dfc3958cSmario.six@gdsys.cc  * @ec:		The error class of the error (enum mvtwsi_error_class).
216dfc3958cSmario.six@gdsys.cc  * @lc:		The last value of the control register.
217dfc3958cSmario.six@gdsys.cc  * @ls:		The last value of the status register.
218dfc3958cSmario.six@gdsys.cc  * @es:		The expected value of the status register.
219dfc3958cSmario.six@gdsys.cc  * @return The generated error code.
220dfc3958cSmario.six@gdsys.cc  */
221dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
222dfc3958cSmario.six@gdsys.cc {
223dfc3958cSmario.six@gdsys.cc 	return ((ec << 24) & 0xFF000000)
224dfc3958cSmario.six@gdsys.cc 	       | ((lc << 16) & 0x00FF0000)
225dfc3958cSmario.six@gdsys.cc 	       | ((ls << 8) & 0x0000FF00)
226dfc3958cSmario.six@gdsys.cc 	       | (es & 0xFF);
227dfc3958cSmario.six@gdsys.cc }
228306563a7SAlbert Aribaud 
229306563a7SAlbert Aribaud /*
23049c801bfSmario.six@gdsys.cc  * Wait for IFLG to raise, or return 'timeout.' Then, if the status is as
23149c801bfSmario.six@gdsys.cc  * expected, return 0 (ok) or 'wrong status' otherwise.
232306563a7SAlbert Aribaud  */
2333c4db636Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status)
23401ec99d9SAlbert Aribaud {
235306563a7SAlbert Aribaud 	int control, status;
236306563a7SAlbert Aribaud 	int timeout = 1000;
237306563a7SAlbert Aribaud 
238306563a7SAlbert Aribaud 	do {
239306563a7SAlbert Aribaud 		control = readl(&twsi->control);
240306563a7SAlbert Aribaud 		if (control & MVTWSI_CONTROL_IFLG) {
241306563a7SAlbert Aribaud 			status = readl(&twsi->status);
242306563a7SAlbert Aribaud 			if (status == expected_status)
243306563a7SAlbert Aribaud 				return 0;
24401ec99d9SAlbert Aribaud 			else
245dfc3958cSmario.six@gdsys.cc 				return mvtwsi_error(
246306563a7SAlbert Aribaud 					MVTWSI_ERROR_WRONG_STATUS,
247306563a7SAlbert Aribaud 					control, status, expected_status);
248306563a7SAlbert Aribaud 		}
24949c801bfSmario.six@gdsys.cc 		udelay(10); /* One clock cycle at 100 kHz */
250306563a7SAlbert Aribaud 	} while (timeout--);
251306563a7SAlbert Aribaud 	status = readl(&twsi->status);
252dfc3958cSmario.six@gdsys.cc 	return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
253dfc3958cSmario.six@gdsys.cc 			    expected_status);
25401ec99d9SAlbert Aribaud }
25501ec99d9SAlbert Aribaud 
256306563a7SAlbert Aribaud /*
257306563a7SAlbert Aribaud  * Assert the START condition, either in a single I2C transaction
258306563a7SAlbert Aribaud  * or inside back-to-back ones (repeated starts).
259306563a7SAlbert Aribaud  */
2603c4db636Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status)
261306563a7SAlbert Aribaud {
26249c801bfSmario.six@gdsys.cc 	/* Assert START */
263670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
2642ca02995SHans de Goede 	       MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
26549c801bfSmario.six@gdsys.cc 	/* Wait for controller to process START */
2663c4db636Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status);
267306563a7SAlbert Aribaud }
268306563a7SAlbert Aribaud 
269306563a7SAlbert Aribaud /*
270306563a7SAlbert Aribaud  * Send a byte (i2c address or data).
271306563a7SAlbert Aribaud  */
2723c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
2733c4db636Smario.six@gdsys.cc 		     int expected_status)
274306563a7SAlbert Aribaud {
27549c801bfSmario.six@gdsys.cc 	/* Write byte to data register for sending */
276306563a7SAlbert Aribaud 	writel(byte, &twsi->data);
27749c801bfSmario.six@gdsys.cc 	/* Clear any pending interrupt -- that will cause sending */
278670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
279670514f5Smario.six@gdsys.cc 	       &twsi->control);
28049c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and check ACK */
2813c4db636Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status);
282306563a7SAlbert Aribaud }
283306563a7SAlbert Aribaud 
284306563a7SAlbert Aribaud /*
285306563a7SAlbert Aribaud  * Receive a byte.
286306563a7SAlbert Aribaud  */
2873c4db636Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag)
288306563a7SAlbert Aribaud {
289670514f5Smario.six@gdsys.cc 	int expected_status, status, control;
290306563a7SAlbert Aribaud 
291670514f5Smario.six@gdsys.cc 	/* Compute expected status based on passed ACK flag */
292670514f5Smario.six@gdsys.cc 	expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
293670514f5Smario.six@gdsys.cc 			  MVTWSI_STATUS_DATA_R_NAK;
29449c801bfSmario.six@gdsys.cc 	/* Acknowledge *previous state*, and launch receive */
295670514f5Smario.six@gdsys.cc 	control = MVTWSI_CONTROL_TWSIEN;
296670514f5Smario.six@gdsys.cc 	control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
297670514f5Smario.six@gdsys.cc 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
29849c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and assert ACK or NAK */
2993c4db636Smario.six@gdsys.cc 	status = twsi_wait(twsi, expected_status);
30049c801bfSmario.six@gdsys.cc 	/* If we did receive the expected byte, store it */
301306563a7SAlbert Aribaud 	if (status == 0)
302306563a7SAlbert Aribaud 		*byte = readl(&twsi->data);
303306563a7SAlbert Aribaud 	return status;
304306563a7SAlbert Aribaud }
305306563a7SAlbert Aribaud 
306306563a7SAlbert Aribaud /*
307306563a7SAlbert Aribaud  * Assert the STOP condition.
30849c801bfSmario.six@gdsys.cc  * This is also used to force the bus back to idle (SDA = SCL = 1).
309306563a7SAlbert Aribaud  */
3103c4db636Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi)
311306563a7SAlbert Aribaud {
312306563a7SAlbert Aribaud 	int control, stop_status;
313059fce9fSmario.six@gdsys.cc 	int status = 0;
314306563a7SAlbert Aribaud 	int timeout = 1000;
315306563a7SAlbert Aribaud 
31649c801bfSmario.six@gdsys.cc 	/* Assert STOP */
317306563a7SAlbert Aribaud 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
318904dfbfdSHans de Goede 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
31949c801bfSmario.six@gdsys.cc 	/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
320306563a7SAlbert Aribaud 	do {
321306563a7SAlbert Aribaud 		stop_status = readl(&twsi->status);
322306563a7SAlbert Aribaud 		if (stop_status == MVTWSI_STATUS_IDLE)
323306563a7SAlbert Aribaud 			break;
32449c801bfSmario.six@gdsys.cc 		udelay(10); /* One clock cycle at 100 kHz */
325306563a7SAlbert Aribaud 	} while (timeout--);
326306563a7SAlbert Aribaud 	control = readl(&twsi->control);
327306563a7SAlbert Aribaud 	if (stop_status != MVTWSI_STATUS_IDLE)
328059fce9fSmario.six@gdsys.cc 		status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
329306563a7SAlbert Aribaud 				      control, status, MVTWSI_STATUS_IDLE);
330306563a7SAlbert Aribaud 	return status;
331306563a7SAlbert Aribaud }
332306563a7SAlbert Aribaud 
333e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
334f582a158SStefan Roese {
335f582a158SStefan Roese #ifdef CONFIG_SUNXI
336f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
337f582a158SStefan Roese #else
338f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
339f582a158SStefan Roese #endif
340f582a158SStefan Roese }
341306563a7SAlbert Aribaud 
342306563a7SAlbert Aribaud /*
343306563a7SAlbert Aribaud  * Reset controller.
344306563a7SAlbert Aribaud  * Controller reset also resets the baud rate and slave address, so
3450db2bbdcSHans de Goede  * they must be re-established afterwards.
346306563a7SAlbert Aribaud  */
3473c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
348306563a7SAlbert Aribaud {
34949c801bfSmario.six@gdsys.cc 	/* Reset controller */
350306563a7SAlbert Aribaud 	writel(0, &twsi->soft_reset);
35149c801bfSmario.six@gdsys.cc 	/* Wait 2 ms -- this is what the Marvell LSP does */
352306563a7SAlbert Aribaud 	udelay(20000);
353306563a7SAlbert Aribaud }
354306563a7SAlbert Aribaud 
355306563a7SAlbert Aribaud /*
35649c801bfSmario.six@gdsys.cc  * Sets baud to the highest possible value not exceeding the requested one.
357306563a7SAlbert Aribaud  */
3583c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
359e0758281Smario.six@gdsys.cc 				     uint requested_speed)
360306563a7SAlbert Aribaud {
361e0758281Smario.six@gdsys.cc 	uint tmp_speed, highest_speed, n, m;
362e0758281Smario.six@gdsys.cc 	uint baud = 0x44; /* Baud rate after controller reset */
363306563a7SAlbert Aribaud 
364306563a7SAlbert Aribaud 	highest_speed = 0;
36549c801bfSmario.six@gdsys.cc 	/* Successively try m, n combinations, and use the combination
36649c801bfSmario.six@gdsys.cc 	 * resulting in the largest speed that's not above the requested
36749c801bfSmario.six@gdsys.cc 	 * speed */
36801ec99d9SAlbert Aribaud 	for (n = 0; n < 8; n++) {
36901ec99d9SAlbert Aribaud 		for (m = 0; m < 16; m++) {
370f582a158SStefan Roese 			tmp_speed = twsi_calc_freq(n, m);
3719ec43b0cSmario.six@gdsys.cc 			if ((tmp_speed <= requested_speed) &&
3729ec43b0cSmario.six@gdsys.cc 			    (tmp_speed > highest_speed)) {
373306563a7SAlbert Aribaud 				highest_speed = tmp_speed;
374306563a7SAlbert Aribaud 				baud = (m << 3) | n;
37501ec99d9SAlbert Aribaud 			}
37601ec99d9SAlbert Aribaud 		}
37701ec99d9SAlbert Aribaud 	}
3780db2bbdcSHans de Goede 	writel(baud, &twsi->baudrate);
3790db2bbdcSHans de Goede 	return 0;
3800db2bbdcSHans de Goede }
3810db2bbdcSHans de Goede 
3823c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
3833c4db636Smario.six@gdsys.cc 			    int slaveadd)
3840db2bbdcSHans de Goede {
38549c801bfSmario.six@gdsys.cc 	/* Reset controller */
3863c4db636Smario.six@gdsys.cc 	twsi_reset(twsi);
38749c801bfSmario.six@gdsys.cc 	/* Set speed */
3883c4db636Smario.six@gdsys.cc 	__twsi_i2c_set_bus_speed(twsi, speed);
38949c801bfSmario.six@gdsys.cc 	/* Set slave address; even though we don't use it */
3900db2bbdcSHans de Goede 	writel(slaveadd, &twsi->slave_address);
3910db2bbdcSHans de Goede 	writel(0, &twsi->xtnd_slave_addr);
39249c801bfSmario.six@gdsys.cc 	/* Assert STOP, but don't care for the result */
3933c4db636Smario.six@gdsys.cc 	(void) twsi_stop(twsi);
39401ec99d9SAlbert Aribaud }
39501ec99d9SAlbert Aribaud 
39601ec99d9SAlbert Aribaud /*
397306563a7SAlbert Aribaud  * Begin I2C transaction with expected start status, at given address.
398306563a7SAlbert Aribaud  * Expected address status will derive from direction bit (bit 0) in addr.
39901ec99d9SAlbert Aribaud  */
4003c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
401670514f5Smario.six@gdsys.cc 		     u8 addr)
40201ec99d9SAlbert Aribaud {
403306563a7SAlbert Aribaud 	int status, expected_addr_status;
40401ec99d9SAlbert Aribaud 
40549c801bfSmario.six@gdsys.cc 	/* Compute the expected address status from the direction bit in
40649c801bfSmario.six@gdsys.cc 	 * the address byte */
40749c801bfSmario.six@gdsys.cc 	if (addr & 1) /* Reading */
408306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
40949c801bfSmario.six@gdsys.cc 	else /* Writing */
410306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
41149c801bfSmario.six@gdsys.cc 	/* Assert START */
4123c4db636Smario.six@gdsys.cc 	status = twsi_start(twsi, expected_start_status);
41349c801bfSmario.six@gdsys.cc 	/* Send out the address if the start went well */
414306563a7SAlbert Aribaud 	if (status == 0)
4153c4db636Smario.six@gdsys.cc 		status = twsi_send(twsi, addr, expected_addr_status);
41649c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
417306563a7SAlbert Aribaud 	return status;
41801ec99d9SAlbert Aribaud }
41901ec99d9SAlbert Aribaud 
420306563a7SAlbert Aribaud /*
421306563a7SAlbert Aribaud  * Begin read, nak data byte, end.
422306563a7SAlbert Aribaud  */
4233c4db636Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip)
42401ec99d9SAlbert Aribaud {
425306563a7SAlbert Aribaud 	u8 dummy_byte;
426306563a7SAlbert Aribaud 	int status;
42701ec99d9SAlbert Aribaud 
42849c801bfSmario.six@gdsys.cc 	/* Begin i2c read */
4293c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1);
43049c801bfSmario.six@gdsys.cc 	/* Dummy read was accepted: receive byte, but NAK it. */
431306563a7SAlbert Aribaud 	if (status == 0)
4323c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK);
433306563a7SAlbert Aribaud 	/* Stop transaction */
4343c4db636Smario.six@gdsys.cc 	twsi_stop(twsi);
43549c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
436306563a7SAlbert Aribaud 	return status;
43701ec99d9SAlbert Aribaud }
43801ec99d9SAlbert Aribaud 
439306563a7SAlbert Aribaud /*
440306563a7SAlbert Aribaud  * Begin write, send address byte(s), begin read, receive data bytes, end.
441306563a7SAlbert Aribaud  *
44249c801bfSmario.six@gdsys.cc  * NOTE: Some devices want a stop right before the second start, while some
44349c801bfSmario.six@gdsys.cc  * will choke if it is there. Since deciding this is not yet supported in
44449c801bfSmario.six@gdsys.cc  * higher level APIs, we need to make a decision here, and for the moment that
44549c801bfSmario.six@gdsys.cc  * will be a repeated start without a preceding stop.
446306563a7SAlbert Aribaud  */
4473c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
448f8a10ed1Smario.six@gdsys.cc 			   u8 *addr, int alen, uchar *data, int length)
44901ec99d9SAlbert Aribaud {
450059fce9fSmario.six@gdsys.cc 	int status = 0;
451059fce9fSmario.six@gdsys.cc 	int stop_status;
452*24f9c6bbSmario.six@gdsys.cc 	int expected_start = MVTWSI_STATUS_START;
45301ec99d9SAlbert Aribaud 
454*24f9c6bbSmario.six@gdsys.cc 	if (alen > 0) {
45549c801bfSmario.six@gdsys.cc 		/* Begin i2c write to send the address bytes */
456*24f9c6bbSmario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1));
45749c801bfSmario.six@gdsys.cc 		/* Send address bytes */
458306563a7SAlbert Aribaud 		while ((status == 0) && alen--)
459*24f9c6bbSmario.six@gdsys.cc 			status = twsi_send(twsi, *(addr++),
460*24f9c6bbSmario.six@gdsys.cc 					   MVTWSI_STATUS_DATA_W_ACK);
461*24f9c6bbSmario.six@gdsys.cc 		/* Send repeated STARTs after the initial START */
462*24f9c6bbSmario.six@gdsys.cc 		expected_start = MVTWSI_STATUS_REPEATED_START;
463*24f9c6bbSmario.six@gdsys.cc 	}
46449c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
465306563a7SAlbert Aribaud 	if (status == 0)
466*24f9c6bbSmario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1) | 1);
467670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
468670514f5Smario.six@gdsys.cc 	 * read */
469670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
4703c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
471670514f5Smario.six@gdsys.cc 				   length > 0 ?
472670514f5Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK);
473306563a7SAlbert Aribaud 	/* Stop transaction */
4743c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
47549c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
476059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
47701ec99d9SAlbert Aribaud }
47801ec99d9SAlbert Aribaud 
479306563a7SAlbert Aribaud /*
480306563a7SAlbert Aribaud  * Begin write, send address byte(s), send data bytes, end.
481306563a7SAlbert Aribaud  */
4823c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
483f8a10ed1Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length)
48401ec99d9SAlbert Aribaud {
485059fce9fSmario.six@gdsys.cc 	int status, stop_status;
48601ec99d9SAlbert Aribaud 
48749c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
48849c801bfSmario.six@gdsys.cc 	 * data bytes */
4893c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1));
49049c801bfSmario.six@gdsys.cc 	/* Send address bytes */
491f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
492f8a10ed1Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK);
49349c801bfSmario.six@gdsys.cc 	/* Send data bytes */
494306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
4953c4db636Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK);
496306563a7SAlbert Aribaud 	/* Stop transaction */
4973c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
49849c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
499059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
50001ec99d9SAlbert Aribaud }
50101ec99d9SAlbert Aribaud 
50214a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
50361bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
50461bc02b2Smario.six@gdsys.cc 			  int slaveadd)
50561bc02b2Smario.six@gdsys.cc {
5063c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5073c4db636Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd);
50861bc02b2Smario.six@gdsys.cc }
50961bc02b2Smario.six@gdsys.cc 
51061bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
51161bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
51261bc02b2Smario.six@gdsys.cc {
5133c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5143c4db636Smario.six@gdsys.cc 	return __twsi_i2c_set_bus_speed(twsi, requested_speed);
51561bc02b2Smario.six@gdsys.cc }
51661bc02b2Smario.six@gdsys.cc 
51761bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
51861bc02b2Smario.six@gdsys.cc {
5193c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5203c4db636Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip);
52161bc02b2Smario.six@gdsys.cc }
52261bc02b2Smario.six@gdsys.cc 
52361bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
52461bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
52561bc02b2Smario.six@gdsys.cc {
5263c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
527f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
528f8a10ed1Smario.six@gdsys.cc 
529f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
530f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
531f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
532f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
533f8a10ed1Smario.six@gdsys.cc 
534f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length);
53561bc02b2Smario.six@gdsys.cc }
53661bc02b2Smario.six@gdsys.cc 
53761bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
53861bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
53961bc02b2Smario.six@gdsys.cc {
5403c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
541f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
542f8a10ed1Smario.six@gdsys.cc 
543f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
544f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
545f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
546f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
547f8a10ed1Smario.six@gdsys.cc 
548f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length);
54961bc02b2Smario.six@gdsys.cc }
55061bc02b2Smario.six@gdsys.cc 
551dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
5520db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
5530db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
5540db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
5550db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
556dd82242bSPaul Kocialkowski #endif
557dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
558dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
559dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
560dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
561dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
562dd82242bSPaul Kocialkowski 
563dd82242bSPaul Kocialkowski #endif
564dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
565dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
566dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
567dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
568dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
569dd82242bSPaul Kocialkowski 
570dd82242bSPaul Kocialkowski #endif
571dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
572dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
573dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
574dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
575dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
576dd82242bSPaul Kocialkowski 
577dd82242bSPaul Kocialkowski #endif
578dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
579dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
580dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
581dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
582dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
583dd82242bSPaul Kocialkowski 
584dd82242bSPaul Kocialkowski #endif
5859d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
5869d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
5879d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
5889d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
5899d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
5909d082687SJelle van der Waa 
5919d082687SJelle van der Waa #endif
59214a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
59314a6ff2cSmario.six@gdsys.cc 
59414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
59514a6ff2cSmario.six@gdsys.cc 				 u32 chip_flags)
59614a6ff2cSmario.six@gdsys.cc {
59714a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
59814a6ff2cSmario.six@gdsys.cc 	return __twsi_i2c_probe_chip(dev->base, chip_addr);
59914a6ff2cSmario.six@gdsys.cc }
60014a6ff2cSmario.six@gdsys.cc 
60114a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
60214a6ff2cSmario.six@gdsys.cc {
60314a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
60414a6ff2cSmario.six@gdsys.cc 	return __twsi_i2c_set_bus_speed(dev->base, speed);
60514a6ff2cSmario.six@gdsys.cc }
60614a6ff2cSmario.six@gdsys.cc 
60714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
60814a6ff2cSmario.six@gdsys.cc {
60914a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
61014a6ff2cSmario.six@gdsys.cc 
61114a6ff2cSmario.six@gdsys.cc 	dev->base = dev_get_addr_ptr(bus);
61214a6ff2cSmario.six@gdsys.cc 
61314a6ff2cSmario.six@gdsys.cc 	if (!dev->base)
61414a6ff2cSmario.six@gdsys.cc 		return -ENOMEM;
61514a6ff2cSmario.six@gdsys.cc 
61614a6ff2cSmario.six@gdsys.cc 	dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
61714a6ff2cSmario.six@gdsys.cc 				    "cell-index", -1);
61814a6ff2cSmario.six@gdsys.cc 	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
61914a6ff2cSmario.six@gdsys.cc 				       "u-boot,i2c-slave-addr", 0x0);
62014a6ff2cSmario.six@gdsys.cc 	dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
62114a6ff2cSmario.six@gdsys.cc 				    "clock-frequency", 100000);
62214a6ff2cSmario.six@gdsys.cc 	return 0;
62314a6ff2cSmario.six@gdsys.cc }
62414a6ff2cSmario.six@gdsys.cc 
62514a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
62614a6ff2cSmario.six@gdsys.cc {
62714a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
62814a6ff2cSmario.six@gdsys.cc 	__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd);
62914a6ff2cSmario.six@gdsys.cc 	return 0;
63014a6ff2cSmario.six@gdsys.cc }
63114a6ff2cSmario.six@gdsys.cc 
63214a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
63314a6ff2cSmario.six@gdsys.cc {
63414a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
63514a6ff2cSmario.six@gdsys.cc 	struct i2c_msg *dmsg, *omsg, dummy;
63614a6ff2cSmario.six@gdsys.cc 
63714a6ff2cSmario.six@gdsys.cc 	memset(&dummy, 0, sizeof(struct i2c_msg));
63814a6ff2cSmario.six@gdsys.cc 
63914a6ff2cSmario.six@gdsys.cc 	/* We expect either two messages (one with an offset and one with the
64014a6ff2cSmario.six@gdsys.cc 	 * actual data) or one message (just data or offset/data combined) */
64114a6ff2cSmario.six@gdsys.cc 	if (nmsgs > 2 || nmsgs == 0) {
64214a6ff2cSmario.six@gdsys.cc 		debug("%s: Only one or two messages are supported.", __func__);
64314a6ff2cSmario.six@gdsys.cc 		return -1;
64414a6ff2cSmario.six@gdsys.cc 	}
64514a6ff2cSmario.six@gdsys.cc 
64614a6ff2cSmario.six@gdsys.cc 	omsg = nmsgs == 1 ? &dummy : msg;
64714a6ff2cSmario.six@gdsys.cc 	dmsg = nmsgs == 1 ? msg : msg + 1;
64814a6ff2cSmario.six@gdsys.cc 
64914a6ff2cSmario.six@gdsys.cc 	if (dmsg->flags & I2C_M_RD)
65014a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
65114a6ff2cSmario.six@gdsys.cc 				       omsg->len, dmsg->buf, dmsg->len);
65214a6ff2cSmario.six@gdsys.cc 	else
65314a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
65414a6ff2cSmario.six@gdsys.cc 					omsg->len, dmsg->buf, dmsg->len);
65514a6ff2cSmario.six@gdsys.cc }
65614a6ff2cSmario.six@gdsys.cc 
65714a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
65814a6ff2cSmario.six@gdsys.cc 	.xfer		= mvtwsi_i2c_xfer,
65914a6ff2cSmario.six@gdsys.cc 	.probe_chip	= mvtwsi_i2c_probe_chip,
66014a6ff2cSmario.six@gdsys.cc 	.set_bus_speed	= mvtwsi_i2c_set_bus_speed,
66114a6ff2cSmario.six@gdsys.cc };
66214a6ff2cSmario.six@gdsys.cc 
66314a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
66414a6ff2cSmario.six@gdsys.cc 	{ .compatible = "marvell,mv64xxx-i2c", },
66514a6ff2cSmario.six@gdsys.cc 	{ /* sentinel */ }
66614a6ff2cSmario.six@gdsys.cc };
66714a6ff2cSmario.six@gdsys.cc 
66814a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
66914a6ff2cSmario.six@gdsys.cc 	.name = "i2c_mvtwsi",
67014a6ff2cSmario.six@gdsys.cc 	.id = UCLASS_I2C,
67114a6ff2cSmario.six@gdsys.cc 	.of_match = mvtwsi_i2c_ids,
67214a6ff2cSmario.six@gdsys.cc 	.probe = mvtwsi_i2c_probe,
67314a6ff2cSmario.six@gdsys.cc 	.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
67414a6ff2cSmario.six@gdsys.cc 	.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
67514a6ff2cSmario.six@gdsys.cc 	.ops = &mvtwsi_i2c_ops,
67614a6ff2cSmario.six@gdsys.cc };
67714a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
678