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
;
58 * Initialization sequence: Use whatevere default values that PV SBTVD
59 * does on its initialisation, obtained via USB snoop
61 static struct regdata mb86a20s_init
[] = {
307 static struct regdata mb86a20s_reset_reception
[] = {
314 static int mb86a20s_i2c_writereg(struct mb86a20s_state
*state
,
315 u8 i2c_addr
, int reg
, int data
)
317 u8 buf
[] = { reg
, data
};
318 struct i2c_msg msg
= {
319 .addr
= i2c_addr
, .flags
= 0, .buf
= buf
, .len
= 2
323 rc
= i2c_transfer(state
->i2c
, &msg
, 1);
325 printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
326 " data == 0x%02x)\n", __func__
, rc
, reg
, data
);
333 static int mb86a20s_i2c_writeregdata(struct mb86a20s_state
*state
,
334 u8 i2c_addr
, struct regdata
*rd
, int size
)
338 for (i
= 0; i
< size
; i
++) {
339 rc
= mb86a20s_i2c_writereg(state
, i2c_addr
, rd
[i
].reg
,
347 static int mb86a20s_i2c_readreg(struct mb86a20s_state
*state
,
352 struct i2c_msg msg
[] = {
353 { .addr
= i2c_addr
, .flags
= 0, .buf
= ®
, .len
= 1 },
354 { .addr
= i2c_addr
, .flags
= I2C_M_RD
, .buf
= &val
, .len
= 1 }
357 rc
= i2c_transfer(state
->i2c
, msg
, 2);
360 rc("%s: reg=0x%x (rcor=%d)\n", __func__
, reg
, rc
);
367 #define mb86a20s_readreg(state, reg) \
368 mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
369 #define mb86a20s_writereg(state, reg, val) \
370 mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
371 #define mb86a20s_writeregdata(state, regdata) \
372 mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
373 regdata, ARRAY_SIZE(regdata))
375 static int mb86a20s_initfe(struct dvb_frontend
*fe
)
377 struct mb86a20s_state
*state
= fe
->demodulator_priv
;
382 /* Initialize the frontend */
383 rc
= mb86a20s_writeregdata(state
, mb86a20s_init
);
390 static int mb86a20s_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
392 struct mb86a20s_state
*state
= fe
->demodulator_priv
;
393 unsigned rf_max
, rf_min
, rf
;
398 /* Does a binary search to get RF strength */
402 rf
= (rf_max
+ rf_min
) / 2;
403 mb86a20s_writereg(state
, 0x04, 0x1f);
404 mb86a20s_writereg(state
, 0x05, rf
>> 8);
405 mb86a20s_writereg(state
, 0x04, 0x20);
406 mb86a20s_writereg(state
, 0x04, rf
);
408 val
= mb86a20s_readreg(state
, 0x02);
410 rf_min
= (rf_max
+ rf_min
) / 2;
412 rf_max
= (rf_max
+ rf_min
) / 2;
413 if (rf_max
- rf_min
< 4) {
414 *strength
= (((rf_max
+ rf_min
) / 2) * 65535) / 4095;
419 dprintk("signal strength = %d\n", *strength
);
424 static int mb86a20s_read_status(struct dvb_frontend
*fe
, fe_status_t
*status
)
426 struct mb86a20s_state
*state
= fe
->demodulator_priv
;
432 val
= mb86a20s_readreg(state
, 0x0a) & 0xf;
435 *status
|= FE_HAS_SIGNAL
;
438 *status
|= FE_HAS_CARRIER
;
441 *status
|= FE_HAS_VITERBI
;
444 *status
|= FE_HAS_SYNC
;
446 if (val
>= 8) /* Maybe 9? */
447 *status
|= FE_HAS_LOCK
;
449 dprintk("val = %d, status = 0x%02x\n", val
, *status
);
454 static int mb86a20s_set_frontend(struct dvb_frontend
*fe
,
455 struct dvb_frontend_parameters
*p
)
457 struct mb86a20s_state
*state
= fe
->demodulator_priv
;
462 fe
->ops
.tuner_ops
.set_params(fe
, p
);
463 rc
= mb86a20s_writeregdata(state
, mb86a20s_reset_reception
);
468 static int mb86a20s_get_frontend(struct dvb_frontend
*fe
,
469 struct dvb_frontend_parameters
*p
)
472 /* FIXME: For now, it does nothing */
474 fe
->dtv_property_cache
.bandwidth_hz
= 6000000;
475 fe
->dtv_property_cache
.transmission_mode
= TRANSMISSION_MODE_AUTO
;
476 fe
->dtv_property_cache
.guard_interval
= GUARD_INTERVAL_AUTO
;
477 fe
->dtv_property_cache
.isdbt_partial_reception
= 0;
482 static int mb86a20s_tune(struct dvb_frontend
*fe
,
483 struct dvb_frontend_parameters
*params
,
484 unsigned int mode_flags
,
493 rc
= mb86a20s_set_frontend(fe
, params
);
495 if (!(mode_flags
& FE_TUNE_MODE_ONESHOT
))
496 mb86a20s_read_status(fe
, status
);
501 static void mb86a20s_release(struct dvb_frontend
*fe
)
503 struct mb86a20s_state
*state
= fe
->demodulator_priv
;
510 static struct dvb_frontend_ops mb86a20s_ops
;
512 struct dvb_frontend
*mb86a20s_attach(const struct mb86a20s_config
*config
,
513 struct i2c_adapter
*i2c
)
517 /* allocate memory for the internal state */
518 struct mb86a20s_state
*state
=
519 kzalloc(sizeof(struct mb86a20s_state
), GFP_KERNEL
);
523 rc("Unable to kzalloc\n");
527 /* setup the state */
528 state
->config
= config
;
531 /* create dvb_frontend */
532 memcpy(&state
->frontend
.ops
, &mb86a20s_ops
,
533 sizeof(struct dvb_frontend_ops
));
534 state
->frontend
.demodulator_priv
= state
;
536 /* Check if it is a mb86a20s frontend */
537 rev
= mb86a20s_readreg(state
, 0);
540 printk(KERN_INFO
"Detected a Fujitsu mb86a20s frontend\n");
542 printk(KERN_ERR
"Frontend revision %d is unknown - aborting.\n",
547 return &state
->frontend
;
553 EXPORT_SYMBOL(mb86a20s_attach
);
555 static struct dvb_frontend_ops mb86a20s_ops
= {
556 /* Use dib8000 values per default */
558 .name
= "Fujitsu mb86A20s",
560 .caps
= FE_CAN_INVERSION_AUTO
| FE_CAN_RECOVER
|
561 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
562 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
563 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
564 FE_CAN_TRANSMISSION_MODE_AUTO
| FE_CAN_QAM_AUTO
|
565 FE_CAN_GUARD_INTERVAL_AUTO
| FE_CAN_HIERARCHY_AUTO
,
566 /* Actually, those values depend on the used tuner */
567 .frequency_min
= 45000000,
568 .frequency_max
= 864000000,
569 .frequency_stepsize
= 62500,
572 .release
= mb86a20s_release
,
574 .init
= mb86a20s_initfe
,
575 .set_frontend
= mb86a20s_set_frontend
,
576 .get_frontend
= mb86a20s_get_frontend
,
577 .read_status
= mb86a20s_read_status
,
578 .read_signal_strength
= mb86a20s_read_signal_strength
,
579 .tune
= mb86a20s_tune
,
582 MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
583 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
584 MODULE_LICENSE("GPL");