blob: d3521460819526c5d0f917d3ade02f8933a7eb43 [file] [log] [blame]
Vipin KUMAR2403f8f2010-01-15 19:15:44 +05301/*
2 * (C) Copyright 2009
3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
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#include <common.h>
25#include <asm/io.h>
26#include <asm/arch/hardware.h>
Vipin KUMAR031ed2f2012-02-26 23:13:29 +000027#include "designware_i2c.h"
Vipin KUMAR2403f8f2010-01-15 19:15:44 +053028
29static struct i2c_regs *const i2c_regs_p =
30 (struct i2c_regs *)CONFIG_SYS_I2C_BASE;
31
32/*
33 * set_speed - Set the i2c speed mode (standard, high, fast)
34 * @i2c_spd: required i2c speed mode
35 *
36 * Set the i2c speed mode (standard, high, fast)
37 */
38static void set_speed(int i2c_spd)
39{
40 unsigned int cntl;
41 unsigned int hcnt, lcnt;
42 unsigned int high, low;
43
44 cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK));
45
46 switch (i2c_spd) {
47 case IC_SPEED_MODE_MAX:
48 cntl |= IC_CON_SPD_HS;
49 high = MIN_HS_SCL_HIGHTIME;
50 low = MIN_HS_SCL_LOWTIME;
51 break;
52
53 case IC_SPEED_MODE_STANDARD:
54 cntl |= IC_CON_SPD_SS;
55 high = MIN_SS_SCL_HIGHTIME;
56 low = MIN_SS_SCL_LOWTIME;
57 break;
58
59 case IC_SPEED_MODE_FAST:
60 default:
61 cntl |= IC_CON_SPD_FS;
62 high = MIN_FS_SCL_HIGHTIME;
63 low = MIN_FS_SCL_LOWTIME;
64 break;
65 }
66
67 writel(cntl, &i2c_regs_p->ic_con);
68
69 hcnt = (IC_CLK * high) / NANO_TO_MICRO;
70 writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt);
71
72 lcnt = (IC_CLK * low) / NANO_TO_MICRO;
73 writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt);
74}
75
76/*
77 * i2c_set_bus_speed - Set the i2c speed
78 * @speed: required i2c speed
79 *
80 * Set the i2c speed.
81 */
82void i2c_set_bus_speed(int speed)
83{
84 if (speed >= I2C_MAX_SPEED)
85 set_speed(IC_SPEED_MODE_MAX);
86 else if (speed >= I2C_FAST_SPEED)
87 set_speed(IC_SPEED_MODE_FAST);
88 else
89 set_speed(IC_SPEED_MODE_STANDARD);
90}
91
92/*
93 * i2c_get_bus_speed - Gets the i2c speed
94 *
95 * Gets the i2c speed.
96 */
97int i2c_get_bus_speed(void)
98{
99 u32 cntl;
100
101 cntl = (readl(&i2c_regs_p->ic_con) & IC_CON_SPD_MSK);
102
103 if (cntl == IC_CON_SPD_HS)
104 return I2C_MAX_SPEED;
105 else if (cntl == IC_CON_SPD_FS)
106 return I2C_FAST_SPEED;
107 else if (cntl == IC_CON_SPD_SS)
108 return I2C_STANDARD_SPEED;
109
110 return 0;
111}
112
113/*
114 * i2c_init - Init function
115 * @speed: required i2c speed
Vipin KUMAR031ed2f2012-02-26 23:13:29 +0000116 * @slaveadd: slave address for the device
Vipin KUMAR2403f8f2010-01-15 19:15:44 +0530117 *
118 * Initialization function.
119 */
120void i2c_init(int speed, int slaveadd)
121{
122 unsigned int enbl;
123
124 /* Disable i2c */
125 enbl = readl(&i2c_regs_p->ic_enable);
126 enbl &= ~IC_ENABLE_0B;
127 writel(enbl, &i2c_regs_p->ic_enable);
128
129 writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_regs_p->ic_con);
130 writel(IC_RX_TL, &i2c_regs_p->ic_rx_tl);
131 writel(IC_TX_TL, &i2c_regs_p->ic_tx_tl);
132 i2c_set_bus_speed(speed);
133 writel(IC_STOP_DET, &i2c_regs_p->ic_intr_mask);
134 writel(slaveadd, &i2c_regs_p->ic_sar);
135
136 /* Enable i2c */
137 enbl = readl(&i2c_regs_p->ic_enable);
138 enbl |= IC_ENABLE_0B;
139 writel(enbl, &i2c_regs_p->ic_enable);
140}
141
142/*
143 * i2c_setaddress - Sets the target slave address
144 * @i2c_addr: target i2c address
145 *
146 * Sets the target slave address.
147 */
148static void i2c_setaddress(unsigned int i2c_addr)
149{
150 writel(i2c_addr, &i2c_regs_p->ic_tar);
151}
152
153/*
154 * i2c_flush_rxfifo - Flushes the i2c RX FIFO
155 *
156 * Flushes the i2c RX FIFO
157 */
158static void i2c_flush_rxfifo(void)
159{
160 while (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE)
161 readl(&i2c_regs_p->ic_cmd_data);
162}
163
164/*
165 * i2c_wait_for_bb - Waits for bus busy
166 *
167 * Waits for bus busy
168 */
169static int i2c_wait_for_bb(void)
170{
171 unsigned long start_time_bb = get_timer(0);
172
173 while ((readl(&i2c_regs_p->ic_status) & IC_STATUS_MA) ||
174 !(readl(&i2c_regs_p->ic_status) & IC_STATUS_TFE)) {
175
176 /* Evaluate timeout */
177 if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB))
178 return 1;
179 }
180
181 return 0;
182}
183
184/* check parameters for i2c_read and i2c_write */
185static int check_params(uint addr, int alen, uchar *buffer, int len)
186{
187 if (buffer == NULL) {
188 printf("Buffer is invalid\n");
189 return 1;
190 }
191
192 if (alen > 1) {
193 printf("addr len %d not supported\n", alen);
194 return 1;
195 }
196
197 if (addr + len > 256) {
198 printf("address out of range\n");
199 return 1;
200 }
201
202 return 0;
203}
204
205static int i2c_xfer_init(uchar chip, uint addr)
206{
207 if (i2c_wait_for_bb()) {
208 printf("Timed out waiting for bus\n");
209 return 1;
210 }
211
212 i2c_setaddress(chip);
213 writel(addr, &i2c_regs_p->ic_cmd_data);
214
215 return 0;
216}
217
218static int i2c_xfer_finish(void)
219{
220 ulong start_stop_det = get_timer(0);
221
222 while (1) {
223 if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) {
224 readl(&i2c_regs_p->ic_clr_stop_det);
225 break;
226 } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) {
227 break;
228 }
229 }
230
231 if (i2c_wait_for_bb()) {
232 printf("Timed out waiting for bus\n");
233 return 1;
234 }
235
236 i2c_flush_rxfifo();
237
238 /* Wait for read/write operation to complete on actual memory */
239 udelay(10000);
240
241 return 0;
242}
243
244/*
245 * i2c_read - Read from i2c memory
246 * @chip: target i2c address
247 * @addr: address to read from
248 * @alen:
249 * @buffer: buffer for read data
250 * @len: no of bytes to be read
251 *
252 * Read from i2c memory.
253 */
254int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
255{
256 unsigned long start_time_rx;
257
258 if (check_params(addr, alen, buffer, len))
259 return 1;
260
261 if (i2c_xfer_init(chip, addr))
262 return 1;
263
264 start_time_rx = get_timer(0);
265 while (len) {
266 writel(IC_CMD, &i2c_regs_p->ic_cmd_data);
267
268 if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) {
269 *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data);
270 len--;
271 start_time_rx = get_timer(0);
272
273 } else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
274 printf("Timed out. i2c read Failed\n");
275 return 1;
276 }
277 }
278
279 return i2c_xfer_finish();
280}
281
282/*
283 * i2c_write - Write to i2c memory
284 * @chip: target i2c address
285 * @addr: address to read from
286 * @alen:
287 * @buffer: buffer for read data
288 * @len: no of bytes to be read
289 *
290 * Write to i2c memory.
291 */
292int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
293{
294 int nb = len;
295 unsigned long start_time_tx;
296
297 if (check_params(addr, alen, buffer, len))
298 return 1;
299
300 if (i2c_xfer_init(chip, addr))
301 return 1;
302
303 start_time_tx = get_timer(0);
304 while (len) {
305 if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) {
306 writel(*buffer, &i2c_regs_p->ic_cmd_data);
307 buffer++;
308 len--;
309 start_time_tx = get_timer(0);
310
311 } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
312 printf("Timed out. i2c write Failed\n");
313 return 1;
314 }
315 }
316
317 return i2c_xfer_finish();
318}
319
320/*
321 * i2c_probe - Probe the i2c chip
322 */
323int i2c_probe(uchar chip)
324{
325 u32 tmp;
326
327 /*
328 * Try to read the first location of the chip.
329 */
330 return i2c_read(chip, 0, 1, (uchar *)&tmp, 1);
331}