Solve the copyright conflicts when merging 'master' into hpc2.
[oweals/u-boot.git] / drivers / tsi108_i2c.c
1 /*
2  * (C) Copyright 2004 Tundra Semiconductor Corp.
3  * Author: Alex Bounine
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  *
23  */
24
25 #include <config.h>
26
27 #ifdef CONFIG_TSI108_I2C
28
29 #include <common.h>
30 #include <tsi108.h>
31
32 #if (CONFIG_COMMANDS & CFG_CMD_I2C)
33
34 #define I2C_DELAY           100000
35 #undef  DEBUG_I2C
36
37 #ifdef DEBUG_I2C
38 #define DPRINT(x) printf(x)
39 #else
40 #define DPRINT(x)
41 #endif
42
43 /* All functions assume that Tsi108 I2C block is the only master on the bus */
44 /* I2C read helper function */
45
46 static int i2c_read_byte(
47                 uint i2c_chan,  /* I2C channel number: 0 - main, 1 - SDC SPD */
48                 uchar chip_addr,/* I2C device address on the bus */
49                 uint byte_addr, /* Byte address within I2C device */
50                 uchar * buffer  /* pointer to data buffer */
51                 )
52 {
53         u32 temp;
54         u32 to_count = I2C_DELAY;
55         u32 op_status = TSI108_I2C_TIMEOUT_ERR;
56         u32 chan_offset = TSI108_I2C_OFFSET;
57
58         DPRINT(("I2C read_byte() %d 0x%02x 0x%02x\n",
59                 i2c_chan, chip_addr, byte_addr));
60
61         if (0 != i2c_chan) {
62                 chan_offset = TSI108_I2C_SDRAM_OFFSET;
63         }
64
65         /* Check if I2C operation is in progress */
66         temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
67
68         if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS |
69                           I2C_CNTRL2_START))
70             ) {
71                 /* Set device address and operation (read = 0) */
72                 temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) |
73                     ((chip_addr >> 3) & 0x0F);
74                 *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
75                     temp;
76
77                 /* Issue the read command
78                  * (at this moment all other parameters are 0 
79                  * (size = 1 byte, lane = 0)
80                  */
81
82                 *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
83                     (I2C_CNTRL2_START);
84
85                 /* Wait until operation completed */
86                 do {
87                         /* Read I2C operation status */
88                         temp =
89                             *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset +
90                                       I2C_CNTRL2);
91
92                         if (0 ==
93                             (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START)))
94                         {
95                                 if (0 ==
96                                     (temp &
97                                      (I2C_CNTRL2_I2C_CFGERR |
98                                       I2C_CNTRL2_I2C_TO_ERR))
99                                     ) {
100                                         op_status = TSI108_I2C_SUCCESS;
101
102                                         temp = *(u32 *) (CFG_TSI108_CSR_BASE +
103                                                          chan_offset +
104                                                          I2C_RD_DATA);
105
106                                         *buffer = (u8) (temp & 0xFF);
107                                 } else {
108                                         /* report HW error */
109                                         op_status = TSI108_I2C_IF_ERROR;
110
111                                         DPRINT(("I2C HW error reported: 0x%02x\n", temp));
112                                 }
113
114                                 break;
115                         }
116                 } while (to_count--);
117         } else {
118                 op_status = TSI108_I2C_IF_BUSY;
119
120                 DPRINT(("I2C Transaction start failed: 0x%02x\n", temp));
121         }
122
123         DPRINT(("I2C read_byte() status: 0x%02x\n", op_status));
124         return op_status;
125 }
126
127 /* 
128  * I2C Read interface as defined in "include/i2c.h" :
129  *   chip_addr: I2C chip address, range 0..127
130  *                  (to read from SPD channel EEPROM use (0xD0 ... 0xD7)
131  *              NOTE: The bit 7 in the chip_addr serves as a channel select.
132  *              This hack is for enabling "isdram" command on Tsi108 boards
133  *              without changes to common code. Used for I2C reads only. 
134  *   byte_addr: Memory or register address within the chip
135  *   alen:      Number of bytes to use for addr (typically 1, 2 for larger
136  *              memories, 0 for register type devices with only one
137  *              register)
138  *   buffer:    Pointer to destination buffer for data to be read
139  *   len:       How many bytes to read
140  *
141  *   Returns: 0 on success, not 0 on failure
142  */
143
144 int i2c_read(uchar chip_addr, uint byte_addr, int alen, uchar * buffer, int len)
145 {
146         u32 op_status = TSI108_I2C_PARAM_ERR;
147         u32 i2c_if = 0;
148
149         /* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/
150         if (0xD0 == (chip_addr & ~0x07)) {
151                 i2c_if = 1;
152                 chip_addr &= 0x7F;
153         }
154         /* Check for valid I2C address */
155         if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
156                 while (len--) {
157                         op_status =
158                             i2c_read_byte(i2c_if, chip_addr, byte_addr++,
159                                           buffer++);
160
161                         if (TSI108_I2C_SUCCESS != op_status) {
162                                 DPRINT(("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len));
163
164                                 break;
165                         }
166                 }
167         }
168
169         DPRINT(("I2C read() status: 0x%02x\n", op_status));
170         return op_status;
171 }
172
173 /* I2C write helper function */
174
175 static int i2c_write_byte(uchar chip_addr,/* I2C device address on the bus */
176                           uint byte_addr, /* Byte address within I2C device */
177                           uchar * buffer  /*  pointer to data buffer */
178                           )
179 {
180         u32 temp;
181         u32 to_count = I2C_DELAY;
182         u32 op_status = TSI108_I2C_TIMEOUT_ERR;
183
184         /* Check if I2C operation is in progress */
185         temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
186
187         if (0 ==
188             (temp &
189              (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START)))
190         {
191                 /* Place data into the I2C Tx Register */
192                 *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
193                           I2C_TX_DATA) = (u32) * buffer;
194
195                 /* Set device address and operation  */
196                 temp =
197                     I2C_CNTRL1_I2CWRITE | (byte_addr << 16) |
198                     ((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F);
199                 *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
200                           I2C_CNTRL1) = temp;
201
202                 /* Issue the write command (at this moment all other parameters
203                  * are 0 (size = 1 byte, lane = 0)
204                  */
205                 
206                 *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
207                           I2C_CNTRL2) = (I2C_CNTRL2_START);
208
209                 op_status = TSI108_I2C_TIMEOUT_ERR;
210
211                 /* Wait until operation completed */
212                 do {
213                         // Read I2C operation status
214                         temp =
215                             *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
216                                       I2C_CNTRL2);
217
218                         if (0 ==
219                             (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START)))
220                         {
221                                 if (0 ==
222                                     (temp &
223                                      (I2C_CNTRL2_I2C_CFGERR |
224                                       I2C_CNTRL2_I2C_TO_ERR))) {
225                                         op_status = TSI108_I2C_SUCCESS;
226                                 } else {
227                                         /* report detected HW error */
228                                         op_status = TSI108_I2C_IF_ERROR;
229
230                                         DPRINT(("I2C HW error reported: 0x%02x\n", temp));
231                                 }
232
233                                 break;
234                         }
235
236                 } while (to_count--);
237         } else {
238                 op_status = TSI108_I2C_IF_BUSY;
239
240                 DPRINT(("I2C Transaction start failed: 0x%02x\n", temp));
241         }
242
243         return op_status;
244 }
245
246 /* 
247  * I2C Write interface as defined in "include/i2c.h" :
248  *   chip_addr: I2C chip address, range 0..127
249  *   byte_addr: Memory or register address within the chip
250  *   alen:      Number of bytes to use for addr (typically 1, 2 for larger
251  *              memories, 0 for register type devices with only one
252  *              register)
253  *   buffer:    Pointer to data to be written
254  *   len:       How many bytes to write
255  *
256  *   Returns: 0 on success, not 0 on failure
257  */
258
259 int i2c_write(uchar chip_addr, uint byte_addr, int alen, uchar * buffer,
260               int len)
261 {
262         u32 op_status = TSI108_I2C_PARAM_ERR;
263
264         /* Check for valid I2C address */
265         if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
266                 while (len--) {
267                         op_status =
268                             i2c_write_byte(chip_addr, byte_addr++, buffer++);
269
270                         if (TSI108_I2C_SUCCESS != op_status) {
271                                 DPRINT(("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len));
272
273                                 break;
274                         }
275                 }
276         }
277
278         return op_status;
279 }
280
281 /* 
282  * I2C interface function as defined in "include/i2c.h".
283  * Probe the given I2C chip address by reading single byte from offset 0.
284  * Returns 0 if a chip responded, not 0 on failure.
285  */
286
287 int i2c_probe(uchar chip)
288 {
289         u32 tmp;
290
291         /*
292          * Try to read the first location of the chip.
293          * The Tsi108 HW doesn't support sending just the chip address
294          * and checkong for an <ACK> back.
295          */
296         return i2c_read(chip, 0, 1, (char *)&tmp, 1);
297 }
298
299 #endif                          /* (CONFIG_COMMANDS & CFG_CMD_I2C) */
300 #endif /* CONFIG_TSI108_I2C */