1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 STB6100 Silicon Tuner 4 Copyright (C) Manu Abraham (abraham.manu@gmail.com) 5 6 Copyright (C) ST Microelectronics 7 8 */ 9 10 #include <linux/init.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/string.h> 15 16 #include <media/dvb_frontend.h> 17 #include "stb6100.h" 18 19 static unsigned int verbose; 20 module_param(verbose, int, 0644); 21 22 /* Max transfer size done by I2C transfer functions */ 23 #define MAX_XFER_SIZE 64 24 25 #define FE_ERROR 0 26 #define FE_NOTICE 1 27 #define FE_INFO 2 28 #define FE_DEBUG 3 29 30 #define dprintk(x, y, z, format, arg...) do { \ 31 if (z) { \ 32 if ((x > FE_ERROR) && (x > y)) \ 33 printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ 34 else if ((x > FE_NOTICE) && (x > y)) \ 35 printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ 36 else if ((x > FE_INFO) && (x > y)) \ 37 printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ 38 else if ((x > FE_DEBUG) && (x > y)) \ 39 printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ 40 } else { \ 41 if (x > y) \ 42 printk(format, ##arg); \ 43 } \ 44 } while (0) 45 46 struct stb6100_lkup { 47 u32 val_low; 48 u32 val_high; 49 u8 reg; 50 }; 51 52 static void stb6100_release(struct dvb_frontend *fe); 53 54 static const struct stb6100_lkup lkup[] = { 55 { 0, 950000, 0x0a }, 56 { 950000, 1000000, 0x0a }, 57 { 1000000, 1075000, 0x0c }, 58 { 1075000, 1200000, 0x00 }, 59 { 1200000, 1300000, 0x01 }, 60 { 1300000, 1370000, 0x02 }, 61 { 1370000, 1470000, 0x04 }, 62 { 1470000, 1530000, 0x05 }, 63 { 1530000, 1650000, 0x06 }, 64 { 1650000, 1800000, 0x08 }, 65 { 1800000, 1950000, 0x0a }, 66 { 1950000, 2150000, 0x0c }, 67 { 2150000, 9999999, 0x0c }, 68 { 0, 0, 0x00 } 69 }; 70 71 /* Register names for easy debugging. */ 72 static const char *stb6100_regnames[] = { 73 [STB6100_LD] = "LD", 74 [STB6100_VCO] = "VCO", 75 [STB6100_NI] = "NI", 76 [STB6100_NF_LSB] = "NF", 77 [STB6100_K] = "K", 78 [STB6100_G] = "G", 79 [STB6100_F] = "F", 80 [STB6100_DLB] = "DLB", 81 [STB6100_TEST1] = "TEST1", 82 [STB6100_FCCK] = "FCCK", 83 [STB6100_LPEN] = "LPEN", 84 [STB6100_TEST3] = "TEST3", 85 }; 86 87 /* Template for normalisation, i.e. setting unused or undocumented 88 * bits as required according to the documentation. 89 */ 90 struct stb6100_regmask { 91 u8 mask; 92 u8 set; 93 }; 94 95 static const struct stb6100_regmask stb6100_template[] = { 96 [STB6100_LD] = { 0xff, 0x00 }, 97 [STB6100_VCO] = { 0xff, 0x00 }, 98 [STB6100_NI] = { 0xff, 0x00 }, 99 [STB6100_NF_LSB] = { 0xff, 0x00 }, 100 [STB6100_K] = { 0xc7, 0x38 }, 101 [STB6100_G] = { 0xef, 0x10 }, 102 [STB6100_F] = { 0x1f, 0xc0 }, 103 [STB6100_DLB] = { 0x38, 0xc4 }, 104 [STB6100_TEST1] = { 0x00, 0x8f }, 105 [STB6100_FCCK] = { 0x40, 0x0d }, 106 [STB6100_LPEN] = { 0xf0, 0x0b }, 107 [STB6100_TEST3] = { 0x00, 0xde }, 108 }; 109 110 /* 111 * Currently unused. Some boards might need it in the future 112 */ 113 static __always_unused inline void stb6100_normalise_regs(u8 regs[]) 114 { 115 int i; 116 117 for (i = 0; i < STB6100_NUMREGS; i++) 118 regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set; 119 } 120 121 static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) 122 { 123 int rc; 124 struct i2c_msg msg = { 125 .addr = state->config->tuner_address, 126 .flags = I2C_M_RD, 127 .buf = regs, 128 .len = STB6100_NUMREGS 129 }; 130 131 rc = i2c_transfer(state->i2c, &msg, 1); 132 if (unlikely(rc != 1)) { 133 dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]", 134 state->config->tuner_address, rc); 135 136 return -EREMOTEIO; 137 } 138 if (unlikely(verbose > FE_DEBUG)) { 139 int i; 140 141 dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); 142 for (i = 0; i < STB6100_NUMREGS; i++) 143 dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]); 144 } 145 return 0; 146 } 147 148 static int stb6100_read_reg(struct stb6100_state *state, u8 reg) 149 { 150 u8 regs[STB6100_NUMREGS]; 151 152 struct i2c_msg msg = { 153 .addr = state->config->tuner_address + reg, 154 .flags = I2C_M_RD, 155 .buf = regs, 156 .len = 1 157 }; 158 159 i2c_transfer(state->i2c, &msg, 1); 160 161 if (unlikely(reg >= STB6100_NUMREGS)) { 162 dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); 163 return -EINVAL; 164 } 165 if (unlikely(verbose > FE_DEBUG)) { 166 dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); 167 dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]); 168 } 169 170 return (unsigned int)regs[0]; 171 } 172 173 static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) 174 { 175 int rc; 176 u8 cmdbuf[MAX_XFER_SIZE]; 177 struct i2c_msg msg = { 178 .addr = state->config->tuner_address, 179 .flags = 0, 180 .buf = cmdbuf, 181 .len = len + 1 182 }; 183 184 if (1 + len > sizeof(cmdbuf)) { 185 printk(KERN_WARNING 186 "%s: i2c wr: len=%d is too big!\n", 187 KBUILD_MODNAME, len); 188 return -EINVAL; 189 } 190 191 if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { 192 dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", 193 start, len); 194 return -EINVAL; 195 } 196 memcpy(&cmdbuf[1], buf, len); 197 cmdbuf[0] = start; 198 199 if (unlikely(verbose > FE_DEBUG)) { 200 int i; 201 202 dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len); 203 for (i = 0; i < len; i++) 204 dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]); 205 } 206 rc = i2c_transfer(state->i2c, &msg, 1); 207 if (unlikely(rc != 1)) { 208 dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]", 209 (unsigned int)state->config->tuner_address, start, len, rc); 210 return -EREMOTEIO; 211 } 212 return 0; 213 } 214 215 static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) 216 { 217 u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ 218 219 if (unlikely(reg >= STB6100_NUMREGS)) { 220 dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); 221 return -EREMOTEIO; 222 } 223 tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set; 224 return stb6100_write_reg_range(state, &tmp, reg, 1); 225 } 226 227 228 static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) 229 { 230 int rc; 231 struct stb6100_state *state = fe->tuner_priv; 232 233 rc = stb6100_read_reg(state, STB6100_LD); 234 if (rc < 0) { 235 dprintk(verbose, FE_ERROR, 1, "%s failed", __func__); 236 return rc; 237 } 238 return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; 239 } 240 241 static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 242 { 243 int rc; 244 u8 f; 245 u32 bw; 246 struct stb6100_state *state = fe->tuner_priv; 247 248 rc = stb6100_read_reg(state, STB6100_F); 249 if (rc < 0) 250 return rc; 251 f = rc & STB6100_F_F; 252 253 bw = (f + 5) * 2000; /* x2 for ZIF */ 254 255 *bandwidth = state->bandwidth = bw * 1000; 256 dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); 257 return 0; 258 } 259 260 static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) 261 { 262 u32 tmp; 263 int rc; 264 struct stb6100_state *state = fe->tuner_priv; 265 266 dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth); 267 268 bandwidth /= 2; /* ZIF */ 269 270 if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */ 271 tmp = 31; 272 else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */ 273 tmp = 0; 274 else /* if 5 < bw/2 < 36 */ 275 tmp = (bandwidth + 500000) / 1000000 - 5; 276 277 /* Turn on LPF bandwidth setting clock control, 278 * set bandwidth, wait 10ms, turn off. 279 */ 280 rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK); 281 if (rc < 0) 282 return rc; 283 rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp); 284 if (rc < 0) 285 return rc; 286 287 msleep(5); /* This is dangerous as another (related) thread may start */ 288 289 rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); 290 if (rc < 0) 291 return rc; 292 293 msleep(10); /* This is dangerous as another (related) thread may start */ 294 295 return 0; 296 } 297 298 static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) 299 { 300 int rc; 301 u32 nint, nfrac, fvco; 302 int psd2, odiv; 303 struct stb6100_state *state = fe->tuner_priv; 304 u8 regs[STB6100_NUMREGS]; 305 306 rc = stb6100_read_regs(state, regs); 307 if (rc < 0) 308 return rc; 309 310 odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; 311 psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT; 312 nint = regs[STB6100_NI]; 313 nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB]; 314 fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2); 315 *frequency = state->frequency = fvco >> (odiv + 1); 316 317 dprintk(verbose, FE_DEBUG, 1, 318 "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u", 319 state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac); 320 return 0; 321 } 322 323 324 static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) 325 { 326 int rc; 327 const struct stb6100_lkup *ptr; 328 struct stb6100_state *state = fe->tuner_priv; 329 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 330 331 u32 srate = 0, fvco, nint, nfrac; 332 u8 regs[STB6100_NUMREGS]; 333 u8 g, psd2, odiv; 334 335 dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51"); 336 337 if (fe->ops.get_frontend) { 338 dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); 339 fe->ops.get_frontend(fe, p); 340 } 341 srate = p->symbol_rate; 342 343 /* Set up tuner cleanly, LPF calibration on */ 344 rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); 345 if (rc < 0) 346 return rc; /* allow LPF calibration */ 347 348 /* PLL Loop disabled, bias on, VCO on, synth on */ 349 regs[STB6100_LPEN] = 0xeb; 350 rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); 351 if (rc < 0) 352 return rc; 353 354 /* Program the registers with their data values */ 355 356 /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ 357 if (frequency <= 1075000) 358 odiv = 1; 359 else 360 odiv = 0; 361 362 /* VCO enabled, search clock off as per LL3.7, 3.4.1 */ 363 regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT); 364 365 /* OSM */ 366 for (ptr = lkup; 367 (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); 368 ptr++); 369 370 if (ptr->val_high == 0) { 371 printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); 372 return -EINVAL; 373 } 374 regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; 375 rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); 376 if (rc < 0) 377 return rc; 378 379 if ((frequency > 1075000) && (frequency <= 1325000)) 380 psd2 = 0; 381 else 382 psd2 = 1; 383 /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ 384 fvco = frequency << (1 + odiv); 385 /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ 386 nint = fvco / (state->reference << psd2); 387 /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ 388 nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2)) 389 << (9 - psd2), state->reference); 390 391 /* NI */ 392 regs[STB6100_NI] = nint; 393 rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]); 394 if (rc < 0) 395 return rc; 396 397 /* NF */ 398 regs[STB6100_NF_LSB] = nfrac; 399 rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]); 400 if (rc < 0) 401 return rc; 402 403 /* K */ 404 regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); 405 regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); 406 rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]); 407 if (rc < 0) 408 return rc; 409 410 /* G Baseband gain. */ 411 if (srate >= 15000000) 412 g = 9; /* +4 dB */ 413 else if (srate >= 5000000) 414 g = 11; /* +8 dB */ 415 else 416 g = 14; /* +14 dB */ 417 418 regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g; 419 regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ 420 regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ 421 rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]); 422 if (rc < 0) 423 return rc; 424 425 /* F we don't write as it is set up in BW set */ 426 427 /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */ 428 regs[STB6100_DLB] = 0xcc; 429 rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]); 430 if (rc < 0) 431 return rc; 432 433 dprintk(verbose, FE_DEBUG, 1, 434 "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", 435 frequency, srate, (unsigned int)g, (unsigned int)odiv, 436 (unsigned int)psd2, state->reference, 437 ptr->reg, fvco, nint, nfrac); 438 439 /* Set up the test registers */ 440 regs[STB6100_TEST1] = 0x8f; 441 rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]); 442 if (rc < 0) 443 return rc; 444 regs[STB6100_TEST3] = 0xde; 445 rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]); 446 if (rc < 0) 447 return rc; 448 449 /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */ 450 regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */ 451 rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); 452 if (rc < 0) 453 return rc; 454 455 msleep(2); 456 457 /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */ 458 regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ 459 rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); 460 if (rc < 0) 461 return rc; 462 463 msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */ 464 465 regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ 466 regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ 467 rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); 468 if (rc < 0) 469 return rc; 470 471 rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); 472 if (rc < 0) 473 return rc; /* Stop LPF calibration */ 474 475 msleep(10); /* This is dangerous as another (related) thread may start */ 476 /* wait for stabilisation, (should not be necessary) */ 477 return 0; 478 } 479 480 static int stb6100_sleep(struct dvb_frontend *fe) 481 { 482 /* TODO: power down */ 483 return 0; 484 } 485 486 static int stb6100_init(struct dvb_frontend *fe) 487 { 488 struct stb6100_state *state = fe->tuner_priv; 489 int refclk = 27000000; /* Hz */ 490 491 /* 492 * iqsense = 1 493 * tunerstep = 125000 494 */ 495 state->bandwidth = 36000000; /* Hz */ 496 state->reference = refclk / 1000; /* kHz */ 497 498 /* Set default bandwidth. Modified, PN 13-May-10 */ 499 return 0; 500 } 501 502 static int stb6100_set_params(struct dvb_frontend *fe) 503 { 504 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 505 506 if (c->frequency > 0) 507 stb6100_set_frequency(fe, c->frequency); 508 509 if (c->bandwidth_hz > 0) 510 stb6100_set_bandwidth(fe, c->bandwidth_hz); 511 512 return 0; 513 } 514 515 static const struct dvb_tuner_ops stb6100_ops = { 516 .info = { 517 .name = "STB6100 Silicon Tuner", 518 .frequency_min_hz = 950 * MHz, 519 .frequency_max_hz = 2150 * MHz, 520 }, 521 522 .init = stb6100_init, 523 .sleep = stb6100_sleep, 524 .get_status = stb6100_get_status, 525 .set_params = stb6100_set_params, 526 .get_frequency = stb6100_get_frequency, 527 .get_bandwidth = stb6100_get_bandwidth, 528 .release = stb6100_release 529 }; 530 531 struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, 532 const struct stb6100_config *config, 533 struct i2c_adapter *i2c) 534 { 535 struct stb6100_state *state = NULL; 536 537 state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); 538 if (!state) 539 return NULL; 540 541 state->config = config; 542 state->i2c = i2c; 543 state->frontend = fe; 544 state->reference = config->refclock / 1000; /* kHz */ 545 fe->tuner_priv = state; 546 fe->ops.tuner_ops = stb6100_ops; 547 548 printk("%s: Attaching STB6100 \n", __func__); 549 return fe; 550 } 551 552 static void stb6100_release(struct dvb_frontend *fe) 553 { 554 struct stb6100_state *state = fe->tuner_priv; 555 556 fe->tuner_priv = NULL; 557 kfree(state); 558 } 559 560 EXPORT_SYMBOL_GPL(stb6100_attach); 561 MODULE_PARM_DESC(verbose, "Set Verbosity level"); 562 563 MODULE_AUTHOR("Manu Abraham"); 564 MODULE_DESCRIPTION("STB6100 Silicon tuner"); 565 MODULE_LICENSE("GPL"); 566