summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h3
-rw-r--r--drivers/media/dvb-frontends/dib0090.c438
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c17
-rw-r--r--drivers/media/dvb-frontends/dib7000p.h7
-rw-r--r--drivers/media/dvb-frontends/dib8000.c2235
-rw-r--r--drivers/media/dvb-frontends/dib8000.h6
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.h3
-rw-r--r--drivers/media/dvb-frontends/lg2160.h4
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c21
-rw-r--r--drivers/media/media-device.c9
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c10
-rw-r--r--drivers/media/pci/cx88/cx88-video.c10
-rw-r--r--drivers/media/platform/coda.c5
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c13
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c17
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.c35
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.h6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c15
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c26
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c5
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c14
-rw-r--r--drivers/media/platform/m2m-deinterlace.c5
-rw-r--r--drivers/media/platform/mem2mem_testdev.c12
-rw-r--r--drivers/media/platform/mx2_emmaprp.c5
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c13
-rw-r--r--drivers/media/radio/Kconfig17
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-si476x.c1599
-rw-r--r--drivers/media/rc/imon.c26
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c4
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c465
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c5
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c130
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c21
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c3
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c3
-rw-r--r--drivers/mfd/Kconfig13
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/of/base.c1
-rw-r--r--drivers/staging/media/go7007/go7007-priv.h4
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c44
49 files changed, 2024 insertions, 3281 deletions
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 399e1042d351..335a8f4695b4 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 d9fe60b4be48..f9916b8434b7 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -528,20 +528,19 @@ static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_
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 @@ void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
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 */
};
-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 */
+/* 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 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 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_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 */
+static const u16 rf_ramp_pwm_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 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
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);
+
+ 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
-#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);
- }
- }
+ dprintk("Engage mux for PWM control");
- if (state->rf_ramp[0] != 0)
- dib0090_write_reg(state, 0x32, (3 << 11));
- else
- dib0090_write_reg(state, 0x32, (0 << 11));
+ dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
- dib0090_write_reg(state, 0x04, 0x03);
- dib0090_write_reg(state, 0x39, (1 << 10));
+ /* 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, 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 @@ int dib0090_gain_control(struct dvb_frontend *fe)
#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 @@ static void dib0090_set_EFUSE(struct dib0090_state *state)
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 3e1eefada0e8..effb87f773b0 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -429,6 +429,13 @@ int dib7000p_get_agc_values(struct dvb_frontend *fe,
}
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 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod)
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 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod)
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 cf5e77956a1f..d08cdff59bdf 100644
--- a/drivers/media/dvb-frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -63,6 +63,7 @@ extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
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 @@ static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
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 1f3bcb5a1de8..1d719cce8995 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 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
#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 i2c_device {
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 @@ struct dib8000_state {
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 @@ struct dib8000_state {
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 void dib8000_set_acquisition_mode(struct dib8000_state *state)
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_output_mode(struct dvb_frontend *fe, int mode)
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 @@ static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
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 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
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_set_bandwidth(struct dvb_frontend *fe, u32 bw)
static int dib8000_sad_calib(struct dib8000_state *state)
{
+ u8 sad_sel = 3;
+
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
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ dib8000_write_word(state, 923, 2048);
- /* do the calibration */
- dib8000_write_word(state, 923, (1 << 0));
- dib8000_write_word(state, 923, (0 << 0));
+ 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 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
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 @@ static void dib8000_reset_pll(struct dib8000_state *state)
}
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 @@ int dib8000_update_pll(struct dvb_frontend *fe,
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);
+
+ 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;
- return 0;
- }
- return -EINVAL;
+ 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 @@ static int dib8000_reset(struct dvb_frontend *fe)
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 @@ static int dib8000_reset(struct dvb_frontend *fe)
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 @@ static int dib8000_reset(struct dvb_frontend *fe)
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 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
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 u16 adc_target_16dB[11] = {
};
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;
-
- 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;
+ u8 cr, constellation, time_intlv;
- 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;
+ switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) {
+ case FEC_1_2:
+ cr = 1;
break;
- case FEC_2_3:
- crate = 2;
+ case FEC_2_3:
+ cr = 2;
break;
- case FEC_3_4:
- crate = 3;
+ case FEC_3_4:
+ cr = 3;
break;
- case FEC_5_6:
- crate = 5;
+ case FEC_5_6:
+ cr = 5;
break;
- case FEC_7_8:
- default:
- crate = 7;
+ case FEC_7_8:
+ default:
+ cr = 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;
+ 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
+ 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[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+ 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;
- }
}
}
- mode = fft_to_mode(state);
+ return max_constellation;
+}
- //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
+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;
- 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));
+ /* channel estimation fine configuration */
+ switch (max_constellation) {
+ case QAM_64:
+ ana_gain = 0x7;
+ adp = &adp_Q64[0];
+ break;
+ case QAM_16:
+ ana_gain = 0x7;
+ adp = &adp_Q16[0];
+ break;
+ default:
+ ana_gain = 0;
+ adp = &adp_Qdefault[0];
+ break;
+ }
- dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
+ for (i = 0; i < 4; i++)
+ dib8000_write_word(state, 215 + i, adp[i]);
- /* signal optimization parameter */
+ return ana_gain;
+}
- 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];
+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 */
+ 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 */
+ for (i = 0; i < 10; i++)
+ dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
}
- 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);
+static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
+{
+ u16 mode = 0;
- 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;
+ if (state->isdbt_cfg_loaded == 0)
+ for (mode = 0; mode < 24; mode++)
+ dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+}
+
+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
+};
- // WRITE: Mode & Diff mask
- dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
+static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
+{
+ int sub_channel_prbs_group = 0;
- 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
+ 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];
+ }
+}
- // ---- SMALL ----
- // P_small_seg_diff
- dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
+static void dib8000_set_13seg_channel(struct dib8000_state *state)
+{
+ u16 i;
+ u16 coff_pow = 0x2800;
- dib8000_write_word(state, 353, seg_mask13); // ADDR 353
+ state->seg_mask = 0x1fff; /* All 13 segments enabled */
-/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
+ /* ---- 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;
- // ---- SMALL ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 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) {
- 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;
+ 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;
-
+ 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;
+ 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;
}
- } 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;
}
- }
- break;
-
+ 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;
+ 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;
}
- } 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;
}
- }
- break;
+ 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);
+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;
- // ---- COFF ----
- // Carloff, the most robust
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+ 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 */
+ }
- // 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);
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) /* 3-segments */
+ state->seg_mask = 0x00E0;
+ else /* 1-segment */
+ state->seg_mask = 0x0040;
-/* // P_small_coef_ext_enable = 1 */
-/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+ /* ---- 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);
- // 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);
- }
+ 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 */
- } 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);
+ /* 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_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_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];
+ }
- // 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, 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]);
}
- // ---- 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
+ /*
+ * 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 */
+
+ 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
- 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));
+ dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
+}
- /* 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;
- default:
- case TRANSMISSION_MODE_2K:
- mode = 64;
- break;
+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->cfg.diversity_delay == 0)
- mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+
+ if (state->seg_diff_mask)
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
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);
+ dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
- /* 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;
- 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;
- 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;
+ 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;
}
- for (mode = 0; mode < 4; mode++)
- dib8000_write_word(state, 215 + mode, coeff[mode]);
- // update ana_gain depending on max constellation
- 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
- 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
- for (i = 0; i < 10; i++)
- dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
- }
+ /* WRITE: Mode & Diff mask */
+ dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
- // ---- ANA_FE ----
+ 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) {
- 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]);
+ 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;
+ }
- // ---- CHAN_BLK ----
+ /* SMALL */
+ dib8000_small_fine_tune(state);
+
+ dib8000_set_subchannel_prbs(state, init_prbs);
+
+ /* ---- 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));
+ 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" 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 ----
+ 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 ----
+ 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 */
+ dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- state->isdbt_cfg_loaded = 0;
- else
- state->isdbt_cfg_loaded = 1;
+ 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;
+
+ if (state->revision == 0x8090)
+ internal = dib8000_read32(state, 23) / 1000;
- int slist = 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 */
- 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;
+ 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 */
- //choose the right list, in sb, always do everything
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ 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));
+ 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;
+
+ slist = 16;
+ state->fe[0]->dtv_property_cache.transmission_mode = state->found_nfft;
+
+ 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)));/* 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 */
+ 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);
} 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;
+ 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.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;
+ 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);
- 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;
-
- 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
-
- factor = 1;
+ dib8000_set_isdbt_common_channel(state, slist, 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));
+ 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, 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);
-
+ 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 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe)
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 int dib8000_tune(struct dvb_frontend *fe)
+static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
{
- struct dib8000_state *state = fe->demodulator_priv;
- int ret = 0;
- u16 lock, value, mode;
+ u16 tmp;
- // we are already tuned - just resuming from suspend
- if (state == NULL)
- return -EINVAL;
+ 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));
+}
- mode = fft_to_mode(state);
+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;
- dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
- dib8000_set_channel(state, 0, 0);
+ 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);
- // restart demod
- ret |= dib8000_write_word(state, 770, 0x4000);
- ret |= dib8000_write_word(state, 770, 0x0000);
- msleep(45);
+ if (invert)
+ dds = (1<<26) - dds;
+ } else {
+ ratio = 2;
+ unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
- /* 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 */
+ if (offset_khz < 0)
+ unit_khz_dds_val *= -1;
- // 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 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));
}
- 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 = (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);
+static void dib8000_set_frequency_offset(struct dib8000_state *state)
+{
+ int i;
+ u32 current_rf;
+ int total_dds_offset_khz;
- /* 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));
+ if (state->fe[0]->ops.tuner_ops.get_frequency)
+ state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_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;
- } else { // Sound Broadcasting mode 3 seg
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ state->subchannel = state->fe[0]->dtv_property_cache.isdbt_sb_subchannel;
- /* 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);
+ i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
+ dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i);
- ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
+ 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;
}
+ }
- } 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);
+ 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);
- ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
+ /* 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;
}
- // we achieved a coff_cpil_lock - it's time to update the timf
- if (state->revision != 0x8090)
- lock = dib8000_read_word(state, 568);
+ 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
- lock = dib8000_read_word(state, 570);
- if ((lock >> 11) & 0x1)
- dib8000_update_timf(state);
+ return systime() + delay;
+}
- //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);
+static s32 dib8000_get_status(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ return state->status;
+}
- 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));
+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;
+ enum frontend_tune_state *tune_state = &state->tune_state;
+
+ u16 locks, deeper_interleaver = 0, i;
+ int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
+
+ u32 *timeout = &state->timeout;
+ u32 now = systime();
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1, agc2;
+#endif
+
+ u32 corm[4] = {0, 0, 0, 0};
+ u8 find_index, max_value;
+
+#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
+
+ 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 */
+
+ dib8000_viterbi_state(state, 0); /* force chan dec in restart */
+
+ /* Layer monit */
+ dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
+
+ dib8000_set_frequency_offset(state);
+ dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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]); */
+
+ 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;
+ }
+
+ /* 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 @@ static int dib8000_wakeup(struct dvb_frontend *fe)
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 @@ static int dib8000_sleep(struct dvb_frontend *fe)
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_get_frontend(struct dvb_frontend *fe)
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 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
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 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
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]);
- }
-
- 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;
+ delay = dib8000_tune(state->fe[index_frontend]);
+ if (delay != FE_CALLBACK_TIME_NEVER)
+ delay += systime();
+
+ /* 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);
-
- dib8000_get_frontend(fe);
- }
+ if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
+ dprintk("strange callback time something went wrong");
+ active = 0;
+ }
- 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]);
+ while ((active == 1) && (systime() < callback_time))
+ msleep(100);
+ } while (active);
- /* 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 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
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 9e7a2b170d55..b8c11e52c512 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -33,6 +33,8 @@ struct dib8000_config {
u8 output_mode;
u8 refclksel;
u8 enMpegOutput:1;
+
+ struct dibx000_bandwidth_config *plltable;
};
#define DEFAULT_DIB8000_I2C_ADDRESS 18
@@ -58,7 +60,7 @@ extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
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 @@ static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
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 5f484881d7b1..b538e0555c95 100644
--- a/drivers/media/dvb-frontends/dibx000_common.h
+++ b/drivers/media/dvb-frontends/dibx000_common.h
@@ -193,7 +193,8 @@ enum frontend_tune_state {
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 a5f036824d68..194a07a78dc1 100644
--- a/drivers/media/dvb-frontends/lg2160.h
+++ b/drivers/media/dvb-frontends/lg2160.h
@@ -57,10 +57,10 @@ struct lg2160_config {
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/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index b353c50a6881..cb52438e53ac 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1457,6 +1457,12 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd)
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_ops s5c73m3_subdev_ops = {
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 @@ out_err1:
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 99b80b6f7f67..1957c0df08fd 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -102,9 +102,12 @@ static long media_device_enum_entities(struct media_device *mdev,
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 c9d3182f79d5..2d3507eb4897 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
{
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 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
{
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 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
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 e3f6181d1044..1b00615fd395 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1954,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
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 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
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 @@ static int cx8800_resume(struct pci_dev *pci_dev)
{
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 @@ static int cx8800_resume(struct pci_dev *pci_dev)
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 @@ static int cx8800_resume(struct pci_dev *pci_dev)
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 20827ba168fc..5612329f9ef7 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -1422,6 +1422,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
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 386c0a7a3a52..40a73f7d20da 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -80,6 +80,9 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 72c516af40f6..528f41369364 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -742,16 +742,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
/*
* 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 int fimc_cap_s_selection(struct file *file, void *fh,
}
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 fimc_initialize_capture_subdev(struct fimc_dev *fimc)
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 f25807d7bc8a..379a5e9d52a7 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -213,6 +213,17 @@ struct fimc_fmt *fimc_get_format(unsigned int index)
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 @@ static int fimc_probe(struct platform_device *pdev)
}
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 @@ static struct platform_driver fimc_driver = {
.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 d2fe162485a3..539a3f71c16a 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 fimc_dev {
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 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
/* 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 1ec6b3c6a62a..c397777d7cbb 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 @@ static const struct of_device_id fimc_is_i2c_of_match[] = {
{ .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 @@ int fimc_is_register_i2c_driver(void)
{
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 02b27190d2ae..6647421e5d3a 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 const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = {
}
};
-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 const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = {
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 @@ static int fimc_is_sensor_probe(struct i2c_client *client,
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 @@ static int fimc_is_sensor_probe(struct i2c_client *client,
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 @@ static int fimc_is_sensor_probe(struct i2c_client *client,
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 @@ static const struct of_device_id fimc_is_sensor_of_match[] = {
},
{ }
};
-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 50b8e4d59d62..6036d49a6c68 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 fimc_is_sensor {
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 3c81c882bfd1..47c6363d04e2 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -220,7 +220,7 @@ static int fimc_is_register_subdevs(struct fimc_is *is)
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 const struct file_operations fimc_is_debugfs_fops = {
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 @@ static int fimc_is_probe(struct platform_device *pdev)
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 @@ err_sd:
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 @@ err_sens:
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 3b9a6642a491..d63947f7b302 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -621,7 +621,7 @@ int fimc_isp_subdev_create(struct fimc_isp *isp)
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 661d0d148cb5..14bb7bc8adbe 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1377,7 +1377,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
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 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
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 71fed5129e30..47da5e049247 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -140,7 +140,7 @@ struct fimc_lite {
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 8449c0705e60..bde1f47f7ed3 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -99,7 +99,7 @@ static int stop_streaming(struct vb2_queue *q)
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 @@ static void fimc_device_run(void *priv)
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 @@ static struct vb2_ops fimc_qops = {
* 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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 1dbd55422706..15ef8f28239b 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -814,7 +814,6 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
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 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
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 8636bcddde1b..a2eda9d5ac87 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 csis_pix_format const *s5pcsis_try_format(
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 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
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 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
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 6c4db9b98989..758564649589 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -207,6 +207,9 @@ static void dma_callback(void *data)
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 7487d7208dea..4cc7f65d7d76 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -38,6 +38,10 @@ MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
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 @@ MODULE_VERSION("0.1.1");
#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 @@ static int device_process(struct m2mtest_ctx *ctx,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
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 4b9e0a28616a..f7440e585b6b 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -377,6 +377,9 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 14d663dacdbd..553d87e5ceab 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -158,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static irqreturn_t g2d_isr(int irq, void *prv)
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 3b023752bcb4..15d23968d1de 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1229,6 +1229,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
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 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
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 e810b1abf40e..01f9ae0dadb0 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -243,12 +243,10 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
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 @@ static int s5p_mfc_probe(struct platform_device *pdev)
}
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/radio/Kconfig b/drivers/media/radio/Kconfig
index fef427e386c1..24e64a09884c 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -18,23 +18,6 @@ config RADIO_SI470X
source "drivers/media/radio/si470x/Kconfig"
-config RADIO_SI476X
- tristate "Silicon Laboratories Si476x I2C FM Radio"
- depends on I2C && VIDEO_V4L2 && SND && SND_SOC
- select MFD_CORE
- select MFD_SI476X_CORE
- select SND_SOC_SI476X
- ---help---
- Choose Y here if you have this FM radio chip.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux 2 API. Information on
- this API and pointers to "v4l2" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-si476x.
-
config USB_MR800
tristate "AverMedia MR 800 USB FM radio support"
depends on USB && VIDEO_V4L2
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 0dcdb320cfc7..303eaebdb85a 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
-obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
deleted file mode 100644
index 9430c6a29937..000000000000
--- a/drivers/media/radio/radio-si476x.c
+++ /dev/null
@@ -1,1599 +0,0 @@
-/*
- * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips
- *
- * Copyright (C) 2012 Innovative Converged Devices(ICD)
- * Copyright (C) 2013 Andrey Smirnov
- *
- * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * 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/module.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/atomic.h>
-#include <linux/videodev2.h>
-#include <linux/mutex.h>
-#include <linux/debugfs.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-device.h>
-
-#include <media/si476x.h>
-#include <linux/mfd/si476x-core.h>
-
-#define FM_FREQ_RANGE_LOW 64000000
-#define FM_FREQ_RANGE_HIGH 108000000
-
-#define AM_FREQ_RANGE_LOW 520000
-#define AM_FREQ_RANGE_HIGH 30000000
-
-#define PWRLINEFLTR (1 << 8)
-
-#define FREQ_MUL (10000000 / 625)
-
-#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status))
-
-#define DRIVER_NAME "si476x-radio"
-#define DRIVER_CARD "SI476x AM/FM Receiver"
-
-enum si476x_freq_bands {
- SI476X_BAND_FM,
- SI476X_BAND_AM,
-};
-
-static const struct v4l2_frequency_band si476x_bands[] = {
- [SI476X_BAND_FM] = {
- .type = V4L2_TUNER_RADIO,
- .index = SI476X_BAND_FM,
- .capability = V4L2_TUNER_CAP_LOW
- | V4L2_TUNER_CAP_STEREO
- | V4L2_TUNER_CAP_RDS
- | V4L2_TUNER_CAP_RDS_BLOCK_IO
- | V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 64 * FREQ_MUL,
- .rangehigh = 108 * FREQ_MUL,
- .modulation = V4L2_BAND_MODULATION_FM,
- },
- [SI476X_BAND_AM] = {
- .type = V4L2_TUNER_RADIO,
- .index = SI476X_BAND_AM,
- .capability = V4L2_TUNER_CAP_LOW
- | V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 0.52 * FREQ_MUL,
- .rangehigh = 30 * FREQ_MUL,
- .modulation = V4L2_BAND_MODULATION_AM,
- },
-};
-
-static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band)
-{
- return freq >= si476x_bands[band].rangelow &&
- freq <= si476x_bands[band].rangehigh;
-}
-
-static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high,
- int band)
-{
- return low >= si476x_bands[band].rangelow &&
- high <= si476x_bands[band].rangehigh;
-}
-
-static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl);
-static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
-
-enum phase_diversity_modes_idx {
- SI476X_IDX_PHDIV_DISABLED,
- SI476X_IDX_PHDIV_PRIMARY_COMBINING,
- SI476X_IDX_PHDIV_PRIMARY_ANTENNA,
- SI476X_IDX_PHDIV_SECONDARY_ANTENNA,
- SI476X_IDX_PHDIV_SECONDARY_COMBINING,
-};
-
-static const char * const phase_diversity_modes[] = {
- [SI476X_IDX_PHDIV_DISABLED] = "Disabled",
- [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary",
- [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna",
- [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna",
- [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary",
-};
-
-static inline enum phase_diversity_modes_idx
-si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode)
-{
- switch (mode) {
- default: /* FALLTHROUGH */
- case SI476X_PHDIV_DISABLED:
- return SI476X_IDX_PHDIV_DISABLED;
- case SI476X_PHDIV_PRIMARY_COMBINING:
- return SI476X_IDX_PHDIV_PRIMARY_COMBINING;
- case SI476X_PHDIV_PRIMARY_ANTENNA:
- return SI476X_IDX_PHDIV_PRIMARY_ANTENNA;
- case SI476X_PHDIV_SECONDARY_ANTENNA:
- return SI476X_IDX_PHDIV_SECONDARY_ANTENNA;
- case SI476X_PHDIV_SECONDARY_COMBINING:
- return SI476X_IDX_PHDIV_SECONDARY_COMBINING;
- }
-}
-
-static inline enum si476x_phase_diversity_mode
-si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx)
-{
- static const int idx_to_value[] = {
- [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED,
- [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING,
- [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA,
- [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA,
- [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING,
- };
-
- return idx_to_value[idx];
-}
-
-static const struct v4l2_ctrl_ops si476x_ctrl_ops = {
- .g_volatile_ctrl = si476x_radio_g_volatile_ctrl,
- .s_ctrl = si476x_radio_s_ctrl,
-};
-
-
-enum si476x_ctrl_idx {
- SI476X_IDX_RSSI_THRESHOLD,
- SI476X_IDX_SNR_THRESHOLD,
- SI476X_IDX_MAX_TUNE_ERROR,
- SI476X_IDX_HARMONICS_COUNT,
- SI476X_IDX_DIVERSITY_MODE,
- SI476X_IDX_INTERCHIP_LINK,
-};
-static struct v4l2_ctrl_config si476x_ctrls[] = {
-
- /**
- * SI476X during its station seeking(or tuning) process uses several
- * parameters to detrmine if "the station" is valid:
- *
- * - Signal's SNR(in dBuV) must be lower than
- * #V4L2_CID_SI476X_SNR_THRESHOLD
- * - Signal's RSSI(in dBuV) must be greater than
- * #V4L2_CID_SI476X_RSSI_THRESHOLD
- * - Signal's frequency deviation(in units of 2ppm) must not be
- * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR
- */
- [SI476X_IDX_RSSI_THRESHOLD] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_RSSI_THRESHOLD,
- .name = "Valid RSSI Threshold",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = -128,
- .max = 127,
- .step = 1,
- },
- [SI476X_IDX_SNR_THRESHOLD] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_SNR_THRESHOLD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Valid SNR Threshold",
- .min = -128,
- .max = 127,
- .step = 1,
- },
- [SI476X_IDX_MAX_TUNE_ERROR] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_MAX_TUNE_ERROR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Max Tune Errors",
- .min = 0,
- .max = 126 * 2,
- .step = 2,
- },
-
- /**
- * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics
- * built-in power-line noise supression filter is to reject
- * during AM-mode operation.
- */
- [SI476X_IDX_HARMONICS_COUNT] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_HARMONICS_COUNT,
- .type = V4L2_CTRL_TYPE_INTEGER,
-
- .name = "Count of Harmonics to Reject",
- .min = 0,
- .max = 20,
- .step = 1,
- },
-
- /**
- * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which
- * two tuners working in diversity mode are to work in.
- *
- * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled
- * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is
- * on, primary tuner's antenna is the main one.
- * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is
- * off, primary tuner's antenna is the main one.
- * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is
- * off, secondary tuner's antenna is the main one.
- * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is
- * on, secondary tuner's antenna is the main one.
- */
- [SI476X_IDX_DIVERSITY_MODE] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_DIVERSITY_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Phase Diversity Mode",
- .qmenu = phase_diversity_modes,
- .min = 0,
- .max = ARRAY_SIZE(phase_diversity_modes) - 1,
- },
-
- /**
- * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in
- * diversity mode indicator. Allows user to determine if two
- * chips working in diversity mode have established a link
- * between each other and if the system as a whole uses
- * signals from both antennas to receive FM radio.
- */
- [SI476X_IDX_INTERCHIP_LINK] = {
- .ops = &si476x_ctrl_ops,
- .id = V4L2_CID_SI476X_INTERCHIP_LINK,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
- .name = "Inter-Chip Link",
- .min = 0,
- .max = 1,
- .step = 1,
- },
-};
-
-struct si476x_radio;
-
-/**
- * struct si476x_radio_ops - vtable of tuner functions
- *
- * This table holds pointers to functions implementing particular
- * operations depending on the mode in which the tuner chip was
- * configured to start in. If the function is not supported
- * corresponding element is set to #NULL.
- *
- * @tune_freq: Tune chip to a specific frequency
- * @seek_start: Star station seeking
- * @rsq_status: Get Recieved Signal Quality(RSQ) status
- * @rds_blckcnt: Get recived RDS blocks count
- * @phase_diversity: Change phase diversity mode of the tuner
- * @phase_div_status: Get phase diversity mode status
- * @acf_status: Get the status of Automatically Controlled
- * Features(ACF)
- * @agc_status: Get Automatic Gain Control(AGC) status
- */
-struct si476x_radio_ops {
- int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *);
- int (*seek_start)(struct si476x_core *, bool, bool);
- int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *,
- struct si476x_rsq_status_report *);
- int (*rds_blckcnt)(struct si476x_core *, bool,
- struct si476x_rds_blockcount_report *);
-
- int (*phase_diversity)(struct si476x_core *,
- enum si476x_phase_diversity_mode);
- int (*phase_div_status)(struct si476x_core *);
- int (*acf_status)(struct si476x_core *,
- struct si476x_acf_status_report *);
- int (*agc_status)(struct si476x_core *,
- struct si476x_agc_status_report *);
-};
-
-/**
- * struct si476x_radio - radio device
- *
- * @core: Pointer to underlying core device
- * @videodev: Pointer to video device created by V4L2 subsystem
- * @ops: Vtable of functions. See struct si476x_radio_ops for details
- * @kref: Reference counter
- * @core_lock: An r/w semaphore to brebvent the deletion of underlying
- * core structure is the radio device is being used
- */
-struct si476x_radio {
- struct v4l2_device v4l2dev;
- struct video_device videodev;
- struct v4l2_ctrl_handler ctrl_handler;
-
- struct si476x_core *core;
- /* This field should not be accesses unless core lock is held */
- const struct si476x_radio_ops *ops;
-
- struct dentry *debugfs;
- u32 audmode;
-};
-
-static inline struct si476x_radio *
-v4l2_dev_to_radio(struct v4l2_device *d)
-{
- return container_of(d, struct si476x_radio, v4l2dev);
-}
-
-static inline struct si476x_radio *
-v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d)
-{
- return container_of(d, struct si476x_radio, ctrl_handler);
-}
-
-/*
- * si476x_vidioc_querycap - query device capabilities
- */
-static int si476x_radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *capability)
-{
- struct si476x_radio *radio = video_drvdata(file);
-
- strlcpy(capability->driver, radio->v4l2dev.name,
- sizeof(capability->driver));
- strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
- snprintf(capability->bus_info, sizeof(capability->bus_info),
- "platform:%s", radio->v4l2dev.name);
-
- capability->device_caps = V4L2_CAP_TUNER
- | V4L2_CAP_RADIO
- | V4L2_CAP_HW_FREQ_SEEK;
-
- si476x_core_lock(radio->core);
- if (!si476x_core_is_a_secondary_tuner(radio->core))
- capability->device_caps |= V4L2_CAP_RDS_CAPTURE
- | V4L2_CAP_READWRITE;
- si476x_core_unlock(radio->core);
-
- capability->capabilities = capability->device_caps
- | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int si476x_radio_enum_freq_bands(struct file *file, void *priv,
- struct v4l2_frequency_band *band)
-{
- int err;
- struct si476x_radio *radio = video_drvdata(file);
-
- if (band->tuner != 0)
- return -EINVAL;
-
- switch (radio->core->chip_id) {
- /* AM/FM tuners -- all bands are supported */
- case SI476X_CHIP_SI4761:
- case SI476X_CHIP_SI4764:
- if (band->index < ARRAY_SIZE(si476x_bands)) {
- *band = si476x_bands[band->index];
- err = 0;
- } else {
- err = -EINVAL;
- }
- break;
- /* FM companion tuner chips -- only FM bands are
- * supported */
- case SI476X_CHIP_SI4768:
- if (band->index == SI476X_BAND_FM) {
- *band = si476x_bands[band->index];
- err = 0;
- } else {
- err = -EINVAL;
- }
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-static int si476x_radio_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
-{
- int err;
- struct si476x_rsq_status_report report;
- struct si476x_radio *radio = video_drvdata(file);
-
- struct si476x_rsq_status_args args = {
- .primary = false,
- .rsqack = false,
- .attune = false,
- .cancel = false,
- .stcack = false,
- };
-
- if (tuner->index != 0)
- return -EINVAL;
-
- tuner->type = V4L2_TUNER_RADIO;
- tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies
- * in multiples of
- * 62.5 Hz */
- | V4L2_TUNER_CAP_STEREO
- | V4L2_TUNER_CAP_HWSEEK_BOUNDED
- | V4L2_TUNER_CAP_HWSEEK_WRAP
- | V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
-
- si476x_core_lock(radio->core);
-
- if (si476x_core_is_a_secondary_tuner(radio->core)) {
- strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
- tuner->rxsubchans = 0;
- tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
- } else if (si476x_core_has_am(radio->core)) {
- if (si476x_core_is_a_primary_tuner(radio->core))
- strlcpy(tuner->name, "AM/FM (primary)",
- sizeof(tuner->name));
- else
- strlcpy(tuner->name, "AM/FM", sizeof(tuner->name));
-
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO
- | V4L2_TUNER_SUB_RDS;
- tuner->capability |= V4L2_TUNER_CAP_RDS
- | V4L2_TUNER_CAP_RDS_BLOCK_IO
- | V4L2_TUNER_CAP_FREQ_BANDS;
-
- tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow;
- } else {
- strlcpy(tuner->name, "FM", sizeof(tuner->name));
- tuner->rxsubchans = V4L2_TUNER_SUB_RDS;
- tuner->capability |= V4L2_TUNER_CAP_RDS
- | V4L2_TUNER_CAP_RDS_BLOCK_IO
- | V4L2_TUNER_CAP_FREQ_BANDS;
- tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
- }
-
- tuner->audmode = radio->audmode;
-
- tuner->afc = 1;
- tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh;
-
- err = radio->ops->rsq_status(radio->core,
- &args, &report);
- if (err < 0) {
- tuner->signal = 0;
- } else {
- /*
- * tuner->signal value range: 0x0000 .. 0xFFFF,
- * report.rssi: -128 .. 127
- */
- tuner->signal = (report.rssi + 128) * 257;
- }
- si476x_core_unlock(radio->core);
-
- return err;
-}
-
-static int si476x_radio_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *tuner)
-{
- struct si476x_radio *radio = video_drvdata(file);
-
- if (tuner->index != 0)
- return -EINVAL;
-
- if (tuner->audmode == V4L2_TUNER_MODE_MONO ||
- tuner->audmode == V4L2_TUNER_MODE_STEREO)
- radio->audmode = tuner->audmode;
- else
- radio->audmode = V4L2_TUNER_MODE_STEREO;
-
- return 0;
-}
-
-static int si476x_radio_init_vtable(struct si476x_radio *radio,
- enum si476x_func func)
-{
- static const struct si476x_radio_ops fm_ops = {
- .tune_freq = si476x_core_cmd_fm_tune_freq,
- .seek_start = si476x_core_cmd_fm_seek_start,
- .rsq_status = si476x_core_cmd_fm_rsq_status,
- .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount,
- .phase_diversity = si476x_core_cmd_fm_phase_diversity,
- .phase_div_status = si476x_core_cmd_fm_phase_div_status,
- .acf_status = si476x_core_cmd_fm_acf_status,
- .agc_status = si476x_core_cmd_agc_status,
- };
-
- static const struct si476x_radio_ops am_ops = {
- .tune_freq = si476x_core_cmd_am_tune_freq,
- .seek_start = si476x_core_cmd_am_seek_start,
- .rsq_status = si476x_core_cmd_am_rsq_status,
- .rds_blckcnt = NULL,
- .phase_diversity = NULL,
- .phase_div_status = NULL,
- .acf_status = si476x_core_cmd_am_acf_status,
- .agc_status = NULL,
- };
-
- switch (func) {
- case SI476X_FUNC_FM_RECEIVER:
- radio->ops = &fm_ops;
- return 0;
-
- case SI476X_FUNC_AM_RECEIVER:
- radio->ops = &am_ops;
- return 0;
- default:
- WARN(1, "Unexpected tuner function value\n");
- return -EINVAL;
- }
-}
-
-static int si476x_radio_pretune(struct si476x_radio *radio,
- enum si476x_func func)
-{
- int retval;
-
- struct si476x_tune_freq_args args = {
- .zifsr = false,
- .hd = false,
- .injside = SI476X_INJSIDE_AUTO,
- .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE,
- .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO,
- .antcap = 0,
- };
-
- switch (func) {
- case SI476X_FUNC_FM_RECEIVER:
- args.freq = v4l2_to_si476x(radio->core,
- 92 * FREQ_MUL);
- retval = radio->ops->tune_freq(radio->core, &args);
- break;
- case SI476X_FUNC_AM_RECEIVER:
- args.freq = v4l2_to_si476x(radio->core,
- 0.6 * FREQ_MUL);
- retval = radio->ops->tune_freq(radio->core, &args);
- break;
- default:
- WARN(1, "Unexpected tuner function value\n");
- retval = -EINVAL;
- }
-
- return retval;
-}
-static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio,
- enum si476x_func func)
-{
- int err;
-
- /* regcache_mark_dirty(radio->core->regmap); */
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE,
- SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT);
- if (err < 0)
- return err;
-
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_AUDIO_DEEMPHASIS,
- SI476X_PROP_AUDIO_PWR_LINE_FILTER);
- if (err < 0)
- return err;
-
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_INT_CTL_ENABLE,
- SI476X_PROP_INT_CTL_ENABLE);
- if (err < 0)
- return err;
-
- /*
- * Is there any point in restoring SNR and the like
- * when switching between AM/FM?
- */
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_VALID_MAX_TUNE_ERROR,
- SI476X_PROP_VALID_MAX_TUNE_ERROR);
- if (err < 0)
- return err;
-
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_VALID_SNR_THRESHOLD,
- SI476X_PROP_VALID_RSSI_THRESHOLD);
- if (err < 0)
- return err;
-
- if (func == SI476X_FUNC_FM_RECEIVER) {
- if (si476x_core_has_diversity(radio->core)) {
- err = si476x_core_cmd_fm_phase_diversity(radio->core,
- radio->core->diversity_mode);
- if (err < 0)
- return err;
- }
-
- err = regcache_sync_region(radio->core->regmap,
- SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
- SI476X_PROP_FM_RDS_CONFIG);
- if (err < 0)
- return err;
- }
-
- return si476x_radio_init_vtable(radio, func);
-
-}
-
-static int si476x_radio_change_func(struct si476x_radio *radio,
- enum si476x_func func)
-{
- int err;
- bool soft;
- /*
- * Since power/up down is a very time consuming operation,
- * try to avoid doing it if the requested mode matches the one
- * the tuner is in
- */
- if (func == radio->core->power_up_parameters.func)
- return 0;
-
- soft = true;
- err = si476x_core_stop(radio->core, soft);
- if (err < 0) {
- /*
- * OK, if the chip does not want to play nice let's
- * try to reset it in more brutal way
- */
- soft = false;
- err = si476x_core_stop(radio->core, soft);
- if (err < 0)
- return err;
- }
- /*
- Set the desired radio tuner function
- */
- radio->core->power_up_parameters.func = func;
-
- err = si476x_core_start(radio->core, soft);
- if (err < 0)
- return err;
-
- /*
- * No need to do the rest of manipulations for the bootlader
- * mode
- */
- if (func != SI476X_FUNC_FM_RECEIVER &&
- func != SI476X_FUNC_AM_RECEIVER)
- return err;
-
- return si476x_radio_do_post_powerup_init(radio, func);
-}
-
-static int si476x_radio_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- int err;
- struct si476x_radio *radio = video_drvdata(file);
-
- if (f->tuner != 0 ||
- f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
-
- si476x_core_lock(radio->core);
-
- if (radio->ops->rsq_status) {
- struct si476x_rsq_status_report report;
- struct si476x_rsq_status_args args = {
- .primary = false,
- .rsqack = false,
- .attune = true,
- .cancel = false,
- .stcack = false,
- };
-
- err = radio->ops->rsq_status(radio->core, &args, &report);
- if (!err)
- f->frequency = si476x_to_v4l2(radio->core,
- report.readfreq);
- } else {
- err = -EINVAL;
- }
-
- si476x_core_unlock(radio->core);
-
- return err;
-}
-
-static int si476x_radio_s_frequency(struct file *file, void *priv,
- const struct v4l2_frequency *f)
-{
- int err;
- u32 freq = f->frequency;
- struct si476x_tune_freq_args args;
- struct si476x_radio *radio = video_drvdata(file);
-
- const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh +
- si476x_bands[SI476X_BAND_FM].rangelow) / 2;
- const int band = (freq > midrange) ?
- SI476X_BAND_FM : SI476X_BAND_AM;
- const enum si476x_func func = (band == SI476X_BAND_AM) ?
- SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER;
-
- if (f->tuner != 0 ||
- f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
-
- si476x_core_lock(radio->core);
-
- freq = clamp(freq,
- si476x_bands[band].rangelow,
- si476x_bands[band].rangehigh);
-
- if (si476x_radio_freq_is_inside_of_the_band(freq,
- SI476X_BAND_AM) &&
- (!si476x_core_has_am(radio->core) ||
- si476x_core_is_a_secondary_tuner(radio->core))) {
- err = -EINVAL;
- goto unlock;
- }
-
- err = si476x_radio_change_func(radio, func);
- if (err < 0)
- goto unlock;
-
- args.zifsr = false;
- args.hd = false;
- args.injside = SI476X_INJSIDE_AUTO;
- args.freq = v4l2_to_si476x(radio->core, freq);
- args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE;
- args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO;
- args.antcap = 0;
-
- err = radio->ops->tune_freq(radio->core, &args);
-
-unlock:
- si476x_core_unlock(radio->core);
- return err;
-}
-
-static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
- const struct v4l2_hw_freq_seek *seek)
-{
- int err;
- enum si476x_func func;
- u32 rangelow, rangehigh;
- struct si476x_radio *radio = video_drvdata(file);
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- if (seek->tuner != 0 ||
- seek->type != V4L2_TUNER_RADIO)
- return -EINVAL;
-
- si476x_core_lock(radio->core);
-
- if (!seek->rangelow) {
- err = regmap_read(radio->core->regmap,
- SI476X_PROP_SEEK_BAND_BOTTOM,
- &rangelow);
- if (!err)
- rangelow = si476x_to_v4l2(radio->core, rangelow);
- else
- goto unlock;
- }
- if (!seek->rangehigh) {
- err = regmap_read(radio->core->regmap,
- SI476X_PROP_SEEK_BAND_TOP,
- &rangehigh);
- if (!err)
- rangehigh = si476x_to_v4l2(radio->core, rangehigh);
- else
- goto unlock;
- }
-
- if (rangelow > rangehigh) {
- err = -EINVAL;
- goto unlock;
- }
-
- if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
- SI476X_BAND_FM)) {
- func = SI476X_FUNC_FM_RECEIVER;
-
- } else if (si476x_core_has_am(radio->core) &&
- si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
- SI476X_BAND_AM)) {
- func = SI476X_FUNC_AM_RECEIVER;
- } else {
- err = -EINVAL;
- goto unlock;
- }
-
- err = si476x_radio_change_func(radio, func);
- if (err < 0)
- goto unlock;
-
- if (seek->rangehigh) {
- err = regmap_write(radio->core->regmap,
- SI476X_PROP_SEEK_BAND_TOP,
- v4l2_to_si476x(radio->core,
- seek->rangehigh));
- if (err)
- goto unlock;
- }
- if (seek->rangelow) {
- err = regmap_write(radio->core->regmap,
- SI476X_PROP_SEEK_BAND_BOTTOM,
- v4l2_to_si476x(radio->core,
- seek->rangelow));
- if (err)
- goto unlock;
- }
- if (seek->spacing) {
- err = regmap_write(radio->core->regmap,
- SI476X_PROP_SEEK_FREQUENCY_SPACING,
- v4l2_to_si476x(radio->core,
- seek->spacing));
- if (err)
- goto unlock;
- }
-
- err = radio->ops->seek_start(radio->core,
- seek->seek_upward,
- seek->wrap_around);
-unlock:
- si476x_core_unlock(radio->core);
-
-
-
- return err;
-}
-
-static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- int retval;
- struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
-
- si476x_core_lock(radio->core);
-
- switch (ctrl->id) {
- case V4L2_CID_SI476X_INTERCHIP_LINK:
- if (si476x_core_has_diversity(radio->core)) {
- if (radio->ops->phase_diversity) {
- retval = radio->ops->phase_div_status(radio->core);
- if (retval < 0)
- break;
-
- ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval);
- retval = 0;
- break;
- } else {
- retval = -ENOTTY;
- break;
- }
- }
- retval = -EINVAL;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- si476x_core_unlock(radio->core);
- return retval;
-
-}
-
-static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- int retval;
- enum si476x_phase_diversity_mode mode;
- struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
-
- si476x_core_lock(radio->core);
-
- switch (ctrl->id) {
- case V4L2_CID_SI476X_HARMONICS_COUNT:
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_AUDIO_PWR_LINE_FILTER,
- SI476X_PROP_PWR_HARMONICS_MASK,
- ctrl->val);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (ctrl->val) {
- case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_AUDIO_PWR_LINE_FILTER,
- SI476X_PROP_PWR_ENABLE_MASK,
- 0);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_AUDIO_PWR_LINE_FILTER,
- SI476X_PROP_PWR_GRID_MASK,
- SI476X_PROP_PWR_GRID_50HZ);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_AUDIO_PWR_LINE_FILTER,
- SI476X_PROP_PWR_GRID_MASK,
- SI476X_PROP_PWR_GRID_60HZ);
- break;
- default:
- retval = -EINVAL;
- break;
- }
- break;
- case V4L2_CID_SI476X_RSSI_THRESHOLD:
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_VALID_RSSI_THRESHOLD,
- ctrl->val);
- break;
- case V4L2_CID_SI476X_SNR_THRESHOLD:
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_VALID_SNR_THRESHOLD,
- ctrl->val);
- break;
- case V4L2_CID_SI476X_MAX_TUNE_ERROR:
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_VALID_MAX_TUNE_ERROR,
- ctrl->val);
- break;
- case V4L2_CID_RDS_RECEPTION:
- /*
- * It looks like RDS related properties are
- * inaccesable when tuner is in AM mode, so cache the
- * changes
- */
- if (si476x_core_is_in_am_receiver_mode(radio->core))
- regcache_cache_only(radio->core->regmap, true);
-
- if (ctrl->val) {
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT,
- radio->core->rds_fifo_depth);
- if (retval < 0)
- break;
-
- if (radio->core->client->irq) {
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
- SI476X_RDSRECV);
- if (retval < 0)
- break;
- }
-
- /* Drain RDS FIFO before enabling RDS processing */
- retval = si476x_core_cmd_fm_rds_status(radio->core,
- false,
- true,
- true,
- NULL);
- if (retval < 0)
- break;
-
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_FM_RDS_CONFIG,
- SI476X_PROP_RDSEN_MASK,
- SI476X_PROP_RDSEN);
- } else {
- retval = regmap_update_bits(radio->core->regmap,
- SI476X_PROP_FM_RDS_CONFIG,
- SI476X_PROP_RDSEN_MASK,
- !SI476X_PROP_RDSEN);
- }
-
- if (si476x_core_is_in_am_receiver_mode(radio->core))
- regcache_cache_only(radio->core->regmap, false);
- break;
- case V4L2_CID_TUNE_DEEMPHASIS:
- retval = regmap_write(radio->core->regmap,
- SI476X_PROP_AUDIO_DEEMPHASIS,
- ctrl->val);
- break;
-
- case V4L2_CID_SI476X_DIVERSITY_MODE:
- mode = si476x_phase_diversity_idx_to_mode(ctrl->val);
-
- if (mode == radio->core->diversity_mode) {
- retval = 0;
- break;
- }
-
- if (si476x_core_is_in_am_receiver_mode(radio->core)) {
- /*
- * Diversity cannot be configured while tuner
- * is in AM mode so save the changes and carry on.
- */
- radio->core->diversity_mode = mode;
- retval = 0;
- } else {
- retval = radio->ops->phase_diversity(radio->core, mode);
- if (!retval)
- radio->core->diversity_mode = mode;
- }
- break;
-
- default:
- retval = -EINVAL;
- break;
- }
-
- si476x_core_unlock(radio->core);
-
- return retval;
-}
-
-static int si476x_radio_g_chip_ident(struct file *file, void *fh,
- struct v4l2_dbg_chip_ident *chip)
-{
- if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
- v4l2_chip_match_host(&chip->match))
- return 0;
- return -EINVAL;
-}
-
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int si476x_radio_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- int err;
- unsigned int value;
- struct si476x_radio *radio = video_drvdata(file);
-
- si476x_core_lock(radio->core);
- reg->size = 2;
- err = regmap_read(radio->core->regmap,
- (unsigned int)reg->reg, &value);
- reg->val = value;
- si476x_core_unlock(radio->core);
-
- return err;
-}
-static int si476x_radio_s_register(struct file *file, void *fh,
- const struct v4l2_dbg_register *reg)
-{
-
- int err;
- struct si476x_radio *radio = video_drvdata(file);
-
- si476x_core_lock(radio->core);
- err = regmap_write(radio->core->regmap,
- (unsigned int)reg->reg,
- (unsigned int)reg->val);
- si476x_core_unlock(radio->core);
-
- return err;
-}
-#endif
-
-static int si476x_radio_fops_open(struct file *file)
-{
- struct si476x_radio *radio = video_drvdata(file);
- int err;
-
- err = v4l2_fh_open(file);
- if (err)
- return err;
-
- if (v4l2_fh_is_singular_file(file)) {
- si476x_core_lock(radio->core);
- err = si476x_core_set_power_state(radio->core,
- SI476X_POWER_UP_FULL);
- if (err < 0)
- goto done;
-
- err = si476x_radio_do_post_powerup_init(radio,
- radio->core->power_up_parameters.func);
- if (err < 0)
- goto power_down;
-
- err = si476x_radio_pretune(radio,
- radio->core->power_up_parameters.func);
- if (err < 0)
- goto power_down;
-
- si476x_core_unlock(radio->core);
- /*Must be done after si476x_core_unlock to prevent a deadlock*/
- v4l2_ctrl_handler_setup(&radio->ctrl_handler);
- }
-
- return err;
-
-power_down:
- si476x_core_set_power_state(radio->core,
- SI476X_POWER_DOWN);
-done:
- si476x_core_unlock(radio->core);
- v4l2_fh_release(file);
-
- return err;
-}
-
-static int si476x_radio_fops_release(struct file *file)
-{
- int err;
- struct si476x_radio *radio = video_drvdata(file);
-
- if (v4l2_fh_is_singular_file(file) &&
- atomic_read(&radio->core->is_alive))
- si476x_core_set_power_state(radio->core,
- SI476X_POWER_DOWN);
-
- err = v4l2_fh_release(file);
-
- return err;
-}
-
-static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- ssize_t rval;
- size_t fifo_len;
- unsigned int copied;
-
- struct si476x_radio *radio = video_drvdata(file);
-
- /* block if no new data available */
- if (kfifo_is_empty(&radio->core->rds_fifo)) {
- if (file->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
-
- rval = wait_event_interruptible(radio->core->rds_read_queue,
- (!kfifo_is_empty(&radio->core->rds_fifo) ||
- !atomic_read(&radio->core->is_alive)));
- if (rval < 0)
- return -EINTR;
-
- if (!atomic_read(&radio->core->is_alive))
- return -ENODEV;
- }
-
- fifo_len = kfifo_len(&radio->core->rds_fifo);
-
- if (kfifo_to_user(&radio->core->rds_fifo, buf,
- min(fifo_len, count),
- &copied) != 0) {
- dev_warn(&radio->videodev.dev,
- "Error during FIFO to userspace copy\n");
- rval = -EIO;
- } else {
- rval = (ssize_t)copied;
- }
-
- return rval;
-}
-
-static unsigned int si476x_radio_fops_poll(struct file *file,
- struct poll_table_struct *pts)
-{
- struct si476x_radio *radio = video_drvdata(file);
- unsigned long req_events = poll_requested_events(pts);
- unsigned int err = v4l2_ctrl_poll(file, pts);
-
- if (req_events & (POLLIN | POLLRDNORM)) {
- if (atomic_read(&radio->core->is_alive))
- poll_wait(file, &radio->core->rds_read_queue, pts);
-
- if (!atomic_read(&radio->core->is_alive))
- err = POLLHUP;
-
- if (!kfifo_is_empty(&radio->core->rds_fifo))
- err = POLLIN | POLLRDNORM;
- }
-
- return err;
-}
-
-static const struct v4l2_file_operations si476x_fops = {
- .owner = THIS_MODULE,
- .read = si476x_radio_fops_read,
- .poll = si476x_radio_fops_poll,
- .unlocked_ioctl = video_ioctl2,
- .open = si476x_radio_fops_open,
- .release = si476x_radio_fops_release,
-};
-
-
-static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
- .vidioc_querycap = si476x_radio_querycap,
- .vidioc_g_tuner = si476x_radio_g_tuner,
- .vidioc_s_tuner = si476x_radio_s_tuner,
-
- .vidioc_g_frequency = si476x_radio_g_frequency,
- .vidioc_s_frequency = si476x_radio_s_frequency,
- .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek,
- .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands,
-
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-
- .vidioc_g_chip_ident = si476x_radio_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = si476x_radio_g_register,
- .vidioc_s_register = si476x_radio_s_register,
-#endif
-};
-
-
-static const struct video_device si476x_viddev_template = {
- .fops = &si476x_fops,
- .name = DRIVER_NAME,
- .release = video_device_release_empty,
-};
-
-
-
-static ssize_t si476x_radio_read_acf_blob(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int err;
- struct si476x_radio *radio = file->private_data;
- struct si476x_acf_status_report report;
-
- si476x_core_lock(radio->core);
- if (radio->ops->acf_status)
- err = radio->ops->acf_status(radio->core, &report);
- else
- err = -ENOENT;
- si476x_core_unlock(radio->core);
-
- if (err < 0)
- return err;
-
- return simple_read_from_buffer(user_buf, count, ppos, &report,
- sizeof(report));
-}
-
-static const struct file_operations radio_acf_fops = {
- .open = simple_open,
- .llseek = default_llseek,
- .read = si476x_radio_read_acf_blob,
-};
-
-static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int err;
- struct si476x_radio *radio = file->private_data;
- struct si476x_rds_blockcount_report report;
-
- si476x_core_lock(radio->core);
- if (radio->ops->rds_blckcnt)
- err = radio->ops->rds_blckcnt(radio->core, true,
- &report);
- else
- err = -ENOENT;
- si476x_core_unlock(radio->core);
-
- if (err < 0)
- return err;
-
- return simple_read_from_buffer(user_buf, count, ppos, &report,
- sizeof(report));
-}
-
-static const struct file_operations radio_rds_blckcnt_fops = {
- .open = simple_open,
- .llseek = default_llseek,
- .read = si476x_radio_read_rds_blckcnt_blob,
-};
-
-static ssize_t si476x_radio_read_agc_blob(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int err;
- struct si476x_radio *radio = file->private_data;
- struct si476x_agc_status_report report;
-
- si476x_core_lock(radio->core);
- if (radio->ops->rds_blckcnt)
- err = radio->ops->agc_status(radio->core, &report);
- else
- err = -ENOENT;
- si476x_core_unlock(radio->core);
-
- if (err < 0)
- return err;
-
- return simple_read_from_buffer(user_buf, count, ppos, &report,
- sizeof(report));
-}
-
-static const struct file_operations radio_agc_fops = {
- .open = simple_open,
- .llseek = default_llseek,
- .read = si476x_radio_read_agc_blob,
-};
-
-static ssize_t si476x_radio_read_rsq_blob(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int err;
- struct si476x_radio *radio = file->private_data;
- struct si476x_rsq_status_report report;
- struct si476x_rsq_status_args args = {
- .primary = false,
- .rsqack = false,
- .attune = false,
- .cancel = false,
- .stcack = false,
- };
-
- si476x_core_lock(radio->core);
- if (radio->ops->rds_blckcnt)
- err = radio->ops->rsq_status(radio->core, &args, &report);
- else
- err = -ENOENT;
- si476x_core_unlock(radio->core);
-
- if (err < 0)
- return err;
-
- return simple_read_from_buffer(user_buf, count, ppos, &report,
- sizeof(report));
-}
-
-static const struct file_operations radio_rsq_fops = {
- .open = simple_open,
- .llseek = default_llseek,
- .read = si476x_radio_read_rsq_blob,
-};
-
-static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int err;
- struct si476x_radio *radio = file->private_data;
- struct si476x_rsq_status_report report;
- struct si476x_rsq_status_args args = {
- .primary = true,
- .rsqack = false,
- .attune = false,
- .cancel = false,
- .stcack = false,
- };
-
- si476x_core_lock(radio->core);
- if (radio->ops->rds_blckcnt)
- err = radio->ops->rsq_status(radio->core, &args, &report);
- else
- err = -ENOENT;
- si476x_core_unlock(radio->core);
-
- if (err < 0)
- return err;
-
- return simple_read_from_buffer(user_buf, count, ppos, &report,
- sizeof(report));
-}
-
-static const struct file_operations radio_rsq_primary_fops = {
- .open = simple_open,
- .llseek = default_llseek,
- .read = si476x_radio_read_rsq_primary_blob,
-};
-
-
-static int si476x_radio_init_debugfs(struct si476x_radio *radio)
-{
- struct dentry *dentry;
- int ret;
-
- dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto exit;
- }
- radio->debugfs = dentry;
-
- dentry = debugfs_create_file("acf", S_IRUGO,
- radio->debugfs, radio, &radio_acf_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- dentry = debugfs_create_file("rds_blckcnt", S_IRUGO,
- radio->debugfs, radio,
- &radio_rds_blckcnt_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- dentry = debugfs_create_file("agc", S_IRUGO,
- radio->debugfs, radio, &radio_agc_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- dentry = debugfs_create_file("rsq", S_IRUGO,
- radio->debugfs, radio, &radio_rsq_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- dentry = debugfs_create_file("rsq_primary", S_IRUGO,
- radio->debugfs, radio,
- &radio_rsq_primary_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- return 0;
-cleanup:
- debugfs_remove_recursive(radio->debugfs);
-exit:
- return ret;
-}
-
-
-static int si476x_radio_add_new_custom(struct si476x_radio *radio,
- enum si476x_ctrl_idx idx)
-{
- int rval;
- struct v4l2_ctrl *ctrl;
-
- ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler,
- &si476x_ctrls[idx],
- NULL);
- rval = radio->ctrl_handler.error;
- if (ctrl == NULL && rval)
- dev_err(radio->v4l2dev.dev,
- "Could not initialize '%s' control %d\n",
- si476x_ctrls[idx].name, rval);
-
- return rval;
-}
-
-static int si476x_radio_probe(struct platform_device *pdev)
-{
- int rval;
- struct si476x_radio *radio;
- struct v4l2_ctrl *ctrl;
-
- static atomic_t instance = ATOMIC_INIT(0);
-
- radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
- if (!radio)
- return -ENOMEM;
-
- radio->core = i2c_mfd_cell_to_core(&pdev->dev);
-
- v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance);
-
- rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
- if (rval) {
- dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
- return rval;
- }
-
- memcpy(&radio->videodev, &si476x_viddev_template,
- sizeof(struct video_device));
-
- radio->videodev.v4l2_dev = &radio->v4l2dev;
- radio->videodev.ioctl_ops = &si4761_ioctl_ops;
-
- video_set_drvdata(&radio->videodev, radio);
- platform_set_drvdata(pdev, radio);
-
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
-
- radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
- v4l2_ctrl_handler_init(&radio->ctrl_handler,
- 1 + ARRAY_SIZE(si476x_ctrls));
-
- if (si476x_core_has_am(radio->core)) {
- ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
- &si476x_ctrl_ops,
- V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- 0, 0);
- rval = radio->ctrl_handler.error;
- if (ctrl == NULL && rval) {
- dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n",
- rval);
- goto exit;
- }
-
- rval = si476x_radio_add_new_custom(radio,
- SI476X_IDX_HARMONICS_COUNT);
- if (rval < 0)
- goto exit;
- }
-
- rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD);
- if (rval < 0)
- goto exit;
-
- rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD);
- if (rval < 0)
- goto exit;
-
- rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR);
- if (rval < 0)
- goto exit;
-
- ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
- &si476x_ctrl_ops,
- V4L2_CID_TUNE_DEEMPHASIS,
- V4L2_DEEMPHASIS_75_uS, 0, 0);
- rval = radio->ctrl_handler.error;
- if (ctrl == NULL && rval) {
- dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n",
- rval);
- goto exit;
- }
-
- ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops,
- V4L2_CID_RDS_RECEPTION,
- 0, 1, 1, 1);
- rval = radio->ctrl_handler.error;
- if (ctrl == NULL && rval) {
- dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n",
- rval);
- goto exit;
- }
-
- if (si476x_core_has_diversity(radio->core)) {
- si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
- si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
- si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
- if (rval < 0)
- goto exit;
-
- si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
- if (rval < 0)
- goto exit;
- }
-
- /* register video device */
- rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1);
- if (rval < 0) {
- dev_err(&pdev->dev, "Could not register video device\n");
- goto exit;
- }
-
- rval = si476x_radio_init_debugfs(radio);
- if (rval < 0) {
- dev_err(&pdev->dev, "Could not creat debugfs interface\n");
- goto exit;
- }
-
- return 0;
-exit:
- v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
- return rval;
-}
-
-static int si476x_radio_remove(struct platform_device *pdev)
-{
- struct si476x_radio *radio = platform_get_drvdata(pdev);
-
- v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
- video_unregister_device(&radio->videodev);
- v4l2_device_unregister(&radio->v4l2dev);
- debugfs_remove_recursive(radio->debugfs);
-
- return 0;
-}
-
-MODULE_ALIAS("platform:si476x-radio");
-
-static struct platform_driver si476x_radio_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
- .probe = si476x_radio_probe,
- .remove = si476x_radio_remove,
-};
-module_platform_driver(si476x_radio_driver);
-
-MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
-MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index b8f9f85a11c9..72e3fa652481 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -528,8 +528,10 @@ static int send_packet(struct imon_context *ictx)
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 bool imon_find_endpoints(struct imon_context *ictx,
}
-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 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
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 @@ static int imon_probe(struct usb_interface *interface,
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 @@ static int imon_probe(struct usb_interface *interface,
}
} 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 @@ static int imon_probe(struct usb_interface *interface,
}
- /* 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/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 2e762742a4c7..90cfa35ef6e6 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -635,7 +635,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
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 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* 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/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 11798426fa88..f08136052f9c 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1431,13 +1431,22 @@ static int dib8090_get_adc_power(struct dvb_frontend *fe)
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 @@ static struct dib8000_config dib809x_dib8000_config[2] = {
.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 @@ static struct dib0090_config dib809x_dib0090_config = {
.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 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
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, &ltgain);
- 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 @@ struct dibx090p_adc {
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 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe)
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 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
}
/* 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 @@ static int dib7090_agc_startup(struct dvb_frontend *fe)
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 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
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 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = {
{ 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 @@ static struct dibx000_agc_config dib7090_agc_config[2] = {
.wbd_alpha = 5,
.agc1_max = 65535,
- .agc1_min = 0,
+ .agc1_min = 32768,
.agc2_max = 65535,
.agc2_min = 0,
@@ -2505,7 +2618,7 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.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 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.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 @@ 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,
@@ -2587,34 +2714,6 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
}
};
-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 @@ static const struct dib0090_config nim7090_dib0090_config = {
.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 @@ static struct dib7000p_config tfe7790e_dib7000p_config = {
.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 @@ static const struct dib0090_config tfe7790e_dib0090_config = {
.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 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
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 @@ static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
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)
-{
- 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)
+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,
- &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 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 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 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Elgato EyeTV DTT rev. 2",
- { &dib0700_usb_id_table[81], NULL },
+ { &dib0700_usb_id_table[80], NULL },
{ NULL },
},
},
@@ -4697,48 +4716,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.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 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.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 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.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 cc63f1963de5..83bfbe4c980f 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2910,7 +2910,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
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 @@ static int em28xx_usb_probe(struct usb_interface *interface,
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 3a43ba0959bf..67f572c3fba2 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -27,7 +27,6 @@ struct videobuf_dma_contig_memory {
u32 magic;
void *vaddr;
dma_addr_t dma_handle;
- bool cached;
unsigned long size;
};
@@ -43,26 +42,8 @@ static int __videobuf_dc_alloc(struct device *dev,
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 int __videobuf_dc_alloc(struct device *dev,
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 @@ out_up:
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 @@ static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
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 @@ static int __videobuf_iolock(struct videobuf_queue *q,
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 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
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 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
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,17 +338,8 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc_vb = __videobuf_alloc_uncached,
- .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,
+ .alloc_vb = __videobuf_alloc,
.iolock = __videobuf_iolock,
- .sync = __videobuf_sync,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = __videobuf_to_vaddr,
};
@@ -447,20 +359,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
}
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 58c17444d22f..7d833eefaf4e 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -54,10 +54,15 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
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 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
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 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
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 ae35d255a430..fd56f2563201 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -162,9 +162,6 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
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 59522b2ebae1..16ae3dcc7e29 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -55,7 +55,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
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/mfd/Kconfig b/drivers/mfd/Kconfig
index b6bb6d5f89e7..c346941a2515 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -977,19 +977,6 @@ config MFD_WL1273_CORE
driver connects the radio-wl1273 V4L2 module and the wl1273
audio codec.
-config MFD_SI476X_CORE
- tristate "Support for Silicon Laboratories 4761/64/68 AM/FM radio."
- depends on I2C
- select MFD_CORE
- select REGMAP_I2C
- help
- This is the core driver for the SI476x series of AM/FM
- radio. This MFD driver connects the radio-si476x V4L2 module
- and the si476x audio codec.
-
- To compile this driver as a module, choose M here: the
- module will be called si476x-core.
-
config MFD_OMAP_USB_HOST
bool "Support OMAP USBHS core and TLL driver"
depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b7aaa1e104a1..b90409c23664 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -131,10 +131,6 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
-
-si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o
-obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
-
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 321d3ef05006..1733081eb873 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -382,6 +382,7 @@ struct device_node *of_get_next_parent(struct device_node *node)
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return parent;
}
+EXPORT_SYMBOL(of_get_next_parent);
/**
* of_get_next_child - Iterate a node childs
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
index 8bde187e4f90..6e16af720504 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/staging/media/go7007/go7007-priv.h
@@ -91,8 +91,8 @@ struct go7007_board_info {
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 6c7d20f8f67c..98e2902afd74 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -519,10 +519,15 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
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_get_input(struct file *file, void *priv,
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 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
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 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv,
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 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv,
if (pix->priv)
solo_enc->type = SOLO_ENC_TYPE_EXT;
*/
+ solo_update_mode(solo_enc);
return 0;
}
@@ -918,8 +941,7 @@ static int solo_enum_framesizes(struct file *file, void *priv,
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 @@ static int solo_enum_frameintervals(struct file *file, void *priv,
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 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
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;