diff options
-rw-r--r-- | drivers/media/dvb/frontends/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10071.c | 1266 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10071.h | 81 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10071_priv.h | 122 |
5 files changed, 1477 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 8e1a18337246..28fbb5c8c0a3 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -236,6 +236,13 @@ config DVB_MB86A16 | |||
236 | A DVB-S/DSS Direct Conversion reveiver. | 236 | A DVB-S/DSS Direct Conversion reveiver. |
237 | Say Y when you want to support this frontend. | 237 | Say Y when you want to support this frontend. |
238 | 238 | ||
239 | config DVB_TDA10071 | ||
240 | tristate "NXP TDA10071" | ||
241 | depends on DVB_CORE && I2C | ||
242 | default m if DVB_FE_CUSTOMISE | ||
243 | help | ||
244 | Say Y when you want to support this frontend. | ||
245 | |||
239 | comment "DVB-T (terrestrial) frontends" | 246 | comment "DVB-T (terrestrial) frontends" |
240 | depends on DVB_CORE | 247 | depends on DVB_CORE |
241 | 248 | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 08040cf1fd69..36c8d81e096a 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -93,4 +93,5 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o | |||
93 | obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o | 93 | obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o |
94 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o | 94 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o |
95 | obj-$(CONFIG_DVB_A8293) += a8293.o | 95 | obj-$(CONFIG_DVB_A8293) += a8293.o |
96 | obj-$(CONFIG_DVB_TDA10071) += tda10071.o | ||
96 | 97 | ||
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c new file mode 100644 index 000000000000..26b52cc83c61 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071.c | |||
@@ -0,0 +1,1266 @@ | |||
1 | /* | ||
2 | * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "tda10071_priv.h" | ||
22 | |||
23 | int tda10071_debug; | ||
24 | module_param_named(debug, tda10071_debug, int, 0644); | ||
25 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
26 | |||
27 | static struct dvb_frontend_ops tda10071_ops; | ||
28 | |||
29 | /* write multiple registers */ | ||
30 | static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val, | ||
31 | int len) | ||
32 | { | ||
33 | int ret; | ||
34 | u8 buf[len+1]; | ||
35 | struct i2c_msg msg[1] = { | ||
36 | { | ||
37 | .addr = priv->cfg.i2c_address, | ||
38 | .flags = 0, | ||
39 | .len = sizeof(buf), | ||
40 | .buf = buf, | ||
41 | } | ||
42 | }; | ||
43 | |||
44 | buf[0] = reg; | ||
45 | memcpy(&buf[1], val, len); | ||
46 | |||
47 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
48 | if (ret == 1) { | ||
49 | ret = 0; | ||
50 | } else { | ||
51 | warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); | ||
52 | ret = -EREMOTEIO; | ||
53 | } | ||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | /* read multiple registers */ | ||
58 | static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val, | ||
59 | int len) | ||
60 | { | ||
61 | int ret; | ||
62 | u8 buf[len]; | ||
63 | struct i2c_msg msg[2] = { | ||
64 | { | ||
65 | .addr = priv->cfg.i2c_address, | ||
66 | .flags = 0, | ||
67 | .len = 1, | ||
68 | .buf = ®, | ||
69 | }, { | ||
70 | .addr = priv->cfg.i2c_address, | ||
71 | .flags = I2C_M_RD, | ||
72 | .len = sizeof(buf), | ||
73 | .buf = buf, | ||
74 | } | ||
75 | }; | ||
76 | |||
77 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
78 | if (ret == 2) { | ||
79 | memcpy(val, buf, len); | ||
80 | ret = 0; | ||
81 | } else { | ||
82 | warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); | ||
83 | ret = -EREMOTEIO; | ||
84 | } | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | /* write single register */ | ||
89 | static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val) | ||
90 | { | ||
91 | return tda10071_wr_regs(priv, reg, &val, 1); | ||
92 | } | ||
93 | |||
94 | /* read single register */ | ||
95 | static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val) | ||
96 | { | ||
97 | return tda10071_rd_regs(priv, reg, val, 1); | ||
98 | } | ||
99 | |||
100 | /* write single register with mask */ | ||
101 | int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask) | ||
102 | { | ||
103 | int ret; | ||
104 | u8 tmp; | ||
105 | |||
106 | /* no need for read if whole reg is written */ | ||
107 | if (mask != 0xff) { | ||
108 | ret = tda10071_rd_regs(priv, reg, &tmp, 1); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | |||
112 | val &= mask; | ||
113 | tmp &= ~mask; | ||
114 | val |= tmp; | ||
115 | } | ||
116 | |||
117 | return tda10071_wr_regs(priv, reg, &val, 1); | ||
118 | } | ||
119 | |||
120 | /* read single register with mask */ | ||
121 | int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask) | ||
122 | { | ||
123 | int ret, i; | ||
124 | u8 tmp; | ||
125 | |||
126 | ret = tda10071_rd_regs(priv, reg, &tmp, 1); | ||
127 | if (ret) | ||
128 | return ret; | ||
129 | |||
130 | tmp &= mask; | ||
131 | |||
132 | /* find position of the first bit */ | ||
133 | for (i = 0; i < 8; i++) { | ||
134 | if ((mask >> i) & 0x01) | ||
135 | break; | ||
136 | } | ||
137 | *val = tmp >> i; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /* execute firmware command */ | ||
143 | static int tda10071_cmd_execute(struct tda10071_priv *priv, | ||
144 | struct tda10071_cmd *cmd) | ||
145 | { | ||
146 | int ret, i; | ||
147 | u8 tmp; | ||
148 | |||
149 | if (!priv->warm) { | ||
150 | ret = -EFAULT; | ||
151 | goto error; | ||
152 | } | ||
153 | |||
154 | /* write cmd and args for firmware */ | ||
155 | ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len); | ||
156 | if (ret) | ||
157 | goto error; | ||
158 | |||
159 | /* start cmd execution */ | ||
160 | ret = tda10071_wr_reg(priv, 0x1f, 1); | ||
161 | if (ret) | ||
162 | goto error; | ||
163 | |||
164 | /* wait cmd execution terminate */ | ||
165 | for (i = 1000, tmp = 1; i && tmp; i--) { | ||
166 | ret = tda10071_rd_reg(priv, 0x1f, &tmp); | ||
167 | if (ret) | ||
168 | goto error; | ||
169 | |||
170 | msleep(1); | ||
171 | } | ||
172 | |||
173 | dbg("%s: loop=%d", __func__, i); | ||
174 | |||
175 | if (i == 0) { | ||
176 | ret = -ETIMEDOUT; | ||
177 | goto error; | ||
178 | } | ||
179 | |||
180 | return ret; | ||
181 | error: | ||
182 | dbg("%s: failed=%d", __func__, ret); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | static int tda10071_set_tone(struct dvb_frontend *fe, | ||
187 | fe_sec_tone_mode_t fe_sec_tone_mode) | ||
188 | { | ||
189 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
190 | struct tda10071_cmd cmd; | ||
191 | int ret; | ||
192 | u8 tone; | ||
193 | |||
194 | if (!priv->warm) { | ||
195 | ret = -EFAULT; | ||
196 | goto error; | ||
197 | } | ||
198 | |||
199 | dbg("%s: tone_mode=%d", __func__, fe_sec_tone_mode); | ||
200 | |||
201 | switch (fe_sec_tone_mode) { | ||
202 | case SEC_TONE_ON: | ||
203 | tone = 1; | ||
204 | break; | ||
205 | case SEC_TONE_OFF: | ||
206 | tone = 0; | ||
207 | break; | ||
208 | default: | ||
209 | dbg("%s: invalid fe_sec_tone_mode", __func__); | ||
210 | ret = -EINVAL; | ||
211 | goto error; | ||
212 | } | ||
213 | |||
214 | cmd.args[0x00] = CMD_LNB_PCB_CONFIG; | ||
215 | cmd.args[0x01] = 0; | ||
216 | cmd.args[0x02] = 0x00; | ||
217 | cmd.args[0x03] = 0x00; | ||
218 | cmd.args[0x04] = tone; | ||
219 | cmd.len = 0x05; | ||
220 | ret = tda10071_cmd_execute(priv, &cmd); | ||
221 | if (ret) | ||
222 | goto error; | ||
223 | |||
224 | return ret; | ||
225 | error: | ||
226 | dbg("%s: failed=%d", __func__, ret); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int tda10071_set_voltage(struct dvb_frontend *fe, | ||
231 | fe_sec_voltage_t fe_sec_voltage) | ||
232 | { | ||
233 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
234 | struct tda10071_cmd cmd; | ||
235 | int ret; | ||
236 | u8 voltage; | ||
237 | |||
238 | if (!priv->warm) { | ||
239 | ret = -EFAULT; | ||
240 | goto error; | ||
241 | } | ||
242 | |||
243 | dbg("%s: voltage=%d", __func__, fe_sec_voltage); | ||
244 | |||
245 | switch (fe_sec_voltage) { | ||
246 | case SEC_VOLTAGE_13: | ||
247 | voltage = 0; | ||
248 | break; | ||
249 | case SEC_VOLTAGE_18: | ||
250 | voltage = 1; | ||
251 | break; | ||
252 | case SEC_VOLTAGE_OFF: | ||
253 | voltage = 0; | ||
254 | break; | ||
255 | default: | ||
256 | dbg("%s: invalid fe_sec_voltage", __func__); | ||
257 | ret = -EINVAL; | ||
258 | goto error; | ||
259 | }; | ||
260 | |||
261 | cmd.args[0x00] = CMD_LNB_SET_DC_LEVEL; | ||
262 | cmd.args[0x01] = 0; | ||
263 | cmd.args[0x02] = voltage; | ||
264 | cmd.len = 0x03; | ||
265 | ret = tda10071_cmd_execute(priv, &cmd); | ||
266 | if (ret) | ||
267 | goto error; | ||
268 | |||
269 | return ret; | ||
270 | error: | ||
271 | dbg("%s: failed=%d", __func__, ret); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, | ||
276 | struct dvb_diseqc_master_cmd *diseqc_cmd) | ||
277 | { | ||
278 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
279 | struct tda10071_cmd cmd; | ||
280 | int ret, i; | ||
281 | u8 tmp; | ||
282 | |||
283 | if (!priv->warm) { | ||
284 | ret = -EFAULT; | ||
285 | goto error; | ||
286 | } | ||
287 | |||
288 | dbg("%s: msg_len=%d", __func__, diseqc_cmd->msg_len); | ||
289 | |||
290 | if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 16) { | ||
291 | ret = -EINVAL; | ||
292 | goto error; | ||
293 | } | ||
294 | |||
295 | /* wait LNB TX */ | ||
296 | for (i = 500, tmp = 0; i && !tmp; i--) { | ||
297 | ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01); | ||
298 | if (ret) | ||
299 | goto error; | ||
300 | |||
301 | msleep(10); | ||
302 | } | ||
303 | |||
304 | dbg("%s: loop=%d", __func__, i); | ||
305 | |||
306 | if (i == 0) { | ||
307 | ret = -ETIMEDOUT; | ||
308 | goto error; | ||
309 | } | ||
310 | |||
311 | ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01); | ||
312 | if (ret) | ||
313 | goto error; | ||
314 | |||
315 | cmd.args[0x00] = CMD_LNB_SEND_DISEQC; | ||
316 | cmd.args[0x01] = 0; | ||
317 | cmd.args[0x02] = 0; | ||
318 | cmd.args[0x03] = 0; | ||
319 | cmd.args[0x04] = 2; | ||
320 | cmd.args[0x05] = 0; | ||
321 | cmd.args[0x06] = diseqc_cmd->msg_len; | ||
322 | memcpy(&cmd.args[0x07], diseqc_cmd->msg, diseqc_cmd->msg_len); | ||
323 | cmd.len = 0x07 + diseqc_cmd->msg_len; | ||
324 | ret = tda10071_cmd_execute(priv, &cmd); | ||
325 | if (ret) | ||
326 | goto error; | ||
327 | |||
328 | return ret; | ||
329 | error: | ||
330 | dbg("%s: failed=%d", __func__, ret); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, | ||
335 | struct dvb_diseqc_slave_reply *reply) | ||
336 | { | ||
337 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
338 | struct tda10071_cmd cmd; | ||
339 | int ret, i; | ||
340 | u8 tmp; | ||
341 | |||
342 | if (!priv->warm) { | ||
343 | ret = -EFAULT; | ||
344 | goto error; | ||
345 | } | ||
346 | |||
347 | dbg("%s:", __func__); | ||
348 | |||
349 | /* wait LNB RX */ | ||
350 | for (i = 500, tmp = 0; i && !tmp; i--) { | ||
351 | ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02); | ||
352 | if (ret) | ||
353 | goto error; | ||
354 | |||
355 | msleep(10); | ||
356 | } | ||
357 | |||
358 | dbg("%s: loop=%d", __func__, i); | ||
359 | |||
360 | if (i == 0) { | ||
361 | ret = -ETIMEDOUT; | ||
362 | goto error; | ||
363 | } | ||
364 | |||
365 | /* reply len */ | ||
366 | ret = tda10071_rd_reg(priv, 0x46, &tmp); | ||
367 | if (ret) | ||
368 | goto error; | ||
369 | |||
370 | reply->msg_len = tmp & 0x1f; /* [4:0] */; | ||
371 | if (reply->msg_len > sizeof(reply->msg)) | ||
372 | reply->msg_len = sizeof(reply->msg); /* truncate API max */ | ||
373 | |||
374 | /* read reply */ | ||
375 | cmd.args[0x00] = CMD_LNB_UPDATE_REPLY; | ||
376 | cmd.args[0x01] = 0; | ||
377 | cmd.len = 0x02; | ||
378 | ret = tda10071_cmd_execute(priv, &cmd); | ||
379 | if (ret) | ||
380 | goto error; | ||
381 | |||
382 | ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len); | ||
383 | if (ret) | ||
384 | goto error; | ||
385 | |||
386 | return ret; | ||
387 | error: | ||
388 | dbg("%s: failed=%d", __func__, ret); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, | ||
393 | fe_sec_mini_cmd_t fe_sec_mini_cmd) | ||
394 | { | ||
395 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
396 | struct tda10071_cmd cmd; | ||
397 | int ret, i; | ||
398 | u8 tmp, burst; | ||
399 | |||
400 | if (!priv->warm) { | ||
401 | ret = -EFAULT; | ||
402 | goto error; | ||
403 | } | ||
404 | |||
405 | dbg("%s: fe_sec_mini_cmd=%d", __func__, fe_sec_mini_cmd); | ||
406 | |||
407 | switch (fe_sec_mini_cmd) { | ||
408 | case SEC_MINI_A: | ||
409 | burst = 0; | ||
410 | break; | ||
411 | case SEC_MINI_B: | ||
412 | burst = 1; | ||
413 | break; | ||
414 | default: | ||
415 | dbg("%s: invalid fe_sec_mini_cmd", __func__); | ||
416 | ret = -EINVAL; | ||
417 | goto error; | ||
418 | } | ||
419 | |||
420 | /* wait LNB TX */ | ||
421 | for (i = 500, tmp = 0; i && !tmp; i--) { | ||
422 | ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01); | ||
423 | if (ret) | ||
424 | goto error; | ||
425 | |||
426 | msleep(10); | ||
427 | } | ||
428 | |||
429 | dbg("%s: loop=%d", __func__, i); | ||
430 | |||
431 | if (i == 0) { | ||
432 | ret = -ETIMEDOUT; | ||
433 | goto error; | ||
434 | } | ||
435 | |||
436 | ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01); | ||
437 | if (ret) | ||
438 | goto error; | ||
439 | |||
440 | cmd.args[0x00] = CMD_LNB_SEND_TONEBURST; | ||
441 | cmd.args[0x01] = 0; | ||
442 | cmd.args[0x02] = burst; | ||
443 | cmd.len = 0x03; | ||
444 | ret = tda10071_cmd_execute(priv, &cmd); | ||
445 | if (ret) | ||
446 | goto error; | ||
447 | |||
448 | return ret; | ||
449 | error: | ||
450 | dbg("%s: failed=%d", __func__, ret); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
455 | { | ||
456 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
457 | int ret; | ||
458 | u8 tmp; | ||
459 | |||
460 | *status = 0; | ||
461 | |||
462 | if (!priv->warm) { | ||
463 | ret = 0; | ||
464 | goto error; | ||
465 | } | ||
466 | |||
467 | ret = tda10071_rd_reg(priv, 0x39, &tmp); | ||
468 | if (ret) | ||
469 | goto error; | ||
470 | |||
471 | if (tmp & 0x01) /* tuner PLL */ | ||
472 | *status |= FE_HAS_SIGNAL; | ||
473 | if (tmp & 0x02) /* demod PLL */ | ||
474 | *status |= FE_HAS_CARRIER; | ||
475 | if (tmp & 0x04) /* viterbi or LDPC*/ | ||
476 | *status |= FE_HAS_VITERBI; | ||
477 | if (tmp & 0x08) /* RS or BCH */ | ||
478 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
479 | |||
480 | priv->fe_status = *status; | ||
481 | |||
482 | return ret; | ||
483 | error: | ||
484 | dbg("%s: failed=%d", __func__, ret); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
489 | { | ||
490 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
491 | int ret; | ||
492 | u8 buf[2]; | ||
493 | |||
494 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
495 | *snr = 0; | ||
496 | ret = 0; | ||
497 | goto error; | ||
498 | } | ||
499 | |||
500 | ret = tda10071_rd_regs(priv, 0x3a, buf, 2); | ||
501 | if (ret) | ||
502 | goto error; | ||
503 | |||
504 | /* Es/No dBx10 */ | ||
505 | *snr = buf[0] << 8 | buf[1]; | ||
506 | |||
507 | return ret; | ||
508 | error: | ||
509 | dbg("%s: failed=%d", __func__, ret); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
514 | { | ||
515 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
516 | struct tda10071_cmd cmd; | ||
517 | int ret; | ||
518 | u8 tmp; | ||
519 | |||
520 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
521 | *strength = 0; | ||
522 | ret = 0; | ||
523 | goto error; | ||
524 | } | ||
525 | |||
526 | cmd.args[0x00] = CMD_GET_AGCACC; | ||
527 | cmd.args[0x01] = 0; | ||
528 | cmd.len = 0x02; | ||
529 | ret = tda10071_cmd_execute(priv, &cmd); | ||
530 | if (ret) | ||
531 | goto error; | ||
532 | |||
533 | /* input power estimate dBm */ | ||
534 | ret = tda10071_rd_reg(priv, 0x50, &tmp); | ||
535 | if (ret) | ||
536 | goto error; | ||
537 | |||
538 | if (tmp < 181) | ||
539 | tmp = 181; /* -75 dBm */ | ||
540 | else if (tmp > 236) | ||
541 | tmp = 236; /* -20 dBm */ | ||
542 | |||
543 | /* scale value to 0x0000-0xffff */ | ||
544 | *strength = (tmp-181) * 0xffff / (236-181); | ||
545 | |||
546 | return ret; | ||
547 | error: | ||
548 | dbg("%s: failed=%d", __func__, ret); | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
553 | { | ||
554 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
555 | struct tda10071_cmd cmd; | ||
556 | int ret, i, len; | ||
557 | u8 tmp, reg, buf[8]; | ||
558 | |||
559 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
560 | *ber = priv->ber = 0; | ||
561 | ret = 0; | ||
562 | goto error; | ||
563 | } | ||
564 | |||
565 | switch (priv->delivery_system) { | ||
566 | case SYS_DVBS: | ||
567 | reg = 0x4c; | ||
568 | len = 8; | ||
569 | i = 1; | ||
570 | break; | ||
571 | case SYS_DVBS2: | ||
572 | reg = 0x4d; | ||
573 | len = 4; | ||
574 | i = 0; | ||
575 | break; | ||
576 | default: | ||
577 | *ber = priv->ber = 0; | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | ret = tda10071_rd_reg(priv, reg, &tmp); | ||
582 | if (ret) | ||
583 | goto error; | ||
584 | |||
585 | if (priv->meas_count[i] == tmp) { | ||
586 | dbg("%s: meas not ready=%02x", __func__, tmp); | ||
587 | *ber = priv->ber; | ||
588 | return 0; | ||
589 | } else { | ||
590 | priv->meas_count[i] = tmp; | ||
591 | } | ||
592 | |||
593 | cmd.args[0x00] = CMD_BER_UPDATE_COUNTERS; | ||
594 | cmd.args[0x01] = 0; | ||
595 | cmd.args[0x02] = i; | ||
596 | cmd.len = 0x03; | ||
597 | ret = tda10071_cmd_execute(priv, &cmd); | ||
598 | if (ret) | ||
599 | goto error; | ||
600 | |||
601 | ret = tda10071_rd_regs(priv, cmd.len, buf, len); | ||
602 | if (ret) | ||
603 | goto error; | ||
604 | |||
605 | if (priv->delivery_system == SYS_DVBS) { | ||
606 | *ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
607 | priv->ucb += (buf[4] << 8) | buf[5]; | ||
608 | } else { | ||
609 | *ber = (buf[0] << 8) | buf[1]; | ||
610 | } | ||
611 | priv->ber = *ber; | ||
612 | |||
613 | return ret; | ||
614 | error: | ||
615 | dbg("%s: failed=%d", __func__, ret); | ||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
620 | { | ||
621 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
622 | int ret = 0; | ||
623 | |||
624 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
625 | *ucblocks = 0; | ||
626 | goto error; | ||
627 | } | ||
628 | |||
629 | /* UCB is updated when BER is read. Assume BER is read anyway. */ | ||
630 | |||
631 | *ucblocks = priv->ucb; | ||
632 | |||
633 | return ret; | ||
634 | error: | ||
635 | dbg("%s: failed=%d", __func__, ret); | ||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | static int tda10071_set_frontend(struct dvb_frontend *fe, | ||
640 | struct dvb_frontend_parameters *params) | ||
641 | { | ||
642 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
643 | struct tda10071_cmd cmd; | ||
644 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
645 | int ret, i; | ||
646 | u8 mode, rolloff, pilot, inversion, div; | ||
647 | |||
648 | dbg("%s: delivery_system=%d modulation=%d frequency=%d " \ | ||
649 | "symbol_rate=%d inversion=%d pilot=%d rolloff=%d", __func__, | ||
650 | c->delivery_system, c->modulation, c->frequency, | ||
651 | c->symbol_rate, c->inversion, c->pilot, c->rolloff); | ||
652 | |||
653 | priv->delivery_system = SYS_UNDEFINED; | ||
654 | |||
655 | if (!priv->warm) { | ||
656 | ret = -EFAULT; | ||
657 | goto error; | ||
658 | } | ||
659 | |||
660 | switch (c->inversion) { | ||
661 | case INVERSION_OFF: | ||
662 | inversion = 1; | ||
663 | break; | ||
664 | case INVERSION_ON: | ||
665 | inversion = 0; | ||
666 | break; | ||
667 | case INVERSION_AUTO: | ||
668 | /* 2 = auto; try first on then off | ||
669 | * 3 = auto; try first off then on */ | ||
670 | inversion = 3; | ||
671 | break; | ||
672 | default: | ||
673 | dbg("%s: invalid inversion", __func__); | ||
674 | ret = -EINVAL; | ||
675 | goto error; | ||
676 | } | ||
677 | |||
678 | switch (c->delivery_system) { | ||
679 | case SYS_DVBS: | ||
680 | rolloff = 0; | ||
681 | pilot = 2; | ||
682 | break; | ||
683 | case SYS_DVBS2: | ||
684 | switch (c->rolloff) { | ||
685 | case ROLLOFF_20: | ||
686 | rolloff = 2; | ||
687 | break; | ||
688 | case ROLLOFF_25: | ||
689 | rolloff = 1; | ||
690 | break; | ||
691 | case ROLLOFF_35: | ||
692 | rolloff = 0; | ||
693 | break; | ||
694 | case ROLLOFF_AUTO: | ||
695 | default: | ||
696 | dbg("%s: invalid rolloff", __func__); | ||
697 | ret = -EINVAL; | ||
698 | goto error; | ||
699 | } | ||
700 | |||
701 | switch (c->pilot) { | ||
702 | case PILOT_OFF: | ||
703 | pilot = 0; | ||
704 | break; | ||
705 | case PILOT_ON: | ||
706 | pilot = 1; | ||
707 | break; | ||
708 | case PILOT_AUTO: | ||
709 | pilot = 2; | ||
710 | break; | ||
711 | default: | ||
712 | dbg("%s: invalid pilot", __func__); | ||
713 | ret = -EINVAL; | ||
714 | goto error; | ||
715 | } | ||
716 | break; | ||
717 | default: | ||
718 | dbg("%s: invalid delivery_system", __func__); | ||
719 | ret = -EINVAL; | ||
720 | goto error; | ||
721 | } | ||
722 | |||
723 | for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) { | ||
724 | if (c->delivery_system == TDA10071_MODCOD[i].delivery_system && | ||
725 | c->modulation == TDA10071_MODCOD[i].modulation && | ||
726 | c->fec_inner == TDA10071_MODCOD[i].fec) { | ||
727 | mode = TDA10071_MODCOD[i].val; | ||
728 | dbg("%s: mode found=%02x", __func__, mode); | ||
729 | break; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | if (mode == 0xff) { | ||
734 | dbg("%s: invalid parameter combination", __func__); | ||
735 | ret = -EINVAL; | ||
736 | goto error; | ||
737 | } | ||
738 | |||
739 | if (c->symbol_rate <= 5000000) | ||
740 | div = 14; | ||
741 | else | ||
742 | div = 4; | ||
743 | |||
744 | ret = tda10071_wr_reg(priv, 0x81, div); | ||
745 | if (ret) | ||
746 | goto error; | ||
747 | |||
748 | ret = tda10071_wr_reg(priv, 0xe3, div); | ||
749 | if (ret) | ||
750 | goto error; | ||
751 | |||
752 | cmd.args[0x00] = CMD_CHANGE_CHANNEL; | ||
753 | cmd.args[0x01] = 0; | ||
754 | cmd.args[0x02] = mode; | ||
755 | cmd.args[0x03] = (c->frequency >> 16) & 0xff; | ||
756 | cmd.args[0x04] = (c->frequency >> 8) & 0xff; | ||
757 | cmd.args[0x05] = (c->frequency >> 0) & 0xff; | ||
758 | cmd.args[0x06] = ((c->symbol_rate / 1000) >> 8) & 0xff; | ||
759 | cmd.args[0x07] = ((c->symbol_rate / 1000) >> 0) & 0xff; | ||
760 | cmd.args[0x08] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff; | ||
761 | cmd.args[0x09] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff; | ||
762 | cmd.args[0x0a] = rolloff; | ||
763 | cmd.args[0x0b] = inversion; | ||
764 | cmd.args[0x0c] = pilot; | ||
765 | cmd.args[0x0d] = 0x00; | ||
766 | cmd.args[0x0e] = 0x00; | ||
767 | cmd.len = 0x0f; | ||
768 | ret = tda10071_cmd_execute(priv, &cmd); | ||
769 | if (ret) | ||
770 | goto error; | ||
771 | |||
772 | priv->delivery_system = c->delivery_system; | ||
773 | |||
774 | return ret; | ||
775 | error: | ||
776 | dbg("%s: failed=%d", __func__, ret); | ||
777 | return ret; | ||
778 | } | ||
779 | |||
780 | static int tda10071_get_frontend(struct dvb_frontend *fe, | ||
781 | struct dvb_frontend_parameters *p) | ||
782 | { | ||
783 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
784 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
785 | int ret, i; | ||
786 | u8 buf[5], tmp; | ||
787 | |||
788 | if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { | ||
789 | ret = -EFAULT; | ||
790 | goto error; | ||
791 | } | ||
792 | |||
793 | ret = tda10071_rd_regs(priv, 0x30, buf, 5); | ||
794 | if (ret) | ||
795 | goto error; | ||
796 | |||
797 | tmp = buf[0] & 0x3f; | ||
798 | for (i = 0; i < ARRAY_SIZE(TDA10071_MODCOD); i++) { | ||
799 | if (tmp == TDA10071_MODCOD[i].val) { | ||
800 | c->modulation = TDA10071_MODCOD[i].modulation; | ||
801 | c->fec_inner = TDA10071_MODCOD[i].fec; | ||
802 | c->delivery_system = TDA10071_MODCOD[i].delivery_system; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | switch ((buf[1] >> 0) & 0x01) { | ||
807 | case 0: | ||
808 | c->inversion = INVERSION_OFF; | ||
809 | break; | ||
810 | case 1: | ||
811 | c->inversion = INVERSION_ON; | ||
812 | break; | ||
813 | } | ||
814 | |||
815 | switch ((buf[1] >> 7) & 0x01) { | ||
816 | case 0: | ||
817 | c->pilot = PILOT_OFF; | ||
818 | break; | ||
819 | case 1: | ||
820 | c->pilot = PILOT_ON; | ||
821 | break; | ||
822 | } | ||
823 | |||
824 | c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0); | ||
825 | |||
826 | ret = tda10071_rd_regs(priv, 0x52, buf, 3); | ||
827 | if (ret) | ||
828 | goto error; | ||
829 | |||
830 | c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0); | ||
831 | |||
832 | return ret; | ||
833 | error: | ||
834 | dbg("%s: failed=%d", __func__, ret); | ||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | static int tda10071_init(struct dvb_frontend *fe) | ||
839 | { | ||
840 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
841 | struct tda10071_cmd cmd; | ||
842 | int ret, i, len, remaining; | ||
843 | const struct firmware *fw; | ||
844 | u8 *fw_file = TDA10071_DEFAULT_FIRMWARE; | ||
845 | u8 tmp, buf[4]; | ||
846 | struct tda10071_reg_val_mask tab[] = { | ||
847 | { 0xcd, 0x00, 0x07 }, | ||
848 | { 0x80, 0x00, 0x02 }, | ||
849 | { 0xcd, 0x00, 0xc0 }, | ||
850 | { 0xce, 0x00, 0x1b }, | ||
851 | { 0x9d, 0x00, 0x01 }, | ||
852 | { 0x9d, 0x00, 0x02 }, | ||
853 | { 0x9e, 0x00, 0x01 }, | ||
854 | { 0x87, 0x00, 0x80 }, | ||
855 | { 0xce, 0x00, 0x08 }, | ||
856 | { 0xce, 0x00, 0x10 }, | ||
857 | }; | ||
858 | struct tda10071_reg_val_mask tab2[] = { | ||
859 | { 0xf1, 0x70, 0xff }, | ||
860 | { 0x88, priv->cfg.pll_multiplier, 0x3f }, | ||
861 | { 0x89, 0x00, 0x10 }, | ||
862 | { 0x89, 0x10, 0x10 }, | ||
863 | { 0xc0, 0x01, 0x01 }, | ||
864 | { 0xc0, 0x00, 0x01 }, | ||
865 | { 0xe0, 0xff, 0xff }, | ||
866 | { 0xe0, 0x00, 0xff }, | ||
867 | { 0x96, 0x1e, 0x7e }, | ||
868 | { 0x8b, 0x08, 0x08 }, | ||
869 | { 0x8b, 0x00, 0x08 }, | ||
870 | { 0x8f, 0x1a, 0x7e }, | ||
871 | { 0x8c, 0x68, 0xff }, | ||
872 | { 0x8d, 0x08, 0xff }, | ||
873 | { 0x8e, 0x4c, 0xff }, | ||
874 | { 0x8f, 0x01, 0x01 }, | ||
875 | { 0x8b, 0x04, 0x04 }, | ||
876 | { 0x8b, 0x00, 0x04 }, | ||
877 | { 0x87, 0x05, 0x07 }, | ||
878 | { 0x80, 0x00, 0x20 }, | ||
879 | { 0xc8, 0x01, 0xff }, | ||
880 | { 0xb4, 0x47, 0xff }, | ||
881 | { 0xb5, 0x9c, 0xff }, | ||
882 | { 0xb6, 0x7d, 0xff }, | ||
883 | { 0xba, 0x00, 0x03 }, | ||
884 | { 0xb7, 0x47, 0xff }, | ||
885 | { 0xb8, 0x9c, 0xff }, | ||
886 | { 0xb9, 0x7d, 0xff }, | ||
887 | { 0xba, 0x00, 0x0c }, | ||
888 | { 0xc8, 0x00, 0xff }, | ||
889 | { 0xcd, 0x00, 0x04 }, | ||
890 | { 0xcd, 0x00, 0x20 }, | ||
891 | { 0xe8, 0x02, 0xff }, | ||
892 | { 0xcf, 0x20, 0xff }, | ||
893 | { 0x9b, 0xd7, 0xff }, | ||
894 | { 0x9a, 0x01, 0x03 }, | ||
895 | { 0xa8, 0x05, 0x0f }, | ||
896 | { 0xa8, 0x65, 0xf0 }, | ||
897 | { 0xa6, 0xa0, 0xf0 }, | ||
898 | { 0x9d, 0x50, 0xfc }, | ||
899 | { 0x9e, 0x20, 0xe0 }, | ||
900 | { 0xa3, 0x1c, 0x7c }, | ||
901 | { 0xd5, 0x03, 0x03 }, | ||
902 | }; | ||
903 | |||
904 | /* firmware status */ | ||
905 | ret = tda10071_rd_reg(priv, 0x51, &tmp); | ||
906 | if (ret) | ||
907 | goto error; | ||
908 | |||
909 | if (!tmp) { | ||
910 | /* warm state - wake up device from sleep */ | ||
911 | priv->warm = 1; | ||
912 | |||
913 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | ||
914 | ret = tda10071_wr_reg_mask(priv, tab[i].reg, | ||
915 | tab[i].val, tab[i].mask); | ||
916 | if (ret) | ||
917 | goto error; | ||
918 | } | ||
919 | |||
920 | cmd.args[0x00] = CMD_SET_SLEEP_MODE; | ||
921 | cmd.args[0x01] = 0; | ||
922 | cmd.args[0x02] = 0; | ||
923 | cmd.len = 0x03; | ||
924 | ret = tda10071_cmd_execute(priv, &cmd); | ||
925 | if (ret) | ||
926 | goto error; | ||
927 | } else { | ||
928 | /* cold state - try to download firmware */ | ||
929 | priv->warm = 0; | ||
930 | |||
931 | /* request the firmware, this will block and timeout */ | ||
932 | ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); | ||
933 | if (ret) { | ||
934 | err("did not find the firmware file. (%s) " | ||
935 | "Please see linux/Documentation/dvb/ for more" \ | ||
936 | " details on firmware-problems. (%d)", | ||
937 | fw_file, ret); | ||
938 | goto error; | ||
939 | } | ||
940 | |||
941 | /* init */ | ||
942 | for (i = 0; i < ARRAY_SIZE(tab2); i++) { | ||
943 | ret = tda10071_wr_reg_mask(priv, tab2[i].reg, | ||
944 | tab2[i].val, tab2[i].mask); | ||
945 | if (ret) | ||
946 | goto error_release_firmware; | ||
947 | } | ||
948 | |||
949 | /* download firmware */ | ||
950 | ret = tda10071_wr_reg(priv, 0xe0, 0x7f); | ||
951 | if (ret) | ||
952 | goto error_release_firmware; | ||
953 | |||
954 | ret = tda10071_wr_reg(priv, 0xf7, 0x81); | ||
955 | if (ret) | ||
956 | goto error_release_firmware; | ||
957 | |||
958 | ret = tda10071_wr_reg(priv, 0xf8, 0x00); | ||
959 | if (ret) | ||
960 | goto error_release_firmware; | ||
961 | |||
962 | ret = tda10071_wr_reg(priv, 0xf9, 0x00); | ||
963 | if (ret) | ||
964 | goto error_release_firmware; | ||
965 | |||
966 | info("found a '%s' in cold state, will try to load a firmware", | ||
967 | tda10071_ops.info.name); | ||
968 | |||
969 | info("downloading firmware from file '%s'", fw_file); | ||
970 | |||
971 | for (remaining = fw->size; remaining > 0; | ||
972 | remaining -= (priv->cfg.i2c_wr_max - 1)) { | ||
973 | len = remaining; | ||
974 | if (len > (priv->cfg.i2c_wr_max - 1)) | ||
975 | len = (priv->cfg.i2c_wr_max - 1); | ||
976 | |||
977 | ret = tda10071_wr_regs(priv, 0xfa, | ||
978 | (u8 *) &fw->data[fw->size - remaining], len); | ||
979 | if (ret) { | ||
980 | err("firmware download failed=%d", ret); | ||
981 | if (ret) | ||
982 | goto error_release_firmware; | ||
983 | } | ||
984 | } | ||
985 | release_firmware(fw); | ||
986 | |||
987 | ret = tda10071_wr_reg(priv, 0xf7, 0x0c); | ||
988 | if (ret) | ||
989 | goto error; | ||
990 | |||
991 | ret = tda10071_wr_reg(priv, 0xe0, 0x00); | ||
992 | if (ret) | ||
993 | goto error; | ||
994 | |||
995 | /* wait firmware start */ | ||
996 | msleep(250); | ||
997 | |||
998 | /* firmware status */ | ||
999 | ret = tda10071_rd_reg(priv, 0x51, &tmp); | ||
1000 | if (ret) | ||
1001 | goto error; | ||
1002 | |||
1003 | if (tmp) { | ||
1004 | info("firmware did not run"); | ||
1005 | ret = -EFAULT; | ||
1006 | goto error; | ||
1007 | } else { | ||
1008 | priv->warm = 1; | ||
1009 | } | ||
1010 | |||
1011 | cmd.args[0x00] = CMD_GET_FW_VERSION; | ||
1012 | cmd.len = 0x01; | ||
1013 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1014 | if (ret) | ||
1015 | goto error; | ||
1016 | |||
1017 | ret = tda10071_rd_regs(priv, cmd.len, buf, 4); | ||
1018 | if (ret) | ||
1019 | goto error; | ||
1020 | |||
1021 | info("firmware version %d.%d.%d.%d", | ||
1022 | buf[0], buf[1], buf[2], buf[3]); | ||
1023 | info("found a '%s' in warm state.", tda10071_ops.info.name); | ||
1024 | |||
1025 | ret = tda10071_rd_regs(priv, 0x81, buf, 2); | ||
1026 | if (ret) | ||
1027 | goto error; | ||
1028 | |||
1029 | cmd.args[0x00] = CMD_DEMOD_INIT; | ||
1030 | cmd.args[0x01] = ((priv->cfg.xtal / 1000) >> 8) & 0xff; | ||
1031 | cmd.args[0x02] = ((priv->cfg.xtal / 1000) >> 0) & 0xff; | ||
1032 | cmd.args[0x03] = buf[0]; | ||
1033 | cmd.args[0x04] = buf[1]; | ||
1034 | cmd.args[0x05] = priv->cfg.pll_multiplier; | ||
1035 | cmd.args[0x06] = priv->cfg.spec_inv; | ||
1036 | cmd.args[0x07] = 0x00; | ||
1037 | cmd.len = 0x08; | ||
1038 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1039 | if (ret) | ||
1040 | goto error; | ||
1041 | |||
1042 | cmd.args[0x00] = CMD_TUNER_INIT; | ||
1043 | cmd.args[0x01] = 0x00; | ||
1044 | cmd.args[0x02] = 0x00; | ||
1045 | cmd.args[0x03] = 0x00; | ||
1046 | cmd.args[0x04] = 0x00; | ||
1047 | cmd.args[0x05] = 0x14; | ||
1048 | cmd.args[0x06] = 0x00; | ||
1049 | cmd.args[0x07] = 0x03; | ||
1050 | cmd.args[0x08] = 0x02; | ||
1051 | cmd.args[0x09] = 0x02; | ||
1052 | cmd.args[0x0a] = 0x00; | ||
1053 | cmd.args[0x0b] = 0x00; | ||
1054 | cmd.args[0x0c] = 0x00; | ||
1055 | cmd.args[0x0d] = 0x00; | ||
1056 | cmd.args[0x0e] = 0x00; | ||
1057 | cmd.len = 0x0f; | ||
1058 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1059 | if (ret) | ||
1060 | goto error; | ||
1061 | |||
1062 | cmd.args[0x00] = CMD_MPEG_CONFIG; | ||
1063 | cmd.args[0x01] = 0; | ||
1064 | cmd.args[0x02] = priv->cfg.ts_mode; | ||
1065 | cmd.args[0x03] = 0x00; | ||
1066 | cmd.args[0x04] = 0x04; | ||
1067 | cmd.args[0x05] = 0x00; | ||
1068 | cmd.len = 0x06; | ||
1069 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1070 | if (ret) | ||
1071 | goto error; | ||
1072 | |||
1073 | ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01); | ||
1074 | if (ret) | ||
1075 | goto error; | ||
1076 | |||
1077 | cmd.args[0x00] = CMD_LNB_CONFIG; | ||
1078 | cmd.args[0x01] = 0; | ||
1079 | cmd.args[0x02] = 150; | ||
1080 | cmd.args[0x03] = 3; | ||
1081 | cmd.args[0x04] = 22; | ||
1082 | cmd.args[0x05] = 1; | ||
1083 | cmd.args[0x06] = 1; | ||
1084 | cmd.args[0x07] = 30; | ||
1085 | cmd.args[0x08] = 30; | ||
1086 | cmd.args[0x09] = 30; | ||
1087 | cmd.args[0x0a] = 30; | ||
1088 | cmd.len = 0x0b; | ||
1089 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1090 | if (ret) | ||
1091 | goto error; | ||
1092 | |||
1093 | cmd.args[0x00] = CMD_BER_CONTROL; | ||
1094 | cmd.args[0x01] = 0; | ||
1095 | cmd.args[0x02] = 14; | ||
1096 | cmd.args[0x03] = 14; | ||
1097 | cmd.len = 0x04; | ||
1098 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1099 | if (ret) | ||
1100 | goto error; | ||
1101 | } | ||
1102 | |||
1103 | return ret; | ||
1104 | error_release_firmware: | ||
1105 | release_firmware(fw); | ||
1106 | error: | ||
1107 | dbg("%s: failed=%d", __func__, ret); | ||
1108 | return ret; | ||
1109 | } | ||
1110 | |||
1111 | static int tda10071_sleep(struct dvb_frontend *fe) | ||
1112 | { | ||
1113 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
1114 | struct tda10071_cmd cmd; | ||
1115 | int ret, i; | ||
1116 | struct tda10071_reg_val_mask tab[] = { | ||
1117 | { 0xcd, 0x07, 0x07 }, | ||
1118 | { 0x80, 0x02, 0x02 }, | ||
1119 | { 0xcd, 0xc0, 0xc0 }, | ||
1120 | { 0xce, 0x1b, 0x1b }, | ||
1121 | { 0x9d, 0x01, 0x01 }, | ||
1122 | { 0x9d, 0x02, 0x02 }, | ||
1123 | { 0x9e, 0x01, 0x01 }, | ||
1124 | { 0x87, 0x80, 0x80 }, | ||
1125 | { 0xce, 0x08, 0x08 }, | ||
1126 | { 0xce, 0x10, 0x10 }, | ||
1127 | }; | ||
1128 | |||
1129 | if (!priv->warm) { | ||
1130 | ret = -EFAULT; | ||
1131 | goto error; | ||
1132 | } | ||
1133 | |||
1134 | cmd.args[0x00] = CMD_SET_SLEEP_MODE; | ||
1135 | cmd.args[0x01] = 0; | ||
1136 | cmd.args[0x02] = 1; | ||
1137 | cmd.len = 0x03; | ||
1138 | ret = tda10071_cmd_execute(priv, &cmd); | ||
1139 | if (ret) | ||
1140 | goto error; | ||
1141 | |||
1142 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | ||
1143 | ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val, | ||
1144 | tab[i].mask); | ||
1145 | if (ret) | ||
1146 | goto error; | ||
1147 | } | ||
1148 | |||
1149 | return ret; | ||
1150 | error: | ||
1151 | dbg("%s: failed=%d", __func__, ret); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | |||
1155 | static int tda10071_get_tune_settings(struct dvb_frontend *fe, | ||
1156 | struct dvb_frontend_tune_settings *s) | ||
1157 | { | ||
1158 | s->min_delay_ms = 8000; | ||
1159 | s->step_size = 0; | ||
1160 | s->max_drift = 0; | ||
1161 | |||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | static void tda10071_release(struct dvb_frontend *fe) | ||
1166 | { | ||
1167 | struct tda10071_priv *priv = fe->demodulator_priv; | ||
1168 | kfree(priv); | ||
1169 | } | ||
1170 | |||
1171 | struct dvb_frontend *tda10071_attach(const struct tda10071_config *config, | ||
1172 | struct i2c_adapter *i2c) | ||
1173 | { | ||
1174 | int ret; | ||
1175 | struct tda10071_priv *priv = NULL; | ||
1176 | u8 tmp; | ||
1177 | |||
1178 | /* allocate memory for the internal priv */ | ||
1179 | priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL); | ||
1180 | if (priv == NULL) { | ||
1181 | ret = -ENOMEM; | ||
1182 | goto error; | ||
1183 | } | ||
1184 | |||
1185 | /* setup the priv */ | ||
1186 | priv->i2c = i2c; | ||
1187 | memcpy(&priv->cfg, config, sizeof(struct tda10071_config)); | ||
1188 | |||
1189 | /* chip ID */ | ||
1190 | ret = tda10071_rd_reg(priv, 0xff, &tmp); | ||
1191 | if (ret || tmp != 0x0f) | ||
1192 | goto error; | ||
1193 | |||
1194 | /* chip type */ | ||
1195 | ret = tda10071_rd_reg(priv, 0xdd, &tmp); | ||
1196 | if (ret || tmp != 0x00) | ||
1197 | goto error; | ||
1198 | |||
1199 | /* chip version */ | ||
1200 | ret = tda10071_rd_reg(priv, 0xfe, &tmp); | ||
1201 | if (ret || tmp != 0x01) | ||
1202 | goto error; | ||
1203 | |||
1204 | /* create dvb_frontend */ | ||
1205 | memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops)); | ||
1206 | priv->fe.demodulator_priv = priv; | ||
1207 | |||
1208 | return &priv->fe; | ||
1209 | error: | ||
1210 | dbg("%s: failed=%d", __func__, ret); | ||
1211 | kfree(priv); | ||
1212 | return NULL; | ||
1213 | } | ||
1214 | EXPORT_SYMBOL(tda10071_attach); | ||
1215 | |||
1216 | static struct dvb_frontend_ops tda10071_ops = { | ||
1217 | .info = { | ||
1218 | .name = "NXP TDA10071", | ||
1219 | .type = FE_QPSK, | ||
1220 | .frequency_min = 950000, | ||
1221 | .frequency_max = 2150000, | ||
1222 | .frequency_tolerance = 5000, | ||
1223 | .symbol_rate_min = 1000000, | ||
1224 | .symbol_rate_max = 45000000, | ||
1225 | .caps = FE_CAN_INVERSION_AUTO | | ||
1226 | FE_CAN_FEC_1_2 | | ||
1227 | FE_CAN_FEC_2_3 | | ||
1228 | FE_CAN_FEC_3_4 | | ||
1229 | FE_CAN_FEC_4_5 | | ||
1230 | FE_CAN_FEC_5_6 | | ||
1231 | FE_CAN_FEC_6_7 | | ||
1232 | FE_CAN_FEC_7_8 | | ||
1233 | FE_CAN_FEC_8_9 | | ||
1234 | FE_CAN_FEC_AUTO | | ||
1235 | FE_CAN_QPSK | | ||
1236 | FE_CAN_RECOVER | | ||
1237 | FE_CAN_2G_MODULATION | ||
1238 | }, | ||
1239 | |||
1240 | .release = tda10071_release, | ||
1241 | |||
1242 | .get_tune_settings = tda10071_get_tune_settings, | ||
1243 | |||
1244 | .init = tda10071_init, | ||
1245 | .sleep = tda10071_sleep, | ||
1246 | |||
1247 | .set_frontend = tda10071_set_frontend, | ||
1248 | .get_frontend = tda10071_get_frontend, | ||
1249 | |||
1250 | .read_status = tda10071_read_status, | ||
1251 | .read_snr = tda10071_read_snr, | ||
1252 | .read_signal_strength = tda10071_read_signal_strength, | ||
1253 | .read_ber = tda10071_read_ber, | ||
1254 | .read_ucblocks = tda10071_read_ucblocks, | ||
1255 | |||
1256 | .diseqc_send_master_cmd = tda10071_diseqc_send_master_cmd, | ||
1257 | .diseqc_recv_slave_reply = tda10071_diseqc_recv_slave_reply, | ||
1258 | .diseqc_send_burst = tda10071_diseqc_send_burst, | ||
1259 | |||
1260 | .set_tone = tda10071_set_tone, | ||
1261 | .set_voltage = tda10071_set_voltage, | ||
1262 | }; | ||
1263 | |||
1264 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
1265 | MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver"); | ||
1266 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/tda10071.h b/drivers/media/dvb/frontends/tda10071.h new file mode 100644 index 000000000000..21163c4b555c --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TDA10071_H | ||
22 | #define TDA10071_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | struct tda10071_config { | ||
27 | /* Demodulator I2C address. | ||
28 | * Default: none, must set | ||
29 | * Values: 0x55, | ||
30 | */ | ||
31 | u8 i2c_address; | ||
32 | |||
33 | /* Max bytes I2C provider can write at once. | ||
34 | * Note: Buffer is taken from the stack currently! | ||
35 | * Default: none, must set | ||
36 | * Values: | ||
37 | */ | ||
38 | u16 i2c_wr_max; | ||
39 | |||
40 | /* TS output mode. | ||
41 | * Default: TDA10071_TS_SERIAL | ||
42 | * Values: | ||
43 | */ | ||
44 | #define TDA10071_TS_SERIAL 0 | ||
45 | #define TDA10071_TS_PARALLEL 1 | ||
46 | u8 ts_mode; | ||
47 | |||
48 | /* Input spectrum inversion. | ||
49 | * Default: 0 | ||
50 | * Values: 0, 1 | ||
51 | */ | ||
52 | bool spec_inv; | ||
53 | |||
54 | /* Xtal frequency Hz | ||
55 | * Default: none, must set | ||
56 | * Values: | ||
57 | */ | ||
58 | u32 xtal; | ||
59 | |||
60 | /* PLL multiplier. | ||
61 | * Default: none, must set | ||
62 | * Values: | ||
63 | */ | ||
64 | u8 pll_multiplier; | ||
65 | }; | ||
66 | |||
67 | |||
68 | #if defined(CONFIG_DVB_TDA10071) || \ | ||
69 | (defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE)) | ||
70 | extern struct dvb_frontend *tda10071_attach( | ||
71 | const struct tda10071_config *config, struct i2c_adapter *i2c); | ||
72 | #else | ||
73 | static inline struct dvb_frontend *tda10071_attach( | ||
74 | const struct tda10071_config *config, struct i2c_adapter *i2c) | ||
75 | { | ||
76 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
77 | return NULL; | ||
78 | } | ||
79 | #endif | ||
80 | |||
81 | #endif /* TDA10071_H */ | ||
diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb/frontends/tda10071_priv.h new file mode 100644 index 000000000000..93c5e6317f07 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071_priv.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TDA10071_PRIV | ||
22 | #define TDA10071_PRIV | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "tda10071.h" | ||
26 | #include <linux/firmware.h> | ||
27 | |||
28 | #define LOG_PREFIX "tda10071" | ||
29 | |||
30 | #undef dbg | ||
31 | #define dbg(f, arg...) \ | ||
32 | if (tda10071_debug) \ | ||
33 | printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
34 | #undef err | ||
35 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
36 | #undef info | ||
37 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
38 | #undef warn | ||
39 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
40 | |||
41 | struct tda10071_priv { | ||
42 | struct i2c_adapter *i2c; | ||
43 | struct dvb_frontend fe; | ||
44 | struct tda10071_config cfg; | ||
45 | |||
46 | u8 meas_count[2]; | ||
47 | u32 ber; | ||
48 | u32 ucb; | ||
49 | fe_status_t fe_status; | ||
50 | fe_delivery_system_t delivery_system; | ||
51 | bool warm; /* FW running */ | ||
52 | }; | ||
53 | |||
54 | static struct tda10071_modcod { | ||
55 | fe_delivery_system_t delivery_system; | ||
56 | fe_modulation_t modulation; | ||
57 | fe_code_rate_t fec; | ||
58 | u8 val; | ||
59 | } TDA10071_MODCOD[] = { | ||
60 | /* NBC-QPSK */ | ||
61 | { SYS_DVBS2, QPSK, FEC_AUTO, 0x00 }, | ||
62 | { SYS_DVBS2, QPSK, FEC_1_2, 0x04 }, | ||
63 | { SYS_DVBS2, QPSK, FEC_3_5, 0x05 }, | ||
64 | { SYS_DVBS2, QPSK, FEC_2_3, 0x06 }, | ||
65 | { SYS_DVBS2, QPSK, FEC_3_4, 0x07 }, | ||
66 | { SYS_DVBS2, QPSK, FEC_4_5, 0x08 }, | ||
67 | { SYS_DVBS2, QPSK, FEC_5_6, 0x09 }, | ||
68 | { SYS_DVBS2, QPSK, FEC_8_9, 0x0a }, | ||
69 | { SYS_DVBS2, QPSK, FEC_9_10, 0x0b }, | ||
70 | /* 8PSK */ | ||
71 | { SYS_DVBS2, PSK_8, FEC_3_5, 0x0c }, | ||
72 | { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d }, | ||
73 | { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e }, | ||
74 | { SYS_DVBS2, PSK_8, FEC_5_6, 0x0f }, | ||
75 | { SYS_DVBS2, PSK_8, FEC_8_9, 0x10 }, | ||
76 | { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 }, | ||
77 | /* QPSK */ | ||
78 | { SYS_DVBS, QPSK, FEC_AUTO, 0x2d }, | ||
79 | { SYS_DVBS, QPSK, FEC_1_2, 0x2e }, | ||
80 | { SYS_DVBS, QPSK, FEC_2_3, 0x2f }, | ||
81 | { SYS_DVBS, QPSK, FEC_3_4, 0x30 }, | ||
82 | { SYS_DVBS, QPSK, FEC_5_6, 0x31 }, | ||
83 | { SYS_DVBS, QPSK, FEC_7_8, 0x32 }, | ||
84 | }; | ||
85 | |||
86 | struct tda10071_reg_val_mask { | ||
87 | u8 reg; | ||
88 | u8 val; | ||
89 | u8 mask; | ||
90 | }; | ||
91 | |||
92 | /* firmware filename */ | ||
93 | #define TDA10071_DEFAULT_FIRMWARE "dvb-fe-tda10071.fw" | ||
94 | |||
95 | /* firmware commands */ | ||
96 | #define CMD_DEMOD_INIT 0x10 | ||
97 | #define CMD_CHANGE_CHANNEL 0x11 | ||
98 | #define CMD_MPEG_CONFIG 0x13 | ||
99 | #define CMD_TUNER_INIT 0x15 | ||
100 | #define CMD_GET_AGCACC 0x1a | ||
101 | |||
102 | #define CMD_LNB_CONFIG 0x20 | ||
103 | #define CMD_LNB_SEND_DISEQC 0x21 | ||
104 | #define CMD_LNB_SET_DC_LEVEL 0x22 | ||
105 | #define CMD_LNB_PCB_CONFIG 0x23 | ||
106 | #define CMD_LNB_SEND_TONEBURST 0x24 | ||
107 | #define CMD_LNB_UPDATE_REPLY 0x25 | ||
108 | |||
109 | #define CMD_GET_FW_VERSION 0x35 | ||
110 | #define CMD_SET_SLEEP_MODE 0x36 | ||
111 | #define CMD_BER_CONTROL 0x3e | ||
112 | #define CMD_BER_UPDATE_COUNTERS 0x3f | ||
113 | |||
114 | /* firmare command struct */ | ||
115 | #define TDA10071_ARGLEN 0x1e | ||
116 | struct tda10071_cmd { | ||
117 | u8 args[TDA10071_ARGLEN]; | ||
118 | u8 len; | ||
119 | }; | ||
120 | |||
121 | |||
122 | #endif /* TDA10071_PRIV */ | ||