blob: 50e8b63e5169bad938b1fc8b79e0871a619364d3 [file] [log] [blame]
Antti Palosaaric0adca72011-07-08 23:34:09 -03001/*
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
Mauro Carvalho Chehab37ebaf62013-11-02 05:11:47 -030030/* Max transfer size done by I2C transfer functions */
31#define MAX_XFER_SIZE 64
32
Antti Palosaari0485a702011-08-04 20:27:19 -030033/* write multiple hardware registers */
Antti Palosaari3a2fca22012-09-12 20:23:49 -030034static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len)
Antti Palosaaric0adca72011-07-08 23:34:09 -030035{
36 int ret;
Mauro Carvalho Chehab37ebaf62013-11-02 05:11:47 -030037 u8 buf[MAX_XFER_SIZE];
Antti Palosaaric0adca72011-07-08 23:34:09 -030038 struct i2c_msg msg[1] = {
39 {
40 .addr = priv->cfg.i2c_addr,
41 .flags = 0,
Mauro Carvalho Chehab37ebaf62013-11-02 05:11:47 -030042 .len = 1 + len,
Antti Palosaaric0adca72011-07-08 23:34:09 -030043 .buf = buf,
44 }
45 };
46
Mauro Carvalho Chehab37ebaf62013-11-02 05:11:47 -030047 if (1 + len > sizeof(buf)) {
48 dev_warn(&priv->i2c->dev,
49 "%s: i2c wr reg=%04x: len=%d is too big!\n",
50 KBUILD_MODNAME, reg, len);
51 return -EINVAL;
52 }
53
Antti Palosaari0485a702011-08-04 20:27:19 -030054 buf[0] = reg;
55 memcpy(&buf[1], val, len);
Antti Palosaaric0adca72011-07-08 23:34:09 -030056
57 ret = i2c_transfer(priv->i2c, msg, 1);
58 if (ret == 1) {
59 ret = 0;
60 } else {
Antti Palosaari86ad0f12012-09-12 20:23:47 -030061 dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
62 "len=%d\n", KBUILD_MODNAME, ret, reg, len);
Antti Palosaaric0adca72011-07-08 23:34:09 -030063 ret = -EREMOTEIO;
64 }
65 return ret;
66}
67
Antti Palosaari0485a702011-08-04 20:27:19 -030068/* read multiple hardware registers */
69static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
Antti Palosaaric0adca72011-07-08 23:34:09 -030070{
71 int ret;
Antti Palosaaric0adca72011-07-08 23:34:09 -030072 struct i2c_msg msg[2] = {
73 {
74 .addr = priv->cfg.i2c_addr,
75 .flags = 0,
Antti Palosaari0485a702011-08-04 20:27:19 -030076 .len = 1,
77 .buf = &reg,
Antti Palosaaric0adca72011-07-08 23:34:09 -030078 }, {
79 .addr = priv->cfg.i2c_addr,
80 .flags = I2C_M_RD,
81 .len = len,
82 .buf = val,
83 }
84 };
85
Antti Palosaaric0adca72011-07-08 23:34:09 -030086 ret = i2c_transfer(priv->i2c, msg, 2);
87 if (ret == 2) {
88 ret = 0;
89 } else {
Antti Palosaari86ad0f12012-09-12 20:23:47 -030090 dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
91 "len=%d\n", KBUILD_MODNAME, ret, reg, len);
Antti Palosaaric0adca72011-07-08 23:34:09 -030092 ret = -EREMOTEIO;
93 }
94 return ret;
95}
96
Antti Palosaari0485a702011-08-04 20:27:19 -030097/* write multiple registers */
Antti Palosaari3a2fca22012-09-12 20:23:49 -030098static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, const u8 *val,
99 int len)
Antti Palosaari0485a702011-08-04 20:27:19 -0300100{
101 int ret;
102 u8 reg2 = (reg >> 0) & 0xff;
103 u8 page = (reg >> 8) & 0xff;
104
105 /* switch bank if needed */
106 if (page != priv->page) {
107 ret = rtl2830_wr(priv, 0x00, &page, 1);
108 if (ret)
109 return ret;
110
111 priv->page = page;
112 }
113
114 return rtl2830_wr(priv, reg2, val, len);
115}
116
117/* read multiple registers */
118static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
119{
120 int ret;
121 u8 reg2 = (reg >> 0) & 0xff;
122 u8 page = (reg >> 8) & 0xff;
123
124 /* switch bank if needed */
125 if (page != priv->page) {
126 ret = rtl2830_wr(priv, 0x00, &page, 1);
127 if (ret)
128 return ret;
129
130 priv->page = page;
131 }
132
133 return rtl2830_rd(priv, reg2, val, len);
134}
135
Antti Palosaaric0adca72011-07-08 23:34:09 -0300136/* read single register */
137static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
138{
139 return rtl2830_rd_regs(priv, reg, val, 1);
140}
141
142/* write single register with mask */
Mauro Carvalho Chehaba17ff2e2012-10-27 11:24:08 -0300143static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
Antti Palosaaric0adca72011-07-08 23:34:09 -0300144{
145 int ret;
146 u8 tmp;
147
148 /* no need for read if whole reg is written */
149 if (mask != 0xff) {
150 ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
151 if (ret)
152 return ret;
153
154 val &= mask;
155 tmp &= ~mask;
156 val |= tmp;
157 }
158
159 return rtl2830_wr_regs(priv, reg, &val, 1);
160}
161
162/* read single register with mask */
Mauro Carvalho Chehaba17ff2e2012-10-27 11:24:08 -0300163static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
Antti Palosaaric0adca72011-07-08 23:34:09 -0300164{
165 int ret, i;
166 u8 tmp;
167
168 ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
169 if (ret)
170 return ret;
171
172 tmp &= mask;
173
174 /* find position of the first bit */
175 for (i = 0; i < 8; i++) {
176 if ((mask >> i) & 0x01)
177 break;
178 }
179 *val = tmp >> i;
180
181 return 0;
182}
183
184static int rtl2830_init(struct dvb_frontend *fe)
185{
186 struct rtl2830_priv *priv = fe->demodulator_priv;
187 int ret, i;
Antti Palosaaric0adca72011-07-08 23:34:09 -0300188 struct rtl2830_reg_val_mask tab[] = {
189 { 0x00d, 0x01, 0x03 },
190 { 0x00d, 0x10, 0x10 },
191 { 0x104, 0x00, 0x1e },
192 { 0x105, 0x80, 0x80 },
193 { 0x110, 0x02, 0x03 },
194 { 0x110, 0x08, 0x0c },
195 { 0x17b, 0x00, 0x40 },
196 { 0x17d, 0x05, 0x0f },
197 { 0x17d, 0x50, 0xf0 },
198 { 0x18c, 0x08, 0x0f },
199 { 0x18d, 0x00, 0xc0 },
200 { 0x188, 0x05, 0x0f },
201 { 0x189, 0x00, 0xfc },
202 { 0x2d5, 0x02, 0x02 },
203 { 0x2f1, 0x02, 0x06 },
204 { 0x2f1, 0x20, 0xf8 },
205 { 0x16d, 0x00, 0x01 },
206 { 0x1a6, 0x00, 0x80 },
207 { 0x106, priv->cfg.vtop, 0x3f },
208 { 0x107, priv->cfg.krf, 0x3f },
209 { 0x112, 0x28, 0xff },
210 { 0x103, priv->cfg.agc_targ_val, 0xff },
211 { 0x00a, 0x02, 0x07 },
212 { 0x140, 0x0c, 0x3c },
213 { 0x140, 0x40, 0xc0 },
214 { 0x15b, 0x05, 0x07 },
215 { 0x15b, 0x28, 0x38 },
216 { 0x15c, 0x05, 0x07 },
217 { 0x15c, 0x28, 0x38 },
218 { 0x115, priv->cfg.spec_inv, 0x01 },
219 { 0x16f, 0x01, 0x07 },
220 { 0x170, 0x18, 0x38 },
221 { 0x172, 0x0f, 0x0f },
222 { 0x173, 0x08, 0x38 },
223 { 0x175, 0x01, 0x07 },
224 { 0x176, 0x00, 0xc0 },
225 };
226
227 for (i = 0; i < ARRAY_SIZE(tab); i++) {
228 ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
229 tab[i].mask);
230 if (ret)
231 goto err;
232 }
233
234 ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
235 if (ret)
236 goto err;
237
238 ret = rtl2830_wr_regs(priv, 0x195,
239 "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
240 if (ret)
241 goto err;
242
Antti Palosaaric0adca72011-07-08 23:34:09 -0300243 /* TODO: spec init */
244
245 /* soft reset */
246 ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
247 if (ret)
248 goto err;
249
250 ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
251 if (ret)
252 goto err;
253
Antti Palosaaria8567cf2012-01-21 22:40:58 -0300254 priv->sleeping = false;
255
Antti Palosaaric0adca72011-07-08 23:34:09 -0300256 return ret;
257err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300258 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300259 return ret;
260}
261
Antti Palosaaria8567cf2012-01-21 22:40:58 -0300262static int rtl2830_sleep(struct dvb_frontend *fe)
263{
264 struct rtl2830_priv *priv = fe->demodulator_priv;
265 priv->sleeping = true;
266 return 0;
267}
268
Mauro Carvalho Chehaba17ff2e2012-10-27 11:24:08 -0300269static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
Antti Palosaaric0adca72011-07-08 23:34:09 -0300270 struct dvb_frontend_tune_settings *s)
271{
272 s->min_delay_ms = 500;
273 s->step_size = fe->ops.info.frequency_stepsize * 2;
274 s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
275
276 return 0;
277}
278
279static int rtl2830_set_frontend(struct dvb_frontend *fe)
280{
281 struct rtl2830_priv *priv = fe->demodulator_priv;
282 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
283 int ret, i;
Antti Palosaari66b3c4d2012-09-12 20:23:48 -0300284 u64 num;
285 u8 buf[3], tmp;
286 u32 if_ctl, if_frequency;
Antti Palosaari3a2fca22012-09-12 20:23:49 -0300287 static const u8 bw_params1[3][34] = {
Antti Palosaaric0adca72011-07-08 23:34:09 -0300288 {
289 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
290 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
291 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
292 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
293 }, {
294 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
295 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
296 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
297 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
298 }, {
299 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
300 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
301 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
302 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
303 },
304 };
Antti Palosaari3a2fca22012-09-12 20:23:49 -0300305 static const u8 bw_params2[3][6] = {
306 {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30}, /* 6 MHz */
307 {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98}, /* 7 MHz */
308 {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */
Antti Palosaaric0adca72011-07-08 23:34:09 -0300309 };
310
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300311 dev_dbg(&priv->i2c->dev,
312 "%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
313 __func__, c->frequency, c->bandwidth_hz, c->inversion);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300314
315 /* program tuner */
316 if (fe->ops.tuner_ops.set_params)
317 fe->ops.tuner_ops.set_params(fe);
318
319 switch (c->bandwidth_hz) {
320 case 6000000:
321 i = 0;
322 break;
323 case 7000000:
324 i = 1;
325 break;
326 case 8000000:
327 i = 2;
328 break;
329 default:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300330 dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300331 return -EINVAL;
332 }
333
334 ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
335 if (ret)
336 goto err;
337
Antti Palosaari66b3c4d2012-09-12 20:23:48 -0300338 /* program if frequency */
339 if (fe->ops.tuner_ops.get_if_frequency)
340 ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
341 else
342 ret = -EINVAL;
343
344 if (ret < 0)
345 goto err;
346
347 num = if_frequency % priv->cfg.xtal;
348 num *= 0x400000;
349 num = div_u64(num, priv->cfg.xtal);
350 num = -num;
351 if_ctl = num & 0x3fffff;
352 dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d if_ctl=%08x\n",
353 __func__, if_frequency, if_ctl);
354
355 ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
356 if (ret)
357 goto err;
358
359 buf[0] = tmp << 6;
360 buf[0] |= (if_ctl >> 16) & 0x3f;
361 buf[1] = (if_ctl >> 8) & 0xff;
362 buf[2] = (if_ctl >> 0) & 0xff;
363
364 ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
365 if (ret)
366 goto err;
367
Antti Palosaaric0adca72011-07-08 23:34:09 -0300368 /* 1/2 split I2C write */
369 ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
370 if (ret)
371 goto err;
372
373 /* 2/2 split I2C write */
374 ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
375 if (ret)
376 goto err;
377
378 ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
379 if (ret)
380 goto err;
381
382 return ret;
383err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300384 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300385 return ret;
386}
387
Antti Palosaari631a2b62012-05-18 15:58:57 -0300388static int rtl2830_get_frontend(struct dvb_frontend *fe)
389{
390 struct rtl2830_priv *priv = fe->demodulator_priv;
391 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
392 int ret;
393 u8 buf[3];
394
Antti Palosaaric1886372012-05-18 16:02:55 -0300395 if (priv->sleeping)
396 return 0;
397
Antti Palosaari631a2b62012-05-18 15:58:57 -0300398 ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
399 if (ret)
400 goto err;
401
402 ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
403 if (ret)
404 goto err;
405
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300406 dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf);
Antti Palosaari631a2b62012-05-18 15:58:57 -0300407
408 switch ((buf[0] >> 2) & 3) {
409 case 0:
410 c->modulation = QPSK;
411 break;
412 case 1:
413 c->modulation = QAM_16;
414 break;
415 case 2:
416 c->modulation = QAM_64;
417 break;
418 }
419
420 switch ((buf[2] >> 2) & 1) {
421 case 0:
422 c->transmission_mode = TRANSMISSION_MODE_2K;
423 break;
424 case 1:
425 c->transmission_mode = TRANSMISSION_MODE_8K;
426 }
427
428 switch ((buf[2] >> 0) & 3) {
429 case 0:
430 c->guard_interval = GUARD_INTERVAL_1_32;
431 break;
432 case 1:
433 c->guard_interval = GUARD_INTERVAL_1_16;
434 break;
435 case 2:
436 c->guard_interval = GUARD_INTERVAL_1_8;
437 break;
438 case 3:
439 c->guard_interval = GUARD_INTERVAL_1_4;
440 break;
441 }
442
443 switch ((buf[0] >> 4) & 7) {
444 case 0:
445 c->hierarchy = HIERARCHY_NONE;
446 break;
447 case 1:
448 c->hierarchy = HIERARCHY_1;
449 break;
450 case 2:
451 c->hierarchy = HIERARCHY_2;
452 break;
453 case 3:
454 c->hierarchy = HIERARCHY_4;
455 break;
456 }
457
458 switch ((buf[1] >> 3) & 7) {
459 case 0:
460 c->code_rate_HP = FEC_1_2;
461 break;
462 case 1:
463 c->code_rate_HP = FEC_2_3;
464 break;
465 case 2:
466 c->code_rate_HP = FEC_3_4;
467 break;
468 case 3:
469 c->code_rate_HP = FEC_5_6;
470 break;
471 case 4:
472 c->code_rate_HP = FEC_7_8;
473 break;
474 }
475
476 switch ((buf[1] >> 0) & 7) {
477 case 0:
478 c->code_rate_LP = FEC_1_2;
479 break;
480 case 1:
481 c->code_rate_LP = FEC_2_3;
482 break;
483 case 2:
484 c->code_rate_LP = FEC_3_4;
485 break;
486 case 3:
487 c->code_rate_LP = FEC_5_6;
488 break;
489 case 4:
490 c->code_rate_LP = FEC_7_8;
491 break;
492 }
493
494 return 0;
495err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300496 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaari631a2b62012-05-18 15:58:57 -0300497 return ret;
498}
499
Antti Palosaaric0adca72011-07-08 23:34:09 -0300500static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
501{
502 struct rtl2830_priv *priv = fe->demodulator_priv;
503 int ret;
504 u8 tmp;
505 *status = 0;
506
Antti Palosaaria8567cf2012-01-21 22:40:58 -0300507 if (priv->sleeping)
508 return 0;
509
Antti Palosaaric0adca72011-07-08 23:34:09 -0300510 ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
511 if (ret)
512 goto err;
513
514 if (tmp == 11) {
515 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
516 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
517 } else if (tmp == 10) {
518 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
519 FE_HAS_VITERBI;
520 }
521
522 return ret;
523err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300524 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300525 return ret;
526}
527
528static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
529{
Antti Palosaarieba672a2012-05-15 18:32:33 -0300530 struct rtl2830_priv *priv = fe->demodulator_priv;
531 int ret, hierarchy, constellation;
532 u8 buf[2], tmp;
533 u16 tmp16;
534#define CONSTELLATION_NUM 3
535#define HIERARCHY_NUM 4
536 static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
537 { 70705899, 70705899, 70705899, 70705899 },
538 { 82433173, 82433173, 87483115, 94445660 },
539 { 92888734, 92888734, 95487525, 99770748 },
540 };
541
Antti Palosaaric1886372012-05-18 16:02:55 -0300542 if (priv->sleeping)
543 return 0;
544
Antti Palosaarieba672a2012-05-15 18:32:33 -0300545 /* reports SNR in resolution of 0.1 dB */
546
547 ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
548 if (ret)
549 goto err;
550
551 constellation = (tmp >> 2) & 0x03; /* [3:2] */
552 if (constellation > CONSTELLATION_NUM - 1)
553 goto err;
554
555 hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
556 if (hierarchy > HIERARCHY_NUM - 1)
557 goto err;
558
559 ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
560 if (ret)
561 goto err;
562
563 tmp16 = buf[0] << 8 | buf[1];
564
565 if (tmp16)
566 *snr = (snr_constant[constellation][hierarchy] -
567 intlog10(tmp16)) / ((1 << 24) / 100);
568 else
569 *snr = 0;
570
Antti Palosaaric0adca72011-07-08 23:34:09 -0300571 return 0;
Antti Palosaarieba672a2012-05-15 18:32:33 -0300572err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300573 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaarieba672a2012-05-15 18:32:33 -0300574 return ret;
Antti Palosaaric0adca72011-07-08 23:34:09 -0300575}
576
577static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
578{
Antti Palosaari525ffc12012-05-18 12:23:42 -0300579 struct rtl2830_priv *priv = fe->demodulator_priv;
580 int ret;
581 u8 buf[2];
582
Antti Palosaaric1886372012-05-18 16:02:55 -0300583 if (priv->sleeping)
584 return 0;
585
Antti Palosaari525ffc12012-05-18 12:23:42 -0300586 ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
587 if (ret)
588 goto err;
589
590 *ber = buf[0] << 8 | buf[1];
591
Antti Palosaaric0adca72011-07-08 23:34:09 -0300592 return 0;
Antti Palosaari525ffc12012-05-18 12:23:42 -0300593err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300594 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaari525ffc12012-05-18 12:23:42 -0300595 return ret;
Antti Palosaaric0adca72011-07-08 23:34:09 -0300596}
597
598static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
599{
600 *ucblocks = 0;
601 return 0;
602}
603
604static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
605{
Antti Palosaari78e75072012-05-18 15:17:51 -0300606 struct rtl2830_priv *priv = fe->demodulator_priv;
607 int ret;
608 u8 buf[2];
609 u16 if_agc_raw, if_agc;
610
Antti Palosaaric1886372012-05-18 16:02:55 -0300611 if (priv->sleeping)
612 return 0;
613
Antti Palosaari78e75072012-05-18 15:17:51 -0300614 ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
615 if (ret)
616 goto err;
617
618 if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
619
620 if (if_agc_raw & (1 << 9))
621 if_agc = -(~(if_agc_raw - 1) & 0x1ff);
622 else
623 if_agc = if_agc_raw;
624
625 *strength = (u8) (55 - if_agc / 182);
626 *strength |= *strength << 8;
627
Antti Palosaaric0adca72011-07-08 23:34:09 -0300628 return 0;
Antti Palosaari78e75072012-05-18 15:17:51 -0300629err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300630 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaari78e75072012-05-18 15:17:51 -0300631 return ret;
Antti Palosaaric0adca72011-07-08 23:34:09 -0300632}
633
634static struct dvb_frontend_ops rtl2830_ops;
635
636static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
637{
638 return I2C_FUNC_I2C;
639}
640
641static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
642 struct i2c_msg msg[], int num)
643{
644 struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
645 int ret;
646
647 /* open i2c-gate */
648 ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
649 if (ret)
650 goto err;
651
652 ret = i2c_transfer(priv->i2c, msg, num);
653 if (ret < 0)
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300654 dev_warn(&priv->i2c->dev, "%s: tuner i2c failed=%d\n",
655 KBUILD_MODNAME, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300656
657 return ret;
658err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300659 dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300660 return ret;
661}
662
663static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
664 .master_xfer = rtl2830_tuner_i2c_xfer,
665 .functionality = rtl2830_tuner_i2c_func,
666};
667
668struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
669{
670 struct rtl2830_priv *priv = fe->demodulator_priv;
671 return &priv->tuner_i2c_adapter;
672}
673EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
674
675static void rtl2830_release(struct dvb_frontend *fe)
676{
677 struct rtl2830_priv *priv = fe->demodulator_priv;
678
679 i2c_del_adapter(&priv->tuner_i2c_adapter);
680 kfree(priv);
681}
682
683struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
684 struct i2c_adapter *i2c)
685{
686 struct rtl2830_priv *priv = NULL;
687 int ret = 0;
688 u8 tmp;
689
690 /* allocate memory for the internal state */
691 priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
692 if (priv == NULL)
693 goto err;
694
695 /* setup the priv */
696 priv->i2c = i2c;
697 memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
698
699 /* check if the demod is there */
700 ret = rtl2830_rd_reg(priv, 0x000, &tmp);
701 if (ret)
702 goto err;
703
704 /* create dvb_frontend */
705 memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
706 priv->fe.demodulator_priv = priv;
707
708 /* create tuner i2c adapter */
709 strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
710 sizeof(priv->tuner_i2c_adapter.name));
711 priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
712 priv->tuner_i2c_adapter.algo_data = NULL;
Antti Palosaarieed5b0c2013-10-21 16:56:36 -0300713 priv->tuner_i2c_adapter.dev.parent = &i2c->dev;
Antti Palosaaric0adca72011-07-08 23:34:09 -0300714 i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
715 if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300716 dev_err(&i2c->dev,
717 "%s: tuner i2c bus could not be initialized\n",
718 KBUILD_MODNAME);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300719 goto err;
720 }
721
Antti Palosaaria8567cf2012-01-21 22:40:58 -0300722 priv->sleeping = true;
723
Antti Palosaaric0adca72011-07-08 23:34:09 -0300724 return &priv->fe;
725err:
Antti Palosaari86ad0f12012-09-12 20:23:47 -0300726 dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
Antti Palosaaric0adca72011-07-08 23:34:09 -0300727 kfree(priv);
728 return NULL;
729}
730EXPORT_SYMBOL(rtl2830_attach);
731
732static struct dvb_frontend_ops rtl2830_ops = {
733 .delsys = { SYS_DVBT },
734 .info = {
735 .name = "Realtek RTL2830 (DVB-T)",
736 .caps = FE_CAN_FEC_1_2 |
737 FE_CAN_FEC_2_3 |
738 FE_CAN_FEC_3_4 |
739 FE_CAN_FEC_5_6 |
740 FE_CAN_FEC_7_8 |
741 FE_CAN_FEC_AUTO |
742 FE_CAN_QPSK |
743 FE_CAN_QAM_16 |
744 FE_CAN_QAM_64 |
745 FE_CAN_QAM_AUTO |
746 FE_CAN_TRANSMISSION_MODE_AUTO |
747 FE_CAN_GUARD_INTERVAL_AUTO |
748 FE_CAN_HIERARCHY_AUTO |
749 FE_CAN_RECOVER |
750 FE_CAN_MUTE_TS
751 },
752
753 .release = rtl2830_release,
754
755 .init = rtl2830_init,
Antti Palosaaria8567cf2012-01-21 22:40:58 -0300756 .sleep = rtl2830_sleep,
Antti Palosaaric0adca72011-07-08 23:34:09 -0300757
758 .get_tune_settings = rtl2830_get_tune_settings,
759
760 .set_frontend = rtl2830_set_frontend,
Antti Palosaari631a2b62012-05-18 15:58:57 -0300761 .get_frontend = rtl2830_get_frontend,
Antti Palosaaric0adca72011-07-08 23:34:09 -0300762
763 .read_status = rtl2830_read_status,
764 .read_snr = rtl2830_read_snr,
765 .read_ber = rtl2830_read_ber,
766 .read_ucblocks = rtl2830_read_ucblocks,
767 .read_signal_strength = rtl2830_read_signal_strength,
768};
769
770MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
771MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
772MODULE_LICENSE("GPL");