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