aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/pt1/va1j5jf8007t.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/pt1/va1j5jf8007t.c')
-rw-r--r--drivers/media/dvb/pt1/va1j5jf8007t.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c
new file mode 100644
index 000000000000..71117f4ca7e6
--- /dev/null
+++ b/drivers/media/dvb/pt1/va1j5jf8007t.c
@@ -0,0 +1,468 @@
1/*
2 * ISDB-T 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 "dvb_math.h"
30#include "va1j5jf8007t.h"
31
32enum va1j5jf8007t_tune_state {
33 VA1J5JF8007T_IDLE,
34 VA1J5JF8007T_SET_FREQUENCY,
35 VA1J5JF8007T_CHECK_FREQUENCY,
36 VA1J5JF8007T_SET_MODULATION,
37 VA1J5JF8007T_CHECK_MODULATION,
38 VA1J5JF8007T_TRACK,
39 VA1J5JF8007T_ABORT,
40};
41
42struct va1j5jf8007t_state {
43 const struct va1j5jf8007t_config *config;
44 struct i2c_adapter *adap;
45 struct dvb_frontend fe;
46 enum va1j5jf8007t_tune_state tune_state;
47};
48
49static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
50{
51 return DVBFE_ALGO_HW;
52}
53
54static int
55va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)
56{
57 struct va1j5jf8007t_state *state;
58
59 state = fe->demodulator_priv;
60
61 switch (state->tune_state) {
62 case VA1J5JF8007T_IDLE:
63 case VA1J5JF8007T_SET_FREQUENCY:
64 case VA1J5JF8007T_CHECK_FREQUENCY:
65 *status = 0;
66 return 0;
67
68
69 case VA1J5JF8007T_SET_MODULATION:
70 case VA1J5JF8007T_CHECK_MODULATION:
71 case VA1J5JF8007T_ABORT:
72 *status |= FE_HAS_SIGNAL;
73 return 0;
74
75 case VA1J5JF8007T_TRACK:
76 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
77 return 0;
78 }
79
80 BUG();
81}
82
83struct va1j5jf8007t_cb_map {
84 u32 frequency;
85 u8 cb;
86};
87
88static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {
89 { 90000000, 0x80 },
90 { 140000000, 0x81 },
91 { 170000000, 0xa1 },
92 { 220000000, 0x62 },
93 { 330000000, 0xa2 },
94 { 402000000, 0xe2 },
95 { 450000000, 0x64 },
96 { 550000000, 0x84 },
97 { 600000000, 0xa4 },
98 { 700000000, 0xc4 },
99};
100
101static u8 va1j5jf8007t_lookup_cb(u32 frequency)
102{
103 int i;
104 const struct va1j5jf8007t_cb_map *map;
105
106 for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {
107 map = &va1j5jf8007t_cb_maps[i];
108 if (frequency < map->frequency)
109 return map->cb;
110 }
111 return 0xe4;
112}
113
114static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)
115{
116 u32 frequency;
117 u16 word;
118 u8 buf[6];
119 struct i2c_msg msg;
120
121 frequency = state->fe.dtv_property_cache.frequency;
122
123 word = (frequency + 71428) / 142857 + 399;
124 buf[0] = 0xfe;
125 buf[1] = 0xc2;
126 buf[2] = word >> 8;
127 buf[3] = word;
128 buf[4] = 0x80;
129 buf[5] = va1j5jf8007t_lookup_cb(frequency);
130
131 msg.addr = state->config->demod_address;
132 msg.flags = 0;
133 msg.len = sizeof(buf);
134 msg.buf = buf;
135
136 if (i2c_transfer(state->adap, &msg, 1) != 1)
137 return -EREMOTEIO;
138
139 return 0;
140}
141
142static int
143va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)
144{
145 u8 addr;
146 u8 write_buf[2], read_buf[1];
147 struct i2c_msg msgs[2];
148
149 addr = state->config->demod_address;
150
151 write_buf[0] = 0xfe;
152 write_buf[1] = 0xc3;
153
154 msgs[0].addr = addr;
155 msgs[0].flags = 0;
156 msgs[0].len = sizeof(write_buf);
157 msgs[0].buf = write_buf;
158
159 msgs[1].addr = addr;
160 msgs[1].flags = I2C_M_RD;
161 msgs[1].len = sizeof(read_buf);
162 msgs[1].buf = read_buf;
163
164 if (i2c_transfer(state->adap, msgs, 2) != 2)
165 return -EREMOTEIO;
166
167 *lock = read_buf[0] & 0x40;
168 return 0;
169}
170
171static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)
172{
173 u8 buf[2];
174 struct i2c_msg msg;
175
176 buf[0] = 0x01;
177 buf[1] = 0x40;
178
179 msg.addr = state->config->demod_address;
180 msg.flags = 0;
181 msg.len = sizeof(buf);
182 msg.buf = buf;
183
184 if (i2c_transfer(state->adap, &msg, 1) != 1)
185 return -EREMOTEIO;
186
187 return 0;
188}
189
190static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
191 int *lock, int *retry)
192{
193 u8 addr;
194 u8 write_buf[1], read_buf[1];
195 struct i2c_msg msgs[2];
196
197 addr = state->config->demod_address;
198
199 write_buf[0] = 0x80;
200
201 msgs[0].addr = addr;
202 msgs[0].flags = 0;
203 msgs[0].len = sizeof(write_buf);
204 msgs[0].buf = write_buf;
205
206 msgs[1].addr = addr;
207 msgs[1].flags = I2C_M_RD;
208 msgs[1].len = sizeof(read_buf);
209 msgs[1].buf = read_buf;
210
211 if (i2c_transfer(state->adap, msgs, 2) != 2)
212 return -EREMOTEIO;
213
214 *lock = !(read_buf[0] & 0x10);
215 *retry = read_buf[0] & 0x80;
216 return 0;
217}
218
219static int
220va1j5jf8007t_tune(struct dvb_frontend *fe,
221 struct dvb_frontend_parameters *params,
222 unsigned int mode_flags, unsigned int *delay,
223 fe_status_t *status)
224{
225 struct va1j5jf8007t_state *state;
226 int ret;
227 int lock, retry;
228
229 state = fe->demodulator_priv;
230
231 if (params != NULL)
232 state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
233
234 switch (state->tune_state) {
235 case VA1J5JF8007T_IDLE:
236 *delay = 3 * HZ;
237 *status = 0;
238 return 0;
239
240 case VA1J5JF8007T_SET_FREQUENCY:
241 ret = va1j5jf8007t_set_frequency(state);
242 if (ret < 0)
243 return ret;
244
245 state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;
246 *delay = 0;
247 *status = 0;
248 return 0;
249
250 case VA1J5JF8007T_CHECK_FREQUENCY:
251 ret = va1j5jf8007t_check_frequency(state, &lock);
252 if (ret < 0)
253 return ret;
254
255 if (!lock) {
256 *delay = (HZ + 999) / 1000;
257 *status = 0;
258 return 0;
259 }
260
261 state->tune_state = VA1J5JF8007T_SET_MODULATION;
262 *delay = 0;
263 *status = FE_HAS_SIGNAL;
264 return 0;
265
266 case VA1J5JF8007T_SET_MODULATION:
267 ret = va1j5jf8007t_set_modulation(state);
268 if (ret < 0)
269 return ret;
270
271 state->tune_state = VA1J5JF8007T_CHECK_MODULATION;
272 *delay = 0;
273 *status = FE_HAS_SIGNAL;
274 return 0;
275
276 case VA1J5JF8007T_CHECK_MODULATION:
277 ret = va1j5jf8007t_check_modulation(state, &lock, &retry);
278 if (ret < 0)
279 return ret;
280
281 if (!lock) {
282 if (!retry) {
283 state->tune_state = VA1J5JF8007T_ABORT;
284 *delay = 3 * HZ;
285 *status = FE_HAS_SIGNAL;
286 return 0;
287 }
288 *delay = (HZ + 999) / 1000;
289 *status = FE_HAS_SIGNAL;
290 return 0;
291 }
292
293 state->tune_state = VA1J5JF8007T_TRACK;
294 /* fall through */
295
296 case VA1J5JF8007T_TRACK:
297 *delay = 3 * HZ;
298 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
299 return 0;
300
301 case VA1J5JF8007T_ABORT:
302 *delay = 3 * HZ;
303 *status = FE_HAS_SIGNAL;
304 return 0;
305 }
306
307 BUG();
308}
309
310static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)
311{
312 u8 buf[7];
313 struct i2c_msg msg;
314
315 buf[0] = 0xfe;
316 buf[1] = 0xc2;
317 buf[2] = 0x01;
318 buf[3] = 0x8f;
319 buf[4] = 0xc1;
320 buf[5] = 0x80;
321 buf[6] = 0x80;
322
323 msg.addr = state->config->demod_address;
324 msg.flags = 0;
325 msg.len = sizeof(buf);
326 msg.buf = buf;
327
328 if (i2c_transfer(state->adap, &msg, 1) != 1)
329 return -EREMOTEIO;
330
331 return 0;
332}
333
334static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)
335{
336 u8 buf[2];
337 struct i2c_msg msg;
338
339 buf[0] = 0x03;
340 buf[1] = sleep ? 0x90 : 0x80;
341
342 msg.addr = state->config->demod_address;
343 msg.flags = 0;
344 msg.len = sizeof(buf);
345 msg.buf = buf;
346
347 if (i2c_transfer(state->adap, &msg, 1) != 1)
348 return -EREMOTEIO;
349
350 return 0;
351}
352
353static int va1j5jf8007t_sleep(struct dvb_frontend *fe)
354{
355 struct va1j5jf8007t_state *state;
356 int ret;
357
358 state = fe->demodulator_priv;
359
360 ret = va1j5jf8007t_init_frequency(state);
361 if (ret < 0)
362 return ret;
363
364 return va1j5jf8007t_set_sleep(state, 1);
365}
366
367static int va1j5jf8007t_init(struct dvb_frontend *fe)
368{
369 struct va1j5jf8007t_state *state;
370
371 state = fe->demodulator_priv;
372 state->tune_state = VA1J5JF8007T_IDLE;
373
374 return va1j5jf8007t_set_sleep(state, 0);
375}
376
377static void va1j5jf8007t_release(struct dvb_frontend *fe)
378{
379 struct va1j5jf8007t_state *state;
380 state = fe->demodulator_priv;
381 kfree(state);
382}
383
384static struct dvb_frontend_ops va1j5jf8007t_ops = {
385 .info = {
386 .name = "VA1J5JF8007 ISDB-T",
387 .type = FE_OFDM,
388 .frequency_min = 90000000,
389 .frequency_max = 770000000,
390 .frequency_stepsize = 142857,
391 .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
392 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
393 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
394 },
395
396 .get_frontend_algo = va1j5jf8007t_get_frontend_algo,
397 .read_status = va1j5jf8007t_read_status,
398 .tune = va1j5jf8007t_tune,
399 .sleep = va1j5jf8007t_sleep,
400 .init = va1j5jf8007t_init,
401 .release = va1j5jf8007t_release,
402};
403
404static const u8 va1j5jf8007t_prepare_bufs[][2] = {
405 {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
406 {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
407 {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
408 {0xef, 0x01}
409};
410
411int va1j5jf8007t_prepare(struct dvb_frontend *fe)
412{
413 struct va1j5jf8007t_state *state;
414 u8 buf[2];
415 struct i2c_msg msg;
416 int i;
417
418 state = fe->demodulator_priv;
419
420 msg.addr = state->config->demod_address;
421 msg.flags = 0;
422 msg.len = sizeof(buf);
423 msg.buf = buf;
424
425 for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) {
426 memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf));
427 if (i2c_transfer(state->adap, &msg, 1) != 1)
428 return -EREMOTEIO;
429 }
430
431 return va1j5jf8007t_init_frequency(state);
432}
433
434struct dvb_frontend *
435va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
436 struct i2c_adapter *adap)
437{
438 struct va1j5jf8007t_state *state;
439 struct dvb_frontend *fe;
440 u8 buf[2];
441 struct i2c_msg msg;
442
443 state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);
444 if (!state)
445 return NULL;
446
447 state->config = config;
448 state->adap = adap;
449
450 fe = &state->fe;
451 memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));
452 fe->demodulator_priv = state;
453
454 buf[0] = 0x01;
455 buf[1] = 0x80;
456
457 msg.addr = state->config->demod_address;
458 msg.flags = 0;
459 msg.len = sizeof(buf);
460 msg.buf = buf;
461
462 if (i2c_transfer(state->adap, &msg, 1) != 1) {
463 kfree(state);
464 return NULL;
465 }
466
467 return fe;
468}