diff options
-rw-r--r-- | drivers/media/tuners/tda18271-common.c | 104 |
1 files changed, 71 insertions, 33 deletions
diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 221171eeb0c3..18c77afe2e4f 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -187,7 +187,8 @@ int tda18271_read_extended(struct dvb_frontend *fe) return (ret == 2 ? 0 : ret); } -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -198,7 +199,6 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) BUG_ON((len == 0) || (idx + len > sizeof(buf))); - switch (priv->small_i2c) { case TDA18271_03_BYTE_CHUNK_INIT: max = 3; @@ -214,7 +214,19 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) max = 39; } - tda18271_i2c_gate_ctrl(fe, 1); + + /* + * If lock_i2c is true, it will take the I2C bus for tda18271 private + * usage during the entire write ops, as otherwise, bad things could + * happen. + * During device init, several write operations will happen. So, + * tda18271_init_regs controls the I2C lock directly, + * disabling lock_i2c here. + */ + if (lock_i2c) { + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + } while (len) { if (max > len) max = len; @@ -226,14 +238,17 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) msg.len = max + 1; /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + ret = __i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) break; idx += max; len -= max; } - tda18271_i2c_gate_ctrl(fe, 0); + if (lock_i2c) { + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); + } if (ret != 1) tda_err("ERROR: idx = 0x%x, len = %d, " @@ -242,10 +257,16 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) return (ret == 1 ? 0 : ret); } +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + return __tda18271_write_regs(fe, idx, len, true); +} + /*---------------------------------------------------------------------*/ -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) +static int __tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -255,9 +276,16 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe, regs[r_cp] &= ~0x20; regs[r_cp] |= ((force & 1) << 5); - return tda18271_write_regs(fe, r_cp, 1); + return __tda18271_write_regs(fe, r_cp, 1, lock_i2c); +} + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + return __tda18271_charge_pump_source(fe, pll, force, true); } + int tda18271_init_regs(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -267,6 +295,13 @@ int tda18271_init_regs(struct dvb_frontend *fe) i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + /* + * Don't let any other I2C transfer to happen at adapter during init, + * as those could cause bad things + */ + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + /* initialize registers */ switch (priv->id) { case TDA18271HDC1: @@ -352,28 +387,28 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB22] = 0x48; regs[R_EB23] = 0xb0; - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + __tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS, false); /* setup agc1 gain */ regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); /* setup agc2 gain */ if ((priv->id) == TDA18271HDC1) { regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); } /* image rejection calibration */ @@ -391,21 +426,21 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD2] = 0x08; regs[R_MD3] = 0x00; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); if ((priv->id) == TDA18271HDC2) { /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1, false); msleep(1); /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0, false); } msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted low measurement */ regs[R_EP5] = 0x85; @@ -413,11 +448,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0x70; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image low optimization completion */ /* mid-band */ @@ -428,11 +463,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x73; regs[R_MD2] = 0x1a; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted mid measurement */ regs[R_EP5] = 0x86; @@ -440,11 +475,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0xa0; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image mid optimization completion */ /* high-band */ @@ -456,30 +491,33 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x71; regs[R_MD2] = 0xcd; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted high measurement */ regs[R_EP5] = 0x87; regs[R_CD1] = 0x65; regs[R_CD2] = 0x50; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image high optimization completion */ /* return to normal mode */ regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); + __tda18271_write_regs(fe, R_EP4, 1, false); /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); + + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); return 0; } |