diff options
author | Steven Toth <stoth@hauppauge.com> | 2008-01-05 14:50:14 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:05:05 -0500 |
commit | 27c685a4b09b5e391023d769cddb97e4fcb3b9e1 (patch) | |
tree | af296caf5de933e90f7c82170f0cc2e57dd062f0 | |
parent | dfc1c08aab447d49230dacb390d3f2263584d28f (diff) |
V4L/DVB (7042): xc5000: Tuner analog support
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 <czhang1974@gmail.com>
Signed-off-by: Steven Toth <stoth@hauppauge.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | Documentation/video4linux/CARDLIST.tuner | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/xc5000.c | 213 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/xc5000.h | 12 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 20 | ||||
-rw-r--r-- | drivers/media/video/tuner-types.c | 4 | ||||
-rw-r--r-- | include/media/tuner.h | 1 |
6 files changed, 213 insertions, 38 deletions
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 2211c8eac643..0e2394695bb8 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner | |||
@@ -73,3 +73,4 @@ tuner=71 - Xceive xc2028/xc3028 tuner | |||
73 | tuner=72 - Thomson FE6600 | 73 | tuner=72 - Thomson FE6600 |
74 | tuner=73 - Samsung TCPG 6121P30A | 74 | tuner=73 - Samsung TCPG 6121P30A |
75 | tuner=75 - Philips TEA5761 FM Radio | 75 | tuner=75 - Philips TEA5761 FM Radio |
76 | tuner=76 - Xceive 5000 tuner | ||
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index a036530ee4b4..28048d5307a2 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
25 | #include <linux/videodev2.h> | ||
25 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
26 | #include <linux/dvb/frontend.h> | 27 | #include <linux/dvb/frontend.h> |
27 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
@@ -56,6 +57,10 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | |||
56 | #define XC_RESULT_I2C_READ_FAILURE 3 | 57 | #define XC_RESULT_I2C_READ_FAILURE 3 |
57 | #define XC_RESULT_OUT_OF_RANGE 5 | 58 | #define XC_RESULT_OUT_OF_RANGE 5 |
58 | 59 | ||
60 | /* Product id */ | ||
61 | #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 | ||
62 | #define XC_PRODUCT_ID_FW_LOADED 0x1388 | ||
63 | |||
59 | /* Registers */ | 64 | /* Registers */ |
60 | #define XREG_INIT 0x00 | 65 | #define XREG_INIT 0x00 |
61 | #define XREG_VIDEO_MODE 0x01 | 66 | #define XREG_VIDEO_MODE 0x01 |
@@ -122,7 +127,29 @@ typedef struct { | |||
122 | } XC_TV_STANDARD; | 127 | } XC_TV_STANDARD; |
123 | 128 | ||
124 | /* Tuner standards */ | 129 | /* Tuner standards */ |
125 | #define DTV6 17 | 130 | #define MN_NTSC_PAL_BTSC 0 |
131 | #define MN_NTSC_PAL_A2 1 | ||
132 | #define MN_NTSC_PAL_EIAJ 2 | ||
133 | #define MN_NTSC_PAL_Mono 3 | ||
134 | #define BG_PAL_A2 4 | ||
135 | #define BG_PAL_NICAM 5 | ||
136 | #define BG_PAL_MONO 6 | ||
137 | #define I_PAL_NICAM 7 | ||
138 | #define I_PAL_NICAM_MONO 8 | ||
139 | #define DK_PAL_A2 9 | ||
140 | #define DK_PAL_NICAM 10 | ||
141 | #define DK_PAL_MONO 11 | ||
142 | #define DK_SECAM_A2DK1 12 | ||
143 | #define DK_SECAM_A2LDK3 13 | ||
144 | #define DK_SECAM_A2MONO 14 | ||
145 | #define L_SECAM_NICAM 15 | ||
146 | #define LC_SECAM_NICAM 16 | ||
147 | #define DTV6 17 | ||
148 | #define DTV8 18 | ||
149 | #define DTV7_8 19 | ||
150 | #define DTV7 20 | ||
151 | #define FM_Radio_INPUT2 21 | ||
152 | #define FM_Radio_INPUT1 22 | ||
126 | 153 | ||
127 | XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { | 154 | XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { |
128 | {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, | 155 | {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, |
@@ -184,12 +211,13 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) | |||
184 | 211 | ||
185 | dprintk(1, "%s()\n", __FUNCTION__); | 212 | dprintk(1, "%s()\n", __FUNCTION__); |
186 | 213 | ||
187 | if (priv->cfg->tuner_reset) { | 214 | if (priv->cfg->tuner_callback) { |
188 | ret = priv->cfg->tuner_reset(fe); | 215 | ret = priv->cfg->tuner_callback(priv->cfg->video_dev, |
216 | XC5000_TUNER_RESET, 0); | ||
189 | if (ret) | 217 | if (ret) |
190 | printk(KERN_ERR "xc5000: reset failed\n"); | 218 | printk(KERN_ERR "xc5000: reset failed\n"); |
191 | } else | 219 | } else |
192 | printk(KERN_ERR "xc5000: no tuner reset function, fatal\n"); | 220 | printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); |
193 | } | 221 | } |
194 | 222 | ||
195 | static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) | 223 | 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[]) | |||
259 | 287 | ||
260 | index=0; | 288 | index=0; |
261 | while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { | 289 | while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { |
262 | |||
263 | len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; | 290 | len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; |
264 | if (len == 0x0000) { | 291 | if (len == 0x0000) { |
265 | /* RESET command */ | 292 | /* RESET command */ |
@@ -311,7 +338,7 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, | |||
311 | u16 VideoMode, u16 AudioMode) | 338 | u16 VideoMode, u16 AudioMode) |
312 | { | 339 | { |
313 | int ret; | 340 | int ret; |
314 | dprintk(1, "%s(%d,%d)\n", __FUNCTION__, VideoMode, AudioMode); | 341 | dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode); |
315 | dprintk(1, "%s() Standard = %s\n", | 342 | dprintk(1, "%s() Standard = %s\n", |
316 | __FUNCTION__, | 343 | __FUNCTION__, |
317 | XC5000_Standard[priv->video_standard].Name); | 344 | XC5000_Standard[priv->video_standard].Name); |
@@ -325,7 +352,11 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, | |||
325 | 352 | ||
326 | static int xc_shutdown(struct xc5000_priv *priv) | 353 | static int xc_shutdown(struct xc5000_priv *priv) |
327 | { | 354 | { |
328 | return xc_write_reg(priv, XREG_POWER_DOWN, 0); | 355 | return 0; |
356 | /* Fixme: cannot bring tuner back alive once shutdown | ||
357 | * without reloading the driver modules. | ||
358 | * return xc_write_reg(priv, XREG_POWER_DOWN, 0); | ||
359 | */ | ||
329 | } | 360 | } |
330 | 361 | ||
331 | static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) | 362 | 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) | |||
349 | { | 380 | { |
350 | u16 freq_code; | 381 | u16 freq_code; |
351 | 382 | ||
352 | dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); | 383 | dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); |
353 | 384 | ||
354 | if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || | 385 | if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || |
355 | (freq_hz < xc5000_tuner_ops.info.frequency_min)) | 386 | (freq_hz < xc5000_tuner_ops.info.frequency_min)) |
@@ -457,7 +488,7 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) | |||
457 | { | 488 | { |
458 | int found = 0; | 489 | int found = 0; |
459 | 490 | ||
460 | dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); | 491 | dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); |
461 | 492 | ||
462 | if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) | 493 | if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) |
463 | return 0; | 494 | return 0; |
@@ -480,7 +511,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) | |||
480 | }; | 511 | }; |
481 | 512 | ||
482 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | 513 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { |
483 | printk(KERN_WARNING "xc5000 I2C read failed\n"); | 514 | printk(KERN_WARNING "xc5000: I2C read failed\n"); |
484 | return -EREMOTEIO; | 515 | return -EREMOTEIO; |
485 | } | 516 | } |
486 | 517 | ||
@@ -494,7 +525,7 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) | |||
494 | .flags = 0, .buf = buf, .len = len }; | 525 | .flags = 0, .buf = buf, .len = len }; |
495 | 526 | ||
496 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | 527 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { |
497 | printk(KERN_ERR "xc5000 I2C write failed (len=%i)\n", | 528 | printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", |
498 | (int)len); | 529 | (int)len); |
499 | return -EREMOTEIO; | 530 | return -EREMOTEIO; |
500 | } | 531 | } |
@@ -519,16 +550,11 @@ static int xc5000_fwupload(struct dvb_frontend* fe) | |||
519 | const struct firmware *fw; | 550 | const struct firmware *fw; |
520 | int ret; | 551 | int ret; |
521 | 552 | ||
522 | if (!priv->cfg->request_firmware) { | ||
523 | printk(KERN_ERR "xc5000: no firmware callback, fatal\n"); | ||
524 | return -EIO; | ||
525 | } | ||
526 | |||
527 | /* request the firmware, this will block and timeout */ | 553 | /* request the firmware, this will block and timeout */ |
528 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | 554 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", |
529 | XC5000_DEFAULT_FIRMWARE); | 555 | XC5000_DEFAULT_FIRMWARE); |
530 | 556 | ||
531 | ret = priv->cfg->request_firmware(fe, &fw, XC5000_DEFAULT_FIRMWARE); | 557 | ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); |
532 | if (ret) { | 558 | if (ret) { |
533 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); | 559 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); |
534 | ret = XC_RESULT_RESET_FAILURE; | 560 | ret = XC_RESULT_RESET_FAILURE; |
@@ -601,7 +627,6 @@ static int xc5000_set_params(struct dvb_frontend *fe, | |||
601 | 627 | ||
602 | dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); | 628 | dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); |
603 | 629 | ||
604 | |||
605 | switch(params->u.vsb.modulation) { | 630 | switch(params->u.vsb.modulation) { |
606 | case VSB_8: | 631 | case VSB_8: |
607 | case VSB_16: | 632 | case VSB_16: |
@@ -658,6 +683,93 @@ static int xc5000_set_params(struct dvb_frontend *fe, | |||
658 | return 0; | 683 | return 0; |
659 | } | 684 | } |
660 | 685 | ||
686 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); | ||
687 | |||
688 | static int xc5000_set_analog_params(struct dvb_frontend *fe, | ||
689 | struct analog_parameters *params) | ||
690 | { | ||
691 | struct xc5000_priv *priv = fe->tuner_priv; | ||
692 | int ret; | ||
693 | |||
694 | if(priv->fwloaded == 0) | ||
695 | xc_load_fw_and_init_tuner(fe); | ||
696 | |||
697 | dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", | ||
698 | __FUNCTION__, params->frequency); | ||
699 | |||
700 | priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ | ||
701 | |||
702 | /* params->frequency is in units of 62.5khz */ | ||
703 | priv->freq_hz = params->frequency * 62500; | ||
704 | |||
705 | /* FIX ME: Some video standards may have several possible audio | ||
706 | standards. We simply default to one of them here. | ||
707 | */ | ||
708 | if(params->std & V4L2_STD_MN) { | ||
709 | /* default to BTSC audio standard */ | ||
710 | priv->video_standard = MN_NTSC_PAL_BTSC; | ||
711 | goto tune_channel; | ||
712 | } | ||
713 | |||
714 | if(params->std & V4L2_STD_PAL_BG) { | ||
715 | /* default to NICAM audio standard */ | ||
716 | priv->video_standard = BG_PAL_NICAM; | ||
717 | goto tune_channel; | ||
718 | } | ||
719 | |||
720 | if(params->std & V4L2_STD_PAL_I) { | ||
721 | /* default to NICAM audio standard */ | ||
722 | priv->video_standard = I_PAL_NICAM; | ||
723 | goto tune_channel; | ||
724 | } | ||
725 | |||
726 | if(params->std & V4L2_STD_PAL_DK) { | ||
727 | /* default to NICAM audio standard */ | ||
728 | priv->video_standard = DK_PAL_NICAM; | ||
729 | goto tune_channel; | ||
730 | } | ||
731 | |||
732 | if(params->std & V4L2_STD_SECAM_DK) { | ||
733 | /* default to A2 DK1 audio standard */ | ||
734 | priv->video_standard = DK_SECAM_A2DK1; | ||
735 | goto tune_channel; | ||
736 | } | ||
737 | |||
738 | if(params->std & V4L2_STD_SECAM_L) { | ||
739 | priv->video_standard = L_SECAM_NICAM; | ||
740 | goto tune_channel; | ||
741 | } | ||
742 | |||
743 | if(params->std & V4L2_STD_SECAM_LC) { | ||
744 | priv->video_standard = LC_SECAM_NICAM; | ||
745 | goto tune_channel; | ||
746 | } | ||
747 | |||
748 | tune_channel: | ||
749 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
750 | if (ret != XC_RESULT_SUCCESS) { | ||
751 | printk(KERN_ERR | ||
752 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
753 | priv->rf_mode); | ||
754 | return -EREMOTEIO; | ||
755 | } | ||
756 | |||
757 | ret = xc_SetTVStandard(priv, | ||
758 | XC5000_Standard[priv->video_standard].VideoMode, | ||
759 | XC5000_Standard[priv->video_standard].AudioMode); | ||
760 | if (ret != XC_RESULT_SUCCESS) { | ||
761 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
762 | return -EREMOTEIO; | ||
763 | } | ||
764 | |||
765 | xc_tune_channel(priv, priv->freq_hz); | ||
766 | |||
767 | if (debug) | ||
768 | xc_debug_dump(priv); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
661 | static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) | 773 | static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) |
662 | { | 774 | { |
663 | struct xc5000_priv *priv = fe->tuner_priv; | 775 | struct xc5000_priv *priv = fe->tuner_priv; |
@@ -670,6 +782,7 @@ static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | |||
670 | { | 782 | { |
671 | struct xc5000_priv *priv = fe->tuner_priv; | 783 | struct xc5000_priv *priv = fe->tuner_priv; |
672 | dprintk(1, "%s()\n", __FUNCTION__); | 784 | dprintk(1, "%s()\n", __FUNCTION__); |
785 | |||
673 | *bw = priv->bandwidth; | 786 | *bw = priv->bandwidth; |
674 | return 0; | 787 | return 0; |
675 | } | 788 | } |
@@ -691,13 +804,12 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) | |||
691 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) | 804 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) |
692 | { | 805 | { |
693 | struct xc5000_priv *priv = fe->tuner_priv; | 806 | struct xc5000_priv *priv = fe->tuner_priv; |
694 | int ret; | 807 | int ret = 0; |
695 | 808 | ||
696 | if (priv->fwloaded == 0) { | 809 | if (priv->fwloaded == 0) { |
697 | ret = xc5000_fwupload(fe); | 810 | ret = xc5000_fwupload(fe); |
698 | if (ret != XC_RESULT_SUCCESS) | 811 | if (ret != XC_RESULT_SUCCESS) |
699 | return ret; | 812 | return ret; |
700 | |||
701 | priv->fwloaded = 1; | 813 | priv->fwloaded = 1; |
702 | } | 814 | } |
703 | 815 | ||
@@ -720,9 +832,27 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) | |||
720 | static int xc5000_sleep(struct dvb_frontend *fe) | 832 | static int xc5000_sleep(struct dvb_frontend *fe) |
721 | { | 833 | { |
722 | struct xc5000_priv *priv = fe->tuner_priv; | 834 | struct xc5000_priv *priv = fe->tuner_priv; |
835 | int ret; | ||
836 | |||
723 | dprintk(1, "%s()\n", __FUNCTION__); | 837 | dprintk(1, "%s()\n", __FUNCTION__); |
724 | 838 | ||
725 | return xc_shutdown(priv); | 839 | /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized |
840 | * once shutdown without reloading the driver. Maybe I am not | ||
841 | * doing something right. | ||
842 | * | ||
843 | */ | ||
844 | |||
845 | ret = xc_shutdown(priv); | ||
846 | if(ret != XC_RESULT_SUCCESS) { | ||
847 | printk(KERN_ERR | ||
848 | "xc5000: %s() unable to shutdown tuner\n", | ||
849 | __FUNCTION__); | ||
850 | return -EREMOTEIO; | ||
851 | } | ||
852 | else { | ||
853 | /* priv->fwloaded = 0; */ | ||
854 | return XC_RESULT_SUCCESS; | ||
855 | } | ||
726 | } | 856 | } |
727 | 857 | ||
728 | static int xc5000_init(struct dvb_frontend *fe) | 858 | static int xc5000_init(struct dvb_frontend *fe) |
@@ -757,14 +887,15 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { | |||
757 | .frequency_step = 50000, | 887 | .frequency_step = 50000, |
758 | }, | 888 | }, |
759 | 889 | ||
760 | .release = xc5000_release, | 890 | .release = xc5000_release, |
761 | .init = xc5000_init, | 891 | .init = xc5000_init, |
762 | .sleep = xc5000_sleep, | 892 | .sleep = xc5000_sleep, |
763 | 893 | ||
764 | .set_params = xc5000_set_params, | 894 | .set_params = xc5000_set_params, |
765 | .get_frequency = xc5000_get_frequency, | 895 | .set_analog_params = xc5000_set_analog_params, |
766 | .get_bandwidth = xc5000_get_bandwidth, | 896 | .get_frequency = xc5000_get_frequency, |
767 | .get_status = xc5000_get_status | 897 | .get_bandwidth = xc5000_get_bandwidth, |
898 | .get_status = xc5000_get_status | ||
768 | }; | 899 | }; |
769 | 900 | ||
770 | struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, | 901 | struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, |
@@ -783,14 +914,33 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, | |||
783 | priv->cfg = cfg; | 914 | priv->cfg = cfg; |
784 | priv->bandwidth = BANDWIDTH_6_MHZ; | 915 | priv->bandwidth = BANDWIDTH_6_MHZ; |
785 | priv->i2c = i2c; | 916 | priv->i2c = i2c; |
786 | priv->fwloaded = 0; | ||
787 | 917 | ||
918 | /* Check if firmware has been loaded. It is possible that another | ||
919 | instance of the driver has loaded the firmware. | ||
920 | */ | ||
788 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { | 921 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { |
789 | kfree(priv); | 922 | kfree(priv); |
790 | return NULL; | 923 | return NULL; |
791 | } | 924 | } |
792 | 925 | ||
793 | if ((id != 0x2000) && (id != 0x1388)) { | 926 | switch(id) { |
927 | case XC_PRODUCT_ID_FW_LOADED: | ||
928 | printk(KERN_INFO | ||
929 | "xc5000: Successfully identified at address 0x%02x\n", | ||
930 | cfg->i2c_address); | ||
931 | printk(KERN_INFO | ||
932 | "xc5000: Firmware has been loaded previously\n"); | ||
933 | priv->fwloaded = 1; | ||
934 | break; | ||
935 | case XC_PRODUCT_ID_FW_NOT_LOADED: | ||
936 | printk(KERN_INFO | ||
937 | "xc5000: Successfully identified at address 0x%02x\n", | ||
938 | cfg->i2c_address); | ||
939 | printk(KERN_INFO | ||
940 | "xc5000: Firmware has not been loaded previously\n"); | ||
941 | priv->fwloaded = 0; | ||
942 | break; | ||
943 | default: | ||
794 | printk(KERN_ERR | 944 | printk(KERN_ERR |
795 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", | 945 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", |
796 | cfg->i2c_address, id); | 946 | cfg->i2c_address, id); |
@@ -798,9 +948,6 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, | |||
798 | return NULL; | 948 | return NULL; |
799 | } | 949 | } |
800 | 950 | ||
801 | printk(KERN_INFO "xc5000: successfully identified at address 0x%02x\n", | ||
802 | cfg->i2c_address); | ||
803 | |||
804 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, | 951 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, |
805 | sizeof(struct dvb_tuner_ops)); | 952 | sizeof(struct dvb_tuner_ops)); |
806 | 953 | ||
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index 941b31948133..85b2d438fa41 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h | |||
@@ -28,13 +28,15 @@ struct dvb_frontend; | |||
28 | struct i2c_adapter; | 28 | struct i2c_adapter; |
29 | 29 | ||
30 | struct xc5000_config { | 30 | struct xc5000_config { |
31 | u8 i2c_address; | 31 | u8 i2c_address; |
32 | u32 if_khz; | 32 | u32 if_khz; |
33 | int (*request_firmware)(struct dvb_frontend *fe, | 33 | void *video_dev; |
34 | const struct firmware **fw, char *name); | 34 | int (*tuner_callback) (void *dev, int command, int arg); |
35 | int (*tuner_reset)(struct dvb_frontend* fe); | ||
36 | }; | 35 | }; |
37 | 36 | ||
37 | /* xc5000 callback command */ | ||
38 | #define XC5000_TUNER_RESET 0 | ||
39 | |||
38 | #if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) | 40 | #if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) |
39 | extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, | 41 | extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, |
40 | struct i2c_adapter *i2c, | 42 | struct i2c_adapter *i2c, |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 35976e6cb1b8..16cdeeafeb6c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "tuner-xc2028.h" | 27 | #include "tuner-xc2028.h" |
28 | #include "tuner-simple.h" | 28 | #include "tuner-simple.h" |
29 | #include "tda9887.h" | 29 | #include "tda9887.h" |
30 | #include "xc5000.h" | ||
30 | 31 | ||
31 | #define UNSET (-1U) | 32 | #define UNSET (-1U) |
32 | 33 | ||
@@ -329,6 +330,8 @@ static void attach_tda829x(struct tuner *t) | |||
329 | tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); | 330 | tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); |
330 | } | 331 | } |
331 | 332 | ||
333 | static struct xc5000_config xc5000_cfg; | ||
334 | |||
332 | static void set_type(struct i2c_client *c, unsigned int type, | 335 | static void set_type(struct i2c_client *c, unsigned int type, |
333 | unsigned int new_mode_mask, unsigned int new_config, | 336 | unsigned int new_mode_mask, unsigned int new_config, |
334 | int (*tuner_callback) (void *dev, int command,int arg)) | 337 | int (*tuner_callback) (void *dev, int command,int arg)) |
@@ -428,6 +431,23 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
428 | case TUNER_TDA9887: | 431 | case TUNER_TDA9887: |
429 | tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); | 432 | tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); |
430 | break; | 433 | break; |
434 | case TUNER_XC5000: | ||
435 | xc5000_cfg.i2c_address = t->i2c->addr; | ||
436 | xc5000_cfg.if_khz = 5380; | ||
437 | xc5000_cfg.video_dev = c->adapter->algo_data; | ||
438 | xc5000_cfg.tuner_callback = t->tuner_callback; | ||
439 | if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { | ||
440 | t->type = TUNER_ABSENT; | ||
441 | t->mode_mask = T_UNINITIALIZED; | ||
442 | return; | ||
443 | } | ||
444 | { | ||
445 | struct dvb_tuner_ops *xc_tuner_ops; | ||
446 | xc_tuner_ops = &t->fe.ops.tuner_ops; | ||
447 | if(xc_tuner_ops->init != NULL) | ||
448 | xc_tuner_ops->init(&t->fe); | ||
449 | } | ||
450 | break; | ||
431 | default: | 451 | default: |
432 | attach_simple_tuner(t); | 452 | attach_simple_tuner(t); |
433 | break; | 453 | break; |
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index e2cd05a05802..883047f9c28c 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c | |||
@@ -1475,6 +1475,10 @@ struct tunertype tuners[] = { | |||
1475 | .name = "Philips TEA5761 FM Radio", | 1475 | .name = "Philips TEA5761 FM Radio", |
1476 | /* see tea5767.c for details */ | 1476 | /* see tea5767.c for details */ |
1477 | }, | 1477 | }, |
1478 | [TUNER_XC5000] = { /* Xceive 5000 */ | ||
1479 | .name = "Xceive 5000 tuner", | ||
1480 | /* see xc5000.c for details */ | ||
1481 | }, | ||
1478 | }; | 1482 | }; |
1479 | 1483 | ||
1480 | unsigned const int tuner_count = ARRAY_SIZE(tuners); | 1484 | unsigned const int tuner_count = ARRAY_SIZE(tuners); |
diff --git a/include/media/tuner.h b/include/media/tuner.h index 97be269afbee..1bf24a6ed8f1 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h | |||
@@ -121,6 +121,7 @@ | |||
121 | #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ | 121 | #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ |
122 | #define TUNER_TDA9887 74 /* This tuner should be used only internally */ | 122 | #define TUNER_TDA9887 74 /* This tuner should be used only internally */ |
123 | #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ | 123 | #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ |
124 | #define TUNER_XC5000 76 /* Xceive Silicon Tuner */ | ||
124 | 125 | ||
125 | /* tv card specific */ | 126 | /* tv card specific */ |
126 | #define TDA9887_PRESENT (1<<0) | 127 | #define TDA9887_PRESENT (1<<0) |