Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
3d17fb1b | 2 | /* |
4d1f413e | 3 | * driver for Earthsoft PT1/PT2 |
3d17fb1b MCC |
4 | * |
5 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | |
6 | * | |
7 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | |
4a3fad70 | 8 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> |
3d17fb1b MCC |
9 | */ |
10 | ||
11 | #include <linux/kernel.h> | |
20a63349 | 12 | #include <linux/sched.h> |
174cd4b1 | 13 | #include <linux/sched/signal.h> |
20a63349 AT |
14 | #include <linux/hrtimer.h> |
15 | #include <linux/delay.h> | |
3d17fb1b | 16 | #include <linux/module.h> |
5a0e3ad6 | 17 | #include <linux/slab.h> |
2a20b05f | 18 | #include <linux/vmalloc.h> |
3d17fb1b MCC |
19 | #include <linux/pci.h> |
20 | #include <linux/kthread.h> | |
21 | #include <linux/freezer.h> | |
69881110 | 22 | #include <linux/ratelimit.h> |
b732539e AT |
23 | #include <linux/string.h> |
24 | #include <linux/i2c.h> | |
3d17fb1b | 25 | |
fada1935 MCC |
26 | #include <media/dvbdev.h> |
27 | #include <media/dvb_demux.h> | |
28 | #include <media/dmxdev.h> | |
29 | #include <media/dvb_net.h> | |
30 | #include <media/dvb_frontend.h> | |
3d17fb1b | 31 | |
b732539e AT |
32 | #include "tc90522.h" |
33 | #include "qm1d1b0004.h" | |
34 | #include "dvb-pll.h" | |
3d17fb1b MCC |
35 | |
36 | #define DRIVER_NAME "earth-pt1" | |
37 | ||
38 | #define PT1_PAGE_SHIFT 12 | |
39 | #define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT) | |
40 | #define PT1_NR_UPACKETS 1024 | |
41 | #define PT1_NR_BUFS 511 | |
42 | ||
43 | struct pt1_buffer_page { | |
44 | __le32 upackets[PT1_NR_UPACKETS]; | |
45 | }; | |
46 | ||
47 | struct pt1_table_page { | |
48 | __le32 next_pfn; | |
49 | __le32 buf_pfns[PT1_NR_BUFS]; | |
50 | }; | |
51 | ||
52 | struct pt1_buffer { | |
53 | struct pt1_buffer_page *page; | |
54 | dma_addr_t addr; | |
55 | }; | |
56 | ||
57 | struct pt1_table { | |
58 | struct pt1_table_page *page; | |
59 | dma_addr_t addr; | |
60 | struct pt1_buffer bufs[PT1_NR_BUFS]; | |
61 | }; | |
62 | ||
b732539e AT |
63 | enum pt1_fe_clk { |
64 | PT1_FE_CLK_20MHZ, /* PT1 */ | |
65 | PT1_FE_CLK_25MHZ, /* PT2 */ | |
66 | }; | |
67 | ||
3d17fb1b MCC |
68 | #define PT1_NR_ADAPS 4 |
69 | ||
70 | struct pt1_adapter; | |
71 | ||
72 | struct pt1 { | |
73 | struct pci_dev *pdev; | |
74 | void __iomem *regs; | |
75 | struct i2c_adapter i2c_adap; | |
76 | int i2c_running; | |
77 | struct pt1_adapter *adaps[PT1_NR_ADAPS]; | |
78 | struct pt1_table *tables; | |
79 | struct task_struct *kthread; | |
847e8765 AT |
80 | int table_index; |
81 | int buf_index; | |
4d1f413e HT |
82 | |
83 | struct mutex lock; | |
84 | int power; | |
85 | int reset; | |
b732539e AT |
86 | |
87 | enum pt1_fe_clk fe_clk; | |
3d17fb1b MCC |
88 | }; |
89 | ||
90 | struct pt1_adapter { | |
91 | struct pt1 *pt1; | |
92 | int index; | |
93 | ||
94 | u8 *buf; | |
95 | int upacket_count; | |
96 | int packet_count; | |
69881110 | 97 | int st_count; |
3d17fb1b MCC |
98 | |
99 | struct dvb_adapter adap; | |
100 | struct dvb_demux demux; | |
101 | int users; | |
102 | struct dmxdev dmxdev; | |
3d17fb1b | 103 | struct dvb_frontend *fe; |
b732539e AT |
104 | struct i2c_client *demod_i2c_client; |
105 | struct i2c_client *tuner_i2c_client; | |
3d17fb1b | 106 | int (*orig_set_voltage)(struct dvb_frontend *fe, |
0df289a2 | 107 | enum fe_sec_voltage voltage); |
4d1f413e HT |
108 | int (*orig_sleep)(struct dvb_frontend *fe); |
109 | int (*orig_init)(struct dvb_frontend *fe); | |
110 | ||
0df289a2 | 111 | enum fe_sec_voltage voltage; |
4d1f413e | 112 | int sleep; |
3d17fb1b MCC |
113 | }; |
114 | ||
b732539e AT |
115 | union pt1_tuner_config { |
116 | struct qm1d1b0004_config qm1d1b0004; | |
117 | struct dvb_pll_config tda6651; | |
118 | }; | |
119 | ||
120 | struct pt1_config { | |
121 | struct i2c_board_info demod_info; | |
122 | struct tc90522_config demod_cfg; | |
123 | ||
124 | struct i2c_board_info tuner_info; | |
125 | union pt1_tuner_config tuner_cfg; | |
126 | }; | |
127 | ||
128 | static const struct pt1_config pt1_configs[PT1_NR_ADAPS] = { | |
129 | { | |
130 | .demod_info = { | |
131 | I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x1b), | |
132 | }, | |
133 | .tuner_info = { | |
134 | I2C_BOARD_INFO("qm1d1b0004", 0x60), | |
135 | }, | |
136 | }, | |
137 | { | |
138 | .demod_info = { | |
139 | I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x1a), | |
140 | }, | |
141 | .tuner_info = { | |
142 | I2C_BOARD_INFO("tda665x_earthpt1", 0x61), | |
143 | }, | |
144 | }, | |
145 | { | |
146 | .demod_info = { | |
147 | I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x19), | |
148 | }, | |
149 | .tuner_info = { | |
150 | I2C_BOARD_INFO("qm1d1b0004", 0x60), | |
151 | }, | |
152 | }, | |
153 | { | |
154 | .demod_info = { | |
155 | I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18), | |
156 | }, | |
157 | .tuner_info = { | |
158 | I2C_BOARD_INFO("tda665x_earthpt1", 0x61), | |
159 | }, | |
160 | }, | |
161 | }; | |
162 | ||
163 | static const u8 va1j5jf8007s_20mhz_configs[][2] = { | |
164 | {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, | |
165 | {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, | |
166 | {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, | |
167 | {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
168 | }; | |
169 | ||
170 | static const u8 va1j5jf8007s_25mhz_configs[][2] = { | |
171 | {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, | |
172 | {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, | |
173 | {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, | |
174 | {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, | |
175 | }; | |
176 | ||
177 | static const u8 va1j5jf8007t_20mhz_configs[][2] = { | |
178 | {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, | |
179 | {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, | |
180 | {0x3b, 0x11}, {0x3c, 0x3f}, | |
181 | {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, | |
182 | {0xef, 0x01} | |
183 | }; | |
184 | ||
185 | static const u8 va1j5jf8007t_25mhz_configs[][2] = { | |
186 | {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, | |
187 | {0x3a, 0x04}, {0x3b, 0x11}, {0x3c, 0x3f}, {0x5c, 0x40}, {0x5f, 0x80}, | |
188 | {0x75, 0x0a}, {0x76, 0x4c}, {0x77, 0x03}, {0xef, 0x01} | |
189 | }; | |
190 | ||
191 | static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk) | |
192 | { | |
193 | int ret; | |
b732539e AT |
194 | bool is_sat; |
195 | const u8 (*cfg_data)[2]; | |
196 | int i, len; | |
197 | ||
5ebaf328 MCC |
198 | is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT, |
199 | strlen(TC90522_I2C_DEV_SAT)); | |
b732539e AT |
200 | if (is_sat) { |
201 | struct i2c_msg msg[2]; | |
202 | u8 wbuf, rbuf; | |
203 | ||
204 | wbuf = 0x07; | |
205 | msg[0].addr = cl->addr; | |
206 | msg[0].flags = 0; | |
207 | msg[0].len = 1; | |
208 | msg[0].buf = &wbuf; | |
209 | ||
210 | msg[1].addr = cl->addr; | |
211 | msg[1].flags = I2C_M_RD; | |
212 | msg[1].len = 1; | |
213 | msg[1].buf = &rbuf; | |
214 | ret = i2c_transfer(cl->adapter, msg, 2); | |
215 | if (ret < 0) | |
216 | return ret; | |
217 | if (rbuf != 0x41) | |
218 | return -EIO; | |
219 | } | |
220 | ||
221 | /* frontend init */ | |
222 | if (clk == PT1_FE_CLK_20MHZ) { | |
223 | if (is_sat) { | |
224 | cfg_data = va1j5jf8007s_20mhz_configs; | |
225 | len = ARRAY_SIZE(va1j5jf8007s_20mhz_configs); | |
226 | } else { | |
227 | cfg_data = va1j5jf8007t_20mhz_configs; | |
228 | len = ARRAY_SIZE(va1j5jf8007t_20mhz_configs); | |
229 | } | |
230 | } else { | |
231 | if (is_sat) { | |
232 | cfg_data = va1j5jf8007s_25mhz_configs; | |
233 | len = ARRAY_SIZE(va1j5jf8007s_25mhz_configs); | |
234 | } else { | |
235 | cfg_data = va1j5jf8007t_25mhz_configs; | |
236 | len = ARRAY_SIZE(va1j5jf8007t_25mhz_configs); | |
237 | } | |
238 | } | |
239 | ||
240 | for (i = 0; i < len; i++) { | |
241 | ret = i2c_master_send(cl, cfg_data[i], 2); | |
242 | if (ret < 0) | |
243 | return ret; | |
244 | } | |
245 | return 0; | |
246 | } | |
247 | ||
15d90a6a AT |
248 | /* |
249 | * Init registers for (each pair of) terrestrial/satellite block in demod. | |
250 | * Note that resetting terr. block also resets its peer sat. block as well. | |
251 | * This function must be called before configuring any demod block | |
252 | * (before pt1_wakeup(), fe->ops.init()). | |
253 | */ | |
254 | static int pt1_demod_block_init(struct pt1 *pt1) | |
255 | { | |
256 | struct i2c_client *cl; | |
257 | u8 buf[2] = {0x01, 0x80}; | |
258 | int ret; | |
259 | int i; | |
260 | ||
261 | /* reset all terr. & sat. pairs first */ | |
262 | for (i = 0; i < PT1_NR_ADAPS; i++) { | |
263 | cl = pt1->adaps[i]->demod_i2c_client; | |
264 | if (strncmp(cl->name, TC90522_I2C_DEV_TER, | |
265 | strlen(TC90522_I2C_DEV_TER))) | |
266 | continue; | |
267 | ||
268 | ret = i2c_master_send(cl, buf, 2); | |
269 | if (ret < 0) | |
270 | return ret; | |
271 | usleep_range(30000, 50000); | |
272 | } | |
273 | ||
274 | for (i = 0; i < PT1_NR_ADAPS; i++) { | |
275 | cl = pt1->adaps[i]->demod_i2c_client; | |
276 | if (strncmp(cl->name, TC90522_I2C_DEV_SAT, | |
277 | strlen(TC90522_I2C_DEV_SAT))) | |
278 | continue; | |
279 | ||
280 | ret = i2c_master_send(cl, buf, 2); | |
281 | if (ret < 0) | |
282 | return ret; | |
283 | usleep_range(30000, 50000); | |
284 | } | |
285 | return 0; | |
286 | } | |
287 | ||
3d17fb1b MCC |
288 | static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) |
289 | { | |
290 | writel(data, pt1->regs + reg * 4); | |
291 | } | |
292 | ||
293 | static u32 pt1_read_reg(struct pt1 *pt1, int reg) | |
294 | { | |
295 | return readl(pt1->regs + reg * 4); | |
296 | } | |
297 | ||
e639c869 MCC |
298 | static unsigned int pt1_nr_tables = 8; |
299 | module_param_named(nr_tables, pt1_nr_tables, uint, 0); | |
3d17fb1b MCC |
300 | |
301 | static void pt1_increment_table_count(struct pt1 *pt1) | |
302 | { | |
303 | pt1_write_reg(pt1, 0, 0x00000020); | |
304 | } | |
305 | ||
306 | static void pt1_init_table_count(struct pt1 *pt1) | |
307 | { | |
308 | pt1_write_reg(pt1, 0, 0x00000010); | |
309 | } | |
310 | ||
311 | static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn) | |
312 | { | |
313 | pt1_write_reg(pt1, 5, first_pfn); | |
314 | pt1_write_reg(pt1, 0, 0x0c000040); | |
315 | } | |
316 | ||
317 | static void pt1_unregister_tables(struct pt1 *pt1) | |
318 | { | |
319 | pt1_write_reg(pt1, 0, 0x08080000); | |
320 | } | |
321 | ||
322 | static int pt1_sync(struct pt1 *pt1) | |
323 | { | |
324 | int i; | |
325 | for (i = 0; i < 57; i++) { | |
326 | if (pt1_read_reg(pt1, 0) & 0x20000000) | |
327 | return 0; | |
328 | pt1_write_reg(pt1, 0, 0x00000008); | |
329 | } | |
509cd826 | 330 | dev_err(&pt1->pdev->dev, "could not sync\n"); |
3d17fb1b MCC |
331 | return -EIO; |
332 | } | |
333 | ||
334 | static u64 pt1_identify(struct pt1 *pt1) | |
335 | { | |
336 | int i; | |
337 | u64 id; | |
338 | id = 0; | |
339 | for (i = 0; i < 57; i++) { | |
340 | id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; | |
341 | pt1_write_reg(pt1, 0, 0x00000008); | |
342 | } | |
343 | return id; | |
344 | } | |
345 | ||
346 | static int pt1_unlock(struct pt1 *pt1) | |
347 | { | |
348 | int i; | |
349 | pt1_write_reg(pt1, 0, 0x00000008); | |
350 | for (i = 0; i < 3; i++) { | |
351 | if (pt1_read_reg(pt1, 0) & 0x80000000) | |
352 | return 0; | |
20a63349 | 353 | usleep_range(1000, 2000); |
3d17fb1b | 354 | } |
509cd826 | 355 | dev_err(&pt1->pdev->dev, "could not unlock\n"); |
3d17fb1b MCC |
356 | return -EIO; |
357 | } | |
358 | ||
359 | static int pt1_reset_pci(struct pt1 *pt1) | |
360 | { | |
361 | int i; | |
362 | pt1_write_reg(pt1, 0, 0x01010000); | |
363 | pt1_write_reg(pt1, 0, 0x01000000); | |
364 | for (i = 0; i < 10; i++) { | |
365 | if (pt1_read_reg(pt1, 0) & 0x00000001) | |
366 | return 0; | |
20a63349 | 367 | usleep_range(1000, 2000); |
3d17fb1b | 368 | } |
509cd826 | 369 | dev_err(&pt1->pdev->dev, "could not reset PCI\n"); |
3d17fb1b MCC |
370 | return -EIO; |
371 | } | |
372 | ||
373 | static int pt1_reset_ram(struct pt1 *pt1) | |
374 | { | |
375 | int i; | |
376 | pt1_write_reg(pt1, 0, 0x02020000); | |
377 | pt1_write_reg(pt1, 0, 0x02000000); | |
378 | for (i = 0; i < 10; i++) { | |
379 | if (pt1_read_reg(pt1, 0) & 0x00000002) | |
380 | return 0; | |
20a63349 | 381 | usleep_range(1000, 2000); |
3d17fb1b | 382 | } |
509cd826 | 383 | dev_err(&pt1->pdev->dev, "could not reset RAM\n"); |
3d17fb1b MCC |
384 | return -EIO; |
385 | } | |
386 | ||
387 | static int pt1_do_enable_ram(struct pt1 *pt1) | |
388 | { | |
389 | int i, j; | |
390 | u32 status; | |
391 | status = pt1_read_reg(pt1, 0) & 0x00000004; | |
392 | pt1_write_reg(pt1, 0, 0x00000002); | |
393 | for (i = 0; i < 10; i++) { | |
394 | for (j = 0; j < 1024; j++) { | |
395 | if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) | |
396 | return 0; | |
397 | } | |
20a63349 | 398 | usleep_range(1000, 2000); |
3d17fb1b | 399 | } |
509cd826 | 400 | dev_err(&pt1->pdev->dev, "could not enable RAM\n"); |
3d17fb1b MCC |
401 | return -EIO; |
402 | } | |
403 | ||
404 | static int pt1_enable_ram(struct pt1 *pt1) | |
405 | { | |
406 | int i, ret; | |
4d1f413e | 407 | int phase; |
20a63349 | 408 | usleep_range(1000, 2000); |
4d1f413e HT |
409 | phase = pt1->pdev->device == 0x211a ? 128 : 166; |
410 | for (i = 0; i < phase; i++) { | |
3d17fb1b MCC |
411 | ret = pt1_do_enable_ram(pt1); |
412 | if (ret < 0) | |
413 | return ret; | |
414 | } | |
415 | return 0; | |
416 | } | |
417 | ||
418 | static void pt1_disable_ram(struct pt1 *pt1) | |
419 | { | |
420 | pt1_write_reg(pt1, 0, 0x0b0b0000); | |
421 | } | |
422 | ||
423 | static void pt1_set_stream(struct pt1 *pt1, int index, int enabled) | |
424 | { | |
425 | pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index); | |
426 | } | |
427 | ||
428 | static void pt1_init_streams(struct pt1 *pt1) | |
429 | { | |
430 | int i; | |
431 | for (i = 0; i < PT1_NR_ADAPS; i++) | |
432 | pt1_set_stream(pt1, i, 0); | |
433 | } | |
434 | ||
435 | static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) | |
436 | { | |
437 | u32 upacket; | |
438 | int i; | |
439 | int index; | |
440 | struct pt1_adapter *adap; | |
441 | int offset; | |
442 | u8 *buf; | |
69881110 | 443 | int sc; |
3d17fb1b MCC |
444 | |
445 | if (!page->upackets[PT1_NR_UPACKETS - 1]) | |
446 | return 0; | |
447 | ||
448 | for (i = 0; i < PT1_NR_UPACKETS; i++) { | |
449 | upacket = le32_to_cpu(page->upackets[i]); | |
450 | index = (upacket >> 29) - 1; | |
451 | if (index < 0 || index >= PT1_NR_ADAPS) | |
452 | continue; | |
453 | ||
454 | adap = pt1->adaps[index]; | |
455 | if (upacket >> 25 & 1) | |
456 | adap->upacket_count = 0; | |
457 | else if (!adap->upacket_count) | |
458 | continue; | |
459 | ||
69881110 | 460 | if (upacket >> 24 & 1) |
2d96b44f | 461 | printk_ratelimited(KERN_INFO "earth-pt1: device buffer overflowing. table[%d] buf[%d]\n", |
69881110 AT |
462 | pt1->table_index, pt1->buf_index); |
463 | sc = upacket >> 26 & 0x7; | |
464 | if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) | |
2d96b44f MCC |
465 | printk_ratelimited(KERN_INFO "earth-pt1: data loss in streamID(adapter)[%d]\n", |
466 | index); | |
69881110 AT |
467 | adap->st_count = sc; |
468 | ||
3d17fb1b MCC |
469 | buf = adap->buf; |
470 | offset = adap->packet_count * 188 + adap->upacket_count * 3; | |
471 | buf[offset] = upacket >> 16; | |
472 | buf[offset + 1] = upacket >> 8; | |
473 | if (adap->upacket_count != 62) | |
474 | buf[offset + 2] = upacket; | |
475 | ||
476 | if (++adap->upacket_count >= 63) { | |
477 | adap->upacket_count = 0; | |
478 | if (++adap->packet_count >= 21) { | |
479 | dvb_dmx_swfilter_packets(&adap->demux, buf, 21); | |
480 | adap->packet_count = 0; | |
481 | } | |
482 | } | |
483 | } | |
484 | ||
485 | page->upackets[PT1_NR_UPACKETS - 1] = 0; | |
486 | return 1; | |
487 | } | |
488 | ||
489 | static int pt1_thread(void *data) | |
490 | { | |
491 | struct pt1 *pt1; | |
3d17fb1b | 492 | struct pt1_buffer_page *page; |
41cb54e2 | 493 | bool was_frozen; |
3d17fb1b | 494 | |
20a63349 AT |
495 | #define PT1_FETCH_DELAY 10 |
496 | #define PT1_FETCH_DELAY_DELTA 2 | |
497 | ||
3d17fb1b MCC |
498 | pt1 = data; |
499 | set_freezable(); | |
500 | ||
41cb54e2 AT |
501 | while (!kthread_freezable_should_stop(&was_frozen)) { |
502 | if (was_frozen) { | |
503 | int i; | |
504 | ||
505 | for (i = 0; i < PT1_NR_ADAPS; i++) | |
506 | pt1_set_stream(pt1, i, !!pt1->adaps[i]->users); | |
507 | } | |
3d17fb1b | 508 | |
847e8765 | 509 | page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; |
3d17fb1b | 510 | if (!pt1_filter(pt1, page)) { |
20a63349 AT |
511 | ktime_t delay; |
512 | ||
b3bc535a | 513 | delay = ktime_set(0, PT1_FETCH_DELAY * NSEC_PER_MSEC); |
20a63349 AT |
514 | set_current_state(TASK_INTERRUPTIBLE); |
515 | schedule_hrtimeout_range(&delay, | |
516 | PT1_FETCH_DELAY_DELTA * NSEC_PER_MSEC, | |
517 | HRTIMER_MODE_REL); | |
3d17fb1b MCC |
518 | continue; |
519 | } | |
520 | ||
847e8765 | 521 | if (++pt1->buf_index >= PT1_NR_BUFS) { |
3d17fb1b | 522 | pt1_increment_table_count(pt1); |
847e8765 AT |
523 | pt1->buf_index = 0; |
524 | if (++pt1->table_index >= pt1_nr_tables) | |
525 | pt1->table_index = 0; | |
3d17fb1b MCC |
526 | } |
527 | } | |
528 | ||
529 | return 0; | |
530 | } | |
531 | ||
532 | static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr) | |
533 | { | |
534 | dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr); | |
535 | } | |
536 | ||
537 | static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp) | |
538 | { | |
539 | void *page; | |
540 | dma_addr_t addr; | |
541 | ||
542 | page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr, | |
543 | GFP_KERNEL); | |
544 | if (page == NULL) | |
545 | return NULL; | |
546 | ||
547 | BUG_ON(addr & (PT1_PAGE_SIZE - 1)); | |
548 | BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1); | |
549 | ||
550 | *addrp = addr; | |
551 | *pfnp = addr >> PT1_PAGE_SHIFT; | |
552 | return page; | |
553 | } | |
554 | ||
555 | static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf) | |
556 | { | |
557 | pt1_free_page(pt1, buf->page, buf->addr); | |
558 | } | |
559 | ||
560 | static int | |
561 | pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp) | |
562 | { | |
563 | struct pt1_buffer_page *page; | |
564 | dma_addr_t addr; | |
565 | ||
566 | page = pt1_alloc_page(pt1, &addr, pfnp); | |
567 | if (page == NULL) | |
568 | return -ENOMEM; | |
569 | ||
570 | page->upackets[PT1_NR_UPACKETS - 1] = 0; | |
571 | ||
572 | buf->page = page; | |
573 | buf->addr = addr; | |
574 | return 0; | |
575 | } | |
576 | ||
577 | static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table) | |
578 | { | |
579 | int i; | |
580 | ||
581 | for (i = 0; i < PT1_NR_BUFS; i++) | |
582 | pt1_cleanup_buffer(pt1, &table->bufs[i]); | |
583 | ||
584 | pt1_free_page(pt1, table->page, table->addr); | |
585 | } | |
586 | ||
587 | static int | |
588 | pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp) | |
589 | { | |
590 | struct pt1_table_page *page; | |
591 | dma_addr_t addr; | |
592 | int i, ret; | |
593 | u32 buf_pfn; | |
594 | ||
595 | page = pt1_alloc_page(pt1, &addr, pfnp); | |
596 | if (page == NULL) | |
597 | return -ENOMEM; | |
598 | ||
599 | for (i = 0; i < PT1_NR_BUFS; i++) { | |
600 | ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn); | |
601 | if (ret < 0) | |
602 | goto err; | |
603 | ||
604 | page->buf_pfns[i] = cpu_to_le32(buf_pfn); | |
605 | } | |
606 | ||
607 | pt1_increment_table_count(pt1); | |
608 | table->page = page; | |
609 | table->addr = addr; | |
610 | return 0; | |
611 | ||
612 | err: | |
613 | while (i--) | |
614 | pt1_cleanup_buffer(pt1, &table->bufs[i]); | |
615 | ||
616 | pt1_free_page(pt1, page, addr); | |
617 | return ret; | |
618 | } | |
619 | ||
620 | static void pt1_cleanup_tables(struct pt1 *pt1) | |
621 | { | |
622 | struct pt1_table *tables; | |
623 | int i; | |
624 | ||
625 | tables = pt1->tables; | |
626 | pt1_unregister_tables(pt1); | |
627 | ||
628 | for (i = 0; i < pt1_nr_tables; i++) | |
629 | pt1_cleanup_table(pt1, &tables[i]); | |
630 | ||
631 | vfree(tables); | |
632 | } | |
633 | ||
634 | static int pt1_init_tables(struct pt1 *pt1) | |
635 | { | |
636 | struct pt1_table *tables; | |
637 | int i, ret; | |
638 | u32 first_pfn, pfn; | |
639 | ||
e639c869 MCC |
640 | if (!pt1_nr_tables) |
641 | return 0; | |
642 | ||
42bc47b3 | 643 | tables = vmalloc(array_size(pt1_nr_tables, sizeof(struct pt1_table))); |
3d17fb1b MCC |
644 | if (tables == NULL) |
645 | return -ENOMEM; | |
646 | ||
647 | pt1_init_table_count(pt1); | |
648 | ||
649 | i = 0; | |
e639c869 MCC |
650 | ret = pt1_init_table(pt1, &tables[0], &first_pfn); |
651 | if (ret) | |
652 | goto err; | |
653 | i++; | |
3d17fb1b MCC |
654 | |
655 | while (i < pt1_nr_tables) { | |
656 | ret = pt1_init_table(pt1, &tables[i], &pfn); | |
657 | if (ret) | |
658 | goto err; | |
659 | tables[i - 1].page->next_pfn = cpu_to_le32(pfn); | |
660 | i++; | |
661 | } | |
662 | ||
663 | tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn); | |
664 | ||
665 | pt1_register_tables(pt1, first_pfn); | |
666 | pt1->tables = tables; | |
667 | return 0; | |
668 | ||
669 | err: | |
670 | while (i--) | |
671 | pt1_cleanup_table(pt1, &tables[i]); | |
672 | ||
673 | vfree(tables); | |
674 | return ret; | |
675 | } | |
676 | ||
847e8765 AT |
677 | static int pt1_start_polling(struct pt1 *pt1) |
678 | { | |
679 | int ret = 0; | |
680 | ||
681 | mutex_lock(&pt1->lock); | |
682 | if (!pt1->kthread) { | |
683 | pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); | |
684 | if (IS_ERR(pt1->kthread)) { | |
685 | ret = PTR_ERR(pt1->kthread); | |
686 | pt1->kthread = NULL; | |
687 | } | |
688 | } | |
689 | mutex_unlock(&pt1->lock); | |
690 | return ret; | |
691 | } | |
692 | ||
3d17fb1b MCC |
693 | static int pt1_start_feed(struct dvb_demux_feed *feed) |
694 | { | |
695 | struct pt1_adapter *adap; | |
696 | adap = container_of(feed->demux, struct pt1_adapter, demux); | |
847e8765 AT |
697 | if (!adap->users++) { |
698 | int ret; | |
699 | ||
700 | ret = pt1_start_polling(adap->pt1); | |
701 | if (ret) | |
702 | return ret; | |
3d17fb1b | 703 | pt1_set_stream(adap->pt1, adap->index, 1); |
847e8765 | 704 | } |
3d17fb1b MCC |
705 | return 0; |
706 | } | |
707 | ||
847e8765 AT |
708 | static void pt1_stop_polling(struct pt1 *pt1) |
709 | { | |
710 | int i, count; | |
711 | ||
712 | mutex_lock(&pt1->lock); | |
713 | for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) | |
714 | count += pt1->adaps[i]->users; | |
715 | ||
716 | if (count == 0 && pt1->kthread) { | |
717 | kthread_stop(pt1->kthread); | |
718 | pt1->kthread = NULL; | |
719 | } | |
720 | mutex_unlock(&pt1->lock); | |
721 | } | |
722 | ||
3d17fb1b MCC |
723 | static int pt1_stop_feed(struct dvb_demux_feed *feed) |
724 | { | |
725 | struct pt1_adapter *adap; | |
726 | adap = container_of(feed->demux, struct pt1_adapter, demux); | |
847e8765 | 727 | if (!--adap->users) { |
3d17fb1b | 728 | pt1_set_stream(adap->pt1, adap->index, 0); |
847e8765 AT |
729 | pt1_stop_polling(adap->pt1); |
730 | } | |
3d17fb1b MCC |
731 | return 0; |
732 | } | |
733 | ||
734 | static void | |
4d1f413e | 735 | pt1_update_power(struct pt1 *pt1) |
3d17fb1b | 736 | { |
4d1f413e HT |
737 | int bits; |
738 | int i; | |
739 | struct pt1_adapter *adap; | |
740 | static const int sleep_bits[] = { | |
741 | 1 << 4, | |
742 | 1 << 6 | 1 << 7, | |
743 | 1 << 5, | |
744 | 1 << 6 | 1 << 8, | |
745 | }; | |
746 | ||
747 | bits = pt1->power | !pt1->reset << 3; | |
748 | mutex_lock(&pt1->lock); | |
749 | for (i = 0; i < PT1_NR_ADAPS; i++) { | |
750 | adap = pt1->adaps[i]; | |
751 | switch (adap->voltage) { | |
752 | case SEC_VOLTAGE_13: /* actually 11V */ | |
20a63349 | 753 | bits |= 1 << 2; |
4d1f413e HT |
754 | break; |
755 | case SEC_VOLTAGE_18: /* actually 15V */ | |
756 | bits |= 1 << 1 | 1 << 2; | |
757 | break; | |
758 | default: | |
759 | break; | |
760 | } | |
761 | ||
762 | /* XXX: The bits should be changed depending on adap->sleep. */ | |
763 | bits |= sleep_bits[i]; | |
764 | } | |
765 | pt1_write_reg(pt1, 1, bits); | |
766 | mutex_unlock(&pt1->lock); | |
3d17fb1b MCC |
767 | } |
768 | ||
0df289a2 | 769 | static int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) |
3d17fb1b MCC |
770 | { |
771 | struct pt1_adapter *adap; | |
3d17fb1b MCC |
772 | |
773 | adap = container_of(fe->dvb, struct pt1_adapter, adap); | |
4d1f413e HT |
774 | adap->voltage = voltage; |
775 | pt1_update_power(adap->pt1); | |
3d17fb1b MCC |
776 | |
777 | if (adap->orig_set_voltage) | |
778 | return adap->orig_set_voltage(fe, voltage); | |
779 | else | |
780 | return 0; | |
781 | } | |
782 | ||
4d1f413e HT |
783 | static int pt1_sleep(struct dvb_frontend *fe) |
784 | { | |
785 | struct pt1_adapter *adap; | |
b732539e | 786 | int ret; |
4d1f413e HT |
787 | |
788 | adap = container_of(fe->dvb, struct pt1_adapter, adap); | |
4d1f413e | 789 | |
b732539e | 790 | ret = 0; |
4d1f413e | 791 | if (adap->orig_sleep) |
b732539e AT |
792 | ret = adap->orig_sleep(fe); |
793 | ||
794 | adap->sleep = 1; | |
795 | pt1_update_power(adap->pt1); | |
796 | return ret; | |
4d1f413e HT |
797 | } |
798 | ||
799 | static int pt1_wakeup(struct dvb_frontend *fe) | |
800 | { | |
801 | struct pt1_adapter *adap; | |
b732539e | 802 | int ret; |
4d1f413e HT |
803 | |
804 | adap = container_of(fe->dvb, struct pt1_adapter, adap); | |
805 | adap->sleep = 0; | |
806 | pt1_update_power(adap->pt1); | |
20a63349 | 807 | usleep_range(1000, 2000); |
4d1f413e | 808 | |
b732539e AT |
809 | ret = config_demod(adap->demod_i2c_client, adap->pt1->fe_clk); |
810 | if (ret == 0 && adap->orig_init) | |
811 | ret = adap->orig_init(fe); | |
812 | return ret; | |
4d1f413e HT |
813 | } |
814 | ||
3d17fb1b MCC |
815 | static void pt1_free_adapter(struct pt1_adapter *adap) |
816 | { | |
3d17fb1b MCC |
817 | adap->demux.dmx.close(&adap->demux.dmx); |
818 | dvb_dmxdev_release(&adap->dmxdev); | |
819 | dvb_dmx_release(&adap->demux); | |
820 | dvb_unregister_adapter(&adap->adap); | |
821 | free_page((unsigned long)adap->buf); | |
822 | kfree(adap); | |
823 | } | |
824 | ||
825 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
826 | ||
827 | static struct pt1_adapter * | |
4d1f413e | 828 | pt1_alloc_adapter(struct pt1 *pt1) |
3d17fb1b MCC |
829 | { |
830 | struct pt1_adapter *adap; | |
831 | void *buf; | |
832 | struct dvb_adapter *dvb_adap; | |
833 | struct dvb_demux *demux; | |
834 | struct dmxdev *dmxdev; | |
835 | int ret; | |
836 | ||
837 | adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL); | |
838 | if (!adap) { | |
839 | ret = -ENOMEM; | |
840 | goto err; | |
841 | } | |
842 | ||
843 | adap->pt1 = pt1; | |
844 | ||
4d1f413e HT |
845 | adap->voltage = SEC_VOLTAGE_OFF; |
846 | adap->sleep = 1; | |
3d17fb1b MCC |
847 | |
848 | buf = (u8 *)__get_free_page(GFP_KERNEL); | |
849 | if (!buf) { | |
850 | ret = -ENOMEM; | |
851 | goto err_kfree; | |
852 | } | |
853 | ||
854 | adap->buf = buf; | |
855 | adap->upacket_count = 0; | |
856 | adap->packet_count = 0; | |
69881110 | 857 | adap->st_count = -1; |
3d17fb1b MCC |
858 | |
859 | dvb_adap = &adap->adap; | |
860 | dvb_adap->priv = adap; | |
861 | ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE, | |
862 | &pt1->pdev->dev, adapter_nr); | |
863 | if (ret < 0) | |
864 | goto err_free_page; | |
865 | ||
866 | demux = &adap->demux; | |
867 | demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; | |
868 | demux->priv = adap; | |
869 | demux->feednum = 256; | |
870 | demux->filternum = 256; | |
871 | demux->start_feed = pt1_start_feed; | |
872 | demux->stop_feed = pt1_stop_feed; | |
873 | demux->write_to_decoder = NULL; | |
874 | ret = dvb_dmx_init(demux); | |
875 | if (ret < 0) | |
876 | goto err_unregister_adapter; | |
877 | ||
878 | dmxdev = &adap->dmxdev; | |
879 | dmxdev->filternum = 256; | |
880 | dmxdev->demux = &demux->dmx; | |
881 | dmxdev->capabilities = 0; | |
882 | ret = dvb_dmxdev_init(dmxdev, dvb_adap); | |
883 | if (ret < 0) | |
884 | goto err_dmx_release; | |
885 | ||
3d17fb1b MCC |
886 | return adap; |
887 | ||
3d17fb1b MCC |
888 | err_dmx_release: |
889 | dvb_dmx_release(demux); | |
890 | err_unregister_adapter: | |
891 | dvb_unregister_adapter(dvb_adap); | |
892 | err_free_page: | |
893 | free_page((unsigned long)buf); | |
894 | err_kfree: | |
895 | kfree(adap); | |
896 | err: | |
897 | return ERR_PTR(ret); | |
898 | } | |
899 | ||
900 | static void pt1_cleanup_adapters(struct pt1 *pt1) | |
901 | { | |
902 | int i; | |
903 | for (i = 0; i < PT1_NR_ADAPS; i++) | |
904 | pt1_free_adapter(pt1->adaps[i]); | |
905 | } | |
906 | ||
4d1f413e HT |
907 | static int pt1_init_adapters(struct pt1 *pt1) |
908 | { | |
909 | int i; | |
910 | struct pt1_adapter *adap; | |
911 | int ret; | |
912 | ||
913 | for (i = 0; i < PT1_NR_ADAPS; i++) { | |
914 | adap = pt1_alloc_adapter(pt1); | |
915 | if (IS_ERR(adap)) { | |
916 | ret = PTR_ERR(adap); | |
917 | goto err; | |
918 | } | |
919 | ||
920 | adap->index = i; | |
921 | pt1->adaps[i] = adap; | |
922 | } | |
923 | return 0; | |
924 | ||
925 | err: | |
926 | while (i--) | |
927 | pt1_free_adapter(pt1->adaps[i]); | |
928 | ||
929 | return ret; | |
930 | } | |
931 | ||
932 | static void pt1_cleanup_frontend(struct pt1_adapter *adap) | |
933 | { | |
934 | dvb_unregister_frontend(adap->fe); | |
b732539e AT |
935 | dvb_module_release(adap->tuner_i2c_client); |
936 | dvb_module_release(adap->demod_i2c_client); | |
4d1f413e HT |
937 | } |
938 | ||
939 | static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) | |
940 | { | |
941 | int ret; | |
942 | ||
943 | adap->orig_set_voltage = fe->ops.set_voltage; | |
944 | adap->orig_sleep = fe->ops.sleep; | |
945 | adap->orig_init = fe->ops.init; | |
946 | fe->ops.set_voltage = pt1_set_voltage; | |
947 | fe->ops.sleep = pt1_sleep; | |
948 | fe->ops.init = pt1_wakeup; | |
949 | ||
950 | ret = dvb_register_frontend(&adap->adap, fe); | |
951 | if (ret < 0) | |
952 | return ret; | |
953 | ||
954 | adap->fe = fe; | |
955 | return 0; | |
956 | } | |
957 | ||
958 | static void pt1_cleanup_frontends(struct pt1 *pt1) | |
959 | { | |
960 | int i; | |
961 | for (i = 0; i < PT1_NR_ADAPS; i++) | |
962 | pt1_cleanup_frontend(pt1->adaps[i]); | |
963 | } | |
964 | ||
4d1f413e | 965 | static int pt1_init_frontends(struct pt1 *pt1) |
3d17fb1b | 966 | { |
b732539e | 967 | int i; |
3d17fb1b MCC |
968 | int ret; |
969 | ||
b732539e AT |
970 | for (i = 0; i < ARRAY_SIZE(pt1_configs); i++) { |
971 | const struct i2c_board_info *info; | |
972 | struct tc90522_config dcfg; | |
973 | struct i2c_client *cl; | |
974 | ||
975 | info = &pt1_configs[i].demod_info; | |
976 | dcfg = pt1_configs[i].demod_cfg; | |
977 | dcfg.tuner_i2c = NULL; | |
978 | ||
979 | ret = -ENODEV; | |
980 | cl = dvb_module_probe("tc90522", info->type, &pt1->i2c_adap, | |
981 | info->addr, &dcfg); | |
982 | if (!cl) | |
983 | goto fe_unregister; | |
984 | pt1->adaps[i]->demod_i2c_client = cl; | |
985 | ||
986 | if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, | |
987 | strlen(TC90522_I2C_DEV_SAT))) { | |
988 | struct qm1d1b0004_config tcfg; | |
989 | ||
990 | info = &pt1_configs[i].tuner_info; | |
991 | tcfg = pt1_configs[i].tuner_cfg.qm1d1b0004; | |
992 | tcfg.fe = dcfg.fe; | |
993 | cl = dvb_module_probe("qm1d1b0004", | |
994 | info->type, dcfg.tuner_i2c, | |
995 | info->addr, &tcfg); | |
996 | } else { | |
997 | struct dvb_pll_config tcfg; | |
998 | ||
999 | info = &pt1_configs[i].tuner_info; | |
1000 | tcfg = pt1_configs[i].tuner_cfg.tda6651; | |
1001 | tcfg.fe = dcfg.fe; | |
1002 | cl = dvb_module_probe("dvb_pll", | |
1003 | info->type, dcfg.tuner_i2c, | |
1004 | info->addr, &tcfg); | |
3d17fb1b | 1005 | } |
b732539e AT |
1006 | if (!cl) |
1007 | goto demod_release; | |
1008 | pt1->adaps[i]->tuner_i2c_client = cl; | |
3d17fb1b | 1009 | |
b732539e | 1010 | ret = pt1_init_frontend(pt1->adaps[i], dcfg.fe); |
3d17fb1b | 1011 | if (ret < 0) |
b732539e AT |
1012 | goto tuner_release; |
1013 | } | |
3d17fb1b | 1014 | |
15d90a6a AT |
1015 | ret = pt1_demod_block_init(pt1); |
1016 | if (ret < 0) | |
1017 | goto fe_unregister; | |
1018 | ||
3d17fb1b MCC |
1019 | return 0; |
1020 | ||
b732539e AT |
1021 | tuner_release: |
1022 | dvb_module_release(pt1->adaps[i]->tuner_i2c_client); | |
1023 | demod_release: | |
1024 | dvb_module_release(pt1->adaps[i]->demod_i2c_client); | |
1025 | fe_unregister: | |
1026 | dev_warn(&pt1->pdev->dev, "failed to init FE(%d).\n", i); | |
1027 | i--; | |
1028 | for (; i >= 0; i--) { | |
1029 | dvb_unregister_frontend(pt1->adaps[i]->fe); | |
1030 | dvb_module_release(pt1->adaps[i]->tuner_i2c_client); | |
1031 | dvb_module_release(pt1->adaps[i]->demod_i2c_client); | |
1032 | } | |
3d17fb1b MCC |
1033 | return ret; |
1034 | } | |
1035 | ||
1036 | static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable, | |
1037 | int clock, int data, int next_addr) | |
1038 | { | |
1039 | pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 | | |
1040 | !clock << 11 | !data << 10 | next_addr); | |
1041 | } | |
1042 | ||
1043 | static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data) | |
1044 | { | |
1045 | pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1); | |
1046 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2); | |
1047 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3); | |
1048 | *addrp = addr + 3; | |
1049 | } | |
1050 | ||
1051 | static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp) | |
1052 | { | |
1053 | pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1); | |
1054 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2); | |
1055 | pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3); | |
1056 | pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4); | |
1057 | *addrp = addr + 4; | |
1058 | } | |
1059 | ||
1060 | static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data) | |
1061 | { | |
1062 | int i; | |
1063 | for (i = 0; i < 8; i++) | |
1064 | pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1); | |
1065 | pt1_i2c_write_bit(pt1, addr, &addr, 1); | |
1066 | *addrp = addr; | |
1067 | } | |
1068 | ||
1069 | static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last) | |
1070 | { | |
1071 | int i; | |
1072 | for (i = 0; i < 8; i++) | |
1073 | pt1_i2c_read_bit(pt1, addr, &addr); | |
1074 | pt1_i2c_write_bit(pt1, addr, &addr, last); | |
1075 | *addrp = addr; | |
1076 | } | |
1077 | ||
1078 | static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp) | |
1079 | { | |
1080 | pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); | |
1081 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | |
1082 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3); | |
1083 | *addrp = addr + 3; | |
1084 | } | |
1085 | ||
1086 | static void | |
1087 | pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) | |
1088 | { | |
1089 | int i; | |
1090 | pt1_i2c_prepare(pt1, addr, &addr); | |
1091 | pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1); | |
1092 | for (i = 0; i < msg->len; i++) | |
1093 | pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]); | |
1094 | *addrp = addr; | |
1095 | } | |
1096 | ||
1097 | static void | |
1098 | pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) | |
1099 | { | |
1100 | int i; | |
1101 | pt1_i2c_prepare(pt1, addr, &addr); | |
1102 | pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1); | |
1103 | for (i = 0; i < msg->len; i++) | |
1104 | pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1); | |
1105 | *addrp = addr; | |
1106 | } | |
1107 | ||
1108 | static int pt1_i2c_end(struct pt1 *pt1, int addr) | |
1109 | { | |
1110 | pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1); | |
1111 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | |
1112 | pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0); | |
1113 | ||
1114 | pt1_write_reg(pt1, 0, 0x00000004); | |
1115 | do { | |
1116 | if (signal_pending(current)) | |
1117 | return -EINTR; | |
20a63349 | 1118 | usleep_range(1000, 2000); |
3d17fb1b MCC |
1119 | } while (pt1_read_reg(pt1, 0) & 0x00000080); |
1120 | return 0; | |
1121 | } | |
1122 | ||
1123 | static void pt1_i2c_begin(struct pt1 *pt1, int *addrp) | |
1124 | { | |
1125 | int addr; | |
1126 | addr = 0; | |
1127 | ||
1128 | pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); | |
1129 | addr = addr + 1; | |
1130 | ||
1131 | if (!pt1->i2c_running) { | |
1132 | pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); | |
1133 | pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); | |
1134 | addr = addr + 2; | |
1135 | pt1->i2c_running = 1; | |
1136 | } | |
1137 | *addrp = addr; | |
1138 | } | |
1139 | ||
1140 | static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |
1141 | { | |
1142 | struct pt1 *pt1; | |
1143 | int i; | |
1144 | struct i2c_msg *msg, *next_msg; | |
1145 | int addr, ret; | |
1146 | u16 len; | |
1147 | u32 word; | |
1148 | ||
1149 | pt1 = i2c_get_adapdata(adap); | |
1150 | ||
1151 | for (i = 0; i < num; i++) { | |
1152 | msg = &msgs[i]; | |
1153 | if (msg->flags & I2C_M_RD) | |
1154 | return -ENOTSUPP; | |
1155 | ||
1156 | if (i + 1 < num) | |
1157 | next_msg = &msgs[i + 1]; | |
1158 | else | |
1159 | next_msg = NULL; | |
1160 | ||
1161 | if (next_msg && next_msg->flags & I2C_M_RD) { | |
1162 | i++; | |
1163 | ||
1164 | len = next_msg->len; | |
1165 | if (len > 4) | |
1166 | return -ENOTSUPP; | |
1167 | ||
1168 | pt1_i2c_begin(pt1, &addr); | |
1169 | pt1_i2c_write_msg(pt1, addr, &addr, msg); | |
1170 | pt1_i2c_read_msg(pt1, addr, &addr, next_msg); | |
1171 | ret = pt1_i2c_end(pt1, addr); | |
1172 | if (ret < 0) | |
1173 | return ret; | |
1174 | ||
1175 | word = pt1_read_reg(pt1, 2); | |
1176 | while (len--) { | |
1177 | next_msg->buf[len] = word; | |
1178 | word >>= 8; | |
1179 | } | |
1180 | } else { | |
1181 | pt1_i2c_begin(pt1, &addr); | |
1182 | pt1_i2c_write_msg(pt1, addr, &addr, msg); | |
1183 | ret = pt1_i2c_end(pt1, addr); | |
1184 | if (ret < 0) | |
1185 | return ret; | |
1186 | } | |
1187 | } | |
1188 | ||
1189 | return num; | |
1190 | } | |
1191 | ||
1192 | static u32 pt1_i2c_func(struct i2c_adapter *adap) | |
1193 | { | |
1194 | return I2C_FUNC_I2C; | |
1195 | } | |
1196 | ||
1197 | static const struct i2c_algorithm pt1_i2c_algo = { | |
1198 | .master_xfer = pt1_i2c_xfer, | |
1199 | .functionality = pt1_i2c_func, | |
1200 | }; | |
1201 | ||
1202 | static void pt1_i2c_wait(struct pt1 *pt1) | |
1203 | { | |
1204 | int i; | |
1205 | for (i = 0; i < 128; i++) | |
1206 | pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0); | |
1207 | } | |
1208 | ||
1209 | static void pt1_i2c_init(struct pt1 *pt1) | |
1210 | { | |
1211 | int i; | |
1212 | for (i = 0; i < 1024; i++) | |
1213 | pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); | |
1214 | } | |
1215 | ||
41cb54e2 AT |
1216 | #ifdef CONFIG_PM_SLEEP |
1217 | ||
1218 | static int pt1_suspend(struct device *dev) | |
1219 | { | |
1220 | struct pci_dev *pdev = to_pci_dev(dev); | |
1221 | struct pt1 *pt1 = pci_get_drvdata(pdev); | |
1222 | ||
1223 | pt1_init_streams(pt1); | |
1224 | pt1_disable_ram(pt1); | |
1225 | pt1->power = 0; | |
1226 | pt1->reset = 1; | |
1227 | pt1_update_power(pt1); | |
1228 | return 0; | |
1229 | } | |
1230 | ||
1231 | static int pt1_resume(struct device *dev) | |
1232 | { | |
1233 | struct pci_dev *pdev = to_pci_dev(dev); | |
1234 | struct pt1 *pt1 = pci_get_drvdata(pdev); | |
1235 | int ret; | |
1236 | int i; | |
1237 | ||
1238 | pt1->power = 0; | |
1239 | pt1->reset = 1; | |
1240 | pt1_update_power(pt1); | |
1241 | ||
1242 | pt1_i2c_init(pt1); | |
1243 | pt1_i2c_wait(pt1); | |
1244 | ||
1245 | ret = pt1_sync(pt1); | |
1246 | if (ret < 0) | |
1247 | goto resume_err; | |
1248 | ||
1249 | pt1_identify(pt1); | |
1250 | ||
1251 | ret = pt1_unlock(pt1); | |
1252 | if (ret < 0) | |
1253 | goto resume_err; | |
1254 | ||
1255 | ret = pt1_reset_pci(pt1); | |
1256 | if (ret < 0) | |
1257 | goto resume_err; | |
1258 | ||
1259 | ret = pt1_reset_ram(pt1); | |
1260 | if (ret < 0) | |
1261 | goto resume_err; | |
1262 | ||
1263 | ret = pt1_enable_ram(pt1); | |
1264 | if (ret < 0) | |
1265 | goto resume_err; | |
1266 | ||
1267 | pt1_init_streams(pt1); | |
1268 | ||
1269 | pt1->power = 1; | |
1270 | pt1_update_power(pt1); | |
1271 | msleep(20); | |
1272 | ||
1273 | pt1->reset = 0; | |
1274 | pt1_update_power(pt1); | |
1275 | usleep_range(1000, 2000); | |
1276 | ||
15d90a6a AT |
1277 | ret = pt1_demod_block_init(pt1); |
1278 | if (ret < 0) | |
1279 | goto resume_err; | |
1280 | ||
41cb54e2 AT |
1281 | for (i = 0; i < PT1_NR_ADAPS; i++) |
1282 | dvb_frontend_reinitialise(pt1->adaps[i]->fe); | |
1283 | ||
1284 | pt1_init_table_count(pt1); | |
1285 | for (i = 0; i < pt1_nr_tables; i++) { | |
1286 | int j; | |
1287 | ||
1288 | for (j = 0; j < PT1_NR_BUFS; j++) | |
1289 | pt1->tables[i].bufs[j].page->upackets[PT1_NR_UPACKETS-1] | |
1290 | = 0; | |
1291 | pt1_increment_table_count(pt1); | |
1292 | } | |
1293 | pt1_register_tables(pt1, pt1->tables[0].addr >> PT1_PAGE_SHIFT); | |
1294 | ||
1295 | pt1->table_index = 0; | |
1296 | pt1->buf_index = 0; | |
1297 | for (i = 0; i < PT1_NR_ADAPS; i++) { | |
1298 | pt1->adaps[i]->upacket_count = 0; | |
1299 | pt1->adaps[i]->packet_count = 0; | |
1300 | pt1->adaps[i]->st_count = -1; | |
1301 | } | |
1302 | ||
1303 | return 0; | |
1304 | ||
1305 | resume_err: | |
1306 | dev_info(&pt1->pdev->dev, "failed to resume PT1/PT2."); | |
1307 | return 0; /* resume anyway */ | |
1308 | } | |
1309 | ||
1310 | #endif /* CONFIG_PM_SLEEP */ | |
1311 | ||
4c62e976 | 1312 | static void pt1_remove(struct pci_dev *pdev) |
3d17fb1b MCC |
1313 | { |
1314 | struct pt1 *pt1; | |
1315 | void __iomem *regs; | |
1316 | ||
1317 | pt1 = pci_get_drvdata(pdev); | |
1318 | regs = pt1->regs; | |
1319 | ||
847e8765 AT |
1320 | if (pt1->kthread) |
1321 | kthread_stop(pt1->kthread); | |
3d17fb1b | 1322 | pt1_cleanup_tables(pt1); |
4d1f413e | 1323 | pt1_cleanup_frontends(pt1); |
3d17fb1b | 1324 | pt1_disable_ram(pt1); |
4d1f413e HT |
1325 | pt1->power = 0; |
1326 | pt1->reset = 1; | |
1327 | pt1_update_power(pt1); | |
1328 | pt1_cleanup_adapters(pt1); | |
3d17fb1b | 1329 | i2c_del_adapter(&pt1->i2c_adap); |
3d17fb1b MCC |
1330 | kfree(pt1); |
1331 | pci_iounmap(pdev, regs); | |
1332 | pci_release_regions(pdev); | |
1333 | pci_disable_device(pdev); | |
1334 | } | |
1335 | ||
4c62e976 | 1336 | static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
3d17fb1b MCC |
1337 | { |
1338 | int ret; | |
1339 | void __iomem *regs; | |
1340 | struct pt1 *pt1; | |
1341 | struct i2c_adapter *i2c_adap; | |
3d17fb1b MCC |
1342 | |
1343 | ret = pci_enable_device(pdev); | |
1344 | if (ret < 0) | |
1345 | goto err; | |
1346 | ||
84d6ae43 | 1347 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
3d17fb1b MCC |
1348 | if (ret < 0) |
1349 | goto err_pci_disable_device; | |
1350 | ||
1351 | pci_set_master(pdev); | |
1352 | ||
1353 | ret = pci_request_regions(pdev, DRIVER_NAME); | |
1354 | if (ret < 0) | |
1355 | goto err_pci_disable_device; | |
1356 | ||
1357 | regs = pci_iomap(pdev, 0, 0); | |
1358 | if (!regs) { | |
1359 | ret = -EIO; | |
1360 | goto err_pci_release_regions; | |
1361 | } | |
1362 | ||
1363 | pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL); | |
1364 | if (!pt1) { | |
1365 | ret = -ENOMEM; | |
1366 | goto err_pci_iounmap; | |
1367 | } | |
1368 | ||
4d1f413e | 1369 | mutex_init(&pt1->lock); |
3d17fb1b MCC |
1370 | pt1->pdev = pdev; |
1371 | pt1->regs = regs; | |
b732539e AT |
1372 | pt1->fe_clk = (pdev->device == 0x211a) ? |
1373 | PT1_FE_CLK_20MHZ : PT1_FE_CLK_25MHZ; | |
3d17fb1b MCC |
1374 | pci_set_drvdata(pdev, pt1); |
1375 | ||
4d1f413e HT |
1376 | ret = pt1_init_adapters(pt1); |
1377 | if (ret < 0) | |
1378 | goto err_kfree; | |
1379 | ||
1380 | mutex_init(&pt1->lock); | |
1381 | ||
1382 | pt1->power = 0; | |
1383 | pt1->reset = 1; | |
1384 | pt1_update_power(pt1); | |
1385 | ||
3d17fb1b | 1386 | i2c_adap = &pt1->i2c_adap; |
3d17fb1b MCC |
1387 | i2c_adap->algo = &pt1_i2c_algo; |
1388 | i2c_adap->algo_data = NULL; | |
1389 | i2c_adap->dev.parent = &pdev->dev; | |
cc1e6315 | 1390 | strscpy(i2c_adap->name, DRIVER_NAME, sizeof(i2c_adap->name)); |
3d17fb1b MCC |
1391 | i2c_set_adapdata(i2c_adap, pt1); |
1392 | ret = i2c_add_adapter(i2c_adap); | |
1393 | if (ret < 0) | |
4d1f413e | 1394 | goto err_pt1_cleanup_adapters; |
3d17fb1b MCC |
1395 | |
1396 | pt1_i2c_init(pt1); | |
1397 | pt1_i2c_wait(pt1); | |
1398 | ||
1399 | ret = pt1_sync(pt1); | |
1400 | if (ret < 0) | |
1401 | goto err_i2c_del_adapter; | |
1402 | ||
1403 | pt1_identify(pt1); | |
1404 | ||
1405 | ret = pt1_unlock(pt1); | |
1406 | if (ret < 0) | |
1407 | goto err_i2c_del_adapter; | |
1408 | ||
1409 | ret = pt1_reset_pci(pt1); | |
1410 | if (ret < 0) | |
1411 | goto err_i2c_del_adapter; | |
1412 | ||
1413 | ret = pt1_reset_ram(pt1); | |
1414 | if (ret < 0) | |
1415 | goto err_i2c_del_adapter; | |
1416 | ||
1417 | ret = pt1_enable_ram(pt1); | |
1418 | if (ret < 0) | |
1419 | goto err_i2c_del_adapter; | |
1420 | ||
1421 | pt1_init_streams(pt1); | |
1422 | ||
4d1f413e HT |
1423 | pt1->power = 1; |
1424 | pt1_update_power(pt1); | |
20a63349 | 1425 | msleep(20); |
3d17fb1b | 1426 | |
4d1f413e HT |
1427 | pt1->reset = 0; |
1428 | pt1_update_power(pt1); | |
20a63349 | 1429 | usleep_range(1000, 2000); |
3d17fb1b | 1430 | |
4d1f413e | 1431 | ret = pt1_init_frontends(pt1); |
3d17fb1b MCC |
1432 | if (ret < 0) |
1433 | goto err_pt1_disable_ram; | |
1434 | ||
1435 | ret = pt1_init_tables(pt1); | |
1436 | if (ret < 0) | |
4d1f413e | 1437 | goto err_pt1_cleanup_frontends; |
3d17fb1b | 1438 | |
3d17fb1b MCC |
1439 | return 0; |
1440 | ||
4d1f413e HT |
1441 | err_pt1_cleanup_frontends: |
1442 | pt1_cleanup_frontends(pt1); | |
3d17fb1b MCC |
1443 | err_pt1_disable_ram: |
1444 | pt1_disable_ram(pt1); | |
4d1f413e HT |
1445 | pt1->power = 0; |
1446 | pt1->reset = 1; | |
1447 | pt1_update_power(pt1); | |
3d17fb1b MCC |
1448 | err_i2c_del_adapter: |
1449 | i2c_del_adapter(i2c_adap); | |
cae72c7c HT |
1450 | err_pt1_cleanup_adapters: |
1451 | pt1_cleanup_adapters(pt1); | |
3d17fb1b | 1452 | err_kfree: |
3d17fb1b MCC |
1453 | kfree(pt1); |
1454 | err_pci_iounmap: | |
1455 | pci_iounmap(pdev, regs); | |
1456 | err_pci_release_regions: | |
1457 | pci_release_regions(pdev); | |
1458 | err_pci_disable_device: | |
1459 | pci_disable_device(pdev); | |
1460 | err: | |
1461 | return ret; | |
1462 | ||
1463 | } | |
1464 | ||
d2c43ff1 | 1465 | static const struct pci_device_id pt1_id_table[] = { |
3d17fb1b | 1466 | { PCI_DEVICE(0x10ee, 0x211a) }, |
4d1f413e | 1467 | { PCI_DEVICE(0x10ee, 0x222a) }, |
3d17fb1b MCC |
1468 | { }, |
1469 | }; | |
1470 | MODULE_DEVICE_TABLE(pci, pt1_id_table); | |
1471 | ||
41cb54e2 AT |
1472 | static SIMPLE_DEV_PM_OPS(pt1_pm_ops, pt1_suspend, pt1_resume); |
1473 | ||
3d17fb1b MCC |
1474 | static struct pci_driver pt1_driver = { |
1475 | .name = DRIVER_NAME, | |
1476 | .probe = pt1_probe, | |
4c62e976 | 1477 | .remove = pt1_remove, |
3d17fb1b | 1478 | .id_table = pt1_id_table, |
41cb54e2 | 1479 | .driver.pm = &pt1_pm_ops, |
3d17fb1b MCC |
1480 | }; |
1481 | ||
e7be28cb | 1482 | module_pci_driver(pt1_driver); |
3d17fb1b MCC |
1483 | |
1484 | MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>"); | |
4d1f413e | 1485 | MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); |
3d17fb1b | 1486 | MODULE_LICENSE("GPL"); |