]>
Commit | Line | Data |
---|---|---|
cbddcba6 DH |
1 | /* |
2 | * ngene-cards.c: nGene PCIe bridge driver - card specific info | |
3 | * | |
4 | * Copyright (C) 2005-2007 Micronas | |
5 | * | |
6 | * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de> | |
7 | * Modifications for new nGene firmware, | |
8 | * support for EEPROM-copying, | |
9 | * support for new dual DVB-S2 card prototype | |
10 | * | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License | |
14 | * version 2 only, as published by the Free Software Foundation. | |
15 | * | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this program; if not, write to the Free Software | |
25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
26 | * 02110-1301, USA | |
27 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | |
28 | */ | |
29 | ||
30 | #include <linux/module.h> | |
31 | #include <linux/init.h> | |
32 | #include <linux/pci.h> | |
33 | #include <linux/pci_ids.h> | |
34 | ||
35 | #include "ngene.h" | |
36 | ||
37 | /* demods/tuners */ | |
38 | #include "stv6110x.h" | |
39 | #include "stv090x.h" | |
40 | #include "lnbh24.h" | |
41 | #include "lgdt330x.h" | |
42 | #include "mt2131.h" | |
43 | ||
44 | ||
45 | /****************************************************************************/ | |
46 | /* Demod/tuner attachment ***************************************************/ | |
47 | /****************************************************************************/ | |
48 | ||
49 | static int tuner_attach_stv6110(struct ngene_channel *chan) | |
50 | { | |
51 | struct stv090x_config *feconf = (struct stv090x_config *) | |
52 | chan->dev->card_info->fe_config[chan->number]; | |
53 | struct stv6110x_config *tunerconf = (struct stv6110x_config *) | |
54 | chan->dev->card_info->tuner_config[chan->number]; | |
55 | struct stv6110x_devctl *ctl; | |
56 | ||
57 | ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, | |
58 | &chan->i2c_adapter); | |
59 | if (ctl == NULL) { | |
60 | printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); | |
61 | return -ENODEV; | |
62 | } | |
63 | ||
64 | feconf->tuner_init = ctl->tuner_init; | |
65 | feconf->tuner_set_mode = ctl->tuner_set_mode; | |
66 | feconf->tuner_set_frequency = ctl->tuner_set_frequency; | |
67 | feconf->tuner_get_frequency = ctl->tuner_get_frequency; | |
68 | feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; | |
69 | feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; | |
70 | feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; | |
71 | feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; | |
72 | feconf->tuner_set_refclk = ctl->tuner_set_refclk; | |
73 | feconf->tuner_get_status = ctl->tuner_get_status; | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | ||
79 | static int demod_attach_stv0900(struct ngene_channel *chan) | |
80 | { | |
81 | struct stv090x_config *feconf = (struct stv090x_config *) | |
82 | chan->dev->card_info->fe_config[chan->number]; | |
83 | ||
84 | chan->fe = dvb_attach(stv090x_attach, | |
85 | feconf, | |
86 | &chan->i2c_adapter, | |
87 | chan->number == 0 ? STV090x_DEMODULATOR_0 : | |
88 | STV090x_DEMODULATOR_1); | |
89 | if (chan->fe == NULL) { | |
90 | printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); | |
91 | return -ENODEV; | |
92 | } | |
93 | ||
94 | if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0, | |
95 | 0, chan->dev->card_info->lnb[chan->number])) { | |
96 | printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); | |
97 | dvb_frontend_detach(chan->fe); | |
98 | return -ENODEV; | |
99 | } | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
104 | static struct lgdt330x_config aver_m780 = { | |
105 | .demod_address = 0xb2 >> 1, | |
106 | .demod_chip = LGDT3303, | |
107 | .serial_mpeg = 0x00, /* PARALLEL */ | |
108 | .clock_polarity_flip = 1, | |
109 | }; | |
110 | ||
111 | static struct mt2131_config m780_tunerconfig = { | |
112 | 0xc0 >> 1 | |
113 | }; | |
114 | ||
115 | /* A single func to attach the demo and tuner, rather than | |
116 | * use two sep funcs like the current design mandates. | |
117 | */ | |
118 | static int demod_attach_lg330x(struct ngene_channel *chan) | |
119 | { | |
120 | chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); | |
121 | if (chan->fe == NULL) { | |
122 | printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); | |
123 | return -ENODEV; | |
124 | } | |
125 | ||
126 | dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, | |
127 | &m780_tunerconfig, 0); | |
128 | ||
129 | return (chan->fe) ? 0 : -ENODEV; | |
130 | } | |
131 | ||
132 | /****************************************************************************/ | |
133 | /* Switch control (I2C gates, etc.) *****************************************/ | |
134 | /****************************************************************************/ | |
135 | ||
136 | ||
137 | static struct stv090x_config fe_cineS2 = { | |
138 | .device = STV0900, | |
139 | .demod_mode = STV090x_DUAL, | |
140 | .clk_mode = STV090x_CLK_EXT, | |
141 | ||
142 | .xtal = 27000000, | |
143 | .address = 0x68, | |
144 | ||
145 | .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, | |
146 | .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, | |
147 | ||
148 | .repeater_level = STV090x_RPTLEVEL_16, | |
149 | ||
150 | .adc1_range = STV090x_ADC_1Vpp, | |
151 | .adc2_range = STV090x_ADC_1Vpp, | |
152 | ||
153 | .diseqc_envelope_mode = true, | |
154 | }; | |
155 | ||
156 | static struct stv6110x_config tuner_cineS2_0 = { | |
157 | .addr = 0x60, | |
158 | .refclk = 27000000, | |
159 | .clk_div = 1, | |
160 | }; | |
161 | ||
162 | static struct stv6110x_config tuner_cineS2_1 = { | |
163 | .addr = 0x63, | |
164 | .refclk = 27000000, | |
165 | .clk_div = 1, | |
166 | }; | |
167 | ||
168 | static struct ngene_info ngene_info_cineS2 = { | |
169 | .type = NGENE_SIDEWINDER, | |
170 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", | |
171 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | |
172 | .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, | |
173 | .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, | |
174 | .fe_config = {&fe_cineS2, &fe_cineS2}, | |
175 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, | |
176 | .lnb = {0x0b, 0x08}, | |
177 | .tsf = {3, 3}, | |
178 | .fw_version = 15, | |
179 | }; | |
180 | ||
181 | static struct ngene_info ngene_info_satixS2 = { | |
182 | .type = NGENE_SIDEWINDER, | |
183 | .name = "Mystique SaTiX-S2 Dual", | |
184 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | |
185 | .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, | |
186 | .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, | |
187 | .fe_config = {&fe_cineS2, &fe_cineS2}, | |
188 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, | |
189 | .lnb = {0x0b, 0x08}, | |
190 | .tsf = {3, 3}, | |
191 | .fw_version = 15, | |
192 | }; | |
193 | ||
194 | static struct ngene_info ngene_info_satixS2v2 = { | |
195 | .type = NGENE_SIDEWINDER, | |
196 | .name = "Mystique SaTiX-S2 Dual (v2)", | |
197 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | |
198 | .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, | |
199 | .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, | |
200 | .fe_config = {&fe_cineS2, &fe_cineS2}, | |
201 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, | |
202 | .lnb = {0x0a, 0x08}, | |
203 | .tsf = {3, 3}, | |
204 | .fw_version = 15, | |
205 | }; | |
206 | ||
207 | static struct ngene_info ngene_info_cineS2v5 = { | |
208 | .type = NGENE_SIDEWINDER, | |
209 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", | |
210 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | |
211 | .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, | |
212 | .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, | |
213 | .fe_config = {&fe_cineS2, &fe_cineS2}, | |
214 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, | |
215 | .lnb = {0x0a, 0x08}, | |
216 | .tsf = {3, 3}, | |
217 | .fw_version = 15, | |
218 | }; | |
219 | ||
220 | static struct ngene_info ngene_info_m780 = { | |
221 | .type = NGENE_APP, | |
222 | .name = "Aver M780 ATSC/QAM-B", | |
223 | ||
224 | /* Channel 0 is analog, which is currently unsupported */ | |
225 | .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, | |
226 | .demod_attach = { NULL, demod_attach_lg330x }, | |
227 | ||
228 | /* Ensure these are NULL else the frame will call them (as funcs) */ | |
229 | .tuner_attach = { 0, 0, 0, 0 }, | |
230 | .fe_config = { NULL, &aver_m780 }, | |
231 | .avf = { 0 }, | |
232 | ||
233 | /* A custom electrical interface config for the demod to bridge */ | |
234 | .tsf = { 4, 4 }, | |
235 | .fw_version = 15, | |
236 | }; | |
237 | ||
238 | /****************************************************************************/ | |
239 | ||
240 | ||
241 | ||
242 | /****************************************************************************/ | |
243 | /* PCI Subsystem ID *********************************************************/ | |
244 | /****************************************************************************/ | |
245 | ||
246 | #define NGENE_ID(_subvend, _subdev, _driverdata) { \ | |
247 | .vendor = NGENE_VID, .device = NGENE_PID, \ | |
248 | .subvendor = _subvend, .subdevice = _subdev, \ | |
249 | .driver_data = (unsigned long) &_driverdata } | |
250 | ||
251 | /****************************************************************************/ | |
252 | ||
253 | static const struct pci_device_id ngene_id_tbl[] __devinitdata = { | |
254 | NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), | |
255 | NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), | |
256 | NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), | |
257 | NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), | |
258 | NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), | |
259 | NGENE_ID(0x1461, 0x062e, ngene_info_m780), | |
260 | {0} | |
261 | }; | |
262 | MODULE_DEVICE_TABLE(pci, ngene_id_tbl); | |
263 | ||
264 | /****************************************************************************/ | |
265 | /* Init/Exit ****************************************************************/ | |
266 | /****************************************************************************/ | |
267 | ||
268 | static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, | |
269 | enum pci_channel_state state) | |
270 | { | |
271 | printk(KERN_ERR DEVICE_NAME ": PCI error\n"); | |
272 | if (state == pci_channel_io_perm_failure) | |
273 | return PCI_ERS_RESULT_DISCONNECT; | |
274 | if (state == pci_channel_io_frozen) | |
275 | return PCI_ERS_RESULT_NEED_RESET; | |
276 | return PCI_ERS_RESULT_CAN_RECOVER; | |
277 | } | |
278 | ||
279 | static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) | |
280 | { | |
281 | printk(KERN_INFO DEVICE_NAME ": link reset\n"); | |
282 | return 0; | |
283 | } | |
284 | ||
285 | static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) | |
286 | { | |
287 | printk(KERN_INFO DEVICE_NAME ": slot reset\n"); | |
288 | return 0; | |
289 | } | |
290 | ||
291 | static void ngene_resume(struct pci_dev *dev) | |
292 | { | |
293 | printk(KERN_INFO DEVICE_NAME ": resume\n"); | |
294 | } | |
295 | ||
296 | static struct pci_error_handlers ngene_errors = { | |
297 | .error_detected = ngene_error_detected, | |
298 | .link_reset = ngene_link_reset, | |
299 | .slot_reset = ngene_slot_reset, | |
300 | .resume = ngene_resume, | |
301 | }; | |
302 | ||
303 | static struct pci_driver ngene_pci_driver = { | |
304 | .name = "ngene", | |
305 | .id_table = ngene_id_tbl, | |
306 | .probe = ngene_probe, | |
307 | .remove = __devexit_p(ngene_remove), | |
308 | .err_handler = &ngene_errors, | |
309 | }; | |
310 | ||
311 | static __init int module_init_ngene(void) | |
312 | { | |
313 | printk(KERN_INFO | |
314 | "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); | |
315 | return pci_register_driver(&ngene_pci_driver); | |
316 | } | |
317 | ||
318 | static __exit void module_exit_ngene(void) | |
319 | { | |
320 | pci_unregister_driver(&ngene_pci_driver); | |
321 | } | |
322 | ||
323 | module_init(module_init_ngene); | |
324 | module_exit(module_exit_ngene); | |
325 | ||
326 | MODULE_DESCRIPTION("nGene"); | |
327 | MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); | |
328 | MODULE_LICENSE("GPL"); |