]>
Commit | Line | Data |
---|---|---|
c0adca73 AP |
1 | /* |
2 | * Realtek RTL2830 DVB-T demodulator 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 | ||
22 | /* | |
23 | * Driver implements own I2C-adapter for tuner I2C access. That's since chip | |
24 | * have unusual I2C-gate control which closes gate automatically after each | |
25 | * I2C transfer. Using own I2C adapter we can workaround that. | |
26 | */ | |
27 | ||
28 | #include "rtl2830_priv.h" | |
29 | ||
0485a708 | 30 | /* write multiple hardware registers */ |
3a2fca26 | 31 | static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len) |
c0adca73 AP |
32 | { |
33 | int ret; | |
0485a708 | 34 | u8 buf[1+len]; |
c0adca73 AP |
35 | struct i2c_msg msg[1] = { |
36 | { | |
37 | .addr = priv->cfg.i2c_addr, | |
38 | .flags = 0, | |
0485a708 | 39 | .len = 1+len, |
c0adca73 AP |
40 | .buf = buf, |
41 | } | |
42 | }; | |
43 | ||
0485a708 AP |
44 | buf[0] = reg; |
45 | memcpy(&buf[1], val, len); | |
c0adca73 AP |
46 | |
47 | ret = i2c_transfer(priv->i2c, msg, 1); | |
48 | if (ret == 1) { | |
49 | ret = 0; | |
50 | } else { | |
86ad0f1d AP |
51 | dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ |
52 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | |
c0adca73 AP |
53 | ret = -EREMOTEIO; |
54 | } | |
55 | return ret; | |
56 | } | |
57 | ||
0485a708 AP |
58 | /* read multiple hardware registers */ |
59 | static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) | |
c0adca73 AP |
60 | { |
61 | int ret; | |
c0adca73 AP |
62 | struct i2c_msg msg[2] = { |
63 | { | |
64 | .addr = priv->cfg.i2c_addr, | |
65 | .flags = 0, | |
0485a708 AP |
66 | .len = 1, |
67 | .buf = ®, | |
c0adca73 AP |
68 | }, { |
69 | .addr = priv->cfg.i2c_addr, | |
70 | .flags = I2C_M_RD, | |
71 | .len = len, | |
72 | .buf = val, | |
73 | } | |
74 | }; | |
75 | ||
c0adca73 AP |
76 | ret = i2c_transfer(priv->i2c, msg, 2); |
77 | if (ret == 2) { | |
78 | ret = 0; | |
79 | } else { | |
86ad0f1d AP |
80 | dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ |
81 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | |
c0adca73 AP |
82 | ret = -EREMOTEIO; |
83 | } | |
84 | return ret; | |
85 | } | |
86 | ||
0485a708 | 87 | /* write multiple registers */ |
3a2fca26 AP |
88 | static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, const u8 *val, |
89 | int len) | |
0485a708 AP |
90 | { |
91 | int ret; | |
92 | u8 reg2 = (reg >> 0) & 0xff; | |
93 | u8 page = (reg >> 8) & 0xff; | |
94 | ||
95 | /* switch bank if needed */ | |
96 | if (page != priv->page) { | |
97 | ret = rtl2830_wr(priv, 0x00, &page, 1); | |
98 | if (ret) | |
99 | return ret; | |
100 | ||
101 | priv->page = page; | |
102 | } | |
103 | ||
104 | return rtl2830_wr(priv, reg2, val, len); | |
105 | } | |
106 | ||
107 | /* read multiple registers */ | |
108 | static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) | |
109 | { | |
110 | int ret; | |
111 | u8 reg2 = (reg >> 0) & 0xff; | |
112 | u8 page = (reg >> 8) & 0xff; | |
113 | ||
114 | /* switch bank if needed */ | |
115 | if (page != priv->page) { | |
116 | ret = rtl2830_wr(priv, 0x00, &page, 1); | |
117 | if (ret) | |
118 | return ret; | |
119 | ||
120 | priv->page = page; | |
121 | } | |
122 | ||
123 | return rtl2830_rd(priv, reg2, val, len); | |
124 | } | |
125 | ||
c0adca73 AP |
126 | /* read single register */ |
127 | static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) | |
128 | { | |
129 | return rtl2830_rd_regs(priv, reg, val, 1); | |
130 | } | |
131 | ||
132 | /* write single register with mask */ | |
a17ff2ee | 133 | static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) |
c0adca73 AP |
134 | { |
135 | int ret; | |
136 | u8 tmp; | |
137 | ||
138 | /* no need for read if whole reg is written */ | |
139 | if (mask != 0xff) { | |
140 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | |
141 | if (ret) | |
142 | return ret; | |
143 | ||
144 | val &= mask; | |
145 | tmp &= ~mask; | |
146 | val |= tmp; | |
147 | } | |
148 | ||
149 | return rtl2830_wr_regs(priv, reg, &val, 1); | |
150 | } | |
151 | ||
152 | /* read single register with mask */ | |
a17ff2ee | 153 | static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) |
c0adca73 AP |
154 | { |
155 | int ret, i; | |
156 | u8 tmp; | |
157 | ||
158 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | |
159 | if (ret) | |
160 | return ret; | |
161 | ||
162 | tmp &= mask; | |
163 | ||
164 | /* find position of the first bit */ | |
165 | for (i = 0; i < 8; i++) { | |
166 | if ((mask >> i) & 0x01) | |
167 | break; | |
168 | } | |
169 | *val = tmp >> i; | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | static int rtl2830_init(struct dvb_frontend *fe) | |
175 | { | |
176 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
177 | int ret, i; | |
c0adca73 AP |
178 | struct rtl2830_reg_val_mask tab[] = { |
179 | { 0x00d, 0x01, 0x03 }, | |
180 | { 0x00d, 0x10, 0x10 }, | |
181 | { 0x104, 0x00, 0x1e }, | |
182 | { 0x105, 0x80, 0x80 }, | |
183 | { 0x110, 0x02, 0x03 }, | |
184 | { 0x110, 0x08, 0x0c }, | |
185 | { 0x17b, 0x00, 0x40 }, | |
186 | { 0x17d, 0x05, 0x0f }, | |
187 | { 0x17d, 0x50, 0xf0 }, | |
188 | { 0x18c, 0x08, 0x0f }, | |
189 | { 0x18d, 0x00, 0xc0 }, | |
190 | { 0x188, 0x05, 0x0f }, | |
191 | { 0x189, 0x00, 0xfc }, | |
192 | { 0x2d5, 0x02, 0x02 }, | |
193 | { 0x2f1, 0x02, 0x06 }, | |
194 | { 0x2f1, 0x20, 0xf8 }, | |
195 | { 0x16d, 0x00, 0x01 }, | |
196 | { 0x1a6, 0x00, 0x80 }, | |
197 | { 0x106, priv->cfg.vtop, 0x3f }, | |
198 | { 0x107, priv->cfg.krf, 0x3f }, | |
199 | { 0x112, 0x28, 0xff }, | |
200 | { 0x103, priv->cfg.agc_targ_val, 0xff }, | |
201 | { 0x00a, 0x02, 0x07 }, | |
202 | { 0x140, 0x0c, 0x3c }, | |
203 | { 0x140, 0x40, 0xc0 }, | |
204 | { 0x15b, 0x05, 0x07 }, | |
205 | { 0x15b, 0x28, 0x38 }, | |
206 | { 0x15c, 0x05, 0x07 }, | |
207 | { 0x15c, 0x28, 0x38 }, | |
208 | { 0x115, priv->cfg.spec_inv, 0x01 }, | |
209 | { 0x16f, 0x01, 0x07 }, | |
210 | { 0x170, 0x18, 0x38 }, | |
211 | { 0x172, 0x0f, 0x0f }, | |
212 | { 0x173, 0x08, 0x38 }, | |
213 | { 0x175, 0x01, 0x07 }, | |
214 | { 0x176, 0x00, 0xc0 }, | |
215 | }; | |
216 | ||
217 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | |
218 | ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, | |
219 | tab[i].mask); | |
220 | if (ret) | |
221 | goto err; | |
222 | } | |
223 | ||
224 | ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); | |
225 | if (ret) | |
226 | goto err; | |
227 | ||
228 | ret = rtl2830_wr_regs(priv, 0x195, | |
229 | "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); | |
230 | if (ret) | |
231 | goto err; | |
232 | ||
c0adca73 AP |
233 | /* TODO: spec init */ |
234 | ||
235 | /* soft reset */ | |
236 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); | |
237 | if (ret) | |
238 | goto err; | |
239 | ||
240 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); | |
241 | if (ret) | |
242 | goto err; | |
243 | ||
a8567cf2 AP |
244 | priv->sleeping = false; |
245 | ||
c0adca73 AP |
246 | return ret; |
247 | err: | |
86ad0f1d | 248 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
c0adca73 AP |
249 | return ret; |
250 | } | |
251 | ||
a8567cf2 AP |
252 | static int rtl2830_sleep(struct dvb_frontend *fe) |
253 | { | |
254 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
255 | priv->sleeping = true; | |
256 | return 0; | |
257 | } | |
258 | ||
a17ff2ee | 259 | static int rtl2830_get_tune_settings(struct dvb_frontend *fe, |
c0adca73 AP |
260 | struct dvb_frontend_tune_settings *s) |
261 | { | |
262 | s->min_delay_ms = 500; | |
263 | s->step_size = fe->ops.info.frequency_stepsize * 2; | |
264 | s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | static int rtl2830_set_frontend(struct dvb_frontend *fe) | |
270 | { | |
271 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
272 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
273 | int ret, i; | |
66b3c4de AP |
274 | u64 num; |
275 | u8 buf[3], tmp; | |
276 | u32 if_ctl, if_frequency; | |
3a2fca26 | 277 | static const u8 bw_params1[3][34] = { |
c0adca73 AP |
278 | { |
279 | 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, | |
280 | 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, | |
281 | 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, | |
282 | 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ | |
283 | }, { | |
284 | 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, | |
285 | 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, | |
286 | 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, | |
287 | 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ | |
288 | }, { | |
289 | 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, | |
290 | 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, | |
291 | 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, | |
292 | 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ | |
293 | }, | |
294 | }; | |
3a2fca26 AP |
295 | static const u8 bw_params2[3][6] = { |
296 | {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30}, /* 6 MHz */ | |
297 | {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98}, /* 7 MHz */ | |
298 | {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */ | |
c0adca73 AP |
299 | }; |
300 | ||
86ad0f1d AP |
301 | dev_dbg(&priv->i2c->dev, |
302 | "%s: frequency=%d bandwidth_hz=%d inversion=%d\n", | |
303 | __func__, c->frequency, c->bandwidth_hz, c->inversion); | |
c0adca73 AP |
304 | |
305 | /* program tuner */ | |
306 | if (fe->ops.tuner_ops.set_params) | |
307 | fe->ops.tuner_ops.set_params(fe); | |
308 | ||
309 | switch (c->bandwidth_hz) { | |
310 | case 6000000: | |
311 | i = 0; | |
312 | break; | |
313 | case 7000000: | |
314 | i = 1; | |
315 | break; | |
316 | case 8000000: | |
317 | i = 2; | |
318 | break; | |
319 | default: | |
86ad0f1d | 320 | dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__); |
c0adca73 AP |
321 | return -EINVAL; |
322 | } | |
323 | ||
324 | ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); | |
325 | if (ret) | |
326 | goto err; | |
327 | ||
66b3c4de AP |
328 | /* program if frequency */ |
329 | if (fe->ops.tuner_ops.get_if_frequency) | |
330 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); | |
331 | else | |
332 | ret = -EINVAL; | |
333 | ||
334 | if (ret < 0) | |
335 | goto err; | |
336 | ||
337 | num = if_frequency % priv->cfg.xtal; | |
338 | num *= 0x400000; | |
339 | num = div_u64(num, priv->cfg.xtal); | |
340 | num = -num; | |
341 | if_ctl = num & 0x3fffff; | |
342 | dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d if_ctl=%08x\n", | |
343 | __func__, if_frequency, if_ctl); | |
344 | ||
345 | ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ | |
346 | if (ret) | |
347 | goto err; | |
348 | ||
349 | buf[0] = tmp << 6; | |
350 | buf[0] |= (if_ctl >> 16) & 0x3f; | |
351 | buf[1] = (if_ctl >> 8) & 0xff; | |
352 | buf[2] = (if_ctl >> 0) & 0xff; | |
353 | ||
354 | ret = rtl2830_wr_regs(priv, 0x119, buf, 3); | |
355 | if (ret) | |
356 | goto err; | |
357 | ||
c0adca73 AP |
358 | /* 1/2 split I2C write */ |
359 | ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); | |
360 | if (ret) | |
361 | goto err; | |
362 | ||
363 | /* 2/2 split I2C write */ | |
364 | ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); | |
365 | if (ret) | |
366 | goto err; | |
367 | ||
368 | ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); | |
369 | if (ret) | |
370 | goto err; | |
371 | ||
372 | return ret; | |
373 | err: | |
86ad0f1d | 374 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
c0adca73 AP |
375 | return ret; |
376 | } | |
377 | ||
631a2b61 AP |
378 | static int rtl2830_get_frontend(struct dvb_frontend *fe) |
379 | { | |
380 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
381 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
382 | int ret; | |
383 | u8 buf[3]; | |
384 | ||
c188637d AP |
385 | if (priv->sleeping) |
386 | return 0; | |
387 | ||
631a2b61 AP |
388 | ret = rtl2830_rd_regs(priv, 0x33c, buf, 2); |
389 | if (ret) | |
390 | goto err; | |
391 | ||
392 | ret = rtl2830_rd_reg(priv, 0x351, &buf[2]); | |
393 | if (ret) | |
394 | goto err; | |
395 | ||
86ad0f1d | 396 | dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf); |
631a2b61 AP |
397 | |
398 | switch ((buf[0] >> 2) & 3) { | |
399 | case 0: | |
400 | c->modulation = QPSK; | |
401 | break; | |
402 | case 1: | |
403 | c->modulation = QAM_16; | |
404 | break; | |
405 | case 2: | |
406 | c->modulation = QAM_64; | |
407 | break; | |
408 | } | |
409 | ||
410 | switch ((buf[2] >> 2) & 1) { | |
411 | case 0: | |
412 | c->transmission_mode = TRANSMISSION_MODE_2K; | |
413 | break; | |
414 | case 1: | |
415 | c->transmission_mode = TRANSMISSION_MODE_8K; | |
416 | } | |
417 | ||
418 | switch ((buf[2] >> 0) & 3) { | |
419 | case 0: | |
420 | c->guard_interval = GUARD_INTERVAL_1_32; | |
421 | break; | |
422 | case 1: | |
423 | c->guard_interval = GUARD_INTERVAL_1_16; | |
424 | break; | |
425 | case 2: | |
426 | c->guard_interval = GUARD_INTERVAL_1_8; | |
427 | break; | |
428 | case 3: | |
429 | c->guard_interval = GUARD_INTERVAL_1_4; | |
430 | break; | |
431 | } | |
432 | ||
433 | switch ((buf[0] >> 4) & 7) { | |
434 | case 0: | |
435 | c->hierarchy = HIERARCHY_NONE; | |
436 | break; | |
437 | case 1: | |
438 | c->hierarchy = HIERARCHY_1; | |
439 | break; | |
440 | case 2: | |
441 | c->hierarchy = HIERARCHY_2; | |
442 | break; | |
443 | case 3: | |
444 | c->hierarchy = HIERARCHY_4; | |
445 | break; | |
446 | } | |
447 | ||
448 | switch ((buf[1] >> 3) & 7) { | |
449 | case 0: | |
450 | c->code_rate_HP = FEC_1_2; | |
451 | break; | |
452 | case 1: | |
453 | c->code_rate_HP = FEC_2_3; | |
454 | break; | |
455 | case 2: | |
456 | c->code_rate_HP = FEC_3_4; | |
457 | break; | |
458 | case 3: | |
459 | c->code_rate_HP = FEC_5_6; | |
460 | break; | |
461 | case 4: | |
462 | c->code_rate_HP = FEC_7_8; | |
463 | break; | |
464 | } | |
465 | ||
466 | switch ((buf[1] >> 0) & 7) { | |
467 | case 0: | |
468 | c->code_rate_LP = FEC_1_2; | |
469 | break; | |
470 | case 1: | |
471 | c->code_rate_LP = FEC_2_3; | |
472 | break; | |
473 | case 2: | |
474 | c->code_rate_LP = FEC_3_4; | |
475 | break; | |
476 | case 3: | |
477 | c->code_rate_LP = FEC_5_6; | |
478 | break; | |
479 | case 4: | |
480 | c->code_rate_LP = FEC_7_8; | |
481 | break; | |
482 | } | |
483 | ||
484 | return 0; | |
485 | err: | |
86ad0f1d | 486 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
631a2b61 AP |
487 | return ret; |
488 | } | |
489 | ||
c0adca73 AP |
490 | static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) |
491 | { | |
492 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
493 | int ret; | |
494 | u8 tmp; | |
495 | *status = 0; | |
496 | ||
a8567cf2 AP |
497 | if (priv->sleeping) |
498 | return 0; | |
499 | ||
c0adca73 AP |
500 | ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ |
501 | if (ret) | |
502 | goto err; | |
503 | ||
504 | if (tmp == 11) { | |
505 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
506 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
507 | } else if (tmp == 10) { | |
508 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
509 | FE_HAS_VITERBI; | |
510 | } | |
511 | ||
512 | return ret; | |
513 | err: | |
86ad0f1d | 514 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
c0adca73 AP |
515 | return ret; |
516 | } | |
517 | ||
518 | static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) | |
519 | { | |
eba672a0 AP |
520 | struct rtl2830_priv *priv = fe->demodulator_priv; |
521 | int ret, hierarchy, constellation; | |
522 | u8 buf[2], tmp; | |
523 | u16 tmp16; | |
524 | #define CONSTELLATION_NUM 3 | |
525 | #define HIERARCHY_NUM 4 | |
526 | static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { | |
527 | { 70705899, 70705899, 70705899, 70705899 }, | |
528 | { 82433173, 82433173, 87483115, 94445660 }, | |
529 | { 92888734, 92888734, 95487525, 99770748 }, | |
530 | }; | |
531 | ||
c188637d AP |
532 | if (priv->sleeping) |
533 | return 0; | |
534 | ||
eba672a0 AP |
535 | /* reports SNR in resolution of 0.1 dB */ |
536 | ||
537 | ret = rtl2830_rd_reg(priv, 0x33c, &tmp); | |
538 | if (ret) | |
539 | goto err; | |
540 | ||
541 | constellation = (tmp >> 2) & 0x03; /* [3:2] */ | |
542 | if (constellation > CONSTELLATION_NUM - 1) | |
543 | goto err; | |
544 | ||
545 | hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ | |
546 | if (hierarchy > HIERARCHY_NUM - 1) | |
547 | goto err; | |
548 | ||
549 | ret = rtl2830_rd_regs(priv, 0x40c, buf, 2); | |
550 | if (ret) | |
551 | goto err; | |
552 | ||
553 | tmp16 = buf[0] << 8 | buf[1]; | |
554 | ||
555 | if (tmp16) | |
556 | *snr = (snr_constant[constellation][hierarchy] - | |
557 | intlog10(tmp16)) / ((1 << 24) / 100); | |
558 | else | |
559 | *snr = 0; | |
560 | ||
c0adca73 | 561 | return 0; |
eba672a0 | 562 | err: |
86ad0f1d | 563 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
eba672a0 | 564 | return ret; |
c0adca73 AP |
565 | } |
566 | ||
567 | static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) | |
568 | { | |
525ffc19 AP |
569 | struct rtl2830_priv *priv = fe->demodulator_priv; |
570 | int ret; | |
571 | u8 buf[2]; | |
572 | ||
c188637d AP |
573 | if (priv->sleeping) |
574 | return 0; | |
575 | ||
525ffc19 AP |
576 | ret = rtl2830_rd_regs(priv, 0x34e, buf, 2); |
577 | if (ret) | |
578 | goto err; | |
579 | ||
580 | *ber = buf[0] << 8 | buf[1]; | |
581 | ||
c0adca73 | 582 | return 0; |
525ffc19 | 583 | err: |
86ad0f1d | 584 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
525ffc19 | 585 | return ret; |
c0adca73 AP |
586 | } |
587 | ||
588 | static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |
589 | { | |
590 | *ucblocks = 0; | |
591 | return 0; | |
592 | } | |
593 | ||
594 | static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | |
595 | { | |
78e75075 AP |
596 | struct rtl2830_priv *priv = fe->demodulator_priv; |
597 | int ret; | |
598 | u8 buf[2]; | |
599 | u16 if_agc_raw, if_agc; | |
600 | ||
c188637d AP |
601 | if (priv->sleeping) |
602 | return 0; | |
603 | ||
78e75075 AP |
604 | ret = rtl2830_rd_regs(priv, 0x359, buf, 2); |
605 | if (ret) | |
606 | goto err; | |
607 | ||
608 | if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff; | |
609 | ||
610 | if (if_agc_raw & (1 << 9)) | |
611 | if_agc = -(~(if_agc_raw - 1) & 0x1ff); | |
612 | else | |
613 | if_agc = if_agc_raw; | |
614 | ||
615 | *strength = (u8) (55 - if_agc / 182); | |
616 | *strength |= *strength << 8; | |
617 | ||
c0adca73 | 618 | return 0; |
78e75075 | 619 | err: |
86ad0f1d | 620 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
78e75075 | 621 | return ret; |
c0adca73 AP |
622 | } |
623 | ||
624 | static struct dvb_frontend_ops rtl2830_ops; | |
625 | ||
626 | static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) | |
627 | { | |
628 | return I2C_FUNC_I2C; | |
629 | } | |
630 | ||
631 | static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, | |
632 | struct i2c_msg msg[], int num) | |
633 | { | |
634 | struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); | |
635 | int ret; | |
636 | ||
637 | /* open i2c-gate */ | |
638 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); | |
639 | if (ret) | |
640 | goto err; | |
641 | ||
642 | ret = i2c_transfer(priv->i2c, msg, num); | |
643 | if (ret < 0) | |
86ad0f1d AP |
644 | dev_warn(&priv->i2c->dev, "%s: tuner i2c failed=%d\n", |
645 | KBUILD_MODNAME, ret); | |
c0adca73 AP |
646 | |
647 | return ret; | |
648 | err: | |
86ad0f1d | 649 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |
c0adca73 AP |
650 | return ret; |
651 | } | |
652 | ||
653 | static struct i2c_algorithm rtl2830_tuner_i2c_algo = { | |
654 | .master_xfer = rtl2830_tuner_i2c_xfer, | |
655 | .functionality = rtl2830_tuner_i2c_func, | |
656 | }; | |
657 | ||
658 | struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) | |
659 | { | |
660 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
661 | return &priv->tuner_i2c_adapter; | |
662 | } | |
663 | EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); | |
664 | ||
665 | static void rtl2830_release(struct dvb_frontend *fe) | |
666 | { | |
667 | struct rtl2830_priv *priv = fe->demodulator_priv; | |
668 | ||
669 | i2c_del_adapter(&priv->tuner_i2c_adapter); | |
670 | kfree(priv); | |
671 | } | |
672 | ||
673 | struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, | |
674 | struct i2c_adapter *i2c) | |
675 | { | |
676 | struct rtl2830_priv *priv = NULL; | |
677 | int ret = 0; | |
678 | u8 tmp; | |
679 | ||
680 | /* allocate memory for the internal state */ | |
681 | priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); | |
682 | if (priv == NULL) | |
683 | goto err; | |
684 | ||
685 | /* setup the priv */ | |
686 | priv->i2c = i2c; | |
687 | memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); | |
688 | ||
689 | /* check if the demod is there */ | |
690 | ret = rtl2830_rd_reg(priv, 0x000, &tmp); | |
691 | if (ret) | |
692 | goto err; | |
693 | ||
694 | /* create dvb_frontend */ | |
695 | memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); | |
696 | priv->fe.demodulator_priv = priv; | |
697 | ||
698 | /* create tuner i2c adapter */ | |
699 | strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", | |
700 | sizeof(priv->tuner_i2c_adapter.name)); | |
701 | priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; | |
702 | priv->tuner_i2c_adapter.algo_data = NULL; | |
703 | i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); | |
704 | if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { | |
86ad0f1d AP |
705 | dev_err(&i2c->dev, |
706 | "%s: tuner i2c bus could not be initialized\n", | |
707 | KBUILD_MODNAME); | |
c0adca73 AP |
708 | goto err; |
709 | } | |
710 | ||
a8567cf2 AP |
711 | priv->sleeping = true; |
712 | ||
c0adca73 AP |
713 | return &priv->fe; |
714 | err: | |
86ad0f1d | 715 | dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); |
c0adca73 AP |
716 | kfree(priv); |
717 | return NULL; | |
718 | } | |
719 | EXPORT_SYMBOL(rtl2830_attach); | |
720 | ||
721 | static struct dvb_frontend_ops rtl2830_ops = { | |
722 | .delsys = { SYS_DVBT }, | |
723 | .info = { | |
724 | .name = "Realtek RTL2830 (DVB-T)", | |
725 | .caps = FE_CAN_FEC_1_2 | | |
726 | FE_CAN_FEC_2_3 | | |
727 | FE_CAN_FEC_3_4 | | |
728 | FE_CAN_FEC_5_6 | | |
729 | FE_CAN_FEC_7_8 | | |
730 | FE_CAN_FEC_AUTO | | |
731 | FE_CAN_QPSK | | |
732 | FE_CAN_QAM_16 | | |
733 | FE_CAN_QAM_64 | | |
734 | FE_CAN_QAM_AUTO | | |
735 | FE_CAN_TRANSMISSION_MODE_AUTO | | |
736 | FE_CAN_GUARD_INTERVAL_AUTO | | |
737 | FE_CAN_HIERARCHY_AUTO | | |
738 | FE_CAN_RECOVER | | |
739 | FE_CAN_MUTE_TS | |
740 | }, | |
741 | ||
742 | .release = rtl2830_release, | |
743 | ||
744 | .init = rtl2830_init, | |
a8567cf2 | 745 | .sleep = rtl2830_sleep, |
c0adca73 AP |
746 | |
747 | .get_tune_settings = rtl2830_get_tune_settings, | |
748 | ||
749 | .set_frontend = rtl2830_set_frontend, | |
631a2b61 | 750 | .get_frontend = rtl2830_get_frontend, |
c0adca73 AP |
751 | |
752 | .read_status = rtl2830_read_status, | |
753 | .read_snr = rtl2830_read_snr, | |
754 | .read_ber = rtl2830_read_ber, | |
755 | .read_ucblocks = rtl2830_read_ucblocks, | |
756 | .read_signal_strength = rtl2830_read_signal_strength, | |
757 | }; | |
758 | ||
759 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | |
760 | MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); | |
761 | MODULE_LICENSE("GPL"); |