From 3e025dc76a7d50bd9111ad5b91fe19a1a1277b92 Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexdeucher@gmail.com>
Date: Sat, 6 Feb 2010 17:06:42 -0500
Subject: [PATCH] drm/radeon/kms: take the pm mutex when using hw i2c

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>
---
 drivers/gpu/drm/radeon/radeon_i2c.c |   26 +++++++++++++++++---------
 1 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index e0a2017..b715632 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -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 |
@@ -410,6 +414,7 @@ done:
 		WREG32(RADEON_BIOS_6_SCRATCH, tmp);
 	}
 
+	mutex_unlock(&rdev->pm.mutex);
 	mutex_unlock(&rdev->dc_hw_i2c_mutex);
 
 	return ret;
@@ -427,12 +432,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);
@@ -486,11 +498,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:
@@ -648,6 +655,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;
-- 
1.5.6.3

