aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-frontends
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb-frontends')
-rw-r--r--drivers/media/dvb-frontends/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/af9033.c18
-rw-r--r--drivers/media/dvb-frontends/af9033.h1
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h132
-rw-r--r--drivers/media/dvb-frontends/bcm3510.h2
-rw-r--r--drivers/media/dvb-frontends/cx22700.h2
-rw-r--r--drivers/media/dvb-frontends/cx24110.h2
-rw-r--r--drivers/media/dvb-frontends/cx24116.c2
-rw-r--r--drivers/media/dvb-frontends/dib0070.h2
-rw-r--r--drivers/media/dvb-frontends/dib0090.h2
-rw-r--r--drivers/media/dvb-frontends/dib3000.h2
-rw-r--r--drivers/media/dvb-frontends/dib8000.h2
-rw-r--r--drivers/media/dvb-frontends/dib9000.h2
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c9
-rw-r--r--drivers/media/dvb-frontends/ds3000.c261
-rw-r--r--drivers/media/dvb-frontends/ds3000.h10
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.h2
-rw-r--r--drivers/media/dvb-frontends/isl6405.h2
-rw-r--r--drivers/media/dvb-frontends/isl6421.h2
-rw-r--r--drivers/media/dvb-frontends/isl6423.h2
-rw-r--r--drivers/media/dvb-frontends/itd1000.h2
-rw-r--r--drivers/media/dvb-frontends/ix2505v.c2
-rw-r--r--drivers/media/dvb-frontends/l64781.h2
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.h2
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c422
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.h6
-rw-r--r--drivers/media/dvb-frontends/mb86a16.h2
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c1790
-rw-r--r--drivers/media/dvb-frontends/mt312.h2
-rw-r--r--drivers/media/dvb-frontends/mt352.h2
-rw-r--r--drivers/media/dvb-frontends/nxt200x.h2
-rw-r--r--drivers/media/dvb-frontends/nxt6000.h2
-rw-r--r--drivers/media/dvb-frontends/or51132.h2
-rw-r--r--drivers/media/dvb-frontends/or51211.c99
-rw-r--r--drivers/media/dvb-frontends/or51211.h2
-rw-r--r--drivers/media/dvb-frontends/s5h1420.h2
-rw-r--r--drivers/media/dvb-frontends/sp8870.h2
-rw-r--r--drivers/media/dvb-frontends/sp887x.h2
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.h2
-rw-r--r--drivers/media/dvb-frontends/stb6100.h2
-rw-r--r--drivers/media/dvb-frontends/stv0297.h2
-rw-r--r--drivers/media/dvb-frontends/stv0299.c2
-rw-r--r--drivers/media/dvb-frontends/stv0299.h2
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c40
-rw-r--r--drivers/media/dvb-frontends/stv0900_reg.h3
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c7
-rw-r--r--drivers/media/dvb-frontends/stv090x.c141
-rw-r--r--drivers/media/dvb-frontends/stv090x.h2
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h2
-rw-r--r--drivers/media/dvb-frontends/tda1002x.h5
-rw-r--r--drivers/media/dvb-frontends/tda1004x.h2
-rw-r--r--drivers/media/dvb-frontends/tda10071.c22
-rw-r--r--drivers/media/dvb-frontends/tda10071.h8
-rw-r--r--drivers/media/dvb-frontends/tda10086.h2
-rw-r--r--drivers/media/dvb-frontends/tda665x.h2
-rw-r--r--drivers/media/dvb-frontends/tda8083.h2
-rw-r--r--drivers/media/dvb-frontends/tda8261.h2
-rw-r--r--drivers/media/dvb-frontends/tda8261_cfg.h2
-rw-r--r--drivers/media/dvb-frontends/tda826x.h2
-rw-r--r--drivers/media/dvb-frontends/ts2020.c373
-rw-r--r--drivers/media/dvb-frontends/ts2020.h50
-rw-r--r--drivers/media/dvb-frontends/tua6100.h2
-rw-r--r--drivers/media/dvb-frontends/ves1820.h2
-rw-r--r--drivers/media/dvb-frontends/ves1x93.h2
-rw-r--r--drivers/media/dvb-frontends/zl10353.h2
66 files changed, 2557 insertions, 938 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 5efec73a32d2..6f809a70c78e 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -207,6 +207,13 @@ config DVB_SI21XX
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_TS2020
+ tristate "Montage Tehnology TS2020 based tuners"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
+
config DVB_DS3000
tristate "Montage Tehnology DS3000 based"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 7eb73bbd2e26..cebc0faffab5 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_TS2020) += ts2020.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 464ad878490b..c9cad989b8b9 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -318,6 +318,10 @@ static int af9033_init(struct dvb_frontend *fe)
len = ARRAY_SIZE(tuner_init_fc2580);
init = tuner_init_fc2580;
break;
+ case AF9033_TUNER_FC0012:
+ len = ARRAY_SIZE(tuner_init_fc0012);
+ init = tuner_init_fc0012;
+ break;
default:
dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
__func__, state->cfg.tuner);
@@ -331,6 +335,20 @@ static int af9033_init(struct dvb_frontend *fe)
goto err;
}
+ if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+ ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
state->bandwidth_hz = 0; /* force to program all parameters */
return 0;
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index bfa4313fde21..82bd8c1513b6 100644
--- a/drivers/media/dvb-frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -40,6 +40,7 @@ struct af9033_config {
*/
#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */
#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */
+#define AF9033_TUNER_FC0012 0x2e /* Fitipower FC0012 */
#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */
#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */
#define AF9033_TUNER_FC2580 0x32 /* FCI FC2580 */
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index 34dddcd77538..e9bd78265543 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -199,10 +199,9 @@ static const struct reg_val ofsm_init[] = {
{ 0x8000a6, 0x01 },
{ 0x8000a9, 0x00 },
{ 0x8000aa, 0x01 },
- { 0x8000ab, 0x01 },
{ 0x8000b0, 0x01 },
- { 0x8000c0, 0x05 },
- { 0x8000c4, 0x19 },
+ { 0x8000c4, 0x05 },
+ { 0x8000c8, 0x19 },
{ 0x80f000, 0x0f },
{ 0x80f016, 0x10 },
{ 0x80f017, 0x04 },
@@ -322,8 +321,9 @@ static const struct reg_val tuner_init_tua9001[] = {
{ 0x80009b, 0x05 },
{ 0x80009c, 0x80 },
{ 0x8000b3, 0x00 },
- { 0x8000c1, 0x01 },
- { 0x8000c2, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000c9, 0x5d },
{ 0x80f007, 0x00 },
{ 0x80f01f, 0x82 },
{ 0x80f020, 0x00 },
@@ -339,14 +339,14 @@ static const struct reg_val tuner_init_tua9001[] = {
/* Fitipower fc0011 tuner init
AF9033_TUNER_FC0011 = 0x28 */
static const struct reg_val tuner_init_fc0011[] = {
- { 0x800046, AF9033_TUNER_FC0011 },
+ { 0x800046, 0x28 },
{ 0x800057, 0x00 },
{ 0x800058, 0x01 },
{ 0x80005f, 0x00 },
{ 0x800060, 0x00 },
{ 0x800068, 0xa5 },
{ 0x80006e, 0x01 },
- { 0x800071, 0x0A },
+ { 0x800071, 0x0a },
{ 0x800072, 0x02 },
{ 0x800074, 0x01 },
{ 0x800079, 0x01 },
@@ -354,7 +354,7 @@ static const struct reg_val tuner_init_fc0011[] = {
{ 0x800094, 0x00 },
{ 0x800095, 0x00 },
{ 0x800096, 0x00 },
- { 0x80009b, 0x2D },
+ { 0x80009b, 0x2d },
{ 0x80009c, 0x60 },
{ 0x80009d, 0x23 },
{ 0x8000a4, 0x50 },
@@ -362,39 +362,82 @@ static const struct reg_val tuner_init_fc0011[] = {
{ 0x8000b3, 0x01 },
{ 0x8000b7, 0x88 },
{ 0x8000b8, 0xa6 },
- { 0x8000c3, 0x01 },
- { 0x8000c4, 0x01 },
- { 0x8000c7, 0x69 },
- { 0x80F007, 0x00 },
- { 0x80F00A, 0x1B },
- { 0x80F00B, 0x1B },
- { 0x80F00C, 0x1B },
- { 0x80F00D, 0x1B },
- { 0x80F00E, 0xFF },
- { 0x80F00F, 0x01 },
- { 0x80F010, 0x00 },
- { 0x80F011, 0x02 },
- { 0x80F012, 0xFF },
- { 0x80F013, 0x01 },
- { 0x80F014, 0x00 },
- { 0x80F015, 0x02 },
- { 0x80F01B, 0xEF },
- { 0x80F01C, 0x01 },
- { 0x80F01D, 0x0f },
- { 0x80F01E, 0x02 },
- { 0x80F01F, 0x6E },
- { 0x80F020, 0x00 },
- { 0x80F025, 0xDE },
- { 0x80F026, 0x00 },
- { 0x80F027, 0x0A },
- { 0x80F028, 0x03 },
- { 0x80F029, 0x6E },
- { 0x80F02A, 0x00 },
- { 0x80F047, 0x00 },
- { 0x80F054, 0x00 },
- { 0x80F055, 0x00 },
- { 0x80F077, 0x01 },
- { 0x80F1E6, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x01 },
+ { 0x8000c9, 0x69 },
+ { 0x80f007, 0x00 },
+ { 0x80f00a, 0x1b },
+ { 0x80f00b, 0x1b },
+ { 0x80f00c, 0x1b },
+ { 0x80f00d, 0x1b },
+ { 0x80f00e, 0xff },
+ { 0x80f00f, 0x01 },
+ { 0x80f010, 0x00 },
+ { 0x80f011, 0x02 },
+ { 0x80f012, 0xff },
+ { 0x80f013, 0x01 },
+ { 0x80f014, 0x00 },
+ { 0x80f015, 0x02 },
+ { 0x80f01b, 0xef },
+ { 0x80f01c, 0x01 },
+ { 0x80f01d, 0x0f },
+ { 0x80f01e, 0x02 },
+ { 0x80f01f, 0x6e },
+ { 0x80f020, 0x00 },
+ { 0x80f025, 0xde },
+ { 0x80f026, 0x00 },
+ { 0x80f027, 0x0a },
+ { 0x80f028, 0x03 },
+ { 0x80f029, 0x6e },
+ { 0x80f02a, 0x00 },
+ { 0x80f047, 0x00 },
+ { 0x80f054, 0x00 },
+ { 0x80f055, 0x00 },
+ { 0x80f077, 0x01 },
+ { 0x80f1e6, 0x00 },
+};
+
+/* Fitipower FC0012 tuner init
+ AF9033_TUNER_FC0012 = 0x2e */
+static const struct reg_val tuner_init_fc0012[] = {
+ { 0x800046, 0x2e },
+ { 0x800057, 0x00 },
+ { 0x800058, 0x01 },
+ { 0x800059, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x80006d, 0x00 },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800074, 0x01 },
+ { 0x800075, 0x03 },
+ { 0x800076, 0x02 },
+ { 0x800077, 0x01 },
+ { 0x800078, 0x00 },
+ { 0x800079, 0x00 },
+ { 0x80007a, 0x90 },
+ { 0x80007b, 0x90 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x01 },
+ { 0x800095, 0x02 },
+ { 0x800096, 0x01 },
+ { 0x800098, 0x0a },
+ { 0x80009b, 0x05 },
+ { 0x80009c, 0x80 },
+ { 0x8000b3, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000c9, 0x5d },
+ { 0x80f007, 0x00 },
+ { 0x80f01f, 0xa0 },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x82 },
+ { 0x80f02a, 0x00 },
+ { 0x80f047, 0x00 },
+ { 0x80f054, 0x00 },
+ { 0x80f055, 0x00 },
+ { 0x80f077, 0x01 },
+ { 0x80f1e6, 0x00 },
};
/* MaxLinear MxL5007T tuner init
@@ -482,11 +525,12 @@ static const struct reg_val tuner_init_fc2580[] = {
{ 0x800095, 0x00 },
{ 0x800096, 0x05 },
{ 0x8000b3, 0x01 },
- { 0x8000c3, 0x01 },
- { 0x8000c4, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000d1, 0x01 },
{ 0x80f007, 0x00 },
{ 0x80f00c, 0x19 },
- { 0x80f00d, 0x1A },
+ { 0x80f00d, 0x1a },
{ 0x80f00e, 0x00 },
{ 0x80f00f, 0x02 },
{ 0x80f010, 0x00 },
diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
index f4575c0cc446..5bd56b1623bf 100644
--- a/drivers/media/dvb-frontends/bcm3510.h
+++ b/drivers/media/dvb-frontends/bcm3510.h
@@ -34,7 +34,7 @@ struct bcm3510_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_BCM3510)
extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h
index 4757a930ca05..382a7b1f3618 100644
--- a/drivers/media/dvb-frontends/cx22700.h
+++ b/drivers/media/dvb-frontends/cx22700.h
@@ -31,7 +31,7 @@ struct cx22700_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX22700)
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h
index fdcceee91f3a..527aff1f2723 100644
--- a/drivers/media/dvb-frontends/cx24110.h
+++ b/drivers/media/dvb-frontends/cx24110.h
@@ -46,7 +46,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
return 0;
}
-#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX24110)
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
index b48879186537..2916d7c74a1d 100644
--- a/drivers/media/dvb-frontends/cx24116.c
+++ b/drivers/media/dvb-frontends/cx24116.c
@@ -819,7 +819,7 @@ static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static void cx24116_clone_params(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
- memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+ state->dcur = state->dnxt;
}
/* Wait for LNB */
diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h
index 45c31fae3967..0c6befcc9143 100644
--- a/drivers/media/dvb-frontends/dib0070.h
+++ b/drivers/media/dvb-frontends/dib0070.h
@@ -48,7 +48,7 @@ struct dib0070_config {
u8 vga_filter;
};
-#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0070)
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h
index 781dc49de45b..6a090954fa10 100644
--- a/drivers/media/dvb-frontends/dib0090.h
+++ b/drivers/media/dvb-frontends/dib0090.h
@@ -75,7 +75,7 @@ struct dib0090_config {
u8 force_crystal_mode;
};
-#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0090)
extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index 404f63a6f26b..9b6c3bbc983a 100644
--- a/drivers/media/dvb-frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -41,7 +41,7 @@ struct dib_fe_xfer_ops
int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
};
-#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB3000MB)
extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
#else
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 39591bb172c1..9e7a2b170d55 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -37,7 +37,7 @@ struct dib8000_config {
#define DEFAULT_DIB8000_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB8000)
extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h
index de1cc91fd833..f3639f045ff0 100644
--- a/drivers/media/dvb-frontends/dib9000.h
+++ b/drivers/media/dvb-frontends/dib9000.h
@@ -27,7 +27,7 @@ struct dib9000_config {
#define DEFAULT_DIB9000_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB9000)
extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index e71cc60851e7..9a2134792cfa 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -2965,7 +2965,7 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
return NULL;
memset(state, 0, sizeof(*state));
- memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
+ state->ops = drxd_ops;
state->dev = dev;
state->config = *config;
state->i2c = i2c;
@@ -2976,10 +2976,13 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
if (Read16(state, 0, 0, 0) < 0)
goto error;
- memcpy(&state->frontend.ops, &drxd_ops,
- sizeof(struct dvb_frontend_ops));
+ state->frontend.ops = drxd_ops;
state->frontend.demodulator_priv = state;
ConfigureMPEGOutput(state, 0);
+ /* add few initialization to allow gate control */
+ CDRXD(state, state->config.IF ? state->config.IF : 36000000);
+ InitHI(state);
+
return &state->frontend;
error:
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c
index 60a529e3833f..1e344b033277 100644
--- a/drivers/media/dvb-frontends/ds3000.c
+++ b/drivers/media/dvb-frontends/ds3000.c
@@ -1,8 +1,8 @@
/*
- Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
- Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+ Montage Technology DS3000 - DVBS/S2 Demodulator driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
- Copyright (C) 2009 TurboSight.com
+ Copyright (C) 2009-2012 TurboSight.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include <linux/firmware.h>
#include "dvb_frontend.h"
+#include "ts2020.h"
#include "ds3000.h"
static int debug;
@@ -42,7 +43,6 @@ static int debug;
#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
#define DS3000_SAMPLE_RATE 96000 /* in kHz */
-#define DS3000_XTAL_FREQ 27000 /* in kHz */
/* Register values to initialise the demod in DVB-S mode */
static u8 ds3000_dvbs_init_tab[] = {
@@ -256,22 +256,14 @@ static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
return 0;
}
-static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
+static int ds3000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
- u8 buf[] = { reg, data };
- struct i2c_msg msg = { .addr = 0x60,
- .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+ struct ds3000_state *state = fe->demodulator_priv;
- ds3000_writereg(state, 0x03, 0x11);
- err = i2c_transfer(state->i2c, &msg, 1);
- if (err != 1) {
- printk("%s: writereg error(err == %i, reg == 0x%02x,"
- " value == 0x%02x)\n", __func__, err, reg, data);
- return -EREMOTEIO;
- }
+ if (enable)
+ ds3000_writereg(state, 0x03, 0x12);
+ else
+ ds3000_writereg(state, 0x03, 0x02);
return 0;
}
@@ -280,15 +272,14 @@ static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
static int ds3000_writeFW(struct ds3000_state *state, int reg,
const u8 *data, u16 len)
{
- int i, ret = -EREMOTEIO;
+ int i, ret = 0;
struct i2c_msg msg;
u8 *buf;
buf = kmalloc(33, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_ERR "Unable to kmalloc\n");
- ret = -ENOMEM;
- goto error;
+ return -ENOMEM;
}
*(buf) = reg;
@@ -308,8 +299,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
printk(KERN_ERR "%s: write error(err == %i, "
"reg == 0x%02x\n", __func__, ret, reg);
ret = -EREMOTEIO;
+ goto error;
}
}
+ ret = 0;
error:
kfree(buf);
@@ -348,38 +341,6 @@ static int ds3000_readreg(struct ds3000_state *state, u8 reg)
return b1[0];
}
-static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
-{
- int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
- struct i2c_msg msg[] = {
- {
- .addr = 0x60,
- .flags = 0,
- .buf = b0,
- .len = 1
- }, {
- .addr = 0x60,
- .flags = I2C_M_RD,
- .buf = b1,
- .len = 1
- }
- };
-
- ds3000_writereg(state, 0x03, 0x12);
- ret = i2c_transfer(state->i2c, msg, 2);
-
- if (ret != 2) {
- printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
- return ret;
- }
-
- dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
-
- return b1[0];
-}
-
static int ds3000_load_firmware(struct dvb_frontend *fe,
const struct firmware *fw);
@@ -424,6 +385,7 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
const struct firmware *fw)
{
struct ds3000_state *state = fe->demodulator_priv;
+ int ret = 0;
dprintk("%s\n", __func__);
dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
@@ -436,10 +398,10 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
/* Begin the firmware load process */
ds3000_writereg(state, 0xb2, 0x01);
/* write the entire firmware */
- ds3000_writeFW(state, 0xb0, fw->data, fw->size);
+ ret = ds3000_writeFW(state, 0xb0, fw->data, fw->size);
ds3000_writereg(state, 0xb2, 0x00);
- return 0;
+ return ret;
}
static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -498,6 +460,9 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
return 1;
}
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, *status == 0 ? 0 : 1);
+
dprintk("%s: status = 0x%02x\n", __func__, lock);
return 0;
@@ -568,33 +533,11 @@ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
return 0;
}
-/* read TS2020 signal strength */
static int ds3000_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
- struct ds3000_state *state = fe->demodulator_priv;
- u16 sig_reading, sig_strength;
- u8 rfgain, bbgain;
-
- dprintk("%s()\n", __func__);
-
- rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f;
- bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f;
-
- if (rfgain > 15)
- rfgain = 15;
- if (bbgain > 13)
- bbgain = 13;
-
- sig_reading = rfgain * 2 + bbgain * 3;
-
- sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
-
- /* cook the value to be suitable for szap-s2 human readable output */
- *signal_strength = sig_strength * 1000;
-
- dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__,
- sig_reading, *signal_strength);
+ if (fe->ops.tuner_ops.get_rf_strength)
+ fe->ops.tuner_ops.get_rf_strength(fe, signal_strength);
return 0;
}
@@ -878,6 +821,10 @@ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
static void ds3000_release(struct dvb_frontend *fe)
{
struct ds3000_state *state = fe->demodulator_priv;
+
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, 0);
+
dprintk("%s\n", __func__);
kfree(state);
}
@@ -952,133 +899,17 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
int i;
fe_status_t status;
- u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
s32 offset_khz;
- u16 value, ndiv;
- u32 f3db;
+ u32 frequency;
+ u16 value;
dprintk("%s() ", __func__);
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
/* Tune */
- /* unknown */
- ds3000_tuner_writereg(state, 0x07, 0x02);
- ds3000_tuner_writereg(state, 0x10, 0x00);
- ds3000_tuner_writereg(state, 0x60, 0x79);
- ds3000_tuner_writereg(state, 0x08, 0x01);
- ds3000_tuner_writereg(state, 0x00, 0x01);
- div4 = 0;
-
- /* calculate and set freq divider */
- if (c->frequency < 1146000) {
- ds3000_tuner_writereg(state, 0x10, 0x11);
- div4 = 1;
- ndiv = ((c->frequency * (6 + 8) * 4) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- } else {
- ds3000_tuner_writereg(state, 0x10, 0x01);
- ndiv = ((c->frequency * (6 + 8) * 2) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- }
-
- ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
- ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
- /* set pll */
- ds3000_tuner_writereg(state, 0x03, 0x06);
- ds3000_tuner_writereg(state, 0x51, 0x0f);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x10);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- value = ds3000_tuner_readreg(state, 0x3d);
- value &= 0x0f;
- if ((value > 4) && (value < 15)) {
- value -= 3;
- if (value < 4)
- value = 4;
- value = ((value << 3) | 0x01) & 0x79;
- }
-
- ds3000_tuner_writereg(state, 0x60, value);
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
-
- /* set low-pass filter period */
- ds3000_tuner_writereg(state, 0x04, 0x2e);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
- if ((c->symbol_rate / 1000) < 5000)
- f3db += 3000;
- if (f3db < 7000)
- f3db = 7000;
- if (f3db > 40000)
- f3db = 40000;
-
- /* set low-pass filter baseband */
- value = ds3000_tuner_readreg(state, 0x26);
- mlpf = 0x2e * 207 / ((value << 1) + 151);
- mlpf_max = mlpf * 135 / 100;
- mlpf_min = mlpf * 78 / 100;
- if (mlpf_max > 63)
- mlpf_max = 63;
-
- /* rounded to the closest integer */
- nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
- / (2766 * DS3000_XTAL_FREQ);
- if (nlpf > 23)
- nlpf = 23;
- if (nlpf < 1)
- nlpf = 1;
-
- /* rounded to the closest integer */
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
-
- if (mlpf_new < mlpf_min) {
- nlpf++;
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
- }
-
- if (mlpf_new > mlpf_max)
- mlpf_new = mlpf_max;
-
- ds3000_tuner_writereg(state, 0x04, mlpf_new);
- ds3000_tuner_writereg(state, 0x06, nlpf);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x1e);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x01);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(60);
-
- offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
- / (6 + 8) / (div4 + 1) / 2 - c->frequency;
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
/* ds3000 global reset */
ds3000_writereg(state, 0x07, 0x80);
@@ -1186,7 +1017,11 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
/* start ds3000 build-in uC */
ds3000_writereg(state, 0xb2, 0x00);
- ds3000_set_carrier_offset(fe, offset_khz);
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &frequency);
+ offset_khz = frequency - c->frequency;
+ ds3000_set_carrier_offset(fe, offset_khz);
+ }
for (i = 0; i < 30 ; i++) {
ds3000_read_status(fe, &status);
@@ -1218,6 +1053,11 @@ static int ds3000_tune(struct dvb_frontend *fe,
static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
{
+ struct ds3000_state *state = fe->demodulator_priv;
+
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, 0);
+
dprintk("%s()\n", __func__);
return DVBFE_ALGO_HW;
}
@@ -1237,10 +1077,6 @@ static int ds3000_initfe(struct dvb_frontend *fe)
ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
msleep(1);
- /* TS2020 init */
- ds3000_tuner_writereg(state, 0x42, 0x73);
- ds3000_tuner_writereg(state, 0x05, 0x01);
- ds3000_tuner_writereg(state, 0x62, 0xf5);
/* Load the firmware if required */
ret = ds3000_firmware_ondemand(fe);
if (ret != 0) {
@@ -1251,17 +1087,10 @@ static int ds3000_initfe(struct dvb_frontend *fe)
return 0;
}
-/* Put device to sleep */
-static int ds3000_sleep(struct dvb_frontend *fe)
-{
- dprintk("%s()\n", __func__);
- return 0;
-}
-
static struct dvb_frontend_ops ds3000_ops = {
- .delsys = { SYS_DVBS, SYS_DVBS2},
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
.info = {
- .name = "Montage Technology DS3000/TS2020",
+ .name = "Montage Technology DS3000",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1279,7 +1108,7 @@ static struct dvb_frontend_ops ds3000_ops = {
.release = ds3000_release,
.init = ds3000_initfe,
- .sleep = ds3000_sleep,
+ .i2c_gate_ctrl = ds3000_i2c_gate_ctrl,
.read_status = ds3000_read_status,
.read_ber = ds3000_read_ber,
.read_signal_strength = ds3000_read_signal_strength,
@@ -1299,7 +1128,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
- "DS3000/TS2020 hardware");
-MODULE_AUTHOR("Konstantin Dimitrov");
+ "DS3000 hardware");
+MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
index 1b736888ea37..478ad66c63d7 100644
--- a/drivers/media/dvb-frontends/ds3000.h
+++ b/drivers/media/dvb-frontends/ds3000.h
@@ -1,8 +1,8 @@
/*
- Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
- Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+ Montage Technology DS3000 - DVBS/S2 Demodulator driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
- Copyright (C) 2009 TurboSight.com
+ Copyright (C) 2009-2012 TurboSight.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ */
#ifndef DS3000_H
#define DS3000_H
@@ -30,6 +30,8 @@ struct ds3000_config {
u8 ci_mode;
/* Set device param to start dma */
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+ /* Hook for Lock LED */
+ void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
#if defined(CONFIG_DVB_DS3000) || \
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
index 4de754f76ce9..f4b5a0601c3a 100644
--- a/drivers/media/dvb-frontends/dvb-pll.h
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -38,7 +38,7 @@
* @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
-#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_PLL)
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
index 1c793d37576b..8abb70c26fd9 100644
--- a/drivers/media/dvb-frontends/isl6405.h
+++ b/drivers/media/dvb-frontends/isl6405.h
@@ -55,7 +55,7 @@
#define ISL6405_ENT2 0x20
#define ISL6405_ISEL2 0x40
-#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6405)
/* override_set and override_clear control which system register bits (above)
* to always set & clear
*/
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index 47e4518a042d..e7ca7d12b50a 100644
--- a/drivers/media/dvb-frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -39,7 +39,7 @@
#define ISL6421_ISEL1 0x20
#define ISL6421_DCL 0x40
-#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6421)
/* override_set and override_clear control which system register bits (above) to always set & clear */
extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
u8 override_set, u8 override_clear);
diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h
index e1a37fba01ca..80dfd9cc4f41 100644
--- a/drivers/media/dvb-frontends/isl6423.h
+++ b/drivers/media/dvb-frontends/isl6423.h
@@ -42,7 +42,7 @@ struct isl6423_config {
u8 mod_extern;
};
-#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6423)
extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h
index 5e18df071b88..edae0902f4fd 100644
--- a/drivers/media/dvb-frontends/itd1000.h
+++ b/drivers/media/dvb-frontends/itd1000.h
@@ -29,7 +29,7 @@ struct itd1000_config {
u8 i2c_address;
};
-#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_ITD1000)
extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
#else
static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c
index bc5a82082aaa..0e3387e00952 100644
--- a/drivers/media/dvb-frontends/ix2505v.c
+++ b/drivers/media/dvb-frontends/ix2505v.c
@@ -212,7 +212,7 @@ static int ix2505v_set_params(struct dvb_frontend *fe)
lpf = 0xb;
deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
- deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+ deb_info("Data 0=[%4phN]\n", data);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h
index 1305a9e7fb0b..6813b08a774d 100644
--- a/drivers/media/dvb-frontends/l64781.h
+++ b/drivers/media/dvb-frontends/l64781.h
@@ -31,7 +31,7 @@ struct l64781_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_L64781)
extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
index 9012504f0f2d..ca0eab562e1e 100644
--- a/drivers/media/dvb-frontends/lgdt330x.h
+++ b/drivers/media/dvb-frontends/lgdt330x.h
@@ -52,7 +52,7 @@ struct lgdt330x_config
int clock_polarity_flip;
};
-#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LGDT330X)
extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
index 633815ed90ca..4da5272075cb 100644
--- a/drivers/media/dvb-frontends/m88rs2000.c
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -60,15 +60,13 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
#define info(format, arg...) \
printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
-static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+static int m88rs2000_writereg(struct m88rs2000_state *state,
u8 reg, u8 data)
{
int ret;
- u8 addr = (tuner == 0) ? state->config->tuner_addr :
- state->config->demod_addr;
u8 buf[] = { reg, data };
struct i2c_msg msg = {
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = 0,
.buf = buf,
.len = 2
@@ -83,44 +81,20 @@ static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
- return m88rs2000_writereg(state, 1, reg, data);
-}
-
-static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
- m88rs2000_demod_write(state, 0x81, 0x84);
- udelay(10);
- return m88rs2000_writereg(state, 0, reg, data);
-
-}
-
-static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
- struct m88rs2000_state *state = fe->demodulator_priv;
-
- if (len != 2)
- return -EINVAL;
-
- return m88rs2000_writereg(state, 1, buf[0], buf[1]);
-}
-
-static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- u8 addr = (tuner == 0) ? state->config->tuner_addr :
- state->config->demod_addr;
+
struct i2c_msg msg[] = {
{
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = 0,
.buf = b0,
.len = 1
}, {
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = I2C_M_RD,
.buf = b1,
.len = 1
@@ -136,18 +110,6 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
return b1[0];
}
-static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
-{
- return m88rs2000_readreg(state, 1, reg);
-}
-
-static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
-{
- m88rs2000_demod_write(state, 0x81, 0x85);
- udelay(10);
- return m88rs2000_readreg(state, 0, reg);
-}
-
static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
{
struct m88rs2000_state *state = fe->demodulator_priv;
@@ -166,9 +128,9 @@ static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
b[0] = (u8) (temp >> 16) & 0xff;
b[1] = (u8) (temp >> 8) & 0xff;
b[2] = (u8) temp & 0xff;
- ret = m88rs2000_demod_write(state, 0x93, b[2]);
- ret |= m88rs2000_demod_write(state, 0x94, b[1]);
- ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+ ret = m88rs2000_writereg(state, 0x93, b[2]);
+ ret |= m88rs2000_writereg(state, 0x94, b[1]);
+ ret |= m88rs2000_writereg(state, 0x95, b[0]);
deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
return ret;
@@ -182,37 +144,37 @@ static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
int i;
u8 reg;
deb_info("%s\n", __func__);
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg = m88rs2000_demod_read(state, 0xb2);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg = m88rs2000_readreg(state, 0xb2);
reg &= 0x3f;
- m88rs2000_demod_write(state, 0xb2, reg);
+ m88rs2000_writereg(state, 0xb2, reg);
for (i = 0; i < m->msg_len; i++)
- m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+ m88rs2000_writereg(state, 0xb3 + i, m->msg[i]);
- reg = m88rs2000_demod_read(state, 0xb1);
+ reg = m88rs2000_readreg(state, 0xb1);
reg &= 0x87;
reg |= ((m->msg_len - 1) << 3) | 0x07;
reg &= 0x7f;
- m88rs2000_demod_write(state, 0xb1, reg);
+ m88rs2000_writereg(state, 0xb1, reg);
for (i = 0; i < 15; i++) {
- if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+ if ((m88rs2000_readreg(state, 0xb1) & 0x40) == 0x0)
break;
msleep(20);
}
- reg = m88rs2000_demod_read(state, 0xb1);
+ reg = m88rs2000_readreg(state, 0xb1);
if ((reg & 0x40) > 0x0) {
reg &= 0x7f;
reg |= 0x40;
- m88rs2000_demod_write(state, 0xb1, reg);
+ m88rs2000_writereg(state, 0xb1, reg);
}
- reg = m88rs2000_demod_read(state, 0xb2);
+ reg = m88rs2000_readreg(state, 0xb2);
reg &= 0x3f;
reg |= 0x80;
- m88rs2000_demod_write(state, 0xb2, reg);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
@@ -224,14 +186,14 @@ static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
struct m88rs2000_state *state = fe->demodulator_priv;
u8 reg0, reg1;
deb_info("%s\n", __func__);
- m88rs2000_demod_write(state, 0x9a, 0x30);
+ m88rs2000_writereg(state, 0x9a, 0x30);
msleep(50);
- reg0 = m88rs2000_demod_read(state, 0xb1);
- reg1 = m88rs2000_demod_read(state, 0xb2);
+ reg0 = m88rs2000_readreg(state, 0xb1);
+ reg1 = m88rs2000_readreg(state, 0xb2);
/* TODO complete this section */
- m88rs2000_demod_write(state, 0xb2, reg1);
- m88rs2000_demod_write(state, 0xb1, reg0);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg1);
+ m88rs2000_writereg(state, 0xb1, reg0);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
}
@@ -240,9 +202,9 @@ static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
struct m88rs2000_state *state = fe->demodulator_priv;
u8 reg0, reg1;
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg0 = m88rs2000_demod_read(state, 0xb1);
- reg1 = m88rs2000_demod_read(state, 0xb2);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg0 = m88rs2000_readreg(state, 0xb1);
+ reg1 = m88rs2000_readreg(state, 0xb2);
reg1 &= 0x3f;
@@ -257,9 +219,9 @@ static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
default:
break;
}
- m88rs2000_demod_write(state, 0xb2, reg1);
- m88rs2000_demod_write(state, 0xb1, reg0);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg1);
+ m88rs2000_writereg(state, 0xb1, reg0);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
}
@@ -276,14 +238,6 @@ struct inittab m88rs2000_setup[] = {
{DEMOD_WRITE, 0x00, 0x00},
{DEMOD_WRITE, 0x9a, 0xb0},
{DEMOD_WRITE, 0x81, 0xc1},
- {TUNER_WRITE, 0x42, 0x73},
- {TUNER_WRITE, 0x05, 0x07},
- {TUNER_WRITE, 0x20, 0x27},
- {TUNER_WRITE, 0x07, 0x02},
- {TUNER_WRITE, 0x11, 0xff},
- {TUNER_WRITE, 0x60, 0xf9},
- {TUNER_WRITE, 0x08, 0x01},
- {TUNER_WRITE, 0x00, 0x41},
{DEMOD_WRITE, 0x81, 0x81},
{DEMOD_WRITE, 0x86, 0xc6},
{DEMOD_WRITE, 0x9a, 0x30},
@@ -301,23 +255,10 @@ struct inittab m88rs2000_shutdown[] = {
{DEMOD_WRITE, 0xf1, 0x89},
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0x9a, 0xb0},
- {TUNER_WRITE, 0x00, 0x40},
{DEMOD_WRITE, 0x81, 0x81},
{0xff, 0xaa, 0xff}
};
-struct inittab tuner_reset[] = {
- {TUNER_WRITE, 0x42, 0x73},
- {TUNER_WRITE, 0x05, 0x07},
- {TUNER_WRITE, 0x20, 0x27},
- {TUNER_WRITE, 0x07, 0x02},
- {TUNER_WRITE, 0x11, 0xff},
- {TUNER_WRITE, 0x60, 0xf9},
- {TUNER_WRITE, 0x08, 0x01},
- {TUNER_WRITE, 0x00, 0x41},
- {0xff, 0xaa, 0xff}
-};
-
struct inittab fe_reset[] = {
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0xf1, 0xbf},
@@ -389,11 +330,7 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state,
for (i = 0; i < 255; i++) {
switch (tab[i].cmd) {
case 0x01:
- ret = m88rs2000_demod_write(state, tab[i].reg,
- tab[i].val);
- break;
- case 0x02:
- ret = m88rs2000_tuner_write(state, tab[i].reg,
+ ret = m88rs2000_writereg(state, tab[i].reg,
tab[i].val);
break;
case 0x10:
@@ -419,7 +356,7 @@ static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
struct m88rs2000_state *state = fe->demodulator_priv;
u8 data;
- data = m88rs2000_demod_read(state, 0xb2);
+ data = m88rs2000_readreg(state, 0xb2);
data |= 0x03; /* bit0 V/H, bit1 off/on */
switch (volt) {
@@ -434,23 +371,11 @@ static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
break;
}
- m88rs2000_demod_write(state, 0xb2, data);
+ m88rs2000_writereg(state, 0xb2, data);
return 0;
}
-static int m88rs2000_startup(struct m88rs2000_state *state)
-{
- int ret = 0;
- u8 reg;
-
- reg = m88rs2000_tuner_read(state, 0x00);
- if ((reg & 0x40) == 0)
- ret = -ENODEV;
-
- return ret;
-}
-
static int m88rs2000_init(struct dvb_frontend *fe)
{
struct m88rs2000_state *state = fe->demodulator_priv;
@@ -458,7 +383,11 @@ static int m88rs2000_init(struct dvb_frontend *fe)
deb_info("m88rs2000: init chip\n");
/* Setup frontend from shutdown/cold */
- ret = m88rs2000_tab_set(state, m88rs2000_setup);
+ if (state->config->inittab)
+ ret = m88rs2000_tab_set(state,
+ (struct inittab *)state->config->inittab);
+ else
+ ret = m88rs2000_tab_set(state, m88rs2000_setup);
return ret;
}
@@ -475,7 +404,7 @@ static int m88rs2000_sleep(struct dvb_frontend *fe)
static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct m88rs2000_state *state = fe->demodulator_priv;
- u8 reg = m88rs2000_demod_read(state, 0x8c);
+ u8 reg = m88rs2000_readreg(state, 0x8c);
*status = 0;
@@ -488,183 +417,64 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
-/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
-
static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- deb_info("m88rs2000_read_ber %d\n", *ber);
- *ber = 0;
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 tmp0, tmp1;
+
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ tmp0 = m88rs2000_readreg(state, 0xd8);
+ if ((tmp0 & 0x10) != 0) {
+ m88rs2000_writereg(state, 0x9a, 0xb0);
+ *ber = 0xffffffff;
+ return 0;
+ }
+
+ *ber = (m88rs2000_readreg(state, 0xd7) << 8) |
+ m88rs2000_readreg(state, 0xd6);
+
+ tmp1 = m88rs2000_readreg(state, 0xd9);
+ m88rs2000_writereg(state, 0xd9, (tmp1 & ~7) | 4);
+ /* needs twice */
+ m88rs2000_writereg(state, 0xd8, (tmp0 & ~8) | 0x30);
+ m88rs2000_writereg(state, 0xd8, (tmp0 & ~8) | 0x30);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
+
return 0;
}
static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
- *strength = 0;
- return 0;
-}
+ if (fe->ops.tuner_ops.get_rf_strength)
+ fe->ops.tuner_ops.get_rf_strength(fe, strength);
-static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- deb_info("m88rs2000_read_snr %d\n", *snr);
- *snr = 0;
return 0;
}
-static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- deb_info("m88rs2000_read_ber %d\n", *ucblocks);
- *ucblocks = 0;
- return 0;
-}
-
-static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
-{
- int ret;
- ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
- ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
- ret |= m88rs2000_tuner_write(state, 0x50, offset);
- ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
- msleep(20);
- return ret;
-}
-
-static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct m88rs2000_state *state = fe->demodulator_priv;
- int reg;
- reg = m88rs2000_tuner_read(state, 0x3d);
- reg &= 0x7f;
- if (reg < 0x16)
- reg = 0xa1;
- else if (reg == 0x16)
- reg = 0x99;
- else
- reg = 0xf9;
- m88rs2000_tuner_write(state, 0x60, reg);
- reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+ *snr = 512 * m88rs2000_readreg(state, 0x65);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- return reg;
+ return 0;
}
-static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct m88rs2000_state *state = fe->demodulator_priv;
- int ret;
- u32 frequency = c->frequency;
- s32 offset_khz;
- s32 tmp;
- u32 symbol_rate = (c->symbol_rate / 1000);
- u32 f3db, gdiv28;
- u16 value, ndiv, lpf_coeff;
- u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
- u8 lo = 0x01, div4 = 0x0;
-
- /* Reset Tuner */
- ret = m88rs2000_tab_set(state, tuner_reset);
-
- /* Calculate frequency divider */
- if (frequency < 1060000) {
- lo |= 0x10;
- div4 = 0x1;
- ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
- } else
- ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
- ndiv = ndiv + ndiv % 2;
- ndiv = ndiv - 1024;
-
- ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
-
- /* Set frequency divider */
- ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
- ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
-
- ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
- if (ret < 0)
- return -ENODEV;
-
- /* Tuner Frequency Range */
- ret = m88rs2000_tuner_write(state, 0x10, lo);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
-
- /* Tuner RF */
- ret |= m88rs2000_set_tuner_rf(fe);
-
- gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
- ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
- if (ret < 0)
- return -ENODEV;
-
- value = m88rs2000_tuner_read(state, 0x26);
-
- f3db = (symbol_rate * 135) / 200 + 2000;
- f3db += FREQ_OFFSET_LOW_SYM_RATE;
- if (f3db < 7000)
- f3db = 7000;
- if (f3db > 40000)
- f3db = 40000;
-
- gdiv28 = gdiv28 * 207 / (value * 2 + 151);
- mlpf_max = gdiv28 * 135 / 100;
- mlpf_min = gdiv28 * 78 / 100;
- if (mlpf_max > 63)
- mlpf_max = 63;
-
- lpf_coeff = 2766;
-
- nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
- (FE_CRYSTAL_KHZ / 1000) + 1) / 2;
- if (nlpf > 23)
- nlpf = 23;
- if (nlpf < 1)
- nlpf = 1;
-
- lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
- * lpf_coeff * 2 / f3db + 1) / 2;
-
- if (lpf_mxdiv < mlpf_min) {
- nlpf++;
- lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
- * lpf_coeff * 2 / f3db + 1) / 2;
- }
-
- if (lpf_mxdiv > mlpf_max)
- lpf_mxdiv = mlpf_max;
-
- ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
- ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
-
- msleep(80);
- /* calculate offset assuming 96000kHz*/
- offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
- / 14 / (div4 + 1) / 2;
+ u8 tmp;
- offset_khz -= frequency;
+ *ucblocks = (m88rs2000_readreg(state, 0xd5) << 8) |
+ m88rs2000_readreg(state, 0xd4);
+ tmp = m88rs2000_readreg(state, 0xd8);
+ m88rs2000_writereg(state, 0xd8, tmp & ~0x20);
+ /* needs two times */
+ m88rs2000_writereg(state, 0xd8, tmp | 0x20);
+ m88rs2000_writereg(state, 0xd8, tmp | 0x20);
- tmp = offset_khz;
- tmp *= 65536;
-
- tmp = (2 * tmp + 96000) / (2 * 96000);
- if (tmp < 0)
- tmp += 65536;
-
- *offset = tmp & 0xffff;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return (ret < 0) ? -EINVAL : 0;
+ return 0;
}
static int m88rs2000_set_fec(struct m88rs2000_state *state,
@@ -692,7 +502,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state,
default:
fec_set = 0x08;
}
- m88rs2000_demod_write(state, 0x76, fec_set);
+ m88rs2000_writereg(state, 0x76, fec_set);
return 0;
}
@@ -701,9 +511,9 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state,
static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
{
u8 reg;
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg = m88rs2000_demod_read(state, 0x76);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg = m88rs2000_readreg(state, 0x76);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
switch (reg) {
case 0x88:
@@ -729,7 +539,9 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
struct m88rs2000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
fe_status_t status;
- int i, ret;
+ int i, ret = 0;
+ s32 tmp;
+ u32 tuner_freq;
u16 offset = 0;
u8 reg;
@@ -743,17 +555,37 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
}
/* Set Tuner */
- ret = m88rs2000_set_tuner(fe, &offset);
+ if (fe->ops.tuner_ops.set_params)
+ ret = fe->ops.tuner_ops.set_params(fe);
+
+ if (ret < 0)
+ return -ENODEV;
+
+ if (fe->ops.tuner_ops.get_frequency)
+ ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_freq);
+
if (ret < 0)
return -ENODEV;
- ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+ offset = tuner_freq - c->frequency;
+
+ /* calculate offset assuming 96000kHz*/
+ tmp = offset;
+ tmp *= 65536;
+
+ tmp = (2 * tmp + 96000) / (2 * 96000);
+ if (tmp < 0)
+ tmp += 65536;
+
+ offset = tmp & 0xffff;
+
+ ret = m88rs2000_writereg(state, 0x9a, 0x30);
/* Unknown usually 0xc6 sometimes 0xc1 */
- reg = m88rs2000_demod_read(state, 0x86);
- ret |= m88rs2000_demod_write(state, 0x86, reg);
+ reg = m88rs2000_readreg(state, 0x86);
+ ret |= m88rs2000_writereg(state, 0x86, reg);
/* Offset lower nibble always 0 */
- ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
- ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+ ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8));
+ ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0);
/* Reset Demod */
@@ -762,16 +594,16 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return -ENODEV;
/* Unknown */
- reg = m88rs2000_demod_read(state, 0x70);
- ret = m88rs2000_demod_write(state, 0x70, reg);
+ reg = m88rs2000_readreg(state, 0x70);
+ ret = m88rs2000_writereg(state, 0x70, reg);
/* Set FEC */
ret |= m88rs2000_set_fec(state, c->fec_inner);
- ret |= m88rs2000_demod_write(state, 0x85, 0x1);
- ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
- ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
- ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
- ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+ ret |= m88rs2000_writereg(state, 0x85, 0x1);
+ ret |= m88rs2000_writereg(state, 0x8a, 0xbf);
+ ret |= m88rs2000_writereg(state, 0x8d, 0x1e);
+ ret |= m88rs2000_writereg(state, 0x90, 0xf1);
+ ret |= m88rs2000_writereg(state, 0x91, 0x08);
if (ret < 0)
return -ENODEV;
@@ -787,27 +619,25 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return -ENODEV;
for (i = 0; i < 25; i++) {
- reg = m88rs2000_demod_read(state, 0x8c);
+ reg = m88rs2000_readreg(state, 0x8c);
if ((reg & 0x7) == 0x7) {
status = FE_HAS_LOCK;
break;
}
state->no_lock_count++;
if (state->no_lock_count == 15) {
- reg = m88rs2000_demod_read(state, 0x70);
+ reg = m88rs2000_readreg(state, 0x70);
reg ^= 0x4;
- m88rs2000_demod_write(state, 0x70, reg);
+ m88rs2000_writereg(state, 0x70, reg);
state->no_lock_count = 0;
}
- if (state->no_lock_count == 20)
- m88rs2000_set_tuner_rf(fe);
msleep(20);
}
if (status & FE_HAS_LOCK) {
state->fec_inner = m88rs2000_get_fec(state);
/* Uknown suspect SNR level */
- reg = m88rs2000_demod_read(state, 0x65);
+ reg = m88rs2000_readreg(state, 0x65);
}
state->tuner_frequency = c->frequency;
@@ -830,9 +660,9 @@ static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
struct m88rs2000_state *state = fe->demodulator_priv;
if (enable)
- m88rs2000_demod_write(state, 0x81, 0x84);
+ m88rs2000_writereg(state, 0x81, 0x84);
else
- m88rs2000_demod_write(state, 0x81, 0x81);
+ m88rs2000_writereg(state, 0x81, 0x81);
udelay(10);
return 0;
}
@@ -863,7 +693,6 @@ static struct dvb_frontend_ops m88rs2000_ops = {
.release = m88rs2000_release,
.init = m88rs2000_init,
.sleep = m88rs2000_sleep,
- .write = m88rs2000_write,
.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
.read_status = m88rs2000_read_status,
.read_ber = m88rs2000_read_ber,
@@ -896,9 +725,6 @@ struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
state->symbol_rate = 0;
state->fec_inner = 0;
- if (m88rs2000_startup(state) < 0)
- goto error;
-
/* create dvb_frontend */
memcpy(&state->frontend.ops, &m88rs2000_ops,
sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h
index 59acdb696873..5a8023e5a4b8 100644
--- a/drivers/media/dvb-frontends/m88rs2000.h
+++ b/drivers/media/dvb-frontends/m88rs2000.h
@@ -26,8 +26,6 @@
struct m88rs2000_config {
/* Demodulator i2c address */
u8 demod_addr;
- /* Tuner address */
- u8 tuner_addr;
u8 *inittab;
@@ -55,12 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach(
}
#endif /* CONFIG_DVB_M88RS2000 */
-#define FE_CRYSTAL_KHZ 27000
-#define FREQ_OFFSET_LOW_SYM_RATE 3000
-
enum {
DEMOD_WRITE = 0x1,
- TUNER_WRITE,
WRITE_DELAY = 0x10,
};
#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h
index 6ea8c376394f..277ce061acf9 100644
--- a/drivers/media/dvb-frontends/mb86a16.h
+++ b/drivers/media/dvb-frontends/mb86a16.h
@@ -33,7 +33,7 @@ struct mb86a16_config {
-#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MB86A16)
extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index fade566927c3..f19cd7367040 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -1,11 +1,9 @@
/*
* Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
*
- * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010-2013 Mauro Carvalho Chehab <mchehab@redhat.com>
* Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
*
- * FIXME: Need to port to DVB v5.2 API
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
@@ -26,24 +24,15 @@ static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-#define rc(args...) do { \
- printk(KERN_ERR "mb86a20s: " args); \
-} while (0)
-
-#define dprintk(args...) \
- do { \
- if (debug) { \
- printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \
- printk(args); \
- } \
- } while (0)
-
struct mb86a20s_state {
struct i2c_adapter *i2c;
const struct mb86a20s_config *config;
+ u32 last_frequency;
struct dvb_frontend frontend;
+ u32 estimated_rate[3];
+
bool need_init;
};
@@ -52,6 +41,8 @@ struct regdata {
u8 data;
};
+#define BER_SAMPLING_RATE 1 /* Seconds */
+
/*
* Initialization sequence: Use whatevere default values that PV SBTVD
* does on its initialisation, obtained via USB snoop
@@ -94,41 +85,68 @@ static struct regdata mb86a20s_init[] = {
{ 0x04, 0x13 }, { 0x05, 0xff },
{ 0x04, 0x15 }, { 0x05, 0x4e },
{ 0x04, 0x16 }, { 0x05, 0x20 },
- { 0x52, 0x01 },
- { 0x50, 0xa7 }, { 0x51, 0xff },
+
+ /*
+ * On this demod, when the bit count reaches the count below,
+ * it collects the bit error count. The bit counters are initialized
+ * to 65535 here. This warrants that all of them will be quickly
+ * calculated when device gets locked. As TMCC is parsed, the values
+ * will be adjusted later in the driver's code.
+ */
+ { 0x52, 0x01 }, /* Turn on BER before Viterbi */
+ { 0x50, 0xa7 }, { 0x51, 0x00 },
{ 0x50, 0xa8 }, { 0x51, 0xff },
{ 0x50, 0xa9 }, { 0x51, 0xff },
- { 0x50, 0xaa }, { 0x51, 0xff },
+ { 0x50, 0xaa }, { 0x51, 0x00 },
{ 0x50, 0xab }, { 0x51, 0xff },
{ 0x50, 0xac }, { 0x51, 0xff },
- { 0x50, 0xad }, { 0x51, 0xff },
+ { 0x50, 0xad }, { 0x51, 0x00 },
{ 0x50, 0xae }, { 0x51, 0xff },
{ 0x50, 0xaf }, { 0x51, 0xff },
- { 0x5e, 0x07 },
- { 0x50, 0xdc }, { 0x51, 0x01 },
- { 0x50, 0xdd }, { 0x51, 0xf4 },
- { 0x50, 0xde }, { 0x51, 0x01 },
- { 0x50, 0xdf }, { 0x51, 0xf4 },
- { 0x50, 0xe0 }, { 0x51, 0x01 },
- { 0x50, 0xe1 }, { 0x51, 0xf4 },
- { 0x50, 0xb0 }, { 0x51, 0x07 },
- { 0x50, 0xb2 }, { 0x51, 0xff },
- { 0x50, 0xb3 }, { 0x51, 0xff },
- { 0x50, 0xb4 }, { 0x51, 0xff },
- { 0x50, 0xb5 }, { 0x51, 0xff },
- { 0x50, 0xb6 }, { 0x51, 0xff },
- { 0x50, 0xb7 }, { 0x51, 0xff },
- { 0x50, 0x50 }, { 0x51, 0x02 },
- { 0x50, 0x51 }, { 0x51, 0x04 },
- { 0x45, 0x04 },
- { 0x48, 0x04 },
+
+ /*
+ * On this demod, post BER counts blocks. When the count reaches the
+ * value below, it collects the block error count. The block counters
+ * are initialized to 127 here. This warrants that all of them will be
+ * quickly calculated when device gets locked. As TMCC is parsed, the
+ * values will be adjusted later in the driver's code.
+ */
+ { 0x5e, 0x07 }, /* Turn on BER after Viterbi */
+ { 0x50, 0xdc }, { 0x51, 0x00 },
+ { 0x50, 0xdd }, { 0x51, 0x7f },
+ { 0x50, 0xde }, { 0x51, 0x00 },
+ { 0x50, 0xdf }, { 0x51, 0x7f },
+ { 0x50, 0xe0 }, { 0x51, 0x00 },
+ { 0x50, 0xe1 }, { 0x51, 0x7f },
+
+ /*
+ * On this demod, when the block count reaches the count below,
+ * it collects the block error count. The block counters are initialized
+ * to 127 here. This warrants that all of them will be quickly
+ * calculated when device gets locked. As TMCC is parsed, the values
+ * will be adjusted later in the driver's code.
+ */
+ { 0x50, 0xb0 }, { 0x51, 0x07 }, /* Enable PER */
+ { 0x50, 0xb2 }, { 0x51, 0x00 },
+ { 0x50, 0xb3 }, { 0x51, 0x7f },
+ { 0x50, 0xb4 }, { 0x51, 0x00 },
+ { 0x50, 0xb5 }, { 0x51, 0x7f },
+ { 0x50, 0xb6 }, { 0x51, 0x00 },
+ { 0x50, 0xb7 }, { 0x51, 0x7f },
+
+ { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */
+ { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */
+ { 0x45, 0x04 }, /* CN symbol 4 */
+ { 0x48, 0x04 }, /* CN manual mode */
+
{ 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */
{ 0x50, 0xd6 }, { 0x51, 0x1f },
{ 0x50, 0xd2 }, { 0x51, 0x03 },
{ 0x50, 0xd7 }, { 0x51, 0x3f },
{ 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
{ 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
- { 0x04, 0x40 }, { 0x05, 0x01 },
+
+ { 0x04, 0x40 }, { 0x05, 0x00 },
{ 0x28, 0x00 }, { 0x29, 0x10 },
{ 0x28, 0x05 }, { 0x29, 0x02 },
{ 0x1c, 0x01 },
@@ -176,8 +194,24 @@ static struct regdata mb86a20s_reset_reception[] = {
{ 0x08, 0x00 },
};
+static struct regdata mb86a20s_per_ber_reset[] = {
+ { 0x53, 0x00 }, /* pre BER Counter reset */
+ { 0x53, 0x07 },
+
+ { 0x5f, 0x00 }, /* post BER Counter reset */
+ { 0x5f, 0x07 },
+
+ { 0x50, 0xb1 }, /* PER Counter reset */
+ { 0x51, 0x07 },
+ { 0x51, 0x00 },
+};
+
+/*
+ * I2C read/write functions and macros
+ */
+
static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
- u8 i2c_addr, int reg, int data)
+ u8 i2c_addr, u8 reg, u8 data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = {
@@ -187,8 +221,9 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, &msg, 1);
if (rc != 1) {
- printk("%s: writereg error (rc == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __func__, rc, reg, data);
+ dev_err(&state->i2c->dev,
+ "%s: writereg error (rc == %i, reg == 0x%02x, data == 0x%02x)\n",
+ __func__, rc, reg, data);
return rc;
}
@@ -222,8 +257,9 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, msg, 2);
if (rc != 2) {
- rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
- return rc;
+ dev_err(&state->i2c->dev, "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, rc);
+ return (rc < 0) ? rc : -EIO;
}
return val;
@@ -237,100 +273,22 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
regdata, ARRAY_SIZE(regdata))
-static int mb86a20s_initfe(struct dvb_frontend *fe)
-{
- struct mb86a20s_state *state = fe->demodulator_priv;
- int rc;
- u8 regD5 = 1;
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- /* Initialize the frontend */
- rc = mb86a20s_writeregdata(state, mb86a20s_init);
- if (rc < 0)
- goto err;
-
- if (!state->config->is_serial) {
- regD5 &= ~1;
-
- rc = mb86a20s_writereg(state, 0x50, 0xd5);
- if (rc < 0)
- goto err;
- rc = mb86a20s_writereg(state, 0x51, regD5);
- if (rc < 0)
- goto err;
- }
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
-err:
- if (rc < 0) {
- state->need_init = true;
- printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
- } else {
- state->need_init = false;
- dprintk("Initialization succeeded.\n");
- }
- return rc;
-}
-
-static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct mb86a20s_state *state = fe->demodulator_priv;
- unsigned rf_max, rf_min, rf;
- u8 val;
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- /* Does a binary search to get RF strength */
- rf_max = 0xfff;
- rf_min = 0;
- do {
- rf = (rf_max + rf_min) / 2;
- mb86a20s_writereg(state, 0x04, 0x1f);
- mb86a20s_writereg(state, 0x05, rf >> 8);
- mb86a20s_writereg(state, 0x04, 0x20);
- mb86a20s_writereg(state, 0x04, rf);
-
- val = mb86a20s_readreg(state, 0x02);
- if (val & 0x08)
- rf_min = (rf_max + rf_min) / 2;
- else
- rf_max = (rf_max + rf_min) / 2;
- if (rf_max - rf_min < 4) {
- *strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
- break;
- }
- } while (1);
-
- dprintk("signal strength = %d\n", *strength);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- return 0;
-}
+/*
+ * Ancillary internal routines (likely compiled inlined)
+ *
+ * The functions below assume that gateway lock has already obtained
+ */
static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- u8 val;
+ int val;
- dprintk("\n");
*status = 0;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
val = mb86a20s_readreg(state, 0x0a) & 0xf;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ if (val < 0)
+ return val;
if (val >= 2)
*status |= FE_HAS_SIGNAL;
@@ -347,49 +305,56 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
if (val >= 8) /* Maybe 9? */
*status |= FE_HAS_LOCK;
- dprintk("val = %d, status = 0x%02x\n", val, *status);
+ dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n",
+ __func__, *status, val);
return 0;
}
-static int mb86a20s_set_frontend(struct dvb_frontend *fe)
+static int mb86a20s_read_signal_strength(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
int rc;
-#if 0
- /*
- * FIXME: Properly implement the set frontend properties
- */
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-#endif
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- dprintk("Calling tuner set parameters\n");
- fe->ops.tuner_ops.set_params(fe);
+ unsigned rf_max, rf_min, rf;
- /*
- * Make it more reliable: if, for some reason, the initial
- * device initialization doesn't happen, initialize it when
- * a SBTVD parameters are adjusted.
- *
- * Unfortunately, due to a hard to track bug at tda829x/tda18271,
- * the agc callback logic is not called during DVB attach time,
- * causing mb86a20s to not be initialized with Kworld SBTVD.
- * So, this hack is needed, in order to make Kworld SBTVD to work.
- */
- if (state->need_init)
- mb86a20s_initfe(fe);
+ /* Does a binary search to get RF strength */
+ rf_max = 0xfff;
+ rf_min = 0;
+ do {
+ rf = (rf_max + rf_min) / 2;
+ rc = mb86a20s_writereg(state, 0x04, 0x1f);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x05, rf >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x04, 0x20);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x04, rf);
+ if (rc < 0)
+ return rc;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ rc = mb86a20s_readreg(state, 0x02);
+ if (rc < 0)
+ return rc;
+ if (rc & 0x08)
+ rf_min = (rf_max + rf_min) / 2;
+ else
+ rf_max = (rf_max + rf_min) / 2;
+ if (rf_max - rf_min < 4) {
+ rf = (rf_max + rf_min) / 2;
+
+ /* Rescale it from 2^12 (4096) to 2^16 */
+ rf <<= (16 - 12);
+ dev_dbg(&state->i2c->dev,
+ "%s: signal strength = %d (%d < RF=%d < %d)\n",
+ __func__, rf, rf_min, rf >> 4, rf_max);
+ return rf;
+ }
+ } while (1);
- return rc;
+ return 0;
}
static int mb86a20s_get_modulation(struct mb86a20s_state *state,
@@ -410,7 +375,7 @@ static int mb86a20s_get_modulation(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- switch ((rc & 0x70) >> 4) {
+ switch ((rc >> 4) & 0x07) {
case 0:
return DQPSK;
case 1:
@@ -443,7 +408,7 @@ static int mb86a20s_get_fec(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- switch (rc) {
+ switch ((rc >> 4) & 0x07) {
case 0:
return FEC_1_2;
case 1:
@@ -478,24 +443,38 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- if (rc > 3)
- return -EINVAL; /* Not used */
- return rc;
+
+ switch ((rc >> 4) & 0x07) {
+ case 1:
+ return GUARD_INTERVAL_1_4;
+ case 2:
+ return GUARD_INTERVAL_1_8;
+ case 3:
+ return GUARD_INTERVAL_1_16;
+ case 4:
+ return GUARD_INTERVAL_1_32;
+
+ default:
+ case 0:
+ return GUARD_INTERVAL_AUTO;
+ }
}
static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
unsigned layer)
{
int rc, count;
-
static unsigned char reg[] = {
[0] = 0x89, /* Layer A */
[1] = 0x8d, /* Layer B */
[2] = 0x91, /* Layer C */
};
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
if (layer >= ARRAY_SIZE(reg))
return -EINVAL;
+
rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
if (rc < 0)
return rc;
@@ -504,113 +483,1451 @@ static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
return rc;
count = (rc >> 4) & 0x0f;
+ dev_dbg(&state->i2c->dev, "%s: segments: %d.\n", __func__, count);
+
return count;
}
+static void mb86a20s_reset_frontend_cache(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Fixed parameters */
+ c->delivery_system = SYS_ISDBT;
+ c->bandwidth_hz = 6000000;
+
+ /* Initialize values that will be later autodetected */
+ c->isdbt_layer_enabled = 0;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+ c->isdbt_sb_mode = 0;
+ c->isdbt_sb_segment_count = 0;
+}
+
+/*
+ * Estimates the bit rate using the per-segment bit rate given by
+ * ABNT/NBR 15601 spec (table 4).
+ */
+static u32 isdbt_rate[3][5][4] = {
+ { /* DQPSK/QPSK */
+ { 280850, 312060, 330420, 340430 }, /* 1/2 */
+ { 374470, 416080, 440560, 453910 }, /* 2/3 */
+ { 421280, 468090, 495630, 510650 }, /* 3/4 */
+ { 468090, 520100, 550700, 567390 }, /* 5/6 */
+ { 491500, 546110, 578230, 595760 }, /* 7/8 */
+ }, { /* QAM16 */
+ { 561710, 624130, 660840, 680870 }, /* 1/2 */
+ { 748950, 832170, 881120, 907820 }, /* 2/3 */
+ { 842570, 936190, 991260, 1021300 }, /* 3/4 */
+ { 936190, 1040210, 1101400, 1134780 }, /* 5/6 */
+ { 983000, 1092220, 1156470, 1191520 }, /* 7/8 */
+ }, { /* QAM64 */
+ { 842570, 936190, 991260, 1021300 }, /* 1/2 */
+ { 1123430, 1248260, 1321680, 1361740 }, /* 2/3 */
+ { 1263860, 1404290, 1486900, 1531950 }, /* 3/4 */
+ { 1404290, 1560320, 1652110, 1702170 }, /* 5/6 */
+ { 1474500, 1638340, 1734710, 1787280 }, /* 7/8 */
+ }
+};
+
+static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
+ u32 modulation, u32 fec, u32 interleaving,
+ u32 segment)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u32 rate;
+ int m, f, i;
+
+ /*
+ * If modulation/fec/interleaving is not detected, the default is
+ * to consider the lowest bit rate, to avoid taking too long time
+ * to get BER.
+ */
+ switch (modulation) {
+ case DQPSK:
+ case QPSK:
+ default:
+ m = 0;
+ break;
+ case QAM_16:
+ m = 1;
+ break;
+ case QAM_64:
+ m = 2;
+ break;
+ }
+
+ switch (fec) {
+ default:
+ case FEC_1_2:
+ case FEC_AUTO:
+ f = 0;
+ break;
+ case FEC_2_3:
+ f = 1;
+ break;
+ case FEC_3_4:
+ f = 2;
+ break;
+ case FEC_5_6:
+ f = 3;
+ break;
+ case FEC_7_8:
+ f = 4;
+ break;
+ }
+
+ switch (interleaving) {
+ default:
+ case GUARD_INTERVAL_1_4:
+ i = 0;
+ break;
+ case GUARD_INTERVAL_1_8:
+ i = 1;
+ break;
+ case GUARD_INTERVAL_1_16:
+ i = 2;
+ break;
+ case GUARD_INTERVAL_1_32:
+ i = 3;
+ break;
+ }
+
+ /* Samples BER at BER_SAMPLING_RATE seconds */
+ rate = isdbt_rate[m][f][i] * segment * BER_SAMPLING_RATE;
+
+ /* Avoids sampling too quickly or to overflow the register */
+ if (rate < 256)
+ rate = 256;
+ else if (rate > (1 << 24) - 1)
+ rate = (1 << 24) - 1;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n",
+ __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000,
+ rate, rate);
+
+ state->estimated_rate[i] = rate;
+}
+
+
static int mb86a20s_get_frontend(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int i, rc;
- /* Fixed parameters */
- p->delivery_system = SYS_ISDBT;
- p->bandwidth_hz = 6000000;
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ /* Reset frontend cache to default values */
+ mb86a20s_reset_frontend_cache(fe);
/* Check for partial reception */
rc = mb86a20s_writereg(state, 0x6d, 0x85);
- if (rc >= 0)
- rc = mb86a20s_readreg(state, 0x6e);
- if (rc >= 0)
- p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ c->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
/* Get per-layer data */
- p->isdbt_layer_enabled = 0;
+
for (i = 0; i < 3; i++) {
+ dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n",
+ __func__, 'A' + i);
+
rc = mb86a20s_get_segment_count(state, i);
- if (rc >= 0 && rc < 14)
- p->layer[i].segment_count = rc;
- if (rc == 0x0f)
+ if (rc < 0)
+ goto noperlayer_error;
+ if (rc >= 0 && rc < 14) {
+ c->layer[i].segment_count = rc;
+ } else {
+ c->layer[i].segment_count = 0;
+ state->estimated_rate[i] = 0;
continue;
- p->isdbt_layer_enabled |= 1 << i;
+ }
+ c->isdbt_layer_enabled |= 1 << i;
rc = mb86a20s_get_modulation(state, i);
- if (rc >= 0)
- p->layer[i].modulation = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: modulation %d.\n",
+ __func__, rc);
+ c->layer[i].modulation = rc;
rc = mb86a20s_get_fec(state, i);
- if (rc >= 0)
- p->layer[i].fec = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: FEC %d.\n",
+ __func__, rc);
+ c->layer[i].fec = rc;
rc = mb86a20s_get_interleaving(state, i);
- if (rc >= 0)
- p->layer[i].interleaving = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n",
+ __func__, rc);
+ c->layer[i].interleaving = rc;
+ mb86a20s_layer_bitrate(fe, i, c->layer[i].modulation,
+ c->layer[i].fec,
+ c->layer[i].interleaving,
+ c->layer[i].segment_count);
}
- p->isdbt_sb_mode = 0;
rc = mb86a20s_writereg(state, 0x6d, 0x84);
- if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
- p->isdbt_sb_mode = 1;
+ if (rc < 0)
+ return rc;
+ if ((rc & 0x60) == 0x20) {
+ c->isdbt_sb_mode = 1;
/* At least, one segment should exist */
- if (!p->isdbt_sb_segment_count)
- p->isdbt_sb_segment_count = 1;
- } else
- p->isdbt_sb_segment_count = 0;
+ if (!c->isdbt_sb_segment_count)
+ c->isdbt_sb_segment_count = 1;
+ }
/* Get transmission mode and guard interval */
- p->transmission_mode = TRANSMISSION_MODE_AUTO;
- p->guard_interval = GUARD_INTERVAL_AUTO;
rc = mb86a20s_readreg(state, 0x07);
- if (rc >= 0) {
- if ((rc & 0x60) == 0x20) {
- switch (rc & 0x0c >> 2) {
- case 0:
- p->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 1:
- p->transmission_mode = TRANSMISSION_MODE_4K;
- break;
- case 2:
- p->transmission_mode = TRANSMISSION_MODE_8K;
- break;
- }
+ if (rc < 0)
+ return rc;
+ if ((rc & 0x60) == 0x20) {
+ switch (rc & 0x0c >> 2) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+ }
+ if (!(rc & 0x10)) {
+ switch (rc & 0x3) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ }
+ }
+ return 0;
+
+noperlayer_error:
+
+ /* per-layer info is incomplete; discard all per-layer */
+ c->isdbt_layer_enabled = 0;
+
+ return rc;
+}
+
+static int mb86a20s_reset_counters(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Reset the counters, if the channel changed */
+ if (state->last_frequency != c->frequency) {
+ memset(&c->strength, 0, sizeof(c->strength));
+ memset(&c->cnr, 0, sizeof(c->cnr));
+ memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error));
+ memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count));
+ memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
+ memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
+ memset(&c->block_error, 0, sizeof(c->block_error));
+ memset(&c->block_count, 0, sizeof(c->block_count));
+
+ state->last_frequency = c->frequency;
+ }
+
+ /* Clear status for most stats */
+
+ /* BER/PER counter reset */
+ rc = mb86a20s_writeregdata(state, mb86a20s_per_ber_reset);
+ if (rc < 0)
+ goto err;
+
+ /* CNR counter reset */
+ rc = mb86a20s_readreg(state, 0x45);
+ if (rc < 0)
+ goto err;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x45, val | 0x10);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x45, val & 0x6f);
+ if (rc < 0)
+ goto err;
+
+ /* MER counter reset */
+ rc = mb86a20s_writereg(state, 0x50, 0x50);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ goto err;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x51, val | 0x01);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x51, val & 0x06);
+ if (rc < 0)
+ goto err;
+
+ goto ok;
+err:
+ dev_err(&state->i2c->dev,
+ "%s: Can't reset FE statistics (error %d).\n",
+ __func__, rc);
+ok:
+ return rc;
+}
+
+static int mb86a20s_get_pre_ber(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the BER measures are already available */
+ rc = mb86a20s_readreg(state, 0x54);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: preBER for layer %c is not available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Bit Error Count */
+ rc = mb86a20s_readreg(state, 0x55 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error = rc << 16;
+ rc = mb86a20s_readreg(state, 0x56 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc << 8;
+ rc = mb86a20s_readreg(state, 0x57 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: bit error before Viterbi for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count = rc << 16;
+ rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: bit count before Viterbi for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (state->estimated_rate[layer]
+ && state->estimated_rate[layer] != *count) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating layer %c preBER counter to %d.\n",
+ __func__, 'A' + layer, state->estimated_rate[layer]);
+
+ /* Turn off BER before Viterbi */
+ rc = mb86a20s_writereg(state, 0x52, 0x00);
+
+ /* Update counter for this layer */
+ rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer] >> 16);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer] >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer]);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on BER before Viterbi */
+ rc = mb86a20s_writereg(state, 0x52, 0x01);
+
+ /* Reset all preBER counters */
+ rc = mb86a20s_writereg(state, 0x53, 0x00);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x53, 0x07);
+ } else {
+ /* Reset counter to collect new data */
+ rc = mb86a20s_readreg(state, 0x53);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x53, val & ~(1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x53, val | (1 << layer));
+ }
+
+ return rc;
+}
+
+static int mb86a20s_get_post_ber(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u32 counter, collect_rate;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the BER measures are already available */
+ rc = mb86a20s_readreg(state, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: post BER for layer %c is not available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Bit Error Count */
+ rc = mb86a20s_readreg(state, 0x64 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error = rc << 16;
+ rc = mb86a20s_readreg(state, 0x65 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc << 8;
+ rc = mb86a20s_readreg(state, 0x66 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: post bit error for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ counter = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ counter |= rc;
+ *count = counter * 204 * 8;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: post bit count for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (!state->estimated_rate[layer])
+ goto reset_measurement;
+
+ collect_rate = state->estimated_rate[layer] / 204 / 8;
+ if (collect_rate < 32)
+ collect_rate = 32;
+ if (collect_rate > 65535)
+ collect_rate = 65535;
+ if (collect_rate != counter) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating postBER counter on layer %c to %d.\n",
+ __func__, 'A' + layer, collect_rate);
+
+ /* Turn off BER after Viterbi */
+ rc = mb86a20s_writereg(state, 0x5e, 0x00);
+
+ /* Update counter for this layer */
+ rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on BER after Viterbi */
+ rc = mb86a20s_writereg(state, 0x5e, 0x07);
+
+ /* Reset all preBER counters */
+ rc = mb86a20s_writereg(state, 0x5f, 0x00);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x5f, 0x07);
+
+ return rc;
+ }
+
+reset_measurement:
+ /* Reset counter to collect new data */
+ rc = mb86a20s_readreg(state, 0x5f);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x5f, val | (1 << layer));
+
+ return rc;
+}
+
+static int mb86a20s_get_blk_error(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc, val;
+ u32 collect_rate;
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the PER measures are already available */
+ rc = mb86a20s_writereg(state, 0x50, 0xb8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: block counts for layer %c aren't available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Packet error Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xb9 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *error = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xba + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+ dev_err(&state->i2c->dev, "%s: block error for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: block count for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (!state->estimated_rate[layer])
+ goto reset_measurement;
+
+ collect_rate = state->estimated_rate[layer] / 204 / 8;
+ if (collect_rate < 32)
+ collect_rate = 32;
+ if (collect_rate > 65535)
+ collect_rate = 65535;
+
+ if (collect_rate != *count) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating PER counter on layer %c to %d.\n",
+ __func__, 'A' + layer, collect_rate);
+
+ /* Stop PER measurement */
+ rc = mb86a20s_writereg(state, 0x50, 0xb0);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x00);
+ if (rc < 0)
+ return rc;
+
+ /* Update this layer's counter */
+ rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff);
+ if (rc < 0)
+ return rc;
+
+ /* start PER measurement */
+ rc = mb86a20s_writereg(state, 0x50, 0xb0);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x07);
+ if (rc < 0)
+ return rc;
+
+ /* Reset all counters to collect new data */
+ rc = mb86a20s_writereg(state, 0x50, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x07);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x00);
+
+ return rc;
+ }
+
+reset_measurement:
+ /* Reset counter to collect new data */
+ rc = mb86a20s_writereg(state, 0x50, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x51, val | (1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, val & ~(1 << layer));
+
+ return rc;
+}
+
+struct linear_segments {
+ unsigned x, y;
+};
+
+/*
+ * All tables below return a dB/1000 measurement
+ */
+
+static struct linear_segments cnr_to_db_table[] = {
+ { 19648, 0},
+ { 18187, 1000},
+ { 16534, 2000},
+ { 14823, 3000},
+ { 13161, 4000},
+ { 11622, 5000},
+ { 10279, 6000},
+ { 9089, 7000},
+ { 8042, 8000},
+ { 7137, 9000},
+ { 6342, 10000},
+ { 5641, 11000},
+ { 5030, 12000},
+ { 4474, 13000},
+ { 3988, 14000},
+ { 3556, 15000},
+ { 3180, 16000},
+ { 2841, 17000},
+ { 2541, 18000},
+ { 2276, 19000},
+ { 2038, 20000},
+ { 1800, 21000},
+ { 1625, 22000},
+ { 1462, 23000},
+ { 1324, 24000},
+ { 1175, 25000},
+ { 1063, 26000},
+ { 980, 27000},
+ { 907, 28000},
+ { 840, 29000},
+ { 788, 30000},
+};
+
+static struct linear_segments cnr_64qam_table[] = {
+ { 3922688, 0},
+ { 3920384, 1000},
+ { 3902720, 2000},
+ { 3894784, 3000},
+ { 3882496, 4000},
+ { 3872768, 5000},
+ { 3858944, 6000},
+ { 3851520, 7000},
+ { 3838976, 8000},
+ { 3829248, 9000},
+ { 3818240, 10000},
+ { 3806976, 11000},
+ { 3791872, 12000},
+ { 3767040, 13000},
+ { 3720960, 14000},
+ { 3637504, 15000},
+ { 3498496, 16000},
+ { 3296000, 17000},
+ { 3031040, 18000},
+ { 2715392, 19000},
+ { 2362624, 20000},
+ { 1963264, 21000},
+ { 1649664, 22000},
+ { 1366784, 23000},
+ { 1120768, 24000},
+ { 890880, 25000},
+ { 723456, 26000},
+ { 612096, 27000},
+ { 518912, 28000},
+ { 448256, 29000},
+ { 388864, 30000},
+};
+
+static struct linear_segments cnr_16qam_table[] = {
+ { 5314816, 0},
+ { 5219072, 1000},
+ { 5118720, 2000},
+ { 4998912, 3000},
+ { 4875520, 4000},
+ { 4736000, 5000},
+ { 4604160, 6000},
+ { 4458752, 7000},
+ { 4300288, 8000},
+ { 4092928, 9000},
+ { 3836160, 10000},
+ { 3521024, 11000},
+ { 3155968, 12000},
+ { 2756864, 13000},
+ { 2347008, 14000},
+ { 1955072, 15000},
+ { 1593600, 16000},
+ { 1297920, 17000},
+ { 1043968, 18000},
+ { 839680, 19000},
+ { 672256, 20000},
+ { 523008, 21000},
+ { 424704, 22000},
+ { 345088, 23000},
+ { 280064, 24000},
+ { 221440, 25000},
+ { 179712, 26000},
+ { 151040, 27000},
+ { 128512, 28000},
+ { 110080, 29000},
+ { 95744, 30000},
+};
+
+struct linear_segments cnr_qpsk_table[] = {
+ { 2834176, 0},
+ { 2683648, 1000},
+ { 2536960, 2000},
+ { 2391808, 3000},
+ { 2133248, 4000},
+ { 1906176, 5000},
+ { 1666560, 6000},
+ { 1422080, 7000},
+ { 1189632, 8000},
+ { 976384, 9000},
+ { 790272, 10000},
+ { 633344, 11000},
+ { 505600, 12000},
+ { 402944, 13000},
+ { 320768, 14000},
+ { 255488, 15000},
+ { 204032, 16000},
+ { 163072, 17000},
+ { 130304, 18000},
+ { 105216, 19000},
+ { 83456, 20000},
+ { 65024, 21000},
+ { 52480, 22000},
+ { 42752, 23000},
+ { 34560, 24000},
+ { 27136, 25000},
+ { 22016, 26000},
+ { 18432, 27000},
+ { 15616, 28000},
+ { 13312, 29000},
+ { 11520, 30000},
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+ unsigned len)
+{
+ u64 tmp64;
+ u32 dx, dy;
+ int i, ret;
+
+ if (value >= segments[0].x)
+ return segments[0].y;
+ if (value < segments[len-1].x)
+ return segments[len-1].y;
+
+ for (i = 1; i < len - 1; i++) {
+ /* If value is identical, no need to interpolate */
+ if (value == segments[i].x)
+ return segments[i].y;
+ if (value > segments[i].x)
+ break;
+ }
+
+ /* Linear interpolation between the two (x,y) points */
+ dy = segments[i].y - segments[i - 1].y;
+ dx = segments[i - 1].x - segments[i].x;
+ tmp64 = value - segments[i].x;
+ tmp64 *= dy;
+ do_div(tmp64, dx);
+ ret = segments[i].y - tmp64;
+
+ return ret;
+}
+
+static int mb86a20s_get_main_CNR(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 cnr_linear, cnr;
+ int rc, val;
+
+ /* Check if CNR is available */
+ rc = mb86a20s_readreg(state, 0x45);
+ if (rc < 0)
+ return rc;
+
+ if (!(rc & 0x40)) {
+ dev_info(&state->i2c->dev, "%s: CNR is not available yet.\n",
+ __func__);
+ return -EBUSY;
+ }
+ val = rc;
+
+ rc = mb86a20s_readreg(state, 0x46);
+ if (rc < 0)
+ return rc;
+ cnr_linear = rc << 8;
+
+ rc = mb86a20s_readreg(state, 0x46);
+ if (rc < 0)
+ return rc;
+ cnr_linear |= rc;
+
+ cnr = interpolate_value(cnr_linear,
+ cnr_to_db_table, ARRAY_SIZE(cnr_to_db_table));
+
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = cnr;
+
+ dev_dbg(&state->i2c->dev, "%s: CNR is %d.%03d dB (%d)\n",
+ __func__, cnr / 1000, cnr % 1000, cnr_linear);
+
+ /* CNR counter reset */
+ rc = mb86a20s_writereg(state, 0x45, val | 0x10);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x45, val & 0x6f);
+
+ return rc;
+}
+
+static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 mer, cnr;
+ int rc, val, i;
+ struct linear_segments *segs;
+ unsigned segs_len;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Check if the measures are already available */
+ rc = mb86a20s_writereg(state, 0x50, 0x5b);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available */
+ if (!(rc & 0x01)) {
+ dev_info(&state->i2c->dev,
+ "%s: MER measures aren't available yet.\n", __func__);
+ return -EBUSY;
+ }
+
+ /* Read all layers */
+ for (i = 0; i < 3; i++) {
+ if (!(c->isdbt_layer_enabled & (1 << i))) {
+ c->cnr.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ continue;
+ }
+
+ rc = mb86a20s_writereg(state, 0x50, 0x52 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer = rc << 16;
+ rc = mb86a20s_writereg(state, 0x50, 0x53 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer |= rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0x54 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer |= rc;
+
+ switch (c->layer[i].modulation) {
+ case DQPSK:
+ case QPSK:
+ segs = cnr_qpsk_table;
+ segs_len = ARRAY_SIZE(cnr_qpsk_table);
+ break;
+ case QAM_16:
+ segs = cnr_16qam_table;
+ segs_len = ARRAY_SIZE(cnr_16qam_table);
+ break;
+ default:
+ case QAM_64:
+ segs = cnr_64qam_table;
+ segs_len = ARRAY_SIZE(cnr_64qam_table);
+ break;
}
- if (!(rc & 0x10)) {
- switch (rc & 0x3) {
- case 0:
- p->guard_interval = GUARD_INTERVAL_1_4;
- break;
- case 1:
- p->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 2:
- p->guard_interval = GUARD_INTERVAL_1_16;
- break;
+ cnr = interpolate_value(mer, segs, segs_len);
+
+ c->cnr.stat[1 + i].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[1 + i].svalue = cnr;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: CNR for layer %c is %d.%03d dB (MER = %d).\n",
+ __func__, 'A' + i, cnr / 1000, cnr % 1000, mer);
+
+ }
+
+ /* Start a new MER measurement */
+ /* MER counter reset */
+ rc = mb86a20s_writereg(state, 0x50, 0x50);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ val = rc;
+
+ rc = mb86a20s_writereg(state, 0x51, val | 0x01);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, val & 0x06);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int i;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Fill the length of each status counter */
+
+ /* Only global stats */
+ c->strength.len = 1;
+
+ /* Per-layer stats - 3 layers + global */
+ c->cnr.len = 4;
+ c->pre_bit_error.len = 4;
+ c->pre_bit_count.len = 4;
+ c->post_bit_error.len = 4;
+ c->post_bit_count.len = 4;
+ c->block_error.len = 4;
+ c->block_count.len = 4;
+
+ /* Signal is always available */
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = 0;
+
+ /* Put all of them at FE_SCALE_NOT_AVAILABLE */
+ for (i = 0; i < 4; i++) {
+ c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+}
+
+static int mb86a20s_get_stats(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc = 0, i;
+ u32 bit_error = 0, bit_count = 0;
+ u32 t_pre_bit_error = 0, t_pre_bit_count = 0;
+ u32 t_post_bit_error = 0, t_post_bit_count = 0;
+ u32 block_error = 0, block_count = 0;
+ u32 t_block_error = 0, t_block_count = 0;
+ int active_layers = 0, pre_ber_layers = 0, post_ber_layers = 0;
+ int per_layers = 0;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ mb86a20s_get_main_CNR(fe);
+
+ /* Get per-layer stats */
+ mb86a20s_get_blk_error_layer_CNR(fe);
+
+ for (i = 0; i < 3; i++) {
+ if (c->isdbt_layer_enabled & (1 << i)) {
+ /* Layer is active and has rc segments */
+ active_layers++;
+
+ /* Handle BER before vterbi */
+ rc = mb86a20s_get_pre_ber(fe, i,
+ &bit_error, &bit_count);
+ if (rc >= 0) {
+ c->pre_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[1 + i].uvalue += bit_error;
+ c->pre_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[1 + i].uvalue += bit_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->pre_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get BER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
}
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ pre_ber_layers++;
+
+ /* Handle BER post vterbi */
+ rc = mb86a20s_get_post_ber(fe, i,
+ &bit_error, &bit_count);
+ if (rc >= 0) {
+ c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[1 + i].uvalue += bit_error;
+ c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[1 + i].uvalue += bit_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->post_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get BER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
+ }
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ post_ber_layers++;
+
+ /* Handle Block errors for PER/UCB reports */
+ rc = mb86a20s_get_blk_error(fe, i,
+ &block_error,
+ &block_count);
+ if (rc >= 0) {
+ c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[1 + i].uvalue += block_error;
+ c->block_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[1 + i].uvalue += block_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->block_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get PER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
+
+ }
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ per_layers++;
+
+ /* Update total preBER */
+ t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue;
+ t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue;
+
+ /* Update total postBER */
+ t_post_bit_error += c->post_bit_error.stat[1 + i].uvalue;
+ t_post_bit_count += c->post_bit_count.stat[1 + i].uvalue;
+
+ /* Update total PER */
+ t_block_error += c->block_error.stat[1 + i].uvalue;
+ t_block_count += c->block_count.stat[1 + i].uvalue;
}
}
+ /*
+ * Start showing global count if at least one error count is
+ * available.
+ */
+ if (pre_ber_layers) {
+ /*
+ * At least one per-layer BER measure was read. We can now
+ * calculate the total BER
+ *
+ * Total Bit Error/Count is calculated as the sum of the
+ * bit errors on all active layers.
+ */
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue = t_pre_bit_error;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue = t_pre_bit_count;
+ } else {
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ /*
+ * Start showing global count if at least one error count is
+ * available.
+ */
+ if (post_ber_layers) {
+ /*
+ * At least one per-layer BER measure was read. We can now
+ * calculate the total BER
+ *
+ * Total Bit Error/Count is calculated as the sum of the
+ * bit errors on all active layers.
+ */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = t_post_bit_error;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue = t_post_bit_count;
+ } else {
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ if (per_layers) {
+ /*
+ * At least one per-layer UCB measure was read. We can now
+ * calculate the total UCB
+ *
+ * Total block Error/Count is calculated as the sum of the
+ * block errors on all active layers.
+ */
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue = t_block_error;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue = t_block_count;
+ } else {
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ return rc;
+}
+
+/*
+ * The functions below are called via DVB callbacks, so they need to
+ * properly use the I2C gate control
+ */
+
+static int mb86a20s_initfe(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+ u8 regD5 = 1;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Initialize the frontend */
+ rc = mb86a20s_writeregdata(state, mb86a20s_init);
+ if (rc < 0)
+ goto err;
+
+ if (!state->config->is_serial) {
+ regD5 &= ~1;
+
+ rc = mb86a20s_writereg(state, 0x50, 0xd5);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x51, regD5);
+ if (rc < 0)
+ goto err;
+ }
+
+err:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
+ if (rc < 0) {
+ state->need_init = true;
+ dev_info(&state->i2c->dev,
+ "mb86a20s: Init failed. Will try again later\n");
+ } else {
+ state->need_init = false;
+ dev_dbg(&state->i2c->dev, "Initialization succeeded.\n");
+ }
+ return rc;
+}
+
+static int mb86a20s_set_frontend(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+#if 0
+ /*
+ * FIXME: Properly implement the set frontend properties
+ */
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+#endif
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /*
+ * Gate should already be opened, but it doesn't hurt to
+ * double-check
+ */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.set_params(fe);
+
+ /*
+ * Make it more reliable: if, for some reason, the initial
+ * device initialization doesn't happen, initialize it when
+ * a SBTVD parameters are adjusted.
+ *
+ * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+ * the agc callback logic is not called during DVB attach time,
+ * causing mb86a20s to not be initialized with Kworld SBTVD.
+ * So, this hack is needed, in order to make Kworld SBTVD to work.
+ */
+ if (state->need_init)
+ mb86a20s_initfe(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
+ mb86a20s_reset_counters(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
+ fe_status_t *status)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Get lock */
+ rc = mb86a20s_read_status(fe, status);
+ if (!(*status & FE_HAS_LOCK)) {
+ mb86a20s_stats_not_ready(fe);
+ mb86a20s_reset_frontend_cache(fe);
+ }
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't read frontend lock status\n", __func__);
+ goto error;
+ }
+
+ /* Get signal strength */
+ rc = mb86a20s_read_signal_strength(fe);
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't reset VBER registers.\n", __func__);
+ mb86a20s_stats_not_ready(fe);
+ mb86a20s_reset_frontend_cache(fe);
+
+ rc = 0; /* Status is OK */
+ goto error;
+ }
+ /* Fill signal strength */
+ c->strength.stat[0].uvalue = rc;
+
+ if (*status & FE_HAS_LOCK) {
+ /* Get TMCC info*/
+ rc = mb86a20s_get_frontend(fe);
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't get FE TMCC data.\n", __func__);
+ rc = 0; /* Status is OK */
+ goto error;
+ }
+
+ /* Get statistics */
+ rc = mb86a20s_get_stats(fe);
+ if (rc < 0 && rc != -EBUSY) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't get FE statistics.\n", __func__);
+ rc = 0;
+ goto error;
+ }
+ rc = 0; /* Don't return EBUSY to userspace */
+ }
+ goto ok;
+
+error:
+ mb86a20s_stats_not_ready(fe);
+
+ok:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_read_signal_strength_from_cache(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+
+ *strength = c->strength.stat[0].uvalue;
+
return 0;
}
+static int mb86a20s_get_frontend_dummy(struct dvb_frontend *fe)
+{
+ /*
+ * get_frontend is now handled together with other stats
+ * retrival, when read_status() is called, as some statistics
+ * will depend on the layers detection.
+ */
+ return 0;
+};
+
static int mb86a20s_tune(struct dvb_frontend *fe,
bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
+ struct mb86a20s_state *state = fe->demodulator_priv;
int rc = 0;
- dprintk("\n");
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
if (re_tune)
rc = mb86a20s_set_frontend(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
- mb86a20s_read_status(fe, status);
+ mb86a20s_read_status_and_stats(fe, status);
return rc;
}
@@ -619,7 +1936,7 @@ static void mb86a20s_release(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- dprintk("\n");
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
kfree(state);
}
@@ -629,15 +1946,16 @@ static struct dvb_frontend_ops mb86a20s_ops;
struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
struct i2c_adapter *i2c)
{
+ struct mb86a20s_state *state;
u8 rev;
- /* allocate memory for the internal state */
- struct mb86a20s_state *state =
- kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
+ dev_dbg(&i2c->dev, "%s called.\n", __func__);
- dprintk("\n");
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
if (state == NULL) {
- rc("Unable to kzalloc\n");
+ dev_err(&i2c->dev,
+ "%s: unable to allocate memory for state\n", __func__);
goto error;
}
@@ -654,9 +1972,11 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
rev = mb86a20s_readreg(state, 0);
if (rev == 0x13) {
- printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
+ dev_info(&i2c->dev,
+ "Detected a Fujitsu mb86a20s frontend\n");
} else {
- printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
+ dev_dbg(&i2c->dev,
+ "Frontend revision %d is unknown - aborting.\n",
rev);
goto error;
}
@@ -690,9 +2010,9 @@ static struct dvb_frontend_ops mb86a20s_ops = {
.init = mb86a20s_initfe,
.set_frontend = mb86a20s_set_frontend,
- .get_frontend = mb86a20s_get_frontend,
- .read_status = mb86a20s_read_status,
- .read_signal_strength = mb86a20s_read_signal_strength,
+ .get_frontend = mb86a20s_get_frontend_dummy,
+ .read_status = mb86a20s_read_status_and_stats,
+ .read_signal_strength = mb86a20s_read_signal_strength_from_cache,
.tune = mb86a20s_tune,
};
diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h
index 29e3bb5496b8..5706621ad79d 100644
--- a/drivers/media/dvb-frontends/mt312.h
+++ b/drivers/media/dvb-frontends/mt312.h
@@ -36,7 +36,7 @@ struct mt312_config {
unsigned int voltage_inverted:1;
};
-#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MT312)
struct dvb_frontend *mt312_attach(const struct mt312_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h
index ca2562d6f289..451d904e1500 100644
--- a/drivers/media/dvb-frontends/mt352.h
+++ b/drivers/media/dvb-frontends/mt352.h
@@ -51,7 +51,7 @@ struct mt352_config
int (*demod_init)(struct dvb_frontend* fe);
};
-#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MT352)
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
index f3c84583770f..b518d545609e 100644
--- a/drivers/media/dvb-frontends/nxt200x.h
+++ b/drivers/media/dvb-frontends/nxt200x.h
@@ -42,7 +42,7 @@ struct nxt200x_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_NXT200X)
extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h
index 878eb38a075e..b5867c2ae681 100644
--- a/drivers/media/dvb-frontends/nxt6000.h
+++ b/drivers/media/dvb-frontends/nxt6000.h
@@ -33,7 +33,7 @@ struct nxt6000_config
u8 clock_inversion:1;
};
-#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_NXT6000)
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
index 1b8e04d973c8..938958386cb1 100644
--- a/drivers/media/dvb-frontends/or51132.h
+++ b/drivers/media/dvb-frontends/or51132.h
@@ -34,7 +34,7 @@ struct or51132_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_OR51132)
extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
index c625b57b4333..10cfc0579168 100644
--- a/drivers/media/dvb-frontends/or51211.c
+++ b/drivers/media/dvb-frontends/or51211.c
@@ -22,6 +22,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
@@ -44,9 +46,7 @@
static int debug;
#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG "or51211: " args); \
- } while (0)
+ do { if (debug) pr_debug(args); } while (0)
static u8 run_buf[] = {0x7f,0x01};
static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
@@ -80,8 +80,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
msg.buf = (u8 *)buf;
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk(KERN_WARNING "or51211: i2c_writebytes error "
- "(addr %02x, err == %i)\n", reg, err);
+ pr_warn("error (addr %02x, err == %i)\n", reg, err);
return -EREMOTEIO;
}
@@ -98,8 +97,7 @@ static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
msg.buf = buf;
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk(KERN_WARNING "or51211: i2c_readbytes error "
- "(addr %02x, err == %i)\n", reg, err);
+ pr_warn("error (addr %02x, err == %i)\n", reg, err);
return -EREMOTEIO;
}
@@ -118,11 +116,11 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
/* Get eprom data */
tudata[0] = 17;
if (i2c_writebytes(state,0x50,tudata,1)) {
- printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
+ pr_warn("error eprom addr\n");
return -1;
}
if (i2c_readbytes(state,0x50,&tudata[145],192)) {
- printk(KERN_WARNING "or51211: load_firmware error eprom\n");
+ pr_warn("error eprom\n");
return -1;
}
@@ -136,32 +134,32 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
state->config->reset(fe);
if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
- printk(KERN_WARNING "or51211: load_firmware error 1\n");
+ pr_warn("error 1\n");
return -1;
}
msleep(1);
if (i2c_writebytes(state,state->config->demod_address,
&fw->data[393],8125)) {
- printk(KERN_WARNING "or51211: load_firmware error 2\n");
+ pr_warn("error 2\n");
return -1;
}
msleep(1);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: load_firmware error 3\n");
+ pr_warn("error 3\n");
return -1;
}
/* Wait at least 5 msec */
msleep(10);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: load_firmware error 4\n");
+ pr_warn("error 4\n");
return -1;
}
msleep(10);
- printk("or51211: Done.\n");
+ pr_info("Done.\n");
return 0;
};
@@ -173,14 +171,14 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
state->config->setmode(fe, mode);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: setmode error 1\n");
+ pr_warn("error 1\n");
return -1;
}
/* Wait at least 5 msec */
msleep(10);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: setmode error 2\n");
+ pr_warn("error 2\n");
return -1;
}
@@ -196,7 +194,7 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
* normal +/-150kHz Carrier acquisition range
*/
if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
- printk(KERN_WARNING "or51211: setmode error 3\n");
+ pr_warn("error 3\n");
return -1;
}
@@ -206,14 +204,14 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
rec_buf[3] = 0x00;
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
- printk(KERN_WARNING "or51211: setmode error 5\n");
+ pr_warn("error 5\n");
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
- printk(KERN_WARNING "or51211: setmode error 6");
+ pr_warn("error 6\n");
return -1;
}
- dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
+ dprintk("rec status %02x %02x\n", rec_buf[10], rec_buf[11]);
return 0;
}
@@ -248,15 +246,15 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Receiver Status */
if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "or51132: read_status write error\n");
+ pr_warn("write error\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51132: read_status read error\n");
+ pr_warn("read error\n");
return -1;
}
- dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+ dprintk("%x %x\n", rec_buf[0], rec_buf[1]);
if (rec_buf[0] & 0x01) { /* Receiver Lock */
*status |= FE_HAS_SIGNAL;
@@ -306,20 +304,18 @@ static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
snd_buf[2] = 0x04;
if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "%s: error writing snr reg\n",
- __func__);
+ pr_warn("error writing snr reg\n");
return -1;
}
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "%s: read_status read error\n",
- __func__);
+ pr_warn("read_status read error\n");
return -1;
}
state->snr = calculate_snr(rec_buf[0], 89599047);
*snr = (state->snr) >> 16;
- dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
+ dprintk("noise = 0x%02x, snr = %d.%02d dB\n", rec_buf[0],
state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
return 0;
@@ -375,25 +371,24 @@ static int or51211_init(struct dvb_frontend* fe)
if (!state->initialized) {
/* Request the firmware, this will block until it uploads */
- printk(KERN_INFO "or51211: Waiting for firmware upload "
- "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
+ pr_info("Waiting for firmware upload (%s)...\n",
+ OR51211_DEFAULT_FIRMWARE);
ret = config->request_firmware(fe, &fw,
OR51211_DEFAULT_FIRMWARE);
- printk(KERN_INFO "or51211:Got Hotplug firmware\n");
+ pr_info("Got Hotplug firmware\n");
if (ret) {
- printk(KERN_WARNING "or51211: No firmware uploaded "
- "(timeout or file not found?)\n");
+ pr_warn("No firmware uploaded "
+ "(timeout or file not found?)\n");
return ret;
}
ret = or51211_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
- printk(KERN_WARNING "or51211: Writing firmware to "
- "device failed!\n");
+ pr_warn("Writing firmware to device failed!\n");
return ret;
}
- printk(KERN_INFO "or51211: Firmware upload complete.\n");
+ pr_info("Firmware upload complete.\n");
/* Set operation mode in Receiver 1 register;
* type 1:
@@ -406,7 +401,7 @@ static int or51211_init(struct dvb_frontend* fe)
*/
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error 5\n");
+ pr_warn("Load DVR Error 5\n");
return -1;
}
@@ -419,13 +414,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(30);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error A\n");
+ pr_warn("Load DVR Error A\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[10],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error B\n");
+ pr_warn("Load DVR Error B\n");
return -1;
}
@@ -436,13 +431,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error C\n");
+ pr_warn("Load DVR Error C\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[12],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error D\n");
+ pr_warn("Load DVR Error D\n");
return -1;
}
@@ -454,16 +449,14 @@ static int or51211_init(struct dvb_frontend* fe)
get_ver_buf[4] = i+1;
if (i2c_writebytes(state,state->config->demod_address,
get_ver_buf,5)) {
- printk(KERN_WARNING "or51211:Load DVR Error 6"
- " - %d\n",i);
+ pr_warn("Load DVR Error 6 - %d\n", i);
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2)) {
- printk(KERN_WARNING "or51211:Load DVR Error 7"
- " - %d\n",i);
+ pr_warn("Load DVR Error 7 - %d\n", i);
return -1;
}
/* If we didn't receive the right index, try again */
@@ -471,15 +464,11 @@ static int or51211_init(struct dvb_frontend* fe)
i--;
}
}
- dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
- rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
- rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
- rec_buf[8], rec_buf[9]);
+ dprintk("read_fwbits %10ph\n", rec_buf);
- printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
- " Status %02x\n",
- rec_buf[2], rec_buf[4],rec_buf[6],
- rec_buf[12],rec_buf[10]);
+ pr_info("ver TU%02x%02x%02x VSB mode %02x Status %02x\n",
+ rec_buf[2], rec_buf[4], rec_buf[6], rec_buf[12],
+ rec_buf[10]);
rec_buf[0] = 0x04;
rec_buf[1] = 0x00;
@@ -488,13 +477,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error 8\n");
+ pr_warn("Load DVR Error 8\n");
return -1;
}
msleep(20);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[8],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error 9\n");
+ pr_warn("Load DVR Error 9\n");
return -1;
}
state->initialized = 1;
diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h
index 3ce0508b898e..9a8ae936b62d 100644
--- a/drivers/media/dvb-frontends/or51211.h
+++ b/drivers/media/dvb-frontends/or51211.h
@@ -37,7 +37,7 @@ struct or51211_config
void (*sleep)(struct dvb_frontend * fe);
};
-#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_OR51211)
extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h
index ff308136d865..210049b5cf30 100644
--- a/drivers/media/dvb-frontends/s5h1420.h
+++ b/drivers/media/dvb-frontends/s5h1420.h
@@ -40,7 +40,7 @@ struct s5h1420_config
u8 serial_mpeg:1;
};
-#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S5H1420)
extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h
index a764a793c7d8..065ec67d4e30 100644
--- a/drivers/media/dvb-frontends/sp8870.h
+++ b/drivers/media/dvb-frontends/sp8870.h
@@ -35,7 +35,7 @@ struct sp8870_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_SP8870)
extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h
index 04eff6e0eef3..2cdc4e8bc9cd 100644
--- a/drivers/media/dvb-frontends/sp887x.h
+++ b/drivers/media/dvb-frontends/sp887x.h
@@ -17,7 +17,7 @@ struct sp887x_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_SP887X)
extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
index 98b200ce0c34..8d26ff6eb1db 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.h
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
@@ -142,7 +142,7 @@ struct stb0899_config {
int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
};
-#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STB0899)
extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
index 2ab096614b3f..3a1e40f3b8be 100644
--- a/drivers/media/dvb-frontends/stb6100.h
+++ b/drivers/media/dvb-frontends/stb6100.h
@@ -94,7 +94,7 @@ struct stb6100_state {
u32 reference;
};
-#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STB6100)
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
const struct stb6100_config *config,
diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h
index 3f8f9468f387..c8ff3639ce00 100644
--- a/drivers/media/dvb-frontends/stv0297.h
+++ b/drivers/media/dvb-frontends/stv0297.h
@@ -42,7 +42,7 @@ struct stv0297_config
u8 stop_during_read:1;
};
-#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0297)
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c
index 92a6075cd82f..b57ecf42e75a 100644
--- a/drivers/media/dvb-frontends/stv0299.c
+++ b/drivers/media/dvb-frontends/stv0299.c
@@ -420,7 +420,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long
do_gettimeofday (&nexttime);
if (debug_legacy_dish_switch)
- memcpy (&tv[0], &nexttime, sizeof (struct timeval));
+ tv[0] = nexttime;
stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
dvb_frontend_sleep_until(&nexttime, 32000);
diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h
index ba219b767a69..06f70fc8327b 100644
--- a/drivers/media/dvb-frontends/stv0299.h
+++ b/drivers/media/dvb-frontends/stv0299.h
@@ -95,7 +95,7 @@ struct stv0299_config
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
-#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0299)
extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index b551ca350e00..e5a87b57d855 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -524,11 +524,8 @@ void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_frequency) {
if ((tuner_ops->set_frequency(fe, frequency)) < 0)
@@ -552,11 +549,8 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_bandwidth) {
if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
@@ -1558,6 +1552,27 @@ static int stv0900_status(struct stv0900_internal *intp,
return locked;
}
+static int stv0900_set_mis(struct stv0900_internal *intp,
+ enum fe_stv0900_demod_num demod, int mis)
+{
+ enum fe_stv0900_error error = STV0900_NO_ERROR;
+
+ dprintk("%s\n", __func__);
+
+ if (mis < 0 || mis > 255) {
+ dprintk("Disable MIS filtering\n");
+ stv0900_write_bits(intp, FILTER_EN, 0);
+ } else {
+ dprintk("Enable MIS filtering - %d\n", mis);
+ stv0900_write_bits(intp, FILTER_EN, 1);
+ stv0900_write_reg(intp, ISIENTRY, mis);
+ stv0900_write_reg(intp, ISIBITENA, 0xff);
+ }
+
+ return error;
+}
+
+
static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
{
struct stv0900_state *state = fe->demodulator_priv;
@@ -1578,6 +1593,8 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
+ stv0900_set_mis(intp, demod, c->stream_id);
+
p_result.locked = FALSE;
p_search.path = demod;
p_search.frequency = c->frequency;
@@ -1935,6 +1952,9 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
if (err_stv0900)
goto error;
+ if (state->internal->chip_id >= 0x30)
+ state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
+
break;
default:
goto error;
diff --git a/drivers/media/dvb-frontends/stv0900_reg.h b/drivers/media/dvb-frontends/stv0900_reg.h
index 731afe93a823..511ed2a2d987 100644
--- a/drivers/media/dvb-frontends/stv0900_reg.h
+++ b/drivers/media/dvb-frontends/stv0900_reg.h
@@ -3446,8 +3446,11 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define R0900_P1_PDELCTRL1 0xf550
#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1)
#define F0900_P1_INV_MISMASK 0xf5500080
+#define INV_MISMASK FLDx(F0900_P1_INV_MISMASK)
#define F0900_P1_FILTER_EN 0xf5500020
+#define FILTER_EN FLDx(F0900_P1_FILTER_EN)
#define F0900_P1_EN_MIS00 0xf5500002
+#define EN_MIS00 FLDx(F0900_P1_EN_MIS00)
#define F0900_P1_ALGOSWRST 0xf5500001
#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST)
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index 4af20780fb9c..0a40edfad739 100644
--- a/drivers/media/dvb-frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -1167,11 +1167,8 @@ static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
struct dvb_tuner_ops *tuner_ops = NULL;
u32 freq = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_frequency) {
if ((tuner_ops->get_frequency(fe, &freq)) < 0)
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 13caec013902..f36eeefb76a6 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -4267,7 +4267,7 @@ err:
return -1;
}
-static int stv090x_set_tspath(struct stv090x_state *state)
+static int stv0900_set_tspath(struct stv090x_state *state)
{
u32 reg;
@@ -4538,6 +4538,121 @@ err:
return -1;
}
+static int stv0903_set_tspath(struct stv090x_state *state)
+{
+ u32 reg;
+
+ if (state->internal->dev_ver >= 0x20) {
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ default:
+ stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c);
+ break;
+ }
+ } else {
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ default:
+ stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+ break;
+ }
+ }
+
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_DVBCI:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ default:
+ break;
+ }
+
+ if (state->config->ts1_clk > 0) {
+ u32 speed;
+
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ default:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 4);
+ if (speed < 0x08)
+ speed = 0x08;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 32);
+ if (speed < 0x20)
+ speed = 0x20;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ }
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+ STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
+ goto err;
+ }
+
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(FE_ERROR, 1, "I/O error");
+ return -1;
+}
+
static int stv090x_init(struct dvb_frontend *fe)
{
struct stv090x_state *state = fe->demodulator_priv;
@@ -4600,8 +4715,13 @@ static int stv090x_init(struct dvb_frontend *fe)
if (stv090x_i2c_gate_ctrl(state, 0) < 0)
goto err;
- if (stv090x_set_tspath(state) < 0)
- goto err;
+ if (state->device == STV0900) {
+ if (stv0900_set_tspath(state) < 0)
+ goto err;
+ } else {
+ if (stv0903_set_tspath(state) < 0)
+ goto err;
+ }
return 0;
@@ -4642,23 +4762,26 @@ static int stv090x_setup(struct dvb_frontend *fe)
/* Stop Demod */
if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
+ goto err;
msleep(5);
/* Set No Tuner Mode */
if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
+ goto err;
/* I2C repeater OFF */
STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
+ goto err;
if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
goto err;
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 29cdc2b71314..0bd6adcfee8a 100644
--- a/drivers/media/dvb-frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -103,7 +103,7 @@ struct stv090x_config {
void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
};
-#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV090x)
extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index 47516753929a..bc4766db29c5 100644
--- a/drivers/media/dvb-frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -53,7 +53,7 @@ struct stv6110x_devctl {
};
-#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV6110x)
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h
index 04d19418bf20..e404b6e44802 100644
--- a/drivers/media/dvb-frontends/tda1002x.h
+++ b/drivers/media/dvb-frontends/tda1002x.h
@@ -57,7 +57,7 @@ struct tda10023_config {
u16 deltaf;
};
-#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10021)
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
@@ -69,8 +69,7 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
}
#endif // CONFIG_DVB_TDA10021
-#if defined(CONFIG_DVB_TDA10023) || \
- (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10023)
extern struct dvb_frontend *tda10023_attach(
const struct tda10023_config *config,
struct i2c_adapter *i2c, u8 pwm);
diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h
index 4e27ffb0f14e..dd283fbb61c0 100644
--- a/drivers/media/dvb-frontends/tda1004x.h
+++ b/drivers/media/dvb-frontends/tda1004x.h
@@ -117,7 +117,7 @@ struct tda1004x_state {
enum tda1004x_demod demod_type;
};
-#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA1004X)
extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 16a4bc54dbe7..2521f7e23018 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -30,7 +30,7 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
u8 buf[len+1];
struct i2c_msg msg[1] = {
{
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
@@ -59,12 +59,12 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
u8 buf[len];
struct i2c_msg msg[2] = {
{
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = I2C_M_RD,
.len = sizeof(buf),
.buf = buf,
@@ -1064,7 +1064,7 @@ static int tda10071_init(struct dvb_frontend *fe)
cmd.args[2] = 0x00;
cmd.args[3] = 0x00;
cmd.args[4] = 0x00;
- cmd.args[5] = 0x14;
+ cmd.args[5] = (priv->cfg.tuner_i2c_addr) ? priv->cfg.tuner_i2c_addr : 0x14;
cmd.args[6] = 0x00;
cmd.args[7] = 0x03;
cmd.args[8] = 0x02;
@@ -1202,6 +1202,20 @@ struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
goto error;
}
+ /* make sure demod i2c address is specified */
+ if (!config->demod_i2c_addr) {
+ dev_dbg(&i2c->dev, "%s: invalid demod i2c address!\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* make sure tuner i2c address is specified */
+ if (!config->tuner_i2c_addr) {
+ dev_dbg(&i2c->dev, "%s: invalid tuner i2c address!\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
/* setup the priv */
priv->i2c = i2c;
memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index 21163c4b555c..bff1c38df802 100644
--- a/drivers/media/dvb-frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -28,7 +28,13 @@ struct tda10071_config {
* Default: none, must set
* Values: 0x55,
*/
- u8 i2c_address;
+ u8 demod_i2c_addr;
+
+ /* Tuner I2C address.
+ * Default: none, must set
+ * Values: 0x14, 0x54, ...
+ */
+ u8 tuner_i2c_addr;
/* Max bytes I2C provider can write at once.
* Note: Buffer is taken from the stack currently!
diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h
index 61148c558d8d..458fe91c1b88 100644
--- a/drivers/media/dvb-frontends/tda10086.h
+++ b/drivers/media/dvb-frontends/tda10086.h
@@ -46,7 +46,7 @@ struct tda10086_config
enum tda10086_xtal xtal_freq;
};
-#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10086)
extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h
index ec7927aa75ae..03a0da6d5cf2 100644
--- a/drivers/media/dvb-frontends/tda665x.h
+++ b/drivers/media/dvb-frontends/tda665x.h
@@ -31,7 +31,7 @@ struct tda665x_config {
u32 ref_divider;
};
-#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA665x)
extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
const struct tda665x_config *config,
diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h
index 5a03c14a10e8..de6b1860dfdd 100644
--- a/drivers/media/dvb-frontends/tda8083.h
+++ b/drivers/media/dvb-frontends/tda8083.h
@@ -35,7 +35,7 @@ struct tda8083_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA8083)
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h
index 006e45351b94..55cf4ffcbfdf 100644
--- a/drivers/media/dvb-frontends/tda8261.h
+++ b/drivers/media/dvb-frontends/tda8261.h
@@ -34,7 +34,7 @@ struct tda8261_config {
enum tda8261_step step_size;
};
-#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA8261)
extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
index 1af1ee49b542..46710744173b 100644
--- a/drivers/media/dvb-frontends/tda8261_cfg.h
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
@@ -78,7 +78,7 @@ static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return err;
}
*bandwidth = t_state.bandwidth;
+ printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
}
- printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
return 0;
}
diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
index 89e97926ab23..5f0f20e7e4f8 100644
--- a/drivers/media/dvb-frontends/tda826x.h
+++ b/drivers/media/dvb-frontends/tda826x.h
@@ -35,7 +35,7 @@
* @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA826X)
extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
int has_loopthrough);
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
new file mode 100644
index 000000000000..ad7ad857ab2a
--- /dev/null
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -0,0 +1,373 @@
+/*
+ Montage Technology TS2020 - Silicon Tuner driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+ Copyright (C) 2009-2012 TurboSight.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dvb_frontend.h"
+#include "ts2020.h"
+
+#define TS2020_XTAL_FREQ 27000 /* in kHz */
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+struct ts2020_priv {
+ /* i2c details */
+ int i2c_address;
+ struct i2c_adapter *i2c;
+ u8 clk_out_div;
+ u32 frequency;
+};
+
+static int ts2020_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int ts2020_writereg(struct dvb_frontend *fe, int reg, int data)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg[] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ }
+ };
+ int err;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ err = i2c_transfer(priv->i2c, msg, 1);
+ if (err != 1) {
+ printk(KERN_ERR
+ "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n",
+ __func__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+static int ts2020_readreg(struct dvb_frontend *fe, u8 reg)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = priv->i2c_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_ERR "%s: reg=0x%x(error=%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return b1[0];
+}
+
+static int ts2020_sleep(struct dvb_frontend *fe)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf[] = { 10, 0 };
+ struct i2c_msg msg = {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c error\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int ts2020_init(struct dvb_frontend *fe)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+
+ ts2020_writereg(fe, 0x42, 0x73);
+ ts2020_writereg(fe, 0x05, priv->clk_out_div);
+ ts2020_writereg(fe, 0x20, 0x27);
+ ts2020_writereg(fe, 0x07, 0x02);
+ ts2020_writereg(fe, 0x11, 0xff);
+ ts2020_writereg(fe, 0x60, 0xf9);
+ ts2020_writereg(fe, 0x08, 0x01);
+ ts2020_writereg(fe, 0x00, 0x41);
+
+ return 0;
+}
+
+static int ts2020_tuner_gate_ctrl(struct dvb_frontend *fe, u8 offset)
+{
+ int ret;
+ ret = ts2020_writereg(fe, 0x51, 0x1f - offset);
+ ret |= ts2020_writereg(fe, 0x51, 0x1f);
+ ret |= ts2020_writereg(fe, 0x50, offset);
+ ret |= ts2020_writereg(fe, 0x50, 0x00);
+ msleep(20);
+ return ret;
+}
+
+static int ts2020_set_tuner_rf(struct dvb_frontend *fe)
+{
+ int reg;
+
+ reg = ts2020_readreg(fe, 0x3d);
+ reg &= 0x7f;
+ if (reg < 0x16)
+ reg = 0xa1;
+ else if (reg == 0x16)
+ reg = 0x99;
+ else
+ reg = 0xf9;
+
+ ts2020_writereg(fe, 0x60, reg);
+ reg = ts2020_tuner_gate_ctrl(fe, 0x08);
+
+ return reg;
+}
+
+static int ts2020_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u32 frequency = c->frequency;
+ s32 offset_khz;
+ u32 symbol_rate = (c->symbol_rate / 1000);
+ u32 f3db, gdiv28;
+ u16 value, ndiv, lpf_coeff;
+ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+ u8 lo = 0x01, div4 = 0x0;
+
+ /* Calculate frequency divider */
+ if (frequency < 1060000) {
+ lo |= 0x10;
+ div4 = 0x1;
+ ndiv = (frequency * 14 * 4) / TS2020_XTAL_FREQ;
+ } else
+ ndiv = (frequency * 14 * 2) / TS2020_XTAL_FREQ;
+ ndiv = ndiv + ndiv % 2;
+ ndiv = ndiv - 1024;
+
+ ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
+
+ /* Set frequency divider */
+ ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf);
+ ret |= ts2020_writereg(fe, 0x02, ndiv & 0xff);
+
+ ret |= ts2020_writereg(fe, 0x03, 0x06);
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x10);
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Tuner Frequency Range */
+ ret = ts2020_writereg(fe, 0x10, lo);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x08);
+
+ /* Tuner RF */
+ ret |= ts2020_set_tuner_rf(fe);
+
+ gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000;
+ ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff);
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x04);
+ if (ret < 0)
+ return -ENODEV;
+
+ value = ts2020_readreg(fe, 0x26);
+
+ f3db = (symbol_rate * 135) / 200 + 2000;
+ f3db += FREQ_OFFSET_LOW_SYM_RATE;
+ if (f3db < 7000)
+ f3db = 7000;
+ if (f3db > 40000)
+ f3db = 40000;
+
+ gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+ mlpf_max = gdiv28 * 135 / 100;
+ mlpf_min = gdiv28 * 78 / 100;
+ if (mlpf_max > 63)
+ mlpf_max = 63;
+
+ lpf_coeff = 2766;
+
+ nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+ (TS2020_XTAL_FREQ / 1000) + 1) / 2;
+ if (nlpf > 23)
+ nlpf = 23;
+ if (nlpf < 1)
+ nlpf = 1;
+
+ lpf_mxdiv = (nlpf * (TS2020_XTAL_FREQ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+
+ if (lpf_mxdiv < mlpf_min) {
+ nlpf++;
+ lpf_mxdiv = (nlpf * (TS2020_XTAL_FREQ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+ }
+
+ if (lpf_mxdiv > mlpf_max)
+ lpf_mxdiv = mlpf_max;
+
+ ret = ts2020_writereg(fe, 0x04, lpf_mxdiv);
+ ret |= ts2020_writereg(fe, 0x06, nlpf);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x04);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x01);
+
+ msleep(80);
+ /* calculate offset assuming 96000kHz*/
+ offset_khz = (ndiv - ndiv % 2 + 1024) * TS2020_XTAL_FREQ
+ / (6 + 8) / (div4 + 1) / 2;
+
+ priv->frequency = offset_khz;
+
+ return (ret < 0) ? -EINVAL : 0;
+}
+
+static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+/* read TS2020 signal strength */
+static int ts2020_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ u16 sig_reading, sig_strength;
+ u8 rfgain, bbgain;
+
+ rfgain = ts2020_readreg(fe, 0x3d) & 0x1f;
+ bbgain = ts2020_readreg(fe, 0x21) & 0x1f;
+
+ if (rfgain > 15)
+ rfgain = 15;
+ if (bbgain > 13)
+ bbgain = 13;
+
+ sig_reading = rfgain * 2 + bbgain * 3;
+
+ sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
+
+ /* cook the value to be suitable for szap-s2 human readable output */
+ *signal_strength = sig_strength * 1000;
+
+ return 0;
+}
+
+static struct dvb_tuner_ops ts2020_tuner_ops = {
+ .info = {
+ .name = "TS2020",
+ .frequency_min = 950000,
+ .frequency_max = 2150000
+ },
+ .init = ts2020_init,
+ .release = ts2020_release,
+ .sleep = ts2020_sleep,
+ .set_params = ts2020_set_params,
+ .get_frequency = ts2020_get_frequency,
+ .get_rf_strength = ts2020_read_signal_strength,
+};
+
+struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct ts2020_priv *priv = NULL;
+ u8 buf;
+
+ priv = kzalloc(sizeof(struct ts2020_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c_address = config->tuner_address;
+ priv->i2c = i2c;
+ priv->clk_out_div = config->clk_out_div;
+ fe->tuner_priv = priv;
+
+ /* Wake Up the tuner */
+ if ((0x03 & ts2020_readreg(fe, 0x00)) == 0x00) {
+ ts2020_writereg(fe, 0x00, 0x01);
+ msleep(2);
+ }
+
+ ts2020_writereg(fe, 0x00, 0x03);
+ msleep(2);
+
+ /* Check the tuner version */
+ buf = ts2020_readreg(fe, 0x00);
+ if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81))
+ printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__);
+ else {
+ printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf);
+ kfree(priv);
+ return NULL;
+ }
+
+ memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(ts2020_attach);
+
+MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
+MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h
new file mode 100644
index 000000000000..c7e64afa614a
--- /dev/null
+++ b/drivers/media/dvb-frontends/ts2020.h
@@ -0,0 +1,50 @@
+/*
+ Montage Technology TS2020 - Silicon Tuner driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+ Copyright (C) 2009-2012 TurboSight.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TS2020_H
+#define TS2020_H
+
+#include <linux/dvb/frontend.h>
+
+struct ts2020_config {
+ u8 tuner_address;
+ u8 clk_out_div;
+};
+
+#if defined(CONFIG_DVB_TS2020) || \
+ (defined(CONFIG_DVB_TS2020_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *ts2020_attach(
+ struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ts2020_attach(
+ struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* TS2020_H */
diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h
index f83dbd5e42ae..83a9c30e67ca 100644
--- a/drivers/media/dvb-frontends/tua6100.h
+++ b/drivers/media/dvb-frontends/tua6100.h
@@ -34,7 +34,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUA6100)
extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h
index e902ed634ec3..c073f353ac38 100644
--- a/drivers/media/dvb-frontends/ves1820.h
+++ b/drivers/media/dvb-frontends/ves1820.h
@@ -41,7 +41,7 @@ struct ves1820_config
u8 selagc:1;
};
-#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_VES1820)
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h
index 8a5a49e808f6..2307caea6aec 100644
--- a/drivers/media/dvb-frontends/ves1x93.h
+++ b/drivers/media/dvb-frontends/ves1x93.h
@@ -40,7 +40,7 @@ struct ves1x93_config
u8 invert_pwm:1;
};
-#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_VES1X93)
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h
index 6e3ca9eed048..50c1004aef36 100644
--- a/drivers/media/dvb-frontends/zl10353.h
+++ b/drivers/media/dvb-frontends/zl10353.h
@@ -47,7 +47,7 @@ struct zl10353_config
u8 pll_0; /* default: 0x15 */
};
-#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ZL10353)
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
struct i2c_adapter *i2c);
#else