xref: /rk3399_rockchip-uboot/drivers/i2c/mvtwsi.c (revision 14a6ff2c4f22010e5d67f25508f09e3b53a1f1c4)
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*14a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
16*14a6ff2cSmario.six@gdsys.cc #include <dm.h>
17*14a6ff2cSmario.six@gdsys.cc #endif
18*14a6ff2cSmario.six@gdsys.cc 
19*14a6ff2cSmario.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 
26*14a6ff2cSmario.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
36*14a6ff2cSmario.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 
71*14a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
72*14a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
73*14a6ff2cSmario.six@gdsys.cc 	/* TWSI Register base for the device */
74*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_registers *base;
75*14a6ff2cSmario.six@gdsys.cc 	/* Number of the device (determined from cell-index property) */
76*14a6ff2cSmario.six@gdsys.cc 	int index;
77*14a6ff2cSmario.six@gdsys.cc 	/* The I2C slave address for the device */
78*14a6ff2cSmario.six@gdsys.cc 	u8 slaveadd;
79*14a6ff2cSmario.six@gdsys.cc 	/* The configured I2C speed in Hz */
80*14a6ff2cSmario.six@gdsys.cc 	uint speed;
81*14a6ff2cSmario.six@gdsys.cc };
82*14a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
83*14a6ff2cSmario.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 
157*14a6ff2cSmario.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 }
196*14a6ff2cSmario.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;
45201ec99d9SAlbert Aribaud 
45349c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send the address bytes */
4543c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1));
45549c801bfSmario.six@gdsys.cc 	/* Send address bytes */
456306563a7SAlbert Aribaud 	while ((status == 0) && alen--)
457f8a10ed1Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK);
45849c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
459306563a7SAlbert Aribaud 	if (status == 0)
4603c4db636Smario.six@gdsys.cc 		status = i2c_begin(twsi, MVTWSI_STATUS_REPEATED_START,
461670514f5Smario.six@gdsys.cc 				   (chip << 1) | 1);
462670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
463670514f5Smario.six@gdsys.cc 	 * read */
464670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
4653c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
466670514f5Smario.six@gdsys.cc 				   length > 0 ?
467670514f5Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK);
468306563a7SAlbert Aribaud 	/* Stop transaction */
4693c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
47049c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
471059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
47201ec99d9SAlbert Aribaud }
47301ec99d9SAlbert Aribaud 
474306563a7SAlbert Aribaud /*
475306563a7SAlbert Aribaud  * Begin write, send address byte(s), send data bytes, end.
476306563a7SAlbert Aribaud  */
4773c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
478f8a10ed1Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length)
47901ec99d9SAlbert Aribaud {
480059fce9fSmario.six@gdsys.cc 	int status, stop_status;
48101ec99d9SAlbert Aribaud 
48249c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
48349c801bfSmario.six@gdsys.cc 	 * data bytes */
4843c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1));
48549c801bfSmario.six@gdsys.cc 	/* Send address bytes */
486f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
487f8a10ed1Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK);
48849c801bfSmario.six@gdsys.cc 	/* Send data bytes */
489306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
4903c4db636Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK);
491306563a7SAlbert Aribaud 	/* Stop transaction */
4923c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
49349c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
494059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
49501ec99d9SAlbert Aribaud }
49601ec99d9SAlbert Aribaud 
497*14a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
49861bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
49961bc02b2Smario.six@gdsys.cc 			  int slaveadd)
50061bc02b2Smario.six@gdsys.cc {
5013c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5023c4db636Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd);
50361bc02b2Smario.six@gdsys.cc }
50461bc02b2Smario.six@gdsys.cc 
50561bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
50661bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
50761bc02b2Smario.six@gdsys.cc {
5083c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5093c4db636Smario.six@gdsys.cc 	return __twsi_i2c_set_bus_speed(twsi, requested_speed);
51061bc02b2Smario.six@gdsys.cc }
51161bc02b2Smario.six@gdsys.cc 
51261bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
51361bc02b2Smario.six@gdsys.cc {
5143c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
5153c4db636Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip);
51661bc02b2Smario.six@gdsys.cc }
51761bc02b2Smario.six@gdsys.cc 
51861bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
51961bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
52061bc02b2Smario.six@gdsys.cc {
5213c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
522f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
523f8a10ed1Smario.six@gdsys.cc 
524f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
525f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
526f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
527f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
528f8a10ed1Smario.six@gdsys.cc 
529f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length);
53061bc02b2Smario.six@gdsys.cc }
53161bc02b2Smario.six@gdsys.cc 
53261bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
53361bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
53461bc02b2Smario.six@gdsys.cc {
5353c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
536f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
537f8a10ed1Smario.six@gdsys.cc 
538f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
539f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
540f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
541f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
542f8a10ed1Smario.six@gdsys.cc 
543f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length);
54461bc02b2Smario.six@gdsys.cc }
54561bc02b2Smario.six@gdsys.cc 
546dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
5470db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
5480db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
5490db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
5500db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
551dd82242bSPaul Kocialkowski #endif
552dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
553dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
554dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
555dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
556dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
557dd82242bSPaul Kocialkowski 
558dd82242bSPaul Kocialkowski #endif
559dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
560dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
561dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
562dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
563dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
564dd82242bSPaul Kocialkowski 
565dd82242bSPaul Kocialkowski #endif
566dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
567dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
568dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
569dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
570dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
571dd82242bSPaul Kocialkowski 
572dd82242bSPaul Kocialkowski #endif
573dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
574dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
575dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
576dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
577dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
578dd82242bSPaul Kocialkowski 
579dd82242bSPaul Kocialkowski #endif
5809d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
5819d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
5829d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
5839d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
5849d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
5859d082687SJelle van der Waa 
5869d082687SJelle van der Waa #endif
587*14a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
588*14a6ff2cSmario.six@gdsys.cc 
589*14a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
590*14a6ff2cSmario.six@gdsys.cc 				 u32 chip_flags)
591*14a6ff2cSmario.six@gdsys.cc {
592*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
593*14a6ff2cSmario.six@gdsys.cc 	return __twsi_i2c_probe_chip(dev->base, chip_addr);
594*14a6ff2cSmario.six@gdsys.cc }
595*14a6ff2cSmario.six@gdsys.cc 
596*14a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
597*14a6ff2cSmario.six@gdsys.cc {
598*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
599*14a6ff2cSmario.six@gdsys.cc 	return __twsi_i2c_set_bus_speed(dev->base, speed);
600*14a6ff2cSmario.six@gdsys.cc }
601*14a6ff2cSmario.six@gdsys.cc 
602*14a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
603*14a6ff2cSmario.six@gdsys.cc {
604*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
605*14a6ff2cSmario.six@gdsys.cc 
606*14a6ff2cSmario.six@gdsys.cc 	dev->base = dev_get_addr_ptr(bus);
607*14a6ff2cSmario.six@gdsys.cc 
608*14a6ff2cSmario.six@gdsys.cc 	if (!dev->base)
609*14a6ff2cSmario.six@gdsys.cc 		return -ENOMEM;
610*14a6ff2cSmario.six@gdsys.cc 
611*14a6ff2cSmario.six@gdsys.cc 	dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
612*14a6ff2cSmario.six@gdsys.cc 				    "cell-index", -1);
613*14a6ff2cSmario.six@gdsys.cc 	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
614*14a6ff2cSmario.six@gdsys.cc 				       "u-boot,i2c-slave-addr", 0x0);
615*14a6ff2cSmario.six@gdsys.cc 	dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
616*14a6ff2cSmario.six@gdsys.cc 				    "clock-frequency", 100000);
617*14a6ff2cSmario.six@gdsys.cc 	return 0;
618*14a6ff2cSmario.six@gdsys.cc }
619*14a6ff2cSmario.six@gdsys.cc 
620*14a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
621*14a6ff2cSmario.six@gdsys.cc {
622*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
623*14a6ff2cSmario.six@gdsys.cc 	__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd);
624*14a6ff2cSmario.six@gdsys.cc 	return 0;
625*14a6ff2cSmario.six@gdsys.cc }
626*14a6ff2cSmario.six@gdsys.cc 
627*14a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
628*14a6ff2cSmario.six@gdsys.cc {
629*14a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
630*14a6ff2cSmario.six@gdsys.cc 	struct i2c_msg *dmsg, *omsg, dummy;
631*14a6ff2cSmario.six@gdsys.cc 
632*14a6ff2cSmario.six@gdsys.cc 	memset(&dummy, 0, sizeof(struct i2c_msg));
633*14a6ff2cSmario.six@gdsys.cc 
634*14a6ff2cSmario.six@gdsys.cc 	/* We expect either two messages (one with an offset and one with the
635*14a6ff2cSmario.six@gdsys.cc 	 * actual data) or one message (just data or offset/data combined) */
636*14a6ff2cSmario.six@gdsys.cc 	if (nmsgs > 2 || nmsgs == 0) {
637*14a6ff2cSmario.six@gdsys.cc 		debug("%s: Only one or two messages are supported.", __func__);
638*14a6ff2cSmario.six@gdsys.cc 		return -1;
639*14a6ff2cSmario.six@gdsys.cc 	}
640*14a6ff2cSmario.six@gdsys.cc 
641*14a6ff2cSmario.six@gdsys.cc 	omsg = nmsgs == 1 ? &dummy : msg;
642*14a6ff2cSmario.six@gdsys.cc 	dmsg = nmsgs == 1 ? msg : msg + 1;
643*14a6ff2cSmario.six@gdsys.cc 
644*14a6ff2cSmario.six@gdsys.cc 	if (dmsg->flags & I2C_M_RD)
645*14a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
646*14a6ff2cSmario.six@gdsys.cc 				       omsg->len, dmsg->buf, dmsg->len);
647*14a6ff2cSmario.six@gdsys.cc 	else
648*14a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
649*14a6ff2cSmario.six@gdsys.cc 					omsg->len, dmsg->buf, dmsg->len);
650*14a6ff2cSmario.six@gdsys.cc }
651*14a6ff2cSmario.six@gdsys.cc 
652*14a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
653*14a6ff2cSmario.six@gdsys.cc 	.xfer		= mvtwsi_i2c_xfer,
654*14a6ff2cSmario.six@gdsys.cc 	.probe_chip	= mvtwsi_i2c_probe_chip,
655*14a6ff2cSmario.six@gdsys.cc 	.set_bus_speed	= mvtwsi_i2c_set_bus_speed,
656*14a6ff2cSmario.six@gdsys.cc };
657*14a6ff2cSmario.six@gdsys.cc 
658*14a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
659*14a6ff2cSmario.six@gdsys.cc 	{ .compatible = "marvell,mv64xxx-i2c", },
660*14a6ff2cSmario.six@gdsys.cc 	{ /* sentinel */ }
661*14a6ff2cSmario.six@gdsys.cc };
662*14a6ff2cSmario.six@gdsys.cc 
663*14a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
664*14a6ff2cSmario.six@gdsys.cc 	.name = "i2c_mvtwsi",
665*14a6ff2cSmario.six@gdsys.cc 	.id = UCLASS_I2C,
666*14a6ff2cSmario.six@gdsys.cc 	.of_match = mvtwsi_i2c_ids,
667*14a6ff2cSmario.six@gdsys.cc 	.probe = mvtwsi_i2c_probe,
668*14a6ff2cSmario.six@gdsys.cc 	.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
669*14a6ff2cSmario.six@gdsys.cc 	.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
670*14a6ff2cSmario.six@gdsys.cc 	.ops = &mvtwsi_i2c_ops,
671*14a6ff2cSmario.six@gdsys.cc };
672*14a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
673