Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] m88rs6000t: add new dvb-s/s2 tuner for integrated chip M88RS6000

M88RS6000 is the integrated chip, which includes tuner and demod.
Here splite its tuner as a standalone driver.
.set_config is used to config its demod clock, which sits inside tuner die.

Signed-off-by: Nibble Max <nibble.max@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

nibble.max and committed by
Mauro Carvalho Chehab
33382911 23222876

+782
+8
drivers/media/tuners/Kconfig
··· 232 232 help 233 233 Montage M88TS2022 silicon tuner driver. 234 234 235 + config MEDIA_TUNER_M88RS6000T 236 + tristate "Montage M88RS6000 internal tuner" 237 + depends on MEDIA_SUPPORT && I2C 238 + select REGMAP_I2C 239 + default m if !MEDIA_SUBDRV_AUTOSELECT 240 + help 241 + Montage M88RS6000 internal tuner. 242 + 235 243 config MEDIA_TUNER_TUA9001 236 244 tristate "Infineon TUA 9001 silicon tuner" 237 245 depends on MEDIA_SUPPORT && I2C
+1
drivers/media/tuners/Makefile
··· 41 41 obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o 42 42 obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o 43 43 obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o 44 + obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o 44 45 45 46 ccflags-y += -I$(srctree)/drivers/media/dvb-core 46 47 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+744
drivers/media/tuners/m88rs6000t.c
··· 1 + /* 2 + * Driver for the internal tuner of Montage M88RS6000 3 + * 4 + * Copyright (C) 2014 Max nibble <nibble.max@gmail.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 + 17 + #include "m88rs6000t.h" 18 + #include <linux/regmap.h> 19 + 20 + struct m88rs6000t_dev { 21 + struct m88rs6000t_config cfg; 22 + struct i2c_client *client; 23 + struct regmap *regmap; 24 + u32 frequency_khz; 25 + }; 26 + 27 + struct m88rs6000t_reg_val { 28 + u8 reg; 29 + u8 val; 30 + }; 31 + 32 + /* set demod main mclk and ts mclk */ 33 + static int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe) 34 + { 35 + struct m88rs6000t_dev *dev = fe->tuner_priv; 36 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 37 + u8 reg11, reg15, reg16, reg1D, reg1E, reg1F; 38 + u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0; 39 + u16 pll_div_fb; 40 + u32 div, ts_mclk; 41 + unsigned int utmp; 42 + int ret; 43 + 44 + /* select demod main mclk */ 45 + ret = regmap_read(dev->regmap, 0x15, &utmp); 46 + if (ret) 47 + goto err; 48 + reg15 = utmp; 49 + if (c->symbol_rate > 45010000) { 50 + reg11 = 0x0E; 51 + reg15 |= 0x02; 52 + reg16 = 115; /* mclk = 110.25MHz */ 53 + } else { 54 + reg11 = 0x0A; 55 + reg15 &= ~0x02; 56 + reg16 = 96; /* mclk = 96MHz */ 57 + } 58 + 59 + /* set ts mclk */ 60 + if (c->delivery_system == SYS_DVBS) 61 + ts_mclk = 96000; 62 + else 63 + ts_mclk = 144000; 64 + 65 + pll_div_fb = (reg15 & 0x01) << 8; 66 + pll_div_fb += reg16; 67 + pll_div_fb += 32; 68 + 69 + div = 36000 * pll_div_fb; 70 + div /= ts_mclk; 71 + 72 + if (div <= 32) { 73 + N = 2; 74 + f0 = 0; 75 + f1 = div / 2; 76 + f2 = div - f1; 77 + f3 = 0; 78 + } else if (div <= 48) { 79 + N = 3; 80 + f0 = div / 3; 81 + f1 = (div - f0) / 2; 82 + f2 = div - f0 - f1; 83 + f3 = 0; 84 + } else if (div <= 64) { 85 + N = 4; 86 + f0 = div / 4; 87 + f1 = (div - f0) / 3; 88 + f2 = (div - f0 - f1) / 2; 89 + f3 = div - f0 - f1 - f2; 90 + } else { 91 + N = 4; 92 + f0 = 16; 93 + f1 = 16; 94 + f2 = 16; 95 + f3 = 16; 96 + } 97 + 98 + if (f0 == 16) 99 + f0 = 0; 100 + if (f1 == 16) 101 + f1 = 0; 102 + if (f2 == 16) 103 + f2 = 0; 104 + if (f3 == 16) 105 + f3 = 0; 106 + 107 + ret = regmap_read(dev->regmap, 0x1D, &utmp); 108 + if (ret) 109 + goto err; 110 + reg1D = utmp; 111 + reg1D &= ~0x03; 112 + reg1D |= N - 1; 113 + reg1E = ((f3 << 4) + f2) & 0xFF; 114 + reg1F = ((f1 << 4) + f0) & 0xFF; 115 + 116 + /* program and recalibrate demod PLL */ 117 + ret = regmap_write(dev->regmap, 0x05, 0x40); 118 + if (ret) 119 + goto err; 120 + ret = regmap_write(dev->regmap, 0x11, 0x08); 121 + if (ret) 122 + goto err; 123 + ret = regmap_write(dev->regmap, 0x15, reg15); 124 + if (ret) 125 + goto err; 126 + ret = regmap_write(dev->regmap, 0x16, reg16); 127 + if (ret) 128 + goto err; 129 + ret = regmap_write(dev->regmap, 0x1D, reg1D); 130 + if (ret) 131 + goto err; 132 + ret = regmap_write(dev->regmap, 0x1E, reg1E); 133 + if (ret) 134 + goto err; 135 + ret = regmap_write(dev->regmap, 0x1F, reg1F); 136 + if (ret) 137 + goto err; 138 + ret = regmap_write(dev->regmap, 0x17, 0xc1); 139 + if (ret) 140 + goto err; 141 + ret = regmap_write(dev->regmap, 0x17, 0x81); 142 + if (ret) 143 + goto err; 144 + usleep_range(5000, 50000); 145 + ret = regmap_write(dev->regmap, 0x05, 0x00); 146 + if (ret) 147 + goto err; 148 + ret = regmap_write(dev->regmap, 0x11, reg11); 149 + if (ret) 150 + goto err; 151 + usleep_range(5000, 50000); 152 + err: 153 + if (ret) 154 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 155 + return ret; 156 + } 157 + 158 + static int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev, 159 + u32 tuner_freq_MHz) 160 + { 161 + u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv; 162 + u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod; 163 + u8 reg27, reg29, reg42, reg42buf; 164 + unsigned int utmp; 165 + int ret; 166 + 167 + fcry_KHz = 27000; /* in kHz */ 168 + refDiv = 27; 169 + 170 + ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); 171 + if (ret) 172 + goto err; 173 + ret = regmap_write(dev->regmap, 0x31, 0x00); 174 + if (ret) 175 + goto err; 176 + ret = regmap_write(dev->regmap, 0x2c, 0x02); 177 + if (ret) 178 + goto err; 179 + 180 + if (tuner_freq_MHz >= 1550) { 181 + ucLoDiv1 = 2; 182 + ucLomod1 = 0; 183 + ucLoDiv2 = 2; 184 + ucLomod2 = 0; 185 + } else if (tuner_freq_MHz >= 1380) { 186 + ucLoDiv1 = 3; 187 + ucLomod1 = 16; 188 + ucLoDiv2 = 2; 189 + ucLomod2 = 0; 190 + } else if (tuner_freq_MHz >= 1070) { 191 + ucLoDiv1 = 3; 192 + ucLomod1 = 16; 193 + ucLoDiv2 = 3; 194 + ucLomod2 = 16; 195 + } else if (tuner_freq_MHz >= 1000) { 196 + ucLoDiv1 = 3; 197 + ucLomod1 = 16; 198 + ucLoDiv2 = 4; 199 + ucLomod2 = 64; 200 + } else if (tuner_freq_MHz >= 775) { 201 + ucLoDiv1 = 4; 202 + ucLomod1 = 64; 203 + ucLoDiv2 = 4; 204 + ucLomod2 = 64; 205 + } else if (tuner_freq_MHz >= 700) { 206 + ucLoDiv1 = 6; 207 + ucLomod1 = 48; 208 + ucLoDiv2 = 4; 209 + ucLomod2 = 64; 210 + } else if (tuner_freq_MHz >= 520) { 211 + ucLoDiv1 = 6; 212 + ucLomod1 = 48; 213 + ucLoDiv2 = 6; 214 + ucLomod2 = 48; 215 + } else { 216 + ucLoDiv1 = 8; 217 + ucLomod1 = 96; 218 + ucLoDiv2 = 8; 219 + ucLomod2 = 96; 220 + } 221 + 222 + ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv 223 + / fcry_KHz - 1024) / 2; 224 + ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv 225 + / fcry_KHz - 1024) / 2; 226 + 227 + reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F; 228 + ret = regmap_write(dev->regmap, 0x27, reg27); 229 + if (ret) 230 + goto err; 231 + ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF)); 232 + if (ret) 233 + goto err; 234 + reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f; 235 + ret = regmap_write(dev->regmap, 0x29, reg29); 236 + if (ret) 237 + goto err; 238 + ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF)); 239 + if (ret) 240 + goto err; 241 + ret = regmap_write(dev->regmap, 0x2F, 0xf5); 242 + if (ret) 243 + goto err; 244 + ret = regmap_write(dev->regmap, 0x30, 0x05); 245 + if (ret) 246 + goto err; 247 + ret = regmap_write(dev->regmap, 0x08, 0x1f); 248 + if (ret) 249 + goto err; 250 + ret = regmap_write(dev->regmap, 0x08, 0x3f); 251 + if (ret) 252 + goto err; 253 + ret = regmap_write(dev->regmap, 0x09, 0x20); 254 + if (ret) 255 + goto err; 256 + ret = regmap_write(dev->regmap, 0x09, 0x00); 257 + if (ret) 258 + goto err; 259 + ret = regmap_write(dev->regmap, 0x3e, 0x11); 260 + if (ret) 261 + goto err; 262 + ret = regmap_write(dev->regmap, 0x08, 0x2f); 263 + if (ret) 264 + goto err; 265 + ret = regmap_write(dev->regmap, 0x08, 0x3f); 266 + if (ret) 267 + goto err; 268 + ret = regmap_write(dev->regmap, 0x09, 0x10); 269 + if (ret) 270 + goto err; 271 + ret = regmap_write(dev->regmap, 0x09, 0x00); 272 + if (ret) 273 + goto err; 274 + usleep_range(2000, 50000); 275 + 276 + ret = regmap_read(dev->regmap, 0x42, &utmp); 277 + if (ret) 278 + goto err; 279 + reg42 = utmp; 280 + 281 + ret = regmap_write(dev->regmap, 0x3e, 0x10); 282 + if (ret) 283 + goto err; 284 + ret = regmap_write(dev->regmap, 0x08, 0x2f); 285 + if (ret) 286 + goto err; 287 + ret = regmap_write(dev->regmap, 0x08, 0x3f); 288 + if (ret) 289 + goto err; 290 + ret = regmap_write(dev->regmap, 0x09, 0x10); 291 + if (ret) 292 + goto err; 293 + ret = regmap_write(dev->regmap, 0x09, 0x00); 294 + if (ret) 295 + goto err; 296 + usleep_range(2000, 50000); 297 + 298 + ret = regmap_read(dev->regmap, 0x42, &utmp); 299 + if (ret) 300 + goto err; 301 + reg42buf = utmp; 302 + if (reg42buf < reg42) { 303 + ret = regmap_write(dev->regmap, 0x3e, 0x11); 304 + if (ret) 305 + goto err; 306 + } 307 + usleep_range(5000, 50000); 308 + 309 + ret = regmap_read(dev->regmap, 0x2d, &utmp); 310 + if (ret) 311 + goto err; 312 + ret = regmap_write(dev->regmap, 0x2d, utmp); 313 + if (ret) 314 + goto err; 315 + ret = regmap_read(dev->regmap, 0x2e, &utmp); 316 + if (ret) 317 + goto err; 318 + ret = regmap_write(dev->regmap, 0x2e, utmp); 319 + if (ret) 320 + goto err; 321 + 322 + ret = regmap_read(dev->regmap, 0x27, &utmp); 323 + if (ret) 324 + goto err; 325 + reg27 = utmp & 0x70; 326 + ret = regmap_read(dev->regmap, 0x83, &utmp); 327 + if (ret) 328 + goto err; 329 + if (reg27 == (utmp & 0x70)) { 330 + ucLoDiv = ucLoDiv1; 331 + ulNDiv = ulNDiv1; 332 + ucLomod = ucLomod1 / 16; 333 + } else { 334 + ucLoDiv = ucLoDiv2; 335 + ulNDiv = ulNDiv2; 336 + ucLomod = ucLomod2 / 16; 337 + } 338 + 339 + if ((ucLoDiv == 3) || (ucLoDiv == 6)) { 340 + refDiv = 18; 341 + ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); 342 + if (ret) 343 + goto err; 344 + ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv 345 + / fcry_KHz - 1024) / 2; 346 + } 347 + 348 + reg27 = (0x80 + ((ucLomod << 4) & 0x70) 349 + + ((ulNDiv >> 8) & 0x0F)) & 0xFF; 350 + ret = regmap_write(dev->regmap, 0x27, reg27); 351 + if (ret) 352 + goto err; 353 + ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF)); 354 + if (ret) 355 + goto err; 356 + ret = regmap_write(dev->regmap, 0x29, 0x80); 357 + if (ret) 358 + goto err; 359 + ret = regmap_write(dev->regmap, 0x31, 0x03); 360 + if (ret) 361 + goto err; 362 + 363 + if (ucLoDiv == 3) 364 + utmp = 0xCE; 365 + else 366 + utmp = 0x8A; 367 + ret = regmap_write(dev->regmap, 0x3b, utmp); 368 + if (ret) 369 + goto err; 370 + 371 + dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv; 372 + 373 + dev_dbg(&dev->client->dev, 374 + "actual tune frequency=%d\n", dev->frequency_khz); 375 + err: 376 + if (ret) 377 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 378 + return ret; 379 + } 380 + 381 + static int m88rs6000t_set_bb(struct m88rs6000t_dev *dev, 382 + u32 symbol_rate_KSs, s32 lpf_offset_KHz) 383 + { 384 + u32 f3dB; 385 + u8 reg40; 386 + 387 + f3dB = symbol_rate_KSs * 9 / 14 + 2000; 388 + f3dB += lpf_offset_KHz; 389 + f3dB = clamp_val(f3dB, 6000U, 43000U); 390 + reg40 = f3dB / 1000; 391 + return regmap_write(dev->regmap, 0x40, reg40); 392 + } 393 + 394 + static int m88rs6000t_set_params(struct dvb_frontend *fe) 395 + { 396 + struct m88rs6000t_dev *dev = fe->tuner_priv; 397 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 398 + int ret; 399 + s32 lpf_offset_KHz; 400 + u32 realFreq, freq_MHz; 401 + 402 + dev_dbg(&dev->client->dev, 403 + "frequency=%d symbol_rate=%d\n", 404 + c->frequency, c->symbol_rate); 405 + 406 + if (c->symbol_rate < 5000000) 407 + lpf_offset_KHz = 3000; 408 + else 409 + lpf_offset_KHz = 0; 410 + 411 + realFreq = c->frequency + lpf_offset_KHz; 412 + /* set tuner pll.*/ 413 + freq_MHz = (realFreq + 500) / 1000; 414 + ret = m88rs6000t_set_pll_freq(dev, freq_MHz); 415 + if (ret) 416 + goto err; 417 + ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz); 418 + if (ret) 419 + goto err; 420 + ret = regmap_write(dev->regmap, 0x00, 0x01); 421 + if (ret) 422 + goto err; 423 + ret = regmap_write(dev->regmap, 0x00, 0x00); 424 + if (ret) 425 + goto err; 426 + /* set demod mlck */ 427 + ret = m88rs6000t_set_demod_mclk(fe); 428 + err: 429 + if (ret) 430 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 431 + return ret; 432 + } 433 + 434 + static int m88rs6000t_init(struct dvb_frontend *fe) 435 + { 436 + struct m88rs6000t_dev *dev = fe->tuner_priv; 437 + int ret; 438 + 439 + dev_dbg(&dev->client->dev, "%s:\n", __func__); 440 + 441 + ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); 442 + if (ret) 443 + goto err; 444 + usleep_range(5000, 50000); 445 + ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); 446 + if (ret) 447 + goto err; 448 + usleep_range(10000, 50000); 449 + ret = regmap_write(dev->regmap, 0x07, 0x7d); 450 + err: 451 + if (ret) 452 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 453 + return ret; 454 + } 455 + 456 + static int m88rs6000t_sleep(struct dvb_frontend *fe) 457 + { 458 + struct m88rs6000t_dev *dev = fe->tuner_priv; 459 + int ret; 460 + 461 + dev_dbg(&dev->client->dev, "%s:\n", __func__); 462 + 463 + ret = regmap_write(dev->regmap, 0x07, 0x6d); 464 + if (ret) 465 + goto err; 466 + usleep_range(5000, 10000); 467 + err: 468 + if (ret) 469 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 470 + return ret; 471 + } 472 + 473 + static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency) 474 + { 475 + struct m88rs6000t_dev *dev = fe->tuner_priv; 476 + 477 + dev_dbg(&dev->client->dev, "\n"); 478 + 479 + *frequency = dev->frequency_khz; 480 + return 0; 481 + } 482 + 483 + static int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 484 + { 485 + struct m88rs6000t_dev *dev = fe->tuner_priv; 486 + 487 + dev_dbg(&dev->client->dev, "\n"); 488 + 489 + *frequency = 0; /* Zero-IF */ 490 + return 0; 491 + } 492 + 493 + 494 + static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength) 495 + { 496 + struct m88rs6000t_dev *dev = fe->tuner_priv; 497 + unsigned int val, i; 498 + int ret; 499 + u16 gain; 500 + u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290; 501 + u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300; 502 + u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0; 503 + u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0; 504 + u32 RFGS[13] = {0, 245, 266, 268, 270, 285, 505 + 298, 295, 283, 285, 285, 300, 300}; 506 + u32 IFGS[12] = {0, 300, 230, 270, 270, 285, 507 + 295, 285, 290, 295, 295, 310}; 508 + u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290, 509 + 290, 285, 283, 260, 295, 290, 260}; 510 + 511 + ret = regmap_read(dev->regmap, 0x5A, &val); 512 + if (ret) 513 + goto err; 514 + RF_GC = val & 0x0f; 515 + 516 + ret = regmap_read(dev->regmap, 0x5F, &val); 517 + if (ret) 518 + goto err; 519 + IF_GC = val & 0x0f; 520 + 521 + ret = regmap_read(dev->regmap, 0x3F, &val); 522 + if (ret) 523 + goto err; 524 + TIA_GC = (val >> 4) & 0x07; 525 + 526 + ret = regmap_read(dev->regmap, 0x77, &val); 527 + if (ret) 528 + goto err; 529 + BB_GC = (val >> 4) & 0x0f; 530 + 531 + ret = regmap_read(dev->regmap, 0x76, &val); 532 + if (ret) 533 + goto err; 534 + PGA2_GC = val & 0x3f; 535 + PGA2_cri = PGA2_GC >> 2; 536 + PGA2_crf = PGA2_GC & 0x03; 537 + 538 + for (i = 0; i <= RF_GC; i++) 539 + RFG += RFGS[i]; 540 + 541 + if (RF_GC == 0) 542 + RFG += 400; 543 + if (RF_GC == 1) 544 + RFG += 300; 545 + if (RF_GC == 2) 546 + RFG += 200; 547 + if (RF_GC == 3) 548 + RFG += 100; 549 + 550 + for (i = 0; i <= IF_GC; i++) 551 + IFG += IFGS[i]; 552 + 553 + TIAG = TIA_GC * TIA_GS; 554 + 555 + for (i = 0; i <= BB_GC; i++) 556 + BBG += BBGS[i]; 557 + 558 + PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS; 559 + 560 + gain = RFG + IFG - TIAG + BBG + PGA2G; 561 + 562 + /* scale value to 0x0000-0xffff */ 563 + gain = clamp_val(gain, 1000U, 10500U); 564 + *strength = (10500 - gain) * 0xffff / (10500 - 1000); 565 + err: 566 + if (ret) 567 + dev_dbg(&dev->client->dev, "failed=%d\n", ret); 568 + return ret; 569 + } 570 + 571 + static const struct dvb_tuner_ops m88rs6000t_tuner_ops = { 572 + .info = { 573 + .name = "Montage M88RS6000 Internal Tuner", 574 + .frequency_min = 950000, 575 + .frequency_max = 2150000, 576 + }, 577 + 578 + .init = m88rs6000t_init, 579 + .sleep = m88rs6000t_sleep, 580 + .set_params = m88rs6000t_set_params, 581 + .get_frequency = m88rs6000t_get_frequency, 582 + .get_if_frequency = m88rs6000t_get_if_frequency, 583 + .get_rf_strength = m88rs6000t_get_rf_strength, 584 + }; 585 + 586 + static int m88rs6000t_probe(struct i2c_client *client, 587 + const struct i2c_device_id *id) 588 + { 589 + struct m88rs6000t_config *cfg = client->dev.platform_data; 590 + struct dvb_frontend *fe = cfg->fe; 591 + struct m88rs6000t_dev *dev; 592 + int ret, i; 593 + unsigned int utmp; 594 + static const struct regmap_config regmap_config = { 595 + .reg_bits = 8, 596 + .val_bits = 8, 597 + }; 598 + static const struct m88rs6000t_reg_val reg_vals[] = { 599 + {0x10, 0xfb}, 600 + {0x24, 0x38}, 601 + {0x11, 0x0a}, 602 + {0x12, 0x00}, 603 + {0x2b, 0x1c}, 604 + {0x44, 0x48}, 605 + {0x54, 0x24}, 606 + {0x55, 0x06}, 607 + {0x59, 0x00}, 608 + {0x5b, 0x4c}, 609 + {0x60, 0x8b}, 610 + {0x61, 0xf4}, 611 + {0x65, 0x07}, 612 + {0x6d, 0x6f}, 613 + {0x6e, 0x31}, 614 + {0x3c, 0xf3}, 615 + {0x37, 0x0f}, 616 + {0x48, 0x28}, 617 + {0x49, 0xd8}, 618 + {0x70, 0x66}, 619 + {0x71, 0xCF}, 620 + {0x72, 0x81}, 621 + {0x73, 0xA7}, 622 + {0x74, 0x4F}, 623 + {0x75, 0xFC}, 624 + }; 625 + 626 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 627 + if (!dev) { 628 + ret = -ENOMEM; 629 + dev_err(&client->dev, "kzalloc() failed\n"); 630 + goto err; 631 + } 632 + 633 + memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config)); 634 + dev->client = client; 635 + dev->regmap = devm_regmap_init_i2c(client, &regmap_config); 636 + if (IS_ERR(dev->regmap)) { 637 + ret = PTR_ERR(dev->regmap); 638 + goto err; 639 + } 640 + 641 + ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); 642 + if (ret) 643 + goto err; 644 + usleep_range(5000, 50000); 645 + ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); 646 + if (ret) 647 + goto err; 648 + usleep_range(10000, 50000); 649 + ret = regmap_write(dev->regmap, 0x07, 0x7d); 650 + if (ret) 651 + goto err; 652 + ret = regmap_write(dev->regmap, 0x04, 0x01); 653 + if (ret) 654 + goto err; 655 + 656 + /* check tuner chip id */ 657 + ret = regmap_read(dev->regmap, 0x01, &utmp); 658 + if (ret) 659 + goto err; 660 + dev_info(&dev->client->dev, "chip_id=%02x\n", utmp); 661 + if (utmp != 0x64) { 662 + ret = -ENODEV; 663 + goto err; 664 + } 665 + 666 + /* tuner init. */ 667 + ret = regmap_write(dev->regmap, 0x05, 0x40); 668 + if (ret) 669 + goto err; 670 + ret = regmap_write(dev->regmap, 0x11, 0x08); 671 + if (ret) 672 + goto err; 673 + ret = regmap_write(dev->regmap, 0x15, 0x6c); 674 + if (ret) 675 + goto err; 676 + ret = regmap_write(dev->regmap, 0x17, 0xc1); 677 + if (ret) 678 + goto err; 679 + ret = regmap_write(dev->regmap, 0x17, 0x81); 680 + if (ret) 681 + goto err; 682 + usleep_range(10000, 50000); 683 + ret = regmap_write(dev->regmap, 0x05, 0x00); 684 + if (ret) 685 + goto err; 686 + ret = regmap_write(dev->regmap, 0x11, 0x0a); 687 + if (ret) 688 + goto err; 689 + 690 + for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { 691 + ret = regmap_write(dev->regmap, 692 + reg_vals[i].reg, reg_vals[i].val); 693 + if (ret) 694 + goto err; 695 + } 696 + 697 + dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n"); 698 + 699 + fe->tuner_priv = dev; 700 + memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops, 701 + sizeof(struct dvb_tuner_ops)); 702 + i2c_set_clientdata(client, dev); 703 + return 0; 704 + err: 705 + dev_dbg(&client->dev, "failed=%d\n", ret); 706 + kfree(dev); 707 + return ret; 708 + } 709 + 710 + static int m88rs6000t_remove(struct i2c_client *client) 711 + { 712 + struct m88rs6000t_dev *dev = i2c_get_clientdata(client); 713 + struct dvb_frontend *fe = dev->cfg.fe; 714 + 715 + dev_dbg(&client->dev, "\n"); 716 + 717 + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); 718 + fe->tuner_priv = NULL; 719 + kfree(dev); 720 + 721 + return 0; 722 + } 723 + 724 + static const struct i2c_device_id m88rs6000t_id[] = { 725 + {"m88rs6000t", 0}, 726 + {} 727 + }; 728 + MODULE_DEVICE_TABLE(i2c, m88rs6000t_id); 729 + 730 + static struct i2c_driver m88rs6000t_driver = { 731 + .driver = { 732 + .owner = THIS_MODULE, 733 + .name = "m88rs6000t", 734 + }, 735 + .probe = m88rs6000t_probe, 736 + .remove = m88rs6000t_remove, 737 + .id_table = m88rs6000t_id, 738 + }; 739 + 740 + module_i2c_driver(m88rs6000t_driver); 741 + 742 + MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); 743 + MODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver"); 744 + MODULE_LICENSE("GPL");
+29
drivers/media/tuners/m88rs6000t.h
··· 1 + /* 2 + * Driver for the internal tuner of Montage M88RS6000 3 + * 4 + * Copyright (C) 2014 Max nibble <nibble.max@gmail.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 + 17 + #ifndef _M88RS6000T_H_ 18 + #define _M88RS6000T_H_ 19 + 20 + #include "dvb_frontend.h" 21 + 22 + struct m88rs6000t_config { 23 + /* 24 + * pointer to DVB frontend 25 + */ 26 + struct dvb_frontend *fe; 27 + }; 28 + 29 + #endif