xref: /rk3399_rockchip-uboot/drivers/i2c/mvtwsi.c (revision 03d6cd972efb7289ef208ba4bad72d1e7acccf1d)
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>
15c68c6243Smario.six@gdsys.cc #include <linux/compat.h>
1614a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
1714a6ff2cSmario.six@gdsys.cc #include <dm.h>
1814a6ff2cSmario.six@gdsys.cc #endif
1914a6ff2cSmario.six@gdsys.cc 
2014a6ff2cSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR;
2101ec99d9SAlbert Aribaud 
22306563a7SAlbert Aribaud /*
2349c801bfSmario.six@gdsys.cc  * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
2449c801bfSmario.six@gdsys.cc  * settings
25306563a7SAlbert Aribaud  */
2601ec99d9SAlbert Aribaud 
2714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
28306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X)
29306563a7SAlbert Aribaud #include <asm/arch/orion5x.h>
3081e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
313dc23f78SStefan Roese #include <asm/arch/soc.h>
326620377eSHans de Goede #elif defined(CONFIG_SUNXI)
336620377eSHans de Goede #include <asm/arch/i2c.h>
34306563a7SAlbert Aribaud #else
35306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board
3601ec99d9SAlbert Aribaud #endif
3714a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
3801ec99d9SAlbert Aribaud 
3901ec99d9SAlbert Aribaud /*
40306563a7SAlbert Aribaud  * TWSI register structure
4101ec99d9SAlbert Aribaud  */
4201ec99d9SAlbert Aribaud 
436620377eSHans de Goede #ifdef CONFIG_SUNXI
446620377eSHans de Goede 
456620377eSHans de Goede struct  mvtwsi_registers {
466620377eSHans de Goede 	u32 slave_address;
476620377eSHans de Goede 	u32 xtnd_slave_addr;
486620377eSHans de Goede 	u32 data;
496620377eSHans de Goede 	u32 control;
506620377eSHans de Goede 	u32 status;
516620377eSHans de Goede 	u32 baudrate;
526620377eSHans de Goede 	u32 soft_reset;
536620377eSHans de Goede };
546620377eSHans de Goede 
556620377eSHans de Goede #else
566620377eSHans de Goede 
57306563a7SAlbert Aribaud struct  mvtwsi_registers {
58306563a7SAlbert Aribaud 	u32 slave_address;
59306563a7SAlbert Aribaud 	u32 data;
60306563a7SAlbert Aribaud 	u32 control;
61306563a7SAlbert Aribaud 	union {
6249c801bfSmario.six@gdsys.cc 		u32 status;	/* When reading */
6349c801bfSmario.six@gdsys.cc 		u32 baudrate;	/* When writing */
64306563a7SAlbert Aribaud 	};
65306563a7SAlbert Aribaud 	u32 xtnd_slave_addr;
66306563a7SAlbert Aribaud 	u32 reserved[2];
67306563a7SAlbert Aribaud 	u32 soft_reset;
68306563a7SAlbert Aribaud };
69306563a7SAlbert Aribaud 
706620377eSHans de Goede #endif
716620377eSHans de Goede 
7214a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
7314a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
7414a6ff2cSmario.six@gdsys.cc 	/* TWSI Register base for the device */
7514a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_registers *base;
7614a6ff2cSmario.six@gdsys.cc 	/* Number of the device (determined from cell-index property) */
7714a6ff2cSmario.six@gdsys.cc 	int index;
7814a6ff2cSmario.six@gdsys.cc 	/* The I2C slave address for the device */
7914a6ff2cSmario.six@gdsys.cc 	u8 slaveadd;
8014a6ff2cSmario.six@gdsys.cc 	/* The configured I2C speed in Hz */
8114a6ff2cSmario.six@gdsys.cc 	uint speed;
82c68c6243Smario.six@gdsys.cc 	/* The current length of a clock period (depending on speed) */
83c68c6243Smario.six@gdsys.cc 	uint tick;
8414a6ff2cSmario.six@gdsys.cc };
8514a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
8614a6ff2cSmario.six@gdsys.cc 
87306563a7SAlbert Aribaud /*
88dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
89dfc3958cSmario.six@gdsys.cc  * register
90306563a7SAlbert Aribaud  */
91dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
92dfc3958cSmario.six@gdsys.cc 	/* Acknowledge bit */
93dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_ACK	= 0x00000004,
94dfc3958cSmario.six@gdsys.cc 	/* Interrupt flag */
95dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_IFLG	= 0x00000008,
96dfc3958cSmario.six@gdsys.cc 	/* Stop bit */
97dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_STOP	= 0x00000010,
98dfc3958cSmario.six@gdsys.cc 	/* Start bit */
99dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_START	= 0x00000020,
100dfc3958cSmario.six@gdsys.cc 	/* I2C enable */
101dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_TWSIEN	= 0x00000040,
102dfc3958cSmario.six@gdsys.cc 	/* Interrupt enable */
103dfc3958cSmario.six@gdsys.cc 	MVTWSI_CONTROL_INTEN	= 0x00000080,
104dfc3958cSmario.six@gdsys.cc };
105306563a7SAlbert Aribaud 
106306563a7SAlbert Aribaud /*
10749c801bfSmario.six@gdsys.cc  * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
10849c801bfSmario.six@gdsys.cc  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
109904dfbfdSHans de Goede  */
110904dfbfdSHans de Goede 
111904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
112904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000008
113904dfbfdSHans de Goede #else
114904dfbfdSHans de Goede #define	MVTWSI_CONTROL_CLEAR_IFLG	0x00000000
115904dfbfdSHans de Goede #endif
116904dfbfdSHans de Goede 
117904dfbfdSHans de Goede /*
118dfc3958cSmario.six@gdsys.cc  * enum mvstwsi_status_values - Possible values of I2C controller's status
119dfc3958cSmario.six@gdsys.cc  * register
120dfc3958cSmario.six@gdsys.cc  *
121dfc3958cSmario.six@gdsys.cc  * Only those statuses expected in normal master operation on
122dfc3958cSmario.six@gdsys.cc  * non-10-bit-address devices are specified.
123dfc3958cSmario.six@gdsys.cc  *
124dfc3958cSmario.six@gdsys.cc  * Every status that's unexpected during normal operation (bus errors,
125dfc3958cSmario.six@gdsys.cc  * arbitration losses, missing ACKs...) is passed back to the caller as an error
126306563a7SAlbert Aribaud  * code.
127306563a7SAlbert Aribaud  */
128dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
129dfc3958cSmario.six@gdsys.cc 	/* START condition transmitted */
130dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_START		= 0x08,
131dfc3958cSmario.six@gdsys.cc 	/* Repeated START condition transmitted */
132dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_REPEATED_START	= 0x10,
133dfc3958cSmario.six@gdsys.cc 	/* Address + write bit transmitted, ACK received */
134dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_W_ACK	= 0x18,
135dfc3958cSmario.six@gdsys.cc 	/* Data transmitted, ACK received */
136dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_W_ACK	= 0x28,
137dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK received */
138dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_ACK	= 0x40,
139dfc3958cSmario.six@gdsys.cc 	/* Address + read bit transmitted, ACK not received */
140dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_ADDR_R_NAK	= 0x48,
141dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK transmitted */
142dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_ACK	= 0x50,
143dfc3958cSmario.six@gdsys.cc 	/* Data received, ACK not transmitted */
144dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_DATA_R_NAK	= 0x58,
145dfc3958cSmario.six@gdsys.cc 	/* No relevant status */
146dfc3958cSmario.six@gdsys.cc 	MVTWSI_STATUS_IDLE		= 0xF8,
147dfc3958cSmario.six@gdsys.cc };
148306563a7SAlbert Aribaud 
149306563a7SAlbert Aribaud /*
150670514f5Smario.six@gdsys.cc  * enum mvstwsi_ack_flags - Determine whether a read byte should be
151670514f5Smario.six@gdsys.cc  * acknowledged or not.
152670514f5Smario.six@gdsys.cc  */
153670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
154670514f5Smario.six@gdsys.cc 	/* Send NAK after received byte */
155670514f5Smario.six@gdsys.cc 	MVTWSI_READ_NAK = 0,
156670514f5Smario.six@gdsys.cc 	/* Send ACK after received byte */
157670514f5Smario.six@gdsys.cc 	MVTWSI_READ_ACK = 1,
158670514f5Smario.six@gdsys.cc };
159670514f5Smario.six@gdsys.cc 
1606e677cafSmario.six@gdsys.cc /*
1616e677cafSmario.six@gdsys.cc  * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
1626e677cafSmario.six@gdsys.cc  *
1636e677cafSmario.six@gdsys.cc  * @speed:	The speed in Hz to calculate the clock cycle duration for.
1646e677cafSmario.six@gdsys.cc  * @return The duration of a clock cycle in ns.
1656e677cafSmario.six@gdsys.cc  */
166c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed)
167c68c6243Smario.six@gdsys.cc {
168c68c6243Smario.six@gdsys.cc 	/* One tick = the duration of a period at the specified speed in ns (we
169c68c6243Smario.six@gdsys.cc 	 * add 100 ns to be on the safe side) */
170c68c6243Smario.six@gdsys.cc 	return (1000000000u / speed) + 100;
171c68c6243Smario.six@gdsys.cc }
172c68c6243Smario.six@gdsys.cc 
17314a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
174c68c6243Smario.six@gdsys.cc 
175670514f5Smario.six@gdsys.cc /*
1766e677cafSmario.six@gdsys.cc  * twsi_get_base() - Get controller register base for specified adapter
1776e677cafSmario.six@gdsys.cc  *
1786e677cafSmario.six@gdsys.cc  * @adap:	Adapter to get the register base for.
1796e677cafSmario.six@gdsys.cc  * @return Register base for the specified adapter.
180306563a7SAlbert Aribaud  */
181dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
182dd82242bSPaul Kocialkowski {
183dd82242bSPaul Kocialkowski 	switch (adap->hwadapnr) {
184dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
185dd82242bSPaul Kocialkowski 	case 0:
186dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
187dd82242bSPaul Kocialkowski #endif
188dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
189dd82242bSPaul Kocialkowski 	case 1:
190dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
191dd82242bSPaul Kocialkowski #endif
192dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
193dd82242bSPaul Kocialkowski 	case 2:
194dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
195dd82242bSPaul Kocialkowski #endif
196dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
197dd82242bSPaul Kocialkowski 	case 3:
198dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
199dd82242bSPaul Kocialkowski #endif
200dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
201dd82242bSPaul Kocialkowski 	case 4:
202dd82242bSPaul Kocialkowski 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
203dd82242bSPaul Kocialkowski #endif
2049d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
2059d082687SJelle van der Waa 	case 5:
2069d082687SJelle van der Waa 		return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
2079d082687SJelle van der Waa #endif
208dd82242bSPaul Kocialkowski 	default:
209dd82242bSPaul Kocialkowski 		printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
210dd82242bSPaul Kocialkowski 		break;
211dd82242bSPaul Kocialkowski 	}
212dd82242bSPaul Kocialkowski 
213dd82242bSPaul Kocialkowski 	return NULL;
214dd82242bSPaul Kocialkowski }
21514a6ff2cSmario.six@gdsys.cc #endif
216306563a7SAlbert Aribaud 
217306563a7SAlbert Aribaud /*
218dfc3958cSmario.six@gdsys.cc  * enum mvtwsi_error_class - types of I2C errors
219306563a7SAlbert Aribaud  */
220dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
221dfc3958cSmario.six@gdsys.cc 	/* The controller returned a different status than expected */
222dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_WRONG_STATUS       = 0x01,
223dfc3958cSmario.six@gdsys.cc 	/* The controller timed out */
224dfc3958cSmario.six@gdsys.cc 	MVTWSI_ERROR_TIMEOUT            = 0x02,
225dfc3958cSmario.six@gdsys.cc };
226306563a7SAlbert Aribaud 
227dfc3958cSmario.six@gdsys.cc /*
228dfc3958cSmario.six@gdsys.cc  * mvtwsi_error() - Build I2C return code from error information
229dfc3958cSmario.six@gdsys.cc  *
230dfc3958cSmario.six@gdsys.cc  * For debugging purposes, this function packs some information of an occurred
231dfc3958cSmario.six@gdsys.cc  * error into a return code. These error codes are returned from I2C API
232dfc3958cSmario.six@gdsys.cc  * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
233dfc3958cSmario.six@gdsys.cc  *
234dfc3958cSmario.six@gdsys.cc  * @ec:		The error class of the error (enum mvtwsi_error_class).
235dfc3958cSmario.six@gdsys.cc  * @lc:		The last value of the control register.
236dfc3958cSmario.six@gdsys.cc  * @ls:		The last value of the status register.
237dfc3958cSmario.six@gdsys.cc  * @es:		The expected value of the status register.
238dfc3958cSmario.six@gdsys.cc  * @return The generated error code.
239dfc3958cSmario.six@gdsys.cc  */
240dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
241dfc3958cSmario.six@gdsys.cc {
242dfc3958cSmario.six@gdsys.cc 	return ((ec << 24) & 0xFF000000)
243dfc3958cSmario.six@gdsys.cc 	       | ((lc << 16) & 0x00FF0000)
244dfc3958cSmario.six@gdsys.cc 	       | ((ls << 8) & 0x0000FF00)
245dfc3958cSmario.six@gdsys.cc 	       | (es & 0xFF);
246dfc3958cSmario.six@gdsys.cc }
247306563a7SAlbert Aribaud 
248306563a7SAlbert Aribaud /*
2496e677cafSmario.six@gdsys.cc  * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
2506e677cafSmario.six@gdsys.cc  *
2516e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
2526e677cafSmario.six@gdsys.cc  *	   out occurred, or the status was not the expected one.
253306563a7SAlbert Aribaud  */
254c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
255c68c6243Smario.six@gdsys.cc 		     uint tick)
25601ec99d9SAlbert Aribaud {
257306563a7SAlbert Aribaud 	int control, status;
258306563a7SAlbert Aribaud 	int timeout = 1000;
259306563a7SAlbert Aribaud 
260306563a7SAlbert Aribaud 	do {
261306563a7SAlbert Aribaud 		control = readl(&twsi->control);
262306563a7SAlbert Aribaud 		if (control & MVTWSI_CONTROL_IFLG) {
263306563a7SAlbert Aribaud 			status = readl(&twsi->status);
264306563a7SAlbert Aribaud 			if (status == expected_status)
265306563a7SAlbert Aribaud 				return 0;
26601ec99d9SAlbert Aribaud 			else
267dfc3958cSmario.six@gdsys.cc 				return mvtwsi_error(
268306563a7SAlbert Aribaud 					MVTWSI_ERROR_WRONG_STATUS,
269306563a7SAlbert Aribaud 					control, status, expected_status);
270306563a7SAlbert Aribaud 		}
271c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
272306563a7SAlbert Aribaud 	} while (timeout--);
273306563a7SAlbert Aribaud 	status = readl(&twsi->status);
274dfc3958cSmario.six@gdsys.cc 	return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
275dfc3958cSmario.six@gdsys.cc 			    expected_status);
27601ec99d9SAlbert Aribaud }
27701ec99d9SAlbert Aribaud 
278306563a7SAlbert Aribaud /*
2796e677cafSmario.six@gdsys.cc  * twsi_start() - Assert a START condition on the bus.
2806e677cafSmario.six@gdsys.cc  *
2816e677cafSmario.six@gdsys.cc  * This function is used in both single I2C transactions and inside
2826e677cafSmario.six@gdsys.cc  * back-to-back transactions (repeated starts).
2836e677cafSmario.six@gdsys.cc  *
2846e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
2856e677cafSmario.six@gdsys.cc  * @expected_status:	The I2C bus status expected to be asserted after the
2866e677cafSmario.six@gdsys.cc  *			operation completion.
2876e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
2886e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
2896e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
290306563a7SAlbert Aribaud  */
291c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
292c68c6243Smario.six@gdsys.cc 		      uint tick)
293306563a7SAlbert Aribaud {
29449c801bfSmario.six@gdsys.cc 	/* Assert START */
295670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
2962ca02995SHans de Goede 	       MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
29749c801bfSmario.six@gdsys.cc 	/* Wait for controller to process START */
298c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
299306563a7SAlbert Aribaud }
300306563a7SAlbert Aribaud 
301306563a7SAlbert Aribaud /*
3026e677cafSmario.six@gdsys.cc  * twsi_send() - Send a byte on the I2C bus.
3036e677cafSmario.six@gdsys.cc  *
3046e677cafSmario.six@gdsys.cc  * The byte may be part of an address byte or data.
3056e677cafSmario.six@gdsys.cc  *
3066e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
3076e677cafSmario.six@gdsys.cc  * @byte:		The byte to send.
3086e677cafSmario.six@gdsys.cc  * @expected_status:	The I2C bus status expected to be asserted after the
3096e677cafSmario.six@gdsys.cc  *			operation completion.
3106e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
3116e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
3126e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
313306563a7SAlbert Aribaud  */
3143c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
315c68c6243Smario.six@gdsys.cc 		     int expected_status, uint tick)
316306563a7SAlbert Aribaud {
31749c801bfSmario.six@gdsys.cc 	/* Write byte to data register for sending */
318306563a7SAlbert Aribaud 	writel(byte, &twsi->data);
31949c801bfSmario.six@gdsys.cc 	/* Clear any pending interrupt -- that will cause sending */
320670514f5Smario.six@gdsys.cc 	writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
321670514f5Smario.six@gdsys.cc 	       &twsi->control);
32249c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and check ACK */
323c68c6243Smario.six@gdsys.cc 	return twsi_wait(twsi, expected_status, tick);
324306563a7SAlbert Aribaud }
325306563a7SAlbert Aribaud 
326306563a7SAlbert Aribaud /*
3276e677cafSmario.six@gdsys.cc  * twsi_recv() - Receive a byte on the I2C bus.
3286e677cafSmario.six@gdsys.cc  *
3296e677cafSmario.six@gdsys.cc  * The static variable mvtwsi_control_flags controls whether we ack or nak.
3306e677cafSmario.six@gdsys.cc  *
3316e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
3326e677cafSmario.six@gdsys.cc  * @byte:		The byte to send.
3336e677cafSmario.six@gdsys.cc  * @ack_flag:		Flag that determines whether the received byte should
3346e677cafSmario.six@gdsys.cc  *			be acknowledged by the controller or not (sent ACK/NAK).
3356e677cafSmario.six@gdsys.cc  * @tick:		The duration of a clock cycle at the current I2C speed.
3366e677cafSmario.six@gdsys.cc  * @return Zero if status is as expected, or a non-zero code if either a time
3376e677cafSmario.six@gdsys.cc  *	   out occurred or the status was not the expected one.
338306563a7SAlbert Aribaud  */
339c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
340c68c6243Smario.six@gdsys.cc 		     uint tick)
341306563a7SAlbert Aribaud {
342670514f5Smario.six@gdsys.cc 	int expected_status, status, control;
343306563a7SAlbert Aribaud 
344670514f5Smario.six@gdsys.cc 	/* Compute expected status based on passed ACK flag */
345670514f5Smario.six@gdsys.cc 	expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
346670514f5Smario.six@gdsys.cc 			  MVTWSI_STATUS_DATA_R_NAK;
34749c801bfSmario.six@gdsys.cc 	/* Acknowledge *previous state*, and launch receive */
348670514f5Smario.six@gdsys.cc 	control = MVTWSI_CONTROL_TWSIEN;
349670514f5Smario.six@gdsys.cc 	control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
350670514f5Smario.six@gdsys.cc 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
35149c801bfSmario.six@gdsys.cc 	/* Wait for controller to receive byte, and assert ACK or NAK */
352c68c6243Smario.six@gdsys.cc 	status = twsi_wait(twsi, expected_status, tick);
35349c801bfSmario.six@gdsys.cc 	/* If we did receive the expected byte, store it */
354306563a7SAlbert Aribaud 	if (status == 0)
355306563a7SAlbert Aribaud 		*byte = readl(&twsi->data);
356306563a7SAlbert Aribaud 	return status;
357306563a7SAlbert Aribaud }
358306563a7SAlbert Aribaud 
359306563a7SAlbert Aribaud /*
3606e677cafSmario.six@gdsys.cc  * twsi_stop() - Assert a STOP condition on the bus.
3616e677cafSmario.six@gdsys.cc  *
3626e677cafSmario.six@gdsys.cc  * This function is also used to force the bus back to idle state (SDA =
3636e677cafSmario.six@gdsys.cc  * SCL = 1).
3646e677cafSmario.six@gdsys.cc  *
3656e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
3666e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
3676e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out
3686e677cafSmario.six@gdsys.cc  *	   occurred.
369306563a7SAlbert Aribaud  */
370c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
371306563a7SAlbert Aribaud {
372306563a7SAlbert Aribaud 	int control, stop_status;
373059fce9fSmario.six@gdsys.cc 	int status = 0;
374306563a7SAlbert Aribaud 	int timeout = 1000;
375306563a7SAlbert Aribaud 
37649c801bfSmario.six@gdsys.cc 	/* Assert STOP */
377306563a7SAlbert Aribaud 	control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
378904dfbfdSHans de Goede 	writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
37949c801bfSmario.six@gdsys.cc 	/* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
380306563a7SAlbert Aribaud 	do {
381306563a7SAlbert Aribaud 		stop_status = readl(&twsi->status);
382306563a7SAlbert Aribaud 		if (stop_status == MVTWSI_STATUS_IDLE)
383306563a7SAlbert Aribaud 			break;
384c68c6243Smario.six@gdsys.cc 		ndelay(tick); /* One clock cycle */
385306563a7SAlbert Aribaud 	} while (timeout--);
386306563a7SAlbert Aribaud 	control = readl(&twsi->control);
387306563a7SAlbert Aribaud 	if (stop_status != MVTWSI_STATUS_IDLE)
388059fce9fSmario.six@gdsys.cc 		status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
389306563a7SAlbert Aribaud 				      control, status, MVTWSI_STATUS_IDLE);
390306563a7SAlbert Aribaud 	return status;
391306563a7SAlbert Aribaud }
392306563a7SAlbert Aribaud 
3936e677cafSmario.six@gdsys.cc /*
3946e677cafSmario.six@gdsys.cc  * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
3956e677cafSmario.six@gdsys.cc  *
3966e677cafSmario.six@gdsys.cc  * @n:		Parameter 'n' for the frequency calculation algorithm.
3976e677cafSmario.six@gdsys.cc  * @m:		Parameter 'm' for the frequency calculation algorithm.
3986e677cafSmario.six@gdsys.cc  * @return The I2C frequency corresponding to the passed m and n parameters.
3996e677cafSmario.six@gdsys.cc  */
400e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
401f582a158SStefan Roese {
402f582a158SStefan Roese #ifdef CONFIG_SUNXI
403f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
404f582a158SStefan Roese #else
405f582a158SStefan Roese 	return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
406f582a158SStefan Roese #endif
407f582a158SStefan Roese }
408306563a7SAlbert Aribaud 
409306563a7SAlbert Aribaud /*
4106e677cafSmario.six@gdsys.cc  * twsi_reset() - Reset the I2C controller.
4116e677cafSmario.six@gdsys.cc  *
4126e677cafSmario.six@gdsys.cc  * Resetting the controller also resets the baud rate and slave address, hence
4136e677cafSmario.six@gdsys.cc  * they must be re-established after the reset.
4146e677cafSmario.six@gdsys.cc  *
4156e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
416306563a7SAlbert Aribaud  */
4173c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
418306563a7SAlbert Aribaud {
41949c801bfSmario.six@gdsys.cc 	/* Reset controller */
420306563a7SAlbert Aribaud 	writel(0, &twsi->soft_reset);
42149c801bfSmario.six@gdsys.cc 	/* Wait 2 ms -- this is what the Marvell LSP does */
422306563a7SAlbert Aribaud 	udelay(20000);
423306563a7SAlbert Aribaud }
424306563a7SAlbert Aribaud 
425306563a7SAlbert Aribaud /*
4266e677cafSmario.six@gdsys.cc  * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
4276e677cafSmario.six@gdsys.cc  *
4286e677cafSmario.six@gdsys.cc  * This function sets baud rate to the highest possible value that does not
4296e677cafSmario.six@gdsys.cc  * exceed the requested rate.
4306e677cafSmario.six@gdsys.cc  *
4316e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
4326e677cafSmario.six@gdsys.cc  * @requested_speed:	The desired frequency the controller should run at
4336e677cafSmario.six@gdsys.cc  *			in Hz.
4346e677cafSmario.six@gdsys.cc  * @return The actual frequency the controller was configured to.
435306563a7SAlbert Aribaud  */
4363c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
437e0758281Smario.six@gdsys.cc 				     uint requested_speed)
438306563a7SAlbert Aribaud {
439e0758281Smario.six@gdsys.cc 	uint tmp_speed, highest_speed, n, m;
440e0758281Smario.six@gdsys.cc 	uint baud = 0x44; /* Baud rate after controller reset */
441306563a7SAlbert Aribaud 
442306563a7SAlbert Aribaud 	highest_speed = 0;
44349c801bfSmario.six@gdsys.cc 	/* Successively try m, n combinations, and use the combination
44449c801bfSmario.six@gdsys.cc 	 * resulting in the largest speed that's not above the requested
44549c801bfSmario.six@gdsys.cc 	 * speed */
44601ec99d9SAlbert Aribaud 	for (n = 0; n < 8; n++) {
44701ec99d9SAlbert Aribaud 		for (m = 0; m < 16; m++) {
448f582a158SStefan Roese 			tmp_speed = twsi_calc_freq(n, m);
4499ec43b0cSmario.six@gdsys.cc 			if ((tmp_speed <= requested_speed) &&
4509ec43b0cSmario.six@gdsys.cc 			    (tmp_speed > highest_speed)) {
451306563a7SAlbert Aribaud 				highest_speed = tmp_speed;
452306563a7SAlbert Aribaud 				baud = (m << 3) | n;
45301ec99d9SAlbert Aribaud 			}
45401ec99d9SAlbert Aribaud 		}
45501ec99d9SAlbert Aribaud 	}
4560db2bbdcSHans de Goede 	writel(baud, &twsi->baudrate);
457c68c6243Smario.six@gdsys.cc 
458c68c6243Smario.six@gdsys.cc 	/* Wait for controller for one tick */
459c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
460c68c6243Smario.six@gdsys.cc 	ndelay(calc_tick(highest_speed));
461c68c6243Smario.six@gdsys.cc #else
462c68c6243Smario.six@gdsys.cc 	ndelay(10000);
463c68c6243Smario.six@gdsys.cc #endif
464c68c6243Smario.six@gdsys.cc 	return highest_speed;
4650db2bbdcSHans de Goede }
4660db2bbdcSHans de Goede 
4676e677cafSmario.six@gdsys.cc /*
4686e677cafSmario.six@gdsys.cc  * __twsi_i2c_init() - Initialize the I2C controller.
4696e677cafSmario.six@gdsys.cc  *
4706e677cafSmario.six@gdsys.cc  * @twsi:		The MVTWSI register structure to use.
4716e677cafSmario.six@gdsys.cc  * @speed:		The initial frequency the controller should run at
4726e677cafSmario.six@gdsys.cc  *			in Hz.
4736e677cafSmario.six@gdsys.cc  * @slaveadd:		The I2C address to be set for the I2C master.
4746e677cafSmario.six@gdsys.cc  * @actual_speed:	A output parameter that receives the actual frequency
4756e677cafSmario.six@gdsys.cc  *			in Hz the controller was set to by the function.
4766e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out
4776e677cafSmario.six@gdsys.cc  *	   occurred.
4786e677cafSmario.six@gdsys.cc  */
4793c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
480c68c6243Smario.six@gdsys.cc 			    int slaveadd, uint *actual_speed)
4810db2bbdcSHans de Goede {
48249c801bfSmario.six@gdsys.cc 	/* Reset controller */
4833c4db636Smario.six@gdsys.cc 	twsi_reset(twsi);
48449c801bfSmario.six@gdsys.cc 	/* Set speed */
485c68c6243Smario.six@gdsys.cc 	*actual_speed = __twsi_i2c_set_bus_speed(twsi, speed);
48649c801bfSmario.six@gdsys.cc 	/* Set slave address; even though we don't use it */
4870db2bbdcSHans de Goede 	writel(slaveadd, &twsi->slave_address);
4880db2bbdcSHans de Goede 	writel(0, &twsi->xtnd_slave_addr);
48949c801bfSmario.six@gdsys.cc 	/* Assert STOP, but don't care for the result */
490c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
491c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, calc_tick(*actual_speed));
492c68c6243Smario.six@gdsys.cc #else
493c68c6243Smario.six@gdsys.cc 	(void) twsi_stop(twsi, 10000);
494c68c6243Smario.six@gdsys.cc #endif
49501ec99d9SAlbert Aribaud }
49601ec99d9SAlbert Aribaud 
49701ec99d9SAlbert Aribaud /*
4986e677cafSmario.six@gdsys.cc  * i2c_begin() - Start a I2C transaction.
4996e677cafSmario.six@gdsys.cc  *
5006e677cafSmario.six@gdsys.cc  * Begin a I2C transaction with a given expected start status and chip address.
5016e677cafSmario.six@gdsys.cc  * A START is asserted, and the address byte is sent to the I2C controller. The
5026e677cafSmario.six@gdsys.cc  * expected address status will be derived from the direction bit (bit 0) of
5036e677cafSmario.six@gdsys.cc  * the address byte.
5046e677cafSmario.six@gdsys.cc  *
5056e677cafSmario.six@gdsys.cc  * @twsi:			The MVTWSI register structure to use.
5066e677cafSmario.six@gdsys.cc  * @expected_start_status:	The I2C status the controller is expected to
5076e677cafSmario.six@gdsys.cc  *				assert after the address byte was sent.
5086e677cafSmario.six@gdsys.cc  * @addr:			The address byte to be sent.
5096e677cafSmario.six@gdsys.cc  * @tick:			The duration of a clock cycle at the current
5106e677cafSmario.six@gdsys.cc  *				I2C speed.
5116e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5126e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
51301ec99d9SAlbert Aribaud  */
5143c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
515c68c6243Smario.six@gdsys.cc 		     u8 addr, uint tick)
51601ec99d9SAlbert Aribaud {
517306563a7SAlbert Aribaud 	int status, expected_addr_status;
51801ec99d9SAlbert Aribaud 
51949c801bfSmario.six@gdsys.cc 	/* Compute the expected address status from the direction bit in
52049c801bfSmario.six@gdsys.cc 	 * the address byte */
52149c801bfSmario.six@gdsys.cc 	if (addr & 1) /* Reading */
522306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
52349c801bfSmario.six@gdsys.cc 	else /* Writing */
524306563a7SAlbert Aribaud 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
52549c801bfSmario.six@gdsys.cc 	/* Assert START */
526c68c6243Smario.six@gdsys.cc 	status = twsi_start(twsi, expected_start_status, tick);
52749c801bfSmario.six@gdsys.cc 	/* Send out the address if the start went well */
528306563a7SAlbert Aribaud 	if (status == 0)
529c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, addr, expected_addr_status, tick);
53049c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
531306563a7SAlbert Aribaud 	return status;
53201ec99d9SAlbert Aribaud }
53301ec99d9SAlbert Aribaud 
534306563a7SAlbert Aribaud /*
5356e677cafSmario.six@gdsys.cc  * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
5366e677cafSmario.six@gdsys.cc  *
5376e677cafSmario.six@gdsys.cc  * This function begins a I2C read transaction, does a dummy read and NAKs; if
5386e677cafSmario.six@gdsys.cc  * the procedure succeeds, the chip is considered to be present.
5396e677cafSmario.six@gdsys.cc  *
5406e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
5416e677cafSmario.six@gdsys.cc  * @chip:	The chip address to probe.
5426e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
5436e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5446e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
545306563a7SAlbert Aribaud  */
546c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
547c68c6243Smario.six@gdsys.cc 				 uint tick)
54801ec99d9SAlbert Aribaud {
549306563a7SAlbert Aribaud 	u8 dummy_byte;
550306563a7SAlbert Aribaud 	int status;
55101ec99d9SAlbert Aribaud 
55249c801bfSmario.six@gdsys.cc 	/* Begin i2c read */
553c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
55449c801bfSmario.six@gdsys.cc 	/* Dummy read was accepted: receive byte, but NAK it. */
555306563a7SAlbert Aribaud 	if (status == 0)
556c68c6243Smario.six@gdsys.cc 		status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
557306563a7SAlbert Aribaud 	/* Stop transaction */
558c68c6243Smario.six@gdsys.cc 	twsi_stop(twsi, tick);
55949c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
560306563a7SAlbert Aribaud 	return status;
56101ec99d9SAlbert Aribaud }
56201ec99d9SAlbert Aribaud 
563306563a7SAlbert Aribaud /*
5646e677cafSmario.six@gdsys.cc  * __twsi_i2c_read() - Read data from a I2C chip.
5656e677cafSmario.six@gdsys.cc  *
5666e677cafSmario.six@gdsys.cc  * This function begins a I2C write transaction, and transmits the address
5676e677cafSmario.six@gdsys.cc  * bytes; then begins a I2C read transaction, and receives the data bytes.
568306563a7SAlbert Aribaud  *
56949c801bfSmario.six@gdsys.cc  * NOTE: Some devices want a stop right before the second start, while some
57049c801bfSmario.six@gdsys.cc  * will choke if it is there. Since deciding this is not yet supported in
57149c801bfSmario.six@gdsys.cc  * higher level APIs, we need to make a decision here, and for the moment that
57249c801bfSmario.six@gdsys.cc  * will be a repeated start without a preceding stop.
5736e677cafSmario.six@gdsys.cc  *
5746e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
5756e677cafSmario.six@gdsys.cc  * @chip:	The chip address to read from.
5766e677cafSmario.six@gdsys.cc  * @addr:	The address bytes to send.
5776e677cafSmario.six@gdsys.cc  * @alen:	The length of the address bytes in bytes.
5786e677cafSmario.six@gdsys.cc  * @data:	The buffer to receive the data read from the chip (has to have
5796e677cafSmario.six@gdsys.cc  *		a size of at least 'length' bytes).
5806e677cafSmario.six@gdsys.cc  * @length:	The amount of data to be read from the chip in bytes.
5816e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
5826e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
5836e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
584306563a7SAlbert Aribaud  */
5853c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
586c68c6243Smario.six@gdsys.cc 			   u8 *addr, int alen, uchar *data, int length,
587c68c6243Smario.six@gdsys.cc 			   uint tick)
58801ec99d9SAlbert Aribaud {
589059fce9fSmario.six@gdsys.cc 	int status = 0;
590059fce9fSmario.six@gdsys.cc 	int stop_status;
59124f9c6bbSmario.six@gdsys.cc 	int expected_start = MVTWSI_STATUS_START;
59201ec99d9SAlbert Aribaud 
59324f9c6bbSmario.six@gdsys.cc 	if (alen > 0) {
59449c801bfSmario.six@gdsys.cc 		/* Begin i2c write to send the address bytes */
595c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1), tick);
59649c801bfSmario.six@gdsys.cc 		/* Send address bytes */
597306563a7SAlbert Aribaud 		while ((status == 0) && alen--)
598*03d6cd97SStefan Roese 			status = twsi_send(twsi, addr[alen],
599c68c6243Smario.six@gdsys.cc 					   MVTWSI_STATUS_DATA_W_ACK, tick);
60024f9c6bbSmario.six@gdsys.cc 		/* Send repeated STARTs after the initial START */
60124f9c6bbSmario.six@gdsys.cc 		expected_start = MVTWSI_STATUS_REPEATED_START;
60224f9c6bbSmario.six@gdsys.cc 	}
60349c801bfSmario.six@gdsys.cc 	/* Begin i2c read to receive data bytes */
604306563a7SAlbert Aribaud 	if (status == 0)
605c68c6243Smario.six@gdsys.cc 		status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
606670514f5Smario.six@gdsys.cc 	/* Receive actual data bytes; set NAK if we if we have nothing more to
607670514f5Smario.six@gdsys.cc 	 * read */
608670514f5Smario.six@gdsys.cc 	while ((status == 0) && length--)
6093c4db636Smario.six@gdsys.cc 		status = twsi_recv(twsi, data++,
610670514f5Smario.six@gdsys.cc 				   length > 0 ?
611c68c6243Smario.six@gdsys.cc 				   MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
612306563a7SAlbert Aribaud 	/* Stop transaction */
613c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
61449c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
615059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
61601ec99d9SAlbert Aribaud }
61701ec99d9SAlbert Aribaud 
618306563a7SAlbert Aribaud /*
6196e677cafSmario.six@gdsys.cc  * __twsi_i2c_write() - Send data to a I2C chip.
6206e677cafSmario.six@gdsys.cc  *
6216e677cafSmario.six@gdsys.cc  * This function begins a I2C write transaction, and transmits the address
6226e677cafSmario.six@gdsys.cc  * bytes; then begins a new I2C write transaction, and sends the data bytes.
6236e677cafSmario.six@gdsys.cc  *
6246e677cafSmario.six@gdsys.cc  * @twsi:	The MVTWSI register structure to use.
6256e677cafSmario.six@gdsys.cc  * @chip:	The chip address to read from.
6266e677cafSmario.six@gdsys.cc  * @addr:	The address bytes to send.
6276e677cafSmario.six@gdsys.cc  * @alen:	The length of the address bytes in bytes.
6286e677cafSmario.six@gdsys.cc  * @data:	The buffer containing the data to be sent to the chip.
6296e677cafSmario.six@gdsys.cc  * @length:	The length of data to be sent to the chip in bytes.
6306e677cafSmario.six@gdsys.cc  * @tick:	The duration of a clock cycle at the current I2C speed.
6316e677cafSmario.six@gdsys.cc  * @return Zero if the operation succeeded, or a non-zero code if a time out or
6326e677cafSmario.six@gdsys.cc  *	   unexpected I2C status occurred.
633306563a7SAlbert Aribaud  */
6343c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
635c68c6243Smario.six@gdsys.cc 			    u8 *addr, int alen, uchar *data, int length,
636c68c6243Smario.six@gdsys.cc 			    uint tick)
63701ec99d9SAlbert Aribaud {
638059fce9fSmario.six@gdsys.cc 	int status, stop_status;
63901ec99d9SAlbert Aribaud 
64049c801bfSmario.six@gdsys.cc 	/* Begin i2c write to send first the address bytes, then the
64149c801bfSmario.six@gdsys.cc 	 * data bytes */
642c68c6243Smario.six@gdsys.cc 	status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
64349c801bfSmario.six@gdsys.cc 	/* Send address bytes */
644f8a10ed1Smario.six@gdsys.cc 	while ((status == 0) && (alen-- > 0))
645*03d6cd97SStefan Roese 		status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
646c68c6243Smario.six@gdsys.cc 				   tick);
64749c801bfSmario.six@gdsys.cc 	/* Send data bytes */
648306563a7SAlbert Aribaud 	while ((status == 0) && (length-- > 0))
649c68c6243Smario.six@gdsys.cc 		status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
650c68c6243Smario.six@gdsys.cc 				   tick);
651306563a7SAlbert Aribaud 	/* Stop transaction */
652c68c6243Smario.six@gdsys.cc 	stop_status = twsi_stop(twsi, tick);
65349c801bfSmario.six@gdsys.cc 	/* Return 0, or the status of the first failure */
654059fce9fSmario.six@gdsys.cc 	return status != 0 ? status : stop_status;
65501ec99d9SAlbert Aribaud }
65601ec99d9SAlbert Aribaud 
65714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
65861bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
65961bc02b2Smario.six@gdsys.cc 			  int slaveadd)
66061bc02b2Smario.six@gdsys.cc {
6613c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
662c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(twsi, speed, slaveadd, NULL);
66361bc02b2Smario.six@gdsys.cc }
66461bc02b2Smario.six@gdsys.cc 
66561bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
66661bc02b2Smario.six@gdsys.cc 				   uint requested_speed)
66761bc02b2Smario.six@gdsys.cc {
6683c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
669c68c6243Smario.six@gdsys.cc 	__twsi_i2c_set_bus_speed(twsi, requested_speed);
670c68c6243Smario.six@gdsys.cc 	return 0;
67161bc02b2Smario.six@gdsys.cc }
67261bc02b2Smario.six@gdsys.cc 
67361bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
67461bc02b2Smario.six@gdsys.cc {
6753c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
676c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(twsi, chip, 10000);
67761bc02b2Smario.six@gdsys.cc }
67861bc02b2Smario.six@gdsys.cc 
67961bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
68061bc02b2Smario.six@gdsys.cc 			 int alen, uchar *data, int length)
68161bc02b2Smario.six@gdsys.cc {
6823c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
683f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
684f8a10ed1Smario.six@gdsys.cc 
685f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
686f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
687f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
688f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
689f8a10ed1Smario.six@gdsys.cc 
690c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
691c68c6243Smario.six@gdsys.cc 			       10000);
69261bc02b2Smario.six@gdsys.cc }
69361bc02b2Smario.six@gdsys.cc 
69461bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
69561bc02b2Smario.six@gdsys.cc 			  int alen, uchar *data, int length)
69661bc02b2Smario.six@gdsys.cc {
6973c4db636Smario.six@gdsys.cc 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
698f8a10ed1Smario.six@gdsys.cc 	u8 addr_bytes[4];
699f8a10ed1Smario.six@gdsys.cc 
700f8a10ed1Smario.six@gdsys.cc 	addr_bytes[0] = (addr >> 0) & 0xFF;
701f8a10ed1Smario.six@gdsys.cc 	addr_bytes[1] = (addr >> 8) & 0xFF;
702f8a10ed1Smario.six@gdsys.cc 	addr_bytes[2] = (addr >> 16) & 0xFF;
703f8a10ed1Smario.six@gdsys.cc 	addr_bytes[3] = (addr >> 24) & 0xFF;
704f8a10ed1Smario.six@gdsys.cc 
705c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
706c68c6243Smario.six@gdsys.cc 				10000);
70761bc02b2Smario.six@gdsys.cc }
70861bc02b2Smario.six@gdsys.cc 
709dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
7100db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
7110db2bbdcSHans de Goede 			 twsi_i2c_read, twsi_i2c_write,
7120db2bbdcSHans de Goede 			 twsi_i2c_set_bus_speed,
7130db2bbdcSHans de Goede 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
714dd82242bSPaul Kocialkowski #endif
715dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
716dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
717dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
718dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
719dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
720dd82242bSPaul Kocialkowski 
721dd82242bSPaul Kocialkowski #endif
722dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
723dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
724dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
725dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
726dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
727dd82242bSPaul Kocialkowski 
728dd82242bSPaul Kocialkowski #endif
729dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
730dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
731dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
732dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
733dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
734dd82242bSPaul Kocialkowski 
735dd82242bSPaul Kocialkowski #endif
736dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
737dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
738dd82242bSPaul Kocialkowski 			 twsi_i2c_read, twsi_i2c_write,
739dd82242bSPaul Kocialkowski 			 twsi_i2c_set_bus_speed,
740dd82242bSPaul Kocialkowski 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
741dd82242bSPaul Kocialkowski 
742dd82242bSPaul Kocialkowski #endif
7439d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
7449d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
7459d082687SJelle van der Waa 			 twsi_i2c_read, twsi_i2c_write,
7469d082687SJelle van der Waa 			 twsi_i2c_set_bus_speed,
7479d082687SJelle van der Waa 			 CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
7489d082687SJelle van der Waa 
7499d082687SJelle van der Waa #endif
75014a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
75114a6ff2cSmario.six@gdsys.cc 
75214a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
75314a6ff2cSmario.six@gdsys.cc 				 u32 chip_flags)
75414a6ff2cSmario.six@gdsys.cc {
75514a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
756c68c6243Smario.six@gdsys.cc 	return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
75714a6ff2cSmario.six@gdsys.cc }
75814a6ff2cSmario.six@gdsys.cc 
75914a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
76014a6ff2cSmario.six@gdsys.cc {
76114a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
762c68c6243Smario.six@gdsys.cc 
763c68c6243Smario.six@gdsys.cc 	dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
764c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
765c68c6243Smario.six@gdsys.cc 
766c68c6243Smario.six@gdsys.cc 	return 0;
76714a6ff2cSmario.six@gdsys.cc }
76814a6ff2cSmario.six@gdsys.cc 
76914a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
77014a6ff2cSmario.six@gdsys.cc {
77114a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
77214a6ff2cSmario.six@gdsys.cc 
77314a6ff2cSmario.six@gdsys.cc 	dev->base = dev_get_addr_ptr(bus);
77414a6ff2cSmario.six@gdsys.cc 
77514a6ff2cSmario.six@gdsys.cc 	if (!dev->base)
77614a6ff2cSmario.six@gdsys.cc 		return -ENOMEM;
77714a6ff2cSmario.six@gdsys.cc 
77814a6ff2cSmario.six@gdsys.cc 	dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
77914a6ff2cSmario.six@gdsys.cc 				    "cell-index", -1);
78014a6ff2cSmario.six@gdsys.cc 	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
78114a6ff2cSmario.six@gdsys.cc 				       "u-boot,i2c-slave-addr", 0x0);
78214a6ff2cSmario.six@gdsys.cc 	dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
78314a6ff2cSmario.six@gdsys.cc 				    "clock-frequency", 100000);
78414a6ff2cSmario.six@gdsys.cc 	return 0;
78514a6ff2cSmario.six@gdsys.cc }
78614a6ff2cSmario.six@gdsys.cc 
78714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
78814a6ff2cSmario.six@gdsys.cc {
78914a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
790c68c6243Smario.six@gdsys.cc 	uint actual_speed;
791c68c6243Smario.six@gdsys.cc 
792c68c6243Smario.six@gdsys.cc 	__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
793c68c6243Smario.six@gdsys.cc 	dev->speed = actual_speed;
794c68c6243Smario.six@gdsys.cc 	dev->tick = calc_tick(dev->speed);
79514a6ff2cSmario.six@gdsys.cc 	return 0;
79614a6ff2cSmario.six@gdsys.cc }
79714a6ff2cSmario.six@gdsys.cc 
79814a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
79914a6ff2cSmario.six@gdsys.cc {
80014a6ff2cSmario.six@gdsys.cc 	struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
80114a6ff2cSmario.six@gdsys.cc 	struct i2c_msg *dmsg, *omsg, dummy;
80214a6ff2cSmario.six@gdsys.cc 
80314a6ff2cSmario.six@gdsys.cc 	memset(&dummy, 0, sizeof(struct i2c_msg));
80414a6ff2cSmario.six@gdsys.cc 
80514a6ff2cSmario.six@gdsys.cc 	/* We expect either two messages (one with an offset and one with the
80614a6ff2cSmario.six@gdsys.cc 	 * actual data) or one message (just data or offset/data combined) */
80714a6ff2cSmario.six@gdsys.cc 	if (nmsgs > 2 || nmsgs == 0) {
80814a6ff2cSmario.six@gdsys.cc 		debug("%s: Only one or two messages are supported.", __func__);
80914a6ff2cSmario.six@gdsys.cc 		return -1;
81014a6ff2cSmario.six@gdsys.cc 	}
81114a6ff2cSmario.six@gdsys.cc 
81214a6ff2cSmario.six@gdsys.cc 	omsg = nmsgs == 1 ? &dummy : msg;
81314a6ff2cSmario.six@gdsys.cc 	dmsg = nmsgs == 1 ? msg : msg + 1;
81414a6ff2cSmario.six@gdsys.cc 
81514a6ff2cSmario.six@gdsys.cc 	if (dmsg->flags & I2C_M_RD)
81614a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
817c68c6243Smario.six@gdsys.cc 				       omsg->len, dmsg->buf, dmsg->len,
818c68c6243Smario.six@gdsys.cc 				       dev->tick);
81914a6ff2cSmario.six@gdsys.cc 	else
82014a6ff2cSmario.six@gdsys.cc 		return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
821c68c6243Smario.six@gdsys.cc 					omsg->len, dmsg->buf, dmsg->len,
822c68c6243Smario.six@gdsys.cc 					dev->tick);
82314a6ff2cSmario.six@gdsys.cc }
82414a6ff2cSmario.six@gdsys.cc 
82514a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
82614a6ff2cSmario.six@gdsys.cc 	.xfer		= mvtwsi_i2c_xfer,
82714a6ff2cSmario.six@gdsys.cc 	.probe_chip	= mvtwsi_i2c_probe_chip,
82814a6ff2cSmario.six@gdsys.cc 	.set_bus_speed	= mvtwsi_i2c_set_bus_speed,
82914a6ff2cSmario.six@gdsys.cc };
83014a6ff2cSmario.six@gdsys.cc 
83114a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
83214a6ff2cSmario.six@gdsys.cc 	{ .compatible = "marvell,mv64xxx-i2c", },
83314a6ff2cSmario.six@gdsys.cc 	{ /* sentinel */ }
83414a6ff2cSmario.six@gdsys.cc };
83514a6ff2cSmario.six@gdsys.cc 
83614a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
83714a6ff2cSmario.six@gdsys.cc 	.name = "i2c_mvtwsi",
83814a6ff2cSmario.six@gdsys.cc 	.id = UCLASS_I2C,
83914a6ff2cSmario.six@gdsys.cc 	.of_match = mvtwsi_i2c_ids,
84014a6ff2cSmario.six@gdsys.cc 	.probe = mvtwsi_i2c_probe,
84114a6ff2cSmario.six@gdsys.cc 	.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
84214a6ff2cSmario.six@gdsys.cc 	.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
84314a6ff2cSmario.six@gdsys.cc 	.ops = &mvtwsi_i2c_ops,
84414a6ff2cSmario.six@gdsys.cc };
84514a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
846