diff options
author | Tomoya MORINAGA <tomoya-linux@dsn.lapis-semi.com> | 2011-10-12 00:13:02 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-10-29 06:09:33 -0400 |
commit | c249ac207f2cedb49f2c9442afbaac35bfcfcd25 (patch) | |
tree | 1d888cf780719716141d54c50346ed45f471109b /drivers/i2c/busses | |
parent | c7b41f3affc63644f398b5faa170b1f531b406a8 (diff) |
i2c-eg20t: Fix 10bit access issue
Reported-by: Jeffrey (Sheng-Hui) Chu <jeffchu@broadcom.com>
Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.lapis-semi.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 543d39c73c37..38e44d959f00 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #define TEN_BIT_ADDR_DEFAULT 0xF000 | 64 | #define TEN_BIT_ADDR_DEFAULT 0xF000 |
65 | #define TEN_BIT_ADDR_MASK 0xF0 | 65 | #define TEN_BIT_ADDR_MASK 0xF0 |
66 | #define PCH_START 0x0020 | 66 | #define PCH_START 0x0020 |
67 | #define PCH_RESTART 0x0004 | ||
67 | #define PCH_ESR_START 0x0001 | 68 | #define PCH_ESR_START 0x0001 |
68 | #define PCH_BUFF_START 0x1 | 69 | #define PCH_BUFF_START 0x1 |
69 | #define PCH_REPSTART 0x0004 | 70 | #define PCH_REPSTART 0x0004 |
@@ -408,7 +409,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, | |||
408 | } | 409 | } |
409 | 410 | ||
410 | if (msgs->flags & I2C_M_TEN) { | 411 | if (msgs->flags & I2C_M_TEN) { |
411 | addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); | 412 | addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06; |
412 | iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); | 413 | iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); |
413 | if (first) | 414 | if (first) |
414 | pch_i2c_start(adap); | 415 | pch_i2c_start(adap); |
@@ -480,6 +481,19 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) | |||
480 | } | 481 | } |
481 | 482 | ||
482 | /** | 483 | /** |
484 | * pch_i2c_restart() - Generate I2C restart condition in normal mode. | ||
485 | * @adap: Pointer to struct i2c_algo_pch_data. | ||
486 | * | ||
487 | * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA. | ||
488 | */ | ||
489 | static void pch_i2c_restart(struct i2c_algo_pch_data *adap) | ||
490 | { | ||
491 | void __iomem *p = adap->pch_base_address; | ||
492 | pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); | ||
493 | pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART); | ||
494 | } | ||
495 | |||
496 | /** | ||
483 | * pch_i2c_readbytes() - read data from I2C bus in normal mode. | 497 | * pch_i2c_readbytes() - read data from I2C bus in normal mode. |
484 | * @i2c_adap: Pointer to the struct i2c_adapter. | 498 | * @i2c_adap: Pointer to the struct i2c_adapter. |
485 | * @msgs: Pointer to i2c_msg structure. | 499 | * @msgs: Pointer to i2c_msg structure. |
@@ -496,6 +510,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | |||
496 | u32 length; | 510 | u32 length; |
497 | u32 addr; | 511 | u32 addr; |
498 | u32 addr_2_msb; | 512 | u32 addr_2_msb; |
513 | u32 addr_8_lsb; | ||
499 | void __iomem *p = adap->pch_base_address; | 514 | void __iomem *p = adap->pch_base_address; |
500 | 515 | ||
501 | length = msgs->len; | 516 | length = msgs->len; |
@@ -511,9 +526,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | |||
511 | } | 526 | } |
512 | 527 | ||
513 | if (msgs->flags & I2C_M_TEN) { | 528 | if (msgs->flags & I2C_M_TEN) { |
514 | addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD)); | 529 | addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); |
515 | iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); | 530 | iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); |
531 | if (first) | ||
532 | pch_i2c_start(adap); | ||
516 | 533 | ||
534 | rtn = pch_i2c_wait_for_xfer_complete(adap); | ||
535 | if (rtn == 0) { | ||
536 | if (pch_i2c_getack(adap)) { | ||
537 | pch_dbg(adap, "Receive NACK for slave address" | ||
538 | "setting\n"); | ||
539 | return -EIO; | ||
540 | } | ||
541 | addr_8_lsb = (addr & I2C_ADDR_MSK); | ||
542 | iowrite32(addr_8_lsb, p + PCH_I2CDR); | ||
543 | } else if (rtn == -EIO) { /* Arbitration Lost */ | ||
544 | pch_err(adap, "Lost Arbitration\n"); | ||
545 | pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||
546 | I2CMAL_BIT); | ||
547 | pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||
548 | I2CMIF_BIT); | ||
549 | pch_i2c_init(adap); | ||
550 | return -EAGAIN; | ||
551 | } else { /* wait-event timeout */ | ||
552 | pch_i2c_stop(adap); | ||
553 | return -ETIME; | ||
554 | } | ||
555 | pch_i2c_restart(adap); | ||
556 | rtn = pch_i2c_wait_for_xfer_complete(adap); | ||
557 | if (rtn == 0) { | ||
558 | if (pch_i2c_getack(adap)) { | ||
559 | pch_dbg(adap, "Receive NACK for slave address" | ||
560 | "setting\n"); | ||
561 | return -EIO; | ||
562 | } | ||
563 | addr_2_msb |= I2C_RD; | ||
564 | iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, | ||
565 | p + PCH_I2CDR); | ||
566 | } else if (rtn == -EIO) { /* Arbitration Lost */ | ||
567 | pch_err(adap, "Lost Arbitration\n"); | ||
568 | pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||
569 | I2CMAL_BIT); | ||
570 | pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||
571 | I2CMIF_BIT); | ||
572 | pch_i2c_init(adap); | ||
573 | return -EAGAIN; | ||
574 | } else { /* wait-event timeout */ | ||
575 | pch_i2c_stop(adap); | ||
576 | return -ETIME; | ||
577 | } | ||
517 | } else { | 578 | } else { |
518 | /* 7 address bits + R/W bit */ | 579 | /* 7 address bits + R/W bit */ |
519 | addr = (((addr) << 1) | (I2C_RD)); | 580 | addr = (((addr) << 1) | (I2C_RD)); |