xref: /rk3399_rockchip-uboot/drivers/i2c/mvtwsi.c (revision f8a10ed1fd9986362a39f2b18d89429dfdb078cb)
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>
1501ec99d9SAlbert Aribaud 
16306563a7SAlbert Aribaud /*
1749c801bfSmario.six@gdsys.cc  * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
1849c801bfSmario.six@gdsys.cc  * settings
19306563a7SAlbert Aribaud  */
2001ec99d9SAlbert Aribaud 
21306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X)
22306563a7SAlbert Aribaud #include <asm/arch/orion5x.h>
2381e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
243dc23f78SStefan Roese #include <asm/arch/soc.h>
256620377eSHans de Goede #elif defined(CONFIG_SUNXI)
266620377eSHans de Goede #include <asm/arch/i2c.h>
27306563a7SAlbert Aribaud #else
28306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board
2901ec99d9SAlbert Aribaud #endif
3001ec99d9SAlbert Aribaud 
3101ec99d9SAlbert Aribaud /*
32306563a7SAlbert Aribaud  * TWSI register structure
3301ec99d9SAlbert Aribaud  */
3401ec99d9SAlbert Aribaud 
356620377eSHans de Goede #ifdef CONFIG_SUNXI
366620377eSHans de Goede 
376620377eSHans de Goede struct  mvtwsi_registers {
386620377eSHans de Goede 	u32 slave_address;
396620377eSHans de Goede 	u32 xtnd_slave_addr;
406620377eSHans de Goede 	u32 data;
416620377eSHans de Goede 	u32 control;
426620377eSHans de Goede 	u32 status;
436620377eSHans de Goede 	u32 baudrate;
446620377eSHans de Goede 	u32 soft_reset;
456620377eSHans de Goede };
466620377eSHans de Goede 
476620377eSHans de Goede #else
486620377eSHans de Goede 
49306563a7SAlbert Aribaud struct  mvtwsi_registers {
50306563a7SAlbert Aribaud 	u32 slave_address;
51306563a7SAlbert Aribaud 	u32 data;
52306563a7SAlbert Aribaud 	u32 control;
53306563a7SAlbert Aribaud 	union {
5449c801bfSmario.six@gdsys.cc 		u32 status;	/* When reading */
5549c801bfSmario.six@gdsys.cc 		u32 baudrate;	/* When writing */
56306563a7SAlbert Aribaud 	};
57306563a7SAlbert Aribaud 	u32 xtnd_slave_addr;
58306563a7SAlbert Aribaud 	u32 reserved[2];
59306563a7SAlbert Aribaud 	u32 soft_reset;
60306563a7SAlbert Aribaud };
61306563a7SAlbert Aribaud 
626620377eSHans de Goede #endif
636620377eSHans de Goede 
64306563a7SAlbert Aribaud /*
65dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
66dfc3958cSmario.six@gdsys.cc  * register
67306563a7SAlbert Aribaud  */
68dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
69dfc3958cSmario.six@gdsys.cc 	/* Acknowledge bit */
70dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_ACK	= 0x00000004,
71dfc3958cSmario.six@gdsys.cc 	/* Interrupt flag */
72dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_IFLG	= 0x00000008,
73dfc3958cSmario.six@gdsys.cc 	/* Stop bit */
74dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_STOP	= 0x00000010,
75dfc3958cSmario.six@gdsys.cc 	/* Start bit */
76dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_START	= 0x00000020,
77dfc3958cSmario.six@gdsys.cc 	/* I2C enable */
78dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_TWSIEN	= 0x00000040,
79dfc3958cSmario.six@gdsys.cc 	/* Interrupt enable */
80dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_INTEN	= 0x00000080,
81dfc3958cSmario.six@gdsys.cc };
82306563a7SAlbert Aribaud 
83306563a7SAlbert Aribaud /*
8449c801bfSmario.six@gdsys.cc  * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
8549c801bfSmario.six@gdsys.cc  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
86904dfbfdSHans de Goede  */
87904dfbfdSHans de Goede 
88904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
89904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
90904dfbfdSHans de Goede #else
91904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
92904dfbfdSHans de Goede #endif
93904dfbfdSHans de Goede 
94904dfbfdSHans de Goede /*
95dfc3958cSmario.six@gdsys.cc  * enum mvstwsi_status_values - Possible values of I2C controller's status
96dfc3958cSmario.six@gdsys.cc  * register
97dfc3958cSmario.six@gdsys.cc  *
98dfc3958cSmario.six@gdsys.cc  * Only those statuses expected in normal master operation on
99dfc3958cSmario.six@gdsys.cc  * non-10-bit-address devices are specified.
100dfc3958cSmario.six@gdsys.cc  *
101dfc3958cSmario.six@gdsys.cc  * Every status that's unexpected during normal operation (bus errors,
102dfc3958cSmario.six@gdsys.cc  * arbitration losses, missing ACKs...) is passed back to the caller as an error
103306563a7SAlbert Aribaud  * code.
104306563a7SAlbert Aribaud  */
105dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
106dfc3958cSmario.six@gdsys.cc 	/* START condition transmitted */
107dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_START		= 0x08,
108dfc3958cSmario.six@gdsys.cc 	/* Repeated START condition transmitted */
109dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_REPEATED_START	= 0x10,
110dfc3958cSmario.six@gdsys.cc 	/* Address + write bit transmitted, ACK received */
111dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_W_ACK	= 0x18,
112dfc3958cSmario.six@gdsys.cc 	/* Data transmitted, ACK received */
113dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_W_ACK	= 0x28,
114dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK received */
115dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_ACK	= 0x40,
116dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK not received */
117dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_NAK	= 0x48,
118dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK transmitted */
119dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_ACK	= 0x50,
120dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK not transmitted */
121dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_NAK	= 0x58,
122dfc3958cSmario.six@gdsys.cc 	/* No relevant status */
123dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_IDLE		= 0xF8,
124dfc3958cSmario.six@gdsys.cc };
125306563a7SAlbert Aribaud 
126306563a7SAlbert Aribaud /*
127670514f5Smario.six@gdsys.cc  * enum mvstwsi_ack_flags - Determine whether a read byte should be
128670514f5Smario.six@gdsys.cc  * acknowledged or not.
129670514f5Smario.six@gdsys.cc  */
130670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
131670514f5Smario.six@gdsys.cc 	/* Send NAK after received byte */
132670514f5Smario.six@gdsys.cc 	MVTWSI_READ_NAK = 0,
133670514f5Smario.six@gdsys.cc 	/* Send ACK after received byte */
134670514f5Smario.six@gdsys.cc 	MVTWSI_READ_ACK = 1,
135670514f5Smario.six@gdsys.cc };
136670514f5Smario.six@gdsys.cc 
137670514f5Smario.six@gdsys.cc /*
138dd82242bSPaul Kocialkowski  * MVTWSI controller base
139306563a7SAlbert Aribaud  */
140306563a7SAlbert Aribaud 
141dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
142dd82242bSPaul Kocialkowski {
143dd82242bSPaul Kocialkowski 	switch (adap->hwadapnr) {
144dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
145dd82242bSPaul Kocialkowski 	case 0:
146dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
147dd82242bSPaul Kocialkowski #endif
148dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
149dd82242bSPaul Kocialkowski 	case 1:
150dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
151dd82242bSPaul Kocialkowski #endif
152dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
153dd82242bSPaul Kocialkowski 	case 2:
154dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
155dd82242bSPaul Kocialkowski #endif
156dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
157dd82242bSPaul Kocialkowski 	case 3:
158dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
159dd82242bSPaul Kocialkowski #endif
160dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
161dd82242bSPaul Kocialkowski 	case 4:
162dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
163dd82242bSPaul Kocialkowski #endif
1649d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
1659d082687SJelle van der Waa 	case 5:
1669d082687SJelle van der Waa 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
1679d082687SJelle van der Waa #endif
168dd82242bSPaul Kocialkowski 	default:
169dd82242bSPaul Kocialkowski 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
170dd82242bSPaul Kocialkowski 		break;
171dd82242bSPaul Kocialkowski 	}
172dd82242bSPaul Kocialkowski 
173dd82242bSPaul Kocialkowski 	return NULL;
174dd82242bSPaul Kocialkowski }
175306563a7SAlbert Aribaud 
176306563a7SAlbert Aribaud /*
177dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_error_class - types of I2C errors
178306563a7SAlbert Aribaud  */
179dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
180dfc3958cSmario.six@gdsys.cc 	/* The controller returned a different status than expected */
181dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_WRONG_STATUS       = 0x01,
182dfc3958cSmario.six@gdsys.cc 	/* The controller timed out */
183dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_TIMEOUT            = 0x02,
184dfc3958cSmario.six@gdsys.cc };
185306563a7SAlbert Aribaud 
186dfc3958cSmario.six@gdsys.cc /*
187dfc3958cSmario.six@gdsys.cc  * mvtwsi_error() - Build I2C return code from error information
188dfc3958cSmario.six@gdsys.cc  *
189dfc3958cSmario.six@gdsys.cc  * For debugging purposes, this function packs some information of an occurred
190dfc3958cSmario.six@gdsys.cc  * error into a return code. These error codes are returned from I2C API
191dfc3958cSmario.six@gdsys.cc  * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
192dfc3958cSmario.six@gdsys.cc  *
193dfc3958cSmario.six@gdsys.cc  * @ec:		The error class of the error (enum mvtwsi_error_class).
194dfc3958cSmario.six@gdsys.cc  * @lc:		The last value of the control register.
195dfc3958cSmario.six@gdsys.cc  * @ls:		The last value of the status register.
196dfc3958cSmario.six@gdsys.cc  * @es:		The expected value of the status register.
197dfc3958cSmario.six@gdsys.cc  * @return The generated error code.
198dfc3958cSmario.six@gdsys.cc  */
199dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
200dfc3958cSmario.six@gdsys.cc {
201dfc3958cSmario.six@gdsys.cc 	return ((ec << 24) & 0xFF000000)
202dfc3958cSmario.six@gdsys.cc 	       | ((lc << 16) & 0x00FF0000)
203dfc3958cSmario.six@gdsys.cc 	       | ((ls << 8) & 0x0000FF00)
204dfc3958cSmario.six@gdsys.cc 	       | (es & 0xFF);
205dfc3958cSmario.six@gdsys.cc }
206306563a7SAlbert Aribaud 
207306563a7SAlbert Aribaud /*
20849c801bfSmario.six@gdsys.cc  * Wait for IFLG to raise, or return 'timeout.' Then, if the status is as
20949c801bfSmario.six@gdsys.cc  * expected, return 0 (ok) or 'wrong status' otherwise.
210306563a7SAlbert Aribaud  */
2113c4db636Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status)
21201ec99d9SAlbert Aribaud {
213306563a7SAlbert Aribaud 	int control, status;
214306563a7SAlbert Aribaud 	int timeout = 1000;
215306563a7SAlbert Aribaud 
216306563a7SAlbert Aribaud 	do {
217306563a7SAlbert Aribaud 		control = readl(&twsi->control);
218306563a7SAlbert Aribaud 		if (control & MVTWSI_CONTROL_IFLG) {
219306563a7SAlbert Aribaud 			status = readl(&twsi->status);
220306563a7SAlbert Aribaud 			if (status == expected_status)
221306563a7SAlbert Aribaud 				return 0;
22201ec99d9SAlbert Aribaud 			else
223dfc3958cSmario.six@gdsys.cc 				return mvtwsi_error(
224306563a7SAlbert Aribaud 					MVTWSI_ERROR_WRONG_STATUS,
225306563a7SAlbert Aribaud 					control, status, expected_status);
226306563a7SAlbert Aribaud 		}
22749c801bfSmario.six@gdsys.cc 		udelay(10); /* One clock cycle at 100 kHz */
228306563a7SAlbert Aribaud 	} while (timeout--);
229306563a7SAlbert Aribaud 	status = readl(&twsi->status);
230dfc3958cSmario.six@gdsys.cc 	return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
231dfc3958cSmario.six@gdsys.cc 			    expected_status);
23201ec99d9SAlbert Aribaud }
23301ec99d9SAlbert Aribaud 
234306563a7SAlbert Aribaud /*
235306563a7SAlbert Aribaud  * Assert the START condition, either in a single I2C transaction
236306563a7SAlbert Aribaud  * or inside back-to-back ones (repeated starts).
237306563a7SAlbert Aribaud  */
2383c4db636Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status)
239306563a7SAlbert Aribaud {
24049c801bfSmario.six@gdsys.cc 	/* Assert START */
241670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
2422ca02995SHans de Goede 	       MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
24349c801bfSmario.six@gdsys.cc 	/* Wait for controller to process START */
2443c4db636Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status);
245306563a7SAlbert Aribaud }
246306563a7SAlbert Aribaud 
247306563a7SAlbert Aribaud /*
248306563a7SAlbert Aribaud  * Send a byte (i2c address or data).
249306563a7SAlbert Aribaud  */
2503c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
2513c4db636Smario.six@gdsys.cc 		     int expected_status)
252306563a7SAlbert Aribaud {
25349c801bfSmario.six@gdsys.cc 	/* Write byte to data register for sending */
254306563a7SAlbert Aribaud 	writel(byte, &twsi->data);
25549c801bfSmario.six@gdsys.cc 	/* Clear any pending interrupt -- that will cause sending */
256670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
257670514f5Smario.six@gdsys.cc 	       &twsi->control);
25849c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and check ACK */
2593c4db636Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status);
260306563a7SAlbert Aribaud }
261306563a7SAlbert Aribaud 
262306563a7SAlbert Aribaud /*
263306563a7SAlbert Aribaud  * Receive a byte.
264306563a7SAlbert Aribaud  */
2653c4db636Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag)
266306563a7SAlbert Aribaud {
267670514f5Smario.six@gdsys.cc 	int expected_status, status, control;
268306563a7SAlbert Aribaud 
269670514f5Smario.six@gdsys.cc 	/* Compute expected status based on passed ACK flag */
270670514f5Smario.six@gdsys.cc 	expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
271670514f5Smario.six@gdsys.cc 			  MVTWSI_STATUS_DATA_R_NAK;
27249c801bfSmario.six@gdsys.cc 	/* Acknowledge *previous state*, and launch receive */
273670514f5Smario.six@gdsys.cc 	control = MVTWSI_CONTROL_TWSIEN;
274670514f5Smario.six@gdsys.cc 	control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
275670514f5Smario.six@gdsys.cc 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
27649c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and assert ACK or NAK */
2773c4db636Smario.six@gdsys.cc 	status = twsi_wait(twsi, expected_status);
27849c801bfSmario.six@gdsys.cc 	/* If we did receive the expected byte, store it */
279306563a7SAlbert Aribaud 	if (status == 0)
280306563a7SAlbert Aribaud 		*byte = readl(&twsi->data);
281306563a7SAlbert Aribaud 	return status;
282306563a7SAlbert Aribaud }
283306563a7SAlbert Aribaud 
284306563a7SAlbert Aribaud /*
285306563a7SAlbert Aribaud  * Assert the STOP condition.
28649c801bfSmario.six@gdsys.cc  * This is also used to force the bus back to idle (SDA = SCL = 1).
287306563a7SAlbert Aribaud  */
2883c4db636Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi)
289306563a7SAlbert Aribaud {
290306563a7SAlbert Aribaud 	int control, stop_status;
291059fce9fSmario.six@gdsys.cc 	int status = 0;
292306563a7SAlbert Aribaud 	int timeout = 1000;
293306563a7SAlbert Aribaud 
29449c801bfSmario.six@gdsys.cc 	/* Assert STOP */
295306563a7SAlbert Aribaud 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
296904dfbfdSHans de Goede 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
29749c801bfSmario.six@gdsys.cc 	/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
298306563a7SAlbert Aribaud 	do {
299306563a7SAlbert Aribaud 		stop_status = readl(&twsi->status);
300306563a7SAlbert Aribaud 		if (stop_status == MVTWSI_STATUS_IDLE)
301306563a7SAlbert Aribaud 			break;
30249c801bfSmario.six@gdsys.cc 		udelay(10); /* One clock cycle at 100 kHz */
303306563a7SAlbert Aribaud 	} while (timeout--);
304306563a7SAlbert Aribaud 	control = readl(&twsi->control);
305306563a7SAlbert Aribaud 	if (stop_status != MVTWSI_STATUS_IDLE)
306059fce9fSmario.six@gdsys.cc 		status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
307306563a7SAlbert Aribaud 				      control, status, MVTWSI_STATUS_IDLE);
308306563a7SAlbert Aribaud 	return status;
309306563a7SAlbert Aribaud }
310306563a7SAlbert Aribaud 
311e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
312f582a158SStefan Roese {
313f582a158SStefan Roese #ifdef CONFIG_SUNXI
314f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
315f582a158SStefan Roese #else
316f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
317f582a158SStefan Roese #endif
318f582a158SStefan Roese }
319306563a7SAlbert Aribaud 
320306563a7SAlbert Aribaud /*
321306563a7SAlbert Aribaud  * Reset controller.
322306563a7SAlbert Aribaud  * Controller reset also resets the baud rate and slave address, so
3230db2bbdcSHans de Goede  * they must be re-established afterwards.
324306563a7SAlbert Aribaud  */
3253c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
326306563a7SAlbert Aribaud {
32749c801bfSmario.six@gdsys.cc 	/* Reset controller */
328306563a7SAlbert Aribaud 	writel(0, &twsi->soft_reset);
32949c801bfSmario.six@gdsys.cc 	/* Wait 2 ms -- this is what the Marvell LSP does */
330306563a7SAlbert Aribaud 	udelay(20000);
331306563a7SAlbert Aribaud }
332306563a7SAlbert Aribaud 
333306563a7SAlbert Aribaud /*
33449c801bfSmario.six@gdsys.cc  * Sets baud to the highest possible value not exceeding the requested one.
335306563a7SAlbert Aribaud  */
3363c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
337e0758281Smario.six@gdsys.cc 				     uint requested_speed)
338306563a7SAlbert Aribaud {
339e0758281Smario.six@gdsys.cc 	uint tmp_speed, highest_speed, n, m;
340e0758281Smario.six@gdsys.cc 	uint baud = 0x44; /* Baud rate after controller reset */
341306563a7SAlbert Aribaud 
342306563a7SAlbert Aribaud 	highest_speed = 0;
34349c801bfSmario.six@gdsys.cc 	/* Successively try m, n combinations, and use the combination
34449c801bfSmario.six@gdsys.cc 	 * resulting in the largest speed that's not above the requested
34549c801bfSmario.six@gdsys.cc 	 * speed */
34601ec99d9SAlbert Aribaud 	for (n = 0; n < 8; n++) {
34701ec99d9SAlbert Aribaud 		for (m = 0; m < 16; m++) {
348f582a158SStefan Roese 			tmp_speed = twsi_calc_freq(n, m);
3499ec43b0cSmario.six@gdsys.cc 			if ((tmp_speed <= requested_speed) &&
3509ec43b0cSmario.six@gdsys.cc 			    (tmp_speed > highest_speed)) {
351306563a7SAlbert Aribaud 				highest_speed = tmp_speed;
352306563a7SAlbert Aribaud 				baud = (m << 3) | n;
35301ec99d9SAlbert Aribaud 			}
35401ec99d9SAlbert Aribaud 		}
35501ec99d9SAlbert Aribaud 	}
3560db2bbdcSHans de Goede 	writel(baud, &twsi->baudrate);
3570db2bbdcSHans de Goede 	return 0;
3580db2bbdcSHans de Goede }
3590db2bbdcSHans de Goede 
3603c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
3613c4db636Smario.six@gdsys.cc 			  int slaveadd)
3620db2bbdcSHans de Goede {
36349c801bfSmario.six@gdsys.cc 	/* Reset controller */
3643c4db636Smario.six@gdsys.cc 	twsi_reset(twsi);
36549c801bfSmario.six@gdsys.cc 	/* Set speed */
3663c4db636Smario.six@gdsys.cc 	__twsi_i2c_set_bus_speed(twsi, speed);
36749c801bfSmario.six@gdsys.cc 	/* Set slave address; even though we don't use it */
3680db2bbdcSHans de Goede 	writel(slaveadd, &twsi->slave_address);
3690db2bbdcSHans de Goede 	writel(0, &twsi->xtnd_slave_addr);
37049c801bfSmario.six@gdsys.cc 	/* Assert STOP, but don't care for the result */
3713c4db636Smario.six@gdsys.cc 	(void) twsi_stop(twsi);
37201ec99d9SAlbert Aribaud }
37301ec99d9SAlbert Aribaud 
37401ec99d9SAlbert Aribaud /*
375306563a7SAlbert Aribaud  * Begin I2C transaction with expected start status, at given address.
376306563a7SAlbert Aribaud  * Expected address status will derive from direction bit (bit 0) in addr.
37701ec99d9SAlbert Aribaud  */
3783c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
379670514f5Smario.six@gdsys.cc 		     u8 addr)
38001ec99d9SAlbert Aribaud {
381306563a7SAlbert Aribaud 	int status, expected_addr_status;
38201ec99d9SAlbert Aribaud 
38349c801bfSmario.six@gdsys.cc 	/* Compute the expected address status from the direction bit in
38449c801bfSmario.six@gdsys.cc 	 * the address byte */
38549c801bfSmario.six@gdsys.cc 	if (addr & 1) /* Reading */
386306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
38749c801bfSmario.six@gdsys.cc 	else /* Writing */
388306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
38949c801bfSmario.six@gdsys.cc 	/* Assert START */
3903c4db636Smario.six@gdsys.cc 	status = twsi_start(twsi, expected_start_status);
39149c801bfSmario.six@gdsys.cc 	/* Send out the address if the start went well */
392306563a7SAlbert Aribaud 	if (status == 0)
3933c4db636Smario.six@gdsys.cc 		status = twsi_send(twsi, addr, expected_addr_status);
39449c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
395306563a7SAlbert Aribaud 	return status;
39601ec99d9SAlbert Aribaud }
39701ec99d9SAlbert Aribaud 
398306563a7SAlbert Aribaud /*
399306563a7SAlbert Aribaud  * Begin read, nak data byte, end.
400306563a7SAlbert Aribaud  */
4013c4db636Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip)
40201ec99d9SAlbert Aribaud {
403306563a7SAlbert Aribaud 	u8 dummy_byte;
404306563a7SAlbert Aribaud 	int status;
40501ec99d9SAlbert Aribaud 
40649c801bfSmario.six@gdsys.cc 	/* Begin i2c read */
4073c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1);
40849c801bfSmario.six@gdsys.cc 	/* Dummy read was accepted: receive byte, but NAK it. */
409306563a7SAlbert Aribaud 	if (status == 0)
4103c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK);
411306563a7SAlbert Aribaud 	/* Stop transaction */
4123c4db636Smario.six@gdsys.cc 	twsi_stop(twsi);
41349c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
414306563a7SAlbert Aribaud 	return status;
41501ec99d9SAlbert Aribaud }
41601ec99d9SAlbert Aribaud 
417306563a7SAlbert Aribaud /*
418306563a7SAlbert Aribaud  * Begin write, send address byte(s), begin read, receive data bytes, end.
419306563a7SAlbert Aribaud  *
42049c801bfSmario.six@gdsys.cc  * NOTE: Some devices want a stop right before the second start, while some
42149c801bfSmario.six@gdsys.cc  * will choke if it is there. Since deciding this is not yet supported in
42249c801bfSmario.six@gdsys.cc  * higher level APIs, we need to make a decision here, and for the moment that
42349c801bfSmario.six@gdsys.cc  * will be a repeated start without a preceding stop.
424306563a7SAlbert Aribaud  */
4253c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
426*f8a10ed1Smario.six@gdsys.cc 			   u8 *addr, int alen, uchar *data, int length)
42701ec99d9SAlbert Aribaud {
428059fce9fSmario.six@gdsys.cc 	int status = 0;
429059fce9fSmario.six@gdsys.cc 	int stop_status;
43001ec99d9SAlbert Aribaud 
43149c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send the address bytes */
4323c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1));
43349c801bfSmario.six@gdsys.cc 	/* Send address bytes */
434306563a7SAlbert Aribaud 	while ((status == 0) && alen--)
435*f8a10ed1Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK);
43649c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
437306563a7SAlbert Aribaud 	if (status == 0)
4383c4db636Smario.six@gdsys.cc 		status = i2c_begin(twsi, MVTWSI_STATUS_REPEATED_START,
439670514f5Smario.six@gdsys.cc 				   (chip << 1) | 1);
440670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
441670514f5Smario.six@gdsys.cc 	 * read */
442670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
4433c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
444670514f5Smario.six@gdsys.cc 				   length > 0 ?
445670514f5Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK);
446306563a7SAlbert Aribaud 	/* Stop transaction */
4473c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
44849c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
449059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
45001ec99d9SAlbert Aribaud }
45101ec99d9SAlbert Aribaud 
452306563a7SAlbert Aribaud /*
453306563a7SAlbert Aribaud  * Begin write, send address byte(s), send data bytes, end.
454306563a7SAlbert Aribaud  */
4553c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
456*f8a10ed1Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length)
45701ec99d9SAlbert Aribaud {
458059fce9fSmario.six@gdsys.cc 	int status, stop_status;
45901ec99d9SAlbert Aribaud 
46049c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
46149c801bfSmario.six@gdsys.cc 	 * data bytes */
4623c4db636Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1));
46349c801bfSmario.six@gdsys.cc 	/* Send address bytes */
464*f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
465*f8a10ed1Smario.six@gdsys.cc 		status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK);
46649c801bfSmario.six@gdsys.cc 	/* Send data bytes */
467306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
4683c4db636Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK);
469306563a7SAlbert Aribaud 	/* Stop transaction */
4703c4db636Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi);
47149c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
472059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
47301ec99d9SAlbert Aribaud }
47401ec99d9SAlbert Aribaud 
47561bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
47661bc02b2Smario.six@gdsys.cc 			  int slaveadd)
47761bc02b2Smario.six@gdsys.cc {
4783c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
4793c4db636Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd);
48061bc02b2Smario.six@gdsys.cc }
48161bc02b2Smario.six@gdsys.cc 
48261bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
48361bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
48461bc02b2Smario.six@gdsys.cc {
4853c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
4863c4db636Smario.six@gdsys.cc 	return __twsi_i2c_set_bus_speed(twsi, requested_speed);
48761bc02b2Smario.six@gdsys.cc }
48861bc02b2Smario.six@gdsys.cc 
48961bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
49061bc02b2Smario.six@gdsys.cc {
4913c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
4923c4db636Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip);
49361bc02b2Smario.six@gdsys.cc }
49461bc02b2Smario.six@gdsys.cc 
49561bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
49661bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
49761bc02b2Smario.six@gdsys.cc {
4983c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
499*f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
500*f8a10ed1Smario.six@gdsys.cc 
501*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
502*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
503*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
504*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
505*f8a10ed1Smario.six@gdsys.cc 
506*f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length);
50761bc02b2Smario.six@gdsys.cc }
50861bc02b2Smario.six@gdsys.cc 
50961bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
51061bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
51161bc02b2Smario.six@gdsys.cc {
5123c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
513*f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
514*f8a10ed1Smario.six@gdsys.cc 
515*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
516*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
517*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
518*f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
519*f8a10ed1Smario.six@gdsys.cc 
520*f8a10ed1Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length);
52161bc02b2Smario.six@gdsys.cc }
52261bc02b2Smario.six@gdsys.cc 
523dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
5240db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
5250db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
5260db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
5270db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
528dd82242bSPaul Kocialkowski #endif
529dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
530dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
531dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
532dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
533dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
534dd82242bSPaul Kocialkowski 
535dd82242bSPaul Kocialkowski #endif
536dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
537dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
538dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
539dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
540dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
541dd82242bSPaul Kocialkowski 
542dd82242bSPaul Kocialkowski #endif
543dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
544dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
545dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
546dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
547dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
548dd82242bSPaul Kocialkowski 
549dd82242bSPaul Kocialkowski #endif
550dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
551dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
552dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
553dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
554dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
555dd82242bSPaul Kocialkowski 
556dd82242bSPaul Kocialkowski #endif
5579d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
5589d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
5599d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
5609d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
5619d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
5629d082687SJelle van der Waa 
5639d082687SJelle van der Waa #endif
564