diff -r 7e47ba1d4ae8 -r c2c6eb5bf6d2 linux/drivers/media/dvb/frontends/lnbp22.c
--- a/linux/drivers/media/dvb/frontends/lnbp22.c	Tue Mar 08 13:38:53 2011 +0200
+++ b/linux/drivers/media/dvb/frontends/lnbp22.c	Tue Apr 26 10:49:23 2011 +0100
@@ -48,38 +48,93 @@
 	struct i2c_adapter *i2c;
 };
 
+static int lnbp22_read_config(struct dvb_frontend *fe, u8 *config) {
+        struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+        struct i2c_msg msg = {  .addr = 0x08, .flags = I2C_M_RD,
+                                .buf = (char*)config,
+                                .len = sizeof(lnbp22->config) };
+
+	if (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) {
+		dprintk(2, "%s: %02X %02X %02X %02X\n", __FUNCTION__,
+			 config[0], config[1], config[2], config[3]);
+		return 0;
+        }
+        return -EIO;
+}
+
+static int lnbp22_write_config(struct dvb_frontend *fe, u8 *config) {
+        struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+        struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+                                .buf = (char*)config,
+                                .len = sizeof(lnbp22->config) };
+
+	if (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) {
+		dprintk(2, "%s: %02X %02X %02X %02X\n", __FUNCTION__,
+			 config[0], config[1], config[2], config[3]);
+		return 0;
+        }
+        return -EIO;
+}
+
 static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) {
 	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = (char*)&lnbp22->config,
-				.len = sizeof(lnbp22->config) };
+	int status;
 
 	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __FUNCTION__, voltage,
 	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
 
-	lnbp22->config[3] = 0x60; // Power down
 	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		lnbp22->config[3] |= LNBP22_EN;
-		break;
-	case SEC_VOLTAGE_18:
-		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
-		break;
-	default:
-		return -EINVAL;
-	};
+		case SEC_VOLTAGE_OFF:
+			lnbp22->config[3] &= ~LNBP22_EN;
+			return lnbp22_write_config(fe, lnbp22->config);
+		case SEC_VOLTAGE_13:
+			lnbp22->config[3] |= LNBP22_EN;
+			lnbp22->config[3] &= ~LNBP22_VSEL;
+			break;
+		case SEC_VOLTAGE_18:
+			lnbp22->config[3] |= LNBP22_EN|LNBP22_VSEL;
+			break;
+		default:
+			return -EINVAL;
+	}
 
-	dprintk(1, "%s: 0x%02x)\n", __FUNCTION__, lnbp22->config[3]);
-	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+	status = lnbp22_write_config(fe, lnbp22->config);
+	if(  status == 0 ) {
+		u8 config[4];
+		int retries = 20;
+
+		/* byte 0: status
+		    bit 3: open loop
+		    bit 2: in progress/not ready
+		    bit 1: over current limit
+		    bit 0: over voltage limit */
+
+		/* wait up to 2 seconds for voltage to stablize.
+		   It is important to wait that long, especially if there is a
+		   rotor to power on, as DC/DC converter capacitors can take a
+		   while to charge up and could cause a temporary overload */
+		do
+		{
+			msleep(50);
+			status = lnbp22_read_config(fe, config);
+			if( status < 0 )
+				return status;
+		}
+		while( (config[0] & (1<<2)) && retries-- );
+
+		dprintk(1, "%s status=0x%02X\n", __FUNCTION__, config[0]);
+
+		if( retries < 0 )
+			return -EAGAIN;  /* temporary overload ? */
+
+		if( config[0] & (1<<3) )
+			return -ENOLINK; /* open loop */
+	}
+	return status;
 }
 
 static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) {
 	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = (char*)&lnbp22->config,
-				.len = sizeof(lnbp22->config) };
 
 	dprintk(1, "%s: %d\n", __FUNCTION__, (int)arg);
 	if (arg)
@@ -87,12 +142,11 @@
 	else
 		lnbp22->config[3] &= ~LNBP22_LLC;
 
-	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+	return lnbp22_write_config(fe, lnbp22->config);
 }
 
 static void lnbp22_release(struct dvb_frontend *fe)
 {
-
 	dprintk(1, "%s\n", __FUNCTION__);
 	/* LNBP power off */
 	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
@@ -109,20 +163,14 @@
 		return NULL;
 
 	/* default configuration */
-	lnbp22->config[0] = 0x00; /* ? */
+	lnbp22->config[0] = 0x00; /* status */
 	lnbp22->config[1] = 0x28; /* ? */
-	lnbp22->config[2] = 0x48; /* ? */
+	lnbp22->config[2] = 0x49; /* ? */
 	lnbp22->config[3] = 0x60; /* Power down */
 	lnbp22->i2c = i2c;
 	fe->sec_priv = lnbp22;
 
-	/* detect if it is present or not */
-	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
-		dprintk(0, "%s LNBP22 not found\n", __FUNCTION__);
-		kfree(lnbp22);
-		fe->sec_priv = NULL;
-		return NULL;
-	}
+	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
 
 	/* install release callback */
 	fe->ops.release_sec = lnbp22_release;

