xref: /rk3399_rockchip-uboot/drivers/i2c/ihs_i2c.c (revision c79cba37b3b42cf8fbd71babcd8998867f76fead)
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+
6b46226bdSDirk Eibach  */
7b46226bdSDirk Eibach 
8b46226bdSDirk Eibach #include <common.h>
9b46226bdSDirk Eibach #include <i2c.h>
10b46226bdSDirk Eibach #include <gdsys_fpga.h>
11b46226bdSDirk Eibach 
12b46226bdSDirk Eibach DECLARE_GLOBAL_DATA_PTR;
13b46226bdSDirk Eibach 
14b46226bdSDirk Eibach enum {
15b46226bdSDirk Eibach 	I2CINT_ERROR_EV = 1 << 13,
16b46226bdSDirk Eibach 	I2CINT_TRANSMIT_EV = 1 << 14,
17b46226bdSDirk Eibach 	I2CINT_RECEIVE_EV = 1 << 15,
18b46226bdSDirk Eibach };
19b46226bdSDirk Eibach 
20b46226bdSDirk Eibach enum {
21b46226bdSDirk Eibach 	I2CMB_WRITE = 1 << 10,
22b46226bdSDirk Eibach 	I2CMB_2BYTE = 1 << 11,
23b46226bdSDirk Eibach 	I2CMB_HOLD_BUS = 1 << 13,
24b46226bdSDirk Eibach 	I2CMB_NATIVE = 2 << 14,
25b46226bdSDirk Eibach };
26b46226bdSDirk Eibach 
27b46226bdSDirk Eibach static int wait_for_int(bool read)
28b46226bdSDirk Eibach {
29b46226bdSDirk Eibach 	u16 val;
30b46226bdSDirk Eibach 	unsigned int ctr = 0;
31b46226bdSDirk Eibach 
32b46226bdSDirk Eibach 	FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val);
33b46226bdSDirk Eibach 	while (!(val & (I2CINT_ERROR_EV
34b46226bdSDirk Eibach 	       | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
35b46226bdSDirk Eibach 		udelay(10);
36b46226bdSDirk Eibach 		if (ctr++ > 5000) {
37b46226bdSDirk Eibach 			return 1;
38b46226bdSDirk Eibach 		}
39b46226bdSDirk Eibach 		FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val);
40b46226bdSDirk Eibach 	}
41b46226bdSDirk Eibach 
42b46226bdSDirk Eibach 	return (val & I2CINT_ERROR_EV) ? 1 : 0;
43b46226bdSDirk Eibach }
44b46226bdSDirk Eibach 
45b46226bdSDirk Eibach static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
46b46226bdSDirk Eibach 			    bool is_last)
47b46226bdSDirk Eibach {
48b46226bdSDirk Eibach 	u16 val;
49b46226bdSDirk Eibach 
50b46226bdSDirk Eibach 	FPGA_SET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, I2CINT_ERROR_EV
51b46226bdSDirk Eibach 		     | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
52b46226bdSDirk Eibach 	FPGA_GET_REG(I2C_ADAP_HWNR, i2c.interrupt_status, &val);
53b46226bdSDirk Eibach 
54b46226bdSDirk Eibach 	if (!read && len) {
55b46226bdSDirk Eibach 		val = buffer[0];
56b46226bdSDirk Eibach 
57b46226bdSDirk Eibach 		if (len > 1)
58b46226bdSDirk Eibach 			val |= buffer[1] << 8;
59b46226bdSDirk Eibach 		FPGA_SET_REG(I2C_ADAP_HWNR, i2c.write_mailbox_ext, val);
60b46226bdSDirk Eibach 	}
61b46226bdSDirk Eibach 
62b46226bdSDirk Eibach 	FPGA_SET_REG(I2C_ADAP_HWNR, i2c.write_mailbox,
63b46226bdSDirk Eibach 		     I2CMB_NATIVE
64b46226bdSDirk Eibach 		     | (read ? 0 : I2CMB_WRITE)
65b46226bdSDirk Eibach 		     | (chip << 1)
66b46226bdSDirk Eibach 		     | ((len > 1) ? I2CMB_2BYTE : 0)
67b46226bdSDirk Eibach 		     | (is_last ? 0 : I2CMB_HOLD_BUS));
68b46226bdSDirk Eibach 
69b46226bdSDirk Eibach 	if (wait_for_int(read))
70b46226bdSDirk Eibach 		return 1;
71b46226bdSDirk Eibach 
72b46226bdSDirk Eibach 	if (read) {
73b46226bdSDirk Eibach 		FPGA_GET_REG(I2C_ADAP_HWNR, i2c.read_mailbox_ext, &val);
74b46226bdSDirk Eibach 		buffer[0] = val & 0xff;
75b46226bdSDirk Eibach 		if (len > 1)
76b46226bdSDirk Eibach 			buffer[1] = val >> 8;
77b46226bdSDirk Eibach 	}
78b46226bdSDirk Eibach 
79b46226bdSDirk Eibach 	return 0;
80b46226bdSDirk Eibach }
81b46226bdSDirk Eibach 
82b46226bdSDirk Eibach static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus)
83b46226bdSDirk Eibach {
84b46226bdSDirk Eibach 	int shift = (alen-1) * 8;
85b46226bdSDirk Eibach 
86b46226bdSDirk Eibach 	while (alen) {
87*c79cba37SMasahiro Yamada 		int transfer = min(alen, 2);
88b46226bdSDirk Eibach 		uchar buf[2];
89b46226bdSDirk Eibach 		bool is_last = alen <= transfer;
90b46226bdSDirk Eibach 
91b46226bdSDirk Eibach 		buf[0] = addr >> shift;
92b46226bdSDirk Eibach 		if (alen > 1)
93b46226bdSDirk Eibach 			buf[1] = addr >> (shift - 8);
94b46226bdSDirk Eibach 
95b46226bdSDirk Eibach 		if (ihs_i2c_transfer(chip, buf, transfer, false,
96b46226bdSDirk Eibach 				     hold_bus ? false : is_last))
97b46226bdSDirk Eibach 			return 1;
98b46226bdSDirk Eibach 
99b46226bdSDirk Eibach 		shift -= 16;
100b46226bdSDirk Eibach 		alen -= transfer;
101b46226bdSDirk Eibach 	}
102b46226bdSDirk Eibach 
103b46226bdSDirk Eibach 	return 0;
104b46226bdSDirk Eibach }
105b46226bdSDirk Eibach 
106b46226bdSDirk Eibach static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr,
107b46226bdSDirk Eibach 			  int alen, uchar *buffer, int len, bool read)
108b46226bdSDirk Eibach {
109b46226bdSDirk Eibach 	if (len <= 0)
110b46226bdSDirk Eibach 		return 1;
111b46226bdSDirk Eibach 
112b46226bdSDirk Eibach 	if (ihs_i2c_address(chip, addr, alen, !read))
113b46226bdSDirk Eibach 		return 1;
114b46226bdSDirk Eibach 
115b46226bdSDirk Eibach 	while (len) {
116*c79cba37SMasahiro Yamada 		int transfer = min(len, 2);
117b46226bdSDirk Eibach 
118b46226bdSDirk Eibach 		if (ihs_i2c_transfer(chip, buffer, transfer, read,
119b46226bdSDirk Eibach 				     len <= transfer))
120b46226bdSDirk Eibach 			return 1;
121b46226bdSDirk Eibach 
122b46226bdSDirk Eibach 		buffer += transfer;
123b46226bdSDirk Eibach 		addr += transfer;
124b46226bdSDirk Eibach 		len -= transfer;
125b46226bdSDirk Eibach 	}
126b46226bdSDirk Eibach 
127b46226bdSDirk Eibach 	return 0;
128b46226bdSDirk Eibach }
129b46226bdSDirk Eibach 
130b46226bdSDirk Eibach 
131b46226bdSDirk Eibach static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
132b46226bdSDirk Eibach {
133b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_INIT_BOARD
134b46226bdSDirk Eibach 	/*
135b46226bdSDirk Eibach 	 * Call board specific i2c bus reset routine before accessing the
136b46226bdSDirk Eibach 	 * environment, which might be in a chip on that bus. For details
137b46226bdSDirk Eibach 	 * about this problem see doc/I2C_Edge_Conditions.
138b46226bdSDirk Eibach 	 */
139b46226bdSDirk Eibach 	i2c_init_board();
140b46226bdSDirk Eibach #endif
141b46226bdSDirk Eibach }
142b46226bdSDirk Eibach 
143b46226bdSDirk Eibach static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
144b46226bdSDirk Eibach {
145b46226bdSDirk Eibach 	uchar buffer[2];
146b46226bdSDirk Eibach 
147b46226bdSDirk Eibach 	if (ihs_i2c_transfer(chip, buffer, 0, true, true))
148b46226bdSDirk Eibach 		return 1;
149b46226bdSDirk Eibach 
150b46226bdSDirk Eibach 	return 0;
151b46226bdSDirk Eibach }
152b46226bdSDirk Eibach 
153b46226bdSDirk Eibach static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
154b46226bdSDirk Eibach 			int alen, uchar *buffer, int len)
155b46226bdSDirk Eibach {
156b46226bdSDirk Eibach 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, true);
157b46226bdSDirk Eibach }
158b46226bdSDirk Eibach 
159b46226bdSDirk Eibach static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
160b46226bdSDirk Eibach 			 int alen, uchar *buffer, int len)
161b46226bdSDirk Eibach {
162b46226bdSDirk Eibach 	return ihs_i2c_access(adap, chip, addr, alen, buffer, len, false);
163b46226bdSDirk Eibach }
164b46226bdSDirk Eibach 
165b46226bdSDirk Eibach static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
166b46226bdSDirk Eibach 					     unsigned int speed)
167b46226bdSDirk Eibach {
168b46226bdSDirk Eibach 	if (speed != adap->speed)
169b46226bdSDirk Eibach 		return 1;
170b46226bdSDirk Eibach 	return speed;
171b46226bdSDirk Eibach }
172b46226bdSDirk Eibach 
173b46226bdSDirk Eibach /*
174b46226bdSDirk Eibach  * Register IHS i2c adapters
175b46226bdSDirk Eibach  */
176b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH0
177b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
178b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
179b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
180b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_0,
181b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
182b46226bdSDirk Eibach #endif
183b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH1
184b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
185b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
186b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
187b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_1,
188b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
189b46226bdSDirk Eibach #endif
190b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH2
191b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
192b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
193b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
194b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_2,
195b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
196b46226bdSDirk Eibach #endif
197b46226bdSDirk Eibach #ifdef CONFIG_SYS_I2C_IHS_CH3
198b46226bdSDirk Eibach U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
199b46226bdSDirk Eibach 			 ihs_i2c_read, ihs_i2c_write,
200b46226bdSDirk Eibach 			 ihs_i2c_set_bus_speed,
201b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SPEED_3,
202b46226bdSDirk Eibach 			 CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
203b46226bdSDirk Eibach #endif
204