Merge branch 'topic/si476x' into patchwork
* topic/si476x:
Revert "[media] mfd: Add chip properties handling code for SI476X MFD"
Revert "[media] mfd: Add the main bulk of core driver for SI476x code"
Revert "[media] mfd: Add commands abstraction layer for SI476X MFD"
[media] v4l2: Add a V4L2 driver for SI476X MFD
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 399e104..335a8f4 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -124,8 +124,7 @@
#define USB_PID_DIBCOM_STK7770P 0x1e80
#define USB_PID_DIBCOM_NIM7090 0x1bb2
#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4
-#define USB_PID_DIBCOM_TFE7090E 0x1bb7
-#define USB_PID_DIBCOM_TFE7790E 0x1e6e
+#define USB_PID_DIBCOM_TFE7790P 0x1e6e
#define USB_PID_DIBCOM_NIM9090M 0x2383
#define USB_PID_DIBCOM_NIM9090MD 0x2384
#define USB_PID_DPOSH_M9206_COLD 0x9206
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index d9fe60b..f9916b8 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -528,20 +528,19 @@
u16 PllCfg, i, v;
HARD_RESET(state);
-
dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
- dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
+ if (cfg->in_soc)
+ return;
- if (!cfg->in_soc) {
- /* adcClkOutRatio=8->7, release reset */
- dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
- if (cfg->clkoutdrive != 0)
- dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
- | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
- else
- dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
- | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
- }
+ dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
+ /* adcClkOutRatio=8->7, release reset */
+ dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+ if (cfg->clkoutdrive != 0)
+ dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+ | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+ else
+ dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+ | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
/* Read Pll current config * */
PllCfg = dib0090_read_reg(state, 0x21);
@@ -694,192 +693,174 @@
EXPORT_SYMBOL(dib0090_dcc_freq);
static const u16 bb_ramp_pwm_normal_socs[] = {
- 550, /* max BB gain in 10th of dB */
- (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 550, /* max BB gain in 10th of dB */
+ (1<<9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
440,
- (4 << 9) | 0, /* BB_RAMP3 = 26dB */
- (0 << 9) | 208, /* BB_RAMP4 */
- (4 << 9) | 208, /* BB_RAMP5 = 29dB */
- (0 << 9) | 440, /* BB_RAMP6 */
+ (4 << 9) | 0, /* BB_RAMP3 = 26dB */
+ (0 << 9) | 208, /* BB_RAMP4 */
+ (4 << 9) | 208, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 440, /* BB_RAMP6 */
};
-static const u16 rf_ramp_pwm_cband_7090[] = {
- 280, /* max RF gain in 10th of dB */
- 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 504, /* ramp_max = maximum X used on the ramp */
- (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
- (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
- (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
- (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
- (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
- (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
- (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
- (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
+static const u16 rf_ramp_pwm_cband_7090p[] = {
+ 280, /* max RF gain in 10th of dB */
+ 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 504, /* ramp_max = maximum X used on the ramp */
+ (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
+ (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
+ (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
+ (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
+ (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
+ (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
+ (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
+ (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
};
-static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
- 186,
- 40,
- 746,
- (10 << 10) | 345,
- (0 << 10) | 746,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (28 << 10) | 200,
- (0 << 10) | 345,
- (20 << 10) | 0,
- (0 << 10) | 200,
+static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = {
+ 186, /* max RF gain in 10th of dB */
+ 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 746, /* ramp_max = maximum X used on the ramp */
+ (10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */
+ (0 << 10) | 746, /* RF_RAMP6, LNA 1 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
+ (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
+ (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
+ (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
+ (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
};
-static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
- 86,
- 40,
- 345,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (28 << 10) | 200,
- (0 << 10) | 345,
- (20 << 10) | 0,
- (0 << 10) | 200,
+static const u16 rf_ramp_pwm_cband_7090e_aci[] = {
+ 86, /* max RF gain in 10th of dB */
+ 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 345, /* ramp_max = maximum X used on the ramp */
+ (0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */
+ (0 << 10) | 0, /* RF_RAMP6, LNA 1 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
+ (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
+ (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
+ (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
+ (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
};
static const u16 rf_ramp_pwm_cband_8090[] = {
- 345, /* max RF gain in 10th of dB */
- 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 1000, /* ramp_max = maximum X used on the ramp */
- (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
- (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
- (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
- (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
- (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
- (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
- (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
- (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
+ 345, /* max RF gain in 10th of dB */
+ 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1000, /* ramp_max = maximum X used on the ramp */
+ (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
+ (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
+ (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
+ (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
+ (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
+ (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
+ (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
+ (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf_7090[] = {
- 407, /* max RF gain in 10th of dB */
- 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 529, /* ramp_max = maximum X used on the ramp */
- (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
- (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
- (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
- (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
- (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
- (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
- (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
- (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
+ 407, /* max RF gain in 10th of dB */
+ 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 529, /* ramp_max = maximum X used on the ramp */
+ (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
+ (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
+ (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
+ (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
+ (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
+ (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
+ (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
+ (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf_8090[] = {
- 388, /* max RF gain in 10th of dB */
- 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 1008, /* ramp_max = maximum X used on the ramp */
- (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
- (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
- (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
- (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
- (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
- (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
- (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
- (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
+ 388, /* max RF gain in 10th of dB */
+ 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1008, /* ramp_max = maximum X used on the ramp */
+ (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
+ (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
+ (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
+ (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
+ (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
+ (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
+ (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
+ (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
+};
+
+/* GENERAL PWM ramp definition for all other Krosus */
+static const u16 bb_ramp_pwm_normal[] = {
+ 500, /* max BB gain in 10th of dB */
+ 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 400,
+ (2 << 9) | 0, /* BB_RAMP3 = 21dB */
+ (0 << 9) | 168, /* BB_RAMP4 */
+ (2 << 9) | 168, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 400, /* BB_RAMP6 */
+};
+
+static const u16 bb_ramp_pwm_boost[] = {
+ 550, /* max BB gain in 10th of dB */
+ 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 440,
+ (2 << 9) | 0, /* BB_RAMP3 = 26dB */
+ (0 << 9) | 208, /* BB_RAMP4 */
+ (2 << 9) | 208, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 440, /* BB_RAMP6 */
};
static const u16 rf_ramp_pwm_cband[] = {
- 0, /* max RF gain in 10th of dB */
- 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 0, /* ramp_max = maximum X used on the ramp */
- (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
- (0 << 10) | 0, /* 0x2d, LNA 1 */
- (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
- (0 << 10) | 0, /* 0x2f, LNA 2 */
- (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
- (0 << 10) | 0, /* 0x31, LNA 3 */
- (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
- (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_vhf[] = {
- 412, /* max RF gain in 10th of dB */
- 132, 307, 127, /* LNA1, 13.2dB */
- 105, 412, 255, /* LNA2, 10.5dB */
- 50, 50, 127, /* LNA3, 5dB */
- 125, 175, 127, /* LNA4, 12.5dB */
- 0, 0, 127, /* CBAND, 0dB */
-};
-
-static const u16 rf_ramp_uhf[] = {
- 412, /* max RF gain in 10th of dB */
- 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
- 105, 412, 255, /* LNA2 : 10.5 dB */
- 50, 50, 127, /* LNA3 : 5.0 dB */
- 125, 175, 127, /* LNA4 : 12.5 dB */
- 0, 0, 127, /* CBAND : 0.0 dB */
-};
-
-static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
-{
- 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
- 84, 314, 127, /* LNA1 */
- 80, 230, 255, /* LNA2 */
- 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
- 70, 70, 127, /* LNA4 */
- 0, 0, 127, /* CBAND */
-};
-
-static const u16 rf_ramp_cband[] = {
- 332, /* max RF gain in 10th of dB */
- 132, 252, 127, /* LNA1, dB */
- 80, 332, 255, /* LNA2, dB */
- 0, 0, 127, /* LNA3, dB */
- 0, 0, 127, /* LNA4, dB */
- 120, 120, 127, /* LT1 CBAND */
+ 314, /* max RF gain in 10th of dB */
+ 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1023, /* ramp_max = maximum X used on the ramp */
+ (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
+ (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */
+ (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
+ (0 << 10) | 742, /* RF_RAMP6, LNA 2 */
+ (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
+ (0 << 10) | 468, /* RF_RAMP8, LNA 3 */
+ (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
+ (0 << 10) | 233, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_vhf[] = {
- 404, /* max RF gain in 10th of dB */
- 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 1011, /* ramp_max = maximum X used on the ramp */
- (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
- (0 << 10) | 756, /* 0x2d, LNA 1 */
- (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
- (0 << 10) | 1011, /* 0x2f, LNA 2 */
- (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
- (0 << 10) | 417, /* 0x31, LNA 3 */
- (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
- (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
+ 398, /* max RF gain in 10th of dB */
+ 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 954, /* ramp_max = maximum X used on the ramp */
+ (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
+ (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
+ (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
+ (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
+ (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
+ (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
+ (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
+ (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf[] = {
- 404, /* max RF gain in 10th of dB */
- 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 1011, /* ramp_max = maximum X used on the ramp */
- (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
- (0 << 10) | 756, /* 0x2d, LNA 1 */
- (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
- (0 << 10) | 1011, /* 0x2f, LNA 2 */
- (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
- (0 << 10) | 127, /* 0x31, LNA 3 */
- (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
- (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
+ 398, /* max RF gain in 10th of dB */
+ 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 954, /* ramp_max = maximum X used on the ramp */
+ (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
+ (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
+ (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
+ (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
+ (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
+ (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
+ (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
+ (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
};
-static const u16 bb_ramp_boost[] = {
- 550, /* max BB gain in 10th of dB */
- 260, 260, 26, /* BB1, 26dB */
- 290, 550, 29, /* BB2, 29dB */
-};
-
-static const u16 bb_ramp_pwm_normal[] = {
- 500, /* max RF gain in 10th of dB */
- 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
- 400,
- (2 << 9) | 0, /* 0x35 = 21dB */
- (0 << 9) | 168, /* 0x36 */
- (2 << 9) | 168, /* 0x37 = 29dB */
- (0 << 9) | 400, /* 0x38 */
+static const u16 rf_ramp_pwm_sband[] = {
+ 253, /* max RF gain in 10th of dB */
+ 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 961,
+ (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
+ (0 << 10) | 508, /* RF_RAMP4, LNA 1 */
+ (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
+ (0 << 10) | 961, /* RF_RAMP6, LNA 2 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 3 */
+ (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
+ (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
};
struct slope {
@@ -1089,70 +1070,69 @@
void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
{
struct dib0090_state *state = fe->tuner_priv;
- /* reset the AGC */
+ u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
+ u16 *rf_ramp = NULL;
+ u8 en_pwm_rf_mux = 1;
+ /* reset the AGC */
if (state->config->use_pwm_agc) {
-#ifdef CONFIG_BAND_SBAND
- if (state->current_band == BAND_SBAND) {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
- } else
-#endif
-#ifdef CONFIG_BAND_CBAND
if (state->current_band == BAND_CBAND) {
if (state->identity.in_soc) {
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
- else if (state->identity.version == SOC_7090_P1G_11R1
- || state->identity.version == SOC_7090_P1G_21R1) {
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
+ else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
if (state->config->is_dib7090e) {
if (state->rf_ramp == NULL)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
else
- dib0090_set_rframp_pwm(state, state->rf_ramp);
+ rf_ramp = (u16 *)state->rf_ramp;
} else
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
}
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
- }
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband;
} else
-#endif
-#ifdef CONFIG_BAND_VHF
- if (state->current_band == BAND_VHF) {
- if (state->identity.in_soc) {
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
- }
- } else
-#endif
- {
- if (state->identity.in_soc) {
- if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
- else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
- }
- }
- if (state->rf_ramp[0] != 0)
- dib0090_write_reg(state, 0x32, (3 << 11));
+ if (state->current_band == BAND_VHF) {
+ if (state->identity.in_soc) {
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+ /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
+ } else if (state->current_band == BAND_UHF) {
+ if (state->identity.in_soc) {
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+ if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
+ else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
+ }
+ if (rf_ramp)
+ dib0090_set_rframp_pwm(state, rf_ramp);
+ dib0090_set_bbramp_pwm(state, bb_ramp);
+
+ /* activate the ramp generator using PWM control */
+ dprintk("ramp RF gain = %d BAND = %s version = %d", state->rf_ramp[0], (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", state->identity.version & 0x1f);
+
+ if ((state->rf_ramp[0] == 0) || (state->current_band == BAND_CBAND && (state->identity.version & 0x1f) <= P1D_E_F)) {
+ dprintk("DE-Engage mux for direct gain reg control");
+ en_pwm_rf_mux = 0;
+ } else
+ dprintk("Engage mux for PWM control");
+
+ dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
+
+ /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
+ if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+ dib0090_write_reg(state, 0x04, 3);
else
- dib0090_write_reg(state, 0x32, (0 << 11));
-
- dib0090_write_reg(state, 0x04, 0x03);
- dib0090_write_reg(state, 0x39, (1 << 10));
+ dib0090_write_reg(state, 0x04, 1);
+ dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
}
}
-
EXPORT_SYMBOL(dib0090_pwm_gain_reset);
void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
@@ -1193,22 +1173,22 @@
#endif
#ifdef CONFIG_BAND_VHF
if (state->current_band == BAND_VHF && !state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_vhf);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_vhf);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
} else
#endif
#ifdef CONFIG_BAND_CBAND
if (state->current_band == BAND_CBAND && !state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_cband);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_cband);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
} else
#endif
if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
} else {
- dib0090_set_rframp(state, rf_ramp_uhf);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_uhf);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
}
dib0090_write_reg(state, 0x32, 0);
@@ -1553,14 +1533,20 @@
if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
c = 32;
+ else
+ c += 14;
if ((h >= HR_MAX) || (h <= HR_MIN))
h = 34;
if ((n >= POLY_MAX) || (n <= POLY_MIN))
n = 3;
- dib0090_write_reg(state, 0x13, (h << 10)) ;
- e2 = (n<<11) | ((h>>2)<<6) | (c);
- dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
+ if ((c >= CAP_VALUE_MIN) && (c <= CAP_VALUE_MAX)
+ && (h >= HR_MIN) && (h <= HR_MAX)
+ && (n >= POLY_MIN) && (n <= POLY_MAX)) {
+ dib0090_write_reg(state, 0x13, (h << 10));
+ e2 = (n << 11) | ((h >> 2)<<6) | c;
+ dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
+ }
}
}
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 3e1eefa..effb87f 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -429,6 +429,13 @@
}
EXPORT_SYMBOL(dib7000p_get_agc_values);
+int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ return dib7000p_write_word(state, 108, v);
+}
+EXPORT_SYMBOL(dib7000p_set_agc1_min);
+
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
@@ -821,6 +828,7 @@
u8 agc_split;
u16 reg;
u32 upd_demod_gain_period = 0x1000;
+ s32 frequency_offset = 0;
switch (state->agc_state) {
case 0:
@@ -841,7 +849,14 @@
if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
return -1;
- dib7000p_set_dds(state, 0);
+ if (demod->ops.tuner_ops.get_frequency) {
+ u32 frequency_tuner;
+
+ demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
+ frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
+ }
+
+ dib7000p_set_dds(state, frequency_offset);
ret = 7;
(*agc_state)++;
break;
diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
index cf5e779..d08cdff 100644
--- a/drivers/media/dvb-frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -63,6 +63,7 @@
extern int dib7090_slave_reset(struct dvb_frontend *fe);
extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
+extern int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v);
#else
static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
{
@@ -154,6 +155,12 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
}
+
+static inline int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
#endif
#endif
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 1f3bcb5..1d719cc 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -23,8 +23,8 @@
#define LAYER_B 2
#define LAYER_C 3
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
#define MAX_NUMBER_OF_FRONTENDS 6
+/* #define DIB8000_AGC_FREEZE */
static int debug;
module_param(debug, int, 0644);
@@ -32,8 +32,6 @@
#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
-#define FE_STATUS_TUNE_FAILED 0
-
struct i2c_device {
struct i2c_adapter *adap;
u8 addr;
@@ -42,6 +40,23 @@
struct mutex *i2c_buffer_lock;
};
+enum param_loop_step {
+ LOOP_TUNE_1,
+ LOOP_TUNE_2
+};
+
+enum dib8000_autosearch_step {
+ AS_START = 0,
+ AS_SEARCHING_FFT,
+ AS_SEARCHING_GUARD,
+ AS_DONE = 100,
+};
+
+enum timeout_mode {
+ SYMBOL_DEPENDENT_OFF = 0,
+ SYMBOL_DEPENDENT_ON,
+};
+
struct dib8000_state {
struct dib8000_config cfg;
@@ -72,7 +87,7 @@
u16 revision;
u8 isdbt_cfg_loaded;
enum frontend_tune_state tune_state;
- u32 status;
+ s32 status;
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
@@ -85,6 +100,30 @@
u16 tuner_enable;
struct i2c_adapter dib8096p_tuner_adap;
+ u16 current_demod_bw;
+
+ u16 seg_mask;
+ u16 seg_diff_mask;
+ u16 mode;
+ u8 layer_b_nb_seg;
+ u8 layer_c_nb_seg;
+
+ u8 channel_parameters_set;
+ u16 autosearch_state;
+ u16 found_nfft;
+ u16 found_guard;
+ u8 subchannel;
+ u8 symbol_duration;
+ u32 timeout;
+ u8 longest_intlv_layer;
+ u16 output_mode;
+
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1_max;
+ u16 agc1_min;
+ u16 agc2_max;
+ u16 agc2_min;
+#endif
};
enum dib8000_power_mode {
@@ -338,9 +377,9 @@
static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
{
struct dib8000_state *state = fe->demodulator_priv;
-
u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
+ state->output_mode = mode;
outreg = 0;
fifo_threshold = 1792;
smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
@@ -399,8 +438,9 @@
static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
{
struct dib8000_state *state = fe->demodulator_priv;
- u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ dprintk("set diversity input to %i", onoff);
if (!state->differential_constellation) {
dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
@@ -424,6 +464,13 @@
dib8000_write_word(state, 271, 1);
break;
}
+
+ if (state->revision == 0x8002) {
+ tmp = dib8000_read_word(state, 903);
+ dib8000_write_word(state, 903, tmp & ~(1 << 3));
+ msleep(30);
+ dib8000_write_word(state, 903, tmp | (1 << 3));
+ }
return 0;
}
@@ -468,27 +515,6 @@
dib8000_write_word(state, 1280, reg_1280);
}
-static int dib8000_init_sdram(struct dib8000_state *state)
-{
- u16 reg = 0;
- dprintk("Init sdram");
-
- reg = dib8000_read_word(state, 274)&0xfff0;
- /* P_dintlv_delay_ram = 7 because of MobileSdram */
- dib8000_write_word(state, 274, reg | 0x7);
-
- dib8000_write_word(state, 1803, (7<<2));
-
- reg = dib8000_read_word(state, 1280);
- /* force restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg | (1<<2));
-
- /* release restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg);
-
- return 0;
-}
-
static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
{
int ret = 0;
@@ -584,18 +610,23 @@
static int dib8000_sad_calib(struct dib8000_state *state)
{
- if (state->revision == 0x8090) {
- dprintk("%s: the sad calibration is not needed for the dib8096P",
- __func__);
- return 0;
- }
- /* internal */
- dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
- dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
+ u8 sad_sel = 3;
- /* do the calibration */
- dib8000_write_word(state, 923, (1 << 0));
- dib8000_write_word(state, 923, (0 << 0));
+ if (state->revision == 0x8090) {
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ dib8000_write_word(state, 923, 2048);
+
+ dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ } else {
+ /* internal */
+ dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
+ dib8000_write_word(state, 924, 776);
+
+ /* do the calibration */
+ dib8000_write_word(state, 923, (1 << 0));
+ dib8000_write_word(state, 923, (0 << 0));
+ }
msleep(1);
return 0;
@@ -609,8 +640,8 @@
state->wbd_ref = value;
return dib8000_write_word(state, 106, value);
}
-
EXPORT_SYMBOL(dib8000_set_wbd_ref);
+
static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
{
dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
@@ -685,20 +716,23 @@
}
int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll)
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
- u8 loopdiv, prediv;
+ u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
u32 internal, xtal;
/* get back old values */
prediv = reg_1856 & 0x3f;
loopdiv = (reg_1856 >> 6) & 0x3f;
- if ((pll != NULL) && (pll->pll_prediv != prediv ||
- pll->pll_ratio != loopdiv)) {
- dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if ((pll == NULL) || (pll->pll_prediv == prediv &&
+ pll->pll_ratio == loopdiv))
+ return -EINVAL;
+
+ dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if (state->revision == 0x8090) {
reg_1856 &= 0xf000;
reg_1857 = dib8000_read_word(state, 1857);
/* disable PLL */
@@ -729,10 +763,33 @@
reg_1856 = dib8000_read_word(state, 1856);
dprintk("PLL Updated with prediv = %d and loopdiv = %d",
reg_1856&0x3f, (reg_1856>>6)&0x3f);
+ } else {
+ if (bw != state->current_demod_bw) {
+ /** Bandwidth change => force PLL update **/
+ dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
- return 0;
- }
- return -EINVAL;
+ if (state->cfg.pll->pll_prediv != oldprediv) {
+ /** Full PLL change only if prediv is changed **/
+
+ /** full update => bypass and reconfigure **/
+ dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
+ dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
+ dib8000_reset_pll(state);
+ dib8000_write_word(state, 898, 0x0004); /* sad */
+ } else
+ ratio = state->cfg.pll->pll_ratio;
+
+ state->current_demod_bw = bw;
+ }
+
+ if (ratio != 0) {
+ /** ratio update => only change ratio **/
+ dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
+ dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
+ }
+}
+
+ return 0;
}
EXPORT_SYMBOL(dib8000_update_pll);
@@ -928,7 +985,7 @@
dib8000_set_power_mode(state, DIB8000_POWER_ALL);
/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
- dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
+ dib8000_set_adc_state(state, DIBX000_ADC_OFF);
/* restart all parts */
dib8000_write_word(state, 770, 0xffff);
@@ -992,12 +1049,11 @@
l = *n++;
}
}
- if (state->revision != 0x8090)
- dib8000_write_word(state, 903, (0 << 4) | 2);
+
state->isdbt_cfg_loaded = 0;
//div_cfg override for special configs
- if (state->cfg.div_cfg != 0)
+ if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
dib8000_write_word(state, 903, state->cfg.div_cfg);
/* unforce divstr regardless whether i2c enumeration was done or not */
@@ -1006,10 +1062,12 @@
dib8000_set_bandwidth(fe, 6000);
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
- if (state->revision != 0x8090) {
- dib8000_sad_calib(state);
+ dib8000_sad_calib(state);
+ if (state->revision != 0x8090)
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
- }
+
+ /* ber_rs_len = 3 */
+ dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
@@ -1441,6 +1499,7 @@
u8 prefer_mpeg_mux_use = 1;
int ret = 0;
+ state->output_mode = mode;
dib8096p_host_bus_drive(state, 1);
fifo_threshold = 1792;
@@ -1879,782 +1938,637 @@
};
static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
-static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
{
- u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
- u8 guard, crate, constellation, timeI;
- u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
- const s16 *ncoeff = NULL, *ana_fe;
- u16 tmcc_pow = 0;
- u16 coff_pow = 0x2800;
- u16 init_prbs = 0xfff;
- u16 ana_gain = 0;
+ u8 cr, constellation, time_intlv;
- if (state->revision == 0x8090)
- dib8000_init_sdram(state);
-
- if (state->ber_monitored_layer != LAYER_ALL)
- dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
- else
- dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
-
- i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
- dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- //compute new dds_freq for the seg and adjust prbs
- int seg_offset =
- state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
- int clk = state->cfg.pll->internal;
- u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
- int dds_offset = seg_offset * segtodds;
- int new_dds, sub_channel;
- if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- dds_offset -= (int)(segtodds / 2);
-
- if (state->cfg.pll->ifreq == 0) {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
- dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
- new_dds = dds_offset;
- } else
- new_dds = dds_offset;
-
- // We shift tuning frequency if the wanted segment is :
- // - the segment of center frequency with an odd total number of segments
- // - the segment to the left of center frequency with an even total number of segments
- // - the segment to the right of center frequency with an even total number of segments
- if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- )) {
- new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
- }
- } else {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
- new_dds = state->cfg.pll->ifreq - dds_offset;
- else
- new_dds = state->cfg.pll->ifreq + dds_offset;
- }
- dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
- if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
- else
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
- sub_channel -= 6;
-
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
- || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
- } else {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
- }
-
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_2K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x423;
- break; // 02~04
- case -4:
- init_prbs = 0x9;
- break; // 05~07
- case -3:
- init_prbs = 0x5C7;
- break; // 08~10
- case -2:
- init_prbs = 0x7A6;
- break; // 11~13
- case -1:
- init_prbs = 0x3D8;
- break; // 14~16
- case 0:
- init_prbs = 0x527;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x79B;
- break; // 23~25
- case 3:
- init_prbs = 0x3D6;
- break; // 26~28
- case 4:
- init_prbs = 0x3A2;
- break; // 29~31
- case 5:
- init_prbs = 0x53B;
- break; // 32~34
- case 6:
- init_prbs = 0x2F4;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x213;
- break; // 38~40
- }
- break;
-
- case TRANSMISSION_MODE_4K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x208;
- break; // 02~04
- case -4:
- init_prbs = 0xC3;
- break; // 05~07
- case -3:
- init_prbs = 0x7B9;
- break; // 08~10
- case -2:
- init_prbs = 0x423;
- break; // 11~13
- case -1:
- init_prbs = 0x5C7;
- break; // 14~16
- case 0:
- init_prbs = 0x3D8;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x3D6;
- break; // 23~25
- case 3:
- init_prbs = 0x53B;
- break; // 26~28
- case 4:
- init_prbs = 0x213;
- break; // 29~31
- case 5:
- init_prbs = 0x29;
- break; // 32~34
- case 6:
- init_prbs = 0xD0;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x48E;
- break; // 38~40
- }
- break;
-
- default:
- case TRANSMISSION_MODE_8K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x740;
- break; // 02~04
- case -4:
- init_prbs = 0x069;
- break; // 05~07
- case -3:
- init_prbs = 0x7DD;
- break; // 08~10
- case -2:
- init_prbs = 0x208;
- break; // 11~13
- case -1:
- init_prbs = 0x7B9;
- break; // 14~16
- case 0:
- init_prbs = 0x5C7;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x53B;
- break; // 23~25
- case 3:
- init_prbs = 0x29;
- break; // 26~28
- case 4:
- init_prbs = 0x48E;
- break; // 29~31
- case 5:
- init_prbs = 0x4C4;
- break; // 32~34
- case 6:
- init_prbs = 0x367;
- break; // 33~37
- default:
- case 7:
- init_prbs = 0x684;
- break; // 38~40
- }
- break;
- }
- } else {
- dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
- dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
- }
- /*P_mode == ?? */
- dib8000_write_word(state, 10, (seq << 4));
- // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
-
- switch (state->fe[0]->dtv_property_cache.guard_interval) {
- case GUARD_INTERVAL_1_32:
- guard = 0;
- break;
- case GUARD_INTERVAL_1_16:
- guard = 1;
- break;
- case GUARD_INTERVAL_1_8:
- guard = 2;
- break;
- case GUARD_INTERVAL_1_4:
- default:
- guard = 3;
- break;
- }
-
- dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
-
- max_constellation = DQPSK;
- for (i = 0; i < 3; i++) {
- switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
- case DQPSK:
+ switch (state->fe[0]->dtv_property_cache.layer[layer_index].modulation) {
+ case DQPSK:
constellation = 0;
break;
- case QPSK:
+ case QPSK:
constellation = 1;
break;
- case QAM_16:
+ case QAM_16:
constellation = 2;
break;
- case QAM_64:
- default:
+ case QAM_64:
+ default:
constellation = 3;
break;
- }
-
- switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
- case FEC_1_2:
- crate = 1;
- break;
- case FEC_2_3:
- crate = 2;
- break;
- case FEC_3_4:
- crate = 3;
- break;
- case FEC_5_6:
- crate = 5;
- break;
- case FEC_7_8:
- default:
- crate = 7;
- break;
- }
-
- if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
- ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
- (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
- )
- timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
- else
- timeI = 0;
- dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
- (crate << 3) | timeI);
- if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
- switch (max_constellation) {
- case DQPSK:
- case QPSK:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
- state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
- break;
- case QAM_16:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
- break;
- }
- }
}
- mode = fft_to_mode(state);
-
- //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
-
- dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
- ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
- isdbt_sb_mode & 1) << 4));
-
- dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
-
- /* signal optimization parameter */
-
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
- seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
- for (i = 1; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i + 1];
- } else {
- for (i = 0; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i];
- }
- dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
-
- state->differential_constellation = (seg_diff_mask != 0);
- if (state->revision != 0x8090)
- dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
- else
- dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
- seg_mask13 = 0x00E0;
- else // 1-segment
- seg_mask13 = 0x0040;
- } else
- seg_mask13 = 0x1fff;
-
- // WRITE: Mode & Diff mask
- dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
-
- if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
- dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
- else
- dib8000_write_word(state, 268, (2 << 9) | 39); //init value
-
- // ---- SMALL ----
- // P_small_seg_diff
- dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
-
- dib8000_write_word(state, 353, seg_mask13); // ADDR 353
-
-/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
-
- // ---- SMALL ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_2K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_2k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_2k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg_0dqpsk;
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg;
- }
- }
+ switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) {
+ case FEC_1_2:
+ cr = 1;
break;
-
- case TRANSMISSION_MODE_4K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_4k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_4k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg_0dqpsk;
- }
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg;
- }
- }
+ case FEC_2_3:
+ cr = 2;
break;
-
- case TRANSMISSION_MODE_AUTO:
- case TRANSMISSION_MODE_8K:
- default:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_8k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_8k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg_0dqpsk;
- }
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg;
- }
- }
+ case FEC_3_4:
+ cr = 3;
break;
- }
- for (i = 0; i < 8; i++)
- dib8000_write_word(state, 343 + i, ncoeff[i]);
- }
-
- // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
- dib8000_write_word(state, 351,
- (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
-
- // ---- COFF ----
- // Carloff, the most robust
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
-
- // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
- // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1
- dib8000_write_word(state, 187,
- (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
- | 0x3);
-
-/* // P_small_coef_ext_enable = 1 */
-/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
-
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
-
- // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)
- if (mode == 3)
- dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
- else
- dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
- // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
- // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
- dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
- // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
- // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
- dib8000_write_word(state, 181, 300);
- dib8000_write_word(state, 182, 150);
- dib8000_write_word(state, 183, 80);
- dib8000_write_word(state, 184, 300);
- dib8000_write_word(state, 185, 150);
- dib8000_write_word(state, 186, 80);
- } else { // Sound Broadcasting mode 3 seg
- // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
- /* if (mode == 3) */
- /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
- /* else */
- /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
- dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
-
- // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
- // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
- dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
- //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
- // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
- dib8000_write_word(state, 181, 350);
- dib8000_write_word(state, 182, 300);
- dib8000_write_word(state, 183, 250);
- dib8000_write_word(state, 184, 350);
- dib8000_write_word(state, 185, 300);
- dib8000_write_word(state, 186, 250);
- }
-
- } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
- dib8000_write_word(state, 180, (16 << 6) | 9);
- dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
- coff_pow = 0x2800;
- for (i = 0; i < 6; i++)
- dib8000_write_word(state, 181 + i, coff_pow);
-
- // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
-
- // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
- dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
- // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
- }
- // ---- FFT ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- dib8000_write_word(state, 178, 64); // P_fft_powrange=64
- else
- dib8000_write_word(state, 178, 32); // P_fft_powrange=32
-
- /* make the cpil_coff_lock more robust but slower p_coff_winlen
- * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
- */
- /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
- dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
-
- dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
- dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
- dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
- if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
- dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
- else
- dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
- dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
- //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
- if (!autosearching)
- dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
- else
- dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
- dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
-
- dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
-
- /* offset loop parameters */
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
-
- else // Sound Broadcasting mode 3 seg
- /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
- } else
- // TODO in 13 seg, timf_alpha can always be the same or not ?
- /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
-
- else // Sound Broadcasting mode 3 seg
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
- } else
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
-
- /* P_dvsy_sync_wait - reuse mode */
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_8K:
- mode = 256;
- break;
- case TRANSMISSION_MODE_4K:
- mode = 128;
- break;
+ case FEC_5_6:
+ cr = 5;
+ break;
+ case FEC_7_8:
default:
- case TRANSMISSION_MODE_2K:
- mode = 64;
- break;
+ cr = 7;
+ break;
}
- if (state->cfg.diversity_delay == 0)
- mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+
+ if ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving > 0) && ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving <= 3) || (state->fe[0]->dtv_property_cache.layer[layer_index].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)))
+ time_intlv = state->fe[0]->dtv_property_cache.layer[layer_index].interleaving;
else
- mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
- mode <<= 4;
- dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
+ time_intlv = 0;
+
+ dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].segment_count > 0) {
+ switch (max_constellation) {
+ case DQPSK:
+ case QPSK:
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_16 || state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
+ max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
+ break;
+ case QAM_16:
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
+ max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
+ break;
+ }
+ }
+
+ return max_constellation;
+}
+
+static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
+static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
+static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */
+static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
+{
+ u16 i, ana_gain = 0;
+ const u16 *adp;
/* channel estimation fine configuration */
switch (max_constellation) {
case QAM_64:
- ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
- coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
- coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
- coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
- coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
- //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
- break;
+ ana_gain = 0x7;
+ adp = &adp_Q64[0];
+ break;
case QAM_16:
- ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
- coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
- coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
- coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
- coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
- //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
- break;
+ ana_gain = 0x7;
+ adp = &adp_Q16[0];
+ break;
default:
- ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
- coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
- coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
- coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
- coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
- break;
+ ana_gain = 0;
+ adp = &adp_Qdefault[0];
+ break;
}
- for (mode = 0; mode < 4; mode++)
- dib8000_write_word(state, 215 + mode, coeff[mode]);
- // update ana_gain depending on max constellation
+ for (i = 0; i < 4; i++)
+ dib8000_write_word(state, 215 + i, adp[i]);
+
+ return ana_gain;
+}
+
+static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
+{
+ u16 i;
+
dib8000_write_word(state, 116, ana_gain);
- // update ADC target depending on ana_gain
- if (ana_gain) { // set -16dB ADC target for ana_gain=-1
+
+ /* update ADC target depending on ana_gain */
+ if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
for (i = 0; i < 10; i++)
dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
- } else { // set -22dB ADC target for ana_gain=0
+ } else { /* set -22dB ADC target for ana_gain=0 */
for (i = 0; i < 10; i++)
dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
}
+}
- // ---- ANA_FE ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
- ana_fe = ana_fe_coeff_3seg;
- else // 1-segment
- ana_fe = ana_fe_coeff_1seg;
- } else
- ana_fe = ana_fe_coeff_13seg;
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
- for (mode = 0; mode < 24; mode++)
- dib8000_write_word(state, 117 + mode, ana_fe[mode]);
-
- // ---- CHAN_BLK ----
- for (i = 0; i < 13; i++) {
- if ((((~seg_diff_mask) >> i) & 1) == 1) {
- P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
- P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
- }
- }
- dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
- dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
- // "P_cspu_left_edge" not used => do not care
- // "P_cspu_right_edge" not used => do not care
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
- dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
- && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
- //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
- dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
- }
- } else if (state->isdbt_cfg_loaded == 0) {
- dib8000_write_word(state, 228, 0); // default value
- dib8000_write_word(state, 265, 31); // default value
- dib8000_write_word(state, 205, 0x200f); // init value
- }
- // ---- TMCC ----
- for (i = 0; i < 3; i++)
- tmcc_pow +=
- (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
- // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
- // Threshold is set at 1/4 of max power.
- tmcc_pow *= (1 << (9 - 2));
-
- dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
- dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
- dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
- //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
- // ---- PHA3 ----
+static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
+{
+ u16 mode = 0;
if (state->isdbt_cfg_loaded == 0)
- dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
+ for (mode = 0; mode < 24; mode++)
+ dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+}
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- state->isdbt_cfg_loaded = 0;
+static const u16 lut_prbs_2k[14] = {
+ 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
+};
+static const u16 lut_prbs_4k[14] = {
+ 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
+};
+static const u16 lut_prbs_8k[14] = {
+ 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
+};
+
+static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
+{
+ int sub_channel_prbs_group = 0;
+
+ sub_channel_prbs_group = (subchannel / 3) + 1;
+ dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
+
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ return lut_prbs_2k[sub_channel_prbs_group];
+ case TRANSMISSION_MODE_4K:
+ return lut_prbs_4k[sub_channel_prbs_group];
+ default:
+ case TRANSMISSION_MODE_8K:
+ return lut_prbs_8k[sub_channel_prbs_group];
+ }
+}
+
+static void dib8000_set_13seg_channel(struct dib8000_state *state)
+{
+ u16 i;
+ u16 coff_pow = 0x2800;
+
+ state->seg_mask = 0x1fff; /* All 13 segments enabled */
+
+ /* ---- COFF ---- Carloff, the most robust --- */
+ if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
+ dib8000_write_word(state, 180, (16 << 6) | 9);
+ dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
+ coff_pow = 0x2800;
+ for (i = 0; i < 6; i++)
+ dib8000_write_word(state, 181+i, coff_pow);
+
+ /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
+ /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
+
+ /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
+ dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
+ /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
+ dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+
+ dib8000_write_word(state, 228, 0); /* default value */
+ dib8000_write_word(state, 265, 31); /* default value */
+ dib8000_write_word(state, 205, 0x200f); /* init value */
+ }
+
+ /*
+ * make the cpil_coff_lock more robust but slower p_coff_winlen
+ * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
+ */
+
+ if (state->cfg.pll->ifreq == 0)
+ dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
+
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
+}
+
+static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
+{
+ u16 reg_1;
+
+ reg_1 = dib8000_read_word(state, 1);
+ dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
+}
+
+static void dib8000_small_fine_tune(struct dib8000_state *state)
+{
+ u16 i;
+ const s16 *ncoeff;
+
+ dib8000_write_word(state, 352, state->seg_diff_mask);
+ dib8000_write_word(state, 353, state->seg_mask);
+
+ /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
+ dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
+
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ /* ---- SMALL ---- */
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_2k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_2k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg;
+ }
+ }
+ break;
+ case TRANSMISSION_MODE_4K:
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_4k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_4k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg;
+ }
+ }
+ break;
+ case TRANSMISSION_MODE_AUTO:
+ case TRANSMISSION_MODE_8K:
+ default:
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_8k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_8k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg;
+ }
+ }
+ break;
+ }
+
+ for (i = 0; i < 8; i++)
+ dib8000_write_word(state, 343 + i, ncoeff[i]);
+ }
+}
+
+static const u16 coff_thres_1seg[3] = {300, 150, 80};
+static const u16 coff_thres_3seg[3] = {350, 300, 250};
+static void dib8000_set_sb_channel(struct dib8000_state *state)
+{
+ const u16 *coff;
+ u16 i;
+
+ if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
+ dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
+ dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
+ } else {
+ dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
+ dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
+ }
+
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) /* 3-segments */
+ state->seg_mask = 0x00E0;
+ else /* 1-segment */
+ state->seg_mask = 0x0040;
+
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
+
+ /* ---- COFF ---- Carloff, the most robust --- */
+ /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
+ dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) | 0x3);
+
+ dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
+ dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
+
+ /* Sound Broadcasting mode 1 seg */
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+ /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
+ if (state->mode == 3)
+ dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
+ else
+ dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
+
+ /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
+ coff = &coff_thres_1seg[0];
+ } else { /* Sound Broadcasting mode 3 seg */
+ dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
+ /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
+ coff = &coff_thres_3seg[0];
+ }
+
+ dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
+ dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
+
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K)
+ dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
+
+ /* Write COFF thres */
+ for (i = 0 ; i < 3; i++) {
+ dib8000_write_word(state, 181+i, coff[i]);
+ dib8000_write_word(state, 184+i, coff[i]);
+ }
+
+ /*
+ * make the cpil_coff_lock more robust but slower p_coff_winlen
+ * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
+ */
+
+ dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
+
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
+ dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
else
- state->isdbt_cfg_loaded = 1;
+ dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
+}
+static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+{
+ u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
+ u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
+ u16 max_constellation = DQPSK;
+ int init_prbs;
+
+ /* P_mode */
+ dib8000_write_word(state, 10, (seq << 4));
+
+ /* init mode */
+ state->mode = fft_to_mode(state);
+
+ /* set guard */
+ tmp = dib8000_read_word(state, 1);
+ dib8000_write_word(state, 1, (tmp&0xfffc) | (state->fe[0]->dtv_property_cache.guard_interval & 0x3));
+
+ dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.isdbt_sb_mode & 1) << 4));
+
+ /* signal optimization parameter */
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
+ state->seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
+ for (i = 1; i < 3; i++)
+ nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
+ for (i = 0; i < nbseg_diff; i++)
+ state->seg_diff_mask |= 1 << permu_seg[i+1];
+ } else {
+ for (i = 0; i < 3; i++)
+ nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
+ for (i = 0; i < nbseg_diff; i++)
+ state->seg_diff_mask |= 1 << permu_seg[i];
+ }
+
+ if (state->seg_diff_mask)
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
+ else
+ dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
+
+ for (i = 0; i < 3; i++)
+ max_constellation = dib8000_set_layer(state, i, max_constellation);
+ if (autosearching == 0) {
+ state->layer_b_nb_seg = state->fe[0]->dtv_property_cache.layer[1].segment_count;
+ state->layer_c_nb_seg = state->fe[0]->dtv_property_cache.layer[2].segment_count;
+ }
+
+ /* WRITE: Mode & Diff mask */
+ dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
+
+ state->differential_constellation = (state->seg_diff_mask != 0);
+
+ /* channel estimation fine configuration */
+ ana_gain = dib8000_adp_fine_tune(state, max_constellation);
+
+ /* update ana_gain depending on max constellation */
+ dib8000_update_ana_gain(state, ana_gain);
+
+ /* ---- ANA_FE ---- */
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) /* 3-segments */
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
+ else
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
+
+ /* TSB or ISDBT ? apply it now */
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ dib8000_set_sb_channel(state);
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_subchannel != -1)
+ init_prbs = dib8000_get_init_prbs(state, state->fe[0]->dtv_property_cache.isdbt_sb_subchannel);
+ else
+ init_prbs = 0;
+ } else {
+ dib8000_set_13seg_channel(state);
+ init_prbs = 0xfff;
+ }
+
+ /* SMALL */
+ dib8000_small_fine_tune(state);
+
+ dib8000_set_subchannel_prbs(state, init_prbs);
+
+ /* ---- CHAN_BLK ---- */
+ for (i = 0; i < 13; i++) {
+ if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
+ p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
+ p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
+ }
+ }
+ dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
+ dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
+ /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
+
+ dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
+ dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
+ dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
+
+ if (!autosearching)
+ dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
+ else
+ dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
+
+ dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
+ dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
+
+ dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
+
+ /* ---- TMCC ---- */
+ for (i = 0; i < 3; i++)
+ tmcc_pow += (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count) ;
+
+ /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
+ /* Threshold is set at 1/4 of max power. */
+ tmcc_pow *= (1 << (9-2));
+ dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
+ dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
+ dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
+ /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
+
+ /* ---- PHA3 ---- */
+ if (state->isdbt_cfg_loaded == 0)
+ dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
+
+ state->isdbt_cfg_loaded = 0;
+}
+
+u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
+{
+ u32 value;
+ u16 reg = 11; /* P_search_end0 start addr */
+
+ for (reg = 11; reg < 16; reg += 2) {
+ if (reg == 11) {
+ if (state->revision == 0x8090)
+ value = internal * wait1_ms; /* P_search_end0 wait time */
+ else
+ value = internal * wait0_ms; /* P_search_end0 wait time */
+ } else if (reg == 13)
+ value = internal * wait1_ms; /* P_search_end0 wait time */
+ else if (reg == 15)
+ value = internal * wait2_ms; /* P_search_end0 wait time */
+ dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
+ dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
+ }
+ return value;
}
static int dib8000_autosearch_start(struct dvb_frontend *fe)
{
- u8 factor;
- u32 value;
struct dib8000_state *state = fe->demodulator_priv;
+ u8 slist = 0;
+ u32 value, internal = state->cfg.pll->internal;
- int slist = 0;
+ if (state->revision == 0x8090)
+ internal = dib8000_read32(state, 23) / 1000;
- state->fe[0]->dtv_property_cache.inversion = 0;
- if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
- state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
- state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
- state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
- state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
+ if (state->autosearch_state == AS_SEARCHING_FFT) {
+ dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
+ dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
- //choose the right list, in sb, always do everything
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
+ dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
+ dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
+ dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
+ dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
+ dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
+
+ if (state->revision == 0x8090)
+ value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+
+ dib8000_write_word(state, 17, 0);
+ dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
+ dib8000_write_word(state, 19, 0);
+ dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
+ dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
+ dib8000_write_word(state, 22, value & 0xffff);
+
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
+ else
+ dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
+ dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
+
+ /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
+ dib8000_write_word(state, 356, 0);
+ dib8000_write_word(state, 357, 0x111);
+
+ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
+ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
+ } else if (state->autosearch_state == AS_SEARCHING_GUARD) {
state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
- slist = 7;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
- } else {
- if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
- slist = 7;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2
- } else
- slist = 3;
- } else {
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
- slist = 2;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
- } else
- slist = 0;
- }
+ state->fe[0]->dtv_property_cache.inversion = 0;
+ state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
+ state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
+ state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
+ state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
- state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
- if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
- state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+ slist = 16;
+ state->fe[0]->dtv_property_cache.transmission_mode = state->found_nfft;
- dprintk("using list for autosearch : %d", slist);
- dib8000_set_channel(state, (unsigned char)slist, 1);
- //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
+ dib8000_set_isdbt_common_channel(state, slist, 1);
- factor = 1;
-
- //set lock_mask values
+ /* set lock_mask values */
dib8000_write_word(state, 6, 0x4);
- dib8000_write_word(state, 7, 0x8);
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
+ else
+ dib8000_write_word(state, 7, 0x8);
dib8000_write_word(state, 8, 0x1000);
- //set lock_mask wait time values
- value = 50 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
- dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
- dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
- value = 1000 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
- dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
+ /* set lock_mask wait time values */
+ if (state->revision == 0x8090)
+ dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+
+ dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
+
+ /* P_search_param_select = 0xf; look for the 4 different guard intervals */
+ dib8000_write_word(state, 356, 0);
+ dib8000_write_word(state, 357, 0xf);
value = dib8000_read_word(state, 0);
- dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
- dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
- dib8000_write_word(state, 0, (u16) value);
+ dib8000_write_word(state, 0, (u16)((1 << 15) | value));
+ dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
+ dib8000_write_word(state, 0, (u16)value);
+ } else {
+ state->fe[0]->dtv_property_cache.inversion = 0;
+ state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
+ state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
+ state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
+ state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
+ if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
+ state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
+ /* choose the right list, in sb, always do everything */
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ slist = 7;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
+ } else {
+ if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
+ if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+ state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+ state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+ slist = 7;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
+ } else {
+ state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+ slist = 3;
+ }
+ } else {
+ if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+ state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+ slist = 2;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
+ } else
+ slist = 0;
+ }
+ }
+ dprintk("Using list for autosearch : %d", slist);
+
+ dib8000_set_isdbt_common_channel(state, slist, 1);
+
+ /* set lock_mask values */
+ dib8000_write_word(state, 6, 0x4);
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
+ else
+ dib8000_write_word(state, 7, 0x8);
+ dib8000_write_word(state, 8, 0x1000);
+
+ /* set lock_mask wait time values */
+ if (state->revision == 0x8090)
+ dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+
+ value = dib8000_read_word(state, 0);
+ dib8000_write_word(state, 0, (u16)((1 << 15) | value));
+ dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
+ dib8000_write_word(state, 0, (u16)value);
}
-
return 0;
}
@@ -2663,96 +2577,623 @@
struct dib8000_state *state = fe->demodulator_priv;
u16 irq_pending = dib8000_read_word(state, 1284);
- if (irq_pending & 0x1) { // failed
- dprintk("dib8000_autosearch_irq failed");
- return 1;
- }
+ if (state->autosearch_state == AS_SEARCHING_FFT) {
+ if (irq_pending & 0x1) {
+ dprintk("dib8000_autosearch_irq: max correlation result available");
+ return 3;
+ }
+ } else {
+ if (irq_pending & 0x1) { /* failed */
+ dprintk("dib8000_autosearch_irq failed");
+ return 1;
+ }
- if (irq_pending & 0x2) { // succeeded
- dprintk("dib8000_autosearch_irq succeeded");
- return 2;
+ if (irq_pending & 0x2) { /* succeeded */
+ dprintk("dib8000_autosearch_irq succeeded");
+ return 2;
+ }
}
return 0; // still pending
}
+static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
+{
+ u16 tmp;
+
+ tmp = dib8000_read_word(state, 771);
+ if (onoff) /* start P_restart_chd : channel_decoder */
+ dib8000_write_word(state, 771, tmp & 0xfffd);
+ else /* stop P_restart_chd : channel_decoder */
+ dib8000_write_word(state, 771, tmp | (1<<1));
+}
+
+static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
+{
+ s16 unit_khz_dds_val;
+ u32 abs_offset_khz = ABS(offset_khz);
+ u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
+ u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
+ u8 ratio;
+
+ if (state->revision == 0x8090) {
+ ratio = 4;
+ unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
+ if (offset_khz < 0)
+ dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
+ else
+ dds = (abs_offset_khz * unit_khz_dds_val);
+
+ if (invert)
+ dds = (1<<26) - dds;
+ } else {
+ ratio = 2;
+ unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
+
+ if (offset_khz < 0)
+ unit_khz_dds_val *= -1;
+
+ /* IF tuner */
+ if (invert)
+ dds -= abs_offset_khz * unit_khz_dds_val;
+ else
+ dds += abs_offset_khz * unit_khz_dds_val;
+ }
+
+ dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
+
+ if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
+ /* Max dds offset is the half of the demod freq */
+ dib8000_write_word(state, 26, invert);
+ dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
+ dib8000_write_word(state, 28, (u16)(dds & 0xffff));
+ }
+}
+
+static void dib8000_set_frequency_offset(struct dib8000_state *state)
+{
+ int i;
+ u32 current_rf;
+ int total_dds_offset_khz;
+
+ if (state->fe[0]->ops.tuner_ops.get_frequency)
+ state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf);
+ else
+ current_rf = state->fe[0]->dtv_property_cache.frequency;
+ current_rf /= 1000;
+ total_dds_offset_khz = (int)current_rf - (int)state->fe[0]->dtv_property_cache.frequency / 1000;
+
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ state->subchannel = state->fe[0]->dtv_property_cache.isdbt_sb_subchannel;
+
+ i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
+ dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i);
+
+ if (state->cfg.pll->ifreq == 0) { /* low if tuner */
+ if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
+ dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
+ } else {
+ if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
+ total_dds_offset_khz *= -1;
+ }
+ }
+
+ dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", state->fe[0]->dtv_property_cache.frequency - current_rf, state->fe[0]->dtv_property_cache.frequency, current_rf, total_dds_offset_khz);
+
+ /* apply dds offset now */
+ dib8000_set_dds(state, total_dds_offset_khz);
+}
+
+static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
+u32 dib8000_get_symbol_duration(struct dib8000_state *state)
+{
+ u16 i;
+
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ i = 0;
+ break;
+ case TRANSMISSION_MODE_4K:
+ i = 2;
+ break;
+ default:
+ case TRANSMISSION_MODE_AUTO:
+ case TRANSMISSION_MODE_8K:
+ i = 1;
+ break;
+ }
+
+ return (LUT_isdbt_symbol_duration[i] / (state->fe[0]->dtv_property_cache.bandwidth_hz / 1000)) + 1;
+}
+
+static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
+{
+ u16 reg_32 = 0, reg_37 = 0;
+
+ switch (loop_step) {
+ case LOOP_TUNE_1:
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+ reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
+ reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
+ } else { /* Sound Broadcasting mode 3 seg */
+ reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
+ reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */
+ }
+ } else { /* 13-seg start conf offset loop parameters */
+ reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
+ reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
+ }
+ break;
+ case LOOP_TUNE_2:
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
+ reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
+ reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
+ } else { /* Sound Broadcasting mode 3 seg */
+ reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
+ reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
+ }
+ } else { /* 13 seg */
+ reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
+ reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
+ }
+ break;
+ }
+ dib8000_write_word(state, 32, reg_32);
+ dib8000_write_word(state, 37, reg_37);
+}
+
+static void dib8000_demod_restart(struct dib8000_state *state)
+{
+ dib8000_write_word(state, 770, 0x4000);
+ dib8000_write_word(state, 770, 0x0000);
+ return;
+}
+
+static void dib8000_set_sync_wait(struct dib8000_state *state)
+{
+ u16 sync_wait = 64;
+
+ /* P_dvsy_sync_wait - reuse mode */
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_8K:
+ sync_wait = 256;
+ break;
+ case TRANSMISSION_MODE_4K:
+ sync_wait = 128;
+ break;
+ default:
+ case TRANSMISSION_MODE_2K:
+ sync_wait = 64;
+ break;
+ }
+
+ if (state->cfg.diversity_delay == 0)
+ sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
+ else
+ sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
+
+ dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
+}
+
+static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
+{
+ if (mode == SYMBOL_DEPENDENT_ON)
+ return systime() + (delay * state->symbol_duration);
+ else
+ return systime() + delay;
+}
+
+static s32 dib8000_get_status(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ return state->status;
+}
+
+enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ return state->tune_state;
+}
+EXPORT_SYMBOL(dib8000_get_tune_state);
+
+int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ state->tune_state = tune_state;
+ return 0;
+}
+EXPORT_SYMBOL(dib8000_set_tune_state);
+
+static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ state->status = FE_STATUS_TUNE_PENDING;
+ state->tune_state = CT_DEMOD_START;
+ return 0;
+}
+
+static u16 dib8000_read_lock(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ if (state->revision == 0x8090)
+ return dib8000_read_word(state, 570);
+ return dib8000_read_word(state, 568);
+}
+
+static int dib8090p_init_sdram(struct dib8000_state *state)
+{
+ u16 reg = 0;
+ dprintk("init sdram");
+
+ reg = dib8000_read_word(state, 274) & 0xfff0;
+ dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
+
+ dib8000_write_word(state, 1803, (7 << 2));
+
+ reg = dib8000_read_word(state, 1280);
+ dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
+ dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
+
+ return 0;
+}
+
static int dib8000_tune(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
- int ret = 0;
- u16 lock, value, mode;
+ enum frontend_tune_state *tune_state = &state->tune_state;
- // we are already tuned - just resuming from suspend
- if (state == NULL)
- return -EINVAL;
+ u16 locks, deeper_interleaver = 0, i;
+ int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
- mode = fft_to_mode(state);
+ u32 *timeout = &state->timeout;
+ u32 now = systime();
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1, agc2;
+#endif
- dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
- dib8000_set_channel(state, 0, 0);
+ u32 corm[4] = {0, 0, 0, 0};
+ u8 find_index, max_value;
- // restart demod
- ret |= dib8000_write_word(state, 770, 0x4000);
- ret |= dib8000_write_word(state, 770, 0x0000);
- msleep(45);
+#if 0
+ if (*tune_state < CT_DEMOD_STOP)
+ dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
+#endif
- /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
- /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
+ switch (*tune_state) {
+ case CT_DEMOD_START: /* 30 */
+ if (state->revision == 0x8090)
+ dib8090p_init_sdram(state);
+ state->status = FE_STATUS_TUNE_PENDING;
+ if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
+ (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
+ (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
+ (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
+ (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
+ (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
+ (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
+ ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
+ (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
+ (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
+ (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
+ (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
+ ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
+ (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
+ (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
+ (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
+ (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
+ ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
+ (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
+ (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
+ ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
+ ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
+ ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
+ ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0))))
+ state->channel_parameters_set = 0; /* auto search */
+ else
+ state->channel_parameters_set = 1; /* channel parameters are known */
- // never achieved a lock before - wait for timfreq to update
- if (state->timf == 0) {
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- msleep(300);
- else // Sound Broadcasting mode 3 seg
- msleep(500);
- } else // 13 seg
- msleep(200);
- }
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+ dib8000_viterbi_state(state, 0); /* force chan dec in restart */
- /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
- dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
- //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
+ /* Layer monit */
+ dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
- /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
- ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
+ dib8000_set_frequency_offset(state);
+ dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
- } else { // Sound Broadcasting mode 3 seg
+ if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
+#ifdef DIB8000_AGC_FREEZE
+ if (state->revision != 0x8090) {
+ state->agc1_max = dib8000_read_word(state, 108);
+ state->agc1_min = dib8000_read_word(state, 109);
+ state->agc2_max = dib8000_read_word(state, 110);
+ state->agc2_min = dib8000_read_word(state, 111);
+ agc1 = dib8000_read_word(state, 388);
+ agc2 = dib8000_read_word(state, 389);
+ dib8000_write_word(state, 108, agc1);
+ dib8000_write_word(state, 109, agc1);
+ dib8000_write_word(state, 110, agc2);
+ dib8000_write_word(state, 111, agc2);
+ }
+#endif
+ state->autosearch_state = AS_SEARCHING_FFT;
+ state->found_nfft = TRANSMISSION_MODE_AUTO;
+ state->found_guard = GUARD_INTERVAL_AUTO;
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ } else { /* we already know the channel struct so TUNE only ! */
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STEP_3;
+ }
+ state->symbol_duration = dib8000_get_symbol_duration(state);
+ break;
- /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
- dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
+ case CT_DEMOD_SEARCH_NEXT: /* 51 */
+ dib8000_autosearch_start(fe);
+ if (state->revision == 0x8090)
+ ret = 50;
+ else
+ ret = 15;
+ *tune_state = CT_DEMOD_STEP_1;
+ break;
- ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
- }
+ case CT_DEMOD_STEP_1: /* 31 */
+ switch (dib8000_autosearch_irq(fe)) {
+ case 1: /* fail */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
+ break;
+ case 2: /* Succes */
+ state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ *tune_state = CT_DEMOD_STEP_3;
+ if (state->autosearch_state == AS_SEARCHING_GUARD)
+ *tune_state = CT_DEMOD_STEP_2;
+ else
+ state->autosearch_state = AS_DONE;
+ break;
+ case 3: /* Autosearch FFT max correlation endded */
+ *tune_state = CT_DEMOD_STEP_2;
+ break;
+ }
+ break;
- } else { // 13 seg
- /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
- dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
+ case CT_DEMOD_STEP_2:
+ switch (state->autosearch_state) {
+ case AS_SEARCHING_FFT:
+ /* searching for the correct FFT */
+ if (state->revision == 0x8090) {
+ corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
+ } else {
+ corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
+ corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ }
+ /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
- ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
+ max_value = 0;
+ for (find_index = 1 ; find_index < 3 ; find_index++) {
+ if (corm[max_value] < corm[find_index])
+ max_value = find_index ;
+ }
+ switch (max_value) {
+ case 0:
+ state->found_nfft = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ state->found_nfft = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ default:
+ state->found_nfft = TRANSMISSION_MODE_8K;
+ break;
+ }
+ /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
+
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ state->autosearch_state = AS_SEARCHING_GUARD;
+ if (state->revision == 0x8090)
+ ret = 50;
+ else
+ ret = 10;
+ break;
+ case AS_SEARCHING_GUARD:
+ /* searching for the correct guard interval */
+ if (state->revision == 0x8090)
+ state->found_guard = dib8000_read_word(state, 572) & 0x3;
+ else
+ state->found_guard = dib8000_read_word(state, 570) & 0x3;
+ /* dprintk("guard interval found=%i", state->found_guard); */
+
+ *tune_state = CT_DEMOD_STEP_3;
+ break;
+ default:
+ /* the demod should never be in this state */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
+ break;
+ }
+ break;
+
+ case CT_DEMOD_STEP_3: /* 33 */
+ state->symbol_duration = dib8000_get_symbol_duration(state);
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
+ dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
+ *tune_state = CT_DEMOD_STEP_4;
+ break;
+
+ case CT_DEMOD_STEP_4: /* (34) */
+ dib8000_demod_restart(state);
+
+ dib8000_set_sync_wait(state);
+ dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+
+ locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
+ /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */
+ *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_5;
+ break;
+
+ case CT_DEMOD_STEP_5: /* (35) */
+ locks = dib8000_read_lock(fe);
+ if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
+ dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
+ if (!state->differential_constellation) {
+ /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
+ *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_7;
+ } else {
+ *tune_state = CT_DEMOD_STEP_8;
+ }
+ } else if (now > *timeout) {
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ }
+ break;
+
+ case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
+ if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
+ /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
+ if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
+ *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
+ else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ } else {
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
+
+ case CT_DEMOD_STEP_7: /* 37 */
+ locks = dib8000_read_lock(fe);
+ if (locks & (1<<10)) { /* lmod4_lock */
+ ret = 14; /* wait for 14 symbols */
+ *tune_state = CT_DEMOD_STEP_8;
+ } else if (now > *timeout)
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ break;
+
+ case CT_DEMOD_STEP_8: /* 38 */
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+
+ /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) {
+ state->subchannel = 0;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else {
+ *tune_state = CT_DEMOD_STEP_9;
+ state->status = FE_STATUS_LOCKED;
+ }
+ break;
+
+ case CT_DEMOD_STEP_9: /* 39 */
+ if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
+ /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */
+ for (i = 0; i < 3; i++) {
+ if (state->fe[0]->dtv_property_cache.layer[i].interleaving >= deeper_interleaver) {
+ dprintk("layer%i: time interleaver = %d ", i, state->fe[0]->dtv_property_cache.layer[i].interleaving);
+ if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { /* valid layer */
+ deeper_interleaver = state->fe[0]->dtv_property_cache.layer[0].interleaving;
+ state->longest_intlv_layer = i;
+ }
+ }
+ }
+
+ if (deeper_interleaver == 0)
+ locks = 2; /* locks is the tmp local variable name */
+ else if (deeper_interleaver == 3)
+ locks = 8;
+ else
+ locks = 2 * deeper_interleaver;
+
+ if (state->diversity_onoff != 0) /* because of diversity sync */
+ locks *= 2;
+
+ *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
+ dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
+
+ *tune_state = CT_DEMOD_STEP_10;
+ } else
+ *tune_state = CT_DEMOD_STOP;
+ break;
+
+ case CT_DEMOD_STEP_10: /* 40 */
+ locks = dib8000_read_lock(fe);
+ if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
+ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation)
+ /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ state->status = FE_STATUS_DEMOD_SUCCESS;
+ else
+ state->status = FE_STATUS_DATA_LOCKED;
+ *tune_state = CT_DEMOD_STOP;
+ } else if (now > *timeout) {
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */
+ state->subchannel += 3;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
+ if (locks & (0x7<<5)) {
+ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
+ state->status = FE_STATUS_DATA_LOCKED;
+ } else
+ state->status = FE_STATUS_TUNE_FAILED;
+ *tune_state = CT_DEMOD_STOP;
+ }
+ }
+ break;
+
+ case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
+ if (state->subchannel <= 41) {
+ dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
+ *tune_state = CT_DEMOD_STEP_9;
+ } else {
+ *tune_state = CT_DEMOD_STOP;
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
+
+ default:
+ break;
}
- // we achieved a coff_cpil_lock - it's time to update the timf
- if (state->revision != 0x8090)
- lock = dib8000_read_word(state, 568);
- else
- lock = dib8000_read_word(state, 570);
- if ((lock >> 11) & 0x1)
- dib8000_update_timf(state);
-
- //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
- dib8000_write_word(state, 6, 0x200);
-
- if (state->revision == 0x8002) {
- value = dib8000_read_word(state, 903);
- dib8000_write_word(state, 903, value & ~(1 << 3));
- msleep(1);
- dib8000_write_word(state, 903, value | (1 << 3));
+ /* tuning is finished - cleanup the demod */
+ switch (*tune_state) {
+ case CT_DEMOD_STOP: /* (42) */
+#ifdef DIB8000_AGC_FREEZE
+ if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
+ dib8000_write_word(state, 108, state->agc1_max);
+ dib8000_write_word(state, 109, state->agc1_min);
+ dib8000_write_word(state, 110, state->agc2_max);
+ dib8000_write_word(state, 111, state->agc2_min);
+ state->agc1_max = 0;
+ state->agc1_min = 0;
+ state->agc2_max = 0;
+ state->agc2_min = 0;
+ }
+#endif
+ ret = FE_CALLBACK_TIME_NEVER;
+ break;
+ default:
+ break;
}
+ if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
+ return ret * state->symbol_duration;
+ if ((ret > 0) && (ret < state->symbol_duration))
+ return state->symbol_duration; /* at least one symbol */
return ret;
}
@@ -2767,7 +3208,7 @@
if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
dprintk("could not start Slow ADC");
- if (state->revision != 0x8090)
+ if (state->revision == 0x8090)
dib8000_sad_calib(state);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
@@ -2797,21 +3238,6 @@
return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
}
-enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
- struct dib8000_state *state = fe->demodulator_priv;
- return state->tune_state;
-}
-EXPORT_SYMBOL(dib8000_get_tune_state);
-
-int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
- struct dib8000_state *state = fe->demodulator_priv;
- state->tune_state = tune_state;
- return 0;
-}
-EXPORT_SYMBOL(dib8000_set_tune_state);
-
static int dib8000_get_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
@@ -2961,10 +3387,9 @@
static int dib8000_set_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
- u8 nbr_pending, exit_condition, index_frontend;
- s8 index_frontend_success = -1;
- int time, ret;
- int time_slave = FE_CALLBACK_TIME_NEVER;
+ int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER;
+ u8 exit_condition, index_frontend;
+ u32 delay, callback_time;
if (state->fe[0]->dtv_property_cache.frequency == 0) {
dprintk("dib8000: must at least specify frequency ");
@@ -2981,18 +3406,36 @@
state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
- if (state->revision != 0x8090)
- dib8000_set_output_mode(state->fe[index_frontend],
- OUTMODE_HIGH_Z);
- else
- dib8096p_set_output_mode(state->fe[index_frontend],
- OUTMODE_HIGH_Z);
+ /* set output mode and diversity input */
+ if (state->revision != 0x8090) {
+ dib8000_set_diversity_in(state->fe[index_frontend], 1);
+ if (index_frontend != 0)
+ dib8000_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ else
+ dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
+ } else {
+ dib8096p_set_diversity_in(state->fe[index_frontend], 1);
+ if (index_frontend != 0)
+ dib8096p_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ else
+ dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
+ }
+
+ /* tune the tuner */
if (state->fe[index_frontend]->ops.tuner_ops.set_params)
state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
}
+ /* turn off the diversity of the last chip */
+ if (state->revision != 0x8090)
+ dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
+ else
+ dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
+
/* start up the AGC */
do {
time = dib8000_agc_startup(state->fe[0]);
@@ -3019,139 +3462,88 @@
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
- if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
- (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
- (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
- (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
- ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
- ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
- ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
- ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
- int i = 100;
- u8 found = 0;
- u8 tune_failed = 0;
-
+ active = 1;
+ do {
+ callback_time = FE_CALLBACK_TIME_NEVER;
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
- dib8000_autosearch_start(state->fe[index_frontend]);
- }
+ delay = dib8000_tune(state->fe[index_frontend]);
+ if (delay != FE_CALLBACK_TIME_NEVER)
+ delay += systime();
- do {
- msleep(20);
- nbr_pending = 0;
- exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
- for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- if (((tune_failed >> index_frontend) & 0x1) == 0) {
- found = dib8000_autosearch_irq(state->fe[index_frontend]);
- switch (found) {
- case 0: /* tune pending */
- nbr_pending++;
- break;
- case 2:
- dprintk("autosearch succeed on the frontend%i", index_frontend);
- exit_condition = 2;
- index_frontend_success = index_frontend;
- break;
- default:
- dprintk("unhandled autosearch result");
- case 1:
- tune_failed |= (1 << index_frontend);
- dprintk("autosearch failed for the frontend%i", index_frontend);
- break;
+ /* we are in autosearch */
+ if (state->channel_parameters_set == 0) { /* searching */
+ if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
+ dprintk("autosearch succeeded on fe%i", index_frontend);
+ dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
+ state->channel_parameters_set = 1;
+
+ for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
+ if (l != index_frontend) { /* and for all frontend except the successful one */
+ dib8000_tune_restart_from_demod(state->fe[l]);
+
+ state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
+ state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
+ state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+ state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
+ state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
+ for (i = 0; i < 3; i++) {
+ state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
+ state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
+ state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
+ state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
+ }
+
+ }
}
}
}
-
- /* if all tune are done and no success, exit: tune failed */
- if ((nbr_pending == 0) && (exit_condition == 0))
- exit_condition = 1;
- } while ((exit_condition == 0) && i--);
-
- if (exit_condition == 1) { /* tune failed */
- dprintk("tune failed");
- return 0;
+ if (delay < callback_time)
+ callback_time = delay;
+ }
+ /* tuning is done when the master frontend is done (failed or success) */
+ if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
+ dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
+ dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
+ active = 0;
+ /* we need to wait for all frontends to be finished */
+ for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
+ active = 1;
+ }
+ if (active == 0)
+ dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
}
- dprintk("tune success on frontend%i", index_frontend_success);
+ if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
+ dprintk("strange callback time something went wrong");
+ active = 0;
+ }
- dib8000_get_frontend(fe);
- }
+ while ((active == 1) && (systime() < callback_time))
+ msleep(100);
+ } while (active);
- for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
- ret = dib8000_tune(state->fe[index_frontend]);
-
- /* set output mode and diversity input */
- if (state->revision != 0x8090) {
+ /* set output mode */
+ if (state->revision != 0x8090)
dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
- for (index_frontend = 1;
- (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
- (state->fe[index_frontend] != NULL);
- index_frontend++) {
- dib8000_set_output_mode(state->fe[index_frontend],
- OUTMODE_DIVERSITY);
- dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
- }
-
- /* turn off the diversity of the last chip */
- dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
- } else {
+ else {
dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
if (state->cfg.enMpegOutput == 0) {
dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
}
- for (index_frontend = 1;
- (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
- (state->fe[index_frontend] != NULL);
- index_frontend++) {
- dib8096p_set_output_mode(state->fe[index_frontend],
- OUTMODE_DIVERSITY);
- dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
- }
-
- /* turn off the diversity of the last chip */
- dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
}
return ret;
}
-static u16 dib8000_read_lock(struct dvb_frontend *fe)
-{
- struct dib8000_state *state = fe->demodulator_priv;
-
- if (state->revision == 0x8090)
- return dib8000_read_word(state, 570);
- return dib8000_read_word(state, 568);
-}
-
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 lock_slave = 0, lock;
u8 index_frontend;
- if (state->revision == 0x8090)
- lock = dib8000_read_word(state, 570);
- else
- lock = dib8000_read_word(state, 568);
-
+ lock = dib8000_read_lock(fe);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
@@ -3545,10 +3937,11 @@
dib8000_reset(fe);
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
+ state->current_demod_bw = 6000;
return fe;
- error:
+error:
kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 9e7a2b1..b8c11e5 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -33,6 +33,8 @@
u8 output_mode;
u8 refclksel;
u8 enMpegOutput:1;
+
+ struct dibx000_bandwidth_config *plltable;
};
#define DEFAULT_DIB8000_I2C_ADDRESS 18
@@ -58,7 +60,7 @@
extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
uint8_t op, uint32_t timf);
extern int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll);
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio);
extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
@@ -147,7 +149,7 @@
return 0;
}
static inline int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll)
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h
index 5f48488..b538e05 100644
--- a/drivers/media/dvb-frontends/dibx000_common.h
+++ b/drivers/media/dvb-frontends/dibx000_common.h
@@ -193,7 +193,8 @@
CT_DEMOD_STEP_8,
CT_DEMOD_STEP_9,
CT_DEMOD_STEP_10,
- CT_DEMOD_SEARCH_NEXT = 41,
+ CT_DEMOD_STEP_11,
+ CT_DEMOD_SEARCH_NEXT = 51,
CT_DEMOD_STEP_LOCKED,
CT_DEMOD_STOP,
diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h
index a5f0368..194a07a 100644
--- a/drivers/media/dvb-frontends/lg2160.h
+++ b/drivers/media/dvb-frontends/lg2160.h
@@ -57,10 +57,10 @@
u16 if_khz;
/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
- int deny_i2c_rptr:1;
+ unsigned int deny_i2c_rptr:1;
/* spectral inversion - 0:disabled 1:enabled */
- int spectral_inversion:1;
+ unsigned int spectral_inversion:1;
unsigned int output_if;
enum lg2160_spi_clock spi_clock;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 7388769..facb848 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -380,13 +380,41 @@
return ret;
}
+
+static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+ u64 pset_iffreq;
+ u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0);
+
+ /*
+ * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
+ * / CrystalFreqHz)
+ */
+
+ pset_iffreq = if_freq % priv->cfg.xtal;
+ pset_iffreq *= 0x400000;
+ pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+ pset_iffreq = -pset_iffreq;
+ pset_iffreq = pset_iffreq & 0x3fffff;
+ dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n",
+ __func__, if_freq, (unsigned)pset_iffreq);
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+ if (ret)
+ return ret;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+
+ return (ret);
+}
+
static int rtl2832_init(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
- int i, ret, len;
- u8 en_bbin;
- u64 pset_iffreq;
const struct rtl2832_reg_value *init;
+ int i, ret, len;
/* initialization values for the demodulator registers */
struct rtl2832_reg_value rtl2832_initial_regs[] = {
@@ -432,22 +460,10 @@
{DVBT_TR_THD_SET2, 0x6},
{DVBT_TRK_KC_I2, 0x5},
{DVBT_CR_THD_SET2, 0x1},
- {DVBT_SPEC_INV, 0x0},
};
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
- en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
-
- /*
- * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
- * / CrystalFreqHz)
- */
- pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
- pset_iffreq *= 0x400000;
- pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
- pset_iffreq = pset_iffreq & 0x3fffff;
-
for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
rtl2832_initial_regs[i].value);
@@ -472,6 +488,10 @@
len = ARRAY_SIZE(rtl2832_tuner_init_e4000);
init = rtl2832_tuner_init_e4000;
break;
+ case RTL2832_TUNER_R820T:
+ len = ARRAY_SIZE(rtl2832_tuner_init_r820t);
+ init = rtl2832_tuner_init_r820t;
+ break;
default:
ret = -EINVAL;
goto err;
@@ -483,14 +503,26 @@
goto err;
}
- /* if frequency settings */
- ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+ if (!fe->ops.tuner_ops.get_if_frequency) {
+ ret = rtl2832_set_if(fe, priv->cfg.if_dvbt);
if (ret)
goto err;
+ }
- ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
- if (ret)
- goto err;
+ /*
+ * r820t NIM code does a software reset here at the demod -
+ * may not be needed, as there's already a software reset at set_params()
+ */
+#if 1
+ /* soft reset */
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+ if (ret)
+ goto err;
+#endif
priv->sleeping = false;
@@ -564,6 +596,19 @@
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
+ /* If the frontend has get_if_frequency(), use it */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ u32 if_freq;
+
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_set_if(fe, if_freq);
+ if (ret)
+ goto err;
+ }
+
switch (c->bandwidth_hz) {
case 6000000:
i = 0;
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index fefba0e..91b2dcf 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -52,6 +52,7 @@
#define RTL2832_TUNER_FC0012 0x26
#define RTL2832_TUNER_E4000 0x27
#define RTL2832_TUNER_FC0013 0x29
+#define RTL2832_TUNER_R820T 0x2a
u8 tuner;
};
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 7d97ce9..b5f2b80 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -267,6 +267,7 @@
{DVBT_OPT_ADC_IQ, 0x1},
{DVBT_AD_AVI, 0x0},
{DVBT_AD_AVQ, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = {
@@ -300,6 +301,7 @@
{DVBT_GI_PGA_STATE, 0x0},
{DVBT_EN_AGC_PGA, 0x1},
{DVBT_IF_AGC_MAN, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = {
@@ -337,6 +339,32 @@
{DVBT_REG_MONSEL, 0x1},
{DVBT_REG_MON, 0x1},
{DVBT_REG_4MSEL, 0x0},
+ {DVBT_SPEC_INV, 0x0},
+};
+
+static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = {
+ {DVBT_DAGC_TRG_VAL, 0x39},
+ {DVBT_AGC_TARG_VAL_0, 0x0},
+ {DVBT_AGC_TARG_VAL_8_1, 0x40},
+ {DVBT_AAGC_LOOP_GAIN, 0x16},
+ {DVBT_LOOP_GAIN2_3_0, 0x8},
+ {DVBT_LOOP_GAIN2_4, 0x1},
+ {DVBT_LOOP_GAIN3, 0x18},
+ {DVBT_VTOP1, 0x35},
+ {DVBT_VTOP2, 0x21},
+ {DVBT_VTOP3, 0x21},
+ {DVBT_KRF1, 0x0},
+ {DVBT_KRF2, 0x40},
+ {DVBT_KRF3, 0x10},
+ {DVBT_KRF4, 0x10},
+ {DVBT_IF_AGC_MIN, 0x80},
+ {DVBT_IF_AGC_MAX, 0x7f},
+ {DVBT_RF_AGC_MIN, 0x80},
+ {DVBT_RF_AGC_MAX, 0x7f},
+ {DVBT_POLAR_RF_AGC, 0x0},
+ {DVBT_POLAR_IF_AGC, 0x0},
+ {DVBT_AD7_SETTING, 0xe9f4},
+ {DVBT_SPEC_INV, 0x1},
};
#endif /* RTL2832_PRIV_H */
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index b353c50..cb52438 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1457,6 +1457,12 @@
return ret;
}
+static void s5c73m3_oif_unregistered(struct v4l2_subdev *sd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ v4l2_device_unregister_subdev(&state->sensor_sd);
+}
+
static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = {
.open = s5c73m3_open,
};
@@ -1474,6 +1480,7 @@
static const struct v4l2_subdev_internal_ops oif_internal_ops = {
.registered = s5c73m3_oif_registered,
+ .unregistered = s5c73m3_oif_unregistered,
.open = s5c73m3_oif_open,
};
@@ -1668,13 +1675,17 @@
static int s5c73m3_remove(struct i2c_client *client)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ struct v4l2_subdev *oif_sd = i2c_get_clientdata(client);
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd);
+ struct v4l2_subdev *sensor_sd = &state->sensor_sd;
- v4l2_device_unregister_subdev(sd);
+ v4l2_device_unregister_subdev(oif_sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(oif_sd->ctrl_handler);
+ media_entity_cleanup(&oif_sd->entity);
+
+ v4l2_device_unregister_subdev(sensor_sd);
+ media_entity_cleanup(&sensor_sd->entity);
s5c73m3_unregister_spi_driver(state);
s5c73m3_free_gpios(state);
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 99b80b6..1957c0d 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -102,9 +102,12 @@
return -EINVAL;
u_ent.id = ent->id;
- u_ent.name[0] = '\0';
- if (ent->name)
- strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
+ if (ent->name) {
+ strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
+ u_ent.name[sizeof(u_ent.name) - 1] = '\0';
+ } else {
+ memset(u_ent.name, 0, sizeof(u_ent.name));
+ }
u_ent.type = ent->type;
u_ent.revision = ent->revision;
u_ent.flags = ent->flags;
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index c9d3182..2d3507e 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -532,16 +532,17 @@
{
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
/* stop mpeg dma */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) {
dprintk( 2, "suspend\n" );
printk("%s: suspend mpeg\n", core->name);
cx8802_stop_dma(dev);
del_timer(&dev->mpegq.timeout);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* FIXME -- shutdown device */
cx88_shutdown(dev->core);
@@ -558,6 +559,7 @@
{
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
int err;
if (dev->state.disabled) {
@@ -584,12 +586,12 @@
cx88_reset(dev->core);
/* restart video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) {
printk("%s: resume mpeg\n", core->name);
cx8802_restart_queue(dev,&dev->mpegq);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index e3f6181..1b00615 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1954,9 +1954,10 @@
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
/* stop video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) {
printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev);
@@ -1967,7 +1968,7 @@
cx8800_stop_vbi_dma(dev);
del_timer(&dev->vbiq.timeout);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
if (core->ir)
cx88_ir_stop(core);
@@ -1986,6 +1987,7 @@
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
int err;
if (dev->state.disabled) {
@@ -2016,7 +2018,7 @@
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* restart video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) {
printk("%s/0: resume video\n", core->name);
restart_video_queue(dev,&dev->vidq);
@@ -2025,7 +2027,7 @@
printk("%s/0: resume vbi\n", core->name);
cx8800_restart_vbi_queue(dev,&dev->vbiq);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 20827ba..5612329 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -1422,6 +1422,7 @@
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1433,6 +1434,7 @@
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -1628,6 +1630,9 @@
dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
}
+ dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+ dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 386c0a7..40a73f7 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -80,6 +80,9 @@
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_vb && dst_vb) {
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_vb, vb_state);
v4l2_m2m_buf_done(dst_vb, vb_state);
@@ -584,6 +587,7 @@
src_vq->ops = &gsc_m2m_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -596,6 +600,7 @@
dst_vq->ops = &gsc_m2m_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 72c516a..528f413 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -742,16 +742,13 @@
/*
* The video node ioctl operations
*/
-static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+static int fimc_cap_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct fimc_dev *fimc = video_drvdata(file);
- strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
-
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE);
return 0;
}
@@ -1375,7 +1372,7 @@
}
static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
- .vidioc_querycap = fimc_vidioc_querycap_capture,
+ .vidioc_querycap = fimc_cap_querycap,
.vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane,
@@ -1869,7 +1866,7 @@
int ret;
v4l2_subdev_init(sd, &fimc_subdev_ops);
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id);
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK;
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index f25807d..379a5e9 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -213,6 +213,17 @@
return &fimc_formats[index];
}
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps)
+{
+ strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", dev_name(dev));
+ cap->device_caps = caps;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+}
+
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
int dw, int dh, int rotation)
{
@@ -955,8 +966,8 @@
}
if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities ||
fimc->id < 0) {
- dev_err(dev, "Invalid driver data or device id (%d/%d)\n",
- fimc->id, fimc->drv_data->num_entities);
+ dev_err(dev, "Invalid driver data or device id (%d)\n",
+ fimc->id);
return -EINVAL;
}
if (!dev->of_node)
@@ -1283,7 +1294,7 @@
.id_table = fimc_driver_ids,
.driver = {
.of_match_table = fimc_of_match,
- .name = FIMC_MODULE_NAME,
+ .name = FIMC_DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &fimc_pm_ops,
}
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index d2fe162..539a3f7 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -35,7 +35,7 @@
/* Time to wait for next frame VSYNC interrupt while stopping operation. */
#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define MAX_FIMC_CLOCKS 2
-#define FIMC_MODULE_NAME "s5p-fimc"
+#define FIMC_DRIVER_NAME "exynos4-fimc"
#define FIMC_MAX_DEVS 4
#define FIMC_MAX_OUT_BUFS 4
#define SCALER_MAX_HRATIO 64
@@ -425,7 +425,7 @@
struct regmap *sysreg;
const struct fimc_variant *variant;
const struct fimc_drvdata *drv_data;
- u16 id;
+ int id;
struct clk *clock[MAX_FIMC_CLOCKS];
void __iomem *regs;
wait_queue_head_t irq_queue;
@@ -620,6 +620,8 @@
/* fimc-core.c */
int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps);
int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
index 1ec6b3c..c397777 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -103,7 +103,6 @@
{ .compatible = FIMC_IS_I2C_COMPATIBLE },
{ },
};
-MODULE_DEVICE_TABLE(of, fimc_is_i2c_of_match);
static struct platform_driver fimc_is_i2c_driver = {
.probe = fimc_is_i2c_probe,
@@ -120,10 +119,8 @@
{
return platform_driver_register(&fimc_is_i2c_driver);
}
-EXPORT_SYMBOL(fimc_is_register_i2c_driver);
void fimc_is_unregister_i2c_driver(void)
{
platform_driver_unregister(&fimc_is_i2c_driver);
}
-EXPORT_SYMBOL(fimc_is_unregister_i2c_driver);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
index 02b2719..6647421 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
@@ -40,11 +40,6 @@
}
};
-static struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct fimc_is_sensor, subdev);
-}
-
static const struct v4l2_mbus_framefmt *find_sensor_format(
struct v4l2_mbus_framefmt *mf)
{
@@ -147,7 +142,7 @@
static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on)
{
- struct fimc_is_sensor *sensor = v4l2_get_subdevdata(sd);
+ struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
int gpio = sensor->gpio_reset;
int ret;
@@ -216,7 +211,8 @@
gpio = of_get_gpio_flags(dev->of_node, 0, NULL);
if (gpio_is_valid(gpio)) {
- ret = gpio_request_one(gpio, GPIOF_OUT_INIT_LOW, DRIVER_NAME);
+ ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW,
+ DRIVER_NAME);
if (ret < 0)
return ret;
}
@@ -228,13 +224,11 @@
ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES,
sensor->supplies);
if (ret < 0)
- goto err_gpio;
+ return ret;
of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node);
- if (!of_id) {
- ret = -ENODEV;
- goto err_reg;
- }
+ if (!of_id)
+ return -ENODEV;
sensor->drvdata = of_id->data;
sensor->dev = dev;
@@ -251,28 +245,18 @@
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0);
if (ret < 0)
- goto err_reg;
+ return ret;
- v4l2_set_subdevdata(sd, sensor);
pm_runtime_no_callbacks(dev);
pm_runtime_enable(dev);
- return 0;
-err_reg:
- regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies);
-err_gpio:
- if (gpio_is_valid(sensor->gpio_reset))
- gpio_free(sensor->gpio_reset);
return ret;
}
static int fimc_is_sensor_remove(struct i2c_client *client)
{
- struct fimc_is_sensor *sensor;
-
- regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies);
- media_entity_cleanup(&sensor->subdev.entity);
-
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ media_entity_cleanup(&sd->entity);
return 0;
}
@@ -294,7 +278,6 @@
},
{ }
};
-MODULE_DEVICE_TABLE(of, fimc_is_sensor_of_match);
static struct i2c_driver fimc_is_sensor_driver = {
.driver = {
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
index 50b8e4d..6036d49 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-sensor.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
@@ -77,6 +77,12 @@
struct v4l2_mbus_framefmt format;
};
+static inline
+struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct fimc_is_sensor, subdev);
+}
+
int fimc_is_register_sensor_driver(void);
void fimc_is_unregister_sensor_driver(void);
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 3c81c88..47c6363 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -220,7 +220,7 @@
if (WARN_ON(is->sensor))
continue;
- is->sensor = v4l2_get_subdevdata(sd);
+ is->sensor = sd_to_fimc_is_sensor(sd);
if (fimc_is_parse_sensor_config(is->sensor, child)) {
dev_warn(&is->pdev->dev, "DT parse error: %s\n",
@@ -766,7 +766,7 @@
static void fimc_is_debugfs_remove(struct fimc_is *is)
{
- debugfs_remove(is->debugfs_entry);
+ debugfs_remove_recursive(is->debugfs_entry);
is->debugfs_entry = NULL;
}
@@ -847,16 +847,17 @@
goto err_irq;
ret = fimc_is_setup_clocks(is);
+ pm_runtime_put_sync(dev);
+
if (ret < 0)
goto err_irq;
- pm_runtime_put_sync(dev);
is->clk_init = true;
is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(is->alloc_ctx)) {
ret = PTR_ERR(is->alloc_ctx);
- goto err_pm;
+ goto err_irq;
}
/*
* Register FIMC-IS V4L2 subdevs to this driver. The video nodes
@@ -885,8 +886,6 @@
fimc_is_unregister_subdevs(is);
err_irq:
free_irq(is->irq, is);
-err_pm:
- pm_runtime_put(dev);
err_clk:
fimc_is_put_clocks(is);
return ret;
@@ -995,9 +994,9 @@
static void fimc_is_module_exit(void)
{
- platform_driver_unregister(&fimc_is_driver);
- fimc_is_unregister_i2c_driver();
fimc_is_unregister_sensor_driver();
+ fimc_is_unregister_i2c_driver();
+ platform_driver_unregister(&fimc_is_driver);
}
module_init(fimc_is_module_init);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 3b9a664..d63947f 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -621,7 +621,7 @@
v4l2_subdev_init(sd, &fimc_is_subdev_ops);
sd->grp_id = GRP_ID_FIMC_IS;
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 661d0d1..14bb7bc 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1377,7 +1377,7 @@
int ret;
v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
@@ -1399,6 +1399,7 @@
sd->ctrl_handler = handler;
sd->internal_ops = &fimc_lite_subdev_internal_ops;
sd->entity.ops = &fimc_lite_subdev_media_ops;
+ sd->owner = THIS_MODULE;
v4l2_set_subdevdata(sd, fimc);
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index 71fed51..47da5e0 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -140,7 +140,7 @@
struct v4l2_subdev *sensor;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *test_pattern;
- u32 index;
+ int index;
struct fimc_pipeline pipeline;
const struct fimc_pipeline_ops *pipeline_ops;
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 8449c07..bde1f47 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -99,7 +99,7 @@
static void fimc_device_run(void *priv)
{
- struct vb2_buffer *vb = NULL;
+ struct vb2_buffer *src_vb, *dst_vb;
struct fimc_ctx *ctx = priv;
struct fimc_frame *sf, *df;
struct fimc_dev *fimc;
@@ -122,16 +122,18 @@
fimc_prepare_dma_offset(ctx, df);
}
- vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr);
+ src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
if (ret)
goto dma_unlock;
- vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, df, &df->paddr);
+ dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
if (ret)
goto dma_unlock;
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+
/* Reconfigure hardware if the context has changed. */
if (fimc->m2m.ctx != ctx) {
ctx->state |= FIMC_PARAMS;
@@ -249,22 +251,20 @@
* V4L2 ioctl handlers
*/
static int fimc_m2m_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
+ struct v4l2_capability *cap)
{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_dev *fimc = video_drvdata(file);
+ unsigned int caps;
- strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
* and are scheduled for removal.
*/
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
+ caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps);
return 0;
}
@@ -622,6 +622,7 @@
src_vq->ops = &fimc_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -633,6 +634,7 @@
dst_vq->ops = &fimc_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 1dbd554..15ef8f2 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -814,7 +814,6 @@
if (fmd->csis[i].sd == NULL)
continue;
v4l2_device_unregister_subdev(fmd->csis[i].sd);
- module_put(fmd->csis[i].sd->owner);
fmd->csis[i].sd = NULL;
}
for (i = 0; i < fmd->num_sensors; i++) {
@@ -823,6 +822,10 @@
fimc_md_unregister_sensor(fmd->sensor[i].subdev);
fmd->sensor[i].subdev = NULL;
}
+
+ if (fmd->fimc_is)
+ v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev);
+
v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n");
}
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 8636bcd..a2eda9d 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -549,10 +549,10 @@
static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
struct csis_state *state, struct v4l2_subdev_fh *fh,
- u32 pad, enum v4l2_subdev_format_whence which)
+ enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+ return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
return &state->format;
}
@@ -564,10 +564,7 @@
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *mf;
- if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
- return -EINVAL;
-
- mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ mf = __s5pcsis_get_format(state, fh, fmt->which);
if (fmt->pad == CSIS_PAD_SOURCE) {
if (mf) {
@@ -594,10 +591,7 @@
struct csis_state *state = sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *mf;
- if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
- return -EINVAL;
-
- mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ mf = __s5pcsis_get_format(state, fh, fmt->which);
if (!mf)
return -EINVAL;
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 6c4db9b..7585646 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -207,6 +207,9 @@
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -866,6 +869,7 @@
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &deinterlace_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_SRC].fmt = &formats[0];
q_data[V4L2_M2M_SRC].width = 640;
q_data[V4L2_M2M_SRC].height = 480;
@@ -882,6 +886,7 @@
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &deinterlace_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_DST].fmt = &formats[0];
q_data[V4L2_M2M_DST].width = 640;
q_data[V4L2_M2M_DST].height = 480;
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 7487d72..4cc7f65d 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -38,6 +38,10 @@
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.1");
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
#define MIN_W 32
#define MIN_H 32
#define MAX_W 640
@@ -67,7 +71,7 @@
#define MEM2MEM_VFLIP (1 << 1)
#define dprintk(dev, fmt, arg...) \
- v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
static void m2mtest_dev_release(struct device *dev)
@@ -234,6 +238,10 @@
bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
w = 0;
+ memcpy(&out_vb->v4l2_buf.timestamp,
+ &in_vb->v4l2_buf.timestamp,
+ sizeof(struct timeval));
+
switch (ctx->mode) {
case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
p_out += bytesperline * height - bytes_left;
@@ -844,6 +852,7 @@
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &m2mtest_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -855,6 +864,7 @@
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &m2mtest_qops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 4b9e0a2..f7440e5 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -377,6 +377,9 @@
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
spin_lock_irqsave(&pcdev->irqlock, flags);
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -763,6 +766,7 @@
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &emmaprp_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -774,6 +778,7 @@
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &emmaprp_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 14d663d..553d87e 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -158,6 +158,7 @@
src_vq->ops = &g2d_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -169,6 +170,7 @@
dst_vq->ops = &g2d_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -635,6 +637,9 @@
BUG_ON(src == NULL);
BUG_ON(dst == NULL);
+ dst->v4l2_buf.timecode = src->v4l2_buf.timecode;
+ dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp;
+
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 3b02375..15d2396 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1229,6 +1229,7 @@
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &s5p_jpeg_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1240,6 +1241,7 @@
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &s5p_jpeg_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -1287,6 +1289,9 @@
payload_size = jpeg_compressed_size(jpeg->regs);
}
+ dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+ dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+
v4l2_m2m_buf_done(src_buf, state);
if (curr_ctx->mode == S5P_JPEG_ENCODE)
vb2_set_plane_payload(dst_buf, 0, payload_size);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index e810b1a..01f9ae0 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -243,12 +243,10 @@
src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
- memcpy(&dst_buf->b->v4l2_buf.timecode,
- &src_buf->b->v4l2_buf.timecode,
- sizeof(struct v4l2_timecode));
- memcpy(&dst_buf->b->v4l2_buf.timestamp,
- &src_buf->b->v4l2_buf.timestamp,
- sizeof(struct timeval));
+ dst_buf->b->v4l2_buf.timecode =
+ src_buf->b->v4l2_buf.timecode;
+ dst_buf->b->v4l2_buf.timestamp =
+ src_buf->b->v4l2_buf.timestamp;
switch (frame_type) {
case S5P_FIMV_DECODE_FRAME_I_FRAME:
dst_buf->b->v4l2_buf.flags |=
@@ -1110,7 +1108,8 @@
}
if (pdev->dev.of_node) {
- if (s5p_mfc_alloc_memdevs(dev) < 0)
+ ret = s5p_mfc_alloc_memdevs(dev);
+ if (ret < 0)
goto err_res;
} else {
dev->mem_dev_l = device_find_child(&dev->plat_dev->dev,
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index b8f9f85..72e3fa6 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -528,8 +528,10 @@
mutex_unlock(&ictx->lock);
retval = wait_for_completion_interruptible(
&ictx->tx.finished);
- if (retval)
+ if (retval) {
+ usb_kill_urb(ictx->tx_urb);
pr_err_ratelimited("task interrupted\n");
+ }
mutex_lock(&ictx->lock);
retval = ictx->tx.status;
@@ -2093,7 +2095,8 @@
}
-static struct imon_context *imon_init_intf0(struct usb_interface *intf)
+static struct imon_context *imon_init_intf0(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
struct imon_context *ictx;
struct urb *rx_urb;
@@ -2133,6 +2136,10 @@
ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
+ /* default send_packet delay is 5ms but some devices need more */
+ ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
+ 20 : 5;
+
ret = -ENODEV;
iface_desc = intf->cur_altsetting;
if (!imon_find_endpoints(ictx, iface_desc)) {
@@ -2311,7 +2318,7 @@
first_if_ctx = usb_get_intfdata(first_if);
if (ifnum == 0) {
- ictx = imon_init_intf0(interface);
+ ictx = imon_init_intf0(interface, id);
if (!ictx) {
pr_err("failed to initialize context!\n");
ret = -ENODEV;
@@ -2319,7 +2326,14 @@
}
} else {
- /* this is the secondary interface on the device */
+ /* this is the secondary interface on the device */
+
+ /* fail early if first intf failed to register */
+ if (!first_if_ctx) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
ictx = imon_init_intf1(interface, first_if_ctx);
if (!ictx) {
pr_err("failed to attach to context!\n");
@@ -2329,10 +2343,6 @@
}
- /* default send_packet delay is 5ms but some devices need more */
- ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
- 20 : 5;
-
usb_set_intfdata(interface, ictx);
if (ifnum == 0) {
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index ffabd66..f6768ca 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -248,4 +248,11 @@
default m if !MEDIA_SUBDRV_AUTOSELECT
help
ITE Tech IT913x silicon tuner driver.
+
+config MEDIA_TUNER_R820T
+ tristate "Rafael Micro R820T silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Rafael Micro R820T silicon tuner driver.
endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 2ebe4b7..308f108 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -35,6 +35,7 @@
obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o
+obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
new file mode 100644
index 0000000..905a106
--- /dev/null
+++ b/drivers/media/tuners/r820t.c
@@ -0,0 +1,2352 @@
+/*
+ * Rafael Micro R820T driver
+ *
+ * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This driver was written from scratch, based on an existing driver
+ * that it is part of rtl-sdr git tree, released under GPLv2:
+ * https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug
+ * https://github.com/n1gp/gr-baz
+ *
+ * From what I understood from the threads, the original driver was converted
+ * to userspace from a Realtek tree. I couldn't find the original tree.
+ * However, the original driver look awkward on my eyes. So, I decided to
+ * write a new version from it from the scratch, while trying to reproduce
+ * everything found there.
+ *
+ * TODO:
+ * After locking, the original driver seems to have some routines to
+ * improve reception. This was not implemented here yet.
+ *
+ * RF Gain set/get is not implemented.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/bitrev.h>
+
+#include "tuner-i2c.h"
+#include "r820t.h"
+
+/*
+ * FIXME: I think that there are only 32 registers, but better safe than
+ * sorry. After finishing the driver, we may review it.
+ */
+#define REG_SHADOW_START 5
+#define NUM_REGS 27
+#define NUM_IMR 5
+#define IMR_TRIAL 9
+
+#define VER_NUM 49
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static int no_imr_cal;
+module_param(no_imr_cal, int, 0444);
+MODULE_PARM_DESC(no_imr_cal, "Disable IMR calibration at module init");
+
+
+/*
+ * enums and structures
+ */
+
+enum xtal_cap_value {
+ XTAL_LOW_CAP_30P = 0,
+ XTAL_LOW_CAP_20P,
+ XTAL_LOW_CAP_10P,
+ XTAL_LOW_CAP_0P,
+ XTAL_HIGH_CAP_0P
+};
+
+struct r820t_sect_type {
+ u8 phase_y;
+ u8 gain_x;
+ u16 value;
+};
+
+struct r820t_priv {
+ struct list_head hybrid_tuner_instance_list;
+ const struct r820t_config *cfg;
+ struct tuner_i2c_props i2c_props;
+ struct mutex lock;
+
+ u8 regs[NUM_REGS];
+ u8 buf[NUM_REGS + 1];
+ enum xtal_cap_value xtal_cap_sel;
+ u16 pll; /* kHz */
+ u32 int_freq;
+ u8 fil_cal_code;
+ bool imr_done;
+ bool has_lock;
+ bool init_done;
+ struct r820t_sect_type imr_data[NUM_IMR];
+
+ /* Store current mode */
+ u32 delsys;
+ enum v4l2_tuner_type type;
+ v4l2_std_id std;
+ u32 bw; /* in MHz */
+};
+
+struct r820t_freq_range {
+ u32 freq;
+ u8 open_d;
+ u8 rf_mux_ploy;
+ u8 tf_c;
+ u8 xtal_cap20p;
+ u8 xtal_cap10p;
+ u8 xtal_cap0p;
+ u8 imr_mem; /* Not used, currently */
+};
+
+#define VCO_POWER_REF 0x02
+#define DIP_FREQ 32000000
+
+/*
+ * Static constants
+ */
+
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(r820t_list_mutex);
+
+/* Those initial values start from REG_SHADOW_START */
+static const u8 r820t_init_array[NUM_REGS] = {
+ 0x83, 0x32, 0x75, /* 05 to 07 */
+ 0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */
+ 0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */
+ 0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */
+ 0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */
+ 0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */
+ 0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */
+};
+
+/* Tuner frequency ranges */
+static const struct r820t_freq_range freq_ranges[] = {
+ {
+ .freq = 0,
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0xdf, /* R27[7:0] band2,band0 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 50, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0xbe, /* R27[7:0] band4,band1 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 55, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x8b, /* R27[7:0] band7,band4 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 60, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x7b, /* R27[7:0] band8,band4 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 65, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x69, /* R27[7:0] band9,band6 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 70, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x58, /* R27[7:0] band10,band7 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 75, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x44, /* R27[7:0] band11,band11 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 80, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x44, /* R27[7:0] band11,band11 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 90, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x34, /* R27[7:0] band12,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 100, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x34, /* R27[7:0] band12,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 110, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x24, /* R27[7:0] band13,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 120, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x24, /* R27[7:0] band13,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 140, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x14, /* R27[7:0] band14,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 180, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x13, /* R27[7:0] band14,band12 */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 220, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x13, /* R27[7:0] band14,band12 */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 250, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x11, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 280, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 310, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 450, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 3,
+ }, {
+ .freq = 588, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 3,
+ }, {
+ .freq = 650, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 4,
+ }
+};
+
+static int r820t_xtal_capacitor[][2] = {
+ { 0x0b, XTAL_LOW_CAP_30P },
+ { 0x02, XTAL_LOW_CAP_20P },
+ { 0x01, XTAL_LOW_CAP_10P },
+ { 0x00, XTAL_LOW_CAP_0P },
+ { 0x10, XTAL_HIGH_CAP_0P },
+};
+
+/*
+ * measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm
+ * input power, for raw results see:
+ * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/
+ */
+
+static const int r820t_lna_gain_steps[] = {
+ 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13
+};
+
+static const int r820t_mixer_gain_steps[] = {
+ 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8
+};
+
+/*
+ * I2C read/write code and shadow registers logic
+ */
+static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val,
+ int len)
+{
+ int r = reg - REG_SHADOW_START;
+
+ if (r < 0) {
+ len += r;
+ r = 0;
+ }
+ if (len <= 0)
+ return;
+ if (len > NUM_REGS)
+ len = NUM_REGS;
+
+ tuner_dbg("%s: prev reg=%02x len=%d: %*ph\n",
+ __func__, r + REG_SHADOW_START, len, len, val);
+
+ memcpy(&priv->regs[r], val, len);
+}
+
+static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val,
+ int len)
+{
+ int rc, size, pos = 0;
+
+ /* Store the shadow registers */
+ shadow_store(priv, reg, val, len);
+
+ do {
+ if (len > priv->cfg->max_i2c_msg_len - 1)
+ size = priv->cfg->max_i2c_msg_len - 1;
+ else
+ size = len;
+
+ /* Fill I2C buffer */
+ priv->buf[0] = reg;
+ memcpy(&priv->buf[1], &val[pos], size);
+
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, priv->buf, size + 1);
+ if (rc != size + 1) {
+ tuner_info("%s: i2c wr failed=%d reg=%02x len=%d: %*ph\n",
+ __func__, rc, reg, size, size, &priv->buf[1]);
+ if (rc < 0)
+ return rc;
+ return -EREMOTEIO;
+ }
+ tuner_dbg("%s: i2c wr reg=%02x len=%d: %*ph\n",
+ __func__, reg, size, size, &priv->buf[1]);
+
+ reg += size;
+ len -= size;
+ pos += size;
+ } while (len > 0);
+
+ return 0;
+}
+
+static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
+{
+ return r820t_write(priv, reg, &val, 1);
+}
+
+static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
+{
+ reg -= REG_SHADOW_START;
+
+ if (reg >= 0 && reg < NUM_REGS)
+ return priv->regs[reg];
+ else
+ return -EINVAL;
+}
+
+static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
+ u8 bit_mask)
+{
+ int rc = r820t_read_cache_reg(priv, reg);
+
+ if (rc < 0)
+ return rc;
+
+ val = (rc & ~bit_mask) | (val & bit_mask);
+
+ return r820t_write(priv, reg, &val, 1);
+}
+
+static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
+{
+ int rc, i;
+ u8 *p = &priv->buf[1];
+
+ priv->buf[0] = reg;
+
+ rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, priv->buf, 1, p, len);
+ if (rc != len) {
+ tuner_info("%s: i2c rd failed=%d reg=%02x len=%d: %*ph\n",
+ __func__, rc, reg, len, len, p);
+ if (rc < 0)
+ return rc;
+ return -EREMOTEIO;
+ }
+
+ /* Copy data to the output buffer */
+ for (i = 0; i < len; i++)
+ val[i] = bitrev8(p[i]);
+
+ tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n",
+ __func__, reg, len, len, val);
+
+ return 0;
+}
+
+/*
+ * r820t tuning logic
+ */
+
+static int r820t_set_mux(struct r820t_priv *priv, u32 freq)
+{
+ const struct r820t_freq_range *range;
+ int i, rc;
+ u8 val, reg08, reg09;
+
+ /* Get the proper frequency range */
+ freq = freq / 1000000;
+ for (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) {
+ if (freq < freq_ranges[i + 1].freq)
+ break;
+ }
+ range = &freq_ranges[i];
+
+ tuner_dbg("set r820t range#%d for frequency %d MHz\n", i, freq);
+
+ /* Open Drain */
+ rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* RF_MUX,Polymux */
+ rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3);
+ if (rc < 0)
+ return rc;
+
+ /* TF BAND */
+ rc = r820t_write_reg(priv, 0x1b, range->tf_c);
+ if (rc < 0)
+ return rc;
+
+ /* XTAL CAP & Drive */
+ switch (priv->xtal_cap_sel) {
+ case XTAL_LOW_CAP_30P:
+ case XTAL_LOW_CAP_20P:
+ val = range->xtal_cap20p | 0x08;
+ break;
+ case XTAL_LOW_CAP_10P:
+ val = range->xtal_cap10p | 0x08;
+ break;
+ case XTAL_HIGH_CAP_0P:
+ val = range->xtal_cap0p | 0x00;
+ break;
+ default:
+ case XTAL_LOW_CAP_0P:
+ val = range->xtal_cap0p | 0x08;
+ break;
+ }
+ rc = r820t_write_reg_mask(priv, 0x10, val, 0x0b);
+ if (rc < 0)
+ return rc;
+
+ if (priv->imr_done) {
+ reg08 = priv->imr_data[range->imr_mem].gain_x;
+ reg09 = priv->imr_data[range->imr_mem].phase_y;
+ } else {
+ reg08 = 0;
+ reg09 = 0;
+ }
+ rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f);
+
+ return rc;
+}
+
+static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type,
+ u32 freq)
+{
+ u32 vco_freq;
+ int rc, i;
+ unsigned sleep_time = 10000;
+ u32 vco_fra; /* VCO contribution by SDM (kHz) */
+ u32 vco_min = 1770000;
+ u32 vco_max = vco_min * 2;
+ u32 pll_ref;
+ u16 n_sdm = 2;
+ u16 sdm = 0;
+ u8 mix_div = 2;
+ u8 div_buf = 0;
+ u8 div_num = 0;
+ u8 refdiv2 = 0;
+ u8 ni, si, nint, vco_fine_tune, val;
+ u8 data[5];
+
+ /* Frequency in kHz */
+ freq = freq / 1000;
+ pll_ref = priv->cfg->xtal / 1000;
+
+#if 0
+ /* Doesn't exist on rtl-sdk, and on field tests, caused troubles */
+ if ((priv->cfg->rafael_chip == CHIP_R620D) ||
+ (priv->cfg->rafael_chip == CHIP_R828D) ||
+ (priv->cfg->rafael_chip == CHIP_R828)) {
+ /* ref set refdiv2, reffreq = Xtal/2 on ATV application */
+ if (type != V4L2_TUNER_DIGITAL_TV) {
+ pll_ref /= 2;
+ refdiv2 = 0x10;
+ sleep_time = 20000;
+ }
+ } else {
+ if (priv->cfg->xtal > 24000000) {
+ pll_ref /= 2;
+ refdiv2 = 0x10;
+ }
+ }
+#endif
+
+ rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set pll autotune = 128kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
+ if (rc < 0)
+ return rc;
+
+ /* set VCO current = 100 */
+ rc = r820t_write_reg_mask(priv, 0x12, 0x80, 0xe0);
+ if (rc < 0)
+ return rc;
+
+ /* Calculate divider */
+ while (mix_div <= 64) {
+ if (((freq * mix_div) >= vco_min) &&
+ ((freq * mix_div) < vco_max)) {
+ div_buf = mix_div;
+ while (div_buf > 2) {
+ div_buf = div_buf >> 1;
+ div_num++;
+ }
+ break;
+ }
+ mix_div = mix_div << 1;
+ }
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ vco_fine_tune = (data[4] & 0x30) >> 4;
+
+ if (vco_fine_tune > VCO_POWER_REF)
+ div_num = div_num - 1;
+ else if (vco_fine_tune < VCO_POWER_REF)
+ div_num = div_num + 1;
+
+ rc = r820t_write_reg_mask(priv, 0x10, div_num << 5, 0xe0);
+ if (rc < 0)
+ return rc;
+
+ vco_freq = freq * mix_div;
+ nint = vco_freq / (2 * pll_ref);
+ vco_fra = vco_freq - 2 * pll_ref * nint;
+
+ /* boundary spur prevention */
+ if (vco_fra < pll_ref / 64) {
+ vco_fra = 0;
+ } else if (vco_fra > pll_ref * 127 / 64) {
+ vco_fra = 0;
+ nint++;
+ } else if ((vco_fra > pll_ref * 127 / 128) && (vco_fra < pll_ref)) {
+ vco_fra = pll_ref * 127 / 128;
+ } else if ((vco_fra > pll_ref) && (vco_fra < pll_ref * 129 / 128)) {
+ vco_fra = pll_ref * 129 / 128;
+ }
+
+ if (nint > 63) {
+ tuner_info("No valid PLL values for %u kHz!\n", freq);
+ return -EINVAL;
+ }
+
+ ni = (nint - 13) / 4;
+ si = nint - 4 * ni - 13;
+
+ rc = r820t_write_reg(priv, 0x14, ni + (si << 6));
+ if (rc < 0)
+ return rc;
+
+ /* pw_sdm */
+ if (!vco_fra)
+ val = 0x08;
+ else
+ val = 0x00;
+
+ rc = r820t_write_reg_mask(priv, 0x12, val, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* sdm calculator */
+ while (vco_fra > 1) {
+ if (vco_fra > (2 * pll_ref / n_sdm)) {
+ sdm = sdm + 32768 / (n_sdm / 2);
+ vco_fra = vco_fra - 2 * pll_ref / n_sdm;
+ if (n_sdm >= 0x8000)
+ break;
+ }
+ n_sdm = n_sdm << 1;
+ }
+
+ tuner_dbg("freq %d kHz, pll ref %d%s, sdm=0x%04x\n",
+ freq, pll_ref, refdiv2 ? " / 2" : "", sdm);
+
+ rc = r820t_write_reg(priv, 0x16, sdm >> 8);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x15, sdm & 0xff);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < 2; i++) {
+ usleep_range(sleep_time, sleep_time + 1000);
+
+ /* Check if PLL has locked */
+ rc = r820t_read(priv, 0x00, data, 3);
+ if (rc < 0)
+ return rc;
+ if (data[2] & 0x40)
+ break;
+
+ if (!i) {
+ /* Didn't lock. Increase VCO current */
+ rc = r820t_write_reg_mask(priv, 0x12, 0x60, 0xe0);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ if (!(data[2] & 0x40)) {
+ priv->has_lock = false;
+ return 0;
+ }
+
+ priv->has_lock = true;
+ tuner_dbg("tuner has lock at frequency %d kHz\n", freq);
+
+ /* set pll autotune = 8kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x08, 0x08);
+
+ return rc;
+}
+
+static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std,
+ u32 delsys)
+{
+ int rc;
+ u8 mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l;
+ u8 air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur;
+
+ tuner_dbg("adjusting tuner parameters for the standard\n");
+
+ switch (delsys) {
+ case SYS_DVBT:
+ if ((freq == 506000000) || (freq == 666000000) ||
+ (freq == 818000000)) {
+ mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ cp_cur = 0x28; /* 101, 0.2 */
+ div_buf_cur = 0x20; /* 10, 200u */
+ } else {
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ }
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ filter_cur = 0x40; /* 10, low */
+ break;
+ case SYS_DVBT2:
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ case SYS_ISDBT:
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ default: /* DVB-T 8M */
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ }
+
+ if (priv->cfg->use_diplexer &&
+ ((priv->cfg->rafael_chip == CHIP_R820T) ||
+ (priv->cfg->rafael_chip == CHIP_R828S) ||
+ (priv->cfg->rafael_chip == CHIP_R820C))) {
+ if (freq > DIP_FREQ)
+ air_cable1_in = 0x00;
+ else
+ air_cable1_in = 0x60;
+ cable2_in = 0x00;
+ }
+
+ rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0xf8);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0d, lna_vth_l);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0e, mixer_vth_l);
+ if (rc < 0)
+ return rc;
+
+ /* Air-IN only for Astrometa */
+ rc = r820t_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x06, cable2_in, 0x08);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x11, cp_cur, 0x38);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x17, div_buf_cur, 0x30);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x0a, filter_cur, 0x60);
+ if (rc < 0)
+ return rc;
+ /*
+ * Original driver initializes regs 0x05 and 0x06 with the
+ * same value again on this point. Probably, it is just an
+ * error there
+ */
+
+ /*
+ * Set LNA
+ */
+
+ tuner_dbg("adjusting LNA parameters\n");
+ if (type != V4L2_TUNER_ANALOG_TV) {
+ /* LNA TOP: lowest */
+ rc = r820t_write_reg_mask(priv, 0x1d, 0, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /* 0: normal mode */
+ rc = r820t_write_reg_mask(priv, 0x1c, 0, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* 0: PRE_DECT off */
+ rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 250hz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x30, 0x30);
+ if (rc < 0)
+ return rc;
+
+ msleep(250);
+
+ /* write LNA TOP = 3 */
+ rc = r820t_write_reg_mask(priv, 0x1d, 0x18, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * write discharge mode
+ * FIXME: IMHO, the mask here is wrong, but it matches
+ * what's there at the original driver
+ */
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* LNA discharge current */
+ rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 60hz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x20, 0x30);
+ if (rc < 0)
+ return rc;
+ } else {
+ /* PRE_DECT off */
+ rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* write LNA TOP */
+ rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * write discharge mode
+ * FIXME: IMHO, the mask here is wrong, but it matches
+ * what's there at the original driver
+ */
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* LNA discharge current */
+ rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 1Khz, external det1 cap 1u */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x30);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x04);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int r820t_set_tv_standard(struct r820t_priv *priv,
+ unsigned bw,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std, u32 delsys)
+
+{
+ int rc, i;
+ u32 if_khz, filt_cal_lo;
+ u8 data[5], val;
+ u8 filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through;
+ u8 lt_att, flt_ext_widest, polyfil_cur;
+ bool need_calibration;
+
+ tuner_dbg("selecting the delivery system\n");
+
+ if (delsys == SYS_ISDBT) {
+ if_khz = 4063;
+ filt_cal_lo = 59000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
+ ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else {
+ if (bw <= 6) {
+ if_khz = 3570;
+ filt_cal_lo = 56000; /* 52000->56000 */
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else if (bw == 7) {
+#if 0
+ /*
+ * There are two 7 MHz tables defined on the original
+ * driver, but just the second one seems to be visible
+ * by rtl2832. Keep this one here commented, as it
+ * might be needed in the future
+ */
+
+ if_khz = 4070;
+ filt_cal_lo = 60000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+#endif
+ /* 7 MHz, second table */
+ if_khz = 4570;
+ filt_cal_lo = 63000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else {
+ if_khz = 4570;
+ filt_cal_lo = 68500;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ }
+ }
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* Init Flag & Xtal_check Result */
+ if (priv->imr_done)
+ val = 1 | priv->xtal_cap_sel << 1;
+ else
+ val = 0;
+ rc = r820t_write_reg_mask(priv, 0x0c, val, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* version */
+ rc = r820t_write_reg_mask(priv, 0x13, VER_NUM, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ /* for LT Gain test */
+ if (type != V4L2_TUNER_ANALOG_TV) {
+ rc = r820t_write_reg_mask(priv, 0x1d, 0x00, 0x38);
+ if (rc < 0)
+ return rc;
+ usleep_range(1000, 2000);
+ }
+ priv->int_freq = if_khz * 1000;
+
+ /* Check if standard changed. If so, filter calibration is needed */
+ if (type != priv->type)
+ need_calibration = true;
+ else if ((type == V4L2_TUNER_ANALOG_TV) && (std != priv->std))
+ need_calibration = true;
+ else if ((type == V4L2_TUNER_DIGITAL_TV) &&
+ ((delsys != priv->delsys) || bw != priv->bw))
+ need_calibration = true;
+ else
+ need_calibration = false;
+
+ if (need_calibration) {
+ tuner_dbg("calibrating the tuner\n");
+ for (i = 0; i < 2; i++) {
+ /* Set filt_cap */
+ rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* set cali clk =on */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* X'tal cap 0pF for PLL */
+ rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_set_pll(priv, type, filt_cal_lo * 1000);
+ if (rc < 0 || !priv->has_lock)
+ return rc;
+
+ /* Start Trigger */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(1000, 2000);
+
+ /* Stop Trigger */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set cali clk =off */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* Check if calibration worked */
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ priv->fil_cal_code = data[4] & 0x0f;
+ if (priv->fil_cal_code && priv->fil_cal_code != 0x0f)
+ break;
+ }
+ /* narrowest */
+ if (priv->fil_cal_code == 0x0f)
+ priv->fil_cal_code = 0;
+ }
+
+ rc = r820t_write_reg_mask(priv, 0x0a,
+ filt_q | priv->fil_cal_code, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* Set BW, Filter_gain, & HP corner */
+ rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0xef);
+ if (rc < 0)
+ return rc;
+
+
+ /* Set Img_R */
+ rc = r820t_write_reg_mask(priv, 0x07, img_r, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Set filt_3dB, V6MHz */
+ rc = r820t_write_reg_mask(priv, 0x06, filt_gain, 0x30);
+ if (rc < 0)
+ return rc;
+
+ /* channel filter extension */
+ rc = r820t_write_reg_mask(priv, 0x1e, ext_enable, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Loop through */
+ rc = r820t_write_reg_mask(priv, 0x05, loop_through, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Loop through attenuation */
+ rc = r820t_write_reg_mask(priv, 0x1f, lt_att, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* filter extension widest */
+ rc = r820t_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* RF poly filter current */
+ rc = r820t_write_reg_mask(priv, 0x19, polyfil_cur, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Store current standard. If it changes, re-calibrate the tuner */
+ priv->delsys = delsys;
+ priv->type = type;
+ priv->std = std;
+ priv->bw = bw;
+
+ return 0;
+}
+
+static int r820t_read_gain(struct r820t_priv *priv)
+{
+ u8 data[4];
+ int rc;
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4);
+}
+
+#if 0
+/* FIXME: This routine requires more testing */
+static int r820t_set_gain_mode(struct r820t_priv *priv,
+ bool set_manual_gain,
+ int gain)
+{
+ int rc;
+
+ if (set_manual_gain) {
+ int i, total_gain = 0;
+ uint8_t mix_index = 0, lna_index = 0;
+ u8 data[4];
+
+ /* LNA auto off */
+ rc = r820t_write_reg_mask(priv, 0x05, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* Mixer auto off */
+ rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ /* set fixed VGA gain for now (16.3 dB) */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x08, 0x9f);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < 15; i++) {
+ if (total_gain >= gain)
+ break;
+
+ total_gain += r820t_lna_gain_steps[++lna_index];
+
+ if (total_gain >= gain)
+ break;
+
+ total_gain += r820t_mixer_gain_steps[++mix_index];
+ }
+
+ /* set LNA gain */
+ rc = r820t_write_reg_mask(priv, 0x05, lna_index, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* set Mixer gain */
+ rc = r820t_write_reg_mask(priv, 0x07, mix_index, 0x0f);
+ if (rc < 0)
+ return rc;
+ } else {
+ /* LNA */
+ rc = r820t_write_reg_mask(priv, 0x05, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* Mixer */
+ rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set fixed VGA gain for now (26.5 dB) */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+#endif
+
+static int generic_set_freq(struct dvb_frontend *fe,
+ u32 freq /* in HZ */,
+ unsigned bw,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std, u32 delsys)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc = -EINVAL;
+ u32 lo_freq;
+
+ tuner_dbg("should set frequency to %d kHz, bw %d MHz\n",
+ freq / 1000, bw);
+
+ rc = r820t_set_tv_standard(priv, bw, type, std, delsys);
+ if (rc < 0)
+ goto err;
+
+ if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC))
+ lo_freq = freq - priv->int_freq;
+ else
+ lo_freq = freq + priv->int_freq;
+
+ rc = r820t_set_mux(priv, lo_freq);
+ if (rc < 0)
+ goto err;
+
+ rc = r820t_set_pll(priv, type, lo_freq);
+ if (rc < 0 || !priv->has_lock)
+ goto err;
+
+ rc = r820t_sysfreq_sel(priv, freq, type, std, delsys);
+ if (rc < 0)
+ goto err;
+
+ tuner_dbg("%s: PLL locked on frequency %d Hz, gain=%d\n",
+ __func__, freq, r820t_read_gain(priv));
+
+err:
+
+ if (rc < 0)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+/*
+ * r820t standby logic
+ */
+
+static int r820t_standby(struct r820t_priv *priv)
+{
+ int rc;
+
+ /* If device was not initialized yet, don't need to standby */
+ if (!priv->init_done)
+ return 0;
+
+ rc = r820t_write_reg(priv, 0x06, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x05, 0x03);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x07, 0x3a);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x08, 0x40);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x09, 0xc0);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0a, 0x36);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0c, 0x35);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0f, 0x68);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x11, 0x03);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x17, 0xf4);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x19, 0x0c);
+
+ /* Force initial calibration */
+ priv->type = -1;
+
+ return rc;
+}
+
+/*
+ * r820t device init logic
+ */
+
+static int r820t_xtal_check(struct r820t_priv *priv)
+{
+ int rc, i;
+ u8 data[3], val;
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* cap 30pF & Drive Low */
+ rc = r820t_write_reg_mask(priv, 0x10, 0x0b, 0x0b);
+ if (rc < 0)
+ return rc;
+
+ /* set pll autotune = 128kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
+ if (rc < 0)
+ return rc;
+
+ /* set manual initial reg = 111111; */
+ rc = r820t_write_reg_mask(priv, 0x13, 0x7f, 0x7f);
+ if (rc < 0)
+ return rc;
+
+ /* set auto */
+ rc = r820t_write_reg_mask(priv, 0x13, 0x00, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* Try several xtal capacitor alternatives */
+ for (i = 0; i < ARRAY_SIZE(r820t_xtal_capacitor); i++) {
+ rc = r820t_write_reg_mask(priv, 0x10,
+ r820t_xtal_capacitor[i][0], 0x1b);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(5000, 6000);
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+ if ((!data[2]) & 0x40)
+ continue;
+
+ val = data[2] & 0x3f;
+
+ if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23))
+ break;
+
+ if (val != 0x3f)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(r820t_xtal_capacitor))
+ return -EINVAL;
+
+ return r820t_xtal_capacitor[i][1];
+}
+
+static int r820t_imr_prepare(struct r820t_priv *priv)
+{
+ int rc;
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* lna off (air-in off) */
+ rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20);
+ if (rc < 0)
+ return rc;
+
+ /* mixer gain mode = manual */
+ rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* filter corner = lowest */
+ rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* filter bw=+2cap, hp=5M */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f);
+ if (rc < 0)
+ return rc;
+
+ /* adc=on, vga code mode, gain = 26.5dB */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
+ if (rc < 0)
+ return rc;
+
+ /* ring clk = on */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* ring power = on */
+ rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* from ring = ring pll in */
+ rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02);
+ if (rc < 0)
+ return rc;
+
+ /* sw_pdect = det3 */
+ rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Set filt_3dB */
+ rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20);
+
+ return rc;
+}
+
+static int r820t_multi_read(struct r820t_priv *priv)
+{
+ int rc, i;
+ u8 data[2], min = 0, max = 255, sum = 0;
+
+ usleep_range(5000, 6000);
+
+ for (i = 0; i < 6; i++) {
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ sum += data[1];
+
+ if (data[1] < min)
+ min = data[1];
+
+ if (data[1] > max)
+ max = data[1];
+ }
+ rc = sum - max - min;
+
+ return rc;
+}
+
+static int r820t_imr_cross(struct r820t_priv *priv,
+ struct r820t_sect_type iq_point[3],
+ u8 *x_direct)
+{
+ struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */
+ struct r820t_sect_type tmp;
+ int i, rc;
+ u8 reg08, reg09;
+
+ reg08 = r820t_read_cache_reg(priv, 8) & 0xc0;
+ reg09 = r820t_read_cache_reg(priv, 9) & 0xc0;
+
+ tmp.gain_x = 0;
+ tmp.phase_y = 0;
+ tmp.value = 255;
+
+ for (i = 0; i < 5; i++) {
+ switch (i) {
+ case 0:
+ cross[i].gain_x = reg08;
+ cross[i].phase_y = reg09;
+ break;
+ case 1:
+ cross[i].gain_x = reg08; /* 0 */
+ cross[i].phase_y = reg09 + 1; /* Q-1 */
+ break;
+ case 2:
+ cross[i].gain_x = reg08; /* 0 */
+ cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */
+ break;
+ case 3:
+ cross[i].gain_x = reg08 + 1; /* Q-1 */
+ cross[i].phase_y = reg09;
+ break;
+ default:
+ cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */
+ cross[i].phase_y = reg09;
+ }
+
+ rc = r820t_write_reg(priv, 0x08, cross[i].gain_x);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, 0x09, cross[i].phase_y);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+
+ cross[i].value = rc;
+
+ if (cross[i].value < tmp.value)
+ memcpy(&tmp, &cross[i], sizeof(tmp));
+ }
+
+ if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */
+ *x_direct = 0;
+
+ iq_point[0] = cross[0];
+ iq_point[1] = cross[1];
+ iq_point[2] = cross[2];
+ } else { /* (0,0) or x-direction */
+ *x_direct = 1;
+
+ iq_point[0] = cross[0];
+ iq_point[1] = cross[3];
+ iq_point[2] = cross[4];
+ }
+ return 0;
+}
+
+static void r820t_compre_cor(struct r820t_sect_type iq[3])
+{
+ int i;
+
+ for (i = 3; i > 0; i--) {
+ if (iq[0].value > iq[i - 1].value)
+ swap(iq[0], iq[i - 1]);
+ }
+}
+
+static int r820t_compre_step(struct r820t_priv *priv,
+ struct r820t_sect_type iq[3], u8 reg)
+{
+ int rc;
+ struct r820t_sect_type tmp;
+
+ /*
+ * Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare
+ * with min value:
+ * new < min => update to min and continue
+ * new > min => Exit
+ */
+
+ /* min value already saved in iq[0] */
+ tmp.phase_y = iq[0].phase_y;
+ tmp.gain_x = iq[0].gain_x;
+
+ while (((tmp.gain_x & 0x1f) < IMR_TRIAL) &&
+ ((tmp.phase_y & 0x1f) < IMR_TRIAL)) {
+ if (reg == 0x08)
+ tmp.gain_x++;
+ else
+ tmp.phase_y++;
+
+ rc = r820t_write_reg(priv, 0x08, tmp.gain_x);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, 0x09, tmp.phase_y);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+ tmp.value = rc;
+
+ if (tmp.value <= iq[0].value) {
+ iq[0].gain_x = tmp.gain_x;
+ iq[0].phase_y = tmp.phase_y;
+ iq[0].value = tmp.value;
+ } else {
+ return 0;
+ }
+
+ }
+
+ return 0;
+}
+
+static int r820t_iq_tree(struct r820t_priv *priv,
+ struct r820t_sect_type iq[3],
+ u8 fix_val, u8 var_val, u8 fix_reg)
+{
+ int rc, i;
+ u8 tmp, var_reg;
+
+ /*
+ * record IMC results by input gain/phase location then adjust
+ * gain or phase positive 1 step and negtive 1 step,
+ * both record results
+ */
+
+ if (fix_reg == 0x08)
+ var_reg = 0x09;
+ else
+ var_reg = 0x08;
+
+ for (i = 0; i < 3; i++) {
+ rc = r820t_write_reg(priv, fix_reg, fix_val);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, var_reg, var_val);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+ iq[i].value = rc;
+
+ if (fix_reg == 0x08) {
+ iq[i].gain_x = fix_val;
+ iq[i].phase_y = var_val;
+ } else {
+ iq[i].phase_y = fix_val;
+ iq[i].gain_x = var_val;
+ }
+
+ if (i == 0) { /* try right-side point */
+ var_val++;
+ } else if (i == 1) { /* try left-side point */
+ /* if absolute location is 1, change I/Q direction */
+ if ((var_val & 0x1f) < 0x02) {
+ tmp = 2 - (var_val & 0x1f);
+
+ /* b[5]:I/Q selection. 0:Q-path, 1:I-path */
+ if (var_val & 0x20) {
+ var_val &= 0xc0;
+ var_val |= tmp;
+ } else {
+ var_val |= 0x20 | tmp;
+ }
+ } else {
+ var_val -= 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int r820t_section(struct r820t_priv *priv,
+ struct r820t_sect_type *iq_point)
+{
+ int rc;
+ struct r820t_sect_type compare_iq[3], compare_bet[3];
+
+ /* Try X-1 column and save min result to compare_bet[0] */
+ if (!(iq_point->gain_x & 0x1f))
+ compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */
+ else
+ compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ /* y-direction */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[0] = compare_iq[0];
+
+ /* Try X column and save min result to compare_bet[1] */
+ compare_iq[0].gain_x = iq_point->gain_x;
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[1] = compare_iq[0];
+
+ /* Try X+1 column and save min result to compare_bet[2] */
+ if ((iq_point->gain_x & 0x1f) == 0x00)
+ compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */
+ else
+ compare_iq[0].gain_x = iq_point->gain_x + 1;
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[2] = compare_iq[0];
+
+ r820t_compre_cor(compare_bet);
+
+ *iq_point = compare_bet[0];
+
+ return 0;
+}
+
+static int r820t_vga_adjust(struct r820t_priv *priv)
+{
+ int rc;
+ u8 vga_count;
+
+ /* increase vga power to let image significant */
+ for (vga_count = 12; vga_count < 16; vga_count++) {
+ rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(10000, 11000);
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+
+ if (rc > 40 * 4)
+ break;
+ }
+
+ return 0;
+}
+
+static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
+{
+ struct r820t_sect_type compare_iq[3];
+ int rc;
+ u8 x_direction = 0; /* 1:x, 0:y */
+ u8 dir_reg, other_reg;
+
+ r820t_vga_adjust(priv);
+
+ rc = r820t_imr_cross(priv, compare_iq, &x_direction);
+ if (rc < 0)
+ return rc;
+
+ if (x_direction == 1) {
+ dir_reg = 0x08;
+ other_reg = 0x09;
+ } else {
+ dir_reg = 0x09;
+ other_reg = 0x08;
+ }
+
+ /* compare and find min of 3 points. determine i/q direction */
+ r820t_compre_cor(compare_iq);
+
+ /* increase step to find min value of this direction */
+ rc = r820t_compre_step(priv, compare_iq, dir_reg);
+ if (rc < 0)
+ return rc;
+
+ /* the other direction */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, dir_reg);
+ if (rc < 0)
+ return rc;
+
+ /* compare and find min of 3 points. determine i/q direction */
+ r820t_compre_cor(compare_iq);
+
+ /* increase step to find min value on this direction */
+ rc = r820t_compre_step(priv, compare_iq, other_reg);
+ if (rc < 0)
+ return rc;
+
+ /* check 3 points again */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, other_reg);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ /* section-9 check */
+ rc = r820t_section(priv, compare_iq);
+
+ *iq_pont = compare_iq[0];
+
+ /* reset gain/phase control setting */
+ rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f);
+
+ return rc;
+}
+
+static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
+{
+ int rc;
+
+ r820t_vga_adjust(priv);
+
+ /*
+ * search surrounding points from previous point
+ * try (x-1), (x), (x+1) columns, and find min IMR result point
+ */
+ rc = r820t_section(priv, iq_pont);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
+{
+ struct r820t_sect_type imr_point;
+ int rc;
+ u32 ring_vco, ring_freq, ring_ref;
+ u8 n_ring, n;
+ int reg18, reg19, reg1f;
+
+ if (priv->cfg->xtal > 24000000)
+ ring_ref = priv->cfg->xtal / 2;
+ else
+ ring_ref = priv->cfg->xtal;
+
+ for (n = 0; n < 16; n++) {
+ if ((16 + n) * 8 * ring_ref >= 3100000) {
+ n_ring = n;
+ break;
+ }
+
+ /* n_ring not found */
+ if (n == 15)
+ n_ring = n;
+ }
+
+ reg18 = r820t_read_cache_reg(priv, 0x18);
+ reg19 = r820t_read_cache_reg(priv, 0x19);
+ reg1f = r820t_read_cache_reg(priv, 0x1f);
+
+ reg18 &= 0xf0; /* set ring[3:0] */
+ reg18 |= n_ring;
+
+ ring_vco = (16 + n_ring) * 8 * ring_ref;
+
+ reg18 &= 0xdf; /* clear ring_se23 */
+ reg19 &= 0xfc; /* clear ring_seldiv */
+ reg1f &= 0xfc; /* clear ring_att */
+
+ switch (imr_mem) {
+ case 0:
+ ring_freq = ring_vco / 48;
+ reg18 |= 0x20; /* ring_se23 = 1 */
+ reg19 |= 0x03; /* ring_seldiv = 3 */
+ reg1f |= 0x02; /* ring_att 10 */
+ break;
+ case 1:
+ ring_freq = ring_vco / 16;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x02; /* ring_seldiv = 2 */
+ reg1f |= 0x00; /* pw_ring 00 */
+ break;
+ case 2:
+ ring_freq = ring_vco / 8;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x01; /* ring_seldiv = 1 */
+ reg1f |= 0x03; /* pw_ring 11 */
+ break;
+ case 3:
+ ring_freq = ring_vco / 6;
+ reg18 |= 0x20; /* ring_se23 = 1 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x03; /* pw_ring 11 */
+ break;
+ case 4:
+ ring_freq = ring_vco / 4;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x01; /* pw_ring 01 */
+ break;
+ default:
+ ring_freq = ring_vco / 4;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x01; /* pw_ring 01 */
+ break;
+ }
+
+
+ /* write pw_ring, n_ring, ringdiv2 registers */
+
+ /* n_ring, ring_se23 */
+ rc = r820t_write_reg(priv, 0x18, reg18);
+ if (rc < 0)
+ return rc;
+
+ /* ring_sediv */
+ rc = r820t_write_reg(priv, 0x19, reg19);
+ if (rc < 0)
+ return rc;
+
+ /* pw_ring */
+ rc = r820t_write_reg(priv, 0x1f, reg1f);
+ if (rc < 0)
+ return rc;
+
+ /* mux input freq ~ rf_in freq */
+ rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV,
+ (ring_freq - 5300) * 1000);
+ if (!priv->has_lock)
+ rc = -EINVAL;
+ if (rc < 0)
+ return rc;
+
+ if (im_flag) {
+ rc = r820t_iq(priv, &imr_point);
+ } else {
+ imr_point.gain_x = priv->imr_data[3].gain_x;
+ imr_point.phase_y = priv->imr_data[3].phase_y;
+ imr_point.value = priv->imr_data[3].value;
+
+ rc = r820t_f_imr(priv, &imr_point);
+ }
+ if (rc < 0)
+ return rc;
+
+ /* save IMR value */
+ switch (imr_mem) {
+ case 0:
+ priv->imr_data[0].gain_x = imr_point.gain_x;
+ priv->imr_data[0].phase_y = imr_point.phase_y;
+ priv->imr_data[0].value = imr_point.value;
+ break;
+ case 1:
+ priv->imr_data[1].gain_x = imr_point.gain_x;
+ priv->imr_data[1].phase_y = imr_point.phase_y;
+ priv->imr_data[1].value = imr_point.value;
+ break;
+ case 2:
+ priv->imr_data[2].gain_x = imr_point.gain_x;
+ priv->imr_data[2].phase_y = imr_point.phase_y;
+ priv->imr_data[2].value = imr_point.value;
+ break;
+ case 3:
+ priv->imr_data[3].gain_x = imr_point.gain_x;
+ priv->imr_data[3].phase_y = imr_point.phase_y;
+ priv->imr_data[3].value = imr_point.value;
+ break;
+ case 4:
+ priv->imr_data[4].gain_x = imr_point.gain_x;
+ priv->imr_data[4].phase_y = imr_point.phase_y;
+ priv->imr_data[4].value = imr_point.value;
+ break;
+ default:
+ priv->imr_data[4].gain_x = imr_point.gain_x;
+ priv->imr_data[4].phase_y = imr_point.phase_y;
+ priv->imr_data[4].value = imr_point.value;
+ break;
+ }
+
+ return 0;
+}
+
+static int r820t_imr_callibrate(struct r820t_priv *priv)
+{
+ int rc, i;
+ int xtal_cap = 0;
+
+ if (priv->init_done)
+ return 0;
+
+ /* Detect Xtal capacitance */
+ if ((priv->cfg->rafael_chip == CHIP_R820T) ||
+ (priv->cfg->rafael_chip == CHIP_R828S) ||
+ (priv->cfg->rafael_chip == CHIP_R820C)) {
+ priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
+ } else {
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+ if (rc < 0)
+ return rc;
+ for (i = 0; i < 3; i++) {
+ rc = r820t_xtal_check(priv);
+ if (rc < 0)
+ return rc;
+ if (!i || rc > xtal_cap)
+ xtal_cap = rc;
+ }
+ priv->xtal_cap_sel = xtal_cap;
+ }
+
+ /*
+ * Disables IMR callibration. That emulates the same behaviour
+ * as what is done by rtl-sdr userspace library. Useful for testing
+ */
+ if (no_imr_cal) {
+ priv->init_done = true;
+
+ return 0;
+ }
+
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_imr_prepare(priv);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_imr(priv, 3, true);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 1, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 0, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 2, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 4, false);
+ if (rc < 0)
+ return rc;
+
+ priv->init_done = true;
+ priv->imr_done = true;
+
+ return 0;
+}
+
+#if 0
+/* Not used, for now */
+static int r820t_gpio(struct r820t_priv *priv, bool enable)
+{
+ return r820t_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01);
+}
+#endif
+
+/*
+ * r820t frontend operations and tuner attach code
+ *
+ * All driver locks and i2c control are only in this part of the code
+ */
+
+static int r820t_init(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = r820t_imr_callibrate(priv);
+ if (rc < 0)
+ goto err;
+
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ if (rc < 0)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_sleep(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = r820t_standby(priv);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_set_analog_freq(struct dvb_frontend *fe,
+ struct analog_parameters *p)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ unsigned bw;
+ int rc;
+
+ tuner_dbg("%s called\n", __func__);
+
+ /* if std is not defined, choose one */
+ if (!p->std)
+ p->std = V4L2_STD_MN;
+
+ if ((p->std == V4L2_STD_PAL_M) || (p->std == V4L2_STD_NTSC))
+ bw = 6;
+ else
+ bw = 8;
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = generic_set_freq(fe, 62500l * p->frequency, bw,
+ V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+static int r820t_set_params(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ unsigned bw;
+
+ tuner_dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ __func__, c->delivery_system, c->frequency, c->bandwidth_hz);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ bw = (c->bandwidth_hz + 500000) / 1000000;
+ if (!bw)
+ bw = 8;
+
+ rc = generic_set_freq(fe, c->frequency, bw,
+ V4L2_TUNER_DIGITAL_TV, 0, c->delivery_system);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ if (rc)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_signal(struct dvb_frontend *fe, u16 *strength)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc = 0;
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (priv->has_lock) {
+ rc = r820t_read_gain(priv);
+ if (rc < 0)
+ goto err;
+
+ /* A higher gain at LNA means a lower signal strength */
+ *strength = (45 - rc) << 4 | 0xff;
+ if (*strength == 0xff)
+ *strength = 0;
+ } else {
+ *strength = 0;
+ }
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("%s: %s, gain=%d strength=%d\n",
+ __func__,
+ priv->has_lock ? "PLL locked" : "no signal",
+ rc, *strength);
+
+ return 0;
+}
+
+static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+
+ tuner_dbg("%s:\n", __func__);
+
+ *frequency = priv->int_freq;
+
+ return 0;
+}
+
+static int r820t_release(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&r820t_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&r820t_list_mutex);
+
+ fe->tuner_priv = NULL;
+
+ kfree(fe->tuner_priv);
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops r820t_tuner_ops = {
+ .info = {
+ .name = "Rafael Micro R820T",
+ .frequency_min = 42000000,
+ .frequency_max = 1002000000,
+ },
+ .init = r820t_init,
+ .release = r820t_release,
+ .sleep = r820t_sleep,
+ .set_params = r820t_set_params,
+ .set_analog_params = r820t_set_analog_freq,
+ .get_if_frequency = r820t_get_if_frequency,
+ .get_rf_strength = r820t_signal,
+};
+
+struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg)
+{
+ struct r820t_priv *priv;
+ int rc = -ENODEV;
+ u8 data[5];
+ int instance;
+
+ mutex_lock(&r820t_list_mutex);
+
+ instance = hybrid_tuner_request_state(struct r820t_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_addr,
+ "r820t");
+ switch (instance) {
+ case 0:
+ /* memory allocation failure */
+ goto err_no_gate;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->cfg = cfg;
+
+ mutex_init(&priv->lock);
+
+ fe->tuner_priv = priv;
+ break;
+ case 2:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
+
+ memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ /* check if the tuner is there */
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ goto err;
+
+ rc = r820t_sleep(fe);
+ if (rc < 0)
+ goto err;
+
+ tuner_info("Rafael Micro r820t successfully identified\n");
+
+ fe->tuner_priv = priv;
+ memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ mutex_unlock(&r820t_list_mutex);
+
+ return fe;
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+err_no_gate:
+ mutex_unlock(&r820t_list_mutex);
+
+ tuner_info("%s: failed=%d\n", __func__, rc);
+ r820t_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(r820t_attach);
+
+MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h
new file mode 100644
index 0000000..4c0823b
--- /dev/null
+++ b/drivers/media/tuners/r820t.h
@@ -0,0 +1,58 @@
+/*
+ * Elonics R820T silicon tuner driver
+ *
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef R820T_H
+#define R820T_H
+
+#include <linux/kconfig.h>
+#include "dvb_frontend.h"
+
+enum r820t_chip {
+ CHIP_R820T,
+ CHIP_R620D,
+ CHIP_R828D,
+ CHIP_R828,
+ CHIP_R828S,
+ CHIP_R820C,
+};
+
+struct r820t_config {
+ u8 i2c_addr; /* 0x34 */
+ u32 xtal;
+ enum r820t_chip rafael_chip;
+ unsigned max_i2c_msg_len;
+ bool use_diplexer;
+};
+
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T)
+struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg);
+#else
+static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 9aff035..a3c8ecf 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -143,6 +143,7 @@
select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 2e76274..90cfa35 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -635,7 +635,7 @@
{
struct anysee_state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
+ int ret = 0;
u8 tmp;
struct i2c_msg msg[2] = {
{
@@ -882,7 +882,7 @@
/* we have no frontend :-( */
ret = -ENODEV;
dev_err(&d->udev->dev,
- "%s: Unsupported Anysee version. Please report the <linux-media@vger.kernel.org>.\n",
+ "%s: Unsupported Anysee version. Please report to <linux-media@vger.kernel.org>.\n",
KBUILD_MODNAME);
}
error:
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 3d128a5..22015fe 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -33,6 +33,7 @@
#include "e4000.h"
#include "fc2580.h"
#include "tua9001.h"
+#include "r820t.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -375,6 +376,7 @@
struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
+ struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf};
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -479,6 +481,14 @@
goto found;
}
+ /* check R820T by reading tuner stats at I2C addr 0x1a */
+ ret = rtl28xxu_ctrl_msg(d, &req_r820t);
+ if (ret == 0) {
+ priv->tuner = TUNER_RTL2832_R820T;
+ priv->tuner_name = "R820T";
+ goto found;
+ }
+
found:
dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
@@ -589,6 +599,12 @@
.tuner = TUNER_RTL2832_E4000,
};
+static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+ .i2c_addr = 0x10,
+ .xtal = 28800000,
+ .tuner = TUNER_RTL2832_R820T,
+};
+
static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
int cmd, int arg)
{
@@ -728,6 +744,9 @@
case TUNER_RTL2832_E4000:
rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
break;
+ case TUNER_RTL2832_R820T:
+ rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
+ break;
default:
dev_err(&d->udev->dev, "%s: unknown tuner=%s\n",
KBUILD_MODNAME, priv->tuner_name);
@@ -840,6 +859,13 @@
.xtal_freq = FC_XTAL_28_8_MHZ,
};
+static const struct r820t_config rtl2832u_r820t_config = {
+ .i2c_addr = 0x1a,
+ .xtal = 28800000,
+ .max_i2c_msg_len = 2,
+ .rafael_chip = CHIP_R820T,
+};
+
static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
@@ -889,6 +915,14 @@
fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap,
&rtl2832u_tua9001_config);
break;
+ case TUNER_RTL2832_R820T:
+ fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ &rtl2832u_r820t_config);
+
+ /* Use tuner to get the signal strength */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+ break;
default:
fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 2f3af2d..533a331 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -82,6 +82,7 @@
TUNER_RTL2832_E4000,
TUNER_RTL2832_TDA18272,
TUNER_RTL2832_FC0013,
+ TUNER_RTL2832_R820T,
};
struct rtl28xxu_req {
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 1179842..f081360 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1431,13 +1431,22 @@
return dib8000_get_adc_power(fe, 1);
}
+static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
+{
+ deb_info("AGC control callback: %i\n", restart);
+ dib0090_dcc_freq(fe, restart);
+
+ if (restart == 0) /* before AGC startup */
+ dib0090_set_dc_servo(fe, 1);
+}
+
static struct dib8000_config dib809x_dib8000_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1456,7 +1465,7 @@
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1504,28 +1513,89 @@
.fref_clock_ratio = 6,
};
+static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe)
+{
+ u8 optimal_pll_ratio = 20;
+ u32 freq_adc, ratio, rest, max = 0;
+ u8 pll_ratio;
+
+ for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) {
+ freq_adc = 12 * pll_ratio * (1 << 8) / 16;
+ ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc;
+ rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc;
+
+ if (rest > freq_adc / 2)
+ rest = freq_adc - rest;
+ deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest);
+ if ((rest > max) && (rest > 717)) {
+ optimal_pll_ratio = pll_ratio;
+ max = rest;
+ }
+ }
+ deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio);
+
+ return optimal_pll_ratio;
+}
+
static int dib8096_set_param_override(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
- u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
- u16 target;
+ u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
+ u16 target, ltgain, rf_gain_limit;
+ u32 timf;
int ret = 0;
enum frontend_tune_state tune_state = CT_SHUTDOWN;
- u16 ltgain, rf_gain_limit;
+
+ switch (band) {
+ default:
+ deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
+ case BAND_VHF:
+ dib8000_set_gpio(fe, 3, 0, 1);
+ break;
+ case BAND_UHF:
+ dib8000_set_gpio(fe, 3, 0, 0);
+ break;
+ }
ret = state->set_param_save(fe);
if (ret < 0)
return ret;
- target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
- dib8000_set_wbd_ref(fe, target);
+ if (fe->dtv_property_cache.bandwidth_hz != 6000000) {
+ deb_info("only 6MHz bandwidth is supported\n");
+ return -EINVAL;
+ }
+ /** Update PLL if needed ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+
+ /** Get optimize PLL ratio to remove spurious **/
+ pll_ratio = dib8090_compute_pll_parameters(fe);
+ if (pll_ratio == 17)
+ timf = 21387946;
+ else if (pll_ratio == 18)
+ timf = 20199727;
+ else if (pll_ratio == 19)
+ timf = 19136583;
+ else
+ timf = 18179756;
+
+ /** Update ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
+
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf);
+
+ if (band != BAND_CBAND) {
+ /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
+ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
+ dib8000_set_wbd_ref(fe, target);
+ }
if (band == BAND_CBAND) {
deb_info("tuning in CBAND - soft-AGC startup\n");
dib0090_set_tune_state(fe, CT_AGC_START);
+
do {
ret = dib0090_gain_control(fe);
msleep(ret);
@@ -1534,14 +1604,17 @@
dib8000_set_gpio(fe, 6, 0, 1);
else if (tune_state == CT_AGC_STEP_1) {
dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain);
- if (rf_gain_limit == 0)
+ if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
dib8000_set_gpio(fe, 6, 0, 0);
}
} while (tune_state < CT_AGC_STOP);
+
+ deb_info("switching to PWM AGC\n");
dib0090_pwm_gain_reset(fe);
dib8000_pwm_agc_reset(fe);
dib8000_set_tune_state(fe, CT_DEMOD_START);
} else {
+ /* for everything else than CBAND we are using standard AGC */
deb_info("not tuning in CBAND - standard AGC startup\n");
dib0090_pwm_gain_reset(fe);
}
@@ -1814,21 +1887,92 @@
u32 pll_prediv; /* New loopdiv */
};
-struct dibx090p_adc dib8090p_adc_tab[] = {
- { 50000, 17043521, 16, 3}, /* 64 MHz */
- {878000, 20199729, 9, 1}, /* 60 MHz */
- {0xffffffff, 0, 0, 0}, /* 60 MHz */
+struct dibx090p_best_adc {
+ u32 timf;
+ u32 pll_loopdiv;
+ u32 pll_prediv;
};
+static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc)
+{
+ u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+ u16 xtal = 12000;
+ u16 fcp_min = 1900; /* PLL, Minimum Frequency of phase comparator (KHz) */
+ u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */
+ u32 fmem_max = 140000; /* 140MHz max SDRAM freq */
+ u32 fdem_min = 66000;
+ u32 fcp = 0, fs = 0, fdem = 0, fmem = 0;
+ u32 harmonic_id = 0;
+
+ adc->timf = 0;
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+
+ deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz);
+
+ /* Find Min and Max prediv */
+ while ((xtal / max_prediv) >= fcp_min)
+ max_prediv++;
+
+ max_prediv--;
+ min_prediv = max_prediv;
+ while ((xtal / min_prediv) <= fcp_max) {
+ min_prediv--;
+ if (min_prediv == 1)
+ break;
+ }
+ deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+ min_prediv = 1;
+
+ for (prediv = min_prediv; prediv < max_prediv; prediv++) {
+ fcp = xtal / prediv;
+ if (fcp > fcp_min && fcp < fcp_max) {
+ for (loopdiv = 1; loopdiv < 64; loopdiv++) {
+ fmem = ((xtal/prediv) * loopdiv);
+ fdem = fmem / 2;
+ fs = fdem / 4;
+
+ /* test min/max system restrictions */
+ if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) {
+ spur = 0;
+ /* test fs harmonics positions */
+ for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs)); harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) {
+ if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) && ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) {
+ spur = 1;
+ break;
+ }
+ }
+
+ if (!spur) {
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+ adc->timf = (4260880253U / fdem) * (1 << 8);
+ adc->timf += ((4260880253U % fdem) << 8) / fdem;
+
+ deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf);
+ break;
+ }
+ }
+ }
+ }
+ if (!spur)
+ break;
+ }
+
+ if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
+ return -EINVAL;
+ return 0;
+}
+
static int dib8096p_agc_startup(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
+ struct dibx090p_best_adc adc;
u16 target;
- int better_sampling_freq = 0, ret;
- struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+ int ret;
ret = state->set_param_save(fe);
if (ret < 0)
@@ -1841,23 +1985,27 @@
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
dib8000_set_wbd_ref(fe, target);
+ if (dib8096p_get_best_sampling(fe, &adc) == 0) {
+ pll.pll_ratio = adc.pll_loopdiv;
+ pll.pll_prediv = adc.pll_prediv;
- while (p->frequency / 1000 > adc_table->freq) {
- better_sampling_freq = 1;
- adc_table++;
- }
-
- if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
- pll.pll_ratio = adc_table->pll_loopdiv;
- pll.pll_prediv = adc_table->pll_prediv;
- dib8000_update_pll(fe, &pll);
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+ dib0700_set_i2c_speed(adap->dev, 200);
+ dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+ dib0700_set_i2c_speed(adap->dev, 1000);
}
return 0;
}
static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_state *st = adap->dev->priv;
+ u32 fw_version;
+
+ dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+ if (fw_version >= 0x10200)
+ st->fw_use_new_i2c_api = 1;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(20);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -2242,13 +2390,7 @@
}
/* NIM7090 */
-struct dib7090p_best_adc {
- u32 timf;
- u32 pll_loopdiv;
- u32 pll_prediv;
-};
-
-static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dibx090p_best_adc *adc)
{
u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
@@ -2327,7 +2469,7 @@
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
u16 target;
- struct dib7090p_best_adc adc;
+ struct dibx090p_best_adc adc;
int ret;
ret = state->set_param_save(fe);
@@ -2357,36 +2499,16 @@
return 0;
}
-static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global)
{
- u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
- s16 wbd_delta;
+ deb_info("update LNA: agc global=%i", agc_global);
- if ((fe->dtv_property_cache.frequency) < 400000000)
- threshold_agc1 = 25000;
- else
- threshold_agc1 = 30000;
-
- wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
- wbd_offset = dib0090_get_wbd_offset(fe);
- dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
- wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
-
- deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
- agc_global, agc1, agc2);
- deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
- wbd, wbd_target, wbd_offset, wbd_delta);
-
- if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
- dib0090_set_switch(fe, 1, 1, 1);
- dib0090_set_vga(fe, 0);
- dib0090_update_rframp_7090(fe, 0);
- dib0090_update_tuning_table_7090(fe, 0);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 8, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
} else {
- dib0090_set_vga(fe, 1);
- dib0090_update_rframp_7090(fe, 1);
- dib0090_update_tuning_table_7090(fe, 1);
- dib0090_set_switch(fe, 0, 0, 0);
+ dib7000p_set_gpio(fe, 8, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
}
return 0;
@@ -2400,15 +2522,6 @@
{ 0xFFFF, 0, 0, 0, 0, 0},
};
-static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
- { 380, 81, 850, 64, 540, 4},
- { 700, 51, 866, 21, 320, 4},
- { 860, 48, 666, 18, 330, 6},
- {1700, 0, 250, 0, 100, 6},
- {2600, 0, 250, 0, 100, 6},
- { 0xFFFF, 0, 0, 0, 0, 0},
-};
-
static struct dibx000_agc_config dib7090_agc_config[2] = {
{
.band_caps = BAND_UHF,
@@ -2428,7 +2541,7 @@
.wbd_alpha = 5,
.agc1_max = 65535,
- .agc1_min = 0,
+ .agc1_min = 32768,
.agc2_max = 65535,
.agc2_min = 0,
@@ -2505,7 +2618,7 @@
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7790p_update_lna, /* GPIO used is the same as TFE7790 */
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2529,12 +2642,26 @@
.enMpegOutput = 1,
};
+static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+ deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 5, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
+ } else {
+ dib7000p_set_gpio(fe, 5, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
+ }
+
+ return 0;
+}
+
static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2561,7 +2688,7 @@
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2587,34 +2714,6 @@
}
};
-static struct dib7000p_config tfe7090e_dib7000p_config = {
- .output_mpeg2_in_188_bytes = 1,
- .hostbus_diversity = 1,
- .tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
-
- .agc_config_count = 2,
- .agc = dib7090_agc_config,
-
- .bw = &dib7090_clock_config_12_mhz,
-
- .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
- .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
- .pwm_freq_div = 0,
-
- .agc_control = dib7090_agc_restart,
-
- .spur_protect = 0,
- .disable_sample_and_hold = 0,
- .enable_current_mirror = 0,
- .diversity_delay = 0,
-
- .output_mode = OUTMODE_MPEG2_FIFO,
- .enMpegOutput = 1,
-};
-
static const struct dib0090_config nim7090_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
@@ -2649,47 +2748,11 @@
.in_soc = 1,
};
-static const struct dib0090_config tfe7090e_dib0090_config = {
- .io.clock_khz = 12000,
- .io.pll_bypass = 0,
- .io.pll_range = 0,
- .io.pll_prediv = 3,
- .io.pll_loopdiv = 6,
- .io.adc_clock_ratio = 0,
- .io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
-
- .freq_offset_khz_uhf = 0,
- .freq_offset_khz_vhf = 0,
-
- .get_adc_power = dib7090_get_adc_power,
-
- .clkouttobamse = 1,
- .analog_output = 0,
-
- .wbd_vhf_offset = 0,
- .wbd_cband_offset = 0,
- .use_pwm_agc = 1,
- .clkoutdrive = 0,
-
- .fref_clock_ratio = 0,
-
- .wbd = dib7090e_wbd_table,
-
- .ls_cfg_pad_drv = 0,
- .data_tx_drv = 0,
- .low_if = NULL,
- .in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
-};
-
-static struct dib7000p_config tfe7790e_dib7000p_config = {
+static struct dib7000p_config tfe7790p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
+ .update_lna = tfe7790p_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2713,7 +2776,7 @@
.enMpegOutput = 1,
};
-static const struct dib0090_config tfe7790e_dib0090_config = {
+static const struct dib0090_config tfe7790p_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -2739,14 +2802,14 @@
.fref_clock_ratio = 0,
- .wbd = dib7090e_wbd_table,
+ .wbd = dib7090_wbd_table,
.ls_cfg_pad_drv = 0,
.data_tx_drv = 0,
.low_if = NULL,
.in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
+ .force_cband_input = 0,
+ .is_dib7090e = 0,
.force_crystal_mode = 1,
};
@@ -2942,37 +3005,11 @@
return 0;
}
-static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
-{
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7090e_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
- __func__);
- return -ENODEV;
- }
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7090e_dib7000p_config);
-
- return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
- /* The TFE7790E requires the dib0700 to not be in master mode */
+ /* The TFE7790P requires the dib0700 to not be in master mode */
st->disable_streaming_master_mode = 1;
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
@@ -2988,42 +3025,25 @@
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+ 1, 0x10, &tfe7790p_dib7000p_config) != 0) {
err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
__func__);
return -ENODEV;
}
adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7790e_dib7000p_config);
+ 0x80, &tfe7790p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
-static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c =
dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7790e_dib0090_config) == NULL)
- return -ENODEV;
-
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
- st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
- adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
- return 0;
-}
-
-static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
-{
- struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c =
- dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7090e_dib0090_config) == NULL)
+ &tfe7790p_dib0090_config) == NULL)
return -ENODEV;
dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
@@ -3566,10 +3586,9 @@
/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) },
-/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
- { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790P) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
+/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3880,7 +3899,7 @@
{ NULL },
},
{ "Elgato EyeTV DTT rev. 2",
- { &dib0700_usb_id_table[81], NULL },
+ { &dib0700_usb_id_table[80], NULL },
{ NULL },
},
},
@@ -4697,48 +4716,8 @@
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7090e_frontend_attach,
- .tuner_attach = tfe7090e_tuner_attach,
-
- DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
- } },
-
- .size_of_priv =
- sizeof(struct dib0700_adapter_state),
- },
- },
-
- .num_device_descs = 1,
- .devices = {
- { "DiBcom TFE7090E reference design",
- { &dib0700_usb_id_table[78], NULL },
- { NULL },
- },
- },
-
- .rc.core = {
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .module_name = "dib0700",
- .rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_BIT_RC5 |
- RC_BIT_RC6_MCE |
- RC_BIT_NEC,
- .change_protocol = dib0700_change_protocol,
- },
- }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = stk70x0p_pid_filter,
- .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7790e_frontend_attach,
- .tuner_attach = tfe7790e_tuner_attach,
+ .frontend_attach = tfe7790p_frontend_attach,
+ .tuner_attach = tfe7790p_tuner_attach,
DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
} },
@@ -4750,8 +4729,8 @@
.num_device_descs = 1,
.devices = {
- { "DiBcom TFE7790E reference design",
- { &dib0700_usb_id_table[79], NULL },
+ { "DiBcom TFE7790P reference design",
+ { &dib0700_usb_id_table[78], NULL },
{ NULL },
},
},
@@ -4792,7 +4771,7 @@
.num_device_descs = 1,
.devices = {
{ "DiBcom TFE8096P reference design",
- { &dib0700_usb_id_table[80], NULL },
+ { &dib0700_usb_id_table[79], NULL },
{ NULL },
},
},
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index cc63f19..83bfbe4 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2910,7 +2910,8 @@
break;
case CHIP_ID_EM2820:
chip_name = "em2710/2820";
- if (dev->udev->descriptor.idVendor == 0xeb1a) {
+ if (le16_to_cpu(dev->udev->descriptor.idVendor)
+ == 0xeb1a) {
__le16 idProd = dev->udev->descriptor.idProduct;
if (le16_to_cpu(idProd) == 0x2710)
chip_name = "em2710";
@@ -3219,9 +3220,9 @@
e->bEndpointAddress;
} else {
if (usb_endpoint_xfer_isoc(e)) {
- dev->dvb_ep_isoc = e->bEndpointAddress;
if (size > dev->dvb_max_pkt_size_isoc) {
has_dvb = true; /* see NOTE (~) */
+ dev->dvb_ep_isoc = e->bEndpointAddress;
dev->dvb_max_pkt_size_isoc = size;
dev->dvb_alt_isoc = i;
}
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 3a43ba0..67f572c 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -27,7 +27,6 @@
u32 magic;
void *vaddr;
dma_addr_t dma_handle;
- bool cached;
unsigned long size;
};
@@ -43,26 +42,8 @@
unsigned long size, gfp_t flags)
{
mem->size = size;
- if (mem->cached) {
- mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA);
- if (mem->vaddr) {
- int err;
-
- mem->dma_handle = dma_map_single(dev, mem->vaddr,
- mem->size,
- DMA_FROM_DEVICE);
- err = dma_mapping_error(dev, mem->dma_handle);
- if (err) {
- dev_err(dev, "dma_map_single failed\n");
-
- free_pages_exact(mem->vaddr, mem->size);
- mem->vaddr = NULL;
- return err;
- }
- }
- } else
- mem->vaddr = dma_alloc_coherent(dev, mem->size,
- &mem->dma_handle, flags);
+ mem->vaddr = dma_alloc_coherent(dev, mem->size,
+ &mem->dma_handle, flags);
if (!mem->vaddr) {
dev_err(dev, "memory alloc size %ld failed\n", mem->size);
@@ -77,14 +58,7 @@
static void __videobuf_dc_free(struct device *dev,
struct videobuf_dma_contig_memory *mem)
{
- if (mem->cached) {
- if (!mem->vaddr)
- return;
- dma_unmap_single(dev, mem->dma_handle, mem->size,
- DMA_FROM_DEVICE);
- free_pages_exact(mem->vaddr, mem->size);
- } else
- dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
+ dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
mem->vaddr = NULL;
}
@@ -234,7 +208,7 @@
return ret;
}
-static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
@@ -244,22 +218,11 @@
vb->priv = ((char *)vb) + size;
mem = vb->priv;
mem->magic = MAGIC_DC_MEM;
- mem->cached = cached;
}
return vb;
}
-static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size)
-{
- return __videobuf_alloc_vb(size, false);
-}
-
-static struct videobuf_buffer *__videobuf_alloc_cached(size_t size)
-{
- return __videobuf_alloc_vb(size, true);
-}
-
static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -310,19 +273,6 @@
return 0;
}
-static int __videobuf_sync(struct videobuf_queue *q,
- struct videobuf_buffer *buf)
-{
- struct videobuf_dma_contig_memory *mem = buf->priv;
- BUG_ON(!mem);
- MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
- dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
- DMA_FROM_DEVICE);
-
- return 0;
-}
-
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_buffer *buf,
struct vm_area_struct *vma)
@@ -331,8 +281,6 @@
struct videobuf_mapping *map;
int retval;
unsigned long size;
- unsigned long pos, start = vma->vm_start;
- struct page *page;
dev_dbg(q->dev, "%s\n", __func__);
@@ -359,43 +307,16 @@
size = vma->vm_end - vma->vm_start;
size = (size < mem->size) ? size : mem->size;
- if (!mem->cached) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = remap_pfn_range(vma, vma->vm_start,
- mem->dma_handle >> PAGE_SHIFT,
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ retval = remap_pfn_range(vma, vma->vm_start,
+ mem->dma_handle >> PAGE_SHIFT,
size, vma->vm_page_prot);
- if (retval) {
- dev_err(q->dev, "mmap: remap failed with error %d. ",
- retval);
- dma_free_coherent(q->dev, mem->size,
- mem->vaddr, mem->dma_handle);
- goto error;
- }
- } else {
- pos = (unsigned long)mem->vaddr;
-
- while (size > 0) {
- page = virt_to_page((void *)pos);
- if (NULL == page) {
- dev_err(q->dev, "mmap: virt_to_page failed\n");
- __videobuf_dc_free(q->dev, mem);
- goto error;
- }
- retval = vm_insert_page(vma, start, page);
- if (retval) {
- dev_err(q->dev, "mmap: insert failed with error %d\n",
- retval);
- __videobuf_dc_free(q->dev, mem);
- goto error;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
-
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
+ if (retval) {
+ dev_err(q->dev, "mmap: remap failed with error %d. ",
+ retval);
+ dma_free_coherent(q->dev, mem->size,
+ mem->vaddr, mem->dma_handle);
+ goto error;
}
vma->vm_ops = &videobuf_vm_ops;
@@ -417,21 +338,12 @@
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc_vb = __videobuf_alloc_uncached,
+ .alloc_vb = __videobuf_alloc,
.iolock = __videobuf_iolock,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = __videobuf_to_vaddr,
};
-static struct videobuf_qtype_ops qops_cached = {
- .magic = MAGIC_QTYPE_OPS,
- .alloc_vb = __videobuf_alloc_cached,
- .iolock = __videobuf_iolock,
- .sync = __videobuf_sync,
- .mmap_mapper = __videobuf_mmap_mapper,
- .vaddr = __videobuf_to_vaddr,
-};
-
void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
const struct videobuf_queue_ops *ops,
struct device *dev,
@@ -447,20 +359,6 @@
}
EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
-void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
- const struct videobuf_queue_ops *ops,
- struct device *dev,
- spinlock_t *irqlock,
- enum v4l2_buf_type type,
- enum v4l2_field field,
- unsigned int msize,
- void *priv, struct mutex *ext_lock)
-{
- videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &qops_cached, ext_lock);
-}
-EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached);
-
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 58c1744..7d833ee 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -54,10 +54,15 @@
void *mem_priv;
int plane;
- /* Allocate memory for all planes in this buffer */
+ /*
+ * Allocate memory for all planes in this buffer
+ * NOTE: mmapped areas should be page aligned
+ */
for (plane = 0; plane < vb->num_planes; ++plane) {
+ unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
+
mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
- q->plane_sizes[plane], q->gfp_flags);
+ size, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -1852,6 +1857,7 @@
struct vb2_buffer *vb;
unsigned int buffer, plane;
int ret;
+ unsigned long length;
if (q->memory != V4L2_MEMORY_MMAP) {
dprintk(1, "Queue is not currently set up for mmap\n");
@@ -1886,8 +1892,15 @@
vb = q->bufs[buffer];
- if (vb->v4l2_planes[plane].length < (vma->vm_end - vma->vm_start)) {
- dprintk(1, "Invalid length\n");
+ /*
+ * MMAP requires page_aligned buffers.
+ * The buffer length was page_aligned at __vb2_buf_mem_alloc(),
+ * so, we need to do the same here.
+ */
+ length = PAGE_ALIGN(vb->v4l2_planes[plane].length);
+ if (length < (vma->vm_end - vma->vm_start)) {
+ dprintk(1,
+ "MMAP invalid, as it would overflow buffer length\n");
return -EINVAL;
}
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index ae35d25..fd56f25 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -162,9 +162,6 @@
if (!buf)
return ERR_PTR(-ENOMEM);
- /* align image size to PAGE_SIZE */
- size = PAGE_ALIGN(size);
-
buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr,
GFP_KERNEL | gfp_flags);
if (!buf->vaddr) {
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 59522b2..16ae3dc 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -55,7 +55,8 @@
buf->write = 0;
buf->offset = 0;
buf->sg_desc.size = size;
- buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ /* size is already page aligned */
+ buf->sg_desc.num_pages = size >> PAGE_SHIFT;
buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
sizeof(*buf->sg_desc.sglist));
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
index 8bde187..6e16af7 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/staging/media/go7007/go7007-priv.h
@@ -91,8 +91,8 @@
int num_i2c_devs;
struct go_i2c {
const char *type;
- int is_video:1;
- int is_audio:1;
+ unsigned int is_video:1;
+ unsigned int is_audio:1;
int addr;
u32 flags;
} i2c_devs[5];
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index 6c7d20f..98e2902 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -519,10 +519,15 @@
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
}
- if (solo_enc->fmt == V4L2_PIX_FMT_MPEG4)
+ switch (solo_enc->fmt) {
+ case V4L2_PIX_FMT_MPEG4:
+ case V4L2_PIX_FMT_H264:
ret = solo_fill_mpeg(solo_enc, vb, vh);
- else
+ break;
+ default: /* V4L2_PIX_FMT_MJPEG */
ret = solo_fill_jpeg(solo_enc, vb, vh);
+ break;
+ }
if (!ret) {
vb->v4l2_buf.sequence = solo_enc->sequence++;
@@ -780,10 +785,21 @@
static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ int dev_type = solo_enc->solo_dev->type;
+
switch (f->index) {
case 0:
- f->pixelformat = V4L2_PIX_FMT_MPEG4;
- strcpy(f->description, "MPEG-4 AVC");
+ switch (dev_type) {
+ case SOLO_DEV_6010:
+ f->pixelformat = V4L2_PIX_FMT_MPEG4;
+ strcpy(f->description, "MPEG-4 part 2");
+ break;
+ case SOLO_DEV_6110:
+ f->pixelformat = V4L2_PIX_FMT_H264;
+ strcpy(f->description, "H.264");
+ break;
+ }
break;
case 1:
f->pixelformat = V4L2_PIX_FMT_MJPEG;
@@ -798,6 +814,13 @@
return 0;
}
+static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
+{
+ return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
+ || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
+ || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
+}
+
static int solo_enc_try_fmt_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -805,8 +828,7 @@
struct solo_dev *solo_dev = solo_enc->solo_dev;
struct v4l2_pix_format *pix = &f->fmt.pix;
- if (pix->pixelformat != V4L2_PIX_FMT_MPEG4 &&
- pix->pixelformat != V4L2_PIX_FMT_MJPEG)
+ if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
return -EINVAL;
if (pix->width < solo_dev->video_hsize ||
@@ -872,6 +894,7 @@
if (pix->priv)
solo_enc->type = SOLO_ENC_TYPE_EXT;
*/
+ solo_update_mode(solo_enc);
return 0;
}
@@ -918,8 +941,7 @@
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
- if (fsize->pixel_format != V4L2_PIX_FMT_MPEG4 &&
- fsize->pixel_format != V4L2_PIX_FMT_MJPEG)
+ if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
return -EINVAL;
switch (fsize->index) {
@@ -946,8 +968,7 @@
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
- if (fintv->pixel_format != V4L2_PIX_FMT_MPEG4 &&
- fintv->pixel_format != V4L2_PIX_FMT_MJPEG)
+ if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
return -EINVAL;
if (fintv->index)
return -EINVAL;
@@ -1224,7 +1245,8 @@
mutex_init(&solo_enc->lock);
spin_lock_init(&solo_enc->av_lock);
INIT_LIST_HEAD(&solo_enc->vidq_active);
- solo_enc->fmt = V4L2_PIX_FMT_MPEG4;
+ solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
+ V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
solo_enc->type = SOLO_ENC_TYPE_STD;
solo_enc->qp = SOLO_DEFAULT_QP;
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
index f473aeb..f0ed825 100644
--- a/include/media/videobuf-dma-contig.h
+++ b/include/media/videobuf-dma-contig.h
@@ -26,16 +26,6 @@
void *priv,
struct mutex *ext_lock);
-void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
- const struct videobuf_queue_ops *ops,
- struct device *dev,
- spinlock_t *irqlock,
- enum v4l2_buf_type type,
- enum v4l2_field field,
- unsigned int msize,
- void *priv,
- struct mutex *ext_lock);
-
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
void videobuf_dma_contig_free(struct videobuf_queue *q,
struct videobuf_buffer *buf);