]>
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 | 13 | * |
1a459660 | 14 | * SPDX-License-Identifier: GPL-2.0+ |
cdace066 SH |
15 | */ |
16 | ||
17 | #include <common.h> | |
127cec18 | 18 | #include <asm/arch/clock.h> |
86271115 | 19 | #include <asm/arch/imx-regs.h> |
cea60b0c | 20 | #include <asm/errno.h> |
24cd738b | 21 | #include <asm/io.h> |
bf0783df | 22 | #include <i2c.h> |
7aa57a01 | 23 | #include <watchdog.h> |
cdace066 | 24 | |
db84140b MV |
25 | struct mxc_i2c_regs { |
26 | uint32_t iadr; | |
27 | uint32_t ifdr; | |
28 | uint32_t i2cr; | |
29 | uint32_t i2sr; | |
30 | uint32_t i2dr; | |
31 | }; | |
cdace066 SH |
32 | |
33 | #define I2CR_IEN (1 << 7) | |
34 | #define I2CR_IIEN (1 << 6) | |
35 | #define I2CR_MSTA (1 << 5) | |
36 | #define I2CR_MTX (1 << 4) | |
37 | #define I2CR_TX_NO_AK (1 << 3) | |
38 | #define I2CR_RSTA (1 << 2) | |
39 | ||
40 | #define I2SR_ICF (1 << 7) | |
41 | #define I2SR_IBB (1 << 5) | |
d5383a63 | 42 | #define I2SR_IAL (1 << 4) |
cdace066 SH |
43 | #define I2SR_IIF (1 << 1) |
44 | #define I2SR_RX_NO_AK (1 << 0) | |
45 | ||
e4ff525f | 46 | #if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE) |
de6f604d | 47 | #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" |
cdace066 SH |
48 | #endif |
49 | ||
db84140b MV |
50 | static u16 i2c_clk_div[50][2] = { |
51 | { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, | |
52 | { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, | |
53 | { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, | |
54 | { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, | |
55 | { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, | |
56 | { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, | |
57 | { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, | |
58 | { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, | |
59 | { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, | |
60 | { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, | |
61 | { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, | |
62 | { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, | |
63 | { 3072, 0x1E }, { 3840, 0x1F } | |
64 | }; | |
65 | ||
db84140b MV |
66 | /* |
67 | * Calculate and set proper clock divider | |
68 | */ | |
bf0783df | 69 | static uint8_t i2c_imx_get_clk(unsigned int rate) |
cdace066 | 70 | { |
db84140b MV |
71 | unsigned int i2c_clk_rate; |
72 | unsigned int div; | |
bf0783df | 73 | u8 clk_div; |
cdace066 | 74 | |
127cec18 | 75 | #if defined(CONFIG_MX31) |
1d549ade SB |
76 | struct clock_control_regs *sc_regs = |
77 | (struct clock_control_regs *)CCM_BASE; | |
db84140b | 78 | |
e7de18af | 79 | /* start the required I2C clock */ |
de6f604d | 80 | writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET), |
1d549ade | 81 | &sc_regs->cgr0); |
127cec18 | 82 | #endif |
e7de18af | 83 | |
db84140b | 84 | /* Divider value calculation */ |
e7bed5c2 | 85 | i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK); |
db84140b MV |
86 | div = (i2c_clk_rate + rate - 1) / rate; |
87 | if (div < i2c_clk_div[0][0]) | |
b567b8ff | 88 | clk_div = 0; |
db84140b | 89 | else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) |
b567b8ff | 90 | clk_div = ARRAY_SIZE(i2c_clk_div) - 1; |
db84140b | 91 | else |
b567b8ff | 92 | for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++) |
db84140b MV |
93 | ; |
94 | ||
95 | /* Store divider value */ | |
bf0783df | 96 | return clk_div; |
db84140b | 97 | } |
cdace066 | 98 | |
db84140b | 99 | /* |
e4ff525f | 100 | * Set I2C Bus speed |
db84140b | 101 | */ |
7f86bd57 | 102 | static int bus_i2c_set_bus_speed(void *base, int speed) |
db84140b | 103 | { |
e4ff525f | 104 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; |
bf0783df MV |
105 | u8 clk_idx = i2c_imx_get_clk(speed); |
106 | u8 idx = i2c_clk_div[clk_idx][1]; | |
107 | ||
108 | /* Store divider value */ | |
109 | writeb(idx, &i2c_regs->ifdr); | |
110 | ||
83a1a190 TK |
111 | /* Reset module */ |
112 | writeb(0, &i2c_regs->i2cr); | |
113 | writeb(0, &i2c_regs->i2sr); | |
b567b8ff MV |
114 | return 0; |
115 | } | |
116 | ||
117 | /* | |
118 | * Get I2C Speed | |
119 | */ | |
7f86bd57 | 120 | static unsigned int bus_i2c_get_bus_speed(void *base) |
b567b8ff | 121 | { |
e4ff525f | 122 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; |
bf0783df MV |
123 | u8 clk_idx = readb(&i2c_regs->ifdr); |
124 | u8 clk_div; | |
125 | ||
126 | for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++) | |
127 | ; | |
128 | ||
e7bed5c2 | 129 | return mxc_get_clock(MXC_I2C_CLK) / i2c_clk_div[clk_div][0]; |
b567b8ff MV |
130 | } |
131 | ||
7aa57a01 TK |
132 | #define ST_BUS_IDLE (0 | (I2SR_IBB << 8)) |
133 | #define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8)) | |
134 | #define ST_IIF (I2SR_IIF | (I2SR_IIF << 8)) | |
81687212 | 135 | |
7aa57a01 | 136 | static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state) |
cdace066 | 137 | { |
7aa57a01 TK |
138 | unsigned sr; |
139 | ulong elapsed; | |
140 | ulong start_time = get_timer(0); | |
141 | for (;;) { | |
142 | sr = readb(&i2c_regs->i2sr); | |
d5383a63 TK |
143 | if (sr & I2SR_IAL) { |
144 | writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr); | |
145 | printf("%s: Arbitration lost sr=%x cr=%x state=%x\n", | |
146 | __func__, sr, readb(&i2c_regs->i2cr), state); | |
147 | return -ERESTART; | |
148 | } | |
7aa57a01 TK |
149 | if ((sr & (state >> 8)) == (unsigned char)state) |
150 | return sr; | |
151 | WATCHDOG_RESET(); | |
152 | elapsed = get_timer(start_time); | |
153 | if (elapsed > (CONFIG_SYS_HZ / 10)) /* .1 seconds */ | |
154 | break; | |
db84140b | 155 | } |
7aa57a01 TK |
156 | printf("%s: failed sr=%x cr=%x state=%x\n", __func__, |
157 | sr, readb(&i2c_regs->i2cr), state); | |
cea60b0c | 158 | return -ETIMEDOUT; |
cdace066 SH |
159 | } |
160 | ||
cea60b0c | 161 | static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) |
81687212 | 162 | { |
cea60b0c | 163 | int ret; |
81687212 | 164 | |
ea572d85 | 165 | writeb(0, &i2c_regs->i2sr); |
cea60b0c | 166 | writeb(byte, &i2c_regs->i2dr); |
7aa57a01 | 167 | ret = wait_for_sr_state(i2c_regs, ST_IIF); |
cea60b0c TK |
168 | if (ret < 0) |
169 | return ret; | |
cea60b0c TK |
170 | if (ret & I2SR_RX_NO_AK) |
171 | return -ENODEV; | |
172 | return 0; | |
db84140b | 173 | } |
81687212 | 174 | |
db84140b | 175 | /* |
90a5b70f | 176 | * Stop I2C transaction |
db84140b | 177 | */ |
27a5da02 | 178 | static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs) |
cdace066 | 179 | { |
7aa57a01 | 180 | int ret; |
90a5b70f | 181 | unsigned int temp = readb(&i2c_regs->i2cr); |
db84140b | 182 | |
1c076dba | 183 | temp &= ~(I2CR_MSTA | I2CR_MTX); |
db84140b | 184 | writeb(temp, &i2c_regs->i2cr); |
7aa57a01 TK |
185 | ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); |
186 | if (ret < 0) | |
187 | printf("%s:trigger stop failed\n", __func__); | |
cdace066 SH |
188 | } |
189 | ||
db84140b | 190 | /* |
b230ddc2 TK |
191 | * Send start signal, chip address and |
192 | * write register address | |
db84140b | 193 | */ |
a7f1a005 | 194 | static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, |
b230ddc2 | 195 | uchar chip, uint addr, int alen) |
cdace066 | 196 | { |
71e9f3cb TK |
197 | unsigned int temp; |
198 | int ret; | |
199 | ||
200 | /* Enable I2C controller */ | |
90a5b70f TK |
201 | if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) { |
202 | writeb(I2CR_IEN, &i2c_regs->i2cr); | |
203 | /* Wait for controller to be stable */ | |
204 | udelay(50); | |
205 | } | |
ca741da1 TK |
206 | if (readb(&i2c_regs->iadr) == (chip << 1)) |
207 | writeb((chip << 1) ^ 2, &i2c_regs->iadr); | |
71e9f3cb | 208 | writeb(0, &i2c_regs->i2sr); |
90a5b70f TK |
209 | ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); |
210 | if (ret < 0) | |
a7f1a005 | 211 | return ret; |
71e9f3cb TK |
212 | |
213 | /* Start I2C transaction */ | |
214 | temp = readb(&i2c_regs->i2cr); | |
215 | temp |= I2CR_MSTA; | |
216 | writeb(temp, &i2c_regs->i2cr); | |
217 | ||
218 | ret = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); | |
219 | if (ret < 0) | |
a7f1a005 | 220 | return ret; |
b230ddc2 | 221 | |
71e9f3cb TK |
222 | temp |= I2CR_MTX | I2CR_TX_NO_AK; |
223 | writeb(temp, &i2c_regs->i2cr); | |
224 | ||
b230ddc2 TK |
225 | /* write slave address */ |
226 | ret = tx_byte(i2c_regs, chip << 1); | |
227 | if (ret < 0) | |
a7f1a005 | 228 | return ret; |
db84140b | 229 | |
bf0783df | 230 | while (alen--) { |
cea60b0c TK |
231 | ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff); |
232 | if (ret < 0) | |
a7f1a005 | 233 | return ret; |
81687212 | 234 | } |
b230ddc2 | 235 | return 0; |
a7f1a005 TK |
236 | } |
237 | ||
96c19bd3 TK |
238 | static int i2c_idle_bus(void *base); |
239 | ||
a7f1a005 TK |
240 | static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, |
241 | uchar chip, uint addr, int alen) | |
242 | { | |
243 | int retry; | |
244 | int ret; | |
245 | for (retry = 0; retry < 3; retry++) { | |
246 | ret = i2c_init_transfer_(i2c_regs, chip, addr, alen); | |
247 | if (ret >= 0) | |
248 | return 0; | |
27a5da02 | 249 | i2c_imx_stop(i2c_regs); |
a7f1a005 TK |
250 | if (ret == -ENODEV) |
251 | return ret; | |
252 | ||
253 | printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip, | |
254 | retry); | |
255 | if (ret != -ERESTART) | |
256 | writeb(0, &i2c_regs->i2cr); /* Disable controller */ | |
257 | udelay(100); | |
96c19bd3 TK |
258 | if (i2c_idle_bus(i2c_regs) < 0) |
259 | break; | |
a7f1a005 TK |
260 | } |
261 | printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs); | |
db84140b | 262 | return ret; |
cdace066 SH |
263 | } |
264 | ||
db84140b MV |
265 | /* |
266 | * Read data from I2C device | |
267 | */ | |
e4ff525f TK |
268 | int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, |
269 | int len) | |
db84140b | 270 | { |
db84140b MV |
271 | int ret; |
272 | unsigned int temp; | |
273 | int i; | |
e4ff525f | 274 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; |
cdace066 | 275 | |
b230ddc2 | 276 | ret = i2c_init_transfer(i2c_regs, chip, addr, alen); |
cea60b0c | 277 | if (ret < 0) |
db84140b MV |
278 | return ret; |
279 | ||
db84140b MV |
280 | temp = readb(&i2c_regs->i2cr); |
281 | temp |= I2CR_RSTA; | |
282 | writeb(temp, &i2c_regs->i2cr); | |
283 | ||
cea60b0c | 284 | ret = tx_byte(i2c_regs, (chip << 1) | 1); |
c4330d28 | 285 | if (ret < 0) { |
27a5da02 | 286 | i2c_imx_stop(i2c_regs); |
db84140b | 287 | return ret; |
c4330d28 | 288 | } |
db84140b MV |
289 | |
290 | /* setup bus to read data */ | |
291 | temp = readb(&i2c_regs->i2cr); | |
292 | temp &= ~(I2CR_MTX | I2CR_TX_NO_AK); | |
293 | if (len == 1) | |
294 | temp |= I2CR_TX_NO_AK; | |
295 | writeb(temp, &i2c_regs->i2cr); | |
ea572d85 TK |
296 | writeb(0, &i2c_regs->i2sr); |
297 | readb(&i2c_regs->i2dr); /* dummy read to clear ICF */ | |
db84140b MV |
298 | |
299 | /* read data */ | |
300 | for (i = 0; i < len; i++) { | |
7aa57a01 TK |
301 | ret = wait_for_sr_state(i2c_regs, ST_IIF); |
302 | if (ret < 0) { | |
27a5da02 | 303 | i2c_imx_stop(i2c_regs); |
db84140b | 304 | return ret; |
c4330d28 | 305 | } |
db84140b MV |
306 | |
307 | /* | |
308 | * It must generate STOP before read I2DR to prevent | |
309 | * controller from generating another clock cycle | |
310 | */ | |
311 | if (i == (len - 1)) { | |
27a5da02 | 312 | i2c_imx_stop(i2c_regs); |
db84140b MV |
313 | } else if (i == (len - 2)) { |
314 | temp = readb(&i2c_regs->i2cr); | |
315 | temp |= I2CR_TX_NO_AK; | |
316 | writeb(temp, &i2c_regs->i2cr); | |
317 | } | |
ea572d85 | 318 | writeb(0, &i2c_regs->i2sr); |
db84140b | 319 | buf[i] = readb(&i2c_regs->i2dr); |
cdace066 | 320 | } |
27a5da02 | 321 | i2c_imx_stop(i2c_regs); |
7aa57a01 | 322 | return 0; |
cdace066 SH |
323 | } |
324 | ||
db84140b MV |
325 | /* |
326 | * Write data to I2C device | |
327 | */ | |
e4ff525f TK |
328 | int bus_i2c_write(void *base, uchar chip, uint addr, int alen, |
329 | const uchar *buf, int len) | |
cdace066 | 330 | { |
db84140b MV |
331 | int ret; |
332 | int i; | |
e4ff525f | 333 | struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; |
cdace066 | 334 | |
b230ddc2 | 335 | ret = i2c_init_transfer(i2c_regs, chip, addr, alen); |
cea60b0c | 336 | if (ret < 0) |
db84140b | 337 | return ret; |
cdace066 | 338 | |
db84140b | 339 | for (i = 0; i < len; i++) { |
cea60b0c TK |
340 | ret = tx_byte(i2c_regs, buf[i]); |
341 | if (ret < 0) | |
c4330d28 | 342 | break; |
db84140b | 343 | } |
27a5da02 | 344 | i2c_imx_stop(i2c_regs); |
db84140b MV |
345 | return ret; |
346 | } | |
cfbb88d3 | 347 | |
e4ff525f TK |
348 | struct i2c_parms { |
349 | void *base; | |
350 | void *idle_bus_data; | |
351 | int (*idle_bus_fn)(void *p); | |
352 | }; | |
353 | ||
354 | struct sram_data { | |
355 | unsigned curr_i2c_bus; | |
356 | struct i2c_parms i2c_data[3]; | |
357 | }; | |
358 | ||
359 | /* | |
360 | * For SPL boot some boards need i2c before SDRAM is initialized so force | |
361 | * variables to live in SRAM | |
362 | */ | |
363 | static struct sram_data __attribute__((section(".data"))) srdata; | |
364 | ||
365 | void *get_base(void) | |
366 | { | |
367 | #ifdef CONFIG_SYS_I2C_BASE | |
368 | #ifdef CONFIG_I2C_MULTI_BUS | |
369 | void *ret = srdata.i2c_data[srdata.curr_i2c_bus].base; | |
370 | if (ret) | |
371 | return ret; | |
372 | #endif | |
373 | return (void *)CONFIG_SYS_I2C_BASE; | |
374 | #elif defined(CONFIG_I2C_MULTI_BUS) | |
375 | return srdata.i2c_data[srdata.curr_i2c_bus].base; | |
376 | #else | |
377 | return srdata.i2c_data[0].base; | |
378 | #endif | |
379 | } | |
380 | ||
96c19bd3 TK |
381 | static struct i2c_parms *i2c_get_parms(void *base) |
382 | { | |
383 | int i = 0; | |
384 | struct i2c_parms *p = srdata.i2c_data; | |
385 | while (i < ARRAY_SIZE(srdata.i2c_data)) { | |
386 | if (p->base == base) | |
387 | return p; | |
388 | p++; | |
389 | i++; | |
390 | } | |
391 | printf("Invalid I2C base: %p\n", base); | |
392 | return NULL; | |
393 | } | |
394 | ||
395 | static int i2c_idle_bus(void *base) | |
396 | { | |
397 | struct i2c_parms *p = i2c_get_parms(base); | |
398 | if (p && p->idle_bus_fn) | |
399 | return p->idle_bus_fn(p->idle_bus_data); | |
400 | return 0; | |
401 | } | |
402 | ||
9815326d TK |
403 | #ifdef CONFIG_I2C_MULTI_BUS |
404 | unsigned int i2c_get_bus_num(void) | |
405 | { | |
406 | return srdata.curr_i2c_bus; | |
407 | } | |
408 | ||
409 | int i2c_set_bus_num(unsigned bus_idx) | |
410 | { | |
411 | if (bus_idx >= ARRAY_SIZE(srdata.i2c_data)) | |
412 | return -1; | |
413 | if (!srdata.i2c_data[bus_idx].base) | |
414 | return -1; | |
415 | srdata.curr_i2c_bus = bus_idx; | |
416 | return 0; | |
417 | } | |
418 | #endif | |
419 | ||
e4ff525f TK |
420 | int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) |
421 | { | |
422 | return bus_i2c_read(get_base(), chip, addr, alen, buf, len); | |
423 | } | |
424 | ||
425 | int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) | |
426 | { | |
427 | return bus_i2c_write(get_base(), chip, addr, alen, buf, len); | |
428 | } | |
429 | ||
cfbb88d3 TK |
430 | /* |
431 | * Test if a chip at a given address responds (probe the chip) | |
432 | */ | |
433 | int i2c_probe(uchar chip) | |
434 | { | |
e4ff525f TK |
435 | return bus_i2c_write(get_base(), chip, 0, 0, NULL, 0); |
436 | } | |
437 | ||
438 | void bus_i2c_init(void *base, int speed, int unused, | |
439 | int (*idle_bus_fn)(void *p), void *idle_bus_data) | |
440 | { | |
441 | int i = 0; | |
442 | struct i2c_parms *p = srdata.i2c_data; | |
443 | if (!base) | |
444 | return; | |
445 | for (;;) { | |
446 | if (!p->base || (p->base == base)) { | |
447 | p->base = base; | |
448 | if (idle_bus_fn) { | |
449 | p->idle_bus_fn = idle_bus_fn; | |
450 | p->idle_bus_data = idle_bus_data; | |
451 | } | |
452 | break; | |
453 | } | |
454 | p++; | |
455 | i++; | |
456 | if (i >= ARRAY_SIZE(srdata.i2c_data)) | |
457 | return; | |
458 | } | |
459 | bus_i2c_set_bus_speed(base, speed); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Init I2C Bus | |
464 | */ | |
465 | void i2c_init(int speed, int unused) | |
466 | { | |
467 | bus_i2c_init(get_base(), speed, unused, NULL, NULL); | |
468 | } | |
469 | ||
470 | /* | |
471 | * Set I2C Speed | |
472 | */ | |
473 | int i2c_set_bus_speed(unsigned int speed) | |
474 | { | |
475 | return bus_i2c_set_bus_speed(get_base(), speed); | |
476 | } | |
477 | ||
478 | /* | |
479 | * Get I2C Speed | |
480 | */ | |
481 | unsigned int i2c_get_bus_speed(void) | |
482 | { | |
483 | return bus_i2c_get_bus_speed(get_base()); | |
cfbb88d3 | 484 | } |