xref: /rk3399_rockchip-uboot/drivers/i2c/ihs_i2c.c (revision f2465934b46235287e07473fa4919035ba1a2b68)
1b46226bdSDirk Eibach /*
2b46226bdSDirk Eibach  * (C) Copyright 2013
3b46226bdSDirk Eibach  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4b46226bdSDirk Eibach  *
5b46226bdSDirk Eibach  * SPDX-License-Identifier:	GPL-2.0+
6*28527096SSimon Glass  *
7*28527096SSimon Glass  * NOTE: This driver should be converted to driver model before June 2017.
8*28527096SSimon Glass  * Please see doc/driver-model/i2c-howto.txt for instructions.
9b46226bdSDirk Eibach  */
10b46226bdSDirk Eibach 
11b46226bdSDirk Eibach #include <common.h>
12b46226bdSDirk Eibach #include <i2c.h>
13b46226bdSDirk Eibach #include <gdsys_fpga.h>
14b46226bdSDirk Eibach 
15b46226bdSDirk Eibach DECLARE_GLOBAL_DATA_PTR;
16b46226bdSDirk Eibach 
17071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
18071be896SDirk Eibach #define I2C_SET_REG(fld, val) \
193af0cdb1SDirk Eibach 	do { \
203af0cdb1SDirk Eibach 		if (I2C_ADAP_HWNR & 0x10) \
21071be896SDirk Eibach 			FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
22071be896SDirk Eibach 		else \
233af0cdb1SDirk Eibach 			FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
243af0cdb1SDirk Eibach 	} while (0)
25071be896SDirk Eibach #else
26071be896SDirk Eibach #define I2C_SET_REG(fld, val) \
273af0cdb1SDirk Eibach 		FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
28071be896SDirk Eibach #endif
29071be896SDirk Eibach 
30071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
31071be896SDirk Eibach #define I2C_GET_REG(fld, val) \
323af0cdb1SDirk Eibach 	do {					\
333af0cdb1SDirk Eibach 		if (I2C_ADAP_HWNR & 0x10) \
34071be896SDirk Eibach 			FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
35071be896SDirk Eibach 		else \
363af0cdb1SDirk Eibach 			FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
373af0cdb1SDirk Eibach 	} while (0)
38071be896SDirk Eibach #else
39071be896SDirk Eibach #define I2C_GET_REG(fld, val) \
403af0cdb1SDirk Eibach 		FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
41071be896SDirk Eibach #endif
42071be896SDirk Eibach 
43b46226bdSDirk Eibach enum {
44b46226bdSDirk Eibach 	I2CINT_ERROR_EV = 1 << 13,
45b46226bdSDirk Eibach 	I2CINT_TRANSMIT_EV = 1 << 14,
46b46226bdSDirk Eibach 	I2CINT_RECEIVE_EV = 1 << 15,
47b46226bdSDirk Eibach };
48b46226bdSDirk Eibach 
49b46226bdSDirk Eibach enum {
50b46226bdSDirk Eibach 	I2CMB_WRITE = 1 << 10,
51b46226bdSDirk Eibach 	I2CMB_2BYTE = 1 << 11,
52b46226bdSDirk Eibach 	I2CMB_HOLD_BUS = 1 << 13,
53b46226bdSDirk Eibach 	I2CMB_NATIVE = 2 << 14,
54b46226bdSDirk Eibach };
55b46226bdSDirk Eibach 
wait_for_int(bool read)56b46226bdSDirk Eibach static int wait_for_int(bool read)
57b46226bdSDirk Eibach {
58b46226bdSDirk Eibach 	u16 val;
59b46226bdSDirk Eibach 	unsigned int ctr = 0;
60b46226bdSDirk Eibach 
61071be896SDirk Eibach 	I2C_GET_REG(interrupt_status, &val);
62b46226bdSDirk Eibach 	while (!(val & (I2CINT_ERROR_EV
63b46226bdSDirk Eibach 	       | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
64b46226bdSDirk Eibach 		udelay(10);
65b46226bdSDirk Eibach 		if (ctr++ > 5000) {
66b46226bdSDirk Eibach 			return 1;
67b46226bdSDirk Eibach 		}
68071be896SDirk Eibach 		I2C_GET_REG(interrupt_status, &val);
69b46226bdSDirk Eibach 	}
70b46226bdSDirk Eibach 
71b46226bdSDirk Eibach 	return (val & I2CINT_ERROR_EV) ? 1 : 0;
72b46226bdSDirk Eibach }
73b46226bdSDirk Eibach 
ihs_i2c_transfer(uchar chip,uchar * buffer,int len,bool read,bool is_last)74b46226bdSDirk Eibach static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
75b46226bdSDirk Eibach 			    bool is_last)
76b46226bdSDirk Eibach {
77b46226bdSDirk Eibach 	u16 val;
78b46226bdSDirk Eibach 
79071be896SDirk Eibach 	I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
80b46226bdSDirk Eibach 		     | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
81071be896SDirk Eibach 	I2C_GET_REG(interrupt_status, &val);
82b46226bdSDirk Eibach 
83b46226bdSDirk Eibach 	if (!read && len) {
84b46226bdSDirk Eibach 		val = buffer[0];
85b46226bdSDirk Eibach 
86b46226bdSDirk Eibach 		if (len > 1)
87b46226bdSDirk Eibach 			val |= buffer[1] << 8;
88071be896SDirk Eibach 		I2C_SET_REG(write_mailbox_ext, val);
89b46226bdSDirk Eibach 	}
90b46226bdSDirk Eibach 
91071be896SDirk Eibach 	I2C_SET_REG(write_mailbox,
92b46226bdSDirk Eibach 		    I2CMB_NATIVE
93b46226bdSDirk Eibach 		    | (read ? 0 : I2CMB_WRITE)
94b46226bdSDirk Eibach 		    | (chip << 1)
95b46226bdSDirk Eibach 		    | ((len > 1) ? I2CMB_2BYTE : 0)
96b46226bdSDirk Eibach 		    | (is_last ? 0 : I2CMB_HOLD_BUS));
97b46226bdSDirk Eibach 
98b46226bdSDirk Eibach 	if (wait_for_int(read))
99b46226bdSDirk Eibach 		return 1;
100b46226bdSDirk Eibach 
101b46226bdSDirk Eibach 	if (read) {
102071be896SDirk Eibach 		I2C_GET_REG(read_mailbox_ext, &val);
103b46226bdSDirk Eibach 		buffer[0] = val & 0xff;
104b46226bdSDirk Eibach 		if (len > 1)
105b46226bdSDirk Eibach 			buffer[1] = val >> 8;
106b46226bdSDirk Eibach 	}
107b46226bdSDirk Eibach 
108b46226bdSDirk Eibach 	return 0;
109b46226bdSDirk Eibach }
110b46226bdSDirk Eibach 
ihs_i2c_address(uchar chip,uint addr,int alen,bool hold_bus)111b46226bdSDirk Eibach static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus)
112b46226bdSDirk Eibach {
113b46226bdSDirk Eibach 	int shift = (alen-1) * 8;
114b46226bdSDirk Eibach 
115b46226bdSDirk Eibach 	while (alen) {
116c79cba37SMasahiro Yamada 		int transfer = min(alen, 2);
117b46226bdSDirk Eibach 		uchar buf[2];
118b46226bdSDirk Eibach 		bool is_last = alen <= transfer;
119b46226bdSDirk Eibach 
120b46226bdSDirk Eibach 		buf[0] = addr >> shift;
121b46226bdSDirk Eibach 		if (alen > 1)
122b46226bdSDirk Eibach 			buf[1] = addr >> (shift - 8);
123b46226bdSDirk Eibach 
124b46226bdSDirk Eibach 		if (ihs_i2c_transfer(chip, buf, transfer, false,
125b46226bdSDirk Eibach 				     hold_bus ? false : is_last))
126b46226bdSDirk Eibach 			return 1;
127b46226bdSDirk Eibach 
128b46226bdSDirk Eibach 		shift -= 16;
129b46226bdSDirk Eibach 		alen -= transfer;
130b46226bdSDirk Eibach 	}
131b46226bdSDirk Eibach 
132b46226bdSDirk Eibach 	return 0;
133b46226bdSDirk Eibach }
134b46226bdSDirk Eibach 
ihs_i2c_access(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len,bool read)135b46226bdSDirk Eibach static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr,
136b46226bdSDirk Eibach 			  int alen, uchar *buffer, int len, bool read)
137b46226bdSDirk Eibach {
138b46226bdSDirk Eibach 	if (len <= 0)
139b46226bdSDirk Eibach 		return 1;
140b46226bdSDirk Eibach 
14145749156SDirk Eibach 	if (ihs_i2c_address(chip, addr, alen, len))
142b46226bdSDirk Eibach 		return 1;
143b46226bdSDirk Eibach 
144b46226bdSDirk Eibach 	while (len) {
145c79cba37SMasahiro Yamada 		int transfer = min(len, 2);
146b46226bdSDirk Eibach 
147b46226bdSDirk Eibach 		if (ihs_i2c_transfer(chip, buffer, transfer, read,
148b46226bdSDirk Eibach 				     len <= transfer))
149b46226bdSDirk Eibach 			return 1;
150b46226bdSDirk Eibach 
151b46226bdSDirk Eibach 		buffer += transfer;
152b46226bdSDirk Eibach 		addr += transfer;
153b46226bdSDirk Eibach 		len -= transfer;
154b46226bdSDirk Eibach 	}
155b46226bdSDirk Eibach 
156b46226bdSDirk Eibach 	return 0;
157b46226bdSDirk Eibach }
158b46226bdSDirk Eibach 
159b46226bdSDirk Eibach 
ihs_i2c_init(struct i2c_adapter * adap,int speed,int slaveaddr)160b46226bdSDirk Eibach static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
161b46226bdSDirk Eibach {
162b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_INIT_BOARD
163b46226bdSDirk Eibach 	/*
164b46226bdSDirk Eibach 	 * Call board specific i2c bus reset routine before accessing the
165b46226bdSDirk Eibach 	 * environment, which might be in a chip on that bus. For details
166b46226bdSDirk Eibach 	 * about this problem see doc/I2C_Edge_Conditions.
167b46226bdSDirk Eibach 	 */
168b46226bdSDirk Eibach 	i2c_init_board();
169b46226bdSDirk Eibach #endif
170b46226bdSDirk Eibach }
171b46226bdSDirk Eibach 
ihs_i2c_probe(struct i2c_adapter * adap,uchar chip)172b46226bdSDirk Eibach static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
173b46226bdSDirk Eibach {
174b46226bdSDirk Eibach 	uchar buffer[2];
175b46226bdSDirk Eibach 
176b46226bdSDirk Eibach 	if (ihs_i2c_transfer(chip, buffer, 0, true, true))
177b46226bdSDirk Eibach 		return 1;
178b46226bdSDirk Eibach 
179b46226bdSDirk Eibach 	return 0;
180b46226bdSDirk Eibach }
181b46226bdSDirk Eibach 
ihs_i2c_read(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len)182b46226bdSDirk Eibach static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
183b46226bdSDirk Eibach 			int alen, uchar *buffer, int len)
184b46226bdSDirk Eibach {
185b46226bdSDirk Eibach 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, true);
186b46226bdSDirk Eibach }
187b46226bdSDirk Eibach 
ihs_i2c_write(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len)188b46226bdSDirk Eibach static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
189b46226bdSDirk Eibach 			 int alen, uchar *buffer, int len)
190b46226bdSDirk Eibach {
191b46226bdSDirk Eibach 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, false);
192b46226bdSDirk Eibach }
193b46226bdSDirk Eibach 
ihs_i2c_set_bus_speed(struct i2c_adapter * adap,unsigned int speed)194b46226bdSDirk Eibach static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
195b46226bdSDirk Eibach 					  unsigned int speed)
196b46226bdSDirk Eibach {
197b46226bdSDirk Eibach 	if (speed != adap->speed)
198b46226bdSDirk Eibach 		return 1;
199b46226bdSDirk Eibach 	return speed;
200b46226bdSDirk Eibach }
201b46226bdSDirk Eibach 
202b46226bdSDirk Eibach /*
203b46226bdSDirk Eibach  * Register IHS i2c adapters
204b46226bdSDirk Eibach  */
205b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH0
206b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
207b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
208b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
209b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_0,
210b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
211071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
212071be896SDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
213071be896SDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
214071be896SDirk Eibach 			 ihs_i2c_set_bus_speed,
215071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_0_1,
216071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
217071be896SDirk Eibach #endif
218b46226bdSDirk Eibach #endif
219b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH1
220b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
221b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
222b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
223b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_1,
224b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
225071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
226071be896SDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
227071be896SDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
228071be896SDirk Eibach 			 ihs_i2c_set_bus_speed,
229071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_1_1,
230071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
231071be896SDirk Eibach #endif
232b46226bdSDirk Eibach #endif
233b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH2
234b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
235b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
236b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
237b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_2,
238b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
239071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
240071be896SDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
241071be896SDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
242071be896SDirk Eibach 			 ihs_i2c_set_bus_speed,
243071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_2_1,
244071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
245071be896SDirk Eibach #endif
246b46226bdSDirk Eibach #endif
247b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH3
248b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
249b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
250b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
251b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_3,
252b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
253071be896SDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_DUAL
254071be896SDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
255071be896SDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
256071be896SDirk Eibach 			 ihs_i2c_set_bus_speed,
257071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_3_1,
258071be896SDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
259071be896SDirk Eibach #endif
260b46226bdSDirk Eibach #endif
261