diff options
Diffstat (limited to 'drivers/media/dvb/pt1/va1j5jf8007s.c')
-rw-r--r-- | drivers/media/dvb/pt1/va1j5jf8007s.c | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c new file mode 100644 index 000000000000..2db940f8635f --- /dev/null +++ b/drivers/media/dvb/pt1/va1j5jf8007s.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | * ISDB-S driver for VA1J5JF8007 | ||
3 | * | ||
4 | * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> | ||
5 | * | ||
6 | * based on pt1dvr - http://pt1dvr.sourceforge.jp/ | ||
7 | * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | #include "va1j5jf8007s.h" | ||
30 | |||
31 | enum va1j5jf8007s_tune_state { | ||
32 | VA1J5JF8007S_IDLE, | ||
33 | VA1J5JF8007S_SET_FREQUENCY_1, | ||
34 | VA1J5JF8007S_SET_FREQUENCY_2, | ||
35 | VA1J5JF8007S_SET_FREQUENCY_3, | ||
36 | VA1J5JF8007S_CHECK_FREQUENCY, | ||
37 | VA1J5JF8007S_SET_MODULATION, | ||
38 | VA1J5JF8007S_CHECK_MODULATION, | ||
39 | VA1J5JF8007S_SET_TS_ID, | ||
40 | VA1J5JF8007S_CHECK_TS_ID, | ||
41 | VA1J5JF8007S_TRACK, | ||
42 | }; | ||
43 | |||
44 | struct va1j5jf8007s_state { | ||
45 | const struct va1j5jf8007s_config *config; | ||
46 | struct i2c_adapter *adap; | ||
47 | struct dvb_frontend fe; | ||
48 | enum va1j5jf8007s_tune_state tune_state; | ||
49 | }; | ||
50 | |||
51 | static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) | ||
52 | { | ||
53 | return DVBFE_ALGO_HW; | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
58 | { | ||
59 | struct va1j5jf8007s_state *state; | ||
60 | |||
61 | state = fe->demodulator_priv; | ||
62 | |||
63 | switch (state->tune_state) { | ||
64 | case VA1J5JF8007S_IDLE: | ||
65 | case VA1J5JF8007S_SET_FREQUENCY_1: | ||
66 | case VA1J5JF8007S_SET_FREQUENCY_2: | ||
67 | case VA1J5JF8007S_SET_FREQUENCY_3: | ||
68 | case VA1J5JF8007S_CHECK_FREQUENCY: | ||
69 | *status = 0; | ||
70 | return 0; | ||
71 | |||
72 | |||
73 | case VA1J5JF8007S_SET_MODULATION: | ||
74 | case VA1J5JF8007S_CHECK_MODULATION: | ||
75 | *status |= FE_HAS_SIGNAL; | ||
76 | return 0; | ||
77 | |||
78 | case VA1J5JF8007S_SET_TS_ID: | ||
79 | case VA1J5JF8007S_CHECK_TS_ID: | ||
80 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
81 | return 0; | ||
82 | |||
83 | case VA1J5JF8007S_TRACK: | ||
84 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | BUG(); | ||
89 | } | ||
90 | |||
91 | struct va1j5jf8007s_cb_map { | ||
92 | u32 frequency; | ||
93 | u8 cb; | ||
94 | }; | ||
95 | |||
96 | static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = { | ||
97 | { 986000, 0xb2 }, | ||
98 | { 1072000, 0xd2 }, | ||
99 | { 1154000, 0xe2 }, | ||
100 | { 1291000, 0x20 }, | ||
101 | { 1447000, 0x40 }, | ||
102 | { 1615000, 0x60 }, | ||
103 | { 1791000, 0x80 }, | ||
104 | { 1972000, 0xa0 }, | ||
105 | }; | ||
106 | |||
107 | static u8 va1j5jf8007s_lookup_cb(u32 frequency) | ||
108 | { | ||
109 | int i; | ||
110 | const struct va1j5jf8007s_cb_map *map; | ||
111 | |||
112 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) { | ||
113 | map = &va1j5jf8007s_cb_maps[i]; | ||
114 | if (frequency < map->frequency) | ||
115 | return map->cb; | ||
116 | } | ||
117 | return 0xc0; | ||
118 | } | ||
119 | |||
120 | static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state) | ||
121 | { | ||
122 | u32 frequency; | ||
123 | u16 word; | ||
124 | u8 buf[6]; | ||
125 | struct i2c_msg msg; | ||
126 | |||
127 | frequency = state->fe.dtv_property_cache.frequency; | ||
128 | |||
129 | word = (frequency + 500) / 1000; | ||
130 | if (frequency < 1072000) | ||
131 | word = (word << 1 & ~0x1f) | (word & 0x0f); | ||
132 | |||
133 | buf[0] = 0xfe; | ||
134 | buf[1] = 0xc0; | ||
135 | buf[2] = 0x40 | word >> 8; | ||
136 | buf[3] = word; | ||
137 | buf[4] = 0xe0; | ||
138 | buf[5] = va1j5jf8007s_lookup_cb(frequency); | ||
139 | |||
140 | msg.addr = state->config->demod_address; | ||
141 | msg.flags = 0; | ||
142 | msg.len = sizeof(buf); | ||
143 | msg.buf = buf; | ||
144 | |||
145 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
146 | return -EREMOTEIO; | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state) | ||
152 | { | ||
153 | u8 buf[3]; | ||
154 | struct i2c_msg msg; | ||
155 | |||
156 | buf[0] = 0xfe; | ||
157 | buf[1] = 0xc0; | ||
158 | buf[2] = 0xe4; | ||
159 | |||
160 | msg.addr = state->config->demod_address; | ||
161 | msg.flags = 0; | ||
162 | msg.len = sizeof(buf); | ||
163 | msg.buf = buf; | ||
164 | |||
165 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
166 | return -EREMOTEIO; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state) | ||
172 | { | ||
173 | u32 frequency; | ||
174 | u8 buf[4]; | ||
175 | struct i2c_msg msg; | ||
176 | |||
177 | frequency = state->fe.dtv_property_cache.frequency; | ||
178 | |||
179 | buf[0] = 0xfe; | ||
180 | buf[1] = 0xc0; | ||
181 | buf[2] = 0xf4; | ||
182 | buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4; | ||
183 | |||
184 | msg.addr = state->config->demod_address; | ||
185 | msg.flags = 0; | ||
186 | msg.len = sizeof(buf); | ||
187 | msg.buf = buf; | ||
188 | |||
189 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
190 | return -EREMOTEIO; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int | ||
196 | va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock) | ||
197 | { | ||
198 | u8 addr; | ||
199 | u8 write_buf[2], read_buf[1]; | ||
200 | struct i2c_msg msgs[2]; | ||
201 | |||
202 | addr = state->config->demod_address; | ||
203 | |||
204 | write_buf[0] = 0xfe; | ||
205 | write_buf[1] = 0xc1; | ||
206 | |||
207 | msgs[0].addr = addr; | ||
208 | msgs[0].flags = 0; | ||
209 | msgs[0].len = sizeof(write_buf); | ||
210 | msgs[0].buf = write_buf; | ||
211 | |||
212 | msgs[1].addr = addr; | ||
213 | msgs[1].flags = I2C_M_RD; | ||
214 | msgs[1].len = sizeof(read_buf); | ||
215 | msgs[1].buf = read_buf; | ||
216 | |||
217 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
218 | return -EREMOTEIO; | ||
219 | |||
220 | *lock = read_buf[0] & 0x40; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state) | ||
225 | { | ||
226 | u8 buf[2]; | ||
227 | struct i2c_msg msg; | ||
228 | |||
229 | buf[0] = 0x03; | ||
230 | buf[1] = 0x01; | ||
231 | |||
232 | msg.addr = state->config->demod_address; | ||
233 | msg.flags = 0; | ||
234 | msg.len = sizeof(buf); | ||
235 | msg.buf = buf; | ||
236 | |||
237 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
238 | return -EREMOTEIO; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int | ||
244 | va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock) | ||
245 | { | ||
246 | u8 addr; | ||
247 | u8 write_buf[1], read_buf[1]; | ||
248 | struct i2c_msg msgs[2]; | ||
249 | |||
250 | addr = state->config->demod_address; | ||
251 | |||
252 | write_buf[0] = 0xc3; | ||
253 | |||
254 | msgs[0].addr = addr; | ||
255 | msgs[0].flags = 0; | ||
256 | msgs[0].len = sizeof(write_buf); | ||
257 | msgs[0].buf = write_buf; | ||
258 | |||
259 | msgs[1].addr = addr; | ||
260 | msgs[1].flags = I2C_M_RD; | ||
261 | msgs[1].len = sizeof(read_buf); | ||
262 | msgs[1].buf = read_buf; | ||
263 | |||
264 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
265 | return -EREMOTEIO; | ||
266 | |||
267 | *lock = !(read_buf[0] & 0x10); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state) | ||
273 | { | ||
274 | u32 ts_id; | ||
275 | u8 buf[3]; | ||
276 | struct i2c_msg msg; | ||
277 | |||
278 | ts_id = state->fe.dtv_property_cache.isdbs_ts_id; | ||
279 | if (!ts_id) | ||
280 | return 0; | ||
281 | |||
282 | buf[0] = 0x8f; | ||
283 | buf[1] = ts_id >> 8; | ||
284 | buf[2] = ts_id; | ||
285 | |||
286 | msg.addr = state->config->demod_address; | ||
287 | msg.flags = 0; | ||
288 | msg.len = sizeof(buf); | ||
289 | msg.buf = buf; | ||
290 | |||
291 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
292 | return -EREMOTEIO; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int | ||
298 | va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) | ||
299 | { | ||
300 | u8 addr; | ||
301 | u8 write_buf[1], read_buf[2]; | ||
302 | struct i2c_msg msgs[2]; | ||
303 | u32 ts_id; | ||
304 | |||
305 | ts_id = state->fe.dtv_property_cache.isdbs_ts_id; | ||
306 | if (!ts_id) { | ||
307 | *lock = 1; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | addr = state->config->demod_address; | ||
312 | |||
313 | write_buf[0] = 0xe6; | ||
314 | |||
315 | msgs[0].addr = addr; | ||
316 | msgs[0].flags = 0; | ||
317 | msgs[0].len = sizeof(write_buf); | ||
318 | msgs[0].buf = write_buf; | ||
319 | |||
320 | msgs[1].addr = addr; | ||
321 | msgs[1].flags = I2C_M_RD; | ||
322 | msgs[1].len = sizeof(read_buf); | ||
323 | msgs[1].buf = read_buf; | ||
324 | |||
325 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
326 | return -EREMOTEIO; | ||
327 | |||
328 | *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id; | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int | ||
333 | va1j5jf8007s_tune(struct dvb_frontend *fe, | ||
334 | struct dvb_frontend_parameters *params, | ||
335 | unsigned int mode_flags, unsigned int *delay, | ||
336 | fe_status_t *status) | ||
337 | { | ||
338 | struct va1j5jf8007s_state *state; | ||
339 | int ret; | ||
340 | int lock; | ||
341 | |||
342 | state = fe->demodulator_priv; | ||
343 | |||
344 | if (params != NULL) | ||
345 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; | ||
346 | |||
347 | switch (state->tune_state) { | ||
348 | case VA1J5JF8007S_IDLE: | ||
349 | *delay = 3 * HZ; | ||
350 | *status = 0; | ||
351 | return 0; | ||
352 | |||
353 | case VA1J5JF8007S_SET_FREQUENCY_1: | ||
354 | ret = va1j5jf8007s_set_frequency_1(state); | ||
355 | if (ret < 0) | ||
356 | return ret; | ||
357 | |||
358 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2; | ||
359 | *delay = 0; | ||
360 | *status = 0; | ||
361 | return 0; | ||
362 | |||
363 | case VA1J5JF8007S_SET_FREQUENCY_2: | ||
364 | ret = va1j5jf8007s_set_frequency_2(state); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3; | ||
369 | *delay = (HZ + 99) / 100; | ||
370 | *status = 0; | ||
371 | return 0; | ||
372 | |||
373 | case VA1J5JF8007S_SET_FREQUENCY_3: | ||
374 | ret = va1j5jf8007s_set_frequency_3(state); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY; | ||
379 | *delay = 0; | ||
380 | *status = 0; | ||
381 | return 0; | ||
382 | |||
383 | case VA1J5JF8007S_CHECK_FREQUENCY: | ||
384 | ret = va1j5jf8007s_check_frequency(state, &lock); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | |||
388 | if (!lock) { | ||
389 | *delay = (HZ + 999) / 1000; | ||
390 | *status = 0; | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | state->tune_state = VA1J5JF8007S_SET_MODULATION; | ||
395 | *delay = 0; | ||
396 | *status = FE_HAS_SIGNAL; | ||
397 | return 0; | ||
398 | |||
399 | case VA1J5JF8007S_SET_MODULATION: | ||
400 | ret = va1j5jf8007s_set_modulation(state); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | state->tune_state = VA1J5JF8007S_CHECK_MODULATION; | ||
405 | *delay = 0; | ||
406 | *status = FE_HAS_SIGNAL; | ||
407 | return 0; | ||
408 | |||
409 | case VA1J5JF8007S_CHECK_MODULATION: | ||
410 | ret = va1j5jf8007s_check_modulation(state, &lock); | ||
411 | if (ret < 0) | ||
412 | return ret; | ||
413 | |||
414 | if (!lock) { | ||
415 | *delay = (HZ + 49) / 50; | ||
416 | *status = FE_HAS_SIGNAL; | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | state->tune_state = VA1J5JF8007S_SET_TS_ID; | ||
421 | *delay = 0; | ||
422 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
423 | return 0; | ||
424 | |||
425 | case VA1J5JF8007S_SET_TS_ID: | ||
426 | ret = va1j5jf8007s_set_ts_id(state); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | |||
430 | state->tune_state = VA1J5JF8007S_CHECK_TS_ID; | ||
431 | return 0; | ||
432 | |||
433 | case VA1J5JF8007S_CHECK_TS_ID: | ||
434 | ret = va1j5jf8007s_check_ts_id(state, &lock); | ||
435 | if (ret < 0) | ||
436 | return ret; | ||
437 | |||
438 | if (!lock) { | ||
439 | *delay = (HZ + 99) / 100; | ||
440 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | state->tune_state = VA1J5JF8007S_TRACK; | ||
445 | /* fall through */ | ||
446 | |||
447 | case VA1J5JF8007S_TRACK: | ||
448 | *delay = 3 * HZ; | ||
449 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | BUG(); | ||
454 | } | ||
455 | |||
456 | static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state) | ||
457 | { | ||
458 | u8 buf[4]; | ||
459 | struct i2c_msg msg; | ||
460 | |||
461 | buf[0] = 0xfe; | ||
462 | buf[1] = 0xc0; | ||
463 | buf[2] = 0xf0; | ||
464 | buf[3] = 0x04; | ||
465 | |||
466 | msg.addr = state->config->demod_address; | ||
467 | msg.flags = 0; | ||
468 | msg.len = sizeof(buf); | ||
469 | msg.buf = buf; | ||
470 | |||
471 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
472 | return -EREMOTEIO; | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep) | ||
478 | { | ||
479 | u8 buf[2]; | ||
480 | struct i2c_msg msg; | ||
481 | |||
482 | buf[0] = 0x17; | ||
483 | buf[1] = sleep ? 0x01 : 0x00; | ||
484 | |||
485 | msg.addr = state->config->demod_address; | ||
486 | msg.flags = 0; | ||
487 | msg.len = sizeof(buf); | ||
488 | msg.buf = buf; | ||
489 | |||
490 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
491 | return -EREMOTEIO; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int va1j5jf8007s_sleep(struct dvb_frontend *fe) | ||
497 | { | ||
498 | struct va1j5jf8007s_state *state; | ||
499 | int ret; | ||
500 | |||
501 | state = fe->demodulator_priv; | ||
502 | |||
503 | ret = va1j5jf8007s_init_frequency(state); | ||
504 | if (ret < 0) | ||
505 | return ret; | ||
506 | |||
507 | return va1j5jf8007s_set_sleep(state, 1); | ||
508 | } | ||
509 | |||
510 | static int va1j5jf8007s_init(struct dvb_frontend *fe) | ||
511 | { | ||
512 | struct va1j5jf8007s_state *state; | ||
513 | |||
514 | state = fe->demodulator_priv; | ||
515 | state->tune_state = VA1J5JF8007S_IDLE; | ||
516 | |||
517 | return va1j5jf8007s_set_sleep(state, 0); | ||
518 | } | ||
519 | |||
520 | static void va1j5jf8007s_release(struct dvb_frontend *fe) | ||
521 | { | ||
522 | struct va1j5jf8007s_state *state; | ||
523 | state = fe->demodulator_priv; | ||
524 | kfree(state); | ||
525 | } | ||
526 | |||
527 | static struct dvb_frontend_ops va1j5jf8007s_ops = { | ||
528 | .info = { | ||
529 | .name = "VA1J5JF8007 ISDB-S", | ||
530 | .type = FE_QPSK, | ||
531 | .frequency_min = 950000, | ||
532 | .frequency_max = 2150000, | ||
533 | .frequency_stepsize = 1000, | ||
534 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | ||
535 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
536 | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, | ||
537 | }, | ||
538 | |||
539 | .get_frontend_algo = va1j5jf8007s_get_frontend_algo, | ||
540 | .read_status = va1j5jf8007s_read_status, | ||
541 | .tune = va1j5jf8007s_tune, | ||
542 | .sleep = va1j5jf8007s_sleep, | ||
543 | .init = va1j5jf8007s_init, | ||
544 | .release = va1j5jf8007s_release, | ||
545 | }; | ||
546 | |||
547 | static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) | ||
548 | { | ||
549 | u8 addr; | ||
550 | u8 write_buf[1], read_buf[1]; | ||
551 | struct i2c_msg msgs[2]; | ||
552 | |||
553 | addr = state->config->demod_address; | ||
554 | |||
555 | write_buf[0] = 0x07; | ||
556 | |||
557 | msgs[0].addr = addr; | ||
558 | msgs[0].flags = 0; | ||
559 | msgs[0].len = sizeof(write_buf); | ||
560 | msgs[0].buf = write_buf; | ||
561 | |||
562 | msgs[1].addr = addr; | ||
563 | msgs[1].flags = I2C_M_RD; | ||
564 | msgs[1].len = sizeof(read_buf); | ||
565 | msgs[1].buf = read_buf; | ||
566 | |||
567 | if (i2c_transfer(state->adap, msgs, 2) != 2) | ||
568 | return -EREMOTEIO; | ||
569 | |||
570 | if (read_buf[0] != 0x41) | ||
571 | return -EIO; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static const u8 va1j5jf8007s_prepare_bufs[][2] = { | ||
577 | {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, | ||
578 | {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, | ||
579 | {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, | ||
580 | {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, | ||
581 | }; | ||
582 | |||
583 | static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) | ||
584 | { | ||
585 | u8 addr; | ||
586 | u8 buf[2]; | ||
587 | struct i2c_msg msg; | ||
588 | int i; | ||
589 | |||
590 | addr = state->config->demod_address; | ||
591 | |||
592 | msg.addr = addr; | ||
593 | msg.flags = 0; | ||
594 | msg.len = 2; | ||
595 | msg.buf = buf; | ||
596 | for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) { | ||
597 | memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf)); | ||
598 | if (i2c_transfer(state->adap, &msg, 1) != 1) | ||
599 | return -EREMOTEIO; | ||
600 | } | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | /* must be called after va1j5jf8007t_attach */ | ||
606 | int va1j5jf8007s_prepare(struct dvb_frontend *fe) | ||
607 | { | ||
608 | struct va1j5jf8007s_state *state; | ||
609 | int ret; | ||
610 | |||
611 | state = fe->demodulator_priv; | ||
612 | |||
613 | ret = va1j5jf8007s_prepare_1(state); | ||
614 | if (ret < 0) | ||
615 | return ret; | ||
616 | |||
617 | ret = va1j5jf8007s_prepare_2(state); | ||
618 | if (ret < 0) | ||
619 | return ret; | ||
620 | |||
621 | return va1j5jf8007s_init_frequency(state); | ||
622 | } | ||
623 | |||
624 | struct dvb_frontend * | ||
625 | va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, | ||
626 | struct i2c_adapter *adap) | ||
627 | { | ||
628 | struct va1j5jf8007s_state *state; | ||
629 | struct dvb_frontend *fe; | ||
630 | u8 buf[2]; | ||
631 | struct i2c_msg msg; | ||
632 | |||
633 | state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL); | ||
634 | if (!state) | ||
635 | return NULL; | ||
636 | |||
637 | state->config = config; | ||
638 | state->adap = adap; | ||
639 | |||
640 | fe = &state->fe; | ||
641 | memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops)); | ||
642 | fe->demodulator_priv = state; | ||
643 | |||
644 | buf[0] = 0x01; | ||
645 | buf[1] = 0x80; | ||
646 | |||
647 | msg.addr = state->config->demod_address; | ||
648 | msg.flags = 0; | ||
649 | msg.len = sizeof(buf); | ||
650 | msg.buf = buf; | ||
651 | |||
652 | if (i2c_transfer(state->adap, &msg, 1) != 1) { | ||
653 | kfree(state); | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | return fe; | ||
658 | } | ||