]>
Commit | Line | Data |
---|---|---|
b825f158 | 1 | /* |
2 | * (C) Copyright 2004 Tundra Semiconductor Corp. | |
3 | * Author: Alex Bounine | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
28527096 SG |
6 | * |
7 | * NOTE: This driver should be converted to driver model before June 2017. | |
8 | * Please see doc/driver-model/i2c-howto.txt for instructions. | |
b825f158 | 9 | */ |
10 | ||
11 | #include <config.h> | |
ee311214 | 12 | #include <common.h> |
b825f158 | 13 | |
b825f158 | 14 | #include <tsi108.h> |
15 | ||
cb51c0bf | 16 | #if defined(CONFIG_CMD_I2C) |
b825f158 | 17 | |
ee311214 | 18 | #define I2C_DELAY 100000 |
b825f158 | 19 | #undef DEBUG_I2C |
20 | ||
21 | #ifdef DEBUG_I2C | |
ee311214 | 22 | #define DPRINT(x) printf (x) |
b825f158 | 23 | #else |
24 | #define DPRINT(x) | |
25 | #endif | |
26 | ||
27 | /* All functions assume that Tsi108 I2C block is the only master on the bus */ | |
28 | /* I2C read helper function */ | |
29 | ||
f0722ee7 PT |
30 | void i2c_init(int speed, int slaveaddr) |
31 | { | |
32 | /* | |
33 | * The TSI108 has a fixed I2C clock rate and doesn't support slave | |
34 | * operation. This function only exists as a stub to fit into the | |
35 | * U-Boot I2C API. | |
36 | */ | |
37 | } | |
38 | ||
ee311214 | 39 | static int i2c_read_byte ( |
b825f158 | 40 | uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */ |
41 | uchar chip_addr,/* I2C device address on the bus */ | |
42 | uint byte_addr, /* Byte address within I2C device */ | |
43 | uchar * buffer /* pointer to data buffer */ | |
44 | ) | |
45 | { | |
46 | u32 temp; | |
47 | u32 to_count = I2C_DELAY; | |
48 | u32 op_status = TSI108_I2C_TIMEOUT_ERR; | |
49 | u32 chan_offset = TSI108_I2C_OFFSET; | |
50 | ||
ee311214 | 51 | DPRINT (("I2C read_byte() %d 0x%02x 0x%02x\n", |
b825f158 | 52 | i2c_chan, chip_addr, byte_addr)); |
53 | ||
ee311214 | 54 | if (0 != i2c_chan) |
b825f158 | 55 | chan_offset = TSI108_I2C_SDRAM_OFFSET; |
b825f158 | 56 | |
57 | /* Check if I2C operation is in progress */ | |
6d0f6bcf | 58 | temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2); |
b825f158 | 59 | |
60 | if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | | |
ee311214 | 61 | I2C_CNTRL2_START))) { |
b825f158 | 62 | /* Set device address and operation (read = 0) */ |
63 | temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) | | |
64 | ((chip_addr >> 3) & 0x0F); | |
6d0f6bcf | 65 | *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) = |
b825f158 | 66 | temp; |
67 | ||
68 | /* Issue the read command | |
ee311214 | 69 | * (at this moment all other parameters are 0 |
b825f158 | 70 | * (size = 1 byte, lane = 0) |
71 | */ | |
72 | ||
6d0f6bcf | 73 | *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) = |
b825f158 | 74 | (I2C_CNTRL2_START); |
75 | ||
76 | /* Wait until operation completed */ | |
77 | do { | |
78 | /* Read I2C operation status */ | |
6d0f6bcf | 79 | temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2); |
647d3c3e WD |
80 | |
81 | if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) { | |
82 | if (0 == (temp & | |
b825f158 | 83 | (I2C_CNTRL2_I2C_CFGERR | |
84 | I2C_CNTRL2_I2C_TO_ERR)) | |
85 | ) { | |
86 | op_status = TSI108_I2C_SUCCESS; | |
87 | ||
6d0f6bcf | 88 | temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + |
b825f158 | 89 | chan_offset + |
90 | I2C_RD_DATA); | |
91 | ||
92 | *buffer = (u8) (temp & 0xFF); | |
93 | } else { | |
94 | /* report HW error */ | |
95 | op_status = TSI108_I2C_IF_ERROR; | |
96 | ||
ee311214 | 97 | DPRINT (("I2C HW error reported: 0x%02x\n", temp)); |
b825f158 | 98 | } |
99 | ||
100 | break; | |
101 | } | |
102 | } while (to_count--); | |
103 | } else { | |
104 | op_status = TSI108_I2C_IF_BUSY; | |
105 | ||
ee311214 | 106 | DPRINT (("I2C Transaction start failed: 0x%02x\n", temp)); |
b825f158 | 107 | } |
108 | ||
ee311214 | 109 | DPRINT (("I2C read_byte() status: 0x%02x\n", op_status)); |
b825f158 | 110 | return op_status; |
111 | } | |
112 | ||
ee311214 | 113 | /* |
b825f158 | 114 | * I2C Read interface as defined in "include/i2c.h" : |
115 | * chip_addr: I2C chip address, range 0..127 | |
116 | * (to read from SPD channel EEPROM use (0xD0 ... 0xD7) | |
117 | * NOTE: The bit 7 in the chip_addr serves as a channel select. | |
0f89c54b | 118 | * This hack is for enabling "i2c sdram" command on Tsi108 boards |
ee311214 | 119 | * without changes to common code. Used for I2C reads only. |
b825f158 | 120 | * byte_addr: Memory or register address within the chip |
121 | * alen: Number of bytes to use for addr (typically 1, 2 for larger | |
122 | * memories, 0 for register type devices with only one | |
123 | * register) | |
124 | * buffer: Pointer to destination buffer for data to be read | |
125 | * len: How many bytes to read | |
126 | * | |
127 | * Returns: 0 on success, not 0 on failure | |
128 | */ | |
129 | ||
ee311214 | 130 | int i2c_read (uchar chip_addr, uint byte_addr, int alen, |
131 | uchar * buffer, int len) | |
b825f158 | 132 | { |
133 | u32 op_status = TSI108_I2C_PARAM_ERR; | |
134 | u32 i2c_if = 0; | |
135 | ||
136 | /* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/ | |
137 | if (0xD0 == (chip_addr & ~0x07)) { | |
138 | i2c_if = 1; | |
139 | chip_addr &= 0x7F; | |
140 | } | |
141 | /* Check for valid I2C address */ | |
142 | if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { | |
143 | while (len--) { | |
647d3c3e | 144 | op_status = i2c_read_byte(i2c_if, chip_addr, byte_addr++, buffer++); |
b825f158 | 145 | |
146 | if (TSI108_I2C_SUCCESS != op_status) { | |
ee311214 | 147 | DPRINT (("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len)); |
b825f158 | 148 | |
149 | break; | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
ee311214 | 154 | DPRINT (("I2C read() status: 0x%02x\n", op_status)); |
b825f158 | 155 | return op_status; |
156 | } | |
157 | ||
158 | /* I2C write helper function */ | |
159 | ||
ee311214 | 160 | static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */ |
b825f158 | 161 | uint byte_addr, /* Byte address within I2C device */ |
162 | uchar * buffer /* pointer to data buffer */ | |
163 | ) | |
164 | { | |
165 | u32 temp; | |
166 | u32 to_count = I2C_DELAY; | |
167 | u32 op_status = TSI108_I2C_TIMEOUT_ERR; | |
168 | ||
169 | /* Check if I2C operation is in progress */ | |
6d0f6bcf | 170 | temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2); |
b825f158 | 171 | |
647d3c3e | 172 | if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) { |
b825f158 | 173 | /* Place data into the I2C Tx Register */ |
6d0f6bcf | 174 | *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + |
b825f158 | 175 | I2C_TX_DATA) = (u32) * buffer; |
176 | ||
177 | /* Set device address and operation */ | |
178 | temp = | |
179 | I2C_CNTRL1_I2CWRITE | (byte_addr << 16) | | |
180 | ((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F); | |
6d0f6bcf | 181 | *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + |
b825f158 | 182 | I2C_CNTRL1) = temp; |
183 | ||
184 | /* Issue the write command (at this moment all other parameters | |
185 | * are 0 (size = 1 byte, lane = 0) | |
186 | */ | |
647d3c3e | 187 | |
6d0f6bcf | 188 | *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + |
b825f158 | 189 | I2C_CNTRL2) = (I2C_CNTRL2_START); |
190 | ||
191 | op_status = TSI108_I2C_TIMEOUT_ERR; | |
192 | ||
193 | /* Wait until operation completed */ | |
194 | do { | |
ee311214 | 195 | /* Read I2C operation status */ |
6d0f6bcf | 196 | temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2); |
647d3c3e WD |
197 | |
198 | if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) { | |
199 | if (0 == (temp & | |
b825f158 | 200 | (I2C_CNTRL2_I2C_CFGERR | |
201 | I2C_CNTRL2_I2C_TO_ERR))) { | |
202 | op_status = TSI108_I2C_SUCCESS; | |
203 | } else { | |
204 | /* report detected HW error */ | |
205 | op_status = TSI108_I2C_IF_ERROR; | |
206 | ||
ee311214 | 207 | DPRINT (("I2C HW error reported: 0x%02x\n", temp)); |
b825f158 | 208 | } |
209 | ||
210 | break; | |
211 | } | |
212 | ||
213 | } while (to_count--); | |
214 | } else { | |
215 | op_status = TSI108_I2C_IF_BUSY; | |
216 | ||
ee311214 | 217 | DPRINT (("I2C Transaction start failed: 0x%02x\n", temp)); |
b825f158 | 218 | } |
219 | ||
220 | return op_status; | |
221 | } | |
222 | ||
ee311214 | 223 | /* |
b825f158 | 224 | * I2C Write interface as defined in "include/i2c.h" : |
225 | * chip_addr: I2C chip address, range 0..127 | |
226 | * byte_addr: Memory or register address within the chip | |
227 | * alen: Number of bytes to use for addr (typically 1, 2 for larger | |
228 | * memories, 0 for register type devices with only one | |
229 | * register) | |
230 | * buffer: Pointer to data to be written | |
231 | * len: How many bytes to write | |
232 | * | |
233 | * Returns: 0 on success, not 0 on failure | |
234 | */ | |
235 | ||
ee311214 | 236 | int i2c_write (uchar chip_addr, uint byte_addr, int alen, uchar * buffer, |
b825f158 | 237 | int len) |
238 | { | |
239 | u32 op_status = TSI108_I2C_PARAM_ERR; | |
240 | ||
241 | /* Check for valid I2C address */ | |
242 | if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) { | |
243 | while (len--) { | |
244 | op_status = | |
ee311214 | 245 | i2c_write_byte (chip_addr, byte_addr++, buffer++); |
b825f158 | 246 | |
247 | if (TSI108_I2C_SUCCESS != op_status) { | |
ee311214 | 248 | DPRINT (("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len)); |
b825f158 | 249 | |
250 | break; | |
251 | } | |
252 | } | |
253 | } | |
254 | ||
255 | return op_status; | |
256 | } | |
257 | ||
ee311214 | 258 | /* |
b825f158 | 259 | * I2C interface function as defined in "include/i2c.h". |
260 | * Probe the given I2C chip address by reading single byte from offset 0. | |
261 | * Returns 0 if a chip responded, not 0 on failure. | |
262 | */ | |
263 | ||
ee311214 | 264 | int i2c_probe (uchar chip) |
b825f158 | 265 | { |
266 | u32 tmp; | |
267 | ||
268 | /* | |
269 | * Try to read the first location of the chip. | |
270 | * The Tsi108 HW doesn't support sending just the chip address | |
271 | * and checkong for an <ACK> back. | |
272 | */ | |
409ecdc0 | 273 | return i2c_read (chip, 0, 1, (uchar *)&tmp, 1); |
b825f158 | 274 | } |
275 | ||
cb51c0bf | 276 | #endif |