drm/radeon/kms: take the pm mutex when using hw i2c
authorAlex Deucher <alexdeucher@gmail.com>
Sat, 6 Feb 2010 22:06:42 +0000 (17:06 -0500)
committerDave Airlie <airlied@redhat.com>
Mon, 8 Feb 2010 23:32:32 +0000 (09:32 +1000)
we need a constant sclk for i2c prescale.  Also,
get the current sclk when calculating prescale rather
than using the default sclk.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/radeon_i2c.c

index b47a5615fe6a78356cff2785b99b33d8921f4a9f..272c45db5cec039c4da81b44eba18d18ab68d12d 100644 (file)
@@ -192,12 +192,16 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
        struct radeon_i2c_bus_rec *rec = &i2c->rec;
        struct i2c_msg *p;
        int i, j, k, ret = num;
-       /* XXX: use get_engine_clock() to get the current sclk */
-       u32 prescale = (((rdev->clock.default_sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+       u32 sclk, prescale;
        u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
        u32 tmp, reg;
 
        mutex_lock(&rdev->dc_hw_i2c_mutex);
+       /* take the pm lock since we need a constant sclk */
+       mutex_lock(&rdev->pm.mutex);
+
+       sclk = radeon_get_engine_clock(rdev);
+       prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
 
        reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
               RADEON_I2C_START |
@@ -424,6 +428,7 @@ done:
                WREG32(RADEON_BIOS_6_SCRATCH, tmp);
        }
 
+       mutex_unlock(&rdev->pm.mutex);
        mutex_unlock(&rdev->dc_hw_i2c_mutex);
 
        return ret;
@@ -441,12 +446,19 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
        struct i2c_msg *p;
        int i2c_clock = 50;
        int i, j, remaining, current_count, buffer_offset, ret = num;
-       /* XXX: use get_engine_clock() to get the current sclk */
-       u32 prescale;
+       u32 sclk, prescale;
        u32 tmp, reg;
        u32 saved1, saved2;
 
        mutex_lock(&rdev->dc_hw_i2c_mutex);
+       /* take the pm lock since we need a constant sclk */
+       mutex_lock(&rdev->pm.mutex);
+
+       sclk = radeon_get_engine_clock(rdev);
+       if (rdev->family == CHIP_R520)
+               prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
+       else
+               prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
 
        /* clear gpio mask bits */
        tmp = RREG32(rec->mask_clk_reg);
@@ -500,11 +512,6 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
                goto done;
        }
 
-       if (rdev->family == CHIP_R520)
-               prescale = (127 << 8) + ((rdev->clock.default_sclk * 10) / (4 * 127 * i2c_clock));
-       else
-               prescale = (((rdev->clock.default_sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
-
        reg = AVIVO_DC_I2C_START | AVIVO_DC_I2C_STOP | AVIVO_DC_I2C_EN;
        switch (rec->mask_clk_reg) {
        case AVIVO_DC_GPIO_DDC1_MASK:
@@ -662,6 +669,7 @@ done:
        tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
        WREG32(RADEON_BIOS_6_SCRATCH, tmp);
 
+       mutex_unlock(&rdev->pm.mutex);
        mutex_unlock(&rdev->dc_hw_i2c_mutex);
 
        return ret;