diff options
Diffstat (limited to 'drivers/media/dvb/frontends/tda10021.c')
-rw-r--r-- | drivers/media/dvb/frontends/tda10021.c | 111 |
1 files changed, 75 insertions, 36 deletions
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 6ca533ea0f0..1bff7f457e1 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c | |||
@@ -224,47 +224,86 @@ static int tda10021_init (struct dvb_frontend *fe) | |||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | static int tda10021_set_parameters (struct dvb_frontend *fe, | 227 | struct qam_params { |
228 | struct dvb_frontend_parameters *p) | 228 | u8 conf, agcref, lthr, mseth, aref; |
229 | }; | ||
230 | |||
231 | static int tda10021_set_parameters(struct dvb_frontend *fe) | ||
229 | { | 232 | { |
233 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
234 | u32 delsys = c->delivery_system; | ||
235 | unsigned qam = c->modulation; | ||
236 | bool is_annex_c; | ||
237 | u32 reg0x3d; | ||
230 | struct tda10021_state* state = fe->demodulator_priv; | 238 | struct tda10021_state* state = fe->demodulator_priv; |
239 | static const struct qam_params qam_params[] = { | ||
240 | /* Modulation Conf AGCref LTHR MSETH AREF */ | ||
241 | [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 }, | ||
242 | [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 }, | ||
243 | [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 }, | ||
244 | [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a }, | ||
245 | [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e }, | ||
246 | [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b }, | ||
247 | }; | ||
248 | |||
249 | switch (delsys) { | ||
250 | case SYS_DVBC_ANNEX_A: | ||
251 | is_annex_c = false; | ||
252 | break; | ||
253 | case SYS_DVBC_ANNEX_C: | ||
254 | is_annex_c = true; | ||
255 | break; | ||
256 | default: | ||
257 | return -EINVAL; | ||
258 | } | ||
231 | 259 | ||
232 | //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 | 260 | /* |
233 | //CONF | 261 | * gcc optimizes the code bellow the same way as it would code: |
234 | static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; | 262 | * "if (qam > 5) return -EINVAL;" |
235 | //AGCREF value | 263 | * Yet, the code is clearer, as it shows what QAM standards are |
236 | static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; | 264 | * supported by the driver, and avoids the usage of magic numbers on |
237 | //LTHR value | 265 | * it. |
238 | static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; | 266 | */ |
239 | //MSETH | 267 | switch (qam) { |
240 | static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; | 268 | case QPSK: |
241 | //AREF | 269 | case QAM_16: |
242 | static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; | 270 | case QAM_32: |
243 | 271 | case QAM_64: | |
244 | int qam = p->u.qam.modulation; | 272 | case QAM_128: |
245 | 273 | case QAM_256: | |
246 | if (qam < 0 || qam > 5) | 274 | break; |
275 | default: | ||
247 | return -EINVAL; | 276 | return -EINVAL; |
277 | } | ||
248 | 278 | ||
249 | if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) | 279 | if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF) |
250 | return -EINVAL; | 280 | return -EINVAL; |
251 | 281 | ||
252 | //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); | 282 | /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/ |
253 | 283 | ||
254 | if (fe->ops.tuner_ops.set_params) { | 284 | if (fe->ops.tuner_ops.set_params) { |
255 | fe->ops.tuner_ops.set_params(fe, p); | 285 | fe->ops.tuner_ops.set_params(fe); |
256 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | 286 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); |
257 | } | 287 | } |
258 | 288 | ||
259 | tda10021_set_symbolrate (state, p->u.qam.symbol_rate); | 289 | tda10021_set_symbolrate(state, c->symbol_rate); |
260 | _tda10021_writereg (state, 0x34, state->pwm); | 290 | _tda10021_writereg(state, 0x34, state->pwm); |
261 | 291 | ||
262 | _tda10021_writereg (state, 0x01, reg0x01[qam]); | 292 | _tda10021_writereg(state, 0x01, qam_params[qam].agcref); |
263 | _tda10021_writereg (state, 0x05, reg0x05[qam]); | 293 | _tda10021_writereg(state, 0x05, qam_params[qam].lthr); |
264 | _tda10021_writereg (state, 0x08, reg0x08[qam]); | 294 | _tda10021_writereg(state, 0x08, qam_params[qam].mseth); |
265 | _tda10021_writereg (state, 0x09, reg0x09[qam]); | 295 | _tda10021_writereg(state, 0x09, qam_params[qam].aref); |
266 | 296 | ||
267 | tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); | 297 | /* |
298 | * Bit 0 == 0 means roll-off = 0.15 (Annex A) | ||
299 | * == 1 means roll-off = 0.13 (Annex C) | ||
300 | */ | ||
301 | reg0x3d = tda10021_readreg (state, 0x3d); | ||
302 | if (is_annex_c) | ||
303 | _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d); | ||
304 | else | ||
305 | _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d); | ||
306 | tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion); | ||
268 | 307 | ||
269 | return 0; | 308 | return 0; |
270 | } | 309 | } |
@@ -347,8 +386,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | |||
347 | return 0; | 386 | return 0; |
348 | } | 387 | } |
349 | 388 | ||
350 | static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | 389 | static int tda10021_get_frontend(struct dvb_frontend *fe) |
351 | { | 390 | { |
391 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
352 | struct tda10021_state* state = fe->demodulator_priv; | 392 | struct tda10021_state* state = fe->demodulator_priv; |
353 | int sync; | 393 | int sync; |
354 | s8 afc = 0; | 394 | s8 afc = 0; |
@@ -360,17 +400,17 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa | |||
360 | printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : | 400 | printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : |
361 | "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", | 401 | "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", |
362 | state->frontend.dvb->num, afc, | 402 | state->frontend.dvb->num, afc, |
363 | -((s32)p->u.qam.symbol_rate * afc) >> 10); | 403 | -((s32)p->symbol_rate * afc) >> 10); |
364 | } | 404 | } |
365 | 405 | ||
366 | p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; | 406 | p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; |
367 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | 407 | p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; |
368 | 408 | ||
369 | p->u.qam.fec_inner = FEC_NONE; | 409 | p->fec_inner = FEC_NONE; |
370 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; | 410 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; |
371 | 411 | ||
372 | if (sync & 2) | 412 | if (sync & 2) |
373 | p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; | 413 | p->frequency -= ((s32)p->symbol_rate * afc) >> 10; |
374 | 414 | ||
375 | return 0; | 415 | return 0; |
376 | } | 416 | } |
@@ -444,10 +484,9 @@ error: | |||
444 | } | 484 | } |
445 | 485 | ||
446 | static struct dvb_frontend_ops tda10021_ops = { | 486 | static struct dvb_frontend_ops tda10021_ops = { |
447 | 487 | .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, | |
448 | .info = { | 488 | .info = { |
449 | .name = "Philips TDA10021 DVB-C", | 489 | .name = "Philips TDA10021 DVB-C", |
450 | .type = FE_QAM, | ||
451 | .frequency_stepsize = 62500, | 490 | .frequency_stepsize = 62500, |
452 | .frequency_min = 47000000, | 491 | .frequency_min = 47000000, |
453 | .frequency_max = 862000000, | 492 | .frequency_max = 862000000, |