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