aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends
diff options
context:
space:
mode:
authorDavid Wong <davidtlwong@gmail.com>2009-06-17 00:38:10 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-12 11:17:38 -0400
commitb80dc1c673f5ff79805215eb94ff008e634e4b2d (patch)
tree80a5849fadf39d81837a8e3ad5443b58032b8382 /drivers/media/dvb/frontends
parenta0d64456f765297782d34750cf4dc862f2a8bce0 (diff)
V4L/DVB (12271): lgs8gxx: add lgs8g75 support
lgs8gxx: add lgs8g75 demodulator support Signed-off-by: David T.L. Wong <davidtlwong@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c484
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.h11
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx_priv.h12
3 files changed, 401 insertions, 106 deletions
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index fde27645bbed..eabcadc425d5 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -1,9 +1,9 @@
1/* 1/*
2 * Support for Legend Silicon DMB-TH demodulator 2 * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
3 * LGS8913, LGS8GL5 3 * LGS8913, LGS8GL5, LGS8G75
4 * experimental support LGS8G42, LGS8G52 4 * experimental support LGS8G42, LGS8G52
5 * 5 *
6 * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> 6 * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited 7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited
8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) 8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
9 * 9 *
@@ -46,6 +46,42 @@ module_param(fake_signal_str, int, 0644);
46MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." 46MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
47"Signal strength calculation is slow.(default:on)."); 47"Signal strength calculation is slow.(default:on).");
48 48
49static const u8 lgs8g75_initdat[] = {
50 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
51 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
54 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
57 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
58 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
59 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
60 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
61 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
62 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
63 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
64 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
65 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
66 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
67 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
68 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
69 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
70 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
71 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
72 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
73 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
74 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
75 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
76 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
77 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
78 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
80 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
81 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
82 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
83};
84
49/* LGS8GXX internal helper functions */ 85/* LGS8GXX internal helper functions */
50 86
51static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) 87static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
55 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; 91 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
56 92
57 msg.addr = priv->config->demod_address; 93 msg.addr = priv->config->demod_address;
58 if (reg >= 0xC0) 94 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
59 msg.addr += 0x02; 95 msg.addr += 0x02;
60 96
61 if (debug >= 2) 97 if (debug >= 2)
@@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
84 }; 120 };
85 121
86 dev_addr = priv->config->demod_address; 122 dev_addr = priv->config->demod_address;
87 if (reg >= 0xC0) 123 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
88 dev_addr += 0x02; 124 dev_addr += 0x02;
89 msg[1].addr = msg[0].addr = dev_addr; 125 msg[1].addr = msg[0].addr = dev_addr;
90 126
@@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
112 return 0; 148 return 0;
113} 149}
114 150
151static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
152 u8 val, u8 delay, u8 tries)
153{
154 u8 t;
155 int i;
156
157 for (i = 0; i < tries; i++) {
158 lgs8gxx_read_reg(priv, reg, &t);
159
160 if ((t & mask) == val)
161 return 0;
162 msleep(delay);
163 }
164
165 return 1;
166}
167
115static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) 168static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
116{ 169{
117 const struct lgs8gxx_config *config = priv->config; 170 const struct lgs8gxx_config *config = priv->config;
118 u8 if_conf; 171 u8 if_conf;
119 172
120 if_conf = 0x10; /* AGC output on; */ 173 if_conf = 0x10; /* AGC output on, RF_AGC output off; */
121 174
122 if_conf |= 175 if_conf |=
123 ((config->ext_adc) ? 0x80 : 0x00) | 176 ((config->ext_adc) ? 0x80 : 0x00) |
124 ((config->if_neg_center) ? 0x04 : 0x00) | 177 ((config->if_neg_center) ? 0x04 : 0x00) |
125 ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */ 178 ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
126 ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) | 179 ((config->adc_signed) ? 0x02 : 0x00) |
127 ((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00); 180 ((config->if_neg_edge) ? 0x01 : 0x00);
128 181
129 if (config->ext_adc && 182 if (config->ext_adc &&
130 (config->prod == LGS8GXX_PROD_LGS8G52)) { 183 (config->prod == LGS8GXX_PROD_LGS8G52)) {
@@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
157 } 210 }
158 dprintk("AFC_INIT_FREQ = 0x%08X\n", v32); 211 dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
159 212
160 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); 213 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
161 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); 214 lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
162 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); 215 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
163 lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); 216 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
217 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
218 } else {
219 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
220 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
221 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
222 lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
223 }
224
225 return 0;
226}
227
228static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
229{
230 u64 val;
231 u32 v32 = 0;
232 u8 reg_addr, t;
233 int i;
234
235 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
236 reg_addr = 0x23;
237 else
238 reg_addr = 0x48;
239
240 for (i = 0; i < 4; i++) {
241 lgs8gxx_read_reg(priv, reg_addr, &t);
242 v32 <<= 8;
243 v32 |= t;
244 reg_addr--;
245 }
164 246
247 val = v32;
248 val *= priv->config->if_clk_freq;
249 val /= (u64)1 << 32;
250 dprintk("AFC = %u kHz\n", (u32)val);
165 return 0; 251 return 0;
166} 252}
167 253
168static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) 254static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
169{ 255{
170 u8 t; 256 u8 t;
257 u8 prod = priv->config->prod;
171 258
172 if (priv->config->prod == LGS8GXX_PROD_LGS8913) 259 if (prod == LGS8GXX_PROD_LGS8913)
173 lgs8gxx_write_reg(priv, 0xC6, 0x01); 260 lgs8gxx_write_reg(priv, 0xC6, 0x01);
174 261
175 lgs8gxx_read_reg(priv, 0x7E, &t); 262 if (prod == LGS8GXX_PROD_LGS8G75) {
176 lgs8gxx_write_reg(priv, 0x7E, t | 0x01); 263 lgs8gxx_read_reg(priv, 0x0C, &t);
177 264 t &= (~0x04);
178 /* clear FEC self reset */ 265 lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
179 lgs8gxx_read_reg(priv, 0xC5, &t); 266 lgs8gxx_write_reg(priv, 0x39, 0x00);
180 lgs8gxx_write_reg(priv, 0xC5, t & 0xE0); 267 lgs8gxx_write_reg(priv, 0x3D, 0x04);
268 } else if (prod == LGS8GXX_PROD_LGS8913 ||
269 prod == LGS8GXX_PROD_LGS8GL5 ||
270 prod == LGS8GXX_PROD_LGS8G42 ||
271 prod == LGS8GXX_PROD_LGS8G52 ||
272 prod == LGS8GXX_PROD_LGS8G54) {
273 lgs8gxx_read_reg(priv, 0x7E, &t);
274 lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
275
276 /* clear FEC self reset */
277 lgs8gxx_read_reg(priv, 0xC5, &t);
278 lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
279 }
181 280
182 if (priv->config->prod == LGS8GXX_PROD_LGS8913) { 281 if (prod == LGS8GXX_PROD_LGS8913) {
183 /* FEC auto detect */ 282 /* FEC auto detect */
184 lgs8gxx_write_reg(priv, 0xC1, 0x03); 283 lgs8gxx_write_reg(priv, 0xC1, 0x03);
185 284
186 lgs8gxx_read_reg(priv, 0x7C, &t); 285 lgs8gxx_read_reg(priv, 0x7C, &t);
187 t = (t & 0x8C) | 0x03; 286 t = (t & 0x8C) | 0x03;
188 lgs8gxx_write_reg(priv, 0x7C, t); 287 lgs8gxx_write_reg(priv, 0x7C, t);
189 }
190
191 288
192 if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
193 /* BER test mode */ 289 /* BER test mode */
194 lgs8gxx_read_reg(priv, 0xC3, &t); 290 lgs8gxx_read_reg(priv, 0xC3, &t);
195 t = (t & 0xEF) | 0x10; 291 t = (t & 0xEF) | 0x10;
@@ -207,6 +303,32 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
207 int ret = 0; 303 int ret = 0;
208 u8 t; 304 u8 t;
209 305
306 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
307 u8 t2;
308 lgs8gxx_read_reg(priv, 0x0C, &t);
309 t &= (~0x80);
310 lgs8gxx_write_reg(priv, 0x0C, t);
311
312 lgs8gxx_read_reg(priv, 0x0C, &t);
313 lgs8gxx_read_reg(priv, 0x19, &t2);
314
315 if (((t&0x03) == 0x01) && (t2&0x01)) {
316 lgs8gxx_write_reg(priv, 0x6E, 0x05);
317 lgs8gxx_write_reg(priv, 0x39, 0x02);
318 lgs8gxx_write_reg(priv, 0x39, 0x03);
319 lgs8gxx_write_reg(priv, 0x3D, 0x05);
320 lgs8gxx_write_reg(priv, 0x3E, 0x28);
321 lgs8gxx_write_reg(priv, 0x53, 0x80);
322 } else {
323 lgs8gxx_write_reg(priv, 0x6E, 0x3F);
324 lgs8gxx_write_reg(priv, 0x39, 0x00);
325 lgs8gxx_write_reg(priv, 0x3D, 0x04);
326 }
327
328 lgs8gxx_soft_reset(priv);
329 return 0;
330 }
331
210 /* turn off auto-detect; manual settings */ 332 /* turn off auto-detect; manual settings */
211 lgs8gxx_write_reg(priv, 0x7E, 0); 333 lgs8gxx_write_reg(priv, 0x7E, 0);
212 if (priv->config->prod == LGS8GXX_PROD_LGS8913) 334 if (priv->config->prod == LGS8GXX_PROD_LGS8913)
@@ -226,11 +348,39 @@ static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
226 int ret = 0; 348 int ret = 0;
227 u8 t; 349 u8 t;
228 350
229 ret = lgs8gxx_read_reg(priv, 0x4B, &t); 351 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
352 ret = lgs8gxx_read_reg(priv, 0x13, &t);
353 else
354 ret = lgs8gxx_read_reg(priv, 0x4B, &t);
230 if (ret != 0) 355 if (ret != 0)
231 return ret; 356 return ret;
232 357
233 *locked = ((t & 0xC0) == 0xC0) ? 1 : 0; 358 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
359 *locked = ((t & 0x80) == 0x80) ? 1 : 0;
360 else
361 *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
362 return 0;
363}
364
365/* Wait for Code Acquisition Lock */
366static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
367{
368 int ret = 0;
369 u8 reg, mask, val;
370
371 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
372 reg = 0x13;
373 mask = 0x80;
374 val = 0x80;
375 } else {
376 reg = 0x4B;
377 mask = 0xC0;
378 val = 0xC0;
379 }
380
381 ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
382 *locked = (ret == 0) ? 1 : 0;
383
234 return 0; 384 return 0;
235} 385}
236 386
@@ -238,21 +388,30 @@ static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
238 u8 *finished) 388 u8 *finished)
239{ 389{
240 int ret = 0; 390 int ret = 0;
241 u8 t; 391 u8 reg, mask, val;
242 392
243 ret = lgs8gxx_read_reg(priv, 0xA4, &t); 393 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
244 if (ret != 0) 394 reg = 0x1f;
245 return ret; 395 mask = 0xC0;
396 val = 0x80;
397 } else {
398 reg = 0xA4;
399 mask = 0x03;
400 val = 0x01;
401 }
246 402
247 *finished = ((t & 0x3) == 0x1) ? 1 : 0; 403 ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
404 *finished = (ret == 0) ? 1 : 0;
248 405
249 return 0; 406 return 0;
250} 407}
251 408
252static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked) 409static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
410 u8 *locked)
253{ 411{
254 int err; 412 int err = 0;
255 u8 ad_fini = 0; 413 u8 ad_fini = 0;
414 u8 t1, t2;
256 415
257 if (gi == GI_945) 416 if (gi == GI_945)
258 dprintk("try GI 945\n"); 417 dprintk("try GI 945\n");
@@ -260,17 +419,29 @@ static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
260 dprintk("try GI 595\n"); 419 dprintk("try GI 595\n");
261 else if (gi == GI_420) 420 else if (gi == GI_420)
262 dprintk("try GI 420\n"); 421 dprintk("try GI 420\n");
263 lgs8gxx_write_reg(priv, 0x04, gi); 422 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
423 lgs8gxx_read_reg(priv, 0x0C, &t1);
424 lgs8gxx_read_reg(priv, 0x18, &t2);
425 t1 &= ~(GI_MASK);
426 t1 |= gi;
427 t2 &= 0xFE;
428 t2 |= cpn ? 0x01 : 0x00;
429 lgs8gxx_write_reg(priv, 0x0C, t1);
430 lgs8gxx_write_reg(priv, 0x18, t2);
431 } else {
432 lgs8gxx_write_reg(priv, 0x04, gi);
433 }
264 lgs8gxx_soft_reset(priv); 434 lgs8gxx_soft_reset(priv);
265 msleep(50); 435 err = lgs8gxx_wait_ca_lock(priv, locked);
436 if (err || !(*locked))
437 return err;
266 err = lgs8gxx_is_autodetect_finished(priv, &ad_fini); 438 err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
267 if (err != 0) 439 if (err != 0)
268 return err; 440 return err;
269 if (ad_fini) { 441 if (ad_fini) {
270 err = lgs8gxx_is_locked(priv, locked); 442 dprintk("auto detect finished\n");
271 if (err != 0) 443 } else
272 return err; 444 *locked = 0;
273 }
274 445
275 return 0; 446 return 0;
276} 447}
@@ -285,13 +456,18 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
285 dprintk("%s\n", __func__); 456 dprintk("%s\n", __func__);
286 457
287 lgs8gxx_set_mode_auto(priv); 458 lgs8gxx_set_mode_auto(priv);
288 /* Guard Interval */ 459 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
289 lgs8gxx_write_reg(priv, 0x03, 00); 460 lgs8gxx_write_reg(priv, 0x67, 0xAA);
461 lgs8gxx_write_reg(priv, 0x6E, 0x3F);
462 } else {
463 /* Guard Interval */
464 lgs8gxx_write_reg(priv, 0x03, 00);
465 }
290 466
291 for (i = 0; i < 2; i++) { 467 for (i = 0; i < 2; i++) {
292 for (j = 0; j < 2; j++) { 468 for (j = 0; j < 2; j++) {
293 tmp_gi = GI_945; 469 tmp_gi = GI_945;
294 err = lgs8gxx_autolock_gi(priv, GI_945, &locked); 470 err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
295 if (err) 471 if (err)
296 goto out; 472 goto out;
297 if (locked) 473 if (locked)
@@ -299,14 +475,14 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
299 } 475 }
300 for (j = 0; j < 2; j++) { 476 for (j = 0; j < 2; j++) {
301 tmp_gi = GI_420; 477 tmp_gi = GI_420;
302 err = lgs8gxx_autolock_gi(priv, GI_420, &locked); 478 err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
303 if (err) 479 if (err)
304 goto out; 480 goto out;
305 if (locked) 481 if (locked)
306 goto locked; 482 goto locked;
307 } 483 }
308 tmp_gi = GI_595; 484 tmp_gi = GI_595;
309 err = lgs8gxx_autolock_gi(priv, GI_595, &locked); 485 err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
310 if (err) 486 if (err)
311 goto out; 487 goto out;
312 if (locked) 488 if (locked)
@@ -317,8 +493,13 @@ locked:
317 if ((err == 0) && (locked == 1)) { 493 if ((err == 0) && (locked == 1)) {
318 u8 t; 494 u8 t;
319 495
320 lgs8gxx_read_reg(priv, 0xA2, &t); 496 if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
321 *detected_param = t; 497 lgs8gxx_read_reg(priv, 0xA2, &t);
498 *detected_param = t;
499 } else {
500 lgs8gxx_read_reg(priv, 0x1F, &t);
501 *detected_param = t & 0x3F;
502 }
322 503
323 if (tmp_gi == GI_945) 504 if (tmp_gi == GI_945)
324 dprintk("GI 945 locked\n"); 505 dprintk("GI 945 locked\n");
@@ -345,18 +526,28 @@ static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
345 526
346 if (err != 0) { 527 if (err != 0) {
347 dprintk("lgs8gxx_auto_detect failed\n"); 528 dprintk("lgs8gxx_auto_detect failed\n");
348 } 529 } else
530 dprintk("detected param = 0x%02X\n", detected_param);
349 531
350 /* Apply detected parameters */ 532 /* Apply detected parameters */
351 if (priv->config->prod == LGS8GXX_PROD_LGS8913) { 533 if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
352 u8 inter_leave_len = detected_param & TIM_MASK ; 534 u8 inter_leave_len = detected_param & TIM_MASK ;
353 inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40; 535 /* Fix 8913 time interleaver detection bug */
536 inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
354 detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK; 537 detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
355 detected_param |= inter_leave_len; 538 detected_param |= inter_leave_len;
356 } 539 }
357 lgs8gxx_write_reg(priv, 0x7D, detected_param); 540 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
358 if (priv->config->prod == LGS8GXX_PROD_LGS8913) 541 u8 t;
359 lgs8gxx_write_reg(priv, 0xC0, detected_param); 542 lgs8gxx_read_reg(priv, 0x19, &t);
543 t &= 0x81;
544 t |= detected_param << 1;
545 lgs8gxx_write_reg(priv, 0x19, t);
546 } else {
547 lgs8gxx_write_reg(priv, 0x7D, detected_param);
548 if (priv->config->prod == LGS8GXX_PROD_LGS8913)
549 lgs8gxx_write_reg(priv, 0xC0, detected_param);
550 }
360 /* lgs8gxx_soft_reset(priv); */ 551 /* lgs8gxx_soft_reset(priv); */
361 552
362 /* Enter manual mode */ 553 /* Enter manual mode */
@@ -378,9 +569,10 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
378 u8 serial, u8 clk_pol, u8 clk_gated) 569 u8 serial, u8 clk_pol, u8 clk_gated)
379{ 570{
380 int ret = 0; 571 int ret = 0;
381 u8 t; 572 u8 t, reg_addr;
382 573
383 ret = lgs8gxx_read_reg(priv, 0xC2, &t); 574 reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
575 ret = lgs8gxx_read_reg(priv, reg_addr, &t);
384 if (ret != 0) 576 if (ret != 0)
385 return ret; 577 return ret;
386 578
@@ -389,13 +581,29 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
389 t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL; 581 t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
390 t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN; 582 t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
391 583
392 ret = lgs8gxx_write_reg(priv, 0xC2, t); 584 ret = lgs8gxx_write_reg(priv, reg_addr, t);
393 if (ret != 0) 585 if (ret != 0)
394 return ret; 586 return ret;
395 587
396 return 0; 588 return 0;
397} 589}
398 590
591/* A/D input peak-to-peak voltage range */
592static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
593 u8 sel)
594{
595 u8 r26 = 0x73, r27 = 0x90;
596
597 if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
598 return 0;
599
600 r26 |= (sel & 0x01) << 7;
601 r27 |= (sel & 0x02) >> 1;
602 lgs8gxx_write_reg(priv, 0x26, r26);
603 lgs8gxx_write_reg(priv, 0x27, r27);
604
605 return 0;
606}
399 607
400/* LGS8913 demod frontend functions */ 608/* LGS8913 demod frontend functions */
401 609
@@ -417,6 +625,34 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
417 return 0; 625 return 0;
418} 626}
419 627
628static int lgs8g75_init_data(struct lgs8gxx_state *priv)
629{
630 const u8 *p = lgs8g75_initdat;
631 int i;
632
633 lgs8gxx_write_reg(priv, 0xC6, 0x40);
634
635 lgs8gxx_write_reg(priv, 0x3D, 0x04);
636 lgs8gxx_write_reg(priv, 0x39, 0x00);
637
638 lgs8gxx_write_reg(priv, 0x3A, 0x00);
639 lgs8gxx_write_reg(priv, 0x38, 0x00);
640 lgs8gxx_write_reg(priv, 0x3B, 0x00);
641 lgs8gxx_write_reg(priv, 0x38, 0x00);
642
643 for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
644 lgs8gxx_write_reg(priv, 0x38, 0x00);
645 lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
646 lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
647 lgs8gxx_write_reg(priv, 0x3C, *p);
648 p++;
649 }
650
651 lgs8gxx_write_reg(priv, 0x38, 0x00);
652
653 return 0;
654}
655
420static int lgs8gxx_init(struct dvb_frontend *fe) 656static int lgs8gxx_init(struct dvb_frontend *fe)
421{ 657{
422 struct lgs8gxx_state *priv = 658 struct lgs8gxx_state *priv =
@@ -429,6 +665,9 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
429 lgs8gxx_read_reg(priv, 0, &data); 665 lgs8gxx_read_reg(priv, 0, &data);
430 dprintk("reg 0 = 0x%02X\n", data); 666 dprintk("reg 0 = 0x%02X\n", data);
431 667
668 if (config->prod == LGS8GXX_PROD_LGS8G75)
669 lgs8g75_set_adc_vpp(priv, config->adc_vpp);
670
432 /* Setup MPEG output format */ 671 /* Setup MPEG output format */
433 err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts, 672 err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
434 config->ts_clk_pol, 673 config->ts_clk_pol,
@@ -439,8 +678,7 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
439 if (config->prod == LGS8GXX_PROD_LGS8913) 678 if (config->prod == LGS8GXX_PROD_LGS8913)
440 lgs8913_init(priv); 679 lgs8913_init(priv);
441 lgs8gxx_set_if_freq(priv, priv->config->if_freq); 680 lgs8gxx_set_if_freq(priv, priv->config->if_freq);
442 if (config->prod != LGS8GXX_PROD_LGS8913) 681 lgs8gxx_set_ad_mode(priv);
443 lgs8gxx_set_ad_mode(priv);
444 682
445 return 0; 683 return 0;
446} 684}
@@ -489,9 +727,6 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
489static int lgs8gxx_get_fe(struct dvb_frontend *fe, 727static int lgs8gxx_get_fe(struct dvb_frontend *fe,
490 struct dvb_frontend_parameters *fe_params) 728 struct dvb_frontend_parameters *fe_params)
491{ 729{
492 struct lgs8gxx_state *priv = fe->demodulator_priv;
493 u8 t;
494
495 dprintk("%s\n", __func__); 730 dprintk("%s\n", __func__);
496 731
497 /* TODO: get real readings from device */ 732 /* TODO: get real readings from device */
@@ -501,29 +736,10 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
501 /* bandwidth */ 736 /* bandwidth */
502 fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; 737 fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
503 738
504
505 lgs8gxx_read_reg(priv, 0x7D, &t);
506 fe_params->u.ofdm.code_rate_HP = FEC_AUTO; 739 fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
507 fe_params->u.ofdm.code_rate_LP = FEC_AUTO; 740 fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
508 741
509 /* constellation */ 742 fe_params->u.ofdm.constellation = QAM_AUTO;
510 switch (t & SC_MASK) {
511 case SC_QAM64:
512 fe_params->u.ofdm.constellation = QAM_64;
513 break;
514 case SC_QAM32:
515 fe_params->u.ofdm.constellation = QAM_32;
516 break;
517 case SC_QAM16:
518 fe_params->u.ofdm.constellation = QAM_16;
519 break;
520 case SC_QAM4:
521 case SC_QAM4NR:
522 fe_params->u.ofdm.constellation = QPSK;
523 break;
524 default:
525 fe_params->u.ofdm.constellation = QAM_64;
526 }
527 743
528 /* transmission mode */ 744 /* transmission mode */
529 fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; 745 fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
@@ -552,9 +768,19 @@ static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
552{ 768{
553 struct lgs8gxx_state *priv = fe->demodulator_priv; 769 struct lgs8gxx_state *priv = fe->demodulator_priv;
554 s8 ret; 770 s8 ret;
555 u8 t; 771 u8 t, locked = 0;
556 772
557 dprintk("%s\n", __func__); 773 dprintk("%s\n", __func__);
774 *fe_status = 0;
775
776 lgs8gxx_get_afc_phase(priv);
777 lgs8gxx_is_locked(priv, &locked);
778 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
779 if (locked)
780 *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
781 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
782 return 0;
783 }
558 784
559 ret = lgs8gxx_read_reg(priv, 0x4B, &t); 785 ret = lgs8gxx_read_reg(priv, 0x4B, &t);
560 if (ret != 0) 786 if (ret != 0)
@@ -658,12 +884,33 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
658 return 0; 884 return 0;
659} 885}
660 886
887static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
888{
889 u8 t;
890 s16 v = 0;
891
892 dprintk("%s\n", __func__);
893
894 lgs8gxx_read_reg(priv, 0xB1, &t);
895 v |= t;
896 v <<= 8;
897 lgs8gxx_read_reg(priv, 0xB0, &t);
898 v |= t;
899
900 *signal = v;
901 dprintk("%s: signal=0x%02X\n", __func__, *signal);
902
903 return 0;
904}
905
661static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal) 906static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
662{ 907{
663 struct lgs8gxx_state *priv = fe->demodulator_priv; 908 struct lgs8gxx_state *priv = fe->demodulator_priv;
664 909
665 if (priv->config->prod == LGS8GXX_PROD_LGS8913) 910 if (priv->config->prod == LGS8GXX_PROD_LGS8913)
666 return lgs8913_read_signal_strength(priv, signal); 911 return lgs8913_read_signal_strength(priv, signal);
912 else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
913 return lgs8g75_read_signal_strength(priv, signal);
667 else 914 else
668 return lgs8gxx_read_signal_agc(priv, signal); 915 return lgs8gxx_read_signal_agc(priv, signal);
669} 916}
@@ -674,7 +921,10 @@ static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
674 u8 t; 921 u8 t;
675 *snr = 0; 922 *snr = 0;
676 923
677 lgs8gxx_read_reg(priv, 0x95, &t); 924 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
925 lgs8gxx_read_reg(priv, 0x34, &t);
926 else
927 lgs8gxx_read_reg(priv, 0x95, &t);
678 dprintk("AVG Noise=0x%02X\n", t); 928 dprintk("AVG Noise=0x%02X\n", t);
679 *snr = 256 - t; 929 *snr = 256 - t;
680 *snr <<= 8; 930 *snr <<= 8;
@@ -690,31 +940,68 @@ static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
690 return 0; 940 return 0;
691} 941}
692 942
943static void packet_counter_start(struct lgs8gxx_state *priv)
944{
945 u8 orig, t;
946
947 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
948 lgs8gxx_read_reg(priv, 0x30, &orig);
949 orig &= 0xE7;
950 t = orig | 0x10;
951 lgs8gxx_write_reg(priv, 0x30, t);
952 t = orig | 0x18;
953 lgs8gxx_write_reg(priv, 0x30, t);
954 t = orig | 0x10;
955 lgs8gxx_write_reg(priv, 0x30, t);
956 } else {
957 lgs8gxx_write_reg(priv, 0xC6, 0x01);
958 lgs8gxx_write_reg(priv, 0xC6, 0x41);
959 lgs8gxx_write_reg(priv, 0xC6, 0x01);
960 }
961}
962
963static void packet_counter_stop(struct lgs8gxx_state *priv)
964{
965 u8 t;
966
967 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
968 lgs8gxx_read_reg(priv, 0x30, &t);
969 t &= 0xE7;
970 lgs8gxx_write_reg(priv, 0x30, t);
971 } else {
972 lgs8gxx_write_reg(priv, 0xC6, 0x81);
973 }
974}
975
693static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber) 976static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
694{ 977{
695 struct lgs8gxx_state *priv = fe->demodulator_priv; 978 struct lgs8gxx_state *priv = fe->demodulator_priv;
696 u8 r0, r1, r2, r3; 979 u8 reg_err, reg_total, t;
697 u32 total_cnt, err_cnt; 980 u32 total_cnt = 0, err_cnt = 0;
981 int i;
698 982
699 dprintk("%s\n", __func__); 983 dprintk("%s\n", __func__);
700 984
701 lgs8gxx_write_reg(priv, 0xc6, 0x01); 985 packet_counter_start(priv);
702 lgs8gxx_write_reg(priv, 0xc6, 0x41);
703 lgs8gxx_write_reg(priv, 0xc6, 0x01);
704
705 msleep(200); 986 msleep(200);
987 packet_counter_stop(priv);
988
989 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
990 reg_total = 0x28; reg_err = 0x2C;
991 } else {
992 reg_total = 0xD0; reg_err = 0xD4;
993 }
706 994
707 lgs8gxx_write_reg(priv, 0xc6, 0x81); 995 for (i = 0; i < 4; i++) {
708 lgs8gxx_read_reg(priv, 0xd0, &r0); 996 total_cnt <<= 8;
709 lgs8gxx_read_reg(priv, 0xd1, &r1); 997 lgs8gxx_read_reg(priv, reg_total+3-i, &t);
710 lgs8gxx_read_reg(priv, 0xd2, &r2); 998 total_cnt |= t;
711 lgs8gxx_read_reg(priv, 0xd3, &r3); 999 }
712 total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0); 1000 for (i = 0; i < 4; i++) {
713 lgs8gxx_read_reg(priv, 0xd4, &r0); 1001 err_cnt <<= 8;
714 lgs8gxx_read_reg(priv, 0xd5, &r1); 1002 lgs8gxx_read_reg(priv, reg_err+3-i, &t);
715 lgs8gxx_read_reg(priv, 0xd6, &r2); 1003 err_cnt |= t;
716 lgs8gxx_read_reg(priv, 0xd7, &r3); 1004 }
717 err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
718 dprintk("error=%d total=%d\n", err_cnt, total_cnt); 1005 dprintk("error=%d total=%d\n", err_cnt, total_cnt);
719 1006
720 if (total_cnt == 0) 1007 if (total_cnt == 0)
@@ -801,6 +1088,9 @@ struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
801 sizeof(struct dvb_frontend_ops)); 1088 sizeof(struct dvb_frontend_ops));
802 priv->frontend.demodulator_priv = priv; 1089 priv->frontend.demodulator_priv = priv;
803 1090
1091 if (config->prod == LGS8GXX_PROD_LGS8G75)
1092 lgs8g75_init_data(priv);
1093
804 return &priv->frontend; 1094 return &priv->frontend;
805 1095
806error_out: 1096error_out:
diff --git a/drivers/media/dvb/frontends/lgs8gxx.h b/drivers/media/dvb/frontends/lgs8gxx.h
index 321d366a8307..33c3c5e162fa 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.h
+++ b/drivers/media/dvb/frontends/lgs8gxx.h
@@ -1,9 +1,9 @@
1/* 1/*
2 * Support for Legend Silicon DMB-TH demodulator 2 * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
3 * LGS8913, LGS8GL5 3 * LGS8913, LGS8GL5, LGS8G75
4 * experimental support LGS8G42, LGS8G52 4 * experimental support LGS8G42, LGS8G52
5 * 5 *
6 * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> 6 * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited 7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited
8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) 8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
9 * 9 *
@@ -34,6 +34,7 @@
34#define LGS8GXX_PROD_LGS8G42 3 34#define LGS8GXX_PROD_LGS8G42 3
35#define LGS8GXX_PROD_LGS8G52 4 35#define LGS8GXX_PROD_LGS8G52 4
36#define LGS8GXX_PROD_LGS8G54 5 36#define LGS8GXX_PROD_LGS8G54 5
37#define LGS8GXX_PROD_LGS8G75 6
37 38
38struct lgs8gxx_config { 39struct lgs8gxx_config {
39 40
@@ -70,6 +71,10 @@ struct lgs8gxx_config {
70 /*IF use Negative center frequency*/ 71 /*IF use Negative center frequency*/
71 u8 if_neg_center; 72 u8 if_neg_center;
72 73
74 /*8G75 internal ADC input range selection*/
75 /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
76 u8 adc_vpp;
77
73 /* slave address and configuration of the tuner */ 78 /* slave address and configuration of the tuner */
74 u8 tuner_address; 79 u8 tuner_address;
75}; 80};
diff --git a/drivers/media/dvb/frontends/lgs8gxx_priv.h b/drivers/media/dvb/frontends/lgs8gxx_priv.h
index 9776d30686dc..8ef376f1414d 100644
--- a/drivers/media/dvb/frontends/lgs8gxx_priv.h
+++ b/drivers/media/dvb/frontends/lgs8gxx_priv.h
@@ -1,9 +1,9 @@
1/* 1/*
2 * Support for Legend Silicon DMB-TH demodulator 2 * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
3 * LGS8913, LGS8GL5 3 * LGS8913, LGS8GL5, LGS8G75
4 * experimental support LGS8G42, LGS8G52 4 * experimental support LGS8G42, LGS8G52
5 * 5 *
6 * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> 6 * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited 7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited
8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) 8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
9 * 9 *
@@ -38,7 +38,7 @@ struct lgs8gxx_state {
38#define SC_QAM64 0x10 /* 64QAM modulation */ 38#define SC_QAM64 0x10 /* 64QAM modulation */
39#define SC_QAM32 0x0C /* 32QAM modulation */ 39#define SC_QAM32 0x0C /* 32QAM modulation */
40#define SC_QAM16 0x08 /* 16QAM modulation */ 40#define SC_QAM16 0x08 /* 16QAM modulation */
41#define SC_QAM4NR 0x04 /* 4QAM modulation */ 41#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */
42#define SC_QAM4 0x00 /* 4QAM modulation */ 42#define SC_QAM4 0x00 /* 4QAM modulation */
43 43
44#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */ 44#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */
@@ -47,8 +47,8 @@ struct lgs8gxx_state {
47#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */ 47#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */
48 48
49#define TIM_MASK 0x20 /* Time Interleave Length Mask */ 49#define TIM_MASK 0x20 /* Time Interleave Length Mask */
50#define TIM_LONG 0x00 /* Time Interleave Length = 720 */ 50#define TIM_LONG 0x20 /* Time Interleave Length = 720 */
51#define TIM_MIDDLE 0x20 /* Time Interleave Length = 240 */ 51#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */
52 52
53#define CF_MASK 0x80 /* Control Frame Mask */ 53#define CF_MASK 0x80 /* Control Frame Mask */
54#define CF_EN 0x80 /* Control Frame On */ 54#define CF_EN 0x80 /* Control Frame On */