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