dvbsky_m88rs6000: Make i2c transactions in tuner_read/writereg() atomic

Frequent failures have been observed when accessing tuner registers on
a busy i2c bus:

[   44.033334] comcerto_i2c comcerto_i2c.0: comcerto_i2c_tx: unexpected
               state (0x20) on address phase, aborting
[   44.043221] slowirq 62 (9668us)
[   44.046515] comcerto_i2c comcerto_i2c.0: comcerto_i2c_master_xfer:
               transfer failed on message #0 (addr=0x21, flags=0x0, len=2)
[   44.058413] m88rs6000_tuner_writereg: writereg error(err == -5,
               reg == 0x05, value == 0x00)

Before reading/writing a tuner register the 2-wire bus repeater needs
to be enabled. The repeater is switched off automatically after a
configurable number of i2c transactions. The driver uses i2c_transfer()
to enable the repeater and calls i2c_transfer() again to access the
tuner register. i2c_transfer() acquires the i2c bus lock and releases it
before returning. This gives other i2c slaves on the same bus the
opportunity to grab the i2c bus after the repeater has been enabled and
perform their transactions. When the m88rs6000 regains control over the
bus the repeater has been switched off again, which causes the above
failure.

To avoid this situation the i2c bus lock must not be released after
enabling the repeater but held until the access to the tuner register is
finished. Use the unlocked __i2c_transfer() instead of i2c_transfer()
and acquire/release the bus lock in the m88rs6000 driver.

Change-Id: I53a1fe63c4d5af2b7e8c2484809d143745682580
diff --git a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
index 377d53e..13b17b1 100644
--- a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
+++ b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
@@ -28,7 +28,7 @@
 	} while (0)
 
 /*demod register operations.*/
-static int m88rs6000_writereg(struct m88rs6000_state *state, int reg, int data)
+static int __m88rs6000_writereg(struct m88rs6000_state *state, int reg, int data)
 {
 	u8 buf[] = { reg, data };
 	struct i2c_msg msg = { .addr = state->config->demod_address,
@@ -39,7 +39,7 @@
 		printk("m88rs6000: %s: write reg 0x%02x, value 0x%02x\n",
 			__func__, reg, data);
 
-	ret = i2c_transfer(state->i2c, &msg, 1);
+	ret = __i2c_transfer(state->i2c, &msg, 1);
 	if (ret != 1) {
 		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
 			 " value == 0x%02x)\n", __func__, ret, reg, data);
@@ -48,7 +48,16 @@
 	return 0;
 }
 
-static int m88rs6000_readreg(struct m88rs6000_state *state, u8 reg)
+static int m88rs6000_writereg(struct m88rs6000_state *state, int reg, int data)
+{
+	int ret;
+	i2c_lock_adapter(state->i2c);
+	ret = __m88rs6000_writereg(state, reg, data);
+	i2c_unlock_adapter(state->i2c);
+	return ret;
+}
+
+static int __m88rs6000_readreg(struct m88rs6000_state *state, u8 reg)
 {
 	int ret;
 	u8 b0[] = { reg };
@@ -59,7 +68,7 @@
 		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
 			.buf = b1, .len = 1 }
 	};
-	ret = i2c_transfer(state->i2c, msg, 2);
+	ret = __i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2) {
 		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
@@ -74,6 +83,15 @@
 	return b1[0];
 }
 
+static int m88rs6000_readreg(struct m88rs6000_state *state, u8 reg)
+{
+	int ret;
+	i2c_lock_adapter(state->i2c);
+	ret = __m88rs6000_readreg(state, reg);
+	i2c_unlock_adapter(state->i2c);
+	return ret;
+}
+
 /*tuner register operations.*/
 static int m88rs6000_tuner_writereg(struct m88rs6000_state *state, int reg, int data)
 {
@@ -82,9 +100,11 @@
 		.flags = 0, .buf = buf, .len = 2 };
 	int ret;
 
-	m88rs6000_writereg(state, 0x03, 0x11);
-	ret = i2c_transfer(state->i2c, &msg, 1);
-	
+	i2c_lock_adapter(state->i2c);
+	__m88rs6000_writereg(state, 0x03, 0x11);
+	ret = __i2c_transfer(state->i2c, &msg, 1);
+	i2c_unlock_adapter(state->i2c);
+
 	if (ret != 1) {
 		printk("%s: writereg error(err == %i, reg == 0x%02x,"
 			 " value == 0x%02x)\n", __func__, ret, reg, data);
@@ -106,8 +126,10 @@
 			.buf = b1, .len = 1 }
 	};
 
-	m88rs6000_writereg(state, 0x03, (0x11 + state->config->tuner_readstops));	
-	ret = i2c_transfer(state->i2c, msg, 2);
+	i2c_lock_adapter(state->i2c);
+	__m88rs6000_writereg(state, 0x03, (0x11 + state->config->tuner_readstops));
+	ret = __i2c_transfer(state->i2c, msg, 2);
+	i2c_unlock_adapter(state->i2c);
 
 	if (ret != 2) {
 		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);