aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Regel <andreas.regel@gmx.de>2011-01-10 06:36:09 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 20:31:44 -0300
commit5bd0dc2d8a0db2f2e119ea50d07bf49e5e038f12 (patch)
tree4c4e788ca3627c334be3a5f9091f81a38006a80d
parent2c2c441b10644a273ff82a43ec18034ec1dd4c4e (diff)
downloadkernel_samsung_smdk4412-5bd0dc2d8a0db2f2e119ea50d07bf49e5e038f12.zip
kernel_samsung_smdk4412-5bd0dc2d8a0db2f2e119ea50d07bf49e5e038f12.tar.gz
kernel_samsung_smdk4412-5bd0dc2d8a0db2f2e119ea50d07bf49e5e038f12.tar.bz2
[media] stv090x: make sleep/wakeup specific to the demod path
The STV0900 features two demodulator paths in one chip. Thus it is not possible to use the generic power off function of the chip when sending one of them to standby. The other path will stop working in that case. The sleep function now switches off functionality specific to the demod path. The global stuff is only switched off, when both paths are in sleep mode. The wakeup function always turns on the global functionality and then works specific to the path. Signed-off-by: Andreas Regel <andreas.regel@gmx.de> Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb/frontends/stv090x.c211
1 files changed, 185 insertions, 26 deletions
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index dba2c04..e26bfd7 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -3846,6 +3846,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
{
struct stv090x_state *state = fe->demodulator_priv;
u32 reg;
+ u8 full_standby = 0;
if (stv090x_i2c_gate_ctrl(state, 1) < 0)
goto err;
@@ -3858,24 +3859,119 @@ static int stv090x_sleep(struct dvb_frontend *fe)
if (stv090x_i2c_gate_ctrl(state, 0) < 0)
goto err;
- dprintk(FE_DEBUG, 1, "Set %s to sleep",
- state->device == STV0900 ? "STV0900" : "STV0903");
+ dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep",
+ state->device == STV0900 ? "STV0900" : "STV0903",
+ state->demod);
- reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
- STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
- if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
- goto err;
+ mutex_lock(&state->internal->demod_lock);
- reg = stv090x_read_reg(state, STV090x_TSTTNR1);
- STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
- if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
- goto err;
+ switch (state->demod) {
+ case STV090x_DEMODULATOR_0:
+ /* power off ADC 1 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+ STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+ goto err;
+ /* power off DiSEqC 1 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+ STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+ goto err;
+
+ /* check whether path 2 is already sleeping, that is when
+ ADC2 is off */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+ if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0)
+ full_standby = 1;
+
+ /* stop clocks */
+ reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+ /* packet delineator 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1);
+ /* ADC 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1);
+ /* FEC clock is shared between the two paths, only stop it
+ when full standby is possible */
+ if (full_standby)
+ STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+ goto err;
+ reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+ /* sampling 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1);
+ /* viterbi 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1);
+ /* TS clock is shared between the two paths, only stop it
+ when full standby is possible */
+ if (full_standby)
+ STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+ goto err;
+ break;
+ case STV090x_DEMODULATOR_1:
+ /* power off ADC 2 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+ STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+ goto err;
+ /* power off DiSEqC 2 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+ STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+ goto err;
+
+ /* check whether path 1 is already sleeping, that is when
+ ADC1 is off */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+ if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0)
+ full_standby = 1;
+
+ /* stop clocks */
+ reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+ /* packet delineator 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1);
+ /* ADC 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1);
+ /* FEC clock is shared between the two paths, only stop it
+ when full standby is possible */
+ if (full_standby)
+ STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+ goto err;
+ reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+ /* sampling 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1);
+ /* viterbi 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1);
+ /* TS clock is shared between the two paths, only stop it
+ when full standby is possible */
+ if (full_standby)
+ STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+ goto err;
+ break;
+
+ default:
+ dprintk(FE_ERROR, 1, "Wrong demodulator!");
+ break;
+ }
+
+ if (full_standby) {
+ /* general power off */
+ reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+ STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+ goto err;
+ }
+
+ mutex_unlock(&state->internal->demod_lock);
return 0;
err_gateoff:
stv090x_i2c_gate_ctrl(state, 0);
err:
+ mutex_unlock(&state->internal->demod_lock);
dprintk(FE_ERROR, 1, "I/O error");
return -1;
}
@@ -3885,21 +3981,94 @@ static int stv090x_wakeup(struct dvb_frontend *fe)
struct stv090x_state *state = fe->demodulator_priv;
u32 reg;
- dprintk(FE_DEBUG, 1, "Wake %s from standby",
- state->device == STV0900 ? "STV0900" : "STV0903");
+ dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby",
+ state->device == STV0900 ? "STV0900" : "STV0903",
+ state->demod);
+
+ mutex_lock(&state->internal->demod_lock);
+ /* general power on */
reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
goto err;
- reg = stv090x_read_reg(state, STV090x_TSTTNR1);
- STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
- if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
- goto err;
+ switch (state->demod) {
+ case STV090x_DEMODULATOR_0:
+ /* power on ADC 1 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+ STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+ goto err;
+ /* power on DiSEqC 1 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+ STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+ goto err;
+
+ /* activate clocks */
+ reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+ /* packet delineator 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0);
+ /* ADC 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0);
+ /* FEC clock */
+ STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+ goto err;
+ reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+ /* sampling 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0);
+ /* viterbi 1 clock */
+ STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0);
+ /* TS clock */
+ STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+ goto err;
+ break;
+ case STV090x_DEMODULATOR_1:
+ /* power on ADC 2 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+ STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+ goto err;
+ /* power on DiSEqC 2 */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+ STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+ goto err;
+
+ /* activate clocks */
+ reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+ /* packet delineator 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0);
+ /* ADC 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0);
+ /* FEC clock */
+ STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+ goto err;
+ reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+ /* sampling 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0);
+ /* viterbi 2 clock */
+ STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0);
+ /* TS clock */
+ STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+ if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+ goto err;
+ break;
+
+ default:
+ dprintk(FE_ERROR, 1, "Wrong demodulator!");
+ break;
+ }
+
+ mutex_unlock(&state->internal->demod_lock);
return 0;
err:
+ mutex_unlock(&state->internal->demod_lock);
dprintk(FE_ERROR, 1, "I/O error");
return -1;
}
@@ -4622,20 +4791,10 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
mutex_init(&state->internal->demod_lock);
mutex_init(&state->internal->tuner_lock);
- if (stv090x_sleep(&state->frontend) < 0) {
- dprintk(FE_ERROR, 1, "Error putting device to sleep");
- goto error;
- }
-
if (stv090x_setup(&state->frontend) < 0) {
dprintk(FE_ERROR, 1, "Error setting up device");
goto error;
}
- if (stv090x_wakeup(&state->frontend) < 0) {
- dprintk(FE_ERROR, 1, "Error waking device");
- goto error;
- }
-
dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
state->device == STV0900 ? "STV0900" : "STV0903",
demod,