2 * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
4 * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
5 * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
7 * FIXME: Need to port to DVB v5.2 API
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation version 2.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
19 #include <linux/kernel.h>
20 #include <asm/div64.h>
22 #include "dvb_frontend.h"
26 module_param(debug, int, 0644);
27 MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
29 #define rc(args...) do { \
30 printk(KERN_ERR "mb86a20s: " args); \
33 #define dprintk(args...) \
36 printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \
41 struct mb86a20s_state {
42 struct i2c_adapter *i2c;
43 const struct mb86a20s_config *config;
45 struct dvb_frontend frontend;
54 * Initialization sequence: Use whatevere default values that PV SBTVD
55 * does on its initialisation, obtained via USB snoop
57 static struct regdata mb86a20s_init[] = {
174 { 0x51, 0x01 }, /* Serial */
303 static struct regdata mb86a20s_reset_reception[] = {
310 static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
311 u8 i2c_addr, int reg, int data)
313 u8 buf[] = { reg, data };
314 struct i2c_msg msg = {
315 .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
319 rc = i2c_transfer(state->i2c, &msg, 1);
321 printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
322 " data == 0x%02x)\n", __func__, rc, reg, data);
329 static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state,
330 u8 i2c_addr, struct regdata *rd, int size)
334 for (i = 0; i < size; i++) {
335 rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg,
343 static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
348 struct i2c_msg msg[] = {
349 { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 },
350 { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
353 rc = i2c_transfer(state->i2c, msg, 2);
356 rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
363 #define mb86a20s_readreg(state, reg) \
364 mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
365 #define mb86a20s_writereg(state, reg, val) \
366 mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
367 #define mb86a20s_writeregdata(state, regdata) \
368 mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
369 regdata, ARRAY_SIZE(regdata))
371 static int mb86a20s_initfe(struct dvb_frontend *fe)
373 struct mb86a20s_state *state = fe->demodulator_priv;
379 if (fe->ops.i2c_gate_ctrl)
380 fe->ops.i2c_gate_ctrl(fe, 0);
382 /* Initialize the frontend */
383 rc = mb86a20s_writeregdata(state, mb86a20s_init);
387 if (!state->config->is_serial) {
390 rc = mb86a20s_writereg(state, 0x50, 0xd5);
393 rc = mb86a20s_writereg(state, 0x51, regD5);
398 if (fe->ops.i2c_gate_ctrl)
399 fe->ops.i2c_gate_ctrl(fe, 1);
404 static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
406 struct mb86a20s_state *state = fe->demodulator_priv;
407 unsigned rf_max, rf_min, rf;
412 if (fe->ops.i2c_gate_ctrl)
413 fe->ops.i2c_gate_ctrl(fe, 0);
415 /* Does a binary search to get RF strength */
419 rf = (rf_max + rf_min) / 2;
420 mb86a20s_writereg(state, 0x04, 0x1f);
421 mb86a20s_writereg(state, 0x05, rf >> 8);
422 mb86a20s_writereg(state, 0x04, 0x20);
423 mb86a20s_writereg(state, 0x04, rf);
425 val = mb86a20s_readreg(state, 0x02);
427 rf_min = (rf_max + rf_min) / 2;
429 rf_max = (rf_max + rf_min) / 2;
430 if (rf_max - rf_min < 4) {
431 *strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
436 dprintk("signal strength = %d\n", *strength);
438 if (fe->ops.i2c_gate_ctrl)
439 fe->ops.i2c_gate_ctrl(fe, 1);
444 static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
446 struct mb86a20s_state *state = fe->demodulator_priv;
452 if (fe->ops.i2c_gate_ctrl)
453 fe->ops.i2c_gate_ctrl(fe, 0);
454 val = mb86a20s_readreg(state, 0x0a) & 0xf;
455 if (fe->ops.i2c_gate_ctrl)
456 fe->ops.i2c_gate_ctrl(fe, 1);
459 *status |= FE_HAS_SIGNAL;
462 *status |= FE_HAS_CARRIER;
465 *status |= FE_HAS_VITERBI;
468 *status |= FE_HAS_SYNC;
470 if (val >= 8) /* Maybe 9? */
471 *status |= FE_HAS_LOCK;
473 dprintk("val = %d, status = 0x%02x\n", val, *status);
478 static int mb86a20s_set_frontend(struct dvb_frontend *fe,
479 struct dvb_frontend_parameters *p)
481 struct mb86a20s_state *state = fe->demodulator_priv;
486 if (fe->ops.i2c_gate_ctrl)
487 fe->ops.i2c_gate_ctrl(fe, 1);
488 fe->ops.tuner_ops.set_params(fe, p);
490 if (fe->ops.i2c_gate_ctrl)
491 fe->ops.i2c_gate_ctrl(fe, 0);
492 rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
493 if (fe->ops.i2c_gate_ctrl)
494 fe->ops.i2c_gate_ctrl(fe, 1);
499 static int mb86a20s_get_frontend(struct dvb_frontend *fe,
500 struct dvb_frontend_parameters *p)
503 /* FIXME: For now, it does nothing */
505 fe->dtv_property_cache.bandwidth_hz = 6000000;
506 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
507 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
508 fe->dtv_property_cache.isdbt_partial_reception = 0;
513 static int mb86a20s_tune(struct dvb_frontend *fe,
514 struct dvb_frontend_parameters *params,
515 unsigned int mode_flags,
524 rc = mb86a20s_set_frontend(fe, params);
526 if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
527 mb86a20s_read_status(fe, status);
532 static void mb86a20s_release(struct dvb_frontend *fe)
534 struct mb86a20s_state *state = fe->demodulator_priv;
541 static struct dvb_frontend_ops mb86a20s_ops;
543 struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
544 struct i2c_adapter *i2c)
548 /* allocate memory for the internal state */
549 struct mb86a20s_state *state =
550 kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
554 rc("Unable to kzalloc\n");
558 /* setup the state */
559 state->config = config;
562 /* create dvb_frontend */
563 memcpy(&state->frontend.ops, &mb86a20s_ops,
564 sizeof(struct dvb_frontend_ops));
565 state->frontend.demodulator_priv = state;
567 /* Check if it is a mb86a20s frontend */
568 rev = mb86a20s_readreg(state, 0);
571 printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
573 printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
578 return &state->frontend;
584 EXPORT_SYMBOL(mb86a20s_attach);
586 static struct dvb_frontend_ops mb86a20s_ops = {
587 /* Use dib8000 values per default */
589 .name = "Fujitsu mb86A20s",
591 .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
592 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
593 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
594 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
595 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO |
596 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
597 /* Actually, those values depend on the used tuner */
598 .frequency_min = 45000000,
599 .frequency_max = 864000000,
600 .frequency_stepsize = 62500,
603 .release = mb86a20s_release,
605 .init = mb86a20s_initfe,
606 .set_frontend = mb86a20s_set_frontend,
607 .get_frontend = mb86a20s_get_frontend,
608 .read_status = mb86a20s_read_status,
609 .read_signal_strength = mb86a20s_read_signal_strength,
610 .tune = mb86a20s_tune,
613 MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
614 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
615 MODULE_LICENSE("GPL");