Commit d5243359e1afc957acd373dbbde1cf6c70ee5485

Authored by Hannes Petermaier
Committed by Heiko Schocher
1 parent d22643e7e8

OMAP24xx I2C: Add support for set-speed

Adds support for set-speed on the OMAP24xx I2C Adapter.

Changes to omap24_i2c_write(...) for polling ARDY Bit from IRQ-Status.
Otherwise on a subsequent call the transfer of last byte from the
predecessor is aborted and therefore lost. For exmaple when
i2c_write(...) is followed by a i2c_setspeed(...) (which has to
deactivate and activate master for changing psc,...).

Minor cosmetical changes.

Signed-off-by: Hannes Petermaier <oe5hpm@oevsv.at>
Cc: Heiko Schocher <hs@denx.de>

Showing 2 changed files with 98 additions and 50 deletions Side-by-side Diff

drivers/i2c/omap24xx_i2c.c
... ... @@ -32,6 +32,10 @@
32 32 * - Status functions now read irqstatus_raw as per TRM guidelines
33 33 * (except for OMAP243X and OMAP34XX).
34 34 * - Driver now supports up to I2C5 (OMAP5).
  35 + *
  36 + * Copyright (c) 2014 Hannes Petermaier <oe5hpm@oevsv.at>, B&R
  37 + * - Added support for set_speed
  38 + *
35 39 */
36 40  
37 41 #include <common.h>
38 42  
39 43  
40 44  
41 45  
42 46  
43 47  
44 48  
45 49  
... ... @@ -53,43 +57,66 @@
53 57 static struct i2c *omap24_get_base(struct i2c_adapter *adap);
54 58 static u16 wait_for_event(struct i2c_adapter *adap);
55 59 static void flush_fifo(struct i2c_adapter *adap);
  60 +static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
  61 +{
  62 + unsigned int sampleclk, prescaler;
  63 + int fsscll, fssclh;
56 64  
57   -static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
  65 + speed <<= 1;
  66 + prescaler = 0;
  67 + /*
  68 + * some divisors may cause a precission loss, but shouldn't
  69 + * be a big thing, because i2c_clk is then allready very slow.
  70 + */
  71 + while (prescaler <= 0xFF) {
  72 + sampleclk = I2C_IP_CLK / (prescaler+1);
  73 +
  74 + fsscll = sampleclk / speed;
  75 + fssclh = fsscll;
  76 + fsscll -= I2C_FASTSPEED_SCLL_TRIM;
  77 + fssclh -= I2C_FASTSPEED_SCLH_TRIM;
  78 +
  79 + if (((fsscll > 0) && (fssclh > 0)) &&
  80 + ((fsscll <= (255-I2C_FASTSPEED_SCLL_TRIM)) &&
  81 + (fssclh <= (255-I2C_FASTSPEED_SCLH_TRIM)))) {
  82 + if (pscl)
  83 + *pscl = fsscll;
  84 + if (psch)
  85 + *psch = fssclh;
  86 +
  87 + return prescaler;
  88 + }
  89 + prescaler++;
  90 + }
  91 + return -1;
  92 +}
  93 +static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
58 94 {
59 95 struct i2c *i2c_base = omap24_get_base(adap);
60   - int psc, fsscll, fssclh;
  96 + int psc, fsscll = 0, fssclh = 0;
61 97 int hsscll = 0, hssclh = 0;
62   - u32 scll, sclh;
63   - int timeout = I2C_TIMEOUT;
  98 + u32 scll = 0, sclh = 0;
64 99  
65   - /* Only handle standard, fast and high speeds */
66   - if ((speed != OMAP_I2C_STANDARD) &&
67   - (speed != OMAP_I2C_FAST_MODE) &&
68   - (speed != OMAP_I2C_HIGH_SPEED)) {
69   - printf("Error : I2C unsupported speed %d\n", speed);
70   - return;
71   - }
72   -
73   - psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
74   - psc -= 1;
75   - if (psc < I2C_PSC_MIN) {
76   - printf("Error : I2C unsupported prescalar %d\n", psc);
77   - return;
78   - }
79   -
80   - if (speed == OMAP_I2C_HIGH_SPEED) {
  100 + if (speed >= OMAP_I2C_HIGH_SPEED) {
81 101 /* High speed */
  102 + psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
  103 + psc -= 1;
  104 + if (psc < I2C_PSC_MIN) {
  105 + printf("Error : I2C unsupported prescaler %d\n", psc);
  106 + return -1;
  107 + }
82 108  
83 109 /* For first phase of HS mode */
84   - fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK /
85   - (2 * OMAP_I2C_FAST_MODE);
  110 + fsscll = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
86 111  
  112 + fssclh = fsscll;
  113 +
87 114 fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
88 115 fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
89 116 if (((fsscll < 0) || (fssclh < 0)) ||
90 117 ((fsscll > 255) || (fssclh > 255))) {
91 118 puts("Error : I2C initializing first phase clock\n");
92   - return;
  119 + return -1;
93 120 }
94 121  
95 122 /* For second phase of HS mode */
... ... @@ -100,7 +127,7 @@
100 127 if (((fsscll < 0) || (fssclh < 0)) ||
101 128 ((fsscll > 255) || (fssclh > 255))) {
102 129 puts("Error : I2C initializing second phase clock\n");
103   - return;
  130 + return -1;
104 131 }
105 132  
106 133 scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
107 134  
108 135  
109 136  
... ... @@ -108,20 +135,29 @@
108 135  
109 136 } else {
110 137 /* Standard and fast speed */
111   - fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
112   -
113   - fsscll -= I2C_FASTSPEED_SCLL_TRIM;
114   - fssclh -= I2C_FASTSPEED_SCLH_TRIM;
115   - if (((fsscll < 0) || (fssclh < 0)) ||
116   - ((fsscll > 255) || (fssclh > 255))) {
  138 + psc = omap24_i2c_findpsc(&scll, &sclh, speed);
  139 + if (0 > psc) {
117 140 puts("Error : I2C initializing clock\n");
118   - return;
  141 + return -1;
119 142 }
120   -
121   - scll = (unsigned int)fsscll;
122   - sclh = (unsigned int)fssclh;
123 143 }
124 144  
  145 + adap->speed = speed;
  146 + adap->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */
  147 + writew(0, &i2c_base->con);
  148 + writew(psc, &i2c_base->psc);
  149 + writew(scll, &i2c_base->scll);
  150 + writew(sclh, &i2c_base->sclh);
  151 + writew(I2C_CON_EN, &i2c_base->con);
  152 + writew(0xFFFF, &i2c_base->stat); /* clear all pending status */
  153 +
  154 + return 0;
  155 +}
  156 +static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
  157 +{
  158 + struct i2c *i2c_base = omap24_get_base(adap);
  159 + int timeout = I2C_TIMEOUT;
  160 +
125 161 if (readw(&i2c_base->con) & I2C_CON_EN) {
126 162 writew(0, &i2c_base->con);
127 163 udelay(50000);
128 164  
... ... @@ -139,14 +175,14 @@
139 175 udelay(1000);
140 176 }
141 177  
142   - writew(0, &i2c_base->con);
143   - writew(psc, &i2c_base->psc);
144   - writew(scll, &i2c_base->scll);
145   - writew(sclh, &i2c_base->sclh);
  178 + if (0 != omap24_i2c_setspeed(adap, speed)) {
  179 + printf("ERROR: failed to setup I2C bus-speed!\n");
  180 + return;
  181 + }
146 182  
147 183 /* own address */
148 184 writew(slaveadd, &i2c_base->oa);
149   - writew(I2C_CON_EN, &i2c_base->con);
  185 +
150 186 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
151 187 /*
152 188 * Have to enable interrupts for OMAP2/3, these IPs don't have
... ... @@ -165,7 +201,8 @@
165 201 struct i2c *i2c_base = omap24_get_base(adap);
166 202 u16 stat;
167 203  
168   - /* note: if you try and read data when its not there or ready
  204 + /*
  205 + * note: if you try and read data when its not there or ready
169 206 * you get a bus error
170 207 */
171 208 while (1) {
... ... @@ -220,8 +257,8 @@
220 257  
221 258 /* Check for ACK (!NAK) */
222 259 if (!(status & I2C_STAT_NACK)) {
223   - res = 0; /* Device found */
224   - udelay(I2C_WAIT); /* Required by AM335X in SPL */
  260 + res = 0; /* Device found */
  261 + udelay(adap->waitdelay);/* Required by AM335X in SPL */
225 262 /* Abort transfer (force idle state) */
226 263 writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
227 264 udelay(1000);
... ... @@ -307,7 +344,7 @@
307 344 adap->hwadapnr, status);
308 345 goto rd_exit;
309 346 }
310   - if (status == 0 || status & I2C_STAT_NACK) {
  347 + if (status == 0 || (status & I2C_STAT_NACK)) {
311 348 i2c_error = 1;
312 349 printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
313 350 status);
... ... @@ -351,7 +388,7 @@
351 388 adap->hwadapnr, status);
352 389 goto rd_exit;
353 390 }
354   - if (status == 0 || status & I2C_STAT_NACK) {
  391 + if (status == 0 || (status & I2C_STAT_NACK)) {
355 392 i2c_error = 1;
356 393 goto rd_exit;
357 394 }
... ... @@ -379,6 +416,7 @@
379 416 int i;
380 417 u16 status;
381 418 int i2c_error = 0;
  419 + int timeout = I2C_TIMEOUT;
382 420  
383 421 if (alen < 0) {
384 422 puts("I2C write: addr len < 0\n");
... ... @@ -428,7 +466,7 @@
428 466 adap->hwadapnr, status);
429 467 goto wr_exit;
430 468 }
431   - if (status == 0 || status & I2C_STAT_NACK) {
  469 + if (status == 0 || (status & I2C_STAT_NACK)) {
432 470 i2c_error = 1;
433 471 printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
434 472 status);
... ... @@ -448,7 +486,7 @@
448 486 /* Address phase is over, now write data */
449 487 for (i = 0; i < len; i++) {
450 488 status = wait_for_event(adap);
451   - if (status == 0 || status & I2C_STAT_NACK) {
  489 + if (status == 0 || (status & I2C_STAT_NACK)) {
452 490 i2c_error = 1;
453 491 printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
454 492 status);
... ... @@ -464,6 +502,15 @@
464 502 goto wr_exit;
465 503 }
466 504 }
  505 + /*
  506 + * poll ARDY bit for making sure that last byte really has been
  507 + * transferred on the bus.
  508 + */
  509 + do {
  510 + status = wait_for_event(adap);
  511 + } while (!(status & I2C_STAT_ARDY) && timeout--);
  512 + if (timeout <= 0)
  513 + printf("i2c_write: timed out writig last byte!\n");
467 514  
468 515 wr_exit:
469 516 flush_fifo(adap);
... ... @@ -490,7 +537,7 @@
490 537 I2C_STAT_BB) && timeout--) {
491 538 #endif
492 539 writew(stat, &i2c_base->stat);
493   - udelay(I2C_WAIT);
  540 + udelay(adap->waitdelay);
494 541 }
495 542  
496 543 if (timeout <= 0) {
... ... @@ -513,7 +560,7 @@
513 560 int timeout = I2C_TIMEOUT;
514 561  
515 562 do {
516   - udelay(I2C_WAIT);
  563 + udelay(adap->waitdelay);
517 564 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
518 565 status = readw(&i2c_base->stat);
519 566 #else
520 567  
... ... @@ -580,12 +627,12 @@
580 627 #endif
581 628  
582 629 U_BOOT_I2C_ADAP_COMPLETE(omap24_0, omap24_i2c_init, omap24_i2c_probe,
583   - omap24_i2c_read, omap24_i2c_write, NULL,
  630 + omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
584 631 CONFIG_SYS_OMAP24_I2C_SPEED,
585 632 CONFIG_SYS_OMAP24_I2C_SLAVE,
586 633 0)
587 634 U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe,
588   - omap24_i2c_read, omap24_i2c_write, NULL,
  635 + omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
589 636 CONFIG_SYS_OMAP24_I2C_SPEED1,
590 637 CONFIG_SYS_OMAP24_I2C_SLAVE1,
591 638 1)
... ... @@ -68,6 +68,7 @@
68 68 uint (*set_bus_speed)(struct i2c_adapter *adap,
69 69 uint speed);
70 70 int speed;
  71 + int waitdelay;
71 72 int slaveaddr;
72 73 int init_done;
73 74 int hwadapnr;