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