diff options
Diffstat (limited to 'drivers/media/dvb/frontends/stv090x.c')
-rw-r--r-- | drivers/media/dvb/frontends/stv090x.c | 99 |
1 files changed, 69 insertions, 30 deletions
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index c52c3357dc54..425e7a43ae19 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> +#include <linux/slab.h> #include <linux/mutex.h> #include <linux/dvb/frontend.h> @@ -753,11 +754,19 @@ static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 d return stv090x_write_regs(state, reg, &data, 1); } -static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) { - struct stv090x_state *state = fe->demodulator_priv; u32 reg; + /* + * NOTE! A lock is used as a FSM to control the state in which + * access is serialized between two tuners on the same demod. + * This has nothing to do with a lock to protect a critical section + * which may in some other cases be confused with protecting I/O + * access to the demodulator gate. + * In case of any error, the lock is unlocked and exit within the + * relevant operations themselves. + */ if (enable) mutex_lock(&state->internal->tuner_lock); @@ -1777,7 +1786,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) freq -= cur_step * car_step; /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_set_frequency) { @@ -1790,12 +1799,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; msleep(50); - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_get_status) { @@ -1808,7 +1817,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) else dprintk(FE_DEBUG, 1, "Tuner unlocked"); - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; } @@ -1821,7 +1830,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) return srate_coarse; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -2166,7 +2175,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) freq -= cur_step * car_step; /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_set_frequency) { @@ -2179,12 +2188,12 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; msleep(50); - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_get_status) { @@ -2197,7 +2206,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) else dprintk(FE_DEBUG, 1, "Tuner unlocked"); - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); @@ -2221,7 +2230,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) return lock; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -2590,7 +2599,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st } state->delsys = stv090x_get_std(state); - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_get_frequency) { @@ -2598,7 +2607,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000; @@ -2618,7 +2627,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) { - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_get_frequency) { @@ -2626,7 +2635,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) @@ -2645,7 +2654,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st return STV090x_OUTOFRANGE; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -2999,7 +3008,7 @@ static int stv090x_optimize_track(struct stv090x_state *state) if (state->algo != STV090x_WARM_SEARCH) { - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_set_bandwidth) { @@ -3007,7 +3016,7 @@ static int stv090x_optimize_track(struct stv090x_state *state) goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; } @@ -3058,7 +3067,7 @@ static int stv090x_optimize_track(struct stv090x_state *state) return 0; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -3234,7 +3243,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) } /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_set_bbgain) { @@ -3255,17 +3264,17 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; msleep(50); if (state->config->tuner_get_status) { - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (state->config->tuner_get_status(fe, ®) < 0) goto err_gateoff; - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; if (reg) @@ -3399,7 +3408,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) return signal_state; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -3838,6 +3847,17 @@ static int stv090x_sleep(struct dvb_frontend *fe) struct stv090x_state *state = fe->demodulator_priv; u32 reg; + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_sleep) { + if (state->config->tuner_sleep(fe) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + dprintk(FE_DEBUG, 1, "Set %s to sleep", state->device == STV0900 ? "STV0900" : "STV0903"); @@ -3852,6 +3872,9 @@ static int stv090x_sleep(struct dvb_frontend *fe) goto err; return 0; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -4310,6 +4333,20 @@ static int stv090x_init(struct dvb_frontend *fe) u32 reg; if (state->internal->mclk == 0) { + /* call tuner init to configure the tuner's clock output + divider directly before setting up the master clock of + the stv090x. */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (config->tuner_init) { + if (config->tuner_init(fe) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */ msleep(5); if (stv090x_write_reg(state, STV090x_SYNTCTRL, @@ -4335,7 +4372,7 @@ static int stv090x_init(struct dvb_frontend *fe) if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) goto err; - if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; if (config->tuner_set_mode) { @@ -4348,7 +4385,7 @@ static int stv090x_init(struct dvb_frontend *fe) goto err_gateoff; } - if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; if (stv090x_set_tspath(state) < 0) @@ -4357,7 +4394,7 @@ static int stv090x_init(struct dvb_frontend *fe) return 0; err_gateoff: - stv090x_i2c_gate_ctrl(fe, 0); + stv090x_i2c_gate_ctrl(state, 0); err: dprintk(FE_ERROR, 1, "I/O error"); return -1; @@ -4469,6 +4506,10 @@ static int stv090x_setup(struct dvb_frontend *fe) if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0) goto err; + /* workaround for stuck DiSEqC output */ + if (config->diseqc_envelope_mode) + stv090x_send_diseqc_burst(fe, SEC_MINI_A); + return 0; err: dprintk(FE_ERROR, 1, "I/O error"); @@ -4498,8 +4539,6 @@ static struct dvb_frontend_ops stv090x_ops = { .sleep = stv090x_sleep, .get_frontend_algo = stv090x_frontend_algo, - .i2c_gate_ctrl = stv090x_i2c_gate_ctrl, - .diseqc_send_master_cmd = stv090x_send_diseqc_msg, .diseqc_send_burst = stv090x_send_diseqc_burst, .diseqc_recv_slave_reply = stv090x_recv_slave_reply, |