diff options
author | Andy Walls <awalls@radix.net> | 2009-07-03 10:54:40 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-07-05 13:29:59 -0400 |
commit | ff861fb21e44ab178eddc6a1dd7c5478e3eb2ec5 (patch) | |
tree | 56aaf1167a8965cc90fcb54605f5c38fe5984e49 /drivers/media | |
parent | 9f38a920b232800fd4000ba3d4617b41198e017e (diff) |
V4L/DVB (12182): cx18: Add DVB-T support for Yuan MPC-718 cards with an MT352 or ZL10353
Add DVB-T support for Yuan MPC-718 cards with an MT352 or ZL10353 demodulator.
There are apparently some units with a DiBcom demodulator which could be
supported by one of the dib7000 modules - but this is not implemented in the
cx18 driver (yet).
Due to lack of porgramming details for the MT352 and the mt352 module requiring
a "demod_init" function, a "firmware" must be obtained and loaded to get
DVB-T working for Yuan MPC-718 cards with an MT352.
Tested-by: Steve Firth <firth650@btinternet.com>
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.c | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.c | 160 |
2 files changed, 162 insertions, 2 deletions
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 80ee7bd64e24..36f2d76006fd 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c | |||
@@ -204,8 +204,8 @@ static const struct cx18_card cx18_card_mpc718 = { | |||
204 | .v4l2_capabilities = CX18_CAP_ENCODER, | 204 | .v4l2_capabilities = CX18_CAP_ENCODER, |
205 | .hw_audio_ctrl = CX18_HW_418_AV, | 205 | .hw_audio_ctrl = CX18_HW_418_AV, |
206 | .hw_muxer = CX18_HW_GPIO_MUX, | 206 | .hw_muxer = CX18_HW_GPIO_MUX, |
207 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | | 207 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | |
208 | CX18_HW_GPIO_RESET_CTRL, | 208 | CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, |
209 | .video_inputs = { | 209 | .video_inputs = { |
210 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 210 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
211 | { CX18_CARD_INPUT_SVIDEO1, 1, | 211 | { CX18_CARD_INPUT_SVIDEO1, 1, |
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 6ea3fe623ef4..51a0c33b25b7 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c | |||
@@ -30,6 +30,10 @@ | |||
30 | #include "s5h1409.h" | 30 | #include "s5h1409.h" |
31 | #include "mxl5005s.h" | 31 | #include "mxl5005s.h" |
32 | #include "zl10353.h" | 32 | #include "zl10353.h" |
33 | |||
34 | #include <linux/firmware.h> | ||
35 | #include "mt352.h" | ||
36 | #include "mt352_priv.h" | ||
33 | #include "tuner-xc2028.h" | 37 | #include "tuner-xc2028.h" |
34 | 38 | ||
35 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 39 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
@@ -38,6 +42,11 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
38 | #define CX18_CLOCK_ENABLE2 0xc71024 | 42 | #define CX18_CLOCK_ENABLE2 0xc71024 |
39 | #define CX18_DMUX_CLK_MASK 0x0080 | 43 | #define CX18_DMUX_CLK_MASK 0x0080 |
40 | 44 | ||
45 | /* | ||
46 | * CX18_CARD_HVR_1600_ESMT | ||
47 | * CX18_CARD_HVR_1600_SAMSUNG | ||
48 | */ | ||
49 | |||
41 | static struct mxl5005s_config hauppauge_hvr1600_tuner = { | 50 | static struct mxl5005s_config hauppauge_hvr1600_tuner = { |
42 | .i2c_address = 0xC6 >> 1, | 51 | .i2c_address = 0xC6 >> 1, |
43 | .if_freq = IF_FREQ_5380000HZ, | 52 | .if_freq = IF_FREQ_5380000HZ, |
@@ -65,6 +74,9 @@ static struct s5h1409_config hauppauge_hvr1600_config = { | |||
65 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK | 74 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK |
66 | }; | 75 | }; |
67 | 76 | ||
77 | /* | ||
78 | * CX18_CARD_LEADTEK_DVR3100H | ||
79 | */ | ||
68 | /* Information/confirmation of proper config values provided by Terry Wu */ | 80 | /* Information/confirmation of proper config values provided by Terry Wu */ |
69 | static struct zl10353_config leadtek_dvr3100h_demod = { | 81 | static struct zl10353_config leadtek_dvr3100h_demod = { |
70 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ | 82 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ |
@@ -74,6 +86,121 @@ static struct zl10353_config leadtek_dvr3100h_demod = { | |||
74 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ | 86 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ |
75 | }; | 87 | }; |
76 | 88 | ||
89 | /* | ||
90 | * CX18_CARD_YUAN_MPC718 | ||
91 | */ | ||
92 | /* | ||
93 | * Due to | ||
94 | * | ||
95 | * 1. an absence of information on how to prgram the MT352 | ||
96 | * 2. the Linux mt352 module pushing MT352 initialzation off onto us here | ||
97 | * | ||
98 | * We have to use an init sequence that *you* must extract from the Windows | ||
99 | * driver (yuanrap.sys) and which we load as a firmware. | ||
100 | * | ||
101 | * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual | ||
102 | * with chip programming details, then I can remove this annoyance. | ||
103 | */ | ||
104 | static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, | ||
105 | const struct firmware **fw) | ||
106 | { | ||
107 | struct cx18 *cx = stream->cx; | ||
108 | const char *fn = "dvb-cx18-mpc718-mt352.fw"; | ||
109 | int ret; | ||
110 | |||
111 | ret = request_firmware(fw, fn, &cx->pci_dev->dev); | ||
112 | if (ret) | ||
113 | CX18_ERR("Unable to open firmware file %s\n", fn); | ||
114 | else { | ||
115 | size_t sz = (*fw)->size; | ||
116 | if (sz < 2 || sz > 64 || (sz % 2) != 0) { | ||
117 | CX18_ERR("Firmware %s has a bad size: %lu bytes\n", | ||
118 | fn, (unsigned long) sz); | ||
119 | ret = -EILSEQ; | ||
120 | release_firmware(*fw); | ||
121 | *fw = NULL; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (ret) { | ||
126 | CX18_ERR("The MPC718 board variant with the MT352 DVB-T" | ||
127 | "demodualtor will not work without it\n"); | ||
128 | CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " | ||
129 | "mpc718' if you need the firmware\n"); | ||
130 | } | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int yuan_mpc718_mt352_init(struct dvb_frontend *fe) | ||
135 | { | ||
136 | struct cx18_dvb *dvb = container_of(fe->dvb, | ||
137 | struct cx18_dvb, dvb_adapter); | ||
138 | struct cx18_stream *stream = container_of(dvb, struct cx18_stream, dvb); | ||
139 | const struct firmware *fw = NULL; | ||
140 | int ret; | ||
141 | int i; | ||
142 | u8 buf[3]; | ||
143 | |||
144 | ret = yuan_mpc718_mt352_reqfw(stream, &fw); | ||
145 | if (ret) | ||
146 | return ret; | ||
147 | |||
148 | /* Loop through all the register-value pairs in the firmware file */ | ||
149 | for (i = 0; i < fw->size; i += 2) { | ||
150 | buf[0] = fw->data[i]; | ||
151 | /* Intercept a few registers we want to set ourselves */ | ||
152 | switch (buf[0]) { | ||
153 | case TRL_NOMINAL_RATE_0: | ||
154 | /* Set our custom OFDM bandwidth in the case below */ | ||
155 | break; | ||
156 | case TRL_NOMINAL_RATE_1: | ||
157 | /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */ | ||
158 | /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */ | ||
159 | /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */ | ||
160 | buf[1] = 0x72; | ||
161 | buf[2] = 0x49; | ||
162 | mt352_write(fe, buf, 3); | ||
163 | break; | ||
164 | case INPUT_FREQ_0: | ||
165 | /* Set our custom IF in the case below */ | ||
166 | break; | ||
167 | case INPUT_FREQ_1: | ||
168 | /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */ | ||
169 | buf[1] = 0x31; | ||
170 | buf[2] = 0xc0; | ||
171 | mt352_write(fe, buf, 3); | ||
172 | break; | ||
173 | default: | ||
174 | /* Pass through the register-value pair from the fw */ | ||
175 | buf[1] = fw->data[i+1]; | ||
176 | mt352_write(fe, buf, 2); | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | buf[0] = (u8) TUNER_GO; | ||
182 | buf[1] = 0x01; /* Go */ | ||
183 | mt352_write(fe, buf, 2); | ||
184 | release_firmware(fw); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct mt352_config yuan_mpc718_mt352_demod = { | ||
189 | .demod_address = 0x1e >> 1, | ||
190 | .adc_clock = 20480, /* 20.480 MHz */ | ||
191 | .if2 = 4560, /* 4.560 MHz */ | ||
192 | .no_tuner = 1, /* XC3028 is not behind the gate */ | ||
193 | .demod_init = yuan_mpc718_mt352_init, | ||
194 | }; | ||
195 | |||
196 | static struct zl10353_config yuan_mpc718_zl10353_demod = { | ||
197 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ | ||
198 | .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ | ||
199 | .parallel_ts = 1, /* Not a serial TS */ | ||
200 | .no_tuner = 1, /* XC3028 is not behind the gate */ | ||
201 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ | ||
202 | }; | ||
203 | |||
77 | static int dvb_register(struct cx18_stream *stream); | 204 | static int dvb_register(struct cx18_stream *stream); |
78 | 205 | ||
79 | /* Kernel DVB framework calls this when the feed needs to start. | 206 | /* Kernel DVB framework calls this when the feed needs to start. |
@@ -113,6 +240,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) | |||
113 | break; | 240 | break; |
114 | 241 | ||
115 | case CX18_CARD_LEADTEK_DVR3100H: | 242 | case CX18_CARD_LEADTEK_DVR3100H: |
243 | case CX18_CARD_YUAN_MPC718: | ||
116 | default: | 244 | default: |
117 | /* Assumption - Parallel transport - Signalling | 245 | /* Assumption - Parallel transport - Signalling |
118 | * undefined or default. | 246 | * undefined or default. |
@@ -326,6 +454,38 @@ static int dvb_register(struct cx18_stream *stream) | |||
326 | fe->ops.tuner_ops.set_config(fe, &ctrl); | 454 | fe->ops.tuner_ops.set_config(fe, &ctrl); |
327 | } | 455 | } |
328 | break; | 456 | break; |
457 | case CX18_CARD_YUAN_MPC718: | ||
458 | /* | ||
459 | * TODO | ||
460 | * Apparently, these cards also could instead have a | ||
461 | * DiBcom demod supported by one of the db7000 drivers | ||
462 | */ | ||
463 | dvb->fe = dvb_attach(mt352_attach, | ||
464 | &yuan_mpc718_mt352_demod, | ||
465 | &cx->i2c_adap[1]); | ||
466 | if (dvb->fe == NULL) | ||
467 | dvb->fe = dvb_attach(zl10353_attach, | ||
468 | &yuan_mpc718_zl10353_demod, | ||
469 | &cx->i2c_adap[1]); | ||
470 | if (dvb->fe != NULL) { | ||
471 | struct dvb_frontend *fe; | ||
472 | struct xc2028_config cfg = { | ||
473 | .i2c_adap = &cx->i2c_adap[1], | ||
474 | .i2c_addr = 0xc2 >> 1, | ||
475 | .ctrl = NULL, | ||
476 | }; | ||
477 | static struct xc2028_ctrl ctrl = { | ||
478 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
479 | .max_len = 64, | ||
480 | .demod = XC3028_FE_ZARLINK456, | ||
481 | .type = XC2028_AUTO, | ||
482 | }; | ||
483 | |||
484 | fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); | ||
485 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
486 | fe->ops.tuner_ops.set_config(fe, &ctrl); | ||
487 | } | ||
488 | break; | ||
329 | default: | 489 | default: |
330 | /* No Digital Tv Support */ | 490 | /* No Digital Tv Support */ |
331 | break; | 491 | break; |