Commit | Line | Data |
---|---|---|
f5d82a75 AT |
1 | /* |
2 | * Toshiba TC90522 Demodulator | |
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 | /* | |
18 | * NOTICE: | |
19 | * This driver is incomplete and lacks init/config of the chips, | |
20 | * as the necessary info is not disclosed. | |
21 | * It assumes that users of this driver (such as a PCI bridge of | |
22 | * DTV receiver cards) properly init and configure the chip | |
23 | * via I2C *before* calling this driver's init() function. | |
24 | * | |
25 | * Currently, PT3 driver is the only one that uses this driver, | |
26 | * and contains init/config code in its firmware. | |
27 | * Thus some part of the code might be dependent on PT3 specific config. | |
28 | */ | |
29 | ||
30 | #include <linux/kernel.h> | |
2ea12442 | 31 | #include <linux/math64.h> |
f5d82a75 AT |
32 | #include <linux/dvb/frontend.h> |
33 | #include "dvb_math.h" | |
34 | #include "tc90522.h" | |
35 | ||
36 | #define TC90522_I2C_THRU_REG 0xfe | |
37 | ||
38 | #define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1) | |
39 | ||
40 | struct tc90522_state { | |
41 | struct tc90522_config cfg; | |
42 | struct dvb_frontend fe; | |
43 | struct i2c_client *i2c_client; | |
44 | struct i2c_adapter tuner_i2c; | |
45 | ||
46 | bool lna; | |
47 | }; | |
48 | ||
49 | struct reg_val { | |
50 | u8 reg; | |
51 | u8 val; | |
52 | }; | |
53 | ||
54 | static int | |
55 | reg_write(struct tc90522_state *state, const struct reg_val *regs, int num) | |
56 | { | |
57 | int i, ret; | |
58 | struct i2c_msg msg; | |
59 | ||
60 | ret = 0; | |
61 | msg.addr = state->i2c_client->addr; | |
62 | msg.flags = 0; | |
63 | msg.len = 2; | |
64 | for (i = 0; i < num; i++) { | |
65 | msg.buf = (u8 *)®s[i]; | |
66 | ret = i2c_transfer(state->i2c_client->adapter, &msg, 1); | |
67 | if (ret == 0) | |
68 | ret = -EIO; | |
69 | if (ret < 0) | |
70 | return ret; | |
71 | } | |
72 | return 0; | |
73 | } | |
74 | ||
75 | static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len) | |
76 | { | |
77 | struct i2c_msg msgs[2] = { | |
78 | { | |
79 | .addr = state->i2c_client->addr, | |
80 | .flags = 0, | |
81 | .buf = ®, | |
82 | .len = 1, | |
83 | }, | |
84 | { | |
85 | .addr = state->i2c_client->addr, | |
86 | .flags = I2C_M_RD, | |
87 | .buf = val, | |
88 | .len = len, | |
89 | }, | |
90 | }; | |
91 | int ret; | |
92 | ||
93 | ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs)); | |
94 | if (ret == ARRAY_SIZE(msgs)) | |
95 | ret = 0; | |
96 | else if (ret >= 0) | |
97 | ret = -EIO; | |
98 | return ret; | |
99 | } | |
100 | ||
101 | static struct tc90522_state *cfg_to_state(struct tc90522_config *c) | |
102 | { | |
103 | return container_of(c, struct tc90522_state, cfg); | |
104 | } | |
105 | ||
106 | ||
107 | static int tc90522s_set_tsid(struct dvb_frontend *fe) | |
108 | { | |
109 | struct reg_val set_tsid[] = { | |
110 | { 0x8f, 00 }, | |
111 | { 0x90, 00 } | |
112 | }; | |
113 | ||
114 | set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8; | |
115 | set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff; | |
116 | return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid)); | |
117 | } | |
118 | ||
119 | static int tc90522t_set_layers(struct dvb_frontend *fe) | |
120 | { | |
121 | struct reg_val rv; | |
122 | u8 laysel; | |
123 | ||
124 | laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07; | |
125 | laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2; | |
126 | rv.reg = 0x71; | |
127 | rv.val = laysel; | |
128 | return reg_write(fe->demodulator_priv, &rv, 1); | |
129 | } | |
130 | ||
131 | /* frontend ops */ | |
132 | ||
0df289a2 | 133 | static int tc90522s_read_status(struct dvb_frontend *fe, enum fe_status *status) |
f5d82a75 AT |
134 | { |
135 | struct tc90522_state *state; | |
136 | int ret; | |
137 | u8 reg; | |
138 | ||
139 | state = fe->demodulator_priv; | |
140 | ret = reg_read(state, 0xc3, ®, 1); | |
141 | if (ret < 0) | |
142 | return ret; | |
143 | ||
144 | *status = 0; | |
145 | if (reg & 0x80) /* input level under min ? */ | |
146 | return 0; | |
147 | *status |= FE_HAS_SIGNAL; | |
148 | ||
149 | if (reg & 0x60) /* carrier? */ | |
150 | return 0; | |
151 | *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC; | |
152 | ||
153 | if (reg & 0x10) | |
154 | return 0; | |
155 | if (reg_read(state, 0xc5, ®, 1) < 0 || !(reg & 0x03)) | |
156 | return 0; | |
157 | *status |= FE_HAS_LOCK; | |
158 | return 0; | |
159 | } | |
160 | ||
0df289a2 | 161 | static int tc90522t_read_status(struct dvb_frontend *fe, enum fe_status *status) |
f5d82a75 AT |
162 | { |
163 | struct tc90522_state *state; | |
164 | int ret; | |
165 | u8 reg; | |
166 | ||
167 | state = fe->demodulator_priv; | |
168 | ret = reg_read(state, 0x96, ®, 1); | |
169 | if (ret < 0) | |
170 | return ret; | |
171 | ||
172 | *status = 0; | |
173 | if (reg & 0xe0) { | |
174 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | |
175 | | FE_HAS_SYNC | FE_HAS_LOCK; | |
176 | return 0; | |
177 | } | |
178 | ||
179 | ret = reg_read(state, 0x80, ®, 1); | |
180 | if (ret < 0) | |
181 | return ret; | |
182 | ||
183 | if (reg & 0xf0) | |
184 | return 0; | |
185 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
186 | ||
187 | if (reg & 0x0c) | |
188 | return 0; | |
189 | *status |= FE_HAS_SYNC | FE_HAS_VITERBI; | |
190 | ||
191 | if (reg & 0x02) | |
192 | return 0; | |
193 | *status |= FE_HAS_LOCK; | |
194 | return 0; | |
195 | } | |
196 | ||
0df289a2 | 197 | static const enum fe_code_rate fec_conv_sat[] = { |
f5d82a75 AT |
198 | FEC_NONE, /* unused */ |
199 | FEC_1_2, /* for BPSK */ | |
200 | FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */ | |
201 | FEC_2_3, /* for 8PSK. (trellis code) */ | |
202 | }; | |
203 | ||
7e3e68bc MCC |
204 | static int tc90522s_get_frontend(struct dvb_frontend *fe, |
205 | struct dtv_frontend_properties *c) | |
f5d82a75 AT |
206 | { |
207 | struct tc90522_state *state; | |
f5d82a75 AT |
208 | struct dtv_fe_stats *stats; |
209 | int ret, i; | |
210 | int layers; | |
211 | u8 val[10]; | |
212 | u32 cndat; | |
213 | ||
214 | state = fe->demodulator_priv; | |
f5d82a75 | 215 | c->delivery_system = SYS_ISDBS; |
e6010442 | 216 | c->symbol_rate = 28860000; |
f5d82a75 AT |
217 | |
218 | layers = 0; | |
906aaf5a | 219 | ret = reg_read(state, 0xe6, val, 5); |
f5d82a75 | 220 | if (ret == 0) { |
f5d82a75 AT |
221 | u8 v; |
222 | ||
906aaf5a AT |
223 | c->stream_id = val[0] << 8 | val[1]; |
224 | ||
f5d82a75 | 225 | /* high/single layer */ |
906aaf5a | 226 | v = (val[2] & 0x70) >> 4; |
f5d82a75 AT |
227 | c->modulation = (v == 7) ? PSK_8 : QPSK; |
228 | c->fec_inner = fec_conv_sat[v]; | |
229 | c->layer[0].fec = c->fec_inner; | |
230 | c->layer[0].modulation = c->modulation; | |
906aaf5a | 231 | c->layer[0].segment_count = val[3] & 0x3f; /* slots */ |
f5d82a75 AT |
232 | |
233 | /* low layer */ | |
906aaf5a | 234 | v = (val[2] & 0x07); |
f5d82a75 AT |
235 | c->layer[1].fec = fec_conv_sat[v]; |
236 | if (v == 0) /* no low layer */ | |
237 | c->layer[1].segment_count = 0; | |
238 | else | |
906aaf5a | 239 | c->layer[1].segment_count = val[4] & 0x3f; /* slots */ |
0df289a2 MCC |
240 | /* |
241 | * actually, BPSK if v==1, but not defined in | |
242 | * enum fe_modulation | |
243 | */ | |
f5d82a75 AT |
244 | c->layer[1].modulation = QPSK; |
245 | layers = (v > 0) ? 2 : 1; | |
f5d82a75 AT |
246 | } |
247 | ||
248 | /* statistics */ | |
249 | ||
250 | stats = &c->strength; | |
251 | stats->len = 0; | |
252 | /* let the connected tuner set RSSI property cache */ | |
253 | if (fe->ops.tuner_ops.get_rf_strength) { | |
254 | u16 dummy; | |
255 | ||
256 | fe->ops.tuner_ops.get_rf_strength(fe, &dummy); | |
257 | } | |
258 | ||
259 | stats = &c->cnr; | |
260 | stats->len = 1; | |
261 | stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
262 | cndat = 0; | |
263 | ret = reg_read(state, 0xbc, val, 2); | |
264 | if (ret == 0) | |
265 | cndat = val[0] << 8 | val[1]; | |
266 | if (cndat >= 3000) { | |
267 | u32 p, p4; | |
268 | s64 cn; | |
269 | ||
270 | cndat -= 3000; /* cndat: 4.12 fixed point float */ | |
271 | /* | |
272 | * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3 | |
273 | * + 88977 * P^2 - 89565 * P + 58857 | |
274 | * (P = sqrt(cndat) / 64) | |
275 | */ | |
276 | /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed point float */ | |
277 | /* cn = cnr << 3 */ | |
278 | p = int_sqrt(cndat << 16); | |
279 | p4 = cndat * cndat; | |
2ea12442 | 280 | cn = div64_s64(-16346LL * p4 * p, 10) >> 35; |
f5d82a75 AT |
281 | cn += (14341LL * p4) >> 21; |
282 | cn -= (50259LL * cndat * p) >> 23; | |
283 | cn += (88977LL * cndat) >> 9; | |
284 | cn -= (89565LL * p) >> 11; | |
285 | cn += 58857 << 3; | |
286 | stats->stat[0].svalue = cn >> 3; | |
287 | stats->stat[0].scale = FE_SCALE_DECIBEL; | |
288 | } | |
289 | ||
290 | /* per-layer post viterbi BER (or PER? config dependent?) */ | |
291 | stats = &c->post_bit_error; | |
292 | memset(stats, 0, sizeof(*stats)); | |
293 | stats->len = layers; | |
294 | ret = reg_read(state, 0xeb, val, 10); | |
295 | if (ret < 0) | |
296 | for (i = 0; i < layers; i++) | |
297 | stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; | |
298 | else { | |
299 | for (i = 0; i < layers; i++) { | |
300 | stats->stat[i].scale = FE_SCALE_COUNTER; | |
301 | stats->stat[i].uvalue = val[i * 5] << 16 | |
302 | | val[i * 5 + 1] << 8 | val[i * 5 + 2]; | |
303 | } | |
304 | } | |
305 | stats = &c->post_bit_count; | |
306 | memset(stats, 0, sizeof(*stats)); | |
307 | stats->len = layers; | |
308 | if (ret < 0) | |
309 | for (i = 0; i < layers; i++) | |
310 | stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; | |
311 | else { | |
312 | for (i = 0; i < layers; i++) { | |
313 | stats->stat[i].scale = FE_SCALE_COUNTER; | |
314 | stats->stat[i].uvalue = | |
315 | val[i * 5 + 3] << 8 | val[i * 5 + 4]; | |
316 | stats->stat[i].uvalue *= 204 * 8; | |
317 | } | |
318 | } | |
319 | ||
320 | return 0; | |
321 | } | |
322 | ||
323 | ||
0df289a2 | 324 | static const enum fe_transmit_mode tm_conv[] = { |
f5d82a75 AT |
325 | TRANSMISSION_MODE_2K, |
326 | TRANSMISSION_MODE_4K, | |
327 | TRANSMISSION_MODE_8K, | |
328 | 0 | |
329 | }; | |
330 | ||
0df289a2 | 331 | static const enum fe_code_rate fec_conv_ter[] = { |
f5d82a75 AT |
332 | FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0 |
333 | }; | |
334 | ||
0df289a2 | 335 | static const enum fe_modulation mod_conv[] = { |
f5d82a75 AT |
336 | DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0 |
337 | }; | |
338 | ||
7e3e68bc MCC |
339 | static int tc90522t_get_frontend(struct dvb_frontend *fe, |
340 | struct dtv_frontend_properties *c) | |
f5d82a75 AT |
341 | { |
342 | struct tc90522_state *state; | |
f5d82a75 AT |
343 | struct dtv_fe_stats *stats; |
344 | int ret, i; | |
345 | int layers; | |
346 | u8 val[15], mode; | |
347 | u32 cndat; | |
348 | ||
349 | state = fe->demodulator_priv; | |
f5d82a75 AT |
350 | c->delivery_system = SYS_ISDBT; |
351 | c->bandwidth_hz = 6000000; | |
352 | mode = 1; | |
353 | ret = reg_read(state, 0xb0, val, 1); | |
354 | if (ret == 0) { | |
355 | mode = (val[0] & 0xc0) >> 2; | |
356 | c->transmission_mode = tm_conv[mode]; | |
357 | c->guard_interval = (val[0] & 0x30) >> 4; | |
358 | } | |
359 | ||
360 | ret = reg_read(state, 0xb2, val, 6); | |
361 | layers = 0; | |
362 | if (ret == 0) { | |
363 | u8 v; | |
364 | ||
365 | c->isdbt_partial_reception = val[0] & 0x01; | |
01bd399a | 366 | c->isdbt_sb_mode = (val[0] & 0xc0) == 0x40; |
f5d82a75 AT |
367 | |
368 | /* layer A */ | |
369 | v = (val[2] & 0x78) >> 3; | |
370 | if (v == 0x0f) | |
371 | c->layer[0].segment_count = 0; | |
372 | else { | |
373 | layers++; | |
374 | c->layer[0].segment_count = v; | |
375 | c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2]; | |
376 | c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5]; | |
377 | v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7; | |
378 | c->layer[0].interleaving = v; | |
379 | } | |
380 | ||
381 | /* layer B */ | |
382 | v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6; | |
383 | if (v == 0x0f) | |
384 | c->layer[1].segment_count = 0; | |
385 | else { | |
386 | layers++; | |
387 | c->layer[1].segment_count = v; | |
388 | c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5]; | |
389 | c->layer[1].modulation = mod_conv[(val[2] & 0x07)]; | |
390 | c->layer[1].interleaving = (val[3] & 0x1c) >> 2; | |
391 | } | |
392 | ||
393 | /* layer C */ | |
394 | v = (val[5] & 0x1e) >> 1; | |
395 | if (v == 0x0f) | |
396 | c->layer[2].segment_count = 0; | |
397 | else { | |
398 | layers++; | |
399 | c->layer[2].segment_count = v; | |
400 | c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)]; | |
401 | c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3]; | |
402 | c->layer[2].interleaving = (val[5] & 0xe0) >> 5; | |
403 | } | |
404 | } | |
405 | ||
406 | /* statistics */ | |
407 | ||
408 | stats = &c->strength; | |
409 | stats->len = 0; | |
410 | /* let the connected tuner set RSSI property cache */ | |
411 | if (fe->ops.tuner_ops.get_rf_strength) { | |
412 | u16 dummy; | |
413 | ||
414 | fe->ops.tuner_ops.get_rf_strength(fe, &dummy); | |
415 | } | |
416 | ||
417 | stats = &c->cnr; | |
418 | stats->len = 1; | |
419 | stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
420 | cndat = 0; | |
421 | ret = reg_read(state, 0x8b, val, 3); | |
422 | if (ret == 0) | |
423 | cndat = val[0] << 16 | val[1] << 8 | val[2]; | |
424 | if (cndat != 0) { | |
425 | u32 p, tmp; | |
426 | s64 cn; | |
427 | ||
428 | /* | |
429 | * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5 | |
430 | * (P = 10log10(5505024/cndat)) | |
431 | */ | |
432 | /* cn = cnr << 3 (61.3 fixed point float */ | |
433 | /* p = 10log10(5505024/cndat) << 24 (8.24 fixed point float)*/ | |
434 | p = intlog10(5505024) - intlog10(cndat); | |
435 | p *= 10; | |
436 | ||
437 | cn = 24772; | |
2ea12442 | 438 | cn += div64_s64(43827LL * p, 10) >> 24; |
f5d82a75 | 439 | tmp = p >> 8; |
2ea12442 | 440 | cn += div64_s64(3184LL * tmp * tmp, 10) >> 32; |
f5d82a75 | 441 | tmp = p >> 13; |
2ea12442 | 442 | cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33; |
f5d82a75 | 443 | tmp = p >> 18; |
2ea12442 | 444 | cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24; |
f5d82a75 AT |
445 | |
446 | stats->stat[0].svalue = cn >> 3; | |
447 | stats->stat[0].scale = FE_SCALE_DECIBEL; | |
448 | } | |
449 | ||
450 | /* per-layer post viterbi BER (or PER? config dependent?) */ | |
451 | stats = &c->post_bit_error; | |
452 | memset(stats, 0, sizeof(*stats)); | |
453 | stats->len = layers; | |
454 | ret = reg_read(state, 0x9d, val, 15); | |
455 | if (ret < 0) | |
456 | for (i = 0; i < layers; i++) | |
457 | stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; | |
458 | else { | |
459 | for (i = 0; i < layers; i++) { | |
460 | stats->stat[i].scale = FE_SCALE_COUNTER; | |
461 | stats->stat[i].uvalue = val[i * 3] << 16 | |
462 | | val[i * 3 + 1] << 8 | val[i * 3 + 2]; | |
463 | } | |
464 | } | |
465 | stats = &c->post_bit_count; | |
466 | memset(stats, 0, sizeof(*stats)); | |
467 | stats->len = layers; | |
468 | if (ret < 0) | |
469 | for (i = 0; i < layers; i++) | |
470 | stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; | |
471 | else { | |
472 | for (i = 0; i < layers; i++) { | |
473 | stats->stat[i].scale = FE_SCALE_COUNTER; | |
474 | stats->stat[i].uvalue = | |
475 | val[9 + i * 2] << 8 | val[9 + i * 2 + 1]; | |
476 | stats->stat[i].uvalue *= 204 * 8; | |
477 | } | |
478 | } | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
483 | static const struct reg_val reset_sat = { 0x03, 0x01 }; | |
484 | static const struct reg_val reset_ter = { 0x01, 0x40 }; | |
485 | ||
486 | static int tc90522_set_frontend(struct dvb_frontend *fe) | |
487 | { | |
488 | struct tc90522_state *state; | |
489 | int ret; | |
490 | ||
491 | state = fe->demodulator_priv; | |
492 | ||
493 | if (fe->ops.tuner_ops.set_params) | |
494 | ret = fe->ops.tuner_ops.set_params(fe); | |
495 | else | |
496 | ret = -ENODEV; | |
497 | if (ret < 0) | |
498 | goto failed; | |
499 | ||
500 | if (fe->ops.delsys[0] == SYS_ISDBS) { | |
501 | ret = tc90522s_set_tsid(fe); | |
502 | if (ret < 0) | |
503 | goto failed; | |
504 | ret = reg_write(state, &reset_sat, 1); | |
505 | } else { | |
506 | ret = tc90522t_set_layers(fe); | |
507 | if (ret < 0) | |
508 | goto failed; | |
509 | ret = reg_write(state, &reset_ter, 1); | |
510 | } | |
511 | if (ret < 0) | |
512 | goto failed; | |
513 | ||
514 | return 0; | |
515 | ||
516 | failed: | |
517 | dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n", | |
518 | __func__, fe->dvb->num, fe->id); | |
519 | return ret; | |
520 | } | |
521 | ||
522 | static int tc90522_get_tune_settings(struct dvb_frontend *fe, | |
523 | struct dvb_frontend_tune_settings *settings) | |
524 | { | |
525 | if (fe->ops.delsys[0] == SYS_ISDBS) { | |
526 | settings->min_delay_ms = 250; | |
527 | settings->step_size = 1000; | |
528 | settings->max_drift = settings->step_size * 2; | |
529 | } else { | |
530 | settings->min_delay_ms = 400; | |
531 | settings->step_size = 142857; | |
532 | settings->max_drift = settings->step_size; | |
533 | } | |
534 | return 0; | |
535 | } | |
536 | ||
537 | static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on) | |
538 | { | |
539 | struct reg_val agc_sat[] = { | |
540 | { 0x0a, 0x00 }, | |
541 | { 0x10, 0x30 }, | |
542 | { 0x11, 0x00 }, | |
543 | { 0x03, 0x01 }, | |
544 | }; | |
545 | struct reg_val agc_ter[] = { | |
546 | { 0x25, 0x00 }, | |
547 | { 0x23, 0x4c }, | |
548 | { 0x01, 0x40 }, | |
549 | }; | |
550 | struct tc90522_state *state; | |
551 | struct reg_val *rv; | |
552 | int num; | |
553 | ||
554 | state = fe->demodulator_priv; | |
555 | if (fe->ops.delsys[0] == SYS_ISDBS) { | |
556 | agc_sat[0].val = on ? 0xff : 0x00; | |
557 | agc_sat[1].val |= 0x80; | |
558 | agc_sat[1].val |= on ? 0x01 : 0x00; | |
559 | agc_sat[2].val |= on ? 0x40 : 0x00; | |
560 | rv = agc_sat; | |
561 | num = ARRAY_SIZE(agc_sat); | |
562 | } else { | |
563 | agc_ter[0].val = on ? 0x40 : 0x00; | |
564 | agc_ter[1].val |= on ? 0x00 : 0x01; | |
565 | rv = agc_ter; | |
566 | num = ARRAY_SIZE(agc_ter); | |
567 | } | |
568 | return reg_write(state, rv, num); | |
569 | } | |
570 | ||
571 | static const struct reg_val sleep_sat = { 0x17, 0x01 }; | |
572 | static const struct reg_val sleep_ter = { 0x03, 0x90 }; | |
573 | ||
574 | static int tc90522_sleep(struct dvb_frontend *fe) | |
575 | { | |
576 | struct tc90522_state *state; | |
577 | int ret; | |
578 | ||
579 | state = fe->demodulator_priv; | |
580 | if (fe->ops.delsys[0] == SYS_ISDBS) | |
581 | ret = reg_write(state, &sleep_sat, 1); | |
582 | else { | |
583 | ret = reg_write(state, &sleep_ter, 1); | |
584 | if (ret == 0 && fe->ops.set_lna && | |
585 | fe->dtv_property_cache.lna == LNA_AUTO) { | |
586 | fe->dtv_property_cache.lna = 0; | |
587 | ret = fe->ops.set_lna(fe); | |
588 | fe->dtv_property_cache.lna = LNA_AUTO; | |
589 | } | |
590 | } | |
591 | if (ret < 0) | |
592 | dev_warn(&state->tuner_i2c.dev, | |
593 | "(%s) failed. [adap%d-fe%d]\n", | |
594 | __func__, fe->dvb->num, fe->id); | |
595 | return ret; | |
596 | } | |
597 | ||
598 | static const struct reg_val wakeup_sat = { 0x17, 0x00 }; | |
599 | static const struct reg_val wakeup_ter = { 0x03, 0x80 }; | |
600 | ||
601 | static int tc90522_init(struct dvb_frontend *fe) | |
602 | { | |
603 | struct tc90522_state *state; | |
604 | int ret; | |
605 | ||
606 | /* | |
607 | * Because the init sequence is not public, | |
608 | * the parent device/driver should have init'ed the device before. | |
609 | * just wake up the device here. | |
610 | */ | |
611 | ||
612 | state = fe->demodulator_priv; | |
613 | if (fe->ops.delsys[0] == SYS_ISDBS) | |
614 | ret = reg_write(state, &wakeup_sat, 1); | |
615 | else { | |
616 | ret = reg_write(state, &wakeup_ter, 1); | |
617 | if (ret == 0 && fe->ops.set_lna && | |
618 | fe->dtv_property_cache.lna == LNA_AUTO) { | |
619 | fe->dtv_property_cache.lna = 1; | |
620 | ret = fe->ops.set_lna(fe); | |
621 | fe->dtv_property_cache.lna = LNA_AUTO; | |
622 | } | |
623 | } | |
624 | if (ret < 0) { | |
625 | dev_warn(&state->tuner_i2c.dev, | |
626 | "(%s) failed. [adap%d-fe%d]\n", | |
627 | __func__, fe->dvb->num, fe->id); | |
628 | return ret; | |
629 | } | |
630 | ||
631 | /* prefer 'all-layers' to 'none' as a default */ | |
632 | if (fe->dtv_property_cache.isdbt_layer_enabled == 0) | |
633 | fe->dtv_property_cache.isdbt_layer_enabled = 7; | |
634 | return tc90522_set_if_agc(fe, true); | |
635 | } | |
636 | ||
637 | ||
638 | /* | |
639 | * tuner I2C adapter functions | |
640 | */ | |
641 | ||
642 | static int | |
643 | tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |
644 | { | |
645 | struct tc90522_state *state; | |
646 | struct i2c_msg *new_msgs; | |
647 | int i, j; | |
648 | int ret, rd_num; | |
649 | u8 wbuf[256]; | |
650 | u8 *p, *bufend; | |
651 | ||
652 | if (num <= 0) | |
653 | return -EINVAL; | |
654 | ||
655 | rd_num = 0; | |
656 | for (i = 0; i < num; i++) | |
657 | if (msgs[i].flags & I2C_M_RD) | |
658 | rd_num++; | |
659 | new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL); | |
660 | if (!new_msgs) | |
661 | return -ENOMEM; | |
662 | ||
663 | state = i2c_get_adapdata(adap); | |
664 | p = wbuf; | |
665 | bufend = wbuf + sizeof(wbuf); | |
666 | for (i = 0, j = 0; i < num; i++, j++) { | |
667 | new_msgs[j].addr = state->i2c_client->addr; | |
668 | new_msgs[j].flags = msgs[i].flags; | |
669 | ||
670 | if (msgs[i].flags & I2C_M_RD) { | |
671 | new_msgs[j].flags &= ~I2C_M_RD; | |
672 | if (p + 2 > bufend) | |
673 | break; | |
674 | p[0] = TC90522_I2C_THRU_REG; | |
675 | p[1] = msgs[i].addr << 1 | 0x01; | |
676 | new_msgs[j].buf = p; | |
677 | new_msgs[j].len = 2; | |
678 | p += 2; | |
679 | j++; | |
680 | new_msgs[j].addr = state->i2c_client->addr; | |
681 | new_msgs[j].flags = msgs[i].flags; | |
682 | new_msgs[j].buf = msgs[i].buf; | |
683 | new_msgs[j].len = msgs[i].len; | |
684 | continue; | |
685 | } | |
686 | ||
687 | if (p + msgs[i].len + 2 > bufend) | |
688 | break; | |
689 | p[0] = TC90522_I2C_THRU_REG; | |
690 | p[1] = msgs[i].addr << 1; | |
691 | memcpy(p + 2, msgs[i].buf, msgs[i].len); | |
692 | new_msgs[j].buf = p; | |
693 | new_msgs[j].len = msgs[i].len + 2; | |
694 | p += new_msgs[j].len; | |
695 | } | |
696 | ||
697 | if (i < num) | |
698 | ret = -ENOMEM; | |
699 | else | |
700 | ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j); | |
701 | if (ret >= 0 && ret < j) | |
702 | ret = -EIO; | |
703 | kfree(new_msgs); | |
704 | return (ret == j) ? num : ret; | |
705 | } | |
706 | ||
70dc5363 | 707 | static u32 tc90522_functionality(struct i2c_adapter *adap) |
f5d82a75 AT |
708 | { |
709 | return I2C_FUNC_I2C; | |
710 | } | |
711 | ||
712 | static const struct i2c_algorithm tc90522_tuner_i2c_algo = { | |
713 | .master_xfer = &tc90522_master_xfer, | |
714 | .functionality = &tc90522_functionality, | |
715 | }; | |
716 | ||
717 | ||
718 | /* | |
719 | * I2C driver functions | |
720 | */ | |
721 | ||
722 | static const struct dvb_frontend_ops tc90522_ops_sat = { | |
723 | .delsys = { SYS_ISDBS }, | |
724 | .info = { | |
725 | .name = "Toshiba TC90522 ISDB-S module", | |
726 | .frequency_min = 950000, | |
727 | .frequency_max = 2150000, | |
728 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | | |
729 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | |
730 | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, | |
731 | }, | |
732 | ||
733 | .init = tc90522_init, | |
734 | .sleep = tc90522_sleep, | |
735 | .set_frontend = tc90522_set_frontend, | |
736 | .get_tune_settings = tc90522_get_tune_settings, | |
737 | ||
738 | .get_frontend = tc90522s_get_frontend, | |
739 | .read_status = tc90522s_read_status, | |
740 | }; | |
741 | ||
742 | static const struct dvb_frontend_ops tc90522_ops_ter = { | |
743 | .delsys = { SYS_ISDBT }, | |
744 | .info = { | |
745 | .name = "Toshiba TC90522 ISDB-T module", | |
746 | .frequency_min = 470000000, | |
747 | .frequency_max = 770000000, | |
748 | .frequency_stepsize = 142857, | |
749 | .caps = FE_CAN_INVERSION_AUTO | | |
750 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | |
751 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | |
752 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | |
753 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | | |
754 | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | | |
755 | FE_CAN_HIERARCHY_AUTO, | |
756 | }, | |
757 | ||
758 | .init = tc90522_init, | |
759 | .sleep = tc90522_sleep, | |
760 | .set_frontend = tc90522_set_frontend, | |
761 | .get_tune_settings = tc90522_get_tune_settings, | |
762 | ||
763 | .get_frontend = tc90522t_get_frontend, | |
764 | .read_status = tc90522t_read_status, | |
765 | }; | |
766 | ||
767 | ||
768 | static int tc90522_probe(struct i2c_client *client, | |
769 | const struct i2c_device_id *id) | |
770 | { | |
771 | struct tc90522_state *state; | |
772 | struct tc90522_config *cfg; | |
773 | const struct dvb_frontend_ops *ops; | |
774 | struct i2c_adapter *adap; | |
775 | int ret; | |
776 | ||
777 | state = kzalloc(sizeof(*state), GFP_KERNEL); | |
778 | if (!state) | |
779 | return -ENOMEM; | |
780 | state->i2c_client = client; | |
781 | ||
782 | cfg = client->dev.platform_data; | |
783 | memcpy(&state->cfg, cfg, sizeof(state->cfg)); | |
784 | cfg->fe = state->cfg.fe = &state->fe; | |
785 | ops = id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter; | |
786 | memcpy(&state->fe.ops, ops, sizeof(*ops)); | |
787 | state->fe.demodulator_priv = state; | |
788 | ||
789 | adap = &state->tuner_i2c; | |
790 | adap->owner = THIS_MODULE; | |
791 | adap->algo = &tc90522_tuner_i2c_algo; | |
792 | adap->dev.parent = &client->dev; | |
793 | strlcpy(adap->name, "tc90522_sub", sizeof(adap->name)); | |
794 | i2c_set_adapdata(adap, state); | |
795 | ret = i2c_add_adapter(adap); | |
796 | if (ret < 0) | |
797 | goto err; | |
798 | cfg->tuner_i2c = state->cfg.tuner_i2c = adap; | |
799 | ||
800 | i2c_set_clientdata(client, &state->cfg); | |
801 | dev_info(&client->dev, "Toshiba TC90522 attached.\n"); | |
802 | return 0; | |
803 | ||
804 | err: | |
805 | kfree(state); | |
806 | return ret; | |
807 | } | |
808 | ||
809 | static int tc90522_remove(struct i2c_client *client) | |
810 | { | |
811 | struct tc90522_state *state; | |
812 | ||
813 | state = cfg_to_state(i2c_get_clientdata(client)); | |
814 | i2c_del_adapter(&state->tuner_i2c); | |
815 | kfree(state); | |
816 | return 0; | |
817 | } | |
818 | ||
819 | ||
820 | static const struct i2c_device_id tc90522_id[] = { | |
821 | { TC90522_I2C_DEV_SAT, 0 }, | |
822 | { TC90522_I2C_DEV_TER, 1 }, | |
823 | {} | |
824 | }; | |
825 | MODULE_DEVICE_TABLE(i2c, tc90522_id); | |
826 | ||
827 | static struct i2c_driver tc90522_driver = { | |
828 | .driver = { | |
829 | .name = "tc90522", | |
830 | }, | |
831 | .probe = tc90522_probe, | |
832 | .remove = tc90522_remove, | |
833 | .id_table = tc90522_id, | |
834 | }; | |
835 | ||
836 | module_i2c_driver(tc90522_driver); | |
837 | ||
838 | MODULE_DESCRIPTION("Toshiba TC90522 frontend"); | |
839 | MODULE_AUTHOR("Akihiro TSUKADA"); | |
840 | MODULE_LICENSE("GPL"); |