Commit | Line | Data |
---|---|---|
f5a98f37 AT |
1 | /* |
2 | * Earthsoft PT3 driver | |
3 | * | |
4 | * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation version 2. | |
9 | * | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/freezer.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/kthread.h> | |
20 | #include <linux/mutex.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/pci.h> | |
23 | #include <linux/string.h> | |
24 | ||
25 | #include "dmxdev.h" | |
26 | #include "dvbdev.h" | |
27 | #include "dvb_demux.h" | |
28 | #include "dvb_frontend.h" | |
29 | ||
30 | #include "pt3.h" | |
31 | ||
32 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
33 | ||
34 | static bool one_adapter; | |
35 | module_param(one_adapter, bool, 0444); | |
36 | MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter."); | |
37 | ||
38 | static int num_bufs = 4; | |
39 | module_param(num_bufs, int, 0444); | |
40 | MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE."); | |
41 | ||
42 | ||
43 | static const struct i2c_algorithm pt3_i2c_algo = { | |
44 | .master_xfer = &pt3_i2c_master_xfer, | |
45 | .functionality = &pt3_i2c_functionality, | |
46 | }; | |
47 | ||
48 | static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = { | |
49 | { | |
50 | .demod_info = { | |
51 | I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11), | |
52 | }, | |
53 | .tuner_info = { | |
54 | I2C_BOARD_INFO("qm1d1c0042", 0x63), | |
55 | }, | |
56 | .tuner_cfg.qm1d1c0042 = { | |
57 | .lpf = 1, | |
58 | }, | |
59 | .init_freq = 1049480 - 300, | |
60 | }, | |
61 | { | |
62 | .demod_info = { | |
63 | I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10), | |
64 | }, | |
65 | .tuner_info = { | |
66 | I2C_BOARD_INFO("mxl301rf", 0x62), | |
67 | }, | |
68 | .init_freq = 515142857, | |
69 | }, | |
70 | { | |
71 | .demod_info = { | |
72 | I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13), | |
73 | }, | |
74 | .tuner_info = { | |
75 | I2C_BOARD_INFO("qm1d1c0042", 0x60), | |
76 | }, | |
77 | .tuner_cfg.qm1d1c0042 = { | |
78 | .lpf = 1, | |
79 | }, | |
80 | .init_freq = 1049480 + 300, | |
81 | }, | |
82 | { | |
83 | .demod_info = { | |
84 | I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12), | |
85 | }, | |
86 | .tuner_info = { | |
87 | I2C_BOARD_INFO("mxl301rf", 0x61), | |
88 | }, | |
89 | .init_freq = 521142857, | |
90 | }, | |
91 | }; | |
92 | ||
93 | ||
94 | struct reg_val { | |
95 | u8 reg; | |
96 | u8 val; | |
97 | }; | |
98 | ||
99 | static int | |
100 | pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num) | |
101 | { | |
102 | struct i2c_msg msg; | |
103 | int i, ret; | |
104 | ||
105 | ret = 0; | |
106 | msg.addr = adap->i2c_demod->addr; | |
107 | msg.flags = 0; | |
108 | msg.len = 2; | |
109 | for (i = 0; i < num; i++) { | |
110 | msg.buf = (u8 *)&data[i]; | |
111 | ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1); | |
112 | if (ret == 0) | |
113 | ret = -EREMOTE; | |
114 | if (ret < 0) | |
115 | return ret; | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on) | |
121 | { | |
122 | iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W); | |
123 | } | |
124 | ||
125 | static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe) | |
126 | { | |
127 | struct pt3_board *pt3; | |
128 | int i; | |
129 | ||
130 | if (one_adapter) { | |
131 | pt3 = fe->dvb->priv; | |
132 | for (i = 0; i < PT3_NUM_FE; i++) | |
133 | if (pt3->adaps[i]->fe == fe) | |
134 | return pt3->adaps[i]; | |
135 | } | |
136 | return container_of(fe->dvb, struct pt3_adapter, dvb_adap); | |
137 | } | |
138 | ||
139 | /* | |
140 | * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103). | |
141 | * it seems that they share the power lines and Amp power line and | |
142 | * adaps[3] controls those powers. | |
143 | */ | |
144 | static int | |
145 | pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on) | |
146 | { | |
147 | struct reg_val rv = { 0x1e, 0x99 }; | |
148 | ||
149 | if (tuner_on) | |
150 | rv.val |= 0x40; | |
151 | if (amp_on) | |
152 | rv.val |= 0x04; | |
153 | return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1); | |
154 | } | |
155 | ||
156 | static int pt3_set_lna(struct dvb_frontend *fe) | |
157 | { | |
158 | struct pt3_adapter *adap; | |
159 | struct pt3_board *pt3; | |
160 | u32 val; | |
161 | int ret; | |
162 | ||
163 | /* LNA is shared btw. 2 TERR-tuners */ | |
164 | ||
165 | adap = pt3_find_adapter(fe); | |
166 | val = fe->dtv_property_cache.lna; | |
167 | if (val == LNA_AUTO || val == adap->cur_lna) | |
168 | return 0; | |
169 | ||
170 | pt3 = adap->dvb_adap.priv; | |
171 | if (mutex_lock_interruptible(&pt3->lock)) | |
172 | return -ERESTARTSYS; | |
173 | if (val) | |
174 | pt3->lna_on_cnt++; | |
175 | else | |
176 | pt3->lna_on_cnt--; | |
177 | ||
178 | if (val && pt3->lna_on_cnt <= 1) { | |
179 | pt3->lna_on_cnt = 1; | |
180 | ret = pt3_set_tuner_power(pt3, true, true); | |
181 | } else if (!val && pt3->lna_on_cnt <= 0) { | |
182 | pt3->lna_on_cnt = 0; | |
183 | ret = pt3_set_tuner_power(pt3, true, false); | |
184 | } else | |
185 | ret = 0; | |
186 | mutex_unlock(&pt3->lock); | |
187 | adap->cur_lna = (val != 0); | |
188 | return ret; | |
189 | } | |
190 | ||
0df289a2 | 191 | static int pt3_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) |
f5a98f37 AT |
192 | { |
193 | struct pt3_adapter *adap; | |
194 | struct pt3_board *pt3; | |
195 | bool on; | |
196 | ||
197 | /* LNB power is shared btw. 2 SAT-tuners */ | |
198 | ||
199 | adap = pt3_find_adapter(fe); | |
200 | on = (volt != SEC_VOLTAGE_OFF); | |
201 | if (on == adap->cur_lnb) | |
202 | return 0; | |
203 | adap->cur_lnb = on; | |
204 | pt3 = adap->dvb_adap.priv; | |
205 | if (mutex_lock_interruptible(&pt3->lock)) | |
206 | return -ERESTARTSYS; | |
207 | if (on) | |
208 | pt3->lnb_on_cnt++; | |
209 | else | |
210 | pt3->lnb_on_cnt--; | |
211 | ||
212 | if (on && pt3->lnb_on_cnt <= 1) { | |
213 | pt3->lnb_on_cnt = 1; | |
214 | pt3_lnb_ctrl(pt3, true); | |
215 | } else if (!on && pt3->lnb_on_cnt <= 0) { | |
216 | pt3->lnb_on_cnt = 0; | |
217 | pt3_lnb_ctrl(pt3, false); | |
218 | } | |
219 | mutex_unlock(&pt3->lock); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | /* register values used in pt3_fe_init() */ | |
224 | ||
225 | static const struct reg_val init0_sat[] = { | |
226 | { 0x03, 0x01 }, | |
227 | { 0x1e, 0x10 }, | |
228 | }; | |
229 | static const struct reg_val init0_ter[] = { | |
230 | { 0x01, 0x40 }, | |
231 | { 0x1c, 0x10 }, | |
232 | }; | |
233 | static const struct reg_val cfg_sat[] = { | |
234 | { 0x1c, 0x15 }, | |
235 | { 0x1f, 0x04 }, | |
236 | }; | |
237 | static const struct reg_val cfg_ter[] = { | |
238 | { 0x1d, 0x01 }, | |
239 | }; | |
240 | ||
241 | /* | |
242 | * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once. | |
243 | * | |
244 | * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF), | |
245 | * the i2c sequences for init'ing them are not public and hidden in a ROM, | |
246 | * and include the board specific configurations as well. | |
247 | * They are stored in a lump and cannot be taken out / accessed separately, | |
248 | * thus cannot be moved to the FE/tuner driver. | |
249 | */ | |
250 | static int pt3_fe_init(struct pt3_board *pt3) | |
251 | { | |
252 | int i, ret; | |
253 | struct dvb_frontend *fe; | |
254 | ||
255 | pt3_i2c_reset(pt3); | |
256 | ret = pt3_init_all_demods(pt3); | |
257 | if (ret < 0) { | |
509cd826 | 258 | dev_warn(&pt3->pdev->dev, "Failed to init demod chips\n"); |
f5a98f37 AT |
259 | return ret; |
260 | } | |
261 | ||
262 | /* additional config? */ | |
263 | for (i = 0; i < PT3_NUM_FE; i++) { | |
264 | fe = pt3->adaps[i]->fe; | |
265 | ||
266 | if (fe->ops.delsys[0] == SYS_ISDBS) | |
267 | ret = pt3_demod_write(pt3->adaps[i], | |
268 | init0_sat, ARRAY_SIZE(init0_sat)); | |
269 | else | |
270 | ret = pt3_demod_write(pt3->adaps[i], | |
271 | init0_ter, ARRAY_SIZE(init0_ter)); | |
272 | if (ret < 0) { | |
273 | dev_warn(&pt3->pdev->dev, | |
509cd826 | 274 | "demod[%d] failed in init sequence0\n", i); |
f5a98f37 AT |
275 | return ret; |
276 | } | |
277 | ret = fe->ops.init(fe); | |
278 | if (ret < 0) | |
279 | return ret; | |
280 | } | |
281 | ||
282 | usleep_range(2000, 4000); | |
283 | ret = pt3_set_tuner_power(pt3, true, false); | |
284 | if (ret < 0) { | |
509cd826 | 285 | dev_warn(&pt3->pdev->dev, "Failed to control tuner module\n"); |
f5a98f37 AT |
286 | return ret; |
287 | } | |
288 | ||
289 | /* output pin configuration */ | |
290 | for (i = 0; i < PT3_NUM_FE; i++) { | |
291 | fe = pt3->adaps[i]->fe; | |
292 | if (fe->ops.delsys[0] == SYS_ISDBS) | |
293 | ret = pt3_demod_write(pt3->adaps[i], | |
294 | cfg_sat, ARRAY_SIZE(cfg_sat)); | |
295 | else | |
296 | ret = pt3_demod_write(pt3->adaps[i], | |
297 | cfg_ter, ARRAY_SIZE(cfg_ter)); | |
298 | if (ret < 0) { | |
299 | dev_warn(&pt3->pdev->dev, | |
509cd826 | 300 | "demod[%d] failed in init sequence1\n", i); |
f5a98f37 AT |
301 | return ret; |
302 | } | |
303 | } | |
304 | usleep_range(4000, 6000); | |
305 | ||
306 | for (i = 0; i < PT3_NUM_FE; i++) { | |
307 | fe = pt3->adaps[i]->fe; | |
308 | if (fe->ops.delsys[0] != SYS_ISDBS) | |
309 | continue; | |
310 | /* init and wake-up ISDB-S tuners */ | |
311 | ret = fe->ops.tuner_ops.init(fe); | |
312 | if (ret < 0) { | |
313 | dev_warn(&pt3->pdev->dev, | |
509cd826 | 314 | "Failed to init SAT-tuner[%d]\n", i); |
f5a98f37 AT |
315 | return ret; |
316 | } | |
317 | } | |
318 | ret = pt3_init_all_mxl301rf(pt3); | |
319 | if (ret < 0) { | |
509cd826 | 320 | dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners\n"); |
f5a98f37 AT |
321 | return ret; |
322 | } | |
323 | ||
324 | ret = pt3_set_tuner_power(pt3, true, true); | |
325 | if (ret < 0) { | |
509cd826 | 326 | dev_warn(&pt3->pdev->dev, "Failed to control tuner module\n"); |
f5a98f37 AT |
327 | return ret; |
328 | } | |
329 | ||
330 | /* Wake up all tuners and make an initial tuning, | |
331 | * in order to avoid interference among the tuners in the module, | |
332 | * according to the doc from the manufacturer. | |
333 | */ | |
334 | for (i = 0; i < PT3_NUM_FE; i++) { | |
335 | fe = pt3->adaps[i]->fe; | |
336 | ret = 0; | |
337 | if (fe->ops.delsys[0] == SYS_ISDBT) | |
338 | ret = fe->ops.tuner_ops.init(fe); | |
339 | /* set only when called from pt3_probe(), not resume() */ | |
340 | if (ret == 0 && fe->dtv_property_cache.frequency == 0) { | |
341 | fe->dtv_property_cache.frequency = | |
342 | adap_conf[i].init_freq; | |
343 | ret = fe->ops.tuner_ops.set_params(fe); | |
344 | } | |
345 | if (ret < 0) { | |
346 | dev_warn(&pt3->pdev->dev, | |
509cd826 | 347 | "Failed in initial tuning of tuner[%d]\n", i); |
f5a98f37 AT |
348 | return ret; |
349 | } | |
350 | } | |
351 | ||
352 | /* and sleep again, waiting to be opened by users. */ | |
353 | for (i = 0; i < PT3_NUM_FE; i++) { | |
354 | fe = pt3->adaps[i]->fe; | |
355 | if (fe->ops.tuner_ops.sleep) | |
356 | ret = fe->ops.tuner_ops.sleep(fe); | |
357 | if (ret < 0) | |
358 | break; | |
359 | if (fe->ops.sleep) | |
360 | ret = fe->ops.sleep(fe); | |
361 | if (ret < 0) | |
362 | break; | |
363 | if (fe->ops.delsys[0] == SYS_ISDBS) | |
364 | fe->ops.set_voltage = &pt3_set_voltage; | |
365 | else | |
366 | fe->ops.set_lna = &pt3_set_lna; | |
367 | } | |
368 | if (i < PT3_NUM_FE) { | |
509cd826 | 369 | dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby\n", i); |
f5a98f37 AT |
370 | return ret; |
371 | } | |
372 | return 0; | |
373 | } | |
374 | ||
375 | ||
376 | static int pt3_attach_fe(struct pt3_board *pt3, int i) | |
377 | { | |
378 | struct i2c_board_info info; | |
379 | struct tc90522_config cfg; | |
380 | struct i2c_client *cl; | |
381 | struct dvb_adapter *dvb_adap; | |
382 | int ret; | |
383 | ||
384 | info = adap_conf[i].demod_info; | |
385 | cfg = adap_conf[i].demod_cfg; | |
386 | cfg.tuner_i2c = NULL; | |
387 | info.platform_data = &cfg; | |
388 | ||
389 | ret = -ENODEV; | |
390 | request_module("tc90522"); | |
391 | cl = i2c_new_device(&pt3->i2c_adap, &info); | |
392 | if (!cl || !cl->dev.driver) | |
393 | return -ENODEV; | |
394 | pt3->adaps[i]->i2c_demod = cl; | |
395 | if (!try_module_get(cl->dev.driver->owner)) | |
cf3167cf | 396 | goto err_demod_i2c_unregister_device; |
f5a98f37 | 397 | |
55a1a9f1 MCC |
398 | if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, |
399 | strlen(TC90522_I2C_DEV_SAT))) { | |
f5a98f37 AT |
400 | struct qm1d1c0042_config tcfg; |
401 | ||
402 | tcfg = adap_conf[i].tuner_cfg.qm1d1c0042; | |
403 | tcfg.fe = cfg.fe; | |
404 | info = adap_conf[i].tuner_info; | |
405 | info.platform_data = &tcfg; | |
406 | request_module("qm1d1c0042"); | |
407 | cl = i2c_new_device(cfg.tuner_i2c, &info); | |
408 | } else { | |
409 | struct mxl301rf_config tcfg; | |
410 | ||
411 | tcfg = adap_conf[i].tuner_cfg.mxl301rf; | |
412 | tcfg.fe = cfg.fe; | |
413 | info = adap_conf[i].tuner_info; | |
414 | info.platform_data = &tcfg; | |
415 | request_module("mxl301rf"); | |
416 | cl = i2c_new_device(cfg.tuner_i2c, &info); | |
417 | } | |
418 | if (!cl || !cl->dev.driver) | |
cf3167cf | 419 | goto err_demod_module_put; |
f5a98f37 AT |
420 | pt3->adaps[i]->i2c_tuner = cl; |
421 | if (!try_module_get(cl->dev.driver->owner)) | |
cf3167cf | 422 | goto err_tuner_i2c_unregister_device; |
f5a98f37 AT |
423 | |
424 | dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; | |
425 | ret = dvb_register_frontend(dvb_adap, cfg.fe); | |
426 | if (ret < 0) | |
cf3167cf | 427 | goto err_tuner_module_put; |
f5a98f37 AT |
428 | pt3->adaps[i]->fe = cfg.fe; |
429 | return 0; | |
430 | ||
cf3167cf AP |
431 | err_tuner_module_put: |
432 | module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); | |
433 | err_tuner_i2c_unregister_device: | |
f5a98f37 | 434 | i2c_unregister_device(pt3->adaps[i]->i2c_tuner); |
cf3167cf AP |
435 | err_demod_module_put: |
436 | module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); | |
437 | err_demod_i2c_unregister_device: | |
f5a98f37 | 438 | i2c_unregister_device(pt3->adaps[i]->i2c_demod); |
cf3167cf | 439 | |
f5a98f37 AT |
440 | return ret; |
441 | } | |
442 | ||
443 | ||
444 | static int pt3_fetch_thread(void *data) | |
445 | { | |
446 | struct pt3_adapter *adap = data; | |
447 | ktime_t delay; | |
448 | bool was_frozen; | |
449 | ||
450 | #define PT3_INITIAL_BUF_DROPS 4 | |
451 | #define PT3_FETCH_DELAY 10 | |
452 | #define PT3_FETCH_DELAY_DELTA 2 | |
453 | ||
454 | pt3_init_dmabuf(adap); | |
455 | adap->num_discard = PT3_INITIAL_BUF_DROPS; | |
456 | ||
509cd826 JP |
457 | dev_dbg(adap->dvb_adap.device, "PT3: [%s] started\n", |
458 | adap->thread->comm); | |
f5a98f37 AT |
459 | set_freezable(); |
460 | while (!kthread_freezable_should_stop(&was_frozen)) { | |
461 | if (was_frozen) | |
462 | adap->num_discard = PT3_INITIAL_BUF_DROPS; | |
463 | ||
464 | pt3_proc_dma(adap); | |
465 | ||
466 | delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC); | |
467 | set_current_state(TASK_UNINTERRUPTIBLE); | |
468 | freezable_schedule_hrtimeout_range(&delay, | |
469 | PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC, | |
470 | HRTIMER_MODE_REL); | |
471 | } | |
509cd826 JP |
472 | dev_dbg(adap->dvb_adap.device, "PT3: [%s] exited\n", |
473 | adap->thread->comm); | |
f5a98f37 AT |
474 | adap->thread = NULL; |
475 | return 0; | |
476 | } | |
477 | ||
478 | static int pt3_start_streaming(struct pt3_adapter *adap) | |
479 | { | |
480 | struct task_struct *thread; | |
481 | ||
482 | /* start fetching thread */ | |
483 | thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i", | |
484 | adap->dvb_adap.num, adap->dmxdev.dvbdev->id); | |
485 | if (IS_ERR(thread)) { | |
486 | int ret = PTR_ERR(thread); | |
487 | ||
488 | dev_warn(adap->dvb_adap.device, | |
509cd826 JP |
489 | "PT3 (adap:%d, dmx:%d): failed to start kthread\n", |
490 | adap->dvb_adap.num, adap->dmxdev.dvbdev->id); | |
f5a98f37 AT |
491 | return ret; |
492 | } | |
493 | adap->thread = thread; | |
494 | ||
495 | return pt3_start_dma(adap); | |
496 | } | |
497 | ||
498 | static int pt3_stop_streaming(struct pt3_adapter *adap) | |
499 | { | |
500 | int ret; | |
501 | ||
502 | ret = pt3_stop_dma(adap); | |
503 | if (ret) | |
504 | dev_warn(adap->dvb_adap.device, | |
509cd826 JP |
505 | "PT3: failed to stop streaming of adap:%d/FE:%d\n", |
506 | adap->dvb_adap.num, adap->fe->id); | |
f5a98f37 AT |
507 | |
508 | /* kill the fetching thread */ | |
509 | ret = kthread_stop(adap->thread); | |
510 | return ret; | |
511 | } | |
512 | ||
513 | static int pt3_start_feed(struct dvb_demux_feed *feed) | |
514 | { | |
515 | struct pt3_adapter *adap; | |
516 | ||
517 | if (signal_pending(current)) | |
518 | return -EINTR; | |
519 | ||
520 | adap = container_of(feed->demux, struct pt3_adapter, demux); | |
521 | adap->num_feeds++; | |
522 | if (adap->thread) | |
523 | return 0; | |
524 | if (adap->num_feeds != 1) { | |
525 | dev_warn(adap->dvb_adap.device, | |
509cd826 JP |
526 | "%s: unmatched start/stop_feed in adap:%i/dmx:%i\n", |
527 | __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id); | |
f5a98f37 AT |
528 | adap->num_feeds = 1; |
529 | } | |
530 | ||
531 | return pt3_start_streaming(adap); | |
532 | ||
533 | } | |
534 | ||
535 | static int pt3_stop_feed(struct dvb_demux_feed *feed) | |
536 | { | |
537 | struct pt3_adapter *adap; | |
538 | ||
539 | adap = container_of(feed->demux, struct pt3_adapter, demux); | |
540 | ||
541 | adap->num_feeds--; | |
542 | if (adap->num_feeds > 0 || !adap->thread) | |
543 | return 0; | |
544 | adap->num_feeds = 0; | |
545 | ||
546 | return pt3_stop_streaming(adap); | |
547 | } | |
548 | ||
549 | ||
550 | static int pt3_alloc_adapter(struct pt3_board *pt3, int index) | |
551 | { | |
552 | int ret; | |
553 | struct pt3_adapter *adap; | |
554 | struct dvb_adapter *da; | |
555 | ||
556 | adap = kzalloc(sizeof(*adap), GFP_KERNEL); | |
509cd826 | 557 | if (!adap) |
f5a98f37 | 558 | return -ENOMEM; |
509cd826 | 559 | |
f5a98f37 AT |
560 | pt3->adaps[index] = adap; |
561 | adap->adap_idx = index; | |
562 | ||
563 | if (index == 0 || !one_adapter) { | |
564 | ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB", | |
565 | THIS_MODULE, &pt3->pdev->dev, adapter_nr); | |
566 | if (ret < 0) { | |
567 | dev_err(&pt3->pdev->dev, | |
509cd826 | 568 | "failed to register adapter dev\n"); |
f5a98f37 AT |
569 | goto err_mem; |
570 | } | |
571 | da = &adap->dvb_adap; | |
572 | } else | |
573 | da = &pt3->adaps[0]->dvb_adap; | |
574 | ||
575 | adap->dvb_adap.priv = pt3; | |
576 | adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; | |
577 | adap->demux.priv = adap; | |
578 | adap->demux.feednum = 256; | |
579 | adap->demux.filternum = 256; | |
580 | adap->demux.start_feed = pt3_start_feed; | |
581 | adap->demux.stop_feed = pt3_stop_feed; | |
582 | ret = dvb_dmx_init(&adap->demux); | |
583 | if (ret < 0) { | |
509cd826 | 584 | dev_err(&pt3->pdev->dev, "failed to init dmx dev\n"); |
f5a98f37 AT |
585 | goto err_adap; |
586 | } | |
587 | ||
588 | adap->dmxdev.filternum = 256; | |
589 | adap->dmxdev.demux = &adap->demux.dmx; | |
590 | ret = dvb_dmxdev_init(&adap->dmxdev, da); | |
591 | if (ret < 0) { | |
509cd826 | 592 | dev_err(&pt3->pdev->dev, "failed to init dmxdev\n"); |
f5a98f37 AT |
593 | goto err_demux; |
594 | } | |
595 | ||
596 | ret = pt3_alloc_dmabuf(adap); | |
597 | if (ret) { | |
509cd826 | 598 | dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers\n"); |
f5a98f37 AT |
599 | goto err_dmabuf; |
600 | } | |
601 | ||
602 | return 0; | |
603 | ||
604 | err_dmabuf: | |
605 | pt3_free_dmabuf(adap); | |
606 | dvb_dmxdev_release(&adap->dmxdev); | |
607 | err_demux: | |
608 | dvb_dmx_release(&adap->demux); | |
609 | err_adap: | |
610 | if (index == 0 || !one_adapter) | |
611 | dvb_unregister_adapter(da); | |
612 | err_mem: | |
613 | kfree(adap); | |
614 | pt3->adaps[index] = NULL; | |
615 | return ret; | |
616 | } | |
617 | ||
618 | static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) | |
619 | { | |
620 | struct pt3_adapter *adap; | |
621 | struct dmx_demux *dmx; | |
622 | ||
623 | adap = pt3->adaps[index]; | |
624 | if (adap == NULL) | |
625 | return; | |
626 | ||
627 | /* stop demux kthread */ | |
628 | if (adap->thread) | |
629 | pt3_stop_streaming(adap); | |
630 | ||
631 | dmx = &adap->demux.dmx; | |
632 | dmx->close(dmx); | |
633 | if (adap->fe) { | |
634 | adap->fe->callback = NULL; | |
635 | if (adap->fe->frontend_priv) | |
636 | dvb_unregister_frontend(adap->fe); | |
637 | if (adap->i2c_tuner) { | |
638 | module_put(adap->i2c_tuner->dev.driver->owner); | |
639 | i2c_unregister_device(adap->i2c_tuner); | |
640 | } | |
641 | if (adap->i2c_demod) { | |
642 | module_put(adap->i2c_demod->dev.driver->owner); | |
643 | i2c_unregister_device(adap->i2c_demod); | |
644 | } | |
645 | } | |
646 | pt3_free_dmabuf(adap); | |
647 | dvb_dmxdev_release(&adap->dmxdev); | |
648 | dvb_dmx_release(&adap->demux); | |
649 | if (index == 0 || !one_adapter) | |
650 | dvb_unregister_adapter(&adap->dvb_adap); | |
651 | kfree(adap); | |
652 | pt3->adaps[index] = NULL; | |
653 | } | |
654 | ||
655 | #ifdef CONFIG_PM_SLEEP | |
656 | ||
657 | static int pt3_suspend(struct device *dev) | |
658 | { | |
659 | struct pci_dev *pdev = to_pci_dev(dev); | |
660 | struct pt3_board *pt3 = pci_get_drvdata(pdev); | |
661 | int i; | |
662 | struct pt3_adapter *adap; | |
663 | ||
664 | for (i = 0; i < PT3_NUM_FE; i++) { | |
665 | adap = pt3->adaps[i]; | |
666 | if (adap->num_feeds > 0) | |
667 | pt3_stop_dma(adap); | |
668 | dvb_frontend_suspend(adap->fe); | |
669 | pt3_free_dmabuf(adap); | |
670 | } | |
671 | ||
672 | pt3_lnb_ctrl(pt3, false); | |
673 | pt3_set_tuner_power(pt3, false, false); | |
674 | return 0; | |
675 | } | |
676 | ||
677 | static int pt3_resume(struct device *dev) | |
678 | { | |
679 | struct pci_dev *pdev = to_pci_dev(dev); | |
680 | struct pt3_board *pt3 = pci_get_drvdata(pdev); | |
681 | int i, ret; | |
682 | struct pt3_adapter *adap; | |
683 | ||
684 | ret = pt3_fe_init(pt3); | |
685 | if (ret) | |
686 | return ret; | |
687 | ||
688 | if (pt3->lna_on_cnt > 0) | |
689 | pt3_set_tuner_power(pt3, true, true); | |
690 | if (pt3->lnb_on_cnt > 0) | |
691 | pt3_lnb_ctrl(pt3, true); | |
692 | ||
693 | for (i = 0; i < PT3_NUM_FE; i++) { | |
694 | adap = pt3->adaps[i]; | |
695 | dvb_frontend_resume(adap->fe); | |
696 | ret = pt3_alloc_dmabuf(adap); | |
697 | if (ret) { | |
509cd826 | 698 | dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs\n"); |
f5a98f37 AT |
699 | continue; |
700 | } | |
701 | if (adap->num_feeds > 0) | |
702 | pt3_start_dma(adap); | |
703 | } | |
704 | ||
705 | return 0; | |
706 | } | |
707 | ||
708 | #endif /* CONFIG_PM_SLEEP */ | |
709 | ||
710 | ||
711 | static void pt3_remove(struct pci_dev *pdev) | |
712 | { | |
713 | struct pt3_board *pt3; | |
714 | int i; | |
715 | ||
716 | pt3 = pci_get_drvdata(pdev); | |
717 | for (i = PT3_NUM_FE - 1; i >= 0; i--) | |
718 | pt3_cleanup_adapter(pt3, i); | |
719 | i2c_del_adapter(&pt3->i2c_adap); | |
720 | kfree(pt3->i2c_buf); | |
721 | pci_iounmap(pt3->pdev, pt3->regs[0]); | |
722 | pci_iounmap(pt3->pdev, pt3->regs[1]); | |
723 | pci_release_regions(pdev); | |
724 | pci_disable_device(pdev); | |
725 | kfree(pt3); | |
726 | } | |
727 | ||
728 | static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
729 | { | |
730 | u8 rev; | |
731 | u32 ver; | |
732 | int i, ret; | |
733 | struct pt3_board *pt3; | |
734 | struct i2c_adapter *i2c; | |
735 | ||
736 | if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1) | |
737 | return -ENODEV; | |
738 | ||
739 | ret = pci_enable_device(pdev); | |
740 | if (ret < 0) | |
741 | return -ENODEV; | |
742 | pci_set_master(pdev); | |
743 | ||
744 | ret = pci_request_regions(pdev, DRV_NAME); | |
745 | if (ret < 0) | |
746 | goto err_disable_device; | |
747 | ||
748 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); | |
749 | if (ret == 0) | |
750 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); | |
751 | else { | |
752 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); | |
753 | if (ret == 0) | |
754 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | |
755 | else { | |
509cd826 | 756 | dev_err(&pdev->dev, "Failed to set DMA mask\n"); |
f5a98f37 AT |
757 | goto err_release_regions; |
758 | } | |
509cd826 | 759 | dev_info(&pdev->dev, "Use 32bit DMA\n"); |
f5a98f37 AT |
760 | } |
761 | ||
762 | pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL); | |
763 | if (!pt3) { | |
f5a98f37 AT |
764 | ret = -ENOMEM; |
765 | goto err_release_regions; | |
766 | } | |
767 | pci_set_drvdata(pdev, pt3); | |
768 | pt3->pdev = pdev; | |
769 | mutex_init(&pt3->lock); | |
770 | pt3->regs[0] = pci_ioremap_bar(pdev, 0); | |
771 | pt3->regs[1] = pci_ioremap_bar(pdev, 2); | |
772 | if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) { | |
509cd826 | 773 | dev_err(&pdev->dev, "Failed to ioremap\n"); |
f5a98f37 AT |
774 | ret = -ENOMEM; |
775 | goto err_kfree; | |
776 | } | |
777 | ||
778 | ver = ioread32(pt3->regs[0] + REG_VERSION); | |
779 | if ((ver >> 16) != 0x0301) { | |
509cd826 JP |
780 | dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported\n", |
781 | ver >> 24, (ver & 0x00ff0000) >> 16); | |
f5a98f37 AT |
782 | ret = -ENODEV; |
783 | goto err_iounmap; | |
784 | } | |
785 | ||
786 | pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS); | |
787 | ||
788 | pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL); | |
789 | if (pt3->i2c_buf == NULL) { | |
f5a98f37 AT |
790 | ret = -ENOMEM; |
791 | goto err_iounmap; | |
792 | } | |
793 | i2c = &pt3->i2c_adap; | |
794 | i2c->owner = THIS_MODULE; | |
795 | i2c->algo = &pt3_i2c_algo; | |
796 | i2c->algo_data = NULL; | |
797 | i2c->dev.parent = &pdev->dev; | |
798 | strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name)); | |
799 | i2c_set_adapdata(i2c, pt3); | |
800 | ret = i2c_add_adapter(i2c); | |
b325c98b | 801 | if (ret < 0) |
f5a98f37 | 802 | goto err_i2cbuf; |
f5a98f37 AT |
803 | |
804 | for (i = 0; i < PT3_NUM_FE; i++) { | |
805 | ret = pt3_alloc_adapter(pt3, i); | |
806 | if (ret < 0) | |
807 | break; | |
808 | ||
809 | ret = pt3_attach_fe(pt3, i); | |
810 | if (ret < 0) | |
811 | break; | |
812 | } | |
813 | if (i < PT3_NUM_FE) { | |
509cd826 | 814 | dev_err(&pdev->dev, "Failed to create FE%d\n", i); |
f5a98f37 AT |
815 | goto err_cleanup_adapters; |
816 | } | |
817 | ||
818 | ret = pt3_fe_init(pt3); | |
819 | if (ret < 0) { | |
509cd826 | 820 | dev_err(&pdev->dev, "Failed to init frontends\n"); |
f5a98f37 AT |
821 | i = PT3_NUM_FE - 1; |
822 | goto err_cleanup_adapters; | |
823 | } | |
824 | ||
825 | dev_info(&pdev->dev, | |
509cd826 JP |
826 | "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x)\n", |
827 | ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff); | |
f5a98f37 AT |
828 | return 0; |
829 | ||
830 | err_cleanup_adapters: | |
831 | while (i >= 0) | |
832 | pt3_cleanup_adapter(pt3, i--); | |
833 | i2c_del_adapter(i2c); | |
834 | err_i2cbuf: | |
835 | kfree(pt3->i2c_buf); | |
836 | err_iounmap: | |
837 | if (pt3->regs[0]) | |
838 | pci_iounmap(pdev, pt3->regs[0]); | |
839 | if (pt3->regs[1]) | |
840 | pci_iounmap(pdev, pt3->regs[1]); | |
841 | err_kfree: | |
842 | kfree(pt3); | |
843 | err_release_regions: | |
844 | pci_release_regions(pdev); | |
845 | err_disable_device: | |
846 | pci_disable_device(pdev); | |
847 | return ret; | |
848 | ||
849 | } | |
850 | ||
851 | static const struct pci_device_id pt3_id_table[] = { | |
852 | { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) }, | |
853 | { }, | |
854 | }; | |
855 | MODULE_DEVICE_TABLE(pci, pt3_id_table); | |
856 | ||
49310ed0 | 857 | static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); |
f5a98f37 AT |
858 | |
859 | static struct pci_driver pt3_driver = { | |
860 | .name = DRV_NAME, | |
861 | .probe = pt3_probe, | |
862 | .remove = pt3_remove, | |
863 | .id_table = pt3_id_table, | |
864 | ||
865 | .driver.pm = &pt3_pm_ops, | |
866 | }; | |
867 | ||
868 | module_pci_driver(pt3_driver); | |
869 | ||
870 | MODULE_DESCRIPTION("Earthsoft PT3 Driver"); | |
871 | MODULE_AUTHOR("Akihiro TSUKADA"); | |
872 | MODULE_LICENSE("GPL"); |