xref: /OK3568_Linux_fs/u-boot/drivers/i2c/ihs_i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2013
3*4882a593Smuzhiyun  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * NOTE: This driver should be converted to driver model before June 2017.
8*4882a593Smuzhiyun  * Please see doc/driver-model/i2c-howto.txt for instructions.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <i2c.h>
13*4882a593Smuzhiyun #include <gdsys_fpga.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
18*4882a593Smuzhiyun #define I2C_SET_REG(fld, val) \
19*4882a593Smuzhiyun 	do { \
20*4882a593Smuzhiyun 		if (I2C_ADAP_HWNR & 0x10) \
21*4882a593Smuzhiyun 			FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
22*4882a593Smuzhiyun 		else \
23*4882a593Smuzhiyun 			FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
24*4882a593Smuzhiyun 	} while (0)
25*4882a593Smuzhiyun #else
26*4882a593Smuzhiyun #define I2C_SET_REG(fld, val) \
27*4882a593Smuzhiyun 		FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
31*4882a593Smuzhiyun #define I2C_GET_REG(fld, val) \
32*4882a593Smuzhiyun 	do {					\
33*4882a593Smuzhiyun 		if (I2C_ADAP_HWNR & 0x10) \
34*4882a593Smuzhiyun 			FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
35*4882a593Smuzhiyun 		else \
36*4882a593Smuzhiyun 			FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
37*4882a593Smuzhiyun 	} while (0)
38*4882a593Smuzhiyun #else
39*4882a593Smuzhiyun #define I2C_GET_REG(fld, val) \
40*4882a593Smuzhiyun 		FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
41*4882a593Smuzhiyun #endif
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun enum {
44*4882a593Smuzhiyun 	I2CINT_ERROR_EV = 1 << 13,
45*4882a593Smuzhiyun 	I2CINT_TRANSMIT_EV = 1 << 14,
46*4882a593Smuzhiyun 	I2CINT_RECEIVE_EV = 1 << 15,
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun enum {
50*4882a593Smuzhiyun 	I2CMB_WRITE = 1 << 10,
51*4882a593Smuzhiyun 	I2CMB_2BYTE = 1 << 11,
52*4882a593Smuzhiyun 	I2CMB_HOLD_BUS = 1 << 13,
53*4882a593Smuzhiyun 	I2CMB_NATIVE = 2 << 14,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
wait_for_int(bool read)56*4882a593Smuzhiyun static int wait_for_int(bool read)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	u16 val;
59*4882a593Smuzhiyun 	unsigned int ctr = 0;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	I2C_GET_REG(interrupt_status, &val);
62*4882a593Smuzhiyun 	while (!(val & (I2CINT_ERROR_EV
63*4882a593Smuzhiyun 	       | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
64*4882a593Smuzhiyun 		udelay(10);
65*4882a593Smuzhiyun 		if (ctr++ > 5000) {
66*4882a593Smuzhiyun 			return 1;
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 		I2C_GET_REG(interrupt_status, &val);
69*4882a593Smuzhiyun 	}
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	return (val & I2CINT_ERROR_EV) ? 1 : 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
ihs_i2c_transfer(uchar chip,uchar * buffer,int len,bool read,bool is_last)74*4882a593Smuzhiyun static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
75*4882a593Smuzhiyun 			    bool is_last)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	u16 val;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
80*4882a593Smuzhiyun 		     | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
81*4882a593Smuzhiyun 	I2C_GET_REG(interrupt_status, &val);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	if (!read && len) {
84*4882a593Smuzhiyun 		val = buffer[0];
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		if (len > 1)
87*4882a593Smuzhiyun 			val |= buffer[1] << 8;
88*4882a593Smuzhiyun 		I2C_SET_REG(write_mailbox_ext, val);
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	I2C_SET_REG(write_mailbox,
92*4882a593Smuzhiyun 		    I2CMB_NATIVE
93*4882a593Smuzhiyun 		    | (read ? 0 : I2CMB_WRITE)
94*4882a593Smuzhiyun 		    | (chip << 1)
95*4882a593Smuzhiyun 		    | ((len > 1) ? I2CMB_2BYTE : 0)
96*4882a593Smuzhiyun 		    | (is_last ? 0 : I2CMB_HOLD_BUS));
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (wait_for_int(read))
99*4882a593Smuzhiyun 		return 1;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (read) {
102*4882a593Smuzhiyun 		I2C_GET_REG(read_mailbox_ext, &val);
103*4882a593Smuzhiyun 		buffer[0] = val & 0xff;
104*4882a593Smuzhiyun 		if (len > 1)
105*4882a593Smuzhiyun 			buffer[1] = val >> 8;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
ihs_i2c_address(uchar chip,uint addr,int alen,bool hold_bus)111*4882a593Smuzhiyun static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	int shift = (alen-1) * 8;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	while (alen) {
116*4882a593Smuzhiyun 		int transfer = min(alen, 2);
117*4882a593Smuzhiyun 		uchar buf[2];
118*4882a593Smuzhiyun 		bool is_last = alen <= transfer;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		buf[0] = addr >> shift;
121*4882a593Smuzhiyun 		if (alen > 1)
122*4882a593Smuzhiyun 			buf[1] = addr >> (shift - 8);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 		if (ihs_i2c_transfer(chip, buf, transfer, false,
125*4882a593Smuzhiyun 				     hold_bus ? false : is_last))
126*4882a593Smuzhiyun 			return 1;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		shift -= 16;
129*4882a593Smuzhiyun 		alen -= transfer;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
ihs_i2c_access(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len,bool read)135*4882a593Smuzhiyun static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr,
136*4882a593Smuzhiyun 			  int alen, uchar *buffer, int len, bool read)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	if (len <= 0)
139*4882a593Smuzhiyun 		return 1;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (ihs_i2c_address(chip, addr, alen, len))
142*4882a593Smuzhiyun 		return 1;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	while (len) {
145*4882a593Smuzhiyun 		int transfer = min(len, 2);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 		if (ihs_i2c_transfer(chip, buffer, transfer, read,
148*4882a593Smuzhiyun 				     len <= transfer))
149*4882a593Smuzhiyun 			return 1;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		buffer += transfer;
152*4882a593Smuzhiyun 		addr += transfer;
153*4882a593Smuzhiyun 		len -= transfer;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 
ihs_i2c_init(struct i2c_adapter * adap,int speed,int slaveaddr)160*4882a593Smuzhiyun static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_INIT_BOARD
163*4882a593Smuzhiyun 	/*
164*4882a593Smuzhiyun 	 * Call board specific i2c bus reset routine before accessing the
165*4882a593Smuzhiyun 	 * environment, which might be in a chip on that bus. For details
166*4882a593Smuzhiyun 	 * about this problem see doc/I2C_Edge_Conditions.
167*4882a593Smuzhiyun 	 */
168*4882a593Smuzhiyun 	i2c_init_board();
169*4882a593Smuzhiyun #endif
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
ihs_i2c_probe(struct i2c_adapter * adap,uchar chip)172*4882a593Smuzhiyun static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	uchar buffer[2];
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (ihs_i2c_transfer(chip, buffer, 0, true, true))
177*4882a593Smuzhiyun 		return 1;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
ihs_i2c_read(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len)182*4882a593Smuzhiyun static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
183*4882a593Smuzhiyun 			int alen, uchar *buffer, int len)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, true);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
ihs_i2c_write(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * buffer,int len)188*4882a593Smuzhiyun static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
189*4882a593Smuzhiyun 			 int alen, uchar *buffer, int len)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, false);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
ihs_i2c_set_bus_speed(struct i2c_adapter * adap,unsigned int speed)194*4882a593Smuzhiyun static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
195*4882a593Smuzhiyun 					  unsigned int speed)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	if (speed != adap->speed)
198*4882a593Smuzhiyun 		return 1;
199*4882a593Smuzhiyun 	return speed;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /*
203*4882a593Smuzhiyun  * Register IHS i2c adapters
204*4882a593Smuzhiyun  */
205*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_CH0
206*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
207*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
208*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
209*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_0,
210*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
211*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
212*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
213*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
214*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
215*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_0_1,
216*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
217*4882a593Smuzhiyun #endif
218*4882a593Smuzhiyun #endif
219*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_CH1
220*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
221*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
222*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
223*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_1,
224*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
225*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
226*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
227*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
228*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
229*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_1_1,
230*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
231*4882a593Smuzhiyun #endif
232*4882a593Smuzhiyun #endif
233*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_CH2
234*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
235*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
236*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
237*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_2,
238*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
239*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
240*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
241*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
242*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
243*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_2_1,
244*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
245*4882a593Smuzhiyun #endif
246*4882a593Smuzhiyun #endif
247*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_CH3
248*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
249*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
250*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
251*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_3,
252*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
253*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_IHS_DUAL
254*4882a593Smuzhiyun U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
255*4882a593Smuzhiyun 			 ihs_i2c_read, ihs_i2c_write,
256*4882a593Smuzhiyun 			 ihs_i2c_set_bus_speed,
257*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SPEED_3_1,
258*4882a593Smuzhiyun 			 CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
259*4882a593Smuzhiyun #endif
260*4882a593Smuzhiyun #endif
261