diff --git a/packages/linux-drivers/media_build/sources/media_build/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch b/packages/linux-drivers/media_build/sources/media_build/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch new file mode 100755 index 0000000000..d8111ab0ae --- /dev/null +++ b/packages/linux-drivers/media_build/sources/media_build/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch @@ -0,0 +1,166 @@ +This patch is from the original driver author and allows minimal power on time, +so that capacitors of secondary equipment like dish motors can be properly loaded and equipment properly initialized +see https://www.spinics.net/lists/linux-media/msg38226.html +and https://github.com/LibreELEC/LibreELEC.tv/pull/1118 + +tested with TT S2-3650CI and a HH90 rotor + + +diff -Naur linux-4.9.orig/drivers/media/dvb-frontends/lnbp22.c linux-4.9/drivers/media/dvb-frontends/lnbp22.c +--- linux-4.9.orig/drivers/media/dvb-frontends/lnbp22.c 2017-01-07 18:58:55.306001049 +0100 ++++ linux-4.9/drivers/media/dvb-frontends/lnbp22.c 2017-01-07 19:39:06.204887989 +0100 +@@ -48,47 +48,95 @@ + 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, + enum fe_sec_voltage 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", __func__, 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; } ++ ++ 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: 0x%02x)\n", __func__, lnbp22->config[3]); +- return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; ++ 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", __func__, (int)arg); + if (arg) +@@ -96,7 +144,7 @@ + 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) +@@ -118,20 +166,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", __func__); +- kfree(lnbp22); +- fe->sec_priv = NULL; +- return NULL; +- } ++ lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* install release callback */ + fe->ops.release_sec = lnbp22_release;