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