]>
Commit | Line | Data |
---|---|---|
cdace066 | 1 | /* |
db84140b | 2 | * i2c driver for Freescale i.MX series |
cdace066 SH |
3 | * |
4 | * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | |
db84140b MV |
5 | * (c) 2011 Marek Vasut <marek.vasut@gmail.com> |
6 | * | |
7 | * Based on i2c-imx.c from linux kernel: | |
8 | * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de> | |
9 | * Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de> | |
10 | * Copyright (C) 2007 RightHand Technologies, Inc. | |
11 | * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> | |
12 | * | |
cdace066 SH |
13 | * |
14 | * See file CREDITS for list of people who contributed to this | |
15 | * project. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or | |
18 | * modify it under the terms of the GNU General Public License as | |
19 | * published by the Free Software Foundation; either version 2 of | |
20 | * the License, or (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, | |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
30 | * MA 02111-1307 USA | |
31 | */ | |
32 | ||
33 | #include <common.h> | |
1d549ade | 34 | #include <asm/io.h> |
cdace066 | 35 | |
a4a549b4 | 36 | #if defined(CONFIG_HARD_I2C) |
cdace066 | 37 | |
127cec18 | 38 | #include <asm/arch/clock.h> |
86271115 | 39 | #include <asm/arch/imx-regs.h> |
bf0783df | 40 | #include <i2c.h> |
cdace066 | 41 | |
db84140b MV |
42 | struct mxc_i2c_regs { |
43 | uint32_t iadr; | |
44 | uint32_t ifdr; | |
45 | uint32_t i2cr; | |
46 | uint32_t i2sr; | |
47 | uint32_t i2dr; | |
48 | }; | |
cdace066 SH |
49 | |
50 | #define I2CR_IEN (1 << 7) | |
51 | #define I2CR_IIEN (1 << 6) | |
52 | #define I2CR_MSTA (1 << 5) | |
53 | #define I2CR_MTX (1 << 4) | |
54 | #define I2CR_TX_NO_AK (1 << 3) | |
55 | #define I2CR_RSTA (1 << 2) | |
56 | ||
57 | #define I2SR_ICF (1 << 7) | |
58 | #define I2SR_IBB (1 << 5) | |
59 | #define I2SR_IIF (1 << 1) | |
60 | #define I2SR_RX_NO_AK (1 << 0) | |
61 | ||
de6f604d TK |
62 | #ifdef CONFIG_SYS_I2C_BASE |
63 | #define I2C_BASE CONFIG_SYS_I2C_BASE | |
cdace066 | 64 | #else |
de6f604d | 65 | #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" |
cdace066 SH |
66 | #endif |
67 | ||
81687212 | 68 | #define I2C_MAX_TIMEOUT 10000 |
cdace066 | 69 | |
db84140b MV |
70 | static u16 i2c_clk_div[50][2] = { |
71 | { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, | |
72 | { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, | |
73 | { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, | |
74 | { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, | |
75 | { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, | |
76 | { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, | |
77 | { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, | |
78 | { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, | |
79 | { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, | |
80 | { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, | |
81 | { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, | |
82 | { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, | |
83 | { 3072, 0x1E }, { 3840, 0x1F } | |
84 | }; | |
85 | ||
db84140b MV |
86 | /* |
87 | * Calculate and set proper clock divider | |
88 | */ | |
bf0783df | 89 | static uint8_t i2c_imx_get_clk(unsigned int rate) |
cdace066 | 90 | { |
db84140b MV |
91 | unsigned int i2c_clk_rate; |
92 | unsigned int div; | |
bf0783df | 93 | u8 clk_div; |
cdace066 | 94 | |
127cec18 | 95 | #if defined(CONFIG_MX31) |
1d549ade SB |
96 | struct clock_control_regs *sc_regs = |
97 | (struct clock_control_regs *)CCM_BASE; | |
db84140b | 98 | |
e7de18af | 99 | /* start the required I2C clock */ |
de6f604d | 100 | writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET), |
1d549ade | 101 | &sc_regs->cgr0); |
127cec18 | 102 | #endif |
e7de18af | 103 | |
db84140b MV |
104 | /* Divider value calculation */ |
105 | i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK); | |
106 | div = (i2c_clk_rate + rate - 1) / rate; | |
107 | if (div < i2c_clk_div[0][0]) | |
b567b8ff | 108 | clk_div = 0; |
db84140b | 109 | else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) |
b567b8ff | 110 | clk_div = ARRAY_SIZE(i2c_clk_div) - 1; |
db84140b | 111 | else |
b567b8ff | 112 | for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++) |
db84140b MV |
113 | ; |
114 | ||
115 | /* Store divider value */ | |
bf0783df | 116 | return clk_div; |
db84140b | 117 | } |
cdace066 | 118 | |
db84140b MV |
119 | /* |
120 | * Reset I2C Controller | |
121 | */ | |
122 | void i2c_reset(void) | |
123 | { | |
124 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; | |
125 | ||
126 | writeb(0, &i2c_regs->i2cr); /* Reset module */ | |
127 | writeb(0, &i2c_regs->i2sr); | |
128 | } | |
cdace066 | 129 | |
db84140b MV |
130 | /* |
131 | * Init I2C Bus | |
132 | */ | |
133 | void i2c_init(int speed, int unused) | |
134 | { | |
bf0783df MV |
135 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
136 | u8 clk_idx = i2c_imx_get_clk(speed); | |
137 | u8 idx = i2c_clk_div[clk_idx][1]; | |
138 | ||
139 | /* Store divider value */ | |
140 | writeb(idx, &i2c_regs->ifdr); | |
141 | ||
1d549ade | 142 | i2c_reset(); |
cdace066 SH |
143 | } |
144 | ||
b567b8ff MV |
145 | /* |
146 | * Set I2C Speed | |
147 | */ | |
148 | int i2c_set_bus_speed(unsigned int speed) | |
149 | { | |
150 | i2c_init(speed, 0); | |
151 | return 0; | |
152 | } | |
153 | ||
154 | /* | |
155 | * Get I2C Speed | |
156 | */ | |
157 | unsigned int i2c_get_bus_speed(void) | |
158 | { | |
bf0783df MV |
159 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
160 | u8 clk_idx = readb(&i2c_regs->ifdr); | |
161 | u8 clk_div; | |
162 | ||
163 | for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++) | |
164 | ; | |
165 | ||
b567b8ff MV |
166 | return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0]; |
167 | } | |
168 | ||
db84140b MV |
169 | /* |
170 | * Wait for bus to be busy (or free if for_busy = 0) | |
171 | * | |
172 | * for_busy = 1: Wait for IBB to be asserted | |
173 | * for_busy = 0: Wait for IBB to be de-asserted | |
174 | */ | |
175 | int i2c_imx_bus_busy(int for_busy) | |
81687212 | 176 | { |
db84140b MV |
177 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
178 | unsigned int temp; | |
179 | ||
81687212 SB |
180 | int timeout = I2C_MAX_TIMEOUT; |
181 | ||
db84140b MV |
182 | while (timeout--) { |
183 | temp = readb(&i2c_regs->i2sr); | |
184 | ||
185 | if (for_busy && (temp & I2SR_IBB)) | |
186 | return 0; | |
187 | if (!for_busy && !(temp & I2SR_IBB)) | |
188 | return 0; | |
189 | ||
81687212 SB |
190 | udelay(1); |
191 | } | |
db84140b MV |
192 | |
193 | return 1; | |
81687212 SB |
194 | } |
195 | ||
db84140b MV |
196 | /* |
197 | * Wait for transaction to complete | |
198 | */ | |
199 | int i2c_imx_trx_complete(void) | |
cdace066 | 200 | { |
db84140b | 201 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
81687212 | 202 | int timeout = I2C_MAX_TIMEOUT; |
cdace066 | 203 | |
db84140b MV |
204 | while (timeout--) { |
205 | if (readb(&i2c_regs->i2sr) & I2SR_IIF) { | |
206 | writeb(0, &i2c_regs->i2sr); | |
207 | return 0; | |
208 | } | |
209 | ||
cdace066 | 210 | udelay(1); |
db84140b | 211 | } |
cdace066 | 212 | |
db84140b | 213 | return 1; |
cdace066 SH |
214 | } |
215 | ||
db84140b MV |
216 | /* |
217 | * Check if the transaction was ACKed | |
218 | */ | |
219 | int i2c_imx_acked(void) | |
81687212 | 220 | { |
db84140b | 221 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
81687212 | 222 | |
db84140b MV |
223 | return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK; |
224 | } | |
81687212 | 225 | |
db84140b MV |
226 | /* |
227 | * Start the controller | |
228 | */ | |
229 | int i2c_imx_start(void) | |
230 | { | |
231 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; | |
232 | unsigned int temp = 0; | |
233 | int result; | |
81687212 | 234 | |
db84140b MV |
235 | /* Enable I2C controller */ |
236 | writeb(0, &i2c_regs->i2sr); | |
237 | writeb(I2CR_IEN, &i2c_regs->i2cr); | |
81687212 | 238 | |
db84140b MV |
239 | /* Wait controller to be stable */ |
240 | udelay(50); | |
241 | ||
242 | /* Start I2C transaction */ | |
243 | temp = readb(&i2c_regs->i2cr); | |
244 | temp |= I2CR_MSTA; | |
245 | writeb(temp, &i2c_regs->i2cr); | |
246 | ||
247 | result = i2c_imx_bus_busy(1); | |
248 | if (result) | |
249 | return result; | |
250 | ||
251 | temp |= I2CR_MTX | I2CR_TX_NO_AK; | |
252 | writeb(temp, &i2c_regs->i2cr); | |
cdace066 | 253 | |
cdace066 SH |
254 | return 0; |
255 | } | |
256 | ||
db84140b MV |
257 | /* |
258 | * Stop the controller | |
259 | */ | |
260 | void i2c_imx_stop(void) | |
cdace066 | 261 | { |
db84140b MV |
262 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
263 | unsigned int temp = 0; | |
264 | ||
265 | /* Stop I2C transaction */ | |
266 | temp = readb(&i2c_regs->i2cr); | |
267 | temp |= ~(I2CR_MSTA | I2CR_MTX); | |
268 | writeb(temp, &i2c_regs->i2cr); | |
cdace066 | 269 | |
db84140b | 270 | i2c_imx_bus_busy(0); |
81687212 | 271 | |
db84140b MV |
272 | /* Disable I2C controller */ |
273 | writeb(0, &i2c_regs->i2cr); | |
cdace066 SH |
274 | } |
275 | ||
db84140b MV |
276 | /* |
277 | * Set chip address and access mode | |
278 | * | |
279 | * read = 1: READ access | |
280 | * read = 0: WRITE access | |
281 | */ | |
282 | int i2c_imx_set_chip_addr(uchar chip, int read) | |
cdace066 | 283 | { |
db84140b | 284 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
cdace066 SH |
285 | int ret; |
286 | ||
db84140b MV |
287 | writeb((chip << 1) | read, &i2c_regs->i2dr); |
288 | ||
289 | ret = i2c_imx_trx_complete(); | |
290 | if (ret) | |
291 | return ret; | |
cdace066 | 292 | |
db84140b MV |
293 | ret = i2c_imx_acked(); |
294 | if (ret) | |
295 | return ret; | |
cdace066 SH |
296 | |
297 | return ret; | |
298 | } | |
299 | ||
db84140b MV |
300 | /* |
301 | * Write register address | |
302 | */ | |
303 | int i2c_imx_set_reg_addr(uint addr, int alen) | |
cdace066 | 304 | { |
db84140b | 305 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
bf0783df | 306 | int ret = 0; |
db84140b | 307 | |
bf0783df MV |
308 | while (alen--) { |
309 | writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->i2dr); | |
db84140b MV |
310 | |
311 | ret = i2c_imx_trx_complete(); | |
312 | if (ret) | |
81687212 | 313 | break; |
cdace066 | 314 | |
db84140b MV |
315 | ret = i2c_imx_acked(); |
316 | if (ret) | |
317 | break; | |
81687212 | 318 | } |
cdace066 | 319 | |
db84140b | 320 | return ret; |
cdace066 SH |
321 | } |
322 | ||
db84140b MV |
323 | /* |
324 | * Try if a chip add given address responds (probe the chip) | |
325 | */ | |
326 | int i2c_probe(uchar chip) | |
cdace066 | 327 | { |
cdace066 SH |
328 | int ret; |
329 | ||
db84140b MV |
330 | ret = i2c_imx_start(); |
331 | if (ret) | |
332 | return ret; | |
cdace066 | 333 | |
db84140b MV |
334 | ret = i2c_imx_set_chip_addr(chip, 0); |
335 | if (ret) | |
336 | return ret; | |
cdace066 | 337 | |
db84140b | 338 | i2c_imx_stop(); |
cdace066 | 339 | |
db84140b MV |
340 | return ret; |
341 | } | |
cdace066 | 342 | |
db84140b MV |
343 | /* |
344 | * Read data from I2C device | |
345 | */ | |
346 | int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) | |
347 | { | |
348 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; | |
349 | int ret; | |
350 | unsigned int temp; | |
351 | int i; | |
cdace066 | 352 | |
db84140b MV |
353 | ret = i2c_imx_start(); |
354 | if (ret) | |
355 | return ret; | |
356 | ||
357 | /* write slave address */ | |
358 | ret = i2c_imx_set_chip_addr(chip, 0); | |
359 | if (ret) | |
360 | return ret; | |
361 | ||
362 | ret = i2c_imx_set_reg_addr(addr, alen); | |
363 | if (ret) | |
364 | return ret; | |
365 | ||
366 | temp = readb(&i2c_regs->i2cr); | |
367 | temp |= I2CR_RSTA; | |
368 | writeb(temp, &i2c_regs->i2cr); | |
369 | ||
370 | ret = i2c_imx_set_chip_addr(chip, 1); | |
371 | if (ret) | |
372 | return ret; | |
373 | ||
374 | /* setup bus to read data */ | |
375 | temp = readb(&i2c_regs->i2cr); | |
376 | temp &= ~(I2CR_MTX | I2CR_TX_NO_AK); | |
377 | if (len == 1) | |
378 | temp |= I2CR_TX_NO_AK; | |
379 | writeb(temp, &i2c_regs->i2cr); | |
380 | readb(&i2c_regs->i2dr); | |
381 | ||
382 | /* read data */ | |
383 | for (i = 0; i < len; i++) { | |
384 | ret = i2c_imx_trx_complete(); | |
385 | if (ret) | |
386 | return ret; | |
387 | ||
388 | /* | |
389 | * It must generate STOP before read I2DR to prevent | |
390 | * controller from generating another clock cycle | |
391 | */ | |
392 | if (i == (len - 1)) { | |
393 | temp = readb(&i2c_regs->i2cr); | |
394 | temp &= ~(I2CR_MSTA | I2CR_MTX); | |
395 | writeb(temp, &i2c_regs->i2cr); | |
396 | i2c_imx_bus_busy(0); | |
397 | } else if (i == (len - 2)) { | |
398 | temp = readb(&i2c_regs->i2cr); | |
399 | temp |= I2CR_TX_NO_AK; | |
400 | writeb(temp, &i2c_regs->i2cr); | |
401 | } | |
cdace066 | 402 | |
db84140b | 403 | buf[i] = readb(&i2c_regs->i2dr); |
cdace066 SH |
404 | } |
405 | ||
db84140b | 406 | i2c_imx_stop(); |
cdace066 | 407 | |
db84140b | 408 | return ret; |
cdace066 SH |
409 | } |
410 | ||
db84140b MV |
411 | /* |
412 | * Write data to I2C device | |
413 | */ | |
cdace066 SH |
414 | int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) |
415 | { | |
db84140b MV |
416 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; |
417 | int ret; | |
418 | int i; | |
cdace066 | 419 | |
db84140b MV |
420 | ret = i2c_imx_start(); |
421 | if (ret) | |
422 | return ret; | |
cdace066 | 423 | |
db84140b MV |
424 | /* write slave address */ |
425 | ret = i2c_imx_set_chip_addr(chip, 0); | |
426 | if (ret) | |
427 | return ret; | |
cdace066 | 428 | |
db84140b MV |
429 | ret = i2c_imx_set_reg_addr(addr, alen); |
430 | if (ret) | |
431 | return ret; | |
cdace066 | 432 | |
db84140b MV |
433 | for (i = 0; i < len; i++) { |
434 | writeb(buf[i], &i2c_regs->i2dr); | |
cdace066 | 435 | |
db84140b MV |
436 | ret = i2c_imx_trx_complete(); |
437 | if (ret) | |
438 | return ret; | |
439 | ||
440 | ret = i2c_imx_acked(); | |
441 | if (ret) | |
442 | return ret; | |
443 | } | |
cdace066 | 444 | |
db84140b MV |
445 | i2c_imx_stop(); |
446 | ||
447 | return ret; | |
448 | } | |
cdace066 | 449 | #endif /* CONFIG_HARD_I2C */ |