1052 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator4 * LGS8913, LGS8GL5, LGS8G755 * experimental support LGS8G42, LGS8G526 *7 * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>8 * Copyright (C) 2008 Sirius International (Hong Kong) Limited9 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)10 */11 12#include <asm/div64.h>13#include <linux/firmware.h>14 15#include <media/dvb_frontend.h>16 17#include "lgs8gxx.h"18#include "lgs8gxx_priv.h"19 20#define dprintk(args...) \21 do { \22 if (debug) \23 printk(KERN_DEBUG "lgs8gxx: " args); \24 } while (0)25 26static int debug;27static int fake_signal_str = 1;28 29#define LGS8GXX_FIRMWARE "lgs8g75.fw"30 31module_param(debug, int, 0644);32MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");33 34module_param(fake_signal_str, int, 0644);35MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."36"Signal strength calculation is slow.(default:on).");37 38/* LGS8GXX internal helper functions */39 40static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)41{42 int ret;43 u8 buf[] = { reg, data };44 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };45 46 msg.addr = priv->config->demod_address;47 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)48 msg.addr += 0x02;49 50 if (debug >= 2)51 dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);52 53 ret = i2c_transfer(priv->i2c, &msg, 1);54 55 if (ret != 1)56 dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",57 __func__, reg, data, ret);58 59 return (ret != 1) ? -1 : 0;60}61 62static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)63{64 int ret;65 u8 dev_addr;66 67 u8 b0[] = { reg };68 u8 b1[] = { 0 };69 struct i2c_msg msg[] = {70 { .flags = 0, .buf = b0, .len = 1 },71 { .flags = I2C_M_RD, .buf = b1, .len = 1 },72 };73 74 dev_addr = priv->config->demod_address;75 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)76 dev_addr += 0x02;77 msg[1].addr = msg[0].addr = dev_addr;78 79 ret = i2c_transfer(priv->i2c, msg, 2);80 if (ret != 2) {81 dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);82 return -1;83 }84 85 *p_data = b1[0];86 if (debug >= 2)87 dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);88 return 0;89}90 91static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)92{93 lgs8gxx_write_reg(priv, 0x02, 0x00);94 msleep(1);95 lgs8gxx_write_reg(priv, 0x02, 0x01);96 msleep(100);97 98 return 0;99}100 101static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,102 u8 val, u8 delay, u8 tries)103{104 u8 t;105 int i;106 107 for (i = 0; i < tries; i++) {108 lgs8gxx_read_reg(priv, reg, &t);109 110 if ((t & mask) == val)111 return 0;112 msleep(delay);113 }114 115 return 1;116}117 118static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)119{120 const struct lgs8gxx_config *config = priv->config;121 u8 if_conf;122 123 if_conf = 0x10; /* AGC output on, RF_AGC output off; */124 125 if_conf |=126 ((config->ext_adc) ? 0x80 : 0x00) |127 ((config->if_neg_center) ? 0x04 : 0x00) |128 ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */129 ((config->adc_signed) ? 0x02 : 0x00) |130 ((config->if_neg_edge) ? 0x01 : 0x00);131 132 if (config->ext_adc &&133 (config->prod == LGS8GXX_PROD_LGS8G52)) {134 lgs8gxx_write_reg(priv, 0xBA, 0x40);135 }136 137 lgs8gxx_write_reg(priv, 0x07, if_conf);138 139 return 0;140}141 142static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)143{144 u64 val;145 u32 v32;146 u32 if_clk;147 148 if_clk = priv->config->if_clk_freq;149 150 val = freq;151 if (freq != 0) {152 val <<= 32;153 if (if_clk != 0)154 do_div(val, if_clk);155 v32 = val & 0xFFFFFFFF;156 dprintk("Set IF Freq to %dkHz\n", freq);157 } else {158 v32 = 0;159 dprintk("Set IF Freq to baseband\n");160 }161 dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);162 163 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {164 lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));165 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));166 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));167 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));168 } else {169 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));170 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));171 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));172 lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));173 }174 175 return 0;176}177 178static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)179{180 u64 val;181 u32 v32 = 0;182 u8 reg_addr, t;183 int i;184 185 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)186 reg_addr = 0x23;187 else188 reg_addr = 0x48;189 190 for (i = 0; i < 4; i++) {191 lgs8gxx_read_reg(priv, reg_addr, &t);192 v32 <<= 8;193 v32 |= t;194 reg_addr--;195 }196 197 val = v32;198 val *= priv->config->if_clk_freq;199 val >>= 32;200 dprintk("AFC = %u kHz\n", (u32)val);201 return 0;202}203 204static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)205{206 u8 t;207 u8 prod = priv->config->prod;208 209 if (prod == LGS8GXX_PROD_LGS8913)210 lgs8gxx_write_reg(priv, 0xC6, 0x01);211 212 if (prod == LGS8GXX_PROD_LGS8G75) {213 lgs8gxx_read_reg(priv, 0x0C, &t);214 t &= (~0x04);215 lgs8gxx_write_reg(priv, 0x0C, t | 0x80);216 lgs8gxx_write_reg(priv, 0x39, 0x00);217 lgs8gxx_write_reg(priv, 0x3D, 0x04);218 } else if (prod == LGS8GXX_PROD_LGS8913 ||219 prod == LGS8GXX_PROD_LGS8GL5 ||220 prod == LGS8GXX_PROD_LGS8G42 ||221 prod == LGS8GXX_PROD_LGS8G52 ||222 prod == LGS8GXX_PROD_LGS8G54) {223 lgs8gxx_read_reg(priv, 0x7E, &t);224 lgs8gxx_write_reg(priv, 0x7E, t | 0x01);225 226 /* clear FEC self reset */227 lgs8gxx_read_reg(priv, 0xC5, &t);228 lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);229 }230 231 if (prod == LGS8GXX_PROD_LGS8913) {232 /* FEC auto detect */233 lgs8gxx_write_reg(priv, 0xC1, 0x03);234 235 lgs8gxx_read_reg(priv, 0x7C, &t);236 t = (t & 0x8C) | 0x03;237 lgs8gxx_write_reg(priv, 0x7C, t);238 239 /* BER test mode */240 lgs8gxx_read_reg(priv, 0xC3, &t);241 t = (t & 0xEF) | 0x10;242 lgs8gxx_write_reg(priv, 0xC3, t);243 }244 245 if (priv->config->prod == LGS8GXX_PROD_LGS8G52)246 lgs8gxx_write_reg(priv, 0xD9, 0x40);247 248 return 0;249}250 251static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)252{253 u8 t;254 255 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {256 u8 t2;257 lgs8gxx_read_reg(priv, 0x0C, &t);258 t &= (~0x80);259 lgs8gxx_write_reg(priv, 0x0C, t);260 261 lgs8gxx_read_reg(priv, 0x0C, &t);262 lgs8gxx_read_reg(priv, 0x19, &t2);263 264 if (((t&0x03) == 0x01) && (t2&0x01)) {265 lgs8gxx_write_reg(priv, 0x6E, 0x05);266 lgs8gxx_write_reg(priv, 0x39, 0x02);267 lgs8gxx_write_reg(priv, 0x39, 0x03);268 lgs8gxx_write_reg(priv, 0x3D, 0x05);269 lgs8gxx_write_reg(priv, 0x3E, 0x28);270 lgs8gxx_write_reg(priv, 0x53, 0x80);271 } else {272 lgs8gxx_write_reg(priv, 0x6E, 0x3F);273 lgs8gxx_write_reg(priv, 0x39, 0x00);274 lgs8gxx_write_reg(priv, 0x3D, 0x04);275 }276 277 lgs8gxx_soft_reset(priv);278 return 0;279 }280 281 /* turn off auto-detect; manual settings */282 lgs8gxx_write_reg(priv, 0x7E, 0);283 if (priv->config->prod == LGS8GXX_PROD_LGS8913)284 lgs8gxx_write_reg(priv, 0xC1, 0);285 286 lgs8gxx_read_reg(priv, 0xC5, &t);287 t = (t & 0xE0) | 0x06;288 lgs8gxx_write_reg(priv, 0xC5, t);289 290 lgs8gxx_soft_reset(priv);291 292 return 0;293}294 295static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)296{297 int ret = 0;298 u8 t;299 300 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)301 ret = lgs8gxx_read_reg(priv, 0x13, &t);302 else303 ret = lgs8gxx_read_reg(priv, 0x4B, &t);304 if (ret != 0)305 return ret;306 307 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)308 *locked = ((t & 0x80) == 0x80) ? 1 : 0;309 else310 *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;311 return 0;312}313 314/* Wait for Code Acquisition Lock */315static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)316{317 int ret = 0;318 u8 reg, mask, val;319 320 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {321 reg = 0x13;322 mask = 0x80;323 val = 0x80;324 } else {325 reg = 0x4B;326 mask = 0xC0;327 val = 0xC0;328 }329 330 ret = wait_reg_mask(priv, reg, mask, val, 50, 40);331 *locked = (ret == 0) ? 1 : 0;332 333 return 0;334}335 336static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,337 u8 *finished)338{339 int ret = 0;340 u8 reg, mask, val;341 342 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {343 reg = 0x1f;344 mask = 0xC0;345 val = 0x80;346 } else {347 reg = 0xA4;348 mask = 0x03;349 val = 0x01;350 }351 352 ret = wait_reg_mask(priv, reg, mask, val, 10, 20);353 *finished = (ret == 0) ? 1 : 0;354 355 return 0;356}357 358static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,359 u8 *locked)360{361 int err = 0;362 u8 ad_fini = 0;363 u8 t1, t2;364 365 if (gi == GI_945)366 dprintk("try GI 945\n");367 else if (gi == GI_595)368 dprintk("try GI 595\n");369 else if (gi == GI_420)370 dprintk("try GI 420\n");371 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {372 lgs8gxx_read_reg(priv, 0x0C, &t1);373 lgs8gxx_read_reg(priv, 0x18, &t2);374 t1 &= ~(GI_MASK);375 t1 |= gi;376 t2 &= 0xFE;377 t2 |= cpn ? 0x01 : 0x00;378 lgs8gxx_write_reg(priv, 0x0C, t1);379 lgs8gxx_write_reg(priv, 0x18, t2);380 } else {381 lgs8gxx_write_reg(priv, 0x04, gi);382 }383 lgs8gxx_soft_reset(priv);384 err = lgs8gxx_wait_ca_lock(priv, locked);385 if (err || !(*locked))386 return err;387 err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);388 if (err != 0)389 return err;390 if (ad_fini) {391 dprintk("auto detect finished\n");392 } else393 *locked = 0;394 395 return 0;396}397 398static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,399 u8 *detected_param, u8 *gi)400{401 int i, j;402 int err = 0;403 u8 locked = 0, tmp_gi;404 405 dprintk("%s\n", __func__);406 407 lgs8gxx_set_mode_auto(priv);408 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {409 lgs8gxx_write_reg(priv, 0x67, 0xAA);410 lgs8gxx_write_reg(priv, 0x6E, 0x3F);411 } else {412 /* Guard Interval */413 lgs8gxx_write_reg(priv, 0x03, 00);414 }415 416 for (i = 0; i < 2; i++) {417 for (j = 0; j < 2; j++) {418 tmp_gi = GI_945;419 err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);420 if (err)421 goto out;422 if (locked)423 goto locked;424 }425 for (j = 0; j < 2; j++) {426 tmp_gi = GI_420;427 err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);428 if (err)429 goto out;430 if (locked)431 goto locked;432 }433 tmp_gi = GI_595;434 err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);435 if (err)436 goto out;437 if (locked)438 goto locked;439 }440 441locked:442 if ((err == 0) && (locked == 1)) {443 u8 t;444 445 if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {446 lgs8gxx_read_reg(priv, 0xA2, &t);447 *detected_param = t;448 } else {449 lgs8gxx_read_reg(priv, 0x1F, &t);450 *detected_param = t & 0x3F;451 }452 453 if (tmp_gi == GI_945)454 dprintk("GI 945 locked\n");455 else if (tmp_gi == GI_595)456 dprintk("GI 595 locked\n");457 else if (tmp_gi == GI_420)458 dprintk("GI 420 locked\n");459 *gi = tmp_gi;460 }461 if (!locked)462 err = -1;463 464out:465 return err;466}467 468static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)469{470 s8 err;471 u8 gi = 0x2;472 u8 detected_param = 0;473 474 err = lgs8gxx_auto_detect(priv, &detected_param, &gi);475 476 if (err != 0) {477 dprintk("lgs8gxx_auto_detect failed\n");478 } else479 dprintk("detected param = 0x%02X\n", detected_param);480 481 /* Apply detected parameters */482 if (priv->config->prod == LGS8GXX_PROD_LGS8913) {483 u8 inter_leave_len = detected_param & TIM_MASK ;484 /* Fix 8913 time interleaver detection bug */485 inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;486 detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;487 detected_param |= inter_leave_len;488 }489 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {490 u8 t;491 lgs8gxx_read_reg(priv, 0x19, &t);492 t &= 0x81;493 t |= detected_param << 1;494 lgs8gxx_write_reg(priv, 0x19, t);495 } else {496 lgs8gxx_write_reg(priv, 0x7D, detected_param);497 if (priv->config->prod == LGS8GXX_PROD_LGS8913)498 lgs8gxx_write_reg(priv, 0xC0, detected_param);499 }500 /* lgs8gxx_soft_reset(priv); */501 502 /* Enter manual mode */503 lgs8gxx_set_mode_manual(priv);504 505 switch (gi) {506 case GI_945:507 priv->curr_gi = 945; break;508 case GI_595:509 priv->curr_gi = 595; break;510 case GI_420:511 priv->curr_gi = 420; break;512 default:513 priv->curr_gi = 945; break;514 }515}516 517static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,518 u8 serial, u8 clk_pol, u8 clk_gated)519{520 int ret = 0;521 u8 t, reg_addr;522 523 reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;524 ret = lgs8gxx_read_reg(priv, reg_addr, &t);525 if (ret != 0)526 return ret;527 528 t &= 0xF8;529 t |= serial ? TS_SERIAL : TS_PARALLEL;530 t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;531 t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;532 533 ret = lgs8gxx_write_reg(priv, reg_addr, t);534 if (ret != 0)535 return ret;536 537 return 0;538}539 540/* A/D input peak-to-peak voltage range */541static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,542 u8 sel)543{544 u8 r26 = 0x73, r27 = 0x90;545 546 if (priv->config->prod != LGS8GXX_PROD_LGS8G75)547 return 0;548 549 r26 |= (sel & 0x01) << 7;550 r27 |= (sel & 0x02) >> 1;551 lgs8gxx_write_reg(priv, 0x26, r26);552 lgs8gxx_write_reg(priv, 0x27, r27);553 554 return 0;555}556 557/* LGS8913 demod frontend functions */558 559static int lgs8913_init(struct lgs8gxx_state *priv)560{561 u8 t;562 563 /* LGS8913 specific */564 lgs8gxx_write_reg(priv, 0xc1, 0x3);565 566 lgs8gxx_read_reg(priv, 0x7c, &t);567 lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3);568 569 /* LGS8913 specific */570 lgs8gxx_read_reg(priv, 0xc3, &t);571 lgs8gxx_write_reg(priv, 0xc3, t&0x10);572 573 574 return 0;575}576 577static int lgs8g75_init_data(struct lgs8gxx_state *priv)578{579 const struct firmware *fw;580 int rc;581 int i;582 583 rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev);584 if (rc)585 return rc;586 587 lgs8gxx_write_reg(priv, 0xC6, 0x40);588 589 lgs8gxx_write_reg(priv, 0x3D, 0x04);590 lgs8gxx_write_reg(priv, 0x39, 0x00);591 592 lgs8gxx_write_reg(priv, 0x3A, 0x00);593 lgs8gxx_write_reg(priv, 0x38, 0x00);594 lgs8gxx_write_reg(priv, 0x3B, 0x00);595 lgs8gxx_write_reg(priv, 0x38, 0x00);596 597 for (i = 0; i < fw->size; i++) {598 lgs8gxx_write_reg(priv, 0x38, 0x00);599 lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));600 lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));601 lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);602 }603 604 lgs8gxx_write_reg(priv, 0x38, 0x00);605 606 release_firmware(fw);607 return 0;608}609 610static int lgs8gxx_init(struct dvb_frontend *fe)611{612 struct lgs8gxx_state *priv =613 (struct lgs8gxx_state *)fe->demodulator_priv;614 const struct lgs8gxx_config *config = priv->config;615 u8 data = 0;616 s8 err;617 dprintk("%s\n", __func__);618 619 lgs8gxx_read_reg(priv, 0, &data);620 dprintk("reg 0 = 0x%02X\n", data);621 622 if (config->prod == LGS8GXX_PROD_LGS8G75)623 lgs8g75_set_adc_vpp(priv, config->adc_vpp);624 625 /* Setup MPEG output format */626 err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,627 config->ts_clk_pol,628 config->ts_clk_gated);629 if (err != 0)630 return -EIO;631 632 if (config->prod == LGS8GXX_PROD_LGS8913)633 lgs8913_init(priv);634 lgs8gxx_set_if_freq(priv, priv->config->if_freq);635 lgs8gxx_set_ad_mode(priv);636 637 return 0;638}639 640static void lgs8gxx_release(struct dvb_frontend *fe)641{642 struct lgs8gxx_state *state = fe->demodulator_priv;643 dprintk("%s\n", __func__);644 645 kfree(state);646}647 648 649static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)650{651 struct lgs8gxx_state *priv = fe->demodulator_priv;652 653 if (len != 2)654 return -EINVAL;655 656 return lgs8gxx_write_reg(priv, buf[0], buf[1]);657}658 659static int lgs8gxx_set_fe(struct dvb_frontend *fe)660{661 struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;662 struct lgs8gxx_state *priv = fe->demodulator_priv;663 664 dprintk("%s\n", __func__);665 666 /* set frequency */667 if (fe->ops.tuner_ops.set_params) {668 fe->ops.tuner_ops.set_params(fe);669 if (fe->ops.i2c_gate_ctrl)670 fe->ops.i2c_gate_ctrl(fe, 0);671 }672 673 /* start auto lock */674 lgs8gxx_auto_lock(priv);675 676 msleep(10);677 678 /* TODO: get real readings from device */679 680 /* bandwidth */681 fe_params->bandwidth_hz = 8000000;682 683 fe_params->code_rate_HP = FEC_AUTO;684 fe_params->code_rate_LP = FEC_AUTO;685 686 fe_params->modulation = QAM_AUTO;687 688 /* transmission mode */689 fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;690 691 /* guard interval */692 fe_params->guard_interval = GUARD_INTERVAL_AUTO;693 694 /* hierarchy */695 fe_params->hierarchy = HIERARCHY_NONE;696 697 return 0;698}699 700static701int lgs8gxx_get_tune_settings(struct dvb_frontend *fe,702 struct dvb_frontend_tune_settings *fesettings)703{704 /* FIXME: copy from tda1004x.c */705 fesettings->min_delay_ms = 800;706 fesettings->step_size = 0;707 fesettings->max_drift = 0;708 return 0;709}710 711static int lgs8gxx_read_status(struct dvb_frontend *fe,712 enum fe_status *fe_status)713{714 struct lgs8gxx_state *priv = fe->demodulator_priv;715 s8 ret;716 u8 t, locked = 0;717 718 dprintk("%s\n", __func__);719 *fe_status = 0;720 721 lgs8gxx_get_afc_phase(priv);722 lgs8gxx_is_locked(priv, &locked);723 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {724 if (locked)725 *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |726 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;727 return 0;728 }729 730 ret = lgs8gxx_read_reg(priv, 0x4B, &t);731 if (ret != 0)732 return -EIO;733 734 dprintk("Reg 0x4B: 0x%02X\n", t);735 736 *fe_status = 0;737 if (priv->config->prod == LGS8GXX_PROD_LGS8913) {738 if ((t & 0x40) == 0x40)739 *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;740 if ((t & 0x80) == 0x80)741 *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC |742 FE_HAS_LOCK;743 } else {744 if ((t & 0x80) == 0x80)745 *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |746 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;747 }748 749 /* success */750 dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);751 return 0;752}753 754static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)755{756 u16 v;757 u8 agc_lvl[2], cat;758 759 dprintk("%s()\n", __func__);760 lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]);761 lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]);762 763 v = agc_lvl[0];764 v <<= 8;765 v |= agc_lvl[1];766 767 dprintk("agc_lvl: 0x%04X\n", v);768 769 if (v < 0x100)770 cat = 0;771 else if (v < 0x190)772 cat = 5;773 else if (v < 0x2A8)774 cat = 4;775 else if (v < 0x381)776 cat = 3;777 else if (v < 0x400)778 cat = 2;779 else if (v == 0x400)780 cat = 1;781 else782 cat = 0;783 784 *signal = cat * 65535 / 5;785 786 return 0;787}788 789static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)790{791 u8 t; s8 ret;792 s16 max_strength = 0;793 u8 str;794 u16 i, gi = priv->curr_gi;795 796 dprintk("%s\n", __func__);797 798 ret = lgs8gxx_read_reg(priv, 0x4B, &t);799 if (ret != 0)800 return -EIO;801 802 if (fake_signal_str) {803 if ((t & 0xC0) == 0xC0) {804 dprintk("Fake signal strength\n");805 *signal = 0x7FFF;806 } else807 *signal = 0;808 return 0;809 }810 811 dprintk("gi = %d\n", gi);812 for (i = 0; i < gi; i++) {813 814 if ((i & 0xFF) == 0)815 lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8));816 lgs8gxx_write_reg(priv, 0x83, i & 0xFF);817 818 lgs8gxx_read_reg(priv, 0x94, &str);819 if (max_strength < str)820 max_strength = str;821 }822 823 *signal = max_strength;824 dprintk("%s: signal=0x%02X\n", __func__, *signal);825 826 lgs8gxx_read_reg(priv, 0x95, &t);827 dprintk("%s: AVG Noise=0x%02X\n", __func__, t);828 829 return 0;830}831 832static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)833{834 u8 t;835 s16 v = 0;836 837 dprintk("%s\n", __func__);838 839 lgs8gxx_read_reg(priv, 0xB1, &t);840 v |= t;841 v <<= 8;842 lgs8gxx_read_reg(priv, 0xB0, &t);843 v |= t;844 845 *signal = v;846 dprintk("%s: signal=0x%02X\n", __func__, *signal);847 848 return 0;849}850 851static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)852{853 struct lgs8gxx_state *priv = fe->demodulator_priv;854 855 if (priv->config->prod == LGS8GXX_PROD_LGS8913)856 return lgs8913_read_signal_strength(priv, signal);857 else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)858 return lgs8g75_read_signal_strength(priv, signal);859 else860 return lgs8gxx_read_signal_agc(priv, signal);861}862 863static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)864{865 struct lgs8gxx_state *priv = fe->demodulator_priv;866 u8 t;867 *snr = 0;868 869 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)870 lgs8gxx_read_reg(priv, 0x34, &t);871 else872 lgs8gxx_read_reg(priv, 0x95, &t);873 dprintk("AVG Noise=0x%02X\n", t);874 *snr = 256 - t;875 *snr <<= 8;876 dprintk("snr=0x%x\n", *snr);877 878 return 0;879}880 881static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)882{883 *ucblocks = 0;884 dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);885 return 0;886}887 888static void packet_counter_start(struct lgs8gxx_state *priv)889{890 u8 orig, t;891 892 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {893 lgs8gxx_read_reg(priv, 0x30, &orig);894 orig &= 0xE7;895 t = orig | 0x10;896 lgs8gxx_write_reg(priv, 0x30, t);897 t = orig | 0x18;898 lgs8gxx_write_reg(priv, 0x30, t);899 t = orig | 0x10;900 lgs8gxx_write_reg(priv, 0x30, t);901 } else {902 lgs8gxx_write_reg(priv, 0xC6, 0x01);903 lgs8gxx_write_reg(priv, 0xC6, 0x41);904 lgs8gxx_write_reg(priv, 0xC6, 0x01);905 }906}907 908static void packet_counter_stop(struct lgs8gxx_state *priv)909{910 u8 t;911 912 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {913 lgs8gxx_read_reg(priv, 0x30, &t);914 t &= 0xE7;915 lgs8gxx_write_reg(priv, 0x30, t);916 } else {917 lgs8gxx_write_reg(priv, 0xC6, 0x81);918 }919}920 921static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)922{923 struct lgs8gxx_state *priv = fe->demodulator_priv;924 u8 reg_err, reg_total, t;925 u32 total_cnt = 0, err_cnt = 0;926 int i;927 928 dprintk("%s\n", __func__);929 930 packet_counter_start(priv);931 msleep(200);932 packet_counter_stop(priv);933 934 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {935 reg_total = 0x28; reg_err = 0x2C;936 } else {937 reg_total = 0xD0; reg_err = 0xD4;938 }939 940 for (i = 0; i < 4; i++) {941 total_cnt <<= 8;942 lgs8gxx_read_reg(priv, reg_total+3-i, &t);943 total_cnt |= t;944 }945 for (i = 0; i < 4; i++) {946 err_cnt <<= 8;947 lgs8gxx_read_reg(priv, reg_err+3-i, &t);948 err_cnt |= t;949 }950 dprintk("error=%d total=%d\n", err_cnt, total_cnt);951 952 if (total_cnt == 0)953 *ber = 0;954 else955 *ber = err_cnt * 100 / total_cnt;956 957 dprintk("%s: ber=0x%x\n", __func__, *ber);958 return 0;959}960 961static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)962{963 struct lgs8gxx_state *priv = fe->demodulator_priv;964 965 if (priv->config->tuner_address == 0)966 return 0;967 if (enable) {968 u8 v = 0x80 | priv->config->tuner_address;969 return lgs8gxx_write_reg(priv, 0x01, v);970 }971 return lgs8gxx_write_reg(priv, 0x01, 0);972}973 974static const struct dvb_frontend_ops lgs8gxx_ops = {975 .delsys = { SYS_DTMB },976 .info = {977 .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",978 .frequency_min_hz = 474 * MHz,979 .frequency_max_hz = 858 * MHz,980 .frequency_stepsize_hz = 10 * kHz,981 .caps =982 FE_CAN_FEC_AUTO |983 FE_CAN_QAM_AUTO |984 FE_CAN_TRANSMISSION_MODE_AUTO |985 FE_CAN_GUARD_INTERVAL_AUTO986 },987 988 .release = lgs8gxx_release,989 990 .init = lgs8gxx_init,991 .write = lgs8gxx_write,992 .i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl,993 994 .set_frontend = lgs8gxx_set_fe,995 .get_tune_settings = lgs8gxx_get_tune_settings,996 997 .read_status = lgs8gxx_read_status,998 .read_ber = lgs8gxx_read_ber,999 .read_signal_strength = lgs8gxx_read_signal_strength,1000 .read_snr = lgs8gxx_read_snr,1001 .read_ucblocks = lgs8gxx_read_ucblocks,1002};1003 1004struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,1005 struct i2c_adapter *i2c)1006{1007 struct lgs8gxx_state *priv = NULL;1008 u8 data = 0;1009 1010 dprintk("%s()\n", __func__);1011 1012 if (config == NULL || i2c == NULL)1013 return NULL;1014 1015 priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL);1016 if (priv == NULL)1017 goto error_out;1018 1019 priv->config = config;1020 priv->i2c = i2c;1021 1022 /* check if the demod is there */1023 if (lgs8gxx_read_reg(priv, 0, &data) != 0) {1024 dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n",1025 __func__, priv->config->demod_address);1026 goto error_out;1027 }1028 1029 lgs8gxx_read_reg(priv, 1, &data);1030 1031 memcpy(&priv->frontend.ops, &lgs8gxx_ops,1032 sizeof(struct dvb_frontend_ops));1033 priv->frontend.demodulator_priv = priv;1034 1035 if (config->prod == LGS8GXX_PROD_LGS8G75)1036 lgs8g75_init_data(priv);1037 1038 return &priv->frontend;1039 1040error_out:1041 dprintk("%s() error_out\n", __func__);1042 kfree(priv);1043 return NULL;1044 1045}1046EXPORT_SYMBOL_GPL(lgs8gxx_attach);1047 1048MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");1049MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");1050MODULE_LICENSE("GPL");1051MODULE_FIRMWARE(LGS8GXX_FIRMWARE);1052