From e2139d325792137613705857f08f07a43ba118f8 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 15 Jan 2008 19:35:22 -0500 Subject: s5h1409: Bug fix for parallel support. From: Steven Toth Parallel support was not working with the s5h1409 and the Pinnacle HD800i. This patch fixes the demodulator driver and ensures that all existing s5h1409 based products configure the demodulator correctly. Signed-off-by: Steven Toth --- linux/drivers/media/dvb/frontends/s5h1409.c | 51 +++++++++++++++++++++---- linux/drivers/media/dvb/frontends/s5h1409.h | 7 ++++ linux/drivers/media/video/cx23885/cx23885-dvb.c | 15 +++++--- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/linux/drivers/media/dvb/frontends/s5h1409.c b/linux/drivers/media/dvb/frontends/s5h1409.c index 3391777e0..819433485 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.c +++ b/linux/drivers/media/dvb/frontends/s5h1409.c @@ -98,7 +98,7 @@ static struct init_tab { { 0xac, 0x1003, }, { 0xad, 0x103f, }, { 0xe2, 0x0100, }, - { 0xe3, 0x0000, }, + { 0xe3, 0x1000, }, { 0x28, 0x1010, }, { 0xb1, 0x000e, }, }; @@ -441,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) dprintk("%s(%d)\n", __FUNCTION__, enable); if (enable) - return s5h1409_writereg(state, 0xe3, 0x1100); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) | 0x1100); else - return s5h1409_writereg(state, 0xe3, 0x1000); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) & 0xeeff); } static int s5h1409_sleep(struct dvb_frontend* fe, int enable) @@ -513,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) s5h1409_writereg(state, 0x96, 0x20); s5h1409_writereg(state, 0xad, ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); - s5h1409_writereg(state, 0xab, 0x1100); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xeffe); } } else { if (state->qam_state != 1) { state->qam_state = 1; s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, 0x1101); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x1001); } } } @@ -556,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, return 0; } +static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __FUNCTION__, mode); + + val = s5h1409_readreg(state, 0xac) & 0xcfff; + switch (mode) { + case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + val |= 0x0000; + break; + case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode); + val |= 0x1000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + val |= 0x2000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + val |= 0x3000; + break; + default: + return -EINVAL; + } + + /* Configure MPEG Signal Timing charactistics */ + return s5h1409_writereg(state, 0xac, val); +} + /* Reset the demod hardware and reset all of the configuration registers to a default state. */ static int s5h1409_init (struct dvb_frontend* fe) @@ -575,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe) state->current_modulation = VSB_8; if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) - s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ else - s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ s5h1409_set_spectralinversion(fe, state->config->inversion); s5h1409_set_if_freq(fe, state->if_freq); s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); s5h1409_softreset(fe); /* Note: Leaving the I2C gate closed. */ diff --git a/linux/drivers/media/dvb/frontends/s5h1409.h b/linux/drivers/media/dvb/frontends/s5h1409.h index b1f433906..f0bb13fe8 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.h +++ b/linux/drivers/media/dvb/frontends/s5h1409.h @@ -51,6 +51,13 @@ struct s5h1409_config #define S5H1409_TUNERLOCKING 0 #define S5H1409_DEMODLOCKING 1 u8 status_mode; + + /* MPEG signal timing */ +#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; }; #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index cd935a13f..fcc5bd346 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -127,7 +127,8 @@ static struct s5h1409_config hauppauge_generic_config = { .gpio = S5H1409_GPIO_ON, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_ezqam_config = { @@ -136,7 +137,8 @@ static struct s5h1409_config hauppauge_ezqam_config = { .gpio = S5H1409_GPIO_OFF, .qam_if = 4000, .inversion = S5H1409_INVERSION_ON, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1800lp_config = { @@ -145,7 +147,8 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .gpio = S5H1409_GPIO_OFF, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1500_config = { @@ -153,7 +156,8 @@ static struct s5h1409_config hauppauge_hvr1500_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -172,7 +176,8 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { .gpio = S5H1409_GPIO_ON, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { -- cgit v1.2.3 From 0ff72a9f6b16aacf4796b7cc828a8e6ef23d21f6 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 14:50:14 -0500 Subject: xc5000: Tuner analog support From: Steven Toth From Zhang: This an updated patch that adds analog support for the xc5000 tuner driver. it was tested on a Pinnacle PCTV HD 800i card (patches to follow). Patch commited as-is, cleanup to follow ... Steve. Signed-off-by: Chaogui Zhang Signed-off-by: Steven Toth --- linux/Documentation/video4linux/CARDLIST.tuner | 1 + linux/drivers/media/dvb/frontends/xc5000.c | 213 +++++++++++++++++++++---- linux/drivers/media/dvb/frontends/xc5000.h | 12 +- linux/drivers/media/video/tuner-core.c | 20 +++ linux/drivers/media/video/tuner-types.c | 4 + linux/include/media/tuner.h | 1 + 6 files changed, 213 insertions(+), 38 deletions(-) diff --git a/linux/Documentation/video4linux/CARDLIST.tuner b/linux/Documentation/video4linux/CARDLIST.tuner index 2211c8eac..0e2394695 100644 --- a/linux/Documentation/video4linux/CARDLIST.tuner +++ b/linux/Documentation/video4linux/CARDLIST.tuner @@ -73,3 +73,4 @@ tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio +tuner=76 - Xceive 5000 tuner diff --git a/linux/drivers/media/dvb/frontends/xc5000.c b/linux/drivers/media/dvb/frontends/xc5000.c index 6d45c3b60..b6fcf8218 100644 --- a/linux/drivers/media/dvb/frontends/xc5000.c +++ b/linux/drivers/media/dvb/frontends/xc5000.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,10 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define XC_RESULT_I2C_READ_FAILURE 3 #define XC_RESULT_OUT_OF_RANGE 5 +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 + /* Registers */ #define XREG_INIT 0x00 #define XREG_VIDEO_MODE 0x01 @@ -122,7 +127,29 @@ typedef struct { } XC_TV_STANDARD; /* Tuner standards */ -#define DTV6 17 +#define MN_NTSC_PAL_BTSC 0 +#define MN_NTSC_PAL_A2 1 +#define MN_NTSC_PAL_EIAJ 2 +#define MN_NTSC_PAL_Mono 3 +#define BG_PAL_A2 4 +#define BG_PAL_NICAM 5 +#define BG_PAL_MONO 6 +#define I_PAL_NICAM 7 +#define I_PAL_NICAM_MONO 8 +#define DK_PAL_A2 9 +#define DK_PAL_NICAM 10 +#define DK_PAL_MONO 11 +#define DK_SECAM_A2DK1 12 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 +#define L_SECAM_NICAM 15 +#define LC_SECAM_NICAM 16 +#define DTV6 17 +#define DTV8 18 +#define DTV7_8 19 +#define DTV7 20 +#define FM_Radio_INPUT2 21 +#define FM_Radio_INPUT1 22 XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, @@ -184,12 +211,13 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __FUNCTION__); - if (priv->cfg->tuner_reset) { - ret = priv->cfg->tuner_reset(fe); + if (priv->cfg->tuner_callback) { + ret = priv->cfg->tuner_callback(priv->cfg->video_dev, + XC5000_TUNER_RESET, 0); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); } else - printk(KERN_ERR "xc5000: no tuner reset function, fatal\n"); + printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); } static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) @@ -259,7 +287,6 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[]) index=0; while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { - len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; if (len == 0x0000) { /* RESET command */ @@ -311,7 +338,7 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, u16 VideoMode, u16 AudioMode) { int ret; - dprintk(1, "%s(%d,%d)\n", __FUNCTION__, VideoMode, AudioMode); + dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode); dprintk(1, "%s() Standard = %s\n", __FUNCTION__, XC5000_Standard[priv->video_standard].Name); @@ -325,7 +352,11 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, static int xc_shutdown(struct xc5000_priv *priv) { - return xc_write_reg(priv, XREG_POWER_DOWN, 0); + return 0; + /* Fixme: cannot bring tuner back alive once shutdown + * without reloading the driver modules. + * return xc_write_reg(priv, XREG_POWER_DOWN, 0); + */ } static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) @@ -349,7 +380,7 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) { u16 freq_code; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || (freq_hz < xc5000_tuner_ops.info.frequency_min)) @@ -476,7 +507,7 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) { int found = 0; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) return 0; @@ -499,7 +530,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) }; if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "xc5000 I2C read failed\n"); + printk(KERN_WARNING "xc5000: I2C read failed\n"); return -EREMOTEIO; } @@ -513,7 +544,7 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) .flags = 0, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C write failed (len=%i)\n", + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", (int)len); return -EREMOTEIO; } @@ -538,16 +569,11 @@ static int xc5000_fwupload(struct dvb_frontend* fe) const struct firmware *fw; int ret; - if (!priv->cfg->request_firmware) { - printk(KERN_ERR "xc5000: no firmware callback, fatal\n"); - return -EIO; - } - /* request the firmware, this will block and timeout */ printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", XC5000_DEFAULT_FIRMWARE); - ret = priv->cfg->request_firmware(fe, &fw, XC5000_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; @@ -620,7 +646,6 @@ static int xc5000_set_params(struct dvb_frontend *fe, dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); - switch(params->u.vsb.modulation) { case VSB_8: case VSB_16: @@ -677,6 +702,93 @@ static int xc5000_set_params(struct dvb_frontend *fe, return 0; } +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if(priv->fwloaded == 0) + xc_load_fw_and_init_tuner(fe); + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __FUNCTION__, params->frequency); + + priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + /* FIX ME: Some video standards may have several possible audio + standards. We simply default to one of them here. + */ + if(params->std & V4L2_STD_MN) { + /* default to BTSC audio standard */ + priv->video_standard = MN_NTSC_PAL_BTSC; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_BG) { + /* default to NICAM audio standard */ + priv->video_standard = BG_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + priv->video_standard = I_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_DK) { + /* default to NICAM audio standard */ + priv->video_standard = DK_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_DK) { + /* default to A2 DK1 audio standard */ + priv->video_standard = DK_SECAM_A2DK1; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_L) { + priv->video_standard = L_SECAM_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_LC) { + priv->video_standard = LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + xc_tune_channel(priv, priv->freq_hz); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; @@ -689,6 +801,7 @@ static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) { struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __FUNCTION__); + *bw = priv->bandwidth; return 0; } @@ -710,13 +823,12 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - int ret; + int ret = 0; if (priv->fwloaded == 0) { ret = xc5000_fwupload(fe); if (ret != XC_RESULT_SUCCESS) return ret; - priv->fwloaded = 1; } @@ -739,9 +851,27 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) static int xc5000_sleep(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); - return xc_shutdown(priv); + /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized + * once shutdown without reloading the driver. Maybe I am not + * doing something right. + * + */ + + ret = xc_shutdown(priv); + if(ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __FUNCTION__); + return -EREMOTEIO; + } + else { + /* priv->fwloaded = 0; */ + return XC_RESULT_SUCCESS; + } } static int xc5000_init(struct dvb_frontend *fe) @@ -776,14 +906,15 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .frequency_step = 50000, }, - .release = xc5000_release, - .init = xc5000_init, - .sleep = xc5000_sleep, + .release = xc5000_release, + .init = xc5000_init, + .sleep = xc5000_sleep, - .set_params = xc5000_set_params, - .get_frequency = xc5000_get_frequency, - .get_bandwidth = xc5000_get_bandwidth, - .get_status = xc5000_get_status + .set_params = xc5000_set_params, + .set_analog_params = xc5000_set_analog_params, + .get_frequency = xc5000_get_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status }; struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, @@ -802,14 +933,33 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, priv->cfg = cfg; priv->bandwidth = BANDWIDTH_6_MHZ; priv->i2c = i2c; - priv->fwloaded = 0; + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { kfree(priv); return NULL; } - if ((id != 0x2000) && (id != 0x1388)) { + switch(id) { + case XC_PRODUCT_ID_FW_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has been loaded previously\n"); + priv->fwloaded = 1; + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has not been loaded previously\n"); + priv->fwloaded = 0; + break; + default: printk(KERN_ERR "xc5000: Device not found at addr 0x%02x (0x%x)\n", cfg->i2c_address, id); @@ -817,9 +967,6 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, return NULL; } - printk(KERN_INFO "xc5000: successfully identified at address 0x%02x\n", - cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, sizeof(struct dvb_tuner_ops)); diff --git a/linux/drivers/media/dvb/frontends/xc5000.h b/linux/drivers/media/dvb/frontends/xc5000.h index 941b31948..85b2d438f 100644 --- a/linux/drivers/media/dvb/frontends/xc5000.h +++ b/linux/drivers/media/dvb/frontends/xc5000.h @@ -28,13 +28,15 @@ struct dvb_frontend; struct i2c_adapter; struct xc5000_config { - u8 i2c_address; - u32 if_khz; - int (*request_firmware)(struct dvb_frontend *fe, - const struct firmware **fw, char *name); - int (*tuner_reset)(struct dvb_frontend* fe); + u8 i2c_address; + u32 if_khz; + void *video_dev; + int (*tuner_callback) (void *dev, int command, int arg); }; +/* xc5000 callback command */ +#define XC5000_TUNER_RESET 0 + #if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index d93a764aa..9fb2b3f77 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -31,6 +31,7 @@ #include "tuner-xc2028.h" #include "tuner-simple.h" #include "tda9887.h" +#include "xc5000.h" #define UNSET (-1U) @@ -358,6 +359,8 @@ static void attach_tda829x(struct tuner *t) tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } +static struct xc5000_config xc5000_cfg; + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -457,6 +460,23 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_TDA9887: tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; + case TUNER_XC5000: + xc5000_cfg.i2c_address = t->i2c->addr; + xc5000_cfg.if_khz = 5380; + xc5000_cfg.video_dev = c->adapter->algo_data; + xc5000_cfg.tuner_callback = t->tuner_callback; + if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + { + struct dvb_tuner_ops *xc_tuner_ops; + xc_tuner_ops = &t->fe.ops.tuner_ops; + if(xc_tuner_ops->init != NULL) + xc_tuner_ops->init(&t->fe); + } + break; default: attach_simple_tuner(t); break; diff --git a/linux/drivers/media/video/tuner-types.c b/linux/drivers/media/video/tuner-types.c index 9076b538d..8b78a2140 100644 --- a/linux/drivers/media/video/tuner-types.c +++ b/linux/drivers/media/video/tuner-types.c @@ -1523,6 +1523,10 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, + [TUNER_XC5000] = { /* Xceive 5000 */ + .name = "Xceive 5000 tuner", + /* see xc5000.c for details */ + }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h index 97be269af..1bf24a6ed 100644 --- a/linux/include/media/tuner.h +++ b/linux/include/media/tuner.h @@ -121,6 +121,7 @@ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ #define TUNER_TDA9887 74 /* This tuner should be used only internally */ #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ +#define TUNER_XC5000 76 /* Xceive Silicon Tuner */ /* tv card specific */ #define TDA9887_PRESENT (1<<0) -- cgit v1.2.3 From 1fb17dcd6513daf99c761c3fbf1d0de8a0170d43 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 14:53:01 -0500 Subject: New card supported(partially): Pinnacle 800i From: Steven Toth From Zhang: This patch continues the support for the Pinnacle HD 800i. Signed-off-by: Chaogui Zhang Patch committed as-is, cleanups to follow ... Steve Signed-off-by: Steven Toth --- linux/Documentation/video4linux/CARDLIST.cx88 | 1 + linux/drivers/media/video/cx88/cx88-cards.c | 63 +++++++++++++++++++++++++++ linux/drivers/media/video/cx88/cx88-dvb.c | 36 +++++++++++++++ linux/drivers/media/video/cx88/cx88-i2c.c | 17 ++++---- linux/drivers/media/video/cx88/cx88-mpeg.c | 7 ++- linux/drivers/media/video/cx88/cx88.h | 2 + 6 files changed, 117 insertions(+), 9 deletions(-) diff --git a/linux/Documentation/video4linux/CARDLIST.cx88 b/linux/Documentation/video4linux/CARDLIST.cx88 index 82ac8250e..bc5593bd9 100644 --- a/linux/Documentation/video4linux/CARDLIST.cx88 +++ b/linux/Documentation/video4linux/CARDLIST.cx88 @@ -56,3 +56,4 @@ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980] 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602] 57 -> ADS Tech Instant Video PCI [1421:0390] + 58 -> Pinnacle PCTV HD 800i [11bd:0051] diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index ec4133254..32c9990b2 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1421,6 +1421,32 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x07fa, }}, }, + [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { + .name = "Pinnacle PCTV HD 800i", + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x10ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + }}, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -1730,6 +1756,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, + },{ + .subvendor = 0x11bd, + .subdevice = 0x0051, + .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, }, }; @@ -1896,6 +1926,39 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) } } +/* ----------------------------------------------------------------------- */ +/* Tuner callback function. Currently only needed for the Pinnacle * + * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * + * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ + +int cx88_tuner_callback(void *i2c_algo, int command, int arg) +{ + struct i2c_algo_bit_data *algo = i2c_algo; + struct cx88_core *core = algo->data; + + switch(core->boardnr) { + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + if(command == 0) { /* This is the reset command from xc5000 */ + /* Reset XC5000 tuner via GPIO pin #2 */ + cx_set(MO_GP0_IO, 0x00000400); + cx_clear(MO_GP0_IO, 0x00000004); + mdelay(200); + cx_set(MO_GP0_IO, 0x00000004); + printk(KERN_ERR "xc5000: in reset for xc5000\n"); + mdelay(200); + return 0; + } + else { + printk(KERN_ERR + "xc5000: unknown tuner callback command.\n"); + return -EINVAL; + } + break; + } + return 0; /* Should never be here */ +} +EXPORT_SYMBOL(cx88_tuner_callback); + /* ----------------------------------------------------------------------- */ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index c4e9177f3..f11865ec3 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -41,6 +41,8 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" +#include "s5h1409.h" +#include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -372,6 +374,22 @@ static struct cx24123_config kworld_dvbs_100_config = { .lnb_polarity = 1, }; +static struct s5h1409_config pinnacle_pctv_hd_800i_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, +}; + +static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { + .i2c_address = 0x64, + .if_khz = 5380, + /* cannot set .video_dev here, do it right before attach */ + .tuner_callback = cx88_tuner_callback, +}; + static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -626,6 +644,24 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Parallel mpeg data port and punctured clock mode */ + dev->ts_gen_cntrl = 0x04; + + dev->dvb.frontend = dvb_attach(s5h1409_attach, + &pinnacle_pctv_hd_800i_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + /* tuner_config.video_dev must point to + * i2c_adap.algo_data + */ + pinnacle_pctv_hd_800i_tuner_config.video_dev = + dev->core->i2c_adap.algo_data; + dvb_attach(xc5000_attach, dev->dvb.frontend, + &dev->core->i2c_adap, + &pinnacle_pctv_hd_800i_tuner_config); + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 04fb4852b..20185aeca 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -117,20 +117,20 @@ static int attach_inform(struct i2c_client *client) if (core->board.radio_type != UNSET) { if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } if (core->board.tuner_type != UNSET) { if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } @@ -190,6 +190,7 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0xc2 >> 1 ] = "tuner (analog/dvb)", + [ 0xc8 >> 1 ] = "xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index e03f15ea9..c63ab2182 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -125,7 +125,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); + cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: @@ -140,6 +140,11 @@ static int cx8802_start_dma(struct cx8802_dev *dev, break; case CX88_BOARD_HAUPPAUGE_HVR1300: break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Enable MPEG parallel port */ + cx_write(MO_PINMUX_IO, 0x80); + udelay(100); + break; default: cx_write(TS_SOP_STAT, 0x00); break; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 0f32cbfbb..ad0a86c15 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -213,6 +213,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 #define CX88_BOARD_HAUPPAUGE_HVR1300 56 #define CX88_BOARD_ADSTECH_PTV_390 57 +#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -622,6 +623,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ +extern int cx88_tuner_callback(void *dev, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); -- cgit v1.2.3 From 5240604a62cc6c8206ed6bf09646c574bdf9b54c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 14:55:45 -0500 Subject: XC5000: Fix support for HVR1500Q broken by patch 1 From: Steven Toth From Zhang: This patch fixes support for the HVR1500Q which was broken when the xc5000 analog patch was added. Signed-off-by: Chaogui Zhang Patch committed as-is, cleanups to follows .... Steve Signed-off-by: Steven Toth --- linux/drivers/media/video/cx23885/cx23885-cards.c | 28 ++++++++++++++++++ linux/drivers/media/video/cx23885/cx23885-dvb.c | 35 +++++------------------ linux/drivers/media/video/cx23885/cx23885.h | 1 + 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index 36d9b6a4a..f7c504b5a 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -245,6 +245,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +/* Tuner callback function for cx23885 boards. Currently only needed + * for HVR1500Q, which has an xc5000 tuner. + */ +int cx23885_tuner_callback(void *i2c_bus, int command, int arg) +{ + struct cx23885_i2c *bus = i2c_bus; + struct cx23885_dev *dev = bus->dev; + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + if(command == 0) { /* Tuner Reset Command from xc5000 */ + /* Drive the tuner into reset and out */ + cx_clear(GP0_IO, 0x00000004); + mdelay(200); + cx_set(GP0_IO, 0x00000004); + return 0; + } + else { + printk(KERN_ERR + "%s(): Unknow command.\n", __FUNCTION__); + return -EINVAL; + } + break; + } + + return 0; /* Should never be here */ +} +EXPORT_SYMBOL(cx23885_tuner_callback); void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index fcc5bd346..8049046fa 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -88,32 +88,6 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } -static int cx23885_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s(?,?,%s)\n", __FUNCTION__, name); - - return request_firmware(fw, name, &dev->pci->dev); -} - -static int hauppauge_hvr1500q_tuner_reset(struct dvb_frontend *fe) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s()\n", __FUNCTION__); - - /* Drive the tuner into reset back back */ - cx_clear(GP0_IO, 0x00000004); - mdelay(200); - cx_set(GP0_IO, 0x00000004); - - return 0; -} - static struct videobuf_queue_ops dvb_qops = { .buf_setup = dvb_buf_setup, .buf_prepare = dvb_buf_prepare, @@ -183,8 +157,8 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - .request_firmware = cx23885_request_firmware, - .tuner_reset = hauppauge_hvr1500q_tuner_reset + /* cannot set .video_dev here, do it before attach. */ + .tuner_callback = cx23885_tuner_callback }; static struct tda829x_config tda829x_no_probe = { @@ -309,6 +283,11 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1500q_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { + /* tunerconfig.video_dev must point to + * i2c_adap.algo_data + */ + hauppauge_hvr1500q_tunerconfig.video_dev = + i2c_bus->i2c_adap.algo_data; dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, &hauppauge_hvr1500q_tunerconfig); diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 4f803d92b..3a160410a 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -400,6 +400,7 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; +extern int cx23885_tuner_callback(void *i2c_bus, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); -- cgit v1.2.3 From 88ad51b6cd401849a446a4d1bcba232055a6923f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 15:08:05 -0500 Subject: xc5000: Small amount of cleanup and commenting. From: Steven Toth xc5000: Small amount of cleanup and commenting, just for clarification. Signed-off-by: Steven Toth --- linux/drivers/media/dvb/frontends/xc5000.c | 4 ++-- linux/drivers/media/dvb/frontends/xc5000.h | 12 ++++++++++-- linux/drivers/media/video/cx23885/cx23885-cards.c | 6 +++--- linux/drivers/media/video/cx23885/cx23885-dvb.c | 7 +------ linux/drivers/media/video/cx23885/cx23885.h | 2 +- linux/drivers/media/video/cx88/cx88-cards.c | 7 +++---- linux/drivers/media/video/cx88/cx88-dvb.c | 3 +-- linux/drivers/media/video/tuner-core.c | 2 +- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/linux/drivers/media/dvb/frontends/xc5000.c b/linux/drivers/media/dvb/frontends/xc5000.c index b6fcf8218..ebc653cfc 100644 --- a/linux/drivers/media/dvb/frontends/xc5000.c +++ b/linux/drivers/media/dvb/frontends/xc5000.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include @@ -212,7 +212,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __FUNCTION__); if (priv->cfg->tuner_callback) { - ret = priv->cfg->tuner_callback(priv->cfg->video_dev, + ret = priv->cfg->tuner_callback(priv->cfg->priv, XC5000_TUNER_RESET, 0); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); diff --git a/linux/drivers/media/dvb/frontends/xc5000.h b/linux/drivers/media/dvb/frontends/xc5000.h index 85b2d438f..e0e84562a 100644 --- a/linux/drivers/media/dvb/frontends/xc5000.h +++ b/linux/drivers/media/dvb/frontends/xc5000.h @@ -30,8 +30,16 @@ struct i2c_adapter; struct xc5000_config { u8 i2c_address; u32 if_khz; - void *video_dev; - int (*tuner_callback) (void *dev, int command, int arg); + + /* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast priv accordingly. + * The xc5000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + void *priv; + int (*tuner_callback) (void *priv, int command, int arg); }; /* xc5000 callback command */ diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index f7c504b5a..8df5e27ed 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -248,9 +248,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* Tuner callback function for cx23885 boards. Currently only needed * for HVR1500Q, which has an xc5000 tuner. */ -int cx23885_tuner_callback(void *i2c_bus, int command, int arg) +int cx23885_tuner_callback(void *priv, int command, int arg) { - struct cx23885_i2c *bus = i2c_bus; + struct cx23885_i2c *bus = priv; struct cx23885_dev *dev = bus->dev; switch(dev->board) { @@ -272,7 +272,7 @@ int cx23885_tuner_callback(void *i2c_bus, int command, int arg) return 0; /* Should never be here */ } -EXPORT_SYMBOL(cx23885_tuner_callback); + void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 8049046fa..fac7523d0 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -157,7 +157,6 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - /* cannot set .video_dev here, do it before attach. */ .tuner_callback = cx23885_tuner_callback }; @@ -283,11 +282,7 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1500q_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - /* tunerconfig.video_dev must point to - * i2c_adap.algo_data - */ - hauppauge_hvr1500q_tunerconfig.video_dev = - i2c_bus->i2c_adap.algo_data; + hauppauge_hvr1500q_tunerconfig.priv = i2c_bus; dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, &hauppauge_hvr1500q_tunerconfig); diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 3a160410a..d66fe2484 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -400,7 +400,7 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; -extern int cx23885_tuner_callback(void *i2c_bus, int command, int arg); +extern int cx23885_tuner_callback(void *priv, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index 32c9990b2..4adecb6a9 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1931,10 +1931,10 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ -int cx88_tuner_callback(void *i2c_algo, int command, int arg) +int cx88_tuner_callback(void *priv, int command, int arg) { - struct i2c_algo_bit_data *algo = i2c_algo; - struct cx88_core *core = algo->data; + struct i2c_algo_bit_data *i2c_algo = priv; + struct cx88_core *core = i2c_algo->data; switch(core->boardnr) { case CX88_BOARD_PINNACLE_PCTV_HD_800i: @@ -1944,7 +1944,6 @@ int cx88_tuner_callback(void *i2c_algo, int command, int arg) cx_clear(MO_GP0_IO, 0x00000004); mdelay(200); cx_set(MO_GP0_IO, 0x00000004); - printk(KERN_ERR "xc5000: in reset for xc5000\n"); mdelay(200); return 0; } diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index f11865ec3..480ad4eac 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -386,7 +386,6 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = { static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { .i2c_address = 0x64, .if_khz = 5380, - /* cannot set .video_dev here, do it right before attach */ .tuner_callback = cx88_tuner_callback, }; @@ -655,7 +654,7 @@ static int dvb_register(struct cx8802_dev *dev) /* tuner_config.video_dev must point to * i2c_adap.algo_data */ - pinnacle_pctv_hd_800i_tuner_config.video_dev = + pinnacle_pctv_hd_800i_tuner_config.priv = dev->core->i2c_adap.algo_data; dvb_attach(xc5000_attach, dev->dvb.frontend, &dev->core->i2c_adap, diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index 9fb2b3f77..6305998e2 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -463,7 +463,7 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_XC5000: xc5000_cfg.i2c_address = t->i2c->addr; xc5000_cfg.if_khz = 5380; - xc5000_cfg.video_dev = c->adapter->algo_data; + xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.tuner_callback = t->tuner_callback; if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { t->type = TUNER_ABSENT; -- cgit v1.2.3 From 42de0c9d677d2af4e41ed7fe4c149427ebeb271e Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 15 Jan 2008 19:57:14 -0500 Subject: Finalise support for the Pinnacle HD 8000i From: Steven Toth Correctly set the atatch structures, enable IR, configure the xc5000 tuner includes. Signed-off-by: Steven Toth --- linux/drivers/media/dvb/frontends/xc5000.c | 2 +- linux/drivers/media/video/cx88/cx88-dvb.c | 4 +--- linux/drivers/media/video/cx88/cx88-input.c | 2 ++ linux/drivers/media/video/cx88/cx88-mpeg.c | 8 ++++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/linux/drivers/media/dvb/frontends/xc5000.c b/linux/drivers/media/dvb/frontends/xc5000.c index ebc653cfc..5afa58a06 100644 --- a/linux/drivers/media/dvb/frontends/xc5000.c +++ b/linux/drivers/media/dvb/frontends/xc5000.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 480ad4eac..1e6eb3123 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -381,6 +381,7 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, }; static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { @@ -644,9 +645,6 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Parallel mpeg data port and punctured clock mode */ - dev->ts_gen_cntrl = 0x04; - dev->dvb.frontend = dvb_attach(s5h1409_attach, &pinnacle_pctv_hd_800i_config, &dev->core->i2c_adap); diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index fc6f476af..66f4423c4 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -237,6 +237,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_PINNACLE_PCTV_HD_800i: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -466,6 +467,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_PINNACLE_PCTV_HD_800i: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index c63ab2182..9ed0af144 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -141,8 +141,12 @@ static int cx8802_start_dma(struct cx8802_dev *dev, case CX88_BOARD_HAUPPAUGE_HVR1300: break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Enable MPEG parallel port */ - cx_write(MO_PINMUX_IO, 0x80); + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); + dev->ts_gen_cntrl = 5; + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); udelay(100); break; default: -- cgit v1.2.3