aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends
diff options
context:
space:
mode:
authorSteven Toth <stoth@hauppauge.com>2008-04-19 00:06:25 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:09:44 -0400
commit7bbb1ce4f3e517666ad27f3307d49bb2da69ffec (patch)
treef41e23bf01d70667c23ea5b5bd56c6330c3dbf08 /drivers/media/dvb/frontends
parent6b92b3bd7ac91b7e255541f4be9bfd55b12dae41 (diff)
V4L/DVB (7644): Adding support for the NXP TDA10048HN DVB OFDM demodulator
Adding support for the NXP TDA10048HN DVB OFDM demodulator Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r--drivers/media/dvb/frontends/Kconfig8
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/tda10048.c704
-rw-r--r--drivers/media/dvb/frontends/tda10048.h63
4 files changed, 776 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ae3659be323f..68fab616f55d 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -188,6 +188,14 @@ config DVB_DIB7000P
188 A DVB-T tuner module. Designed for mobile usage. Say Y when you want 188 A DVB-T tuner module. Designed for mobile usage. Say Y when you want
189 to support this frontend. 189 to support this frontend.
190 190
191config DVB_TDA10048
192 tristate "Philips TDA10048HN based"
193 depends on DVB_CORE && I2C
194 default m if DVB_FE_CUSTOMISE
195 select FW_LOADER
196 help
197 A DVB-T tuner module. Say Y when you want to support this frontend.
198
191comment "DVB-C (cable) frontends" 199comment "DVB-C (cable) frontends"
192 depends on DVB_CORE 200 depends on DVB_CORE
193 201
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 8e23a30ed3be..2f873fc0f649 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
54obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o 54obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
55obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o 55obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
56obj-$(CONFIG_DVB_AU8522) += au8522.o 56obj-$(CONFIG_DVB_AU8522) += au8522.o
57obj-$(CONFIG_DVB_TDA10048) += tda10048.o
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
new file mode 100644
index 000000000000..701dd02b0d07
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -0,0 +1,704 @@
1/*
2 NXP TDA10048HN DVB OFDM demodulator driver
3
4 Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20*/
21
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/string.h>
26#include <linux/slab.h>
27#include <linux/delay.h>
28#include "dvb_frontend.h"
29#include "tda10048.h"
30
31#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
32#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
33
34/* Register name definitions */
35#define TDA10048_IDENTITY 0x00
36#define TDA10048_VERSION 0x01
37#define TDA10048_DSP_CODE_CPT 0x0C
38#define TDA10048_DSP_CODE_IN 0x0E
39#define TDA10048_IN_CONF1 0x10
40#define TDA10048_IN_CONF2 0x11
41#define TDA10048_IN_CONF3 0x12
42#define TDA10048_OUT_CONF1 0x14
43#define TDA10048_OUT_CONF2 0x15
44#define TDA10048_OUT_CONF3 0x16
45#define TDA10048_AUTO 0x18
46#define TDA10048_SYNC_STATUS 0x1A
47#define TDA10048_CONF_C4_1 0x1E
48#define TDA10048_CONF_C4_2 0x1F
49#define TDA10048_CODE_IN_RAM 0x20
50#define TDA10048_CHANNEL_INFO_1_R 0x22
51#define TDA10048_CHANNEL_INFO_2_R 0x23
52#define TDA10048_CHANNEL_INFO1 0x24
53#define TDA10048_CHANNEL_INFO2 0x25
54#define TDA10048_TIME_ERROR_R 0x26
55#define TDA10048_TIME_ERROR 0x27
56#define TDA10048_FREQ_ERROR_LSB_R 0x28
57#define TDA10048_FREQ_ERROR_MSB_R 0x29
58#define TDA10048_FREQ_ERROR_LSB 0x2A
59#define TDA10048_FREQ_ERROR_MSB 0x2B
60#define TDA10048_IT_SEL 0x30
61#define TDA10048_IT_STAT 0x32
62#define TDA10048_DSP_AD_LSB 0x3C
63#define TDA10048_DSP_AD_MSB 0x3D
64#define TDA10048_DSP_REF_LSB 0x3E
65#define TDA10048_DSP_REF_MSB 0x3F
66#define TDA10048_CONF_TRISTATE1 0x44
67#define TDA10048_CONF_TRISTATE2 0x45
68#define TDA10048_CONF_POLARITY 0x46
69#define TDA10048_GPIO_SP_DS0 0x48
70#define TDA10048_GPIO_SP_DS1 0x49
71#define TDA10048_GPIO_SP_DS2 0x4A
72#define TDA10048_GPIO_SP_DS3 0x4B
73#define TDA10048_GPIO_OUT_SEL 0x4C
74#define TDA10048_GPIO_SELECT 0x4D
75#define TDA10048_IC_MODE 0x4E
76#define TDA10048_CONF_XO 0x50
77#define TDA10048_CONF_PLL1 0x51
78#define TDA10048_CONF_PLL2 0x52
79#define TDA10048_CONF_PLL3 0x53
80#define TDA10048_CONF_ADC 0x54
81#define TDA10048_CONF_ADC_2 0x55
82#define TDA10048_CONF_C1_1 0x60
83#define TDA10048_CONF_C1_3 0x62
84#define TDA10048_AGC_CONF 0x70
85#define TDA10048_AGC_THRESHOLD_LSB 0x72
86#define TDA10048_AGC_THRESHOLD_MSB 0x73
87#define TDA10048_AGC_RENORM 0x74
88#define TDA10048_AGC_GAINS 0x76
89#define TDA10048_AGC_TUN_MIN 0x78
90#define TDA10048_AGC_TUN_MAX 0x79
91#define TDA10048_AGC_IF_MIN 0x7A
92#define TDA10048_AGC_IF_MAX 0x7B
93#define TDA10048_AGC_TUN_LEVEL 0x7E
94#define TDA10048_AGC_IF_LEVEL 0x7F
95#define TDA10048_DIG_AGC_LEVEL 0x81
96#define TDA10048_FREQ_PHY2_LSB 0x86
97#define TDA10048_FREQ_PHY2_MSB 0x87
98#define TDA10048_TIME_INVWREF_LSB 0x88
99#define TDA10048_TIME_INVWREF_MSB 0x89
100#define TDA10048_TIME_WREF_LSB 0x8A
101#define TDA10048_TIME_WREF_MID1 0x8B
102#define TDA10048_TIME_WREF_MID2 0x8C
103#define TDA10048_TIME_WREF_MSB 0x8D
104#define TDA10048_NP_OUT 0xA2
105#define TDA10048_CELL_ID_LSB 0xA4
106#define TDA10048_CELL_ID_MSB 0xA5
107#define TDA10048_EXTTPS_ODD 0xAA
108#define TDA10048_EXTTPS_EVEN 0xAB
109#define TDA10048_TPS_LENGTH 0xAC
110#define TDA10048_FREE_REG_1 0xB2
111#define TDA10048_FREE_REG_2 0xB3
112#define TDA10048_CONF_C3_1 0xC0
113#define TDA10048_CYBER_CTRL 0xC2
114#define TDA10048_CBER_NMAX_LSB 0xC4
115#define TDA10048_CBER_NMAX_MSB 0xC5
116#define TDA10048_CBER_LSB 0xC6
117#define TDA10048_CBER_MSB 0xC7
118#define TDA10048_VBER_LSB 0xC8
119#define TDA10048_VBER_MID 0xC9
120#define TDA10048_VBER_MSB 0xCA
121#define TDA10048_CYBER_LUT 0xCC
122#define TDA10048_UNCOR_CTRL 0xCD
123#define TDA10048_UNCOR_CPT_LSB 0xCE
124#define TDA10048_UNCOR_CPT_MSB 0xCF
125#define TDA10048_SOFT_IT_C3 0xD6
126#define TDA10048_CONF_TS2 0xE0
127#define TDA10048_CONF_TS1 0xE1
128
129static unsigned int debug;
130
131#define dprintk(level, fmt, arg...)\
132 do { if (debug >= level)\
133 printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
134 } while (0)
135
136struct tda10048_state {
137
138 struct i2c_adapter *i2c;
139
140 /* configuration settings */
141 const struct tda10048_config *config;
142 struct dvb_frontend frontend;
143
144 int fwloaded;
145};
146
147static struct init_tab {
148 u8 reg;
149 u16 data;
150} init_tab[] = {
151 { TDA10048_CONF_PLL1, 0x08 },
152 { TDA10048_CONF_ADC_2, 0x00 },
153 { TDA10048_CONF_C4_1, 0x00 },
154 { TDA10048_CONF_PLL1, 0x0f },
155 { TDA10048_CONF_PLL2, 0x0a },
156 { TDA10048_CONF_PLL3, 0x43 },
157 { TDA10048_FREQ_PHY2_LSB, 0x02 },
158 { TDA10048_FREQ_PHY2_MSB, 0x0a },
159 { TDA10048_TIME_WREF_LSB, 0xbd },
160 { TDA10048_TIME_WREF_MID1, 0xe4 },
161 { TDA10048_TIME_WREF_MID2, 0xa8 },
162 { TDA10048_TIME_WREF_MSB, 0x02 },
163 { TDA10048_TIME_INVWREF_LSB, 0x04 },
164 { TDA10048_TIME_INVWREF_MSB, 0x06 },
165 { TDA10048_CONF_C4_1, 0x00 },
166 { TDA10048_CONF_C1_1, 0xa8 },
167 { TDA10048_AGC_CONF, 0x16 },
168 { TDA10048_CONF_C1_3, 0x0b },
169 { TDA10048_AGC_TUN_MIN, 0x00 },
170 { TDA10048_AGC_TUN_MAX, 0xff },
171 { TDA10048_AGC_IF_MIN, 0x00 },
172 { TDA10048_AGC_IF_MAX, 0xff },
173 { TDA10048_AGC_THRESHOLD_MSB, 0x00 },
174 { TDA10048_AGC_THRESHOLD_LSB, 0x70 },
175 { TDA10048_CYBER_CTRL, 0x38 },
176 { TDA10048_AGC_GAINS, 0x12 },
177 { TDA10048_CONF_XO, 0x00 },
178 { TDA10048_CONF_TS1, 0x07 },
179 { TDA10048_IC_MODE, 0x00 },
180 { TDA10048_CONF_TS2, 0xc0 },
181 { TDA10048_CONF_TRISTATE1, 0x21 },
182 { TDA10048_CONF_TRISTATE2, 0x00 },
183 { TDA10048_CONF_POLARITY, 0x00 },
184 { TDA10048_CONF_C4_2, 0x04 },
185 { TDA10048_CONF_ADC, 0x60 },
186 { TDA10048_CONF_ADC_2, 0x10 },
187 { TDA10048_CONF_ADC, 0x60 },
188 { TDA10048_CONF_ADC_2, 0x00 },
189 { TDA10048_CONF_C1_1, 0xa8 },
190 { TDA10048_UNCOR_CTRL, 0x00 },
191 { TDA10048_CONF_C4_2, 0x04 },
192};
193
194static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
195{
196 int ret;
197 u8 buf [] = { reg, data };
198 struct i2c_msg msg = {
199 .addr = state->config->demod_address,
200 .flags = 0, .buf = buf, .len = 2 };
201
202 dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
203
204 ret = i2c_transfer(state->i2c, &msg, 1);
205
206 if (ret != 1)
207 printk("%s: writereg error (ret == %i)\n", __func__, ret);
208
209 return (ret != 1) ? -1 : 0;
210}
211
212static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
213{
214 int ret;
215 u8 b0 [] = { reg };
216 u8 b1 [] = { 0 };
217 struct i2c_msg msg [] = {
218 { .addr = state->config->demod_address,
219 .flags = 0, .buf = b0, .len = 1 },
220 { .addr = state->config->demod_address,
221 .flags = I2C_M_RD, .buf = b1, .len = 1 } };
222
223 dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
224
225 ret = i2c_transfer(state->i2c, msg, 2);
226
227 if (ret != 2)
228 printk(KERN_ERR "%s: readreg error (ret == %i)\n",
229 __func__, ret);
230
231 return b1[0];
232}
233
234static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
235 u8 *data, u16 len)
236{
237 int ret = -EREMOTEIO;
238 struct i2c_msg msg;
239 u8 *buf;
240
241 dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
242
243 buf = kmalloc(len + 1, GFP_KERNEL);
244 if (buf == NULL) {
245 ret = -ENOMEM;
246 goto error;
247 }
248
249 *buf = reg;
250 memcpy(buf + 1, data, len);
251
252 msg.addr = state->config->demod_address;
253 msg.flags = 0;
254 msg.buf = buf;
255 msg.len = len + 1;
256
257 dprintk(2, "%s(): write len = %d\n",
258 __func__, msg.len);
259
260 ret = i2c_transfer(state->i2c, &msg, 1);
261 if (ret != 1) {
262 printk(KERN_ERR "%s(): writereg error err %i\n",
263 __func__, ret);
264 ret = -EREMOTEIO;
265 }
266
267error:
268 kfree(buf);
269
270 return ret;
271}
272
273static int tda10048_firmware_upload(struct dvb_frontend *fe)
274{
275 struct tda10048_state *state = fe->demodulator_priv;
276 const struct firmware *fw;
277 int ret;
278 int pos = 0;
279 int cnt;
280 u8 wlen = state->config->fwbulkwritelen;
281
282 if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
283 wlen = TDA10048_BULKWRITE_200;
284
285 /* request the firmware, this will block and timeout */
286 printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
287 __func__,
288 TDA10048_DEFAULT_FIRMWARE);
289
290 ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
291 &state->i2c->dev);
292 if (ret) {
293 printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
294 __func__);
295 return -EIO;
296 } else {
297 printk(KERN_INFO "%s: firmware read %Zu bytes.\n",
298 __func__,
299 fw->size);
300 ret = 0;
301 }
302
303 if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
304 printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
305 return -EIO;
306 } else {
307 printk(KERN_INFO "%s: firmware uploading\n", __func__);
308
309 /* Soft reset */
310 tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
311 tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
312 & 0xfe);
313 tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
314 tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
315 | 0x01);
316
317 /* Put the demod into host download mode */
318 tda10048_writereg(state, TDA10048_CONF_C4_1,
319 tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
320
321 /* Boot the DSP */
322 tda10048_writereg(state, TDA10048_CONF_C4_1,
323 tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
324
325 /* Prepare for download */
326 tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
327
328 /* Download the firmware payload */
329 while (pos < fw->size) {
330
331 if ((fw->size - pos) > wlen)
332 cnt = wlen;
333 else
334 cnt = fw->size - pos;
335
336 tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
337 &fw->data[pos], cnt);
338
339 pos += cnt;
340 }
341
342 ret = -EIO;
343 /* Wait up to 250ms for the DSP to boot */
344 for (cnt = 0; cnt < 250 ; cnt += 10) {
345
346 msleep(10);
347
348 if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
349 & 0x40) {
350 ret = 0;
351 break;
352 }
353 }
354 }
355
356 release_firmware(fw);
357
358 if (ret == 0) {
359 printk(KERN_INFO "%s: firmware uploaded\n", __func__);
360 state->fwloaded = 1;
361 } else
362 printk(KERN_ERR "%s: firmware upload failed\n", __func__);
363
364 return ret;
365}
366
367static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
368{
369 struct tda10048_state *state = fe->demodulator_priv;
370
371 dprintk(1, "%s(%d)\n", __func__, inversion);
372
373 if (inversion == TDA10048_INVERSION_ON)
374 tda10048_writereg(state, TDA10048_CONF_C1_1,
375 tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
376 else
377 tda10048_writereg(state, TDA10048_CONF_C1_1,
378 tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
379
380 return 0;
381}
382
383/* Retrieve the demod settings */
384static int tda10048_get_tps(struct tda10048_state *state,
385 struct dvb_ofdm_parameters *p)
386{
387 u8 val;
388
389 /* Make sure the TPS regs are valid */
390 if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
391 return -EAGAIN;
392
393 val = tda10048_readreg(state, TDA10048_OUT_CONF2);
394 switch ((val & 0x60) >> 5) {
395 case 0: p->constellation = QPSK; break;
396 case 1: p->constellation = QAM_16; break;
397 case 2: p->constellation = QAM_64; break;
398 }
399 switch ((val & 0x18) >> 3) {
400 case 0: p->hierarchy_information = HIERARCHY_NONE; break;
401 case 1: p->hierarchy_information = HIERARCHY_1; break;
402 case 2: p->hierarchy_information = HIERARCHY_2; break;
403 case 3: p->hierarchy_information = HIERARCHY_4; break;
404 }
405 switch (val & 0x07) {
406 case 0: p->code_rate_HP = FEC_1_2; break;
407 case 1: p->code_rate_HP = FEC_2_3; break;
408 case 2: p->code_rate_HP = FEC_3_4; break;
409 case 3: p->code_rate_HP = FEC_5_6; break;
410 case 4: p->code_rate_HP = FEC_7_8; break;
411 }
412
413 val = tda10048_readreg(state, TDA10048_OUT_CONF3);
414 switch (val & 0x07) {
415 case 0: p->code_rate_LP = FEC_1_2; break;
416 case 1: p->code_rate_LP = FEC_2_3; break;
417 case 2: p->code_rate_LP = FEC_3_4; break;
418 case 3: p->code_rate_LP = FEC_5_6; break;
419 case 4: p->code_rate_LP = FEC_7_8; break;
420 }
421
422 val = tda10048_readreg(state, TDA10048_OUT_CONF1);
423 switch ((val & 0x0c) >> 2) {
424 case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
425 case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
426 case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
427 case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
428 }
429 switch (val & 0x02) {
430 case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
431 case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
432 }
433
434 return 0;
435}
436
437static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
438{
439 struct tda10048_state *state = fe->demodulator_priv;
440 dprintk(1, "%s(%d)\n", __func__, enable);
441
442 if (enable)
443 return tda10048_writereg(state, TDA10048_CONF_C4_1,
444 tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
445 else
446 return tda10048_writereg(state, TDA10048_CONF_C4_1,
447 tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
448}
449
450static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
451{
452 struct tda10048_state *state = fe->demodulator_priv;
453 dprintk(1, "%s(%d)\n", __func__, serial);
454
455 /* Ensure pins are out of tri-state */
456 tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
457 tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
458
459 if (serial) {
460 tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
461 tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
462 } else {
463 tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
464 tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
465 }
466
467 return 0;
468}
469
470/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
471/* TODO: Support manual tuning with specific params */
472static int tda10048_set_frontend(struct dvb_frontend *fe,
473 struct dvb_frontend_parameters *p)
474{
475 struct tda10048_state *state = fe->demodulator_priv;
476
477 dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
478
479 if (fe->ops.tuner_ops.set_params) {
480
481 if (fe->ops.i2c_gate_ctrl)
482 fe->ops.i2c_gate_ctrl(fe, 1);
483
484 fe->ops.tuner_ops.set_params(fe, p);
485
486 if (fe->ops.i2c_gate_ctrl)
487 fe->ops.i2c_gate_ctrl(fe, 0);
488 }
489
490 /* Enable demod TPS auto detection and begin acquisition */
491 tda10048_writereg(state, TDA10048_AUTO, 0x57);
492
493 return 0;
494}
495
496/* Establish sane defaults and load firmware. */
497static int tda10048_init(struct dvb_frontend *fe)
498{
499 struct tda10048_state *state = fe->demodulator_priv;
500 int ret = 0, i;
501
502 dprintk(1, "%s()\n", __func__);
503
504 /* Apply register defaults */
505 for (i = 0; i < ARRAY_SIZE(init_tab); i++)
506 tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
507
508 if (state->fwloaded == 0)
509 ret = tda10048_firmware_upload(fe);
510
511 /* Set either serial or parallel */
512 tda10048_output_mode(fe, state->config->output_mode);
513
514 /* set inversion */
515 tda10048_set_inversion(fe, state->config->inversion);
516
517 /* Ensure we leave the gate closed */
518 tda10048_i2c_gate_ctrl(fe, 0);
519
520 return ret;
521}
522
523static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
524{
525 struct tda10048_state *state = fe->demodulator_priv;
526 u8 reg;
527
528 *status = 0;
529
530 reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
531
532 dprintk(1, "%s() status =0x%02x\n", __func__, reg);
533
534 if (reg & 0x02)
535 *status |= FE_HAS_CARRIER;
536
537 if (reg & 0x04)
538 *status |= FE_HAS_SIGNAL;
539
540 if (reg & 0x08) {
541 *status |= FE_HAS_LOCK;
542 *status |= FE_HAS_VITERBI;
543 *status |= FE_HAS_SYNC;
544 }
545
546 return 0;
547}
548
549static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
550{
551 struct tda10048_state *state = fe->demodulator_priv;
552
553 dprintk(1, "%s()\n", __func__);
554
555 /* TODO: A reset may be required here */
556 *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
557 tda10048_readreg(state, TDA10048_CBER_LSB);
558
559 return 0;
560}
561
562static int tda10048_read_signal_strength(struct dvb_frontend *fe,
563 u16 *signal_strength)
564{
565 struct tda10048_state *state = fe->demodulator_priv;
566 u16 v;
567
568 dprintk(1, "%s()\n", __func__);
569
570 v = tda10048_readreg(state, TDA10048_NP_OUT);
571 if (v == 0)
572 *signal_strength = 100;
573 else {
574 /* TODO: Apply .db math for correct values */
575 *signal_strength = v;
576 }
577
578 return 0;
579}
580
581static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
582{
583 struct tda10048_state *state = fe->demodulator_priv;
584
585 dprintk(1, "%s()\n", __func__);
586
587 /* TODO: This result should be the same as signal strength */
588 *snr = tda10048_readreg(state, TDA10048_NP_OUT);
589
590 return 0;
591}
592
593static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
594{
595 struct tda10048_state *state = fe->demodulator_priv;
596
597 dprintk(1, "%s()\n", __func__);
598
599 *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
600 tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
601
602 return 0;
603}
604
605static int tda10048_get_frontend(struct dvb_frontend *fe,
606 struct dvb_frontend_parameters *p)
607{
608 struct tda10048_state *state = fe->demodulator_priv;
609
610 dprintk(1, "%s()\n", __func__);
611
612 p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
613 & 0x20 ? INVERSION_ON : INVERSION_OFF;
614
615 return tda10048_get_tps(state, &p->u.ofdm);
616}
617
618static int tda10048_get_tune_settings(struct dvb_frontend *fe,
619 struct dvb_frontend_tune_settings *tune)
620{
621 tune->min_delay_ms = 1000;
622 return 0;
623}
624
625static void tda10048_release(struct dvb_frontend *fe)
626{
627 struct tda10048_state *state = fe->demodulator_priv;
628 dprintk(1, "%s()\n", __func__);
629 kfree(state);
630}
631
632static struct dvb_frontend_ops tda10048_ops;
633
634struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
635 struct i2c_adapter *i2c)
636{
637 struct tda10048_state *state = NULL;
638
639 dprintk(1, "%s()\n", __func__);
640
641 /* allocate memory for the internal state */
642 state = kmalloc(sizeof(struct tda10048_state), GFP_KERNEL);
643 if (state == NULL)
644 goto error;
645
646 /* setup the state */
647 state->config = config;
648 state->i2c = i2c;
649 state->fwloaded = 0;
650
651 /* check if the demod is present */
652 if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
653 goto error;
654
655 /* create dvb_frontend */
656 memcpy(&state->frontend.ops, &tda10048_ops,
657 sizeof(struct dvb_frontend_ops));
658 state->frontend.demodulator_priv = state;
659
660 /* Leave the gate closed */
661 tda10048_i2c_gate_ctrl(&state->frontend, 0);
662
663 return &state->frontend;
664
665error:
666 kfree(state);
667 return NULL;
668}
669EXPORT_SYMBOL(tda10048_attach);
670
671static struct dvb_frontend_ops tda10048_ops = {
672
673 .info = {
674 .name = "NXP TDA10048HN DVB-T",
675 .type = FE_OFDM,
676 .frequency_min = 177000000,
677 .frequency_max = 858000000,
678 .frequency_stepsize = 166666,
679 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
680 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
681 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
682 FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
683 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
684 },
685
686 .release = tda10048_release,
687 .init = tda10048_init,
688 .i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
689 .set_frontend = tda10048_set_frontend,
690 .get_frontend = tda10048_get_frontend,
691 .get_tune_settings = tda10048_get_tune_settings,
692 .read_status = tda10048_read_status,
693 .read_ber = tda10048_read_ber,
694 .read_signal_strength = tda10048_read_signal_strength,
695 .read_snr = tda10048_read_snr,
696 .read_ucblocks = tda10048_read_ucblocks,
697};
698
699module_param(debug, int, 0644);
700MODULE_PARM_DESC(debug, "Enable verbose debug messages");
701
702MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
703MODULE_AUTHOR("Steven Toth");
704MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
new file mode 100644
index 000000000000..2b5c78e62c86
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -0,0 +1,63 @@
1/*
2 NXP TDA10048HN DVB OFDM demodulator driver
3
4 Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20*/
21
22#ifndef TDA10048_H
23#define TDA10048_H
24
25#include <linux/dvb/frontend.h>
26#include <linux/firmware.h>
27
28struct tda10048_config {
29
30 /* the demodulator's i2c address */
31 u8 demod_address;
32
33 /* serial/parallel output */
34#define TDA10048_PARALLEL_OUTPUT 0
35#define TDA10048_SERIAL_OUTPUT 1
36 u8 output_mode;
37
38#define TDA10048_BULKWRITE_200 200
39#define TDA10048_BULKWRITE_50 50
40 u8 fwbulkwritelen;
41
42 /* Spectral Inversion */
43#define TDA10048_INVERSION_OFF 0
44#define TDA10048_INVERSION_ON 1
45 u8 inversion;
46};
47
48#if defined(CONFIG_DVB_TDA10048) || \
49 (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
50extern struct dvb_frontend *tda10048_attach(
51 const struct tda10048_config *config,
52 struct i2c_adapter *i2c);
53#else
54static inline struct dvb_frontend *tda10048_attach(
55 const struct tda10048_config *config,
56 struct i2c_adapter *i2c)
57{
58 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
59 return NULL;
60}
61#endif /* CONFIG_DVB_TDA10048 */
62
63#endif /* TDA10048_H */