diff options
author | Antti Palosaari <crope@iki.fi> | 2011-07-08 22:34:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-02-28 16:31:37 -0500 |
commit | c0adca734013389ac81513da546947e75d95151a (patch) | |
tree | 0faa6cd3715129092a41e90b2e817e2a0949a5bc | |
parent | 5145aa76e6f6d5562f931cc719683002be7a0f81 (diff) |
[media] Realtek RTL2830 DVB-T demodulator driver
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-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/rtl2830.c | 514 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/rtl2830.h | 97 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/rtl2830_priv.h | 53 |
5 files changed, 672 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ebb5ed7a7783..2995204c3355 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -425,6 +425,13 @@ config DVB_CXD2820R | |||
425 | help | 425 | help |
426 | Say Y when you want to support this frontend. | 426 | Say Y when you want to support this frontend. |
427 | 427 | ||
428 | config DVB_RTL2830 | ||
429 | tristate "Realtek RTL2830 DVB-T" | ||
430 | depends on DVB_CORE && I2C | ||
431 | default m if DVB_FE_CUSTOMISE | ||
432 | help | ||
433 | Say Y when you want to support this frontend. | ||
434 | |||
428 | comment "DVB-C (cable) frontends" | 435 | comment "DVB-C (cable) frontends" |
429 | depends on DVB_CORE | 436 | depends on DVB_CORE |
430 | 437 | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 00a20636df62..7f85e64cdcb1 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -96,4 +96,5 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o | |||
96 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o | 96 | obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o |
97 | obj-$(CONFIG_DVB_A8293) += a8293.o | 97 | obj-$(CONFIG_DVB_A8293) += a8293.o |
98 | obj-$(CONFIG_DVB_TDA10071) += tda10071.o | 98 | obj-$(CONFIG_DVB_TDA10071) += tda10071.o |
99 | obj-$(CONFIG_DVB_RTL2830) += rtl2830.o | ||
99 | 100 | ||
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c new file mode 100644 index 000000000000..37a9fa29874e --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830.c | |||
@@ -0,0 +1,514 @@ | |||
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 | |||
30 | int rtl2830_debug; | ||
31 | module_param_named(debug, rtl2830_debug, int, 0644); | ||
32 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
33 | |||
34 | /* write multiple registers */ | ||
35 | static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) | ||
36 | { | ||
37 | int ret; | ||
38 | u8 buf[2+len]; | ||
39 | struct i2c_msg msg[1] = { | ||
40 | { | ||
41 | .addr = priv->cfg.i2c_addr, | ||
42 | .flags = 0, | ||
43 | .len = sizeof(buf), | ||
44 | .buf = buf, | ||
45 | } | ||
46 | }; | ||
47 | |||
48 | buf[0] = (reg >> 8) & 0xff; | ||
49 | buf[1] = (reg >> 0) & 0xff; | ||
50 | memcpy(&buf[2], val, len); | ||
51 | |||
52 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
53 | if (ret == 1) { | ||
54 | ret = 0; | ||
55 | } else { | ||
56 | warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len); | ||
57 | ret = -EREMOTEIO; | ||
58 | } | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | /* read multiple registers */ | ||
63 | static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) | ||
64 | { | ||
65 | int ret; | ||
66 | u8 buf[2]; | ||
67 | struct i2c_msg msg[2] = { | ||
68 | { | ||
69 | .addr = priv->cfg.i2c_addr, | ||
70 | .flags = 0, | ||
71 | .len = sizeof(buf), | ||
72 | .buf = buf, | ||
73 | }, { | ||
74 | .addr = priv->cfg.i2c_addr, | ||
75 | .flags = I2C_M_RD, | ||
76 | .len = len, | ||
77 | .buf = val, | ||
78 | } | ||
79 | }; | ||
80 | |||
81 | buf[0] = (reg >> 8) & 0xff; | ||
82 | buf[1] = (reg >> 0) & 0xff; | ||
83 | |||
84 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
85 | if (ret == 2) { | ||
86 | ret = 0; | ||
87 | } else { | ||
88 | warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len); | ||
89 | ret = -EREMOTEIO; | ||
90 | } | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | #if 0 /* currently not used */ | ||
95 | /* write single register */ | ||
96 | static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val) | ||
97 | { | ||
98 | return rtl2830_wr_regs(priv, reg, &val, 1); | ||
99 | } | ||
100 | #endif | ||
101 | |||
102 | /* read single register */ | ||
103 | static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) | ||
104 | { | ||
105 | return rtl2830_rd_regs(priv, reg, val, 1); | ||
106 | } | ||
107 | |||
108 | /* write single register with mask */ | ||
109 | int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) | ||
110 | { | ||
111 | int ret; | ||
112 | u8 tmp; | ||
113 | |||
114 | /* no need for read if whole reg is written */ | ||
115 | if (mask != 0xff) { | ||
116 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | ||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | val &= mask; | ||
121 | tmp &= ~mask; | ||
122 | val |= tmp; | ||
123 | } | ||
124 | |||
125 | return rtl2830_wr_regs(priv, reg, &val, 1); | ||
126 | } | ||
127 | |||
128 | /* read single register with mask */ | ||
129 | int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) | ||
130 | { | ||
131 | int ret, i; | ||
132 | u8 tmp; | ||
133 | |||
134 | ret = rtl2830_rd_regs(priv, reg, &tmp, 1); | ||
135 | if (ret) | ||
136 | return ret; | ||
137 | |||
138 | tmp &= mask; | ||
139 | |||
140 | /* find position of the first bit */ | ||
141 | for (i = 0; i < 8; i++) { | ||
142 | if ((mask >> i) & 0x01) | ||
143 | break; | ||
144 | } | ||
145 | *val = tmp >> i; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int rtl2830_init(struct dvb_frontend *fe) | ||
151 | { | ||
152 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
153 | int ret, i; | ||
154 | u64 num; | ||
155 | u8 buf[3], tmp; | ||
156 | u32 if_ctl; | ||
157 | struct rtl2830_reg_val_mask tab[] = { | ||
158 | { 0x00d, 0x01, 0x03 }, | ||
159 | { 0x00d, 0x10, 0x10 }, | ||
160 | { 0x104, 0x00, 0x1e }, | ||
161 | { 0x105, 0x80, 0x80 }, | ||
162 | { 0x110, 0x02, 0x03 }, | ||
163 | { 0x110, 0x08, 0x0c }, | ||
164 | { 0x17b, 0x00, 0x40 }, | ||
165 | { 0x17d, 0x05, 0x0f }, | ||
166 | { 0x17d, 0x50, 0xf0 }, | ||
167 | { 0x18c, 0x08, 0x0f }, | ||
168 | { 0x18d, 0x00, 0xc0 }, | ||
169 | { 0x188, 0x05, 0x0f }, | ||
170 | { 0x189, 0x00, 0xfc }, | ||
171 | { 0x2d5, 0x02, 0x02 }, | ||
172 | { 0x2f1, 0x02, 0x06 }, | ||
173 | { 0x2f1, 0x20, 0xf8 }, | ||
174 | { 0x16d, 0x00, 0x01 }, | ||
175 | { 0x1a6, 0x00, 0x80 }, | ||
176 | { 0x106, priv->cfg.vtop, 0x3f }, | ||
177 | { 0x107, priv->cfg.krf, 0x3f }, | ||
178 | { 0x112, 0x28, 0xff }, | ||
179 | { 0x103, priv->cfg.agc_targ_val, 0xff }, | ||
180 | { 0x00a, 0x02, 0x07 }, | ||
181 | { 0x140, 0x0c, 0x3c }, | ||
182 | { 0x140, 0x40, 0xc0 }, | ||
183 | { 0x15b, 0x05, 0x07 }, | ||
184 | { 0x15b, 0x28, 0x38 }, | ||
185 | { 0x15c, 0x05, 0x07 }, | ||
186 | { 0x15c, 0x28, 0x38 }, | ||
187 | { 0x115, priv->cfg.spec_inv, 0x01 }, | ||
188 | { 0x16f, 0x01, 0x07 }, | ||
189 | { 0x170, 0x18, 0x38 }, | ||
190 | { 0x172, 0x0f, 0x0f }, | ||
191 | { 0x173, 0x08, 0x38 }, | ||
192 | { 0x175, 0x01, 0x07 }, | ||
193 | { 0x176, 0x00, 0xc0 }, | ||
194 | }; | ||
195 | |||
196 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | ||
197 | ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, | ||
198 | tab[i].mask); | ||
199 | if (ret) | ||
200 | goto err; | ||
201 | } | ||
202 | |||
203 | ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); | ||
204 | if (ret) | ||
205 | goto err; | ||
206 | |||
207 | ret = rtl2830_wr_regs(priv, 0x195, | ||
208 | "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); | ||
209 | if (ret) | ||
210 | goto err; | ||
211 | |||
212 | num = priv->cfg.if_dvbt % priv->cfg.xtal; | ||
213 | num *= 0x400000; | ||
214 | num /= priv->cfg.xtal; | ||
215 | num = -num; | ||
216 | if_ctl = num & 0x3fffff; | ||
217 | dbg("%s: if_ctl=%08x", __func__, if_ctl); | ||
218 | |||
219 | ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ | ||
220 | if (ret) | ||
221 | goto err; | ||
222 | |||
223 | buf[0] = tmp << 6; | ||
224 | buf[0] = (if_ctl >> 16) & 0x3f; | ||
225 | buf[1] = (if_ctl >> 8) & 0xff; | ||
226 | buf[2] = (if_ctl >> 0) & 0xff; | ||
227 | |||
228 | ret = rtl2830_wr_regs(priv, 0x119, buf, 3); | ||
229 | if (ret) | ||
230 | goto err; | ||
231 | |||
232 | /* TODO: spec init */ | ||
233 | |||
234 | /* soft reset */ | ||
235 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); | ||
236 | if (ret) | ||
237 | goto err; | ||
238 | |||
239 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); | ||
240 | if (ret) | ||
241 | goto err; | ||
242 | |||
243 | return ret; | ||
244 | err: | ||
245 | dbg("%s: failed=%d", __func__, ret); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | int rtl2830_get_tune_settings(struct dvb_frontend *fe, | ||
250 | struct dvb_frontend_tune_settings *s) | ||
251 | { | ||
252 | s->min_delay_ms = 500; | ||
253 | s->step_size = fe->ops.info.frequency_stepsize * 2; | ||
254 | s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int rtl2830_set_frontend(struct dvb_frontend *fe) | ||
260 | { | ||
261 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
262 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
263 | int ret, i; | ||
264 | static u8 bw_params1[3][34] = { | ||
265 | { | ||
266 | 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, | ||
267 | 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, | ||
268 | 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, | ||
269 | 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ | ||
270 | }, { | ||
271 | 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, | ||
272 | 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, | ||
273 | 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, | ||
274 | 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ | ||
275 | }, { | ||
276 | 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, | ||
277 | 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, | ||
278 | 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, | ||
279 | 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ | ||
280 | }, | ||
281 | }; | ||
282 | static u8 bw_params2[3][6] = { | ||
283 | {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */ | ||
284 | {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */ | ||
285 | {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */ | ||
286 | }; | ||
287 | |||
288 | |||
289 | dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__, | ||
290 | c->frequency, c->bandwidth_hz, c->inversion); | ||
291 | |||
292 | /* program tuner */ | ||
293 | if (fe->ops.tuner_ops.set_params) | ||
294 | fe->ops.tuner_ops.set_params(fe); | ||
295 | |||
296 | switch (c->bandwidth_hz) { | ||
297 | case 6000000: | ||
298 | i = 0; | ||
299 | break; | ||
300 | case 7000000: | ||
301 | i = 1; | ||
302 | break; | ||
303 | case 8000000: | ||
304 | i = 2; | ||
305 | break; | ||
306 | default: | ||
307 | dbg("invalid bandwidth"); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); | ||
312 | if (ret) | ||
313 | goto err; | ||
314 | |||
315 | /* 1/2 split I2C write */ | ||
316 | ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); | ||
317 | if (ret) | ||
318 | goto err; | ||
319 | |||
320 | /* 2/2 split I2C write */ | ||
321 | ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); | ||
322 | if (ret) | ||
323 | goto err; | ||
324 | |||
325 | ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); | ||
326 | if (ret) | ||
327 | goto err; | ||
328 | |||
329 | return ret; | ||
330 | err: | ||
331 | dbg("%s: failed=%d", __func__, ret); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
336 | { | ||
337 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
338 | int ret; | ||
339 | u8 tmp; | ||
340 | *status = 0; | ||
341 | |||
342 | ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ | ||
343 | if (ret) | ||
344 | goto err; | ||
345 | |||
346 | if (tmp == 11) { | ||
347 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
348 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
349 | } else if (tmp == 10) { | ||
350 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
351 | FE_HAS_VITERBI; | ||
352 | } | ||
353 | |||
354 | return ret; | ||
355 | err: | ||
356 | dbg("%s: failed=%d", __func__, ret); | ||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
361 | { | ||
362 | *snr = 0; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
367 | { | ||
368 | *ber = 0; | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
373 | { | ||
374 | *ucblocks = 0; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
379 | { | ||
380 | *strength = 0; | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static struct dvb_frontend_ops rtl2830_ops; | ||
385 | |||
386 | static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) | ||
387 | { | ||
388 | return I2C_FUNC_I2C; | ||
389 | } | ||
390 | |||
391 | static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
392 | struct i2c_msg msg[], int num) | ||
393 | { | ||
394 | struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); | ||
395 | int ret; | ||
396 | |||
397 | /* open i2c-gate */ | ||
398 | ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); | ||
399 | if (ret) | ||
400 | goto err; | ||
401 | |||
402 | ret = i2c_transfer(priv->i2c, msg, num); | ||
403 | if (ret < 0) | ||
404 | warn("tuner i2c failed=%d", ret); | ||
405 | |||
406 | return ret; | ||
407 | err: | ||
408 | dbg("%s: failed=%d", __func__, ret); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static struct i2c_algorithm rtl2830_tuner_i2c_algo = { | ||
413 | .master_xfer = rtl2830_tuner_i2c_xfer, | ||
414 | .functionality = rtl2830_tuner_i2c_func, | ||
415 | }; | ||
416 | |||
417 | struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) | ||
418 | { | ||
419 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
420 | return &priv->tuner_i2c_adapter; | ||
421 | } | ||
422 | EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); | ||
423 | |||
424 | static void rtl2830_release(struct dvb_frontend *fe) | ||
425 | { | ||
426 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
427 | |||
428 | i2c_del_adapter(&priv->tuner_i2c_adapter); | ||
429 | kfree(priv); | ||
430 | } | ||
431 | |||
432 | struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, | ||
433 | struct i2c_adapter *i2c) | ||
434 | { | ||
435 | struct rtl2830_priv *priv = NULL; | ||
436 | int ret = 0; | ||
437 | u8 tmp; | ||
438 | |||
439 | /* allocate memory for the internal state */ | ||
440 | priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); | ||
441 | if (priv == NULL) | ||
442 | goto err; | ||
443 | |||
444 | /* setup the priv */ | ||
445 | priv->i2c = i2c; | ||
446 | memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); | ||
447 | |||
448 | /* check if the demod is there */ | ||
449 | ret = rtl2830_rd_reg(priv, 0x000, &tmp); | ||
450 | if (ret) | ||
451 | goto err; | ||
452 | |||
453 | /* create dvb_frontend */ | ||
454 | memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); | ||
455 | priv->fe.demodulator_priv = priv; | ||
456 | |||
457 | /* create tuner i2c adapter */ | ||
458 | strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", | ||
459 | sizeof(priv->tuner_i2c_adapter.name)); | ||
460 | priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; | ||
461 | priv->tuner_i2c_adapter.algo_data = NULL; | ||
462 | i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); | ||
463 | if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { | ||
464 | err("tuner I2C bus could not be initialized"); | ||
465 | goto err; | ||
466 | } | ||
467 | |||
468 | return &priv->fe; | ||
469 | err: | ||
470 | dbg("%s: failed=%d", __func__, ret); | ||
471 | kfree(priv); | ||
472 | return NULL; | ||
473 | } | ||
474 | EXPORT_SYMBOL(rtl2830_attach); | ||
475 | |||
476 | static struct dvb_frontend_ops rtl2830_ops = { | ||
477 | .delsys = { SYS_DVBT }, | ||
478 | .info = { | ||
479 | .name = "Realtek RTL2830 (DVB-T)", | ||
480 | .caps = FE_CAN_FEC_1_2 | | ||
481 | FE_CAN_FEC_2_3 | | ||
482 | FE_CAN_FEC_3_4 | | ||
483 | FE_CAN_FEC_5_6 | | ||
484 | FE_CAN_FEC_7_8 | | ||
485 | FE_CAN_FEC_AUTO | | ||
486 | FE_CAN_QPSK | | ||
487 | FE_CAN_QAM_16 | | ||
488 | FE_CAN_QAM_64 | | ||
489 | FE_CAN_QAM_AUTO | | ||
490 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
491 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
492 | FE_CAN_HIERARCHY_AUTO | | ||
493 | FE_CAN_RECOVER | | ||
494 | FE_CAN_MUTE_TS | ||
495 | }, | ||
496 | |||
497 | .release = rtl2830_release, | ||
498 | |||
499 | .init = rtl2830_init, | ||
500 | |||
501 | .get_tune_settings = rtl2830_get_tune_settings, | ||
502 | |||
503 | .set_frontend = rtl2830_set_frontend, | ||
504 | |||
505 | .read_status = rtl2830_read_status, | ||
506 | .read_snr = rtl2830_read_snr, | ||
507 | .read_ber = rtl2830_read_ber, | ||
508 | .read_ucblocks = rtl2830_read_ucblocks, | ||
509 | .read_signal_strength = rtl2830_read_signal_strength, | ||
510 | }; | ||
511 | |||
512 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
513 | MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); | ||
514 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h new file mode 100644 index 000000000000..1c6ee91749c2 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830.h | |||
@@ -0,0 +1,97 @@ | |||
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 | #ifndef RTL2830_H | ||
22 | #define RTL2830_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | struct rtl2830_config { | ||
27 | /* | ||
28 | * Demodulator I2C address. | ||
29 | */ | ||
30 | u8 i2c_addr; | ||
31 | |||
32 | /* | ||
33 | * Xtal frequency. | ||
34 | * Hz | ||
35 | * 4000000, 16000000, 25000000, 28800000 | ||
36 | */ | ||
37 | u32 xtal; | ||
38 | |||
39 | /* | ||
40 | * TS output mode. | ||
41 | */ | ||
42 | u8 ts_mode; | ||
43 | |||
44 | /* | ||
45 | * Spectrum inversion. | ||
46 | */ | ||
47 | bool spec_inv; | ||
48 | |||
49 | /* | ||
50 | * IFs for all used modes. | ||
51 | * Hz | ||
52 | * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 | ||
53 | */ | ||
54 | u32 if_dvbt; | ||
55 | |||
56 | /* | ||
57 | */ | ||
58 | u8 vtop; | ||
59 | |||
60 | /* | ||
61 | */ | ||
62 | u8 krf; | ||
63 | |||
64 | /* | ||
65 | */ | ||
66 | u8 agc_targ_val; | ||
67 | }; | ||
68 | |||
69 | #if defined(CONFIG_DVB_RTL2830) || \ | ||
70 | (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE)) | ||
71 | extern struct dvb_frontend *rtl2830_attach( | ||
72 | const struct rtl2830_config *config, | ||
73 | struct i2c_adapter *i2c | ||
74 | ); | ||
75 | |||
76 | extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( | ||
77 | struct dvb_frontend *fe | ||
78 | ); | ||
79 | #else | ||
80 | static inline struct dvb_frontend *rtl2830_attach( | ||
81 | const struct rtl2830_config *config, | ||
82 | struct i2c_adapter *i2c | ||
83 | ) | ||
84 | { | ||
85 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( | ||
90 | struct dvb_frontend *fe | ||
91 | ) | ||
92 | { | ||
93 | return NULL; | ||
94 | } | ||
95 | #endif | ||
96 | |||
97 | #endif /* RTL2830_H */ | ||
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h new file mode 100644 index 000000000000..2bc662ee87a0 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2830_priv.h | |||
@@ -0,0 +1,53 @@ | |||
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 | #ifndef RTL2830_PRIV_H | ||
22 | #define RTL2830_PRIV_H | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "rtl2830.h" | ||
26 | |||
27 | #define LOG_PREFIX "rtl2830" | ||
28 | |||
29 | #undef dbg | ||
30 | #define dbg(f, arg...) \ | ||
31 | if (rtl2830_debug) \ | ||
32 | printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
33 | #undef err | ||
34 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
35 | #undef info | ||
36 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
37 | #undef warn | ||
38 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
39 | |||
40 | struct rtl2830_priv { | ||
41 | struct i2c_adapter *i2c; | ||
42 | struct dvb_frontend fe; | ||
43 | struct rtl2830_config cfg; | ||
44 | struct i2c_adapter tuner_i2c_adapter; | ||
45 | }; | ||
46 | |||
47 | struct rtl2830_reg_val_mask { | ||
48 | u16 reg; | ||
49 | u8 val; | ||
50 | u8 mask; | ||
51 | }; | ||
52 | |||
53 | #endif /* RTL2830_PRIV_H */ | ||