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 error (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 (error=%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");