>From ef5a12fddf73716159f17d61391ad5b0e022bc38 Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexdeuc...@gmail.com>
Date: Fri, 5 Feb 2010 16:48:23 -0500
Subject: [PATCH] drm/radeon/kms: hw i2c fixes

- handle bus probing correctly
- use meaningful error numbers
- abort if transaction fails

This gets i2cdetect working as well with hw i2c as
sw.

Signed-off-by: Alex Deucher <alexdeuc...@gmail.com>
---
 drivers/gpu/drm/radeon/radeon_i2c.c |   95 ++++++++++++++++++++++++++++++-----
 1 files changed, 82 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c
b/drivers/gpu/drm/radeon/radeon_i2c.c
index 14a68b4..825c921 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -216,11 +216,43 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                        break;
                default:
                        DRM_ERROR("gpio not supported with hw i2c\n");
-                       ret = -1;
+                       ret = -EINVAL;
                        goto done;
                }
        }

+       /* check for bus probe */
+       p = &msgs[0];
+       if ((num == 1) && (p->len == 0)) {
+               WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
+                                   RADEON_I2C_NACK |
+                                   RADEON_I2C_HALT |
+                                   RADEON_I2C_SOFT_RST));
+               WREG32(i2c_data, (p->addr << 1) & 0xff);
+               WREG32(i2c_data, 0);
+               WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
+                                   (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
+                                   RADEON_I2C_EN |
+                                   (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
+               WREG32(i2c_cntl_0, reg);
+               for (k = 0; k < 32; k++) {
+                       udelay(10);
+                       tmp = RREG32(i2c_cntl_0);
+                       if (tmp & RADEON_I2C_GO)
+                               continue;
+                       tmp = RREG32(i2c_cntl_0);
+                       if (tmp & RADEON_I2C_DONE)
+                               break;
+                       else {
+                               DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+                               WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
+                               ret = -EIO;
+                               goto done;
+                       }
+               }
+               goto done;
+       }
+
        for (i = 0; i < num; i++) {
                p = &msgs[i];
                for (j = 0; j < p->len; j++) {
@@ -245,7 +277,8 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                                                break;
                                        else {
                                                DRM_DEBUG("i2c read error 
0x%08x\n", tmp);
-                                               ret = -1;
+                                               WREG32(i2c_cntl_0, tmp | 
RADEON_I2C_ABORT);
+                                               ret = -EIO;
                                                goto done;
                                        }
                                }
@@ -272,7 +305,8 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                                                break;
                                        else {
                                                DRM_DEBUG("i2c write error 
0x%08x\n", tmp);
-                                               ret = -1;
+                                               WREG32(i2c_cntl_0, tmp | 
RADEON_I2C_ABORT);
+                                               ret = -EIO;
                                                goto done;
                                        }
                                }
@@ -361,11 +395,10 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
        }
        if (i == 50) {
                DRM_ERROR("failed to get i2c bus\n");
-               ret = -1;
+               ret = -EBUSY;
                goto done;
        }

-
        if (rdev->family == CHIP_R520)
                prescale = (127 << 8) + ((rdev->clock.default_sclk * 10) / (4 * 
127
* i2c_clock));
        else
@@ -384,7 +417,44 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                break;
        default:
                DRM_ERROR("gpio not supported with hw i2c\n");
-               ret = -1;
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* check for bus probe */
+       p = &msgs[0];
+       if ((num == 1) && (p->len == 0)) {
+               WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
+                                             AVIVO_DC_I2C_NACK |
+                                             AVIVO_DC_I2C_HALT));
+               WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
+               udelay(1);
+               WREG32(AVIVO_DC_I2C_RESET, 0);
+
+               WREG32(AVIVO_DC_I2C_DATA, (p->addr << 1) & 0xff);
+               WREG32(AVIVO_DC_I2C_DATA, 0);
+
+               WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
+               WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
+                                              AVIVO_DC_I2C_DATA_COUNT(1) |
+                                              (prescale << 16)));
+               WREG32(AVIVO_DC_I2C_CONTROL1, reg);
+               WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
+               for (j = 0; j < 200; j++) {
+                       udelay(50);
+                       tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+                       if (tmp & AVIVO_DC_I2C_GO)
+                               continue;
+                       tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+                       if (tmp & AVIVO_DC_I2C_DONE)
+                               break;
+                       else {
+                               DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+                               WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
+                               ret = -EIO;
+                               goto done;
+                       }
+               }
                goto done;
        }

@@ -422,7 +492,8 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                                                break;
                                        else {
                                                DRM_DEBUG("i2c read error 
0x%08x\n", tmp);
-                                               ret = -1;
+                                               WREG32(AVIVO_DC_I2C_RESET, 
AVIVO_DC_I2C_ABORT);
+                                               ret = -EIO;
                                                goto done;
                                        }
                                }
@@ -464,7 +535,8 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                                                break;
                                        else {
                                                DRM_DEBUG("i2c write error 
0x%08x\n", tmp);
-                                               ret = -1;
+                                               WREG32(AVIVO_DC_I2C_RESET, 
AVIVO_DC_I2C_ABORT);
+                                               ret = -EIO;
                                                goto done;
                                        }
                                }
@@ -499,10 +571,7 @@ static int radeon_sw_i2c_xfer(struct i2c_adapter *i2c_adap,
        int ret;

        radeon_i2c_do_lock(i2c, 1);
-       if (i2c_transfer(&i2c->algo.radeon.bit_adapter, msgs, num) == num)
-               ret = num;
-       else
-               ret = -1;
+       ret = i2c_transfer(&i2c->algo.radeon.bit_adapter, msgs, num);
        radeon_i2c_do_lock(i2c, 0);

        return ret;
@@ -580,7 +649,7 @@ static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap,
                break;
        default:
                DRM_ERROR("i2c: unhandled radeon chip\n");
-               ret = -1;
+               ret = -EIO;
                break;
        }

-- 
1.5.6.3

Attachment: 0001-drm-radeon-kms-hw-i2c-fixes.patch
Description: application/mbox

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to